]> git.saurik.com Git - apple/javascriptcore.git/blob - jit/JITStubs.cpp
JavaScriptCore-721.26.tar.gz
[apple/javascriptcore.git] / jit / JITStubs.cpp
1 /*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "config.h"
31 #include "JITStubs.h"
32
33 #if ENABLE(JIT)
34
35 #include "Arguments.h"
36 #include "CallFrame.h"
37 #include "CodeBlock.h"
38 #include "Collector.h"
39 #include "Debugger.h"
40 #include "ExceptionHelpers.h"
41 #include "GetterSetter.h"
42 #include "GlobalEvalFunction.h"
43 #include "JIT.h"
44 #include "JSActivation.h"
45 #include "JSArray.h"
46 #include "JSByteArray.h"
47 #include "JSFunction.h"
48 #include "JSNotAnObject.h"
49 #include "JSPropertyNameIterator.h"
50 #include "JSStaticScopeObject.h"
51 #include "JSString.h"
52 #include "ObjectPrototype.h"
53 #include "Operations.h"
54 #include "Parser.h"
55 #include "Profiler.h"
56 #include "RegExpObject.h"
57 #include "RegExpPrototype.h"
58 #include "Register.h"
59 #include "SamplingTool.h"
60 #include <wtf/StdLibExtras.h>
61 #include <stdarg.h>
62 #include <stdio.h>
63
64 using namespace std;
65
66 namespace JSC {
67
68 #if OS(DARWIN) || OS(WINDOWS)
69 #define SYMBOL_STRING(name) "_" #name
70 #else
71 #define SYMBOL_STRING(name) #name
72 #endif
73
74 #if OS(IPHONE_OS)
75 #define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name)
76 #else
77 #define THUMB_FUNC_PARAM(name)
78 #endif
79
80 #if OS(LINUX) && CPU(X86_64)
81 #define SYMBOL_STRING_RELOCATION(name) #name "@plt"
82 #else
83 #define SYMBOL_STRING_RELOCATION(name) SYMBOL_STRING(name)
84 #endif
85
86 #if OS(DARWIN)
87 // Mach-O platform
88 #define HIDE_SYMBOL(name) ".private_extern _" #name
89 #elif OS(AIX)
90 // IBM's own file format
91 #define HIDE_SYMBOL(name) ".lglobl " #name
92 #elif OS(LINUX) \
93 || OS(FREEBSD) \
94 || OS(OPENBSD) \
95 || OS(SOLARIS) \
96 || (OS(HPUX) && CPU(IA64)) \
97 || OS(SYMBIAN) \
98 || OS(NETBSD)
99 // ELF platform
100 #define HIDE_SYMBOL(name) ".hidden " #name
101 #else
102 #define HIDE_SYMBOL(name)
103 #endif
104
105 #if USE(JSVALUE32_64)
106
107 #if COMPILER(GCC) && CPU(X86)
108
109 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
110 // need to change the assembly trampolines below to match.
111 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment);
112 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
113 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
114 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline);
115
116 asm volatile (
117 ".text\n"
118 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
119 HIDE_SYMBOL(ctiTrampoline) "\n"
120 SYMBOL_STRING(ctiTrampoline) ":" "\n"
121 "pushl %ebp" "\n"
122 "movl %esp, %ebp" "\n"
123 "pushl %esi" "\n"
124 "pushl %edi" "\n"
125 "pushl %ebx" "\n"
126 "subl $0x3c, %esp" "\n"
127 "movl $512, %esi" "\n"
128 "movl 0x58(%esp), %edi" "\n"
129 "call *0x50(%esp)" "\n"
130 "addl $0x3c, %esp" "\n"
131 "popl %ebx" "\n"
132 "popl %edi" "\n"
133 "popl %esi" "\n"
134 "popl %ebp" "\n"
135 "ret" "\n"
136 );
137
138 asm volatile (
139 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
140 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
141 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
142 #if !USE(JIT_STUB_ARGUMENT_VA_LIST)
143 "movl %esp, %ecx" "\n"
144 #endif
145 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
146 "addl $0x3c, %esp" "\n"
147 "popl %ebx" "\n"
148 "popl %edi" "\n"
149 "popl %esi" "\n"
150 "popl %ebp" "\n"
151 "ret" "\n"
152 );
153
154 asm volatile (
155 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
156 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
157 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
158 "addl $0x3c, %esp" "\n"
159 "popl %ebx" "\n"
160 "popl %edi" "\n"
161 "popl %esi" "\n"
162 "popl %ebp" "\n"
163 "ret" "\n"
164 );
165
166 #elif COMPILER(GCC) && CPU(X86_64)
167
168 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
169 #error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64."
170 #endif
171
172 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
173 // need to change the assembly trampolines below to match.
174 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 32 == 0x0, JITStackFrame_maintains_32byte_stack_alignment);
175 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
176 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
177 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline);
178
179 asm volatile (
180 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
181 HIDE_SYMBOL(ctiTrampoline) "\n"
182 SYMBOL_STRING(ctiTrampoline) ":" "\n"
183 "pushq %rbp" "\n"
184 "movq %rsp, %rbp" "\n"
185 "pushq %r12" "\n"
186 "pushq %r13" "\n"
187 "pushq %r14" "\n"
188 "pushq %r15" "\n"
189 "pushq %rbx" "\n"
190 "subq $0x48, %rsp" "\n"
191 "movq $512, %r12" "\n"
192 "movq $0xFFFF000000000000, %r14" "\n"
193 "movq $0xFFFF000000000002, %r15" "\n"
194 "movq 0x90(%rsp), %r13" "\n"
195 "call *0x80(%rsp)" "\n"
196 "addq $0x48, %rsp" "\n"
197 "popq %rbx" "\n"
198 "popq %r15" "\n"
199 "popq %r14" "\n"
200 "popq %r13" "\n"
201 "popq %r12" "\n"
202 "popq %rbp" "\n"
203 "ret" "\n"
204 );
205
206 asm volatile (
207 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
208 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
209 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
210 "movq %rsp, %rdi" "\n"
211 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
212 "addq $0x48, %rsp" "\n"
213 "popq %rbx" "\n"
214 "popq %r15" "\n"
215 "popq %r14" "\n"
216 "popq %r13" "\n"
217 "popq %r12" "\n"
218 "popq %rbp" "\n"
219 "ret" "\n"
220 );
221
222 asm volatile (
223 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
224 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
225 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
226 "addq $0x48, %rsp" "\n"
227 "popq %rbx" "\n"
228 "popq %r15" "\n"
229 "popq %r14" "\n"
230 "popq %r13" "\n"
231 "popq %r12" "\n"
232 "popq %rbp" "\n"
233 "ret" "\n"
234 );
235
236 #elif COMPILER(GCC) && CPU(ARM_THUMB2)
237
238 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
239 #error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7."
240 #endif
241
242 #define THUNK_RETURN_ADDRESS_OFFSET 0x3C
243 #define PRESERVED_RETURN_ADDRESS_OFFSET 0x40
244 #define PRESERVED_R4_OFFSET 0x44
245 #define PRESERVED_R5_OFFSET 0x48
246 #define PRESERVED_R6_OFFSET 0x4C
247 #define REGISTER_FILE_OFFSET 0x50
248 #define CALLFRAME_OFFSET 0x54
249 #define EXCEPTION_OFFSET 0x58
250 #define ENABLE_PROFILER_REFERENCE_OFFSET 0x60
251
252 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
253
254 #define THUNK_RETURN_ADDRESS_OFFSET 64
255 #define PRESERVEDR4_OFFSET 68
256
257 #elif COMPILER(MSVC) && CPU(X86)
258
259 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
260 #error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC."
261 #endif
262
263 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
264 // need to change the assembly trampolines below to match.
265 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment);
266 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
267 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
268 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline);
269
270 extern "C" {
271
272 __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*)
273 {
274 __asm {
275 push ebp;
276 mov ebp, esp;
277 push esi;
278 push edi;
279 push ebx;
280 sub esp, 0x3c;
281 mov esi, 512;
282 mov ecx, esp;
283 mov edi, [esp + 0x58];
284 call [esp + 0x50];
285 add esp, 0x3c;
286 pop ebx;
287 pop edi;
288 pop esi;
289 pop ebp;
290 ret;
291 }
292 }
293
294 __declspec(naked) void ctiVMThrowTrampoline()
295 {
296 __asm {
297 mov ecx, esp;
298 call cti_vm_throw;
299 add esp, 0x3c;
300 pop ebx;
301 pop edi;
302 pop esi;
303 pop ebp;
304 ret;
305 }
306 }
307
308 __declspec(naked) void ctiOpThrowNotCaught()
309 {
310 __asm {
311 add esp, 0x3c;
312 pop ebx;
313 pop edi;
314 pop esi;
315 pop ebp;
316 ret;
317 }
318 }
319 }
320
321 #else
322 #error "JIT not supported on this platform."
323 #endif
324
325 #else // USE(JSVALUE32_64)
326
327 #if COMPILER(GCC) && CPU(X86)
328
329 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
330 // need to change the assembly trampolines below to match.
331 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
332 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline);
333 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
334
335 asm volatile (
336 ".text\n"
337 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
338 HIDE_SYMBOL(ctiTrampoline) "\n"
339 SYMBOL_STRING(ctiTrampoline) ":" "\n"
340 "pushl %ebp" "\n"
341 "movl %esp, %ebp" "\n"
342 "pushl %esi" "\n"
343 "pushl %edi" "\n"
344 "pushl %ebx" "\n"
345 "subl $0x1c, %esp" "\n"
346 "movl $512, %esi" "\n"
347 "movl 0x38(%esp), %edi" "\n"
348 "call *0x30(%esp)" "\n"
349 "addl $0x1c, %esp" "\n"
350 "popl %ebx" "\n"
351 "popl %edi" "\n"
352 "popl %esi" "\n"
353 "popl %ebp" "\n"
354 "ret" "\n"
355 );
356
357 asm volatile (
358 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
359 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
360 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
361 #if !USE(JIT_STUB_ARGUMENT_VA_LIST)
362 "movl %esp, %ecx" "\n"
363 #endif
364 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
365 "addl $0x1c, %esp" "\n"
366 "popl %ebx" "\n"
367 "popl %edi" "\n"
368 "popl %esi" "\n"
369 "popl %ebp" "\n"
370 "ret" "\n"
371 );
372
373 asm volatile (
374 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
375 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
376 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
377 "addl $0x1c, %esp" "\n"
378 "popl %ebx" "\n"
379 "popl %edi" "\n"
380 "popl %esi" "\n"
381 "popl %ebp" "\n"
382 "ret" "\n"
383 );
384
385 #elif COMPILER(GCC) && CPU(X86_64)
386
387 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
388 #error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64."
389 #endif
390
391 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
392 // need to change the assembly trampolines below to match.
393 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
394 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x48, JITStackFrame_code_offset_matches_ctiTrampoline);
395 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x78, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
396
397 asm volatile (
398 ".text\n"
399 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
400 HIDE_SYMBOL(ctiTrampoline) "\n"
401 SYMBOL_STRING(ctiTrampoline) ":" "\n"
402 "pushq %rbp" "\n"
403 "movq %rsp, %rbp" "\n"
404 "pushq %r12" "\n"
405 "pushq %r13" "\n"
406 "pushq %r14" "\n"
407 "pushq %r15" "\n"
408 "pushq %rbx" "\n"
409 // Form the JIT stubs area
410 "pushq %r9" "\n"
411 "pushq %r8" "\n"
412 "pushq %rcx" "\n"
413 "pushq %rdx" "\n"
414 "pushq %rsi" "\n"
415 "pushq %rdi" "\n"
416 "subq $0x48, %rsp" "\n"
417 "movq $512, %r12" "\n"
418 "movq $0xFFFF000000000000, %r14" "\n"
419 "movq $0xFFFF000000000002, %r15" "\n"
420 "movq %rdx, %r13" "\n"
421 "call *%rdi" "\n"
422 "addq $0x78, %rsp" "\n"
423 "popq %rbx" "\n"
424 "popq %r15" "\n"
425 "popq %r14" "\n"
426 "popq %r13" "\n"
427 "popq %r12" "\n"
428 "popq %rbp" "\n"
429 "ret" "\n"
430 );
431
432 asm volatile (
433 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
434 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
435 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
436 "movq %rsp, %rdi" "\n"
437 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
438 "addq $0x78, %rsp" "\n"
439 "popq %rbx" "\n"
440 "popq %r15" "\n"
441 "popq %r14" "\n"
442 "popq %r13" "\n"
443 "popq %r12" "\n"
444 "popq %rbp" "\n"
445 "ret" "\n"
446 );
447
448 asm volatile (
449 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
450 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
451 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
452 "addq $0x78, %rsp" "\n"
453 "popq %rbx" "\n"
454 "popq %r15" "\n"
455 "popq %r14" "\n"
456 "popq %r13" "\n"
457 "popq %r12" "\n"
458 "popq %rbp" "\n"
459 "ret" "\n"
460 );
461
462 #elif COMPILER(GCC) && CPU(ARM_THUMB2)
463
464 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
465 #error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7."
466 #endif
467
468 #define THUNK_RETURN_ADDRESS_OFFSET 0x1C
469 #define PRESERVED_RETURN_ADDRESS_OFFSET 0x20
470 #define PRESERVED_R4_OFFSET 0x24
471 #define PRESERVED_R5_OFFSET 0x28
472 #define PRESERVED_R6_OFFSET 0x2C
473 #define REGISTER_FILE_OFFSET 0x30
474 #define CALLFRAME_OFFSET 0x34
475 #define EXCEPTION_OFFSET 0x38
476 #define ENABLE_PROFILER_REFERENCE_OFFSET 0x40
477
478 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
479
480 #define THUNK_RETURN_ADDRESS_OFFSET 32
481 #define PRESERVEDR4_OFFSET 36
482
483 #elif CPU(MIPS)
484
485 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
486 #error "JIT_STUB_ARGUMENT_VA_LIST not supported on MIPS."
487 #endif
488
489 asm volatile(
490 ".text" "\n"
491 ".align 2" "\n"
492 ".set noreorder" "\n"
493 ".set nomacro" "\n"
494 ".set nomips16" "\n"
495 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
496 ".ent " SYMBOL_STRING(ctiTrampoline) "\n"
497 SYMBOL_STRING(ctiTrampoline) ":" "\n"
498 "addiu $29,$29,-72" "\n"
499 "sw $31,44($29)" "\n"
500 "sw $18,40($29)" "\n"
501 "sw $17,36($29)" "\n"
502 "sw $16,32($29)" "\n"
503 #if WTF_MIPS_PIC
504 "sw $28,28($29)" "\n"
505 #endif
506 "move $16,$6 # set callFrameRegister" "\n"
507 "li $17,512 # set timeoutCheckRegister" "\n"
508 "move $25,$4 # move executableAddress to t9" "\n"
509 "sw $5,52($29) # store registerFile to current stack" "\n"
510 "sw $6,56($29) # store callFrame to curent stack" "\n"
511 "sw $7,60($29) # store exception to current stack" "\n"
512 "lw $8,88($29) # load enableProfilerReference from previous stack" "\n"
513 "lw $9,92($29) # load globalData from previous stack" "\n"
514 "sw $8,64($29) # store enableProfilerReference to current stack" "\n"
515 "jalr $25" "\n"
516 "sw $9,68($29) # store globalData to current stack" "\n"
517 "lw $16,32($29)" "\n"
518 "lw $17,36($29)" "\n"
519 "lw $18,40($29)" "\n"
520 "lw $31,44($29)" "\n"
521 "jr $31" "\n"
522 "addiu $29,$29,72" "\n"
523 ".set reorder" "\n"
524 ".set macro" "\n"
525 ".end " SYMBOL_STRING(ctiTrampoline) "\n"
526 );
527
528 asm volatile(
529 ".text" "\n"
530 ".align 2" "\n"
531 ".set noreorder" "\n"
532 ".set nomacro" "\n"
533 ".set nomips16" "\n"
534 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
535 ".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
536 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
537 #if WTF_MIPS_PIC
538 "lw $28,28($29)" "\n"
539 ".set macro" "\n"
540 "la $25," SYMBOL_STRING(cti_vm_throw) "\n"
541 ".set nomacro" "\n"
542 "bal " SYMBOL_STRING(cti_vm_throw) "\n"
543 "move $4,$29" "\n"
544 #else
545 "jal " SYMBOL_STRING(cti_vm_throw) "\n"
546 "move $4,$29" "\n"
547 #endif
548 "lw $16,32($29)" "\n"
549 "lw $17,36($29)" "\n"
550 "lw $18,40($29)" "\n"
551 "lw $31,44($29)" "\n"
552 "jr $31" "\n"
553 "addiu $29,$29,72" "\n"
554 ".set reorder" "\n"
555 ".set macro" "\n"
556 ".end " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
557 );
558
559 asm volatile(
560 ".text" "\n"
561 ".align 2" "\n"
562 ".set noreorder" "\n"
563 ".set nomacro" "\n"
564 ".set nomips16" "\n"
565 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
566 ".ent " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
567 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
568 "lw $16,32($29)" "\n"
569 "lw $17,36($29)" "\n"
570 "lw $18,40($29)" "\n"
571 "lw $31,44($29)" "\n"
572 "jr $31" "\n"
573 "addiu $29,$29,72" "\n"
574 ".set reorder" "\n"
575 ".set macro" "\n"
576 ".end " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
577 );
578
579 #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
580
581 #define THUNK_RETURN_ADDRESS_OFFSET 32
582 #define PRESERVEDR4_OFFSET 36
583
584 __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
585 {
586 ARM
587 stmdb sp!, {r1-r3}
588 stmdb sp!, {r4-r8, lr}
589 sub sp, sp, #36
590 mov r4, r2
591 mov r5, #512
592 mov lr, pc
593 bx r0
594 add sp, sp, #36
595 ldmia sp!, {r4-r8, lr}
596 add sp, sp, #12
597 bx lr
598 }
599
600 __asm void ctiVMThrowTrampoline()
601 {
602 ARM
603 PRESERVE8
604 mov r0, sp
605 bl cti_vm_throw
606 add sp, sp, #36
607 ldmia sp!, {r4-r8, lr}
608 add sp, sp, #12
609 bx lr
610 }
611
612 __asm void ctiOpThrowNotCaught()
613 {
614 ARM
615 add sp, sp, #36
616 ldmia sp!, {r4-r8, lr}
617 add sp, sp, #12
618 bx lr
619 }
620
621 #elif COMPILER(MSVC) && CPU(X86)
622
623 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
624 #error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC."
625 #endif
626
627 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
628 // need to change the assembly trampolines below to match.
629 COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
630 COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline);
631 COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
632
633 extern "C" {
634
635 __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*)
636 {
637 __asm {
638 push ebp;
639 mov ebp, esp;
640 push esi;
641 push edi;
642 push ebx;
643 sub esp, 0x1c;
644 mov esi, 512;
645 mov ecx, esp;
646 mov edi, [esp + 0x38];
647 call [esp + 0x30];
648 add esp, 0x1c;
649 pop ebx;
650 pop edi;
651 pop esi;
652 pop ebp;
653 ret;
654 }
655 }
656
657 __declspec(naked) void ctiVMThrowTrampoline()
658 {
659 __asm {
660 mov ecx, esp;
661 call cti_vm_throw;
662 add esp, 0x1c;
663 pop ebx;
664 pop edi;
665 pop esi;
666 pop ebp;
667 ret;
668 }
669 }
670
671 __declspec(naked) void ctiOpThrowNotCaught()
672 {
673 __asm {
674 add esp, 0x1c;
675 pop ebx;
676 pop edi;
677 pop esi;
678 pop ebp;
679 ret;
680 }
681 }
682 }
683
684 #else
685 #error "JIT not supported on this platform."
686 #endif
687
688 #endif // USE(JSVALUE32_64)
689
690 #if COMPILER(GCC) && CPU(ARM_THUMB2)
691
692 asm volatile(
693 ".text" "\n"
694 ".align 2" "\n"
695 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
696 HIDE_SYMBOL(ctiTrampoline) "\n"
697 ".thumb" "\n"
698 ".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n"
699 SYMBOL_STRING(ctiTrampoline) ":" "\n"
700 "sub sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n"
701 "str lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n"
702 "str r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n"
703 "str r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n"
704 "str r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n"
705 "str r1, [sp, #" STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET) "]" "\n"
706 "str r2, [sp, #" STRINGIZE_VALUE_OF(CALLFRAME_OFFSET) "]" "\n"
707 "str r3, [sp, #" STRINGIZE_VALUE_OF(EXCEPTION_OFFSET) "]" "\n"
708 "cpy r5, r2" "\n"
709 "mov r6, #512" "\n"
710 "blx r0" "\n"
711 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n"
712 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n"
713 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n"
714 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n"
715 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n"
716 "bx lr" "\n"
717 );
718
719 asm volatile(
720 ".text" "\n"
721 ".align 2" "\n"
722 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
723 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
724 ".thumb" "\n"
725 ".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n"
726 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
727 "cpy r0, sp" "\n"
728 "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n"
729 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n"
730 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n"
731 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n"
732 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n"
733 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n"
734 "bx lr" "\n"
735 );
736
737 asm volatile(
738 ".text" "\n"
739 ".align 2" "\n"
740 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
741 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
742 ".thumb" "\n"
743 ".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n"
744 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
745 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET) "]" "\n"
746 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET) "]" "\n"
747 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET) "]" "\n"
748 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET) "]" "\n"
749 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET) "\n"
750 "bx lr" "\n"
751 );
752
753 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
754
755 asm volatile(
756 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
757 HIDE_SYMBOL(ctiTrampoline) "\n"
758 SYMBOL_STRING(ctiTrampoline) ":" "\n"
759 "stmdb sp!, {r1-r3}" "\n"
760 "stmdb sp!, {r4-r8, lr}" "\n"
761 "sub sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n"
762 "mov r4, r2" "\n"
763 "mov r5, #512" "\n"
764 // r0 contains the code
765 "mov lr, pc" "\n"
766 "mov pc, r0" "\n"
767 "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n"
768 "ldmia sp!, {r4-r8, lr}" "\n"
769 "add sp, sp, #12" "\n"
770 "mov pc, lr" "\n"
771 );
772
773 asm volatile(
774 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
775 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
776 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
777 "mov r0, sp" "\n"
778 "bl " SYMBOL_STRING(cti_vm_throw) "\n"
779
780 // Both has the same return sequence
781 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
782 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
783 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
784 "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n"
785 "ldmia sp!, {r4-r8, lr}" "\n"
786 "add sp, sp, #12" "\n"
787 "mov pc, lr" "\n"
788 );
789
790 #endif
791
792 #if ENABLE(OPCODE_SAMPLING)
793 #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler()
794 #else
795 #define CTI_SAMPLER 0
796 #endif
797
798 JITThunks::JITThunks(JSGlobalData* globalData)
799 {
800 JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_trampolineStructure);
801
802 #if CPU(ARM_THUMB2)
803 // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types),
804 // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT
805 // macros.
806 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET);
807 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVED_R4_OFFSET);
808 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == PRESERVED_R5_OFFSET);
809 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == PRESERVED_R6_OFFSET);
810
811 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET);
812 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET);
813 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == EXCEPTION_OFFSET);
814 // The fifth argument is the first item already on the stack.
815 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET);
816
817 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
818
819 #elif CPU(ARM_TRADITIONAL)
820
821 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
822 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVEDR4_OFFSET);
823
824
825 #elif CPU(MIPS)
826 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedGP) == 28);
827 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS0) == 32);
828 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS1) == 36);
829 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS2) == 40);
830 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == 44);
831 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 48);
832 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == 52);
833 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == 56);
834 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == 60);
835 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 64);
836 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == 68);
837
838 #endif
839 }
840
841 JITThunks::~JITThunks()
842 {
843 }
844
845 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
846
847 NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct)
848 {
849 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
850
851 if (!baseValue.isCell())
852 return;
853
854 // Uncacheable: give up.
855 if (!slot.isCacheable()) {
856 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
857 return;
858 }
859
860 JSCell* baseCell = asCell(baseValue);
861 Structure* structure = baseCell->structure();
862
863 if (structure->isUncacheableDictionary()) {
864 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
865 return;
866 }
867
868 // If baseCell != base, then baseCell must be a proxy for another object.
869 if (baseCell != slot.base()) {
870 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
871 return;
872 }
873
874 // Cache hit: Specialize instruction and ref Structures.
875
876 // Structure transition, cache transition info
877 if (slot.type() == PutPropertySlot::NewProperty) {
878 if (structure->isDictionary()) {
879 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(direct ? cti_op_put_by_id_direct_generic : cti_op_put_by_id_generic));
880 return;
881 }
882
883 // put_by_id_transition checks the prototype chain for setters.
884 normalizePrototypeChain(callFrame, baseCell);
885
886 StructureChain* prototypeChain = structure->prototypeChain(callFrame);
887 stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain);
888 JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress, direct);
889 return;
890 }
891
892 stubInfo->initPutByIdReplace(structure);
893
894 JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct);
895 }
896
897 NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo)
898 {
899 // FIXME: Write a test that proves we need to check for recursion here just
900 // like the interpreter does, then add a check for recursion.
901
902 // FIXME: Cache property access for immediates.
903 if (!baseValue.isCell()) {
904 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
905 return;
906 }
907
908 JSGlobalData* globalData = &callFrame->globalData();
909
910 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
911 JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress);
912 return;
913 }
914
915 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
916 // The tradeoff of compiling an patched inline string length access routine does not seem
917 // to pay off, so we currently only do this for arrays.
918 ctiPatchCallByReturnAddress(codeBlock, returnAddress, globalData->jitStubs->ctiStringLengthTrampoline());
919 return;
920 }
921
922 // Uncacheable: give up.
923 if (!slot.isCacheable()) {
924 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
925 return;
926 }
927
928 JSCell* baseCell = asCell(baseValue);
929 Structure* structure = baseCell->structure();
930
931 if (structure->isUncacheableDictionary()) {
932 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
933 return;
934 }
935
936 // Cache hit: Specialize instruction and ref Structures.
937
938 if (slot.slotBase() == baseValue) {
939 // set this up, so derefStructures can do it's job.
940 stubInfo->initGetByIdSelf(structure);
941 if (slot.cachedPropertyType() != PropertySlot::Value)
942 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_self_fail));
943 else
944 JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);
945 return;
946 }
947
948 if (structure->isDictionary()) {
949 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
950 return;
951 }
952
953 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
954 ASSERT(slot.slotBase().isObject());
955
956 JSObject* slotBaseObject = asObject(slot.slotBase());
957 size_t offset = slot.cachedOffset();
958
959 // Since we're accessing a prototype in a loop, it's a good bet that it
960 // should not be treated as a dictionary.
961 if (slotBaseObject->structure()->isDictionary()) {
962 slotBaseObject->flattenDictionaryObject();
963 offset = slotBaseObject->structure()->get(propertyName);
964 }
965
966 stubInfo->initGetByIdProto(structure, slotBaseObject->structure());
967
968 ASSERT(!structure->isDictionary());
969 ASSERT(!slotBaseObject->structure()->isDictionary());
970 JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), propertyName, slot, offset, returnAddress);
971 return;
972 }
973
974 size_t offset = slot.cachedOffset();
975 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
976 if (!count) {
977 stubInfo->accessType = access_get_by_id_generic;
978 return;
979 }
980
981 StructureChain* prototypeChain = structure->prototypeChain(callFrame);
982 stubInfo->initGetByIdChain(structure, prototypeChain);
983 JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, propertyName, slot, offset, returnAddress);
984 }
985
986 #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
987
988 #if USE(JIT_STUB_ARGUMENT_VA_LIST)
989 #define SETUP_VA_LISTL_ARGS va_list vl_args; va_start(vl_args, args)
990 #else
991 #define SETUP_VA_LISTL_ARGS
992 #endif
993
994 #ifndef NDEBUG
995
996 extern "C" {
997
998 static void jscGeneratedNativeCode()
999 {
1000 // When executing a JIT stub function (which might do an allocation), we hack the return address
1001 // to pretend to be executing this function, to keep stack logging tools from blowing out
1002 // memory.
1003 }
1004
1005 }
1006
1007 struct StackHack {
1008 ALWAYS_INLINE StackHack(JITStackFrame& stackFrame)
1009 : stackFrame(stackFrame)
1010 , savedReturnAddress(*stackFrame.returnAddressSlot())
1011 {
1012 *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode));
1013 }
1014
1015 ALWAYS_INLINE ~StackHack()
1016 {
1017 *stackFrame.returnAddressSlot() = savedReturnAddress;
1018 }
1019
1020 JITStackFrame& stackFrame;
1021 ReturnAddressPtr savedReturnAddress;
1022 };
1023
1024 #define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame)
1025 #define STUB_SET_RETURN_ADDRESS(returnAddress) stackHack.savedReturnAddress = ReturnAddressPtr(returnAddress)
1026 #define STUB_RETURN_ADDRESS stackHack.savedReturnAddress
1027
1028 #else
1029
1030 #define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS)
1031 #define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress)
1032 #define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot()
1033
1034 #endif
1035
1036 // The reason this is not inlined is to avoid having to do a PIC branch
1037 // to get the address of the ctiVMThrowTrampoline function. It's also
1038 // good to keep the code size down by leaving as much of the exception
1039 // handling code out of line as possible.
1040 static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot)
1041 {
1042 ASSERT(globalData->exception);
1043 globalData->exceptionLocation = exceptionLocation;
1044 returnAddressSlot = ReturnAddressPtr(FunctionPtr(ctiVMThrowTrampoline));
1045 }
1046
1047 static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot)
1048 {
1049 globalData->exception = createStackOverflowError(callFrame);
1050 returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot);
1051 }
1052
1053 #define VM_THROW_EXCEPTION() \
1054 do { \
1055 VM_THROW_EXCEPTION_AT_END(); \
1056 return 0; \
1057 } while (0)
1058 #define VM_THROW_EXCEPTION_AT_END() \
1059 returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS)
1060
1061 #define CHECK_FOR_EXCEPTION() \
1062 do { \
1063 if (UNLIKELY(stackFrame.globalData->exception)) \
1064 VM_THROW_EXCEPTION(); \
1065 } while (0)
1066 #define CHECK_FOR_EXCEPTION_AT_END() \
1067 do { \
1068 if (UNLIKELY(stackFrame.globalData->exception)) \
1069 VM_THROW_EXCEPTION_AT_END(); \
1070 } while (0)
1071 #define CHECK_FOR_EXCEPTION_VOID() \
1072 do { \
1073 if (UNLIKELY(stackFrame.globalData->exception)) { \
1074 VM_THROW_EXCEPTION_AT_END(); \
1075 return; \
1076 } \
1077 } while (0)
1078
1079 #if CPU(ARM_THUMB2)
1080
1081 #define DEFINE_STUB_FUNCTION(rtype, op) \
1082 extern "C" { \
1083 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1084 }; \
1085 asm volatile ( \
1086 ".text" "\n" \
1087 ".align 2" "\n" \
1088 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1089 HIDE_SYMBOL(cti_##op) "\n" \
1090 ".thumb" "\n" \
1091 ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \
1092 SYMBOL_STRING(cti_##op) ":" "\n" \
1093 "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1094 "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1095 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1096 "bx lr" "\n" \
1097 ); \
1098 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \
1099
1100 #elif CPU(MIPS)
1101 #if WTF_MIPS_PIC
1102 #define DEFINE_STUB_FUNCTION(rtype, op) \
1103 extern "C" { \
1104 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1105 }; \
1106 asm volatile( \
1107 ".text" "\n" \
1108 ".align 2" "\n" \
1109 ".set noreorder" "\n" \
1110 ".set nomacro" "\n" \
1111 ".set nomips16" "\n" \
1112 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1113 ".ent " SYMBOL_STRING(cti_##op) "\n" \
1114 SYMBOL_STRING(cti_##op) ":" "\n" \
1115 "lw $28,28($29)" "\n" \
1116 "sw $31,48($29)" "\n" \
1117 ".set macro" "\n" \
1118 "la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \
1119 ".set nomacro" "\n" \
1120 "bal " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1121 "nop" "\n" \
1122 "lw $31,48($29)" "\n" \
1123 "jr $31" "\n" \
1124 "nop" "\n" \
1125 ".set reorder" "\n" \
1126 ".set macro" "\n" \
1127 ".end " SYMBOL_STRING(cti_##op) "\n" \
1128 ); \
1129 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1130
1131 #else // WTF_MIPS_PIC
1132 #define DEFINE_STUB_FUNCTION(rtype, op) \
1133 extern "C" { \
1134 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1135 }; \
1136 asm volatile( \
1137 ".text" "\n" \
1138 ".align 2" "\n" \
1139 ".set noreorder" "\n" \
1140 ".set nomacro" "\n" \
1141 ".set nomips16" "\n" \
1142 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1143 ".ent " SYMBOL_STRING(cti_##op) "\n" \
1144 SYMBOL_STRING(cti_##op) ":" "\n" \
1145 "sw $31,48($29)" "\n" \
1146 "jal " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1147 "nop" "\n" \
1148 "lw $31,48($29)" "\n" \
1149 "jr $31" "\n" \
1150 "nop" "\n" \
1151 ".set reorder" "\n" \
1152 ".set macro" "\n" \
1153 ".end " SYMBOL_STRING(cti_##op) "\n" \
1154 ); \
1155 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1156
1157 #endif
1158
1159 #elif CPU(ARM_TRADITIONAL) && COMPILER(GCC)
1160
1161 #define DEFINE_STUB_FUNCTION(rtype, op) \
1162 extern "C" { \
1163 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1164 }; \
1165 asm volatile ( \
1166 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1167 SYMBOL_STRING(cti_##op) ":" "\n" \
1168 "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1169 "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1170 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1171 "mov pc, lr" "\n" \
1172 ); \
1173 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1174
1175 #elif CPU(ARM_TRADITIONAL) && COMPILER(RVCT)
1176
1177 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1178
1179 /* The following is a workaround for RVCT toolchain; precompiler macros are not expanded before the code is passed to the assembler */
1180
1181 /* The following section is a template to generate code for GeneratedJITStubs_RVCT.h */
1182 /* The pattern "#xxx#" will be replaced with "xxx" */
1183
1184 /*
1185 RVCT(extern "C" #rtype# JITStubThunked_#op#(STUB_ARGS_DECLARATION);)
1186 RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION))
1187 RVCT({)
1188 RVCT( ARM)
1189 RVCT( IMPORT JITStubThunked_#op#)
1190 RVCT( str lr, [sp, ##offset#])
1191 RVCT( bl JITStubThunked_#op#)
1192 RVCT( ldr lr, [sp, ##offset#])
1193 RVCT( bx lr)
1194 RVCT(})
1195 RVCT()
1196 */
1197
1198 /* Include the generated file */
1199 #include "GeneratedJITStubs_RVCT.h"
1200
1201 #else
1202 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION)
1203 #endif
1204
1205 DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this)
1206 {
1207 STUB_INIT_STACK_FRAME(stackFrame);
1208
1209 JSValue v1 = stackFrame.args[0].jsValue();
1210 CallFrame* callFrame = stackFrame.callFrame;
1211
1212 JSObject* result = v1.toThisObject(callFrame);
1213 CHECK_FOR_EXCEPTION_AT_END();
1214 return JSValue::encode(result);
1215 }
1216
1217 DEFINE_STUB_FUNCTION(void, op_end)
1218 {
1219 STUB_INIT_STACK_FRAME(stackFrame);
1220
1221 ScopeChainNode* scopeChain = stackFrame.callFrame->scopeChain();
1222 ASSERT(scopeChain->refCount > 1);
1223 scopeChain->deref();
1224 }
1225
1226 DEFINE_STUB_FUNCTION(EncodedJSValue, op_add)
1227 {
1228 STUB_INIT_STACK_FRAME(stackFrame);
1229
1230 JSValue v1 = stackFrame.args[0].jsValue();
1231 JSValue v2 = stackFrame.args[1].jsValue();
1232 CallFrame* callFrame = stackFrame.callFrame;
1233
1234 if (v1.isString()) {
1235 JSValue result = v2.isString()
1236 ? jsString(callFrame, asString(v1), asString(v2))
1237 : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame));
1238 CHECK_FOR_EXCEPTION_AT_END();
1239 return JSValue::encode(result);
1240 }
1241
1242 double left = 0.0, right;
1243 if (v1.getNumber(left) && v2.getNumber(right))
1244 return JSValue::encode(jsNumber(stackFrame.globalData, left + right));
1245
1246 // All other cases are pretty uncommon
1247 JSValue result = jsAddSlowCase(callFrame, v1, v2);
1248 CHECK_FOR_EXCEPTION_AT_END();
1249 return JSValue::encode(result);
1250 }
1251
1252 DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc)
1253 {
1254 STUB_INIT_STACK_FRAME(stackFrame);
1255
1256 JSValue v = stackFrame.args[0].jsValue();
1257
1258 CallFrame* callFrame = stackFrame.callFrame;
1259 JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) + 1);
1260 CHECK_FOR_EXCEPTION_AT_END();
1261 return JSValue::encode(result);
1262 }
1263
1264 DEFINE_STUB_FUNCTION(int, timeout_check)
1265 {
1266 STUB_INIT_STACK_FRAME(stackFrame);
1267
1268 JSGlobalData* globalData = stackFrame.globalData;
1269 TimeoutChecker& timeoutChecker = globalData->timeoutChecker;
1270
1271 if (globalData->terminator.shouldTerminate()) {
1272 globalData->exception = createTerminatedExecutionException(globalData);
1273 VM_THROW_EXCEPTION_AT_END();
1274 } else if (timeoutChecker.didTimeOut(stackFrame.callFrame)) {
1275 globalData->exception = createInterruptedExecutionException(globalData);
1276 VM_THROW_EXCEPTION_AT_END();
1277 }
1278
1279 return timeoutChecker.ticksUntilNextCheck();
1280 }
1281
1282 DEFINE_STUB_FUNCTION(void, register_file_check)
1283 {
1284 STUB_INIT_STACK_FRAME(stackFrame);
1285
1286 if (LIKELY(stackFrame.registerFile->grow(&stackFrame.callFrame->registers()[stackFrame.callFrame->codeBlock()->m_numCalleeRegisters])))
1287 return;
1288
1289 // Rewind to the previous call frame because op_call already optimistically
1290 // moved the call frame forward.
1291 CallFrame* oldCallFrame = stackFrame.callFrame->callerFrame();
1292 stackFrame.callFrame = oldCallFrame;
1293 throwStackOverflowError(oldCallFrame, stackFrame.globalData, ReturnAddressPtr(oldCallFrame->returnPC()), STUB_RETURN_ADDRESS);
1294 }
1295
1296 DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq)
1297 {
1298 STUB_INIT_STACK_FRAME(stackFrame);
1299
1300 JSValue src1 = stackFrame.args[0].jsValue();
1301 JSValue src2 = stackFrame.args[1].jsValue();
1302 CallFrame* callFrame = stackFrame.callFrame;
1303
1304 bool result = jsLessEq(callFrame, src1, src2);
1305 CHECK_FOR_EXCEPTION_AT_END();
1306 return result;
1307 }
1308
1309 DEFINE_STUB_FUNCTION(JSObject*, op_new_object)
1310 {
1311 STUB_INIT_STACK_FRAME(stackFrame);
1312
1313 return constructEmptyObject(stackFrame.callFrame);
1314 }
1315
1316 DEFINE_STUB_FUNCTION(void, op_put_by_id_generic)
1317 {
1318 STUB_INIT_STACK_FRAME(stackFrame);
1319
1320 PutPropertySlot slot;
1321 stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
1322 CHECK_FOR_EXCEPTION_AT_END();
1323 }
1324
1325 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic)
1326 {
1327 STUB_INIT_STACK_FRAME(stackFrame);
1328
1329 PutPropertySlot slot;
1330 stackFrame.args[0].jsValue().putDirect(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
1331 CHECK_FOR_EXCEPTION_AT_END();
1332 }
1333
1334 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic)
1335 {
1336 STUB_INIT_STACK_FRAME(stackFrame);
1337
1338 CallFrame* callFrame = stackFrame.callFrame;
1339 Identifier& ident = stackFrame.args[1].identifier();
1340
1341 JSValue baseValue = stackFrame.args[0].jsValue();
1342 PropertySlot slot(baseValue);
1343 JSValue result = baseValue.get(callFrame, ident, slot);
1344
1345 CHECK_FOR_EXCEPTION_AT_END();
1346 return JSValue::encode(result);
1347 }
1348
1349 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
1350
1351 DEFINE_STUB_FUNCTION(void, op_put_by_id)
1352 {
1353 STUB_INIT_STACK_FRAME(stackFrame);
1354 CallFrame* callFrame = stackFrame.callFrame;
1355 Identifier& ident = stackFrame.args[1].identifier();
1356
1357 PutPropertySlot slot;
1358 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
1359
1360 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1361 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1362 if (!stubInfo->seenOnce())
1363 stubInfo->setSeen();
1364 else
1365 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, false);
1366
1367 CHECK_FOR_EXCEPTION_AT_END();
1368 }
1369
1370 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct)
1371 {
1372 STUB_INIT_STACK_FRAME(stackFrame);
1373 CallFrame* callFrame = stackFrame.callFrame;
1374 Identifier& ident = stackFrame.args[1].identifier();
1375
1376 PutPropertySlot slot;
1377 stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot);
1378
1379 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1380 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1381 if (!stubInfo->seenOnce())
1382 stubInfo->setSeen();
1383 else
1384 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true);
1385
1386 CHECK_FOR_EXCEPTION_AT_END();
1387 }
1388
1389 DEFINE_STUB_FUNCTION(void, op_put_by_id_fail)
1390 {
1391 STUB_INIT_STACK_FRAME(stackFrame);
1392
1393 CallFrame* callFrame = stackFrame.callFrame;
1394 Identifier& ident = stackFrame.args[1].identifier();
1395
1396 PutPropertySlot slot;
1397 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
1398
1399 CHECK_FOR_EXCEPTION_AT_END();
1400 }
1401
1402 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail)
1403 {
1404 STUB_INIT_STACK_FRAME(stackFrame);
1405
1406 CallFrame* callFrame = stackFrame.callFrame;
1407 Identifier& ident = stackFrame.args[1].identifier();
1408
1409 PutPropertySlot slot;
1410 stackFrame.args[0].jsValue().putDirect(callFrame, ident, stackFrame.args[2].jsValue(), slot);
1411
1412 CHECK_FOR_EXCEPTION_AT_END();
1413 }
1414
1415 DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc)
1416 {
1417 STUB_INIT_STACK_FRAME(stackFrame);
1418
1419 JSValue baseValue = stackFrame.args[0].jsValue();
1420 int32_t oldSize = stackFrame.args[3].int32();
1421 int32_t newSize = stackFrame.args[4].int32();
1422
1423 ASSERT(baseValue.isObject());
1424 JSObject* base = asObject(baseValue);
1425 base->allocatePropertyStorage(oldSize, newSize);
1426
1427 return base;
1428 }
1429
1430 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check)
1431 {
1432 STUB_INIT_STACK_FRAME(stackFrame);
1433
1434 CallFrame* callFrame = stackFrame.callFrame;
1435 Identifier& ident = stackFrame.args[1].identifier();
1436
1437 JSValue baseValue = stackFrame.args[0].jsValue();
1438 PropertySlot slot(baseValue);
1439 JSValue result = baseValue.get(callFrame, ident, slot);
1440 CHECK_FOR_EXCEPTION();
1441
1442 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1443 MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS);
1444
1445 if (!methodCallLinkInfo.seenOnce()) {
1446 methodCallLinkInfo.setSeen();
1447 return JSValue::encode(result);
1448 }
1449
1450 // If we successfully got something, then the base from which it is being accessed must
1451 // be an object. (Assertion to ensure asObject() call below is safe, which comes after
1452 // an isCacheable() chceck.
1453 ASSERT(!slot.isCacheableValue() || slot.slotBase().isObject());
1454
1455 // Check that:
1456 // * We're dealing with a JSCell,
1457 // * the property is cachable,
1458 // * it's not a dictionary
1459 // * there is a function cached.
1460 Structure* structure;
1461 JSCell* specific;
1462 JSObject* slotBaseObject;
1463 if (baseValue.isCell()
1464 && slot.isCacheableValue()
1465 && !(structure = asCell(baseValue)->structure())->isUncacheableDictionary()
1466 && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific)
1467 && specific
1468 ) {
1469
1470 JSFunction* callee = (JSFunction*)specific;
1471
1472 // Since we're accessing a prototype in a loop, it's a good bet that it
1473 // should not be treated as a dictionary.
1474 if (slotBaseObject->structure()->isDictionary())
1475 slotBaseObject->flattenDictionaryObject();
1476
1477 // The result fetched should always be the callee!
1478 ASSERT(result == JSValue(callee));
1479
1480 // Check to see if the function is on the object's prototype. Patch up the code to optimize.
1481 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
1482 JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, slotBaseObject, STUB_RETURN_ADDRESS);
1483 return JSValue::encode(result);
1484 }
1485
1486 // Check to see if the function is on the object itself.
1487 // Since we generate the method-check to check both the structure and a prototype-structure (since this
1488 // is the common case) we have a problem - we need to patch the prototype structure check to do something
1489 // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler
1490 // for now. For now it performs a check on a special object on the global object only used for this
1491 // purpose. The object is in no way exposed, and as such the check will always pass.
1492 if (slot.slotBase() == baseValue) {
1493 JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS);
1494 return JSValue::encode(result);
1495 }
1496 }
1497
1498 // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to.
1499 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id));
1500 return JSValue::encode(result);
1501 }
1502
1503 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id)
1504 {
1505 STUB_INIT_STACK_FRAME(stackFrame);
1506 CallFrame* callFrame = stackFrame.callFrame;
1507 Identifier& ident = stackFrame.args[1].identifier();
1508
1509 JSValue baseValue = stackFrame.args[0].jsValue();
1510 PropertySlot slot(baseValue);
1511 JSValue result = baseValue.get(callFrame, ident, slot);
1512
1513 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1514 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1515 if (!stubInfo->seenOnce())
1516 stubInfo->setSeen();
1517 else
1518 JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo);
1519
1520 CHECK_FOR_EXCEPTION_AT_END();
1521 return JSValue::encode(result);
1522 }
1523
1524 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
1525 {
1526 STUB_INIT_STACK_FRAME(stackFrame);
1527
1528 CallFrame* callFrame = stackFrame.callFrame;
1529 Identifier& ident = stackFrame.args[1].identifier();
1530
1531 JSValue baseValue = stackFrame.args[0].jsValue();
1532 PropertySlot slot(baseValue);
1533 JSValue result = baseValue.get(callFrame, ident, slot);
1534
1535 CHECK_FOR_EXCEPTION();
1536
1537 if (baseValue.isCell()
1538 && slot.isCacheable()
1539 && !asCell(baseValue)->structure()->isUncacheableDictionary()
1540 && slot.slotBase() == baseValue) {
1541
1542 CodeBlock* codeBlock = callFrame->codeBlock();
1543 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1544
1545 ASSERT(slot.slotBase().isObject());
1546
1547 PolymorphicAccessStructureList* polymorphicStructureList;
1548 int listIndex = 1;
1549
1550 if (stubInfo->accessType == access_get_by_id_self) {
1551 ASSERT(!stubInfo->stubRoutine);
1552 polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure);
1553 stubInfo->initGetByIdSelfList(polymorphicStructureList, 1);
1554 } else {
1555 polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList;
1556 listIndex = stubInfo->u.getByIdSelfList.listSize;
1557 }
1558 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
1559 stubInfo->u.getByIdSelfList.listSize++;
1560 JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), ident, slot, slot.cachedOffset());
1561
1562 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1563 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
1564 }
1565 } else
1566 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
1567 return JSValue::encode(result);
1568 }
1569
1570 static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex)
1571 {
1572 PolymorphicAccessStructureList* prototypeStructureList = 0;
1573 listIndex = 1;
1574
1575 switch (stubInfo->accessType) {
1576 case access_get_by_id_proto:
1577 prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure);
1578 stubInfo->stubRoutine = CodeLocationLabel();
1579 stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
1580 break;
1581 case access_get_by_id_chain:
1582 prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain);
1583 stubInfo->stubRoutine = CodeLocationLabel();
1584 stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
1585 break;
1586 case access_get_by_id_proto_list:
1587 prototypeStructureList = stubInfo->u.getByIdProtoList.structureList;
1588 listIndex = stubInfo->u.getByIdProtoList.listSize;
1589 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE)
1590 stubInfo->u.getByIdProtoList.listSize++;
1591 break;
1592 default:
1593 ASSERT_NOT_REACHED();
1594 }
1595
1596 ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE);
1597 return prototypeStructureList;
1598 }
1599
1600 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_getter_stub)
1601 {
1602 STUB_INIT_STACK_FRAME(stackFrame);
1603 CallFrame* callFrame = stackFrame.callFrame;
1604 GetterSetter* getterSetter = asGetterSetter(stackFrame.args[0].jsObject());
1605 if (!getterSetter->getter())
1606 return JSValue::encode(jsUndefined());
1607 JSObject* getter = asObject(getterSetter->getter());
1608 CallData callData;
1609 CallType callType = getter->getCallData(callData);
1610 JSValue result = call(callFrame, getter, callType, callData, stackFrame.args[1].jsObject(), ArgList());
1611 if (callFrame->hadException())
1612 returnToThrowTrampoline(&callFrame->globalData(), stackFrame.args[2].returnAddress(), STUB_RETURN_ADDRESS);
1613
1614 return JSValue::encode(result);
1615 }
1616
1617 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_custom_stub)
1618 {
1619 STUB_INIT_STACK_FRAME(stackFrame);
1620 CallFrame* callFrame = stackFrame.callFrame;
1621 JSObject* slotBase = stackFrame.args[0].jsObject();
1622 PropertySlot::GetValueFunc getter = reinterpret_cast<PropertySlot::GetValueFunc>(stackFrame.args[1].asPointer);
1623 const Identifier& ident = stackFrame.args[2].identifier();
1624 JSValue result = getter(callFrame, slotBase, ident);
1625 if (callFrame->hadException())
1626 returnToThrowTrampoline(&callFrame->globalData(), stackFrame.args[3].returnAddress(), STUB_RETURN_ADDRESS);
1627
1628 return JSValue::encode(result);
1629 }
1630
1631 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
1632 {
1633 STUB_INIT_STACK_FRAME(stackFrame);
1634
1635 CallFrame* callFrame = stackFrame.callFrame;
1636 const Identifier& propertyName = stackFrame.args[1].identifier();
1637
1638 JSValue baseValue = stackFrame.args[0].jsValue();
1639 PropertySlot slot(baseValue);
1640 JSValue result = baseValue.get(callFrame, propertyName, slot);
1641
1642 CHECK_FOR_EXCEPTION();
1643
1644 if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) {
1645 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1646 return JSValue::encode(result);
1647 }
1648
1649 Structure* structure = asCell(baseValue)->structure();
1650 CodeBlock* codeBlock = callFrame->codeBlock();
1651 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1652
1653 ASSERT(slot.slotBase().isObject());
1654 JSObject* slotBaseObject = asObject(slot.slotBase());
1655
1656 size_t offset = slot.cachedOffset();
1657
1658 if (slot.slotBase() == baseValue)
1659 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1660 else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
1661 ASSERT(!asCell(baseValue)->structure()->isDictionary());
1662 // Since we're accessing a prototype in a loop, it's a good bet that it
1663 // should not be treated as a dictionary.
1664 if (slotBaseObject->structure()->isDictionary()) {
1665 slotBaseObject->flattenDictionaryObject();
1666 offset = slotBaseObject->structure()->get(propertyName);
1667 }
1668
1669 int listIndex;
1670 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
1671 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
1672 JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), propertyName, slot, offset);
1673
1674 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1675 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
1676 }
1677 } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) {
1678 ASSERT(!asCell(baseValue)->structure()->isDictionary());
1679 int listIndex;
1680 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
1681
1682 if (listIndex < POLYMORPHIC_LIST_CACHE_SIZE) {
1683 StructureChain* protoChain = structure->prototypeChain(callFrame);
1684 JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, propertyName, slot, offset);
1685
1686 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1687 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
1688 }
1689 } else
1690 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1691
1692 return JSValue::encode(result);
1693 }
1694
1695 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list_full)
1696 {
1697 STUB_INIT_STACK_FRAME(stackFrame);
1698
1699 JSValue baseValue = stackFrame.args[0].jsValue();
1700 PropertySlot slot(baseValue);
1701 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1702
1703 CHECK_FOR_EXCEPTION_AT_END();
1704 return JSValue::encode(result);
1705 }
1706
1707 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_fail)
1708 {
1709 STUB_INIT_STACK_FRAME(stackFrame);
1710
1711 JSValue baseValue = stackFrame.args[0].jsValue();
1712 PropertySlot slot(baseValue);
1713 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1714
1715 CHECK_FOR_EXCEPTION_AT_END();
1716 return JSValue::encode(result);
1717 }
1718
1719 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_array_fail)
1720 {
1721 STUB_INIT_STACK_FRAME(stackFrame);
1722
1723 JSValue baseValue = stackFrame.args[0].jsValue();
1724 PropertySlot slot(baseValue);
1725 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1726
1727 CHECK_FOR_EXCEPTION_AT_END();
1728 return JSValue::encode(result);
1729 }
1730
1731 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail)
1732 {
1733 STUB_INIT_STACK_FRAME(stackFrame);
1734
1735 JSValue baseValue = stackFrame.args[0].jsValue();
1736 PropertySlot slot(baseValue);
1737 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1738
1739 CHECK_FOR_EXCEPTION_AT_END();
1740 return JSValue::encode(result);
1741 }
1742
1743 #endif // ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
1744
1745 DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof)
1746 {
1747 STUB_INIT_STACK_FRAME(stackFrame);
1748
1749 CallFrame* callFrame = stackFrame.callFrame;
1750 JSValue value = stackFrame.args[0].jsValue();
1751 JSValue baseVal = stackFrame.args[1].jsValue();
1752 JSValue proto = stackFrame.args[2].jsValue();
1753
1754 // At least one of these checks must have failed to get to the slow case.
1755 ASSERT(!value.isCell() || !baseVal.isCell() || !proto.isCell()
1756 || !value.isObject() || !baseVal.isObject() || !proto.isObject()
1757 || (asObject(baseVal)->structure()->typeInfo().flags() & (ImplementsHasInstance | OverridesHasInstance)) != ImplementsHasInstance);
1758
1759
1760 // ECMA-262 15.3.5.3:
1761 // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
1762 TypeInfo typeInfo(UnspecifiedType);
1763 if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) {
1764 CallFrame* callFrame = stackFrame.callFrame;
1765 CodeBlock* codeBlock = callFrame->codeBlock();
1766 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1767 stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, vPCIndex, codeBlock);
1768 VM_THROW_EXCEPTION();
1769 }
1770 ASSERT(typeInfo.type() != UnspecifiedType);
1771
1772 if (!typeInfo.overridesHasInstance()) {
1773 if (!value.isObject())
1774 return JSValue::encode(jsBoolean(false));
1775
1776 if (!proto.isObject()) {
1777 throwError(callFrame, TypeError, "instanceof called on an object with an invalid prototype property.");
1778 VM_THROW_EXCEPTION();
1779 }
1780 }
1781
1782 JSValue result = jsBoolean(asObject(baseVal)->hasInstance(callFrame, value, proto));
1783 CHECK_FOR_EXCEPTION_AT_END();
1784
1785 return JSValue::encode(result);
1786 }
1787
1788 DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id)
1789 {
1790 STUB_INIT_STACK_FRAME(stackFrame);
1791
1792 CallFrame* callFrame = stackFrame.callFrame;
1793
1794 JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame);
1795
1796 JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier()));
1797 CHECK_FOR_EXCEPTION_AT_END();
1798 return JSValue::encode(result);
1799 }
1800
1801 DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul)
1802 {
1803 STUB_INIT_STACK_FRAME(stackFrame);
1804
1805 JSValue src1 = stackFrame.args[0].jsValue();
1806 JSValue src2 = stackFrame.args[1].jsValue();
1807
1808 double left;
1809 double right;
1810 if (src1.getNumber(left) && src2.getNumber(right))
1811 return JSValue::encode(jsNumber(stackFrame.globalData, left * right));
1812
1813 CallFrame* callFrame = stackFrame.callFrame;
1814 JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) * src2.toNumber(callFrame));
1815 CHECK_FOR_EXCEPTION_AT_END();
1816 return JSValue::encode(result);
1817 }
1818
1819 DEFINE_STUB_FUNCTION(JSObject*, op_new_func)
1820 {
1821 STUB_INIT_STACK_FRAME(stackFrame);
1822
1823 return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scopeChain());
1824 }
1825
1826 DEFINE_STUB_FUNCTION(void*, op_call_JSFunction)
1827 {
1828 STUB_INIT_STACK_FRAME(stackFrame);
1829
1830 #if !ASSERT_DISABLED
1831 CallData callData;
1832 ASSERT(stackFrame.args[0].jsValue().getCallData(callData) == CallTypeJS);
1833 #endif
1834
1835 JSFunction* function = asFunction(stackFrame.args[0].jsValue());
1836 ASSERT(!function->isHostFunction());
1837 FunctionExecutable* executable = function->jsExecutable();
1838 ScopeChainNode* callDataScopeChain = function->scope().node();
1839 executable->jitCode(stackFrame.callFrame, callDataScopeChain);
1840
1841 return function;
1842 }
1843
1844 DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck)
1845 {
1846 STUB_INIT_STACK_FRAME(stackFrame);
1847
1848 CallFrame* callFrame = stackFrame.callFrame;
1849 JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
1850 ASSERT(!callee->isHostFunction());
1851 CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecode();
1852 int argCount = stackFrame.args[2].int32();
1853
1854 ASSERT(argCount != newCodeBlock->m_numParameters);
1855
1856 CallFrame* oldCallFrame = callFrame->callerFrame();
1857
1858 if (argCount > newCodeBlock->m_numParameters) {
1859 size_t numParameters = newCodeBlock->m_numParameters;
1860 Register* r = callFrame->registers() + numParameters;
1861 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
1862 if (!stackFrame.registerFile->grow(newEnd)) {
1863 // Rewind to the previous call frame because op_call already optimistically
1864 // moved the call frame forward.
1865 stackFrame.callFrame = oldCallFrame;
1866 throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS);
1867 RETURN_POINTER_PAIR(0, 0);
1868 }
1869
1870 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
1871 for (size_t i = 0; i < numParameters; ++i)
1872 argv[i + argCount] = argv[i];
1873
1874 callFrame = CallFrame::create(r);
1875 callFrame->setCallerFrame(oldCallFrame);
1876 } else {
1877 size_t omittedArgCount = newCodeBlock->m_numParameters - argCount;
1878 Register* r = callFrame->registers() + omittedArgCount;
1879 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
1880 if (!stackFrame.registerFile->grow(newEnd)) {
1881 // Rewind to the previous call frame because op_call already optimistically
1882 // moved the call frame forward.
1883 stackFrame.callFrame = oldCallFrame;
1884 throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS);
1885 RETURN_POINTER_PAIR(0, 0);
1886 }
1887
1888 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
1889 for (size_t i = 0; i < omittedArgCount; ++i)
1890 argv[i] = jsUndefined();
1891
1892 callFrame = CallFrame::create(r);
1893 callFrame->setCallerFrame(oldCallFrame);
1894 }
1895
1896 ASSERT((void*)callFrame <= stackFrame.registerFile->end());
1897 RETURN_POINTER_PAIR(callee, callFrame);
1898 }
1899
1900 #if ENABLE(JIT_OPTIMIZE_CALL)
1901 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall)
1902 {
1903 STUB_INIT_STACK_FRAME(stackFrame);
1904 JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
1905 ExecutableBase* executable = callee->executable();
1906 JITCode& jitCode = executable->generatedJITCode();
1907
1908 CodeBlock* codeBlock = 0;
1909 if (!executable->isHostFunction())
1910 codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecode(stackFrame.callFrame, callee->scope().node());
1911 CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress());
1912
1913 if (!callLinkInfo->seenOnce())
1914 callLinkInfo->setSeen();
1915 else
1916 JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32(), stackFrame.globalData);
1917
1918 return jitCode.addressForCall().executableAddress();
1919 }
1920 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
1921
1922 DEFINE_STUB_FUNCTION(JSObject*, op_push_activation)
1923 {
1924 STUB_INIT_STACK_FRAME(stackFrame);
1925
1926 JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable()));
1927 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->copy()->push(activation));
1928 return activation;
1929 }
1930
1931 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction)
1932 {
1933 STUB_INIT_STACK_FRAME(stackFrame);
1934
1935 JSValue funcVal = stackFrame.args[0].jsValue();
1936
1937 CallData callData;
1938 CallType callType = funcVal.getCallData(callData);
1939
1940 ASSERT(callType != CallTypeJS);
1941
1942 if (callType == CallTypeHost) {
1943 int registerOffset = stackFrame.args[1].int32();
1944 int argCount = stackFrame.args[2].int32();
1945 CallFrame* previousCallFrame = stackFrame.callFrame;
1946 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
1947
1948 callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0);
1949 stackFrame.callFrame = callFrame;
1950
1951 Register* argv = stackFrame.callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
1952 ArgList argList(argv + 1, argCount - 1);
1953
1954 JSValue returnValue;
1955 {
1956 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
1957
1958 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
1959 JSValue thisValue = argv[0].jsValue();
1960 if (thisValue == jsNull())
1961 thisValue = callFrame->globalThisValue();
1962
1963 returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList);
1964 }
1965 stackFrame.callFrame = previousCallFrame;
1966 CHECK_FOR_EXCEPTION();
1967
1968 return JSValue::encode(returnValue);
1969 }
1970
1971 ASSERT(callType == CallTypeNone);
1972
1973 CallFrame* callFrame = stackFrame.callFrame;
1974 CodeBlock* codeBlock = callFrame->codeBlock();
1975 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1976 stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal, vPCIndex, codeBlock);
1977 VM_THROW_EXCEPTION();
1978 }
1979
1980 DEFINE_STUB_FUNCTION(void, op_create_arguments)
1981 {
1982 STUB_INIT_STACK_FRAME(stackFrame);
1983
1984 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame);
1985 stackFrame.callFrame->setCalleeArguments(arguments);
1986 stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments);
1987 }
1988
1989 DEFINE_STUB_FUNCTION(void, op_create_arguments_no_params)
1990 {
1991 STUB_INIT_STACK_FRAME(stackFrame);
1992
1993 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters);
1994 stackFrame.callFrame->setCalleeArguments(arguments);
1995 stackFrame.callFrame[RegisterFile::ArgumentsRegister] = JSValue(arguments);
1996 }
1997
1998 DEFINE_STUB_FUNCTION(void, op_tear_off_activation)
1999 {
2000 STUB_INIT_STACK_FRAME(stackFrame);
2001
2002 ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain());
2003 asActivation(stackFrame.args[0].jsValue())->copyRegisters(stackFrame.callFrame->optionalCalleeArguments());
2004 }
2005
2006 DEFINE_STUB_FUNCTION(void, op_tear_off_arguments)
2007 {
2008 STUB_INIT_STACK_FRAME(stackFrame);
2009
2010 ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain());
2011 if (stackFrame.callFrame->optionalCalleeArguments())
2012 stackFrame.callFrame->optionalCalleeArguments()->copyRegisters();
2013 }
2014
2015 DEFINE_STUB_FUNCTION(void, op_profile_will_call)
2016 {
2017 STUB_INIT_STACK_FRAME(stackFrame);
2018
2019 ASSERT(*stackFrame.enabledProfilerReference);
2020 (*stackFrame.enabledProfilerReference)->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
2021 }
2022
2023 DEFINE_STUB_FUNCTION(void, op_profile_did_call)
2024 {
2025 STUB_INIT_STACK_FRAME(stackFrame);
2026
2027 ASSERT(*stackFrame.enabledProfilerReference);
2028 (*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
2029 }
2030
2031 DEFINE_STUB_FUNCTION(void, op_ret_scopeChain)
2032 {
2033 STUB_INIT_STACK_FRAME(stackFrame);
2034
2035 ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain());
2036 stackFrame.callFrame->scopeChain()->deref();
2037 }
2038
2039 DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
2040 {
2041 STUB_INIT_STACK_FRAME(stackFrame);
2042
2043 ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
2044 return constructArray(stackFrame.callFrame, argList);
2045 }
2046
2047 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
2048 {
2049 STUB_INIT_STACK_FRAME(stackFrame);
2050
2051 CallFrame* callFrame = stackFrame.callFrame;
2052 ScopeChainNode* scopeChain = callFrame->scopeChain();
2053
2054 ScopeChainIterator iter = scopeChain->begin();
2055 ScopeChainIterator end = scopeChain->end();
2056 ASSERT(iter != end);
2057
2058 Identifier& ident = stackFrame.args[0].identifier();
2059 do {
2060 JSObject* o = *iter;
2061 PropertySlot slot(o);
2062 if (o->getPropertySlot(callFrame, ident, slot)) {
2063 JSValue result = slot.getValue(callFrame, ident);
2064 CHECK_FOR_EXCEPTION_AT_END();
2065 return JSValue::encode(result);
2066 }
2067 } while (++iter != end);
2068
2069 CodeBlock* codeBlock = callFrame->codeBlock();
2070 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2071 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
2072 VM_THROW_EXCEPTION();
2073 }
2074
2075 DEFINE_STUB_FUNCTION(JSObject*, op_construct_JSConstruct)
2076 {
2077 STUB_INIT_STACK_FRAME(stackFrame);
2078
2079 JSFunction* constructor = asFunction(stackFrame.args[0].jsValue());
2080 if (constructor->isHostFunction()) {
2081 CallFrame* callFrame = stackFrame.callFrame;
2082 CodeBlock* codeBlock = callFrame->codeBlock();
2083 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2084 stackFrame.globalData->exception = createNotAConstructorError(callFrame, constructor, vPCIndex, codeBlock);
2085 VM_THROW_EXCEPTION();
2086 }
2087
2088 #if !ASSERT_DISABLED
2089 ConstructData constructData;
2090 ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
2091 #endif
2092
2093 Structure* structure;
2094 if (stackFrame.args[3].jsValue().isObject())
2095 structure = asObject(stackFrame.args[3].jsValue())->inheritorID();
2096 else
2097 structure = constructor->scope().node()->globalObject->emptyObjectStructure();
2098 return new (stackFrame.globalData) JSObject(structure);
2099 }
2100
2101 DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
2102 {
2103 STUB_INIT_STACK_FRAME(stackFrame);
2104
2105 CallFrame* callFrame = stackFrame.callFrame;
2106
2107 JSValue constrVal = stackFrame.args[0].jsValue();
2108 int argCount = stackFrame.args[2].int32();
2109 int thisRegister = stackFrame.args[4].int32();
2110
2111 ConstructData constructData;
2112 ConstructType constructType = constrVal.getConstructData(constructData);
2113
2114 if (constructType == ConstructTypeHost) {
2115 ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1);
2116
2117 JSValue returnValue;
2118 {
2119 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
2120 returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
2121 }
2122 CHECK_FOR_EXCEPTION();
2123
2124 return JSValue::encode(returnValue);
2125 }
2126
2127 ASSERT(constructType == ConstructTypeNone);
2128
2129 CodeBlock* codeBlock = callFrame->codeBlock();
2130 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2131 stackFrame.globalData->exception = createNotAConstructorError(callFrame, constrVal, vPCIndex, codeBlock);
2132 VM_THROW_EXCEPTION();
2133 }
2134
2135 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val)
2136 {
2137 STUB_INIT_STACK_FRAME(stackFrame);
2138
2139 CallFrame* callFrame = stackFrame.callFrame;
2140 JSGlobalData* globalData = stackFrame.globalData;
2141
2142 JSValue baseValue = stackFrame.args[0].jsValue();
2143 JSValue subscript = stackFrame.args[1].jsValue();
2144
2145 if (LIKELY(baseValue.isCell() && subscript.isString())) {
2146 Identifier propertyName(callFrame, asString(subscript)->value(callFrame));
2147 PropertySlot slot(asCell(baseValue));
2148 // JSString::value may have thrown, but we shouldn't find a property with a null identifier,
2149 // so we should miss this case and wind up in the CHECK_FOR_EXCEPTION_AT_END, below.
2150 if (asCell(baseValue)->fastGetOwnPropertySlot(callFrame, propertyName, slot)) {
2151 JSValue result = slot.getValue(callFrame, propertyName);
2152 CHECK_FOR_EXCEPTION();
2153 return JSValue::encode(result);
2154 }
2155 }
2156
2157 if (subscript.isUInt32()) {
2158 uint32_t i = subscript.asUInt32();
2159 if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) {
2160 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string));
2161 JSValue result = asString(baseValue)->getIndex(callFrame, i);
2162 CHECK_FOR_EXCEPTION();
2163 return JSValue::encode(result);
2164 }
2165 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2166 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2167 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array));
2168 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i));
2169 }
2170 JSValue result = baseValue.get(callFrame, i);
2171 CHECK_FOR_EXCEPTION();
2172 return JSValue::encode(result);
2173 }
2174
2175 Identifier property(callFrame, subscript.toString(callFrame));
2176 JSValue result = baseValue.get(callFrame, property);
2177 CHECK_FOR_EXCEPTION_AT_END();
2178 return JSValue::encode(result);
2179 }
2180
2181 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string)
2182 {
2183 STUB_INIT_STACK_FRAME(stackFrame);
2184
2185 CallFrame* callFrame = stackFrame.callFrame;
2186 JSGlobalData* globalData = stackFrame.globalData;
2187
2188 JSValue baseValue = stackFrame.args[0].jsValue();
2189 JSValue subscript = stackFrame.args[1].jsValue();
2190
2191 JSValue result;
2192
2193 if (LIKELY(subscript.isUInt32())) {
2194 uint32_t i = subscript.asUInt32();
2195 if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
2196 result = asString(baseValue)->getIndex(callFrame, i);
2197 else {
2198 result = baseValue.get(callFrame, i);
2199 if (!isJSString(globalData, baseValue))
2200 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val));
2201 }
2202 } else {
2203 Identifier property(callFrame, subscript.toString(callFrame));
2204 result = baseValue.get(callFrame, property);
2205 }
2206
2207 CHECK_FOR_EXCEPTION_AT_END();
2208 return JSValue::encode(result);
2209 }
2210
2211 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array)
2212 {
2213 STUB_INIT_STACK_FRAME(stackFrame);
2214
2215 CallFrame* callFrame = stackFrame.callFrame;
2216 JSGlobalData* globalData = stackFrame.globalData;
2217
2218 JSValue baseValue = stackFrame.args[0].jsValue();
2219 JSValue subscript = stackFrame.args[1].jsValue();
2220
2221 JSValue result;
2222
2223 if (LIKELY(subscript.isUInt32())) {
2224 uint32_t i = subscript.asUInt32();
2225 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2226 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2227 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i));
2228 }
2229
2230 result = baseValue.get(callFrame, i);
2231 if (!isJSByteArray(globalData, baseValue))
2232 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val));
2233 } else {
2234 Identifier property(callFrame, subscript.toString(callFrame));
2235 result = baseValue.get(callFrame, property);
2236 }
2237
2238 CHECK_FOR_EXCEPTION_AT_END();
2239 return JSValue::encode(result);
2240 }
2241
2242 DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub)
2243 {
2244 STUB_INIT_STACK_FRAME(stackFrame);
2245
2246 JSValue src1 = stackFrame.args[0].jsValue();
2247 JSValue src2 = stackFrame.args[1].jsValue();
2248
2249 double left;
2250 double right;
2251 if (src1.getNumber(left) && src2.getNumber(right))
2252 return JSValue::encode(jsNumber(stackFrame.globalData, left - right));
2253
2254 CallFrame* callFrame = stackFrame.callFrame;
2255 JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) - src2.toNumber(callFrame));
2256 CHECK_FOR_EXCEPTION_AT_END();
2257 return JSValue::encode(result);
2258 }
2259
2260 DEFINE_STUB_FUNCTION(void, op_put_by_val)
2261 {
2262 STUB_INIT_STACK_FRAME(stackFrame);
2263
2264 CallFrame* callFrame = stackFrame.callFrame;
2265 JSGlobalData* globalData = stackFrame.globalData;
2266
2267 JSValue baseValue = stackFrame.args[0].jsValue();
2268 JSValue subscript = stackFrame.args[1].jsValue();
2269 JSValue value = stackFrame.args[2].jsValue();
2270
2271 if (LIKELY(subscript.isUInt32())) {
2272 uint32_t i = subscript.asUInt32();
2273 if (isJSArray(globalData, baseValue)) {
2274 JSArray* jsArray = asArray(baseValue);
2275 if (jsArray->canSetIndex(i))
2276 jsArray->setIndex(i, value);
2277 else
2278 jsArray->JSArray::put(callFrame, i, value);
2279 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2280 JSByteArray* jsByteArray = asByteArray(baseValue);
2281 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array));
2282 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2283 if (value.isInt32()) {
2284 jsByteArray->setIndex(i, value.asInt32());
2285 return;
2286 } else {
2287 double dValue = 0;
2288 if (value.getNumber(dValue)) {
2289 jsByteArray->setIndex(i, dValue);
2290 return;
2291 }
2292 }
2293
2294 baseValue.put(callFrame, i, value);
2295 } else
2296 baseValue.put(callFrame, i, value);
2297 } else {
2298 Identifier property(callFrame, subscript.toString(callFrame));
2299 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
2300 PutPropertySlot slot;
2301 baseValue.put(callFrame, property, value, slot);
2302 }
2303 }
2304
2305 CHECK_FOR_EXCEPTION_AT_END();
2306 }
2307
2308 DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array)
2309 {
2310 STUB_INIT_STACK_FRAME(stackFrame);
2311
2312 CallFrame* callFrame = stackFrame.callFrame;
2313 JSGlobalData* globalData = stackFrame.globalData;
2314
2315 JSValue baseValue = stackFrame.args[0].jsValue();
2316 JSValue subscript = stackFrame.args[1].jsValue();
2317 JSValue value = stackFrame.args[2].jsValue();
2318
2319 if (LIKELY(subscript.isUInt32())) {
2320 uint32_t i = subscript.asUInt32();
2321 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2322 JSByteArray* jsByteArray = asByteArray(baseValue);
2323
2324 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2325 if (value.isInt32()) {
2326 jsByteArray->setIndex(i, value.asInt32());
2327 return;
2328 } else {
2329 double dValue = 0;
2330 if (value.getNumber(dValue)) {
2331 jsByteArray->setIndex(i, dValue);
2332 return;
2333 }
2334 }
2335 }
2336
2337 if (!isJSByteArray(globalData, baseValue))
2338 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val));
2339 baseValue.put(callFrame, i, value);
2340 } else {
2341 Identifier property(callFrame, subscript.toString(callFrame));
2342 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
2343 PutPropertySlot slot;
2344 baseValue.put(callFrame, property, value, slot);
2345 }
2346 }
2347
2348 CHECK_FOR_EXCEPTION_AT_END();
2349 }
2350
2351 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lesseq)
2352 {
2353 STUB_INIT_STACK_FRAME(stackFrame);
2354
2355 CallFrame* callFrame = stackFrame.callFrame;
2356 JSValue result = jsBoolean(jsLessEq(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue()));
2357 CHECK_FOR_EXCEPTION_AT_END();
2358 return JSValue::encode(result);
2359 }
2360
2361 DEFINE_STUB_FUNCTION(int, op_load_varargs)
2362 {
2363 STUB_INIT_STACK_FRAME(stackFrame);
2364
2365 CallFrame* callFrame = stackFrame.callFrame;
2366 RegisterFile* registerFile = stackFrame.registerFile;
2367 int argsOffset = stackFrame.args[0].int32();
2368 JSValue arguments = callFrame->registers()[argsOffset].jsValue();
2369 uint32_t argCount = 0;
2370 if (!arguments) {
2371 int providedParams = callFrame->registers()[RegisterFile::ArgumentCount].i() - 1;
2372 argCount = providedParams;
2373 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2374 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2375 Register* newEnd = callFrame->registers() + sizeDelta;
2376 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2377 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2378 VM_THROW_EXCEPTION();
2379 }
2380 int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount();
2381 int32_t inplaceArgs = min(providedParams, expectedParams);
2382
2383 Register* inplaceArgsDst = callFrame->registers() + argsOffset;
2384
2385 Register* inplaceArgsEnd = inplaceArgsDst + inplaceArgs;
2386 Register* inplaceArgsEnd2 = inplaceArgsDst + providedParams;
2387
2388 Register* inplaceArgsSrc = callFrame->registers() - RegisterFile::CallFrameHeaderSize - expectedParams;
2389 Register* inplaceArgsSrc2 = inplaceArgsSrc - providedParams - 1 + inplaceArgs;
2390
2391 // First step is to copy the "expected" parameters from their normal location relative to the callframe
2392 while (inplaceArgsDst < inplaceArgsEnd)
2393 *inplaceArgsDst++ = *inplaceArgsSrc++;
2394
2395 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
2396 while (inplaceArgsDst < inplaceArgsEnd2)
2397 *inplaceArgsDst++ = *inplaceArgsSrc2++;
2398
2399 } else if (!arguments.isUndefinedOrNull()) {
2400 if (!arguments.isObject()) {
2401 CodeBlock* codeBlock = callFrame->codeBlock();
2402 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2403 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock);
2404 VM_THROW_EXCEPTION();
2405 }
2406 if (asObject(arguments)->classInfo() == &Arguments::info) {
2407 Arguments* argsObject = asArguments(arguments);
2408 argCount = argsObject->numProvidedArguments(callFrame);
2409 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2410 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2411 Register* newEnd = callFrame->registers() + sizeDelta;
2412 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2413 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2414 VM_THROW_EXCEPTION();
2415 }
2416 argsObject->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
2417 } else if (isJSArray(&callFrame->globalData(), arguments)) {
2418 JSArray* array = asArray(arguments);
2419 argCount = array->length();
2420 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2421 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2422 Register* newEnd = callFrame->registers() + sizeDelta;
2423 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2424 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2425 VM_THROW_EXCEPTION();
2426 }
2427 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
2428 } else if (asObject(arguments)->inherits(&JSArray::info)) {
2429 JSObject* argObject = asObject(arguments);
2430 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
2431 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2432 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2433 Register* newEnd = callFrame->registers() + sizeDelta;
2434 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2435 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2436 VM_THROW_EXCEPTION();
2437 }
2438 Register* argsBuffer = callFrame->registers() + argsOffset;
2439 for (unsigned i = 0; i < argCount; ++i) {
2440 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
2441 CHECK_FOR_EXCEPTION();
2442 }
2443 } else {
2444 CodeBlock* codeBlock = callFrame->codeBlock();
2445 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2446 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock);
2447 VM_THROW_EXCEPTION();
2448 }
2449 }
2450
2451 return argCount + 1;
2452 }
2453
2454 DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate)
2455 {
2456 STUB_INIT_STACK_FRAME(stackFrame);
2457
2458 JSValue src = stackFrame.args[0].jsValue();
2459
2460 double v;
2461 if (src.getNumber(v))
2462 return JSValue::encode(jsNumber(stackFrame.globalData, -v));
2463
2464 CallFrame* callFrame = stackFrame.callFrame;
2465 JSValue result = jsNumber(stackFrame.globalData, -src.toNumber(callFrame));
2466 CHECK_FOR_EXCEPTION_AT_END();
2467 return JSValue::encode(result);
2468 }
2469
2470 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base)
2471 {
2472 STUB_INIT_STACK_FRAME(stackFrame);
2473
2474 return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain()));
2475 }
2476
2477 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip)
2478 {
2479 STUB_INIT_STACK_FRAME(stackFrame);
2480
2481 CallFrame* callFrame = stackFrame.callFrame;
2482 ScopeChainNode* scopeChain = callFrame->scopeChain();
2483
2484 int skip = stackFrame.args[1].int32();
2485
2486 ScopeChainIterator iter = scopeChain->begin();
2487 ScopeChainIterator end = scopeChain->end();
2488 ASSERT(iter != end);
2489 while (skip--) {
2490 ++iter;
2491 ASSERT(iter != end);
2492 }
2493 Identifier& ident = stackFrame.args[0].identifier();
2494 do {
2495 JSObject* o = *iter;
2496 PropertySlot slot(o);
2497 if (o->getPropertySlot(callFrame, ident, slot)) {
2498 JSValue result = slot.getValue(callFrame, ident);
2499 CHECK_FOR_EXCEPTION_AT_END();
2500 return JSValue::encode(result);
2501 }
2502 } while (++iter != end);
2503
2504 CodeBlock* codeBlock = callFrame->codeBlock();
2505 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2506 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
2507 VM_THROW_EXCEPTION();
2508 }
2509
2510 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
2511 {
2512 STUB_INIT_STACK_FRAME(stackFrame);
2513
2514 CallFrame* callFrame = stackFrame.callFrame;
2515 JSGlobalObject* globalObject = stackFrame.args[0].globalObject();
2516 Identifier& ident = stackFrame.args[1].identifier();
2517 unsigned globalResolveInfoIndex = stackFrame.args[2].int32();
2518 ASSERT(globalObject->isGlobalObject());
2519
2520 PropertySlot slot(globalObject);
2521 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
2522 JSValue result = slot.getValue(callFrame, ident);
2523 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
2524 GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex);
2525 if (globalResolveInfo.structure)
2526 globalResolveInfo.structure->deref();
2527 globalObject->structure()->ref();
2528 globalResolveInfo.structure = globalObject->structure();
2529 globalResolveInfo.offset = slot.cachedOffset();
2530 return JSValue::encode(result);
2531 }
2532
2533 CHECK_FOR_EXCEPTION_AT_END();
2534 return JSValue::encode(result);
2535 }
2536
2537 unsigned vPCIndex = callFrame->codeBlock()->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2538 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, callFrame->codeBlock());
2539 VM_THROW_EXCEPTION();
2540 }
2541
2542 DEFINE_STUB_FUNCTION(EncodedJSValue, op_div)
2543 {
2544 STUB_INIT_STACK_FRAME(stackFrame);
2545
2546 JSValue src1 = stackFrame.args[0].jsValue();
2547 JSValue src2 = stackFrame.args[1].jsValue();
2548
2549 double left;
2550 double right;
2551 if (src1.getNumber(left) && src2.getNumber(right))
2552 return JSValue::encode(jsNumber(stackFrame.globalData, left / right));
2553
2554 CallFrame* callFrame = stackFrame.callFrame;
2555 JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) / src2.toNumber(callFrame));
2556 CHECK_FOR_EXCEPTION_AT_END();
2557 return JSValue::encode(result);
2558 }
2559
2560 DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec)
2561 {
2562 STUB_INIT_STACK_FRAME(stackFrame);
2563
2564 JSValue v = stackFrame.args[0].jsValue();
2565
2566 CallFrame* callFrame = stackFrame.callFrame;
2567 JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) - 1);
2568 CHECK_FOR_EXCEPTION_AT_END();
2569 return JSValue::encode(result);
2570 }
2571
2572 DEFINE_STUB_FUNCTION(int, op_jless)
2573 {
2574 STUB_INIT_STACK_FRAME(stackFrame);
2575
2576 JSValue src1 = stackFrame.args[0].jsValue();
2577 JSValue src2 = stackFrame.args[1].jsValue();
2578 CallFrame* callFrame = stackFrame.callFrame;
2579
2580 bool result = jsLess(callFrame, src1, src2);
2581 CHECK_FOR_EXCEPTION_AT_END();
2582 return result;
2583 }
2584
2585 DEFINE_STUB_FUNCTION(int, op_jlesseq)
2586 {
2587 STUB_INIT_STACK_FRAME(stackFrame);
2588
2589 JSValue src1 = stackFrame.args[0].jsValue();
2590 JSValue src2 = stackFrame.args[1].jsValue();
2591 CallFrame* callFrame = stackFrame.callFrame;
2592
2593 bool result = jsLessEq(callFrame, src1, src2);
2594 CHECK_FOR_EXCEPTION_AT_END();
2595 return result;
2596 }
2597
2598 DEFINE_STUB_FUNCTION(EncodedJSValue, op_not)
2599 {
2600 STUB_INIT_STACK_FRAME(stackFrame);
2601
2602 JSValue src = stackFrame.args[0].jsValue();
2603
2604 CallFrame* callFrame = stackFrame.callFrame;
2605
2606 JSValue result = jsBoolean(!src.toBoolean(callFrame));
2607 CHECK_FOR_EXCEPTION_AT_END();
2608 return JSValue::encode(result);
2609 }
2610
2611 DEFINE_STUB_FUNCTION(int, op_jtrue)
2612 {
2613 STUB_INIT_STACK_FRAME(stackFrame);
2614
2615 JSValue src1 = stackFrame.args[0].jsValue();
2616
2617 CallFrame* callFrame = stackFrame.callFrame;
2618
2619 bool result = src1.toBoolean(callFrame);
2620 CHECK_FOR_EXCEPTION_AT_END();
2621 return result;
2622 }
2623
2624 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc)
2625 {
2626 STUB_INIT_STACK_FRAME(stackFrame);
2627
2628 JSValue v = stackFrame.args[0].jsValue();
2629
2630 CallFrame* callFrame = stackFrame.callFrame;
2631
2632 JSValue number = v.toJSNumber(callFrame);
2633 CHECK_FOR_EXCEPTION_AT_END();
2634
2635 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() + 1);
2636 return JSValue::encode(number);
2637 }
2638
2639 DEFINE_STUB_FUNCTION(int, op_eq)
2640 {
2641 STUB_INIT_STACK_FRAME(stackFrame);
2642
2643 JSValue src1 = stackFrame.args[0].jsValue();
2644 JSValue src2 = stackFrame.args[1].jsValue();
2645
2646 #if USE(JSVALUE32_64)
2647 start:
2648 if (src2.isUndefined()) {
2649 return src1.isNull() ||
2650 (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) ||
2651 src1.isUndefined();
2652 }
2653
2654 if (src2.isNull()) {
2655 return src1.isUndefined() ||
2656 (src1.isCell() && asCell(src1)->structure()->typeInfo().masqueradesAsUndefined()) ||
2657 src1.isNull();
2658 }
2659
2660 if (src1.isInt32()) {
2661 if (src2.isDouble())
2662 return src1.asInt32() == src2.asDouble();
2663 double d = src2.toNumber(stackFrame.callFrame);
2664 CHECK_FOR_EXCEPTION();
2665 return src1.asInt32() == d;
2666 }
2667
2668 if (src1.isDouble()) {
2669 if (src2.isInt32())
2670 return src1.asDouble() == src2.asInt32();
2671 double d = src2.toNumber(stackFrame.callFrame);
2672 CHECK_FOR_EXCEPTION();
2673 return src1.asDouble() == d;
2674 }
2675
2676 if (src1.isTrue()) {
2677 if (src2.isFalse())
2678 return false;
2679 double d = src2.toNumber(stackFrame.callFrame);
2680 CHECK_FOR_EXCEPTION();
2681 return d == 1.0;
2682 }
2683
2684 if (src1.isFalse()) {
2685 if (src2.isTrue())
2686 return false;
2687 double d = src2.toNumber(stackFrame.callFrame);
2688 CHECK_FOR_EXCEPTION();
2689 return d == 0.0;
2690 }
2691
2692 if (src1.isUndefined())
2693 return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined();
2694
2695 if (src1.isNull())
2696 return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined();
2697
2698 JSCell* cell1 = asCell(src1);
2699
2700 if (cell1->isString()) {
2701 if (src2.isInt32())
2702 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asInt32();
2703
2704 if (src2.isDouble())
2705 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asDouble();
2706
2707 if (src2.isTrue())
2708 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 1.0;
2709
2710 if (src2.isFalse())
2711 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 0.0;
2712
2713 JSCell* cell2 = asCell(src2);
2714 if (cell2->isString())
2715 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame) == static_cast<JSString*>(cell2)->value(stackFrame.callFrame);
2716
2717 src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame);
2718 CHECK_FOR_EXCEPTION();
2719 goto start;
2720 }
2721
2722 if (src2.isObject())
2723 return asObject(cell1) == asObject(src2);
2724 src1 = asObject(cell1)->toPrimitive(stackFrame.callFrame);
2725 CHECK_FOR_EXCEPTION();
2726 goto start;
2727
2728 #else // USE(JSVALUE32_64)
2729 CallFrame* callFrame = stackFrame.callFrame;
2730
2731 bool result = JSValue::equalSlowCaseInline(callFrame, src1, src2);
2732 CHECK_FOR_EXCEPTION_AT_END();
2733 return result;
2734 #endif // USE(JSVALUE32_64)
2735 }
2736
2737 DEFINE_STUB_FUNCTION(int, op_eq_strings)
2738 {
2739 #if USE(JSVALUE32_64)
2740 STUB_INIT_STACK_FRAME(stackFrame);
2741
2742 JSString* string1 = stackFrame.args[0].jsString();
2743 JSString* string2 = stackFrame.args[1].jsString();
2744
2745 ASSERT(string1->isString());
2746 ASSERT(string2->isString());
2747 return string1->value(stackFrame.callFrame) == string2->value(stackFrame.callFrame);
2748 #else
2749 UNUSED_PARAM(args);
2750 ASSERT_NOT_REACHED();
2751 return 0;
2752 #endif
2753 }
2754
2755 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift)
2756 {
2757 STUB_INIT_STACK_FRAME(stackFrame);
2758
2759 JSValue val = stackFrame.args[0].jsValue();
2760 JSValue shift = stackFrame.args[1].jsValue();
2761
2762 CallFrame* callFrame = stackFrame.callFrame;
2763 JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
2764 CHECK_FOR_EXCEPTION_AT_END();
2765 return JSValue::encode(result);
2766 }
2767
2768 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand)
2769 {
2770 STUB_INIT_STACK_FRAME(stackFrame);
2771
2772 JSValue src1 = stackFrame.args[0].jsValue();
2773 JSValue src2 = stackFrame.args[1].jsValue();
2774
2775 ASSERT(!src1.isInt32() || !src2.isInt32());
2776 CallFrame* callFrame = stackFrame.callFrame;
2777 JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) & src2.toInt32(callFrame));
2778 CHECK_FOR_EXCEPTION_AT_END();
2779 return JSValue::encode(result);
2780 }
2781
2782 DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift)
2783 {
2784 STUB_INIT_STACK_FRAME(stackFrame);
2785
2786 JSValue val = stackFrame.args[0].jsValue();
2787 JSValue shift = stackFrame.args[1].jsValue();
2788
2789 CallFrame* callFrame = stackFrame.callFrame;
2790 JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2791
2792 CHECK_FOR_EXCEPTION_AT_END();
2793 return JSValue::encode(result);
2794 }
2795
2796 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot)
2797 {
2798 STUB_INIT_STACK_FRAME(stackFrame);
2799
2800 JSValue src = stackFrame.args[0].jsValue();
2801
2802 ASSERT(!src.isInt32());
2803 CallFrame* callFrame = stackFrame.callFrame;
2804 JSValue result = jsNumber(stackFrame.globalData, ~src.toInt32(callFrame));
2805 CHECK_FOR_EXCEPTION_AT_END();
2806 return JSValue::encode(result);
2807 }
2808
2809 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base)
2810 {
2811 STUB_INIT_STACK_FRAME(stackFrame);
2812
2813 CallFrame* callFrame = stackFrame.callFrame;
2814 ScopeChainNode* scopeChain = callFrame->scopeChain();
2815
2816 ScopeChainIterator iter = scopeChain->begin();
2817 ScopeChainIterator end = scopeChain->end();
2818
2819 // FIXME: add scopeDepthIsZero optimization
2820
2821 ASSERT(iter != end);
2822
2823 Identifier& ident = stackFrame.args[0].identifier();
2824 JSObject* base;
2825 do {
2826 base = *iter;
2827 PropertySlot slot(base);
2828 if (base->getPropertySlot(callFrame, ident, slot)) {
2829 JSValue result = slot.getValue(callFrame, ident);
2830 CHECK_FOR_EXCEPTION_AT_END();
2831
2832 callFrame->registers()[stackFrame.args[1].int32()] = JSValue(base);
2833 return JSValue::encode(result);
2834 }
2835 ++iter;
2836 } while (iter != end);
2837
2838 CodeBlock* codeBlock = callFrame->codeBlock();
2839 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2840 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
2841 VM_THROW_EXCEPTION_AT_END();
2842 return JSValue::encode(JSValue());
2843 }
2844
2845 DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp)
2846 {
2847 STUB_INIT_STACK_FRAME(stackFrame);
2848 CallFrame* callFrame = stackFrame.callFrame;
2849
2850 FunctionExecutable* function = stackFrame.args[0].function();
2851 JSFunction* func = function->make(callFrame, callFrame->scopeChain());
2852
2853 /*
2854 The Identifier in a FunctionExpression can be referenced from inside
2855 the FunctionExpression's FunctionBody to allow the function to call
2856 itself recursively. However, unlike in a FunctionDeclaration, the
2857 Identifier in a FunctionExpression cannot be referenced from and
2858 does not affect the scope enclosing the FunctionExpression.
2859 */
2860 if (!function->name().isNull()) {
2861 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
2862 func->scope().push(functionScopeObject);
2863 }
2864
2865 return func;
2866 }
2867
2868 DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod)
2869 {
2870 STUB_INIT_STACK_FRAME(stackFrame);
2871
2872 JSValue dividendValue = stackFrame.args[0].jsValue();
2873 JSValue divisorValue = stackFrame.args[1].jsValue();
2874
2875 CallFrame* callFrame = stackFrame.callFrame;
2876 double d = dividendValue.toNumber(callFrame);
2877 JSValue result = jsNumber(stackFrame.globalData, fmod(d, divisorValue.toNumber(callFrame)));
2878 CHECK_FOR_EXCEPTION_AT_END();
2879 return JSValue::encode(result);
2880 }
2881
2882 DEFINE_STUB_FUNCTION(EncodedJSValue, op_less)
2883 {
2884 STUB_INIT_STACK_FRAME(stackFrame);
2885
2886 CallFrame* callFrame = stackFrame.callFrame;
2887 JSValue result = jsBoolean(jsLess(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue()));
2888 CHECK_FOR_EXCEPTION_AT_END();
2889 return JSValue::encode(result);
2890 }
2891
2892 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec)
2893 {
2894 STUB_INIT_STACK_FRAME(stackFrame);
2895
2896 JSValue v = stackFrame.args[0].jsValue();
2897
2898 CallFrame* callFrame = stackFrame.callFrame;
2899
2900 JSValue number = v.toJSNumber(callFrame);
2901 CHECK_FOR_EXCEPTION_AT_END();
2902
2903 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() - 1);
2904 return JSValue::encode(number);
2905 }
2906
2907 DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift)
2908 {
2909 STUB_INIT_STACK_FRAME(stackFrame);
2910
2911 JSValue val = stackFrame.args[0].jsValue();
2912 JSValue shift = stackFrame.args[1].jsValue();
2913
2914 CallFrame* callFrame = stackFrame.callFrame;
2915 JSValue result = jsNumber(stackFrame.globalData, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2916 CHECK_FOR_EXCEPTION_AT_END();
2917 return JSValue::encode(result);
2918 }
2919
2920 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor)
2921 {
2922 STUB_INIT_STACK_FRAME(stackFrame);
2923
2924 JSValue src1 = stackFrame.args[0].jsValue();
2925 JSValue src2 = stackFrame.args[1].jsValue();
2926
2927 CallFrame* callFrame = stackFrame.callFrame;
2928
2929 JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
2930 CHECK_FOR_EXCEPTION_AT_END();
2931 return JSValue::encode(result);
2932 }
2933
2934 DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp)
2935 {
2936 STUB_INIT_STACK_FRAME(stackFrame);
2937
2938 return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), stackFrame.args[0].regExp());
2939 }
2940
2941 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor)
2942 {
2943 STUB_INIT_STACK_FRAME(stackFrame);
2944
2945 JSValue src1 = stackFrame.args[0].jsValue();
2946 JSValue src2 = stackFrame.args[1].jsValue();
2947
2948 CallFrame* callFrame = stackFrame.callFrame;
2949
2950 JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) | src2.toInt32(callFrame));
2951 CHECK_FOR_EXCEPTION_AT_END();
2952 return JSValue::encode(result);
2953 }
2954
2955 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval)
2956 {
2957 STUB_INIT_STACK_FRAME(stackFrame);
2958
2959 CallFrame* callFrame = stackFrame.callFrame;
2960 RegisterFile* registerFile = stackFrame.registerFile;
2961
2962 Interpreter* interpreter = stackFrame.globalData->interpreter;
2963
2964 JSValue funcVal = stackFrame.args[0].jsValue();
2965 int registerOffset = stackFrame.args[1].int32();
2966 int argCount = stackFrame.args[2].int32();
2967
2968 Register* newCallFrame = callFrame->registers() + registerOffset;
2969 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
2970 JSValue thisValue = argv[0].jsValue();
2971 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject;
2972
2973 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
2974 JSValue exceptionValue;
2975 JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
2976 if (UNLIKELY(exceptionValue)) {
2977 stackFrame.globalData->exception = exceptionValue;
2978 VM_THROW_EXCEPTION_AT_END();
2979 }
2980 return JSValue::encode(result);
2981 }
2982
2983 return JSValue::encode(JSValue());
2984 }
2985
2986 DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw)
2987 {
2988 STUB_INIT_STACK_FRAME(stackFrame);
2989
2990 CallFrame* callFrame = stackFrame.callFrame;
2991 CodeBlock* codeBlock = callFrame->codeBlock();
2992
2993 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2994
2995 JSValue exceptionValue = stackFrame.args[0].jsValue();
2996 ASSERT(exceptionValue);
2997
2998 HandlerInfo* handler = stackFrame.globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, true);
2999
3000 if (!handler) {
3001 *stackFrame.exception = exceptionValue;
3002 STUB_SET_RETURN_ADDRESS(FunctionPtr(ctiOpThrowNotCaught).value());
3003 return JSValue::encode(jsNull());
3004 }
3005
3006 stackFrame.callFrame = callFrame;
3007 void* catchRoutine = handler->nativeCode.executableAddress();
3008 ASSERT(catchRoutine);
3009 STUB_SET_RETURN_ADDRESS(catchRoutine);
3010 return JSValue::encode(exceptionValue);
3011 }
3012
3013 DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames)
3014 {
3015 STUB_INIT_STACK_FRAME(stackFrame);
3016
3017 CallFrame* callFrame = stackFrame.callFrame;
3018 JSObject* o = stackFrame.args[0].jsObject();
3019 Structure* structure = o->structure();
3020 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
3021 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
3022 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
3023 return jsPropertyNameIterator;
3024 }
3025
3026 DEFINE_STUB_FUNCTION(int, has_property)
3027 {
3028 STUB_INIT_STACK_FRAME(stackFrame);
3029
3030 JSObject* base = stackFrame.args[0].jsObject();
3031 JSString* property = stackFrame.args[1].jsString();
3032 int result = base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value(stackFrame.callFrame)));
3033 CHECK_FOR_EXCEPTION_AT_END();
3034 return result;
3035 }
3036
3037 DEFINE_STUB_FUNCTION(JSObject*, op_push_scope)
3038 {
3039 STUB_INIT_STACK_FRAME(stackFrame);
3040
3041 JSObject* o = stackFrame.args[0].jsValue().toObject(stackFrame.callFrame);
3042 CHECK_FOR_EXCEPTION();
3043 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(o));
3044 return o;
3045 }
3046
3047 DEFINE_STUB_FUNCTION(void, op_pop_scope)
3048 {
3049 STUB_INIT_STACK_FRAME(stackFrame);
3050
3051 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->pop());
3052 }
3053
3054 DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof)
3055 {
3056 STUB_INIT_STACK_FRAME(stackFrame);
3057
3058 return JSValue::encode(jsTypeStringForValue(stackFrame.callFrame, stackFrame.args[0].jsValue()));
3059 }
3060
3061 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_undefined)
3062 {
3063 STUB_INIT_STACK_FRAME(stackFrame);
3064
3065 JSValue v = stackFrame.args[0].jsValue();
3066 return JSValue::encode(jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined()));
3067 }
3068
3069 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_boolean)
3070 {
3071 STUB_INIT_STACK_FRAME(stackFrame);
3072
3073 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isBoolean()));
3074 }
3075
3076 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_number)
3077 {
3078 STUB_INIT_STACK_FRAME(stackFrame);
3079
3080 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isNumber()));
3081 }
3082
3083 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_string)
3084 {
3085 STUB_INIT_STACK_FRAME(stackFrame);
3086
3087 return JSValue::encode(jsBoolean(isJSString(stackFrame.globalData, stackFrame.args[0].jsValue())));
3088 }
3089
3090 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_object)
3091 {
3092 STUB_INIT_STACK_FRAME(stackFrame);
3093
3094 return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame.args[0].jsValue())));
3095 }
3096
3097 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_function)
3098 {
3099 STUB_INIT_STACK_FRAME(stackFrame);
3100
3101 return JSValue::encode(jsBoolean(jsIsFunctionType(stackFrame.args[0].jsValue())));
3102 }
3103
3104 DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq)
3105 {
3106 STUB_INIT_STACK_FRAME(stackFrame);
3107
3108 JSValue src1 = stackFrame.args[0].jsValue();
3109 JSValue src2 = stackFrame.args[1].jsValue();
3110
3111 bool result = JSValue::strictEqual(stackFrame.callFrame, src1, src2);
3112 CHECK_FOR_EXCEPTION_AT_END();
3113 return JSValue::encode(jsBoolean(result));
3114 }
3115
3116 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive)
3117 {
3118 STUB_INIT_STACK_FRAME(stackFrame);
3119
3120 return JSValue::encode(stackFrame.args[0].jsValue().toPrimitive(stackFrame.callFrame));
3121 }
3122
3123 DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat)
3124 {
3125 STUB_INIT_STACK_FRAME(stackFrame);
3126
3127 JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
3128 CHECK_FOR_EXCEPTION_AT_END();
3129 return JSValue::encode(result);
3130 }
3131
3132 DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq)
3133 {
3134 STUB_INIT_STACK_FRAME(stackFrame);
3135
3136 JSValue src1 = stackFrame.args[0].jsValue();
3137 JSValue src2 = stackFrame.args[1].jsValue();
3138
3139 bool result = !JSValue::strictEqual(stackFrame.callFrame, src1, src2);
3140 CHECK_FOR_EXCEPTION_AT_END();
3141 return JSValue::encode(jsBoolean(result));
3142 }
3143
3144 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber)
3145 {
3146 STUB_INIT_STACK_FRAME(stackFrame);
3147
3148 JSValue src = stackFrame.args[0].jsValue();
3149 CallFrame* callFrame = stackFrame.callFrame;
3150
3151 JSValue result = src.toJSNumber(callFrame);
3152 CHECK_FOR_EXCEPTION_AT_END();
3153 return JSValue::encode(result);
3154 }
3155
3156 DEFINE_STUB_FUNCTION(EncodedJSValue, op_in)
3157 {
3158 STUB_INIT_STACK_FRAME(stackFrame);
3159
3160 CallFrame* callFrame = stackFrame.callFrame;
3161 JSValue baseVal = stackFrame.args[1].jsValue();
3162
3163 if (!baseVal.isObject()) {
3164 CallFrame* callFrame = stackFrame.callFrame;
3165 CodeBlock* codeBlock = callFrame->codeBlock();
3166 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
3167 stackFrame.globalData->exception = createInvalidParamError(callFrame, "in", baseVal, vPCIndex, codeBlock);
3168 VM_THROW_EXCEPTION();
3169 }
3170
3171 JSValue propName = stackFrame.args[0].jsValue();
3172 JSObject* baseObj = asObject(baseVal);
3173
3174 uint32_t i;
3175 if (propName.getUInt32(i))
3176 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i)));
3177
3178 Identifier property(callFrame, propName.toString(callFrame));
3179 CHECK_FOR_EXCEPTION();
3180 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property)));
3181 }
3182
3183 DEFINE_STUB_FUNCTION(JSObject*, op_push_new_scope)
3184 {
3185 STUB_INIT_STACK_FRAME(stackFrame);
3186
3187 JSObject* scope = new (stackFrame.globalData) JSStaticScopeObject(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].jsValue(), DontDelete);
3188
3189 CallFrame* callFrame = stackFrame.callFrame;
3190 callFrame->setScopeChain(callFrame->scopeChain()->push(scope));
3191 return scope;
3192 }
3193
3194 DEFINE_STUB_FUNCTION(void, op_jmp_scopes)
3195 {
3196 STUB_INIT_STACK_FRAME(stackFrame);
3197
3198 unsigned count = stackFrame.args[0].int32();
3199 CallFrame* callFrame = stackFrame.callFrame;
3200
3201 ScopeChainNode* tmp = callFrame->scopeChain();
3202 while (count--)
3203 tmp = tmp->pop();
3204 callFrame->setScopeChain(tmp);
3205 }
3206
3207 DEFINE_STUB_FUNCTION(void, op_put_by_index)
3208 {
3209 STUB_INIT_STACK_FRAME(stackFrame);
3210
3211 CallFrame* callFrame = stackFrame.callFrame;
3212 unsigned property = stackFrame.args[1].int32();
3213
3214 stackFrame.args[0].jsValue().put(callFrame, property, stackFrame.args[2].jsValue());
3215 }
3216
3217 DEFINE_STUB_FUNCTION(void*, op_switch_imm)
3218 {
3219 STUB_INIT_STACK_FRAME(stackFrame);
3220
3221 JSValue scrutinee = stackFrame.args[0].jsValue();
3222 unsigned tableIndex = stackFrame.args[1].int32();
3223 CallFrame* callFrame = stackFrame.callFrame;
3224 CodeBlock* codeBlock = callFrame->codeBlock();
3225
3226 if (scrutinee.isInt32())
3227 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.asInt32()).executableAddress();
3228 else {
3229 double value;
3230 int32_t intValue;
3231 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
3232 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(intValue).executableAddress();
3233 else
3234 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3235 }
3236 }
3237
3238 DEFINE_STUB_FUNCTION(void*, op_switch_char)
3239 {
3240 STUB_INIT_STACK_FRAME(stackFrame);
3241
3242 JSValue scrutinee = stackFrame.args[0].jsValue();
3243 unsigned tableIndex = stackFrame.args[1].int32();
3244 CallFrame* callFrame = stackFrame.callFrame;
3245 CodeBlock* codeBlock = callFrame->codeBlock();
3246
3247 void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3248
3249 if (scrutinee.isString()) {
3250 UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
3251 if (value->length() == 1)
3252 result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->characters()[0]).executableAddress();
3253 }
3254
3255 CHECK_FOR_EXCEPTION_AT_END();
3256 return result;
3257 }
3258
3259 DEFINE_STUB_FUNCTION(void*, op_switch_string)
3260 {
3261 STUB_INIT_STACK_FRAME(stackFrame);
3262
3263 JSValue scrutinee = stackFrame.args[0].jsValue();
3264 unsigned tableIndex = stackFrame.args[1].int32();
3265 CallFrame* callFrame = stackFrame.callFrame;
3266 CodeBlock* codeBlock = callFrame->codeBlock();
3267
3268 void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3269
3270 if (scrutinee.isString()) {
3271 UString::Rep* value = asString(scrutinee)->value(callFrame).rep();
3272 result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress();
3273 }
3274
3275 CHECK_FOR_EXCEPTION_AT_END();
3276 return result;
3277 }
3278
3279 DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val)
3280 {
3281 STUB_INIT_STACK_FRAME(stackFrame);
3282
3283 CallFrame* callFrame = stackFrame.callFrame;
3284
3285 JSValue baseValue = stackFrame.args[0].jsValue();
3286 JSObject* baseObj = baseValue.toObject(callFrame); // may throw
3287
3288 JSValue subscript = stackFrame.args[1].jsValue();
3289 JSValue result;
3290 uint32_t i;
3291 if (subscript.getUInt32(i))
3292 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
3293 else {
3294 CHECK_FOR_EXCEPTION();
3295 Identifier property(callFrame, subscript.toString(callFrame));
3296 CHECK_FOR_EXCEPTION();
3297 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
3298 }
3299
3300 CHECK_FOR_EXCEPTION_AT_END();
3301 return JSValue::encode(result);
3302 }
3303
3304 DEFINE_STUB_FUNCTION(void, op_put_getter)
3305 {
3306 STUB_INIT_STACK_FRAME(stackFrame);
3307
3308 CallFrame* callFrame = stackFrame.callFrame;
3309
3310 ASSERT(stackFrame.args[0].jsValue().isObject());
3311 JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
3312 ASSERT(stackFrame.args[2].jsValue().isObject());
3313 baseObj->defineGetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()));
3314 }
3315
3316 DEFINE_STUB_FUNCTION(void, op_put_setter)
3317 {
3318 STUB_INIT_STACK_FRAME(stackFrame);
3319
3320 CallFrame* callFrame = stackFrame.callFrame;
3321
3322 ASSERT(stackFrame.args[0].jsValue().isObject());
3323 JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
3324 ASSERT(stackFrame.args[2].jsValue().isObject());
3325 baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()));
3326 }
3327
3328 DEFINE_STUB_FUNCTION(JSObject*, op_new_error)
3329 {
3330 STUB_INIT_STACK_FRAME(stackFrame);
3331
3332 CallFrame* callFrame = stackFrame.callFrame;
3333 CodeBlock* codeBlock = callFrame->codeBlock();
3334 unsigned type = stackFrame.args[0].int32();
3335 JSValue message = stackFrame.args[1].jsValue();
3336 unsigned bytecodeOffset = stackFrame.args[2].int32();
3337
3338 unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
3339 return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL());
3340 }
3341
3342 DEFINE_STUB_FUNCTION(void, op_debug)
3343 {
3344 STUB_INIT_STACK_FRAME(stackFrame);
3345
3346 CallFrame* callFrame = stackFrame.callFrame;
3347
3348 int debugHookID = stackFrame.args[0].int32();
3349 int firstLine = stackFrame.args[1].int32();
3350 int lastLine = stackFrame.args[2].int32();
3351
3352 stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3353 }
3354
3355 DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw)
3356 {
3357 STUB_INIT_STACK_FRAME(stackFrame);
3358
3359 CallFrame* callFrame = stackFrame.callFrame;
3360 CodeBlock* codeBlock = callFrame->codeBlock();
3361 JSGlobalData* globalData = stackFrame.globalData;
3362
3363 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, globalData->exceptionLocation);
3364
3365 JSValue exceptionValue = globalData->exception;
3366 ASSERT(exceptionValue);
3367 globalData->exception = JSValue();
3368
3369 HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, false);
3370
3371 if (!handler) {
3372 *stackFrame.exception = exceptionValue;
3373 return JSValue::encode(jsNull());
3374 }
3375
3376 stackFrame.callFrame = callFrame;
3377 void* catchRoutine = handler->nativeCode.executableAddress();
3378 ASSERT(catchRoutine);
3379 STUB_SET_RETURN_ADDRESS(catchRoutine);
3380 return JSValue::encode(exceptionValue);
3381 }
3382
3383 DEFINE_STUB_FUNCTION(EncodedJSValue, to_object)
3384 {
3385 STUB_INIT_STACK_FRAME(stackFrame);
3386
3387 CallFrame* callFrame = stackFrame.callFrame;
3388 return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame));
3389 }
3390
3391 NativeExecutable* JITThunks::specializedThunk(JSGlobalData* globalData, ThunkGenerator generator)
3392 {
3393 std::pair<ThunkMap::iterator, bool> entry = m_thunkMap.add(generator, 0);
3394 if (!entry.second)
3395 return entry.first->second.get();
3396 entry.first->second = generator(globalData, m_executablePool.get());
3397 return entry.first->second.get();
3398 }
3399
3400 } // namespace JSC
3401
3402 #endif // ENABLE(JIT)