2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 * Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 #include "CommonSlowPaths.h"
37 #include "Arguments.h"
38 #include "CallFrame.h"
39 #include "CodeBlock.h"
40 #include "CodeProfiling.h"
41 #include "DFGOSREntry.h"
43 #include "ExceptionHelpers.h"
44 #include "GetterSetter.h"
46 #include <wtf/InlineASM.h>
48 #include "JITExceptions.h"
49 #include "JSActivation.h"
51 #include "JSFunction.h"
52 #include "JSGlobalObjectFunctions.h"
53 #include "JSNotAnObject.h"
54 #include "JSPropertyNameIterator.h"
55 #include "JSStaticScopeObject.h"
57 #include "ObjectPrototype.h"
58 #include "Operations.h"
61 #include "RegExpObject.h"
62 #include "RegExpPrototype.h"
64 #include "SamplingTool.h"
66 #include <wtf/StdLibExtras.h>
76 #if COMPILER(GCC) && CPU(X86)
78 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
79 // need to change the assembly trampolines below to match.
80 COMPILE_ASSERT(offsetof(struct JITStackFrame
, code
) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment
);
81 COMPILE_ASSERT(offsetof(struct JITStackFrame
, savedEBX
) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline
);
82 COMPILE_ASSERT(offsetof(struct JITStackFrame
, callFrame
) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline
);
83 COMPILE_ASSERT(offsetof(struct JITStackFrame
, code
) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline
);
87 ".globl " SYMBOL_STRING(ctiTrampoline
) "\n"
88 HIDE_SYMBOL(ctiTrampoline
) "\n"
89 SYMBOL_STRING(ctiTrampoline
) ":" "\n"
91 "movl %esp, %ebp" "\n"
95 "subl $0x3c, %esp" "\n"
96 "movl 0x58(%esp), %edi" "\n"
97 "call *0x50(%esp)" "\n"
98 "addl $0x3c, %esp" "\n"
104 ".globl " SYMBOL_STRING(ctiTrampolineEnd
) "\n"
105 HIDE_SYMBOL(ctiTrampolineEnd
) "\n"
106 SYMBOL_STRING(ctiTrampolineEnd
) ":" "\n"
110 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
111 HIDE_SYMBOL(ctiVMThrowTrampoline
) "\n"
112 SYMBOL_STRING(ctiVMThrowTrampoline
) ":" "\n"
113 "movl %esp, %ecx" "\n"
114 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw
) "\n"
119 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
120 HIDE_SYMBOL(ctiOpThrowNotCaught
) "\n"
121 SYMBOL_STRING(ctiOpThrowNotCaught
) ":" "\n"
122 "addl $0x3c, %esp" "\n"
130 #elif COMPILER(GCC) && CPU(X86_64)
132 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
133 // need to change the assembly trampolines below to match.
134 COMPILE_ASSERT(offsetof(struct JITStackFrame
, code
) % 32 == 0x0, JITStackFrame_maintains_32byte_stack_alignment
);
135 COMPILE_ASSERT(offsetof(struct JITStackFrame
, savedRBX
) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline
);
136 COMPILE_ASSERT(offsetof(struct JITStackFrame
, callFrame
) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline
);
137 COMPILE_ASSERT(offsetof(struct JITStackFrame
, code
) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline
);
140 ".globl " SYMBOL_STRING(ctiTrampoline
) "\n"
141 HIDE_SYMBOL(ctiTrampoline
) "\n"
142 SYMBOL_STRING(ctiTrampoline
) ":" "\n"
144 "movq %rsp, %rbp" "\n"
150 "subq $0x48, %rsp" "\n"
151 "movq $512, %r12" "\n"
152 "movq $0xFFFF000000000000, %r14" "\n"
153 "movq $0xFFFF000000000002, %r15" "\n"
154 "movq 0x90(%rsp), %r13" "\n"
155 "call *0x80(%rsp)" "\n"
156 "addq $0x48, %rsp" "\n"
164 ".globl " SYMBOL_STRING(ctiTrampolineEnd
) "\n"
165 HIDE_SYMBOL(ctiTrampolineEnd
) "\n"
166 SYMBOL_STRING(ctiTrampolineEnd
) ":" "\n"
170 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
171 HIDE_SYMBOL(ctiVMThrowTrampoline
) "\n"
172 SYMBOL_STRING(ctiVMThrowTrampoline
) ":" "\n"
173 "movq %rsp, %rdi" "\n"
174 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw
) "\n"
179 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
180 HIDE_SYMBOL(ctiOpThrowNotCaught
) "\n"
181 SYMBOL_STRING(ctiOpThrowNotCaught
) ":" "\n"
182 "addq $0x48, %rsp" "\n"
192 #elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_THUMB2)
194 #define THUNK_RETURN_ADDRESS_OFFSET 0x38
195 #define PRESERVED_RETURN_ADDRESS_OFFSET 0x3C
196 #define PRESERVED_R4_OFFSET 0x40
197 #define PRESERVED_R5_OFFSET 0x44
198 #define PRESERVED_R6_OFFSET 0x48
199 #define PRESERVED_R7_OFFSET 0x4C
200 #define PRESERVED_R8_OFFSET 0x50
201 #define PRESERVED_R9_OFFSET 0x54
202 #define PRESERVED_R10_OFFSET 0x58
203 #define PRESERVED_R11_OFFSET 0x5C
204 #define REGISTER_FILE_OFFSET 0x60
205 #define CALLFRAME_OFFSET 0x64
206 #define EXCEPTION_OFFSET 0x64
207 #define ENABLE_PROFILER_REFERENCE_OFFSET 0x68
209 #elif (COMPILER(GCC) || COMPILER(MSVC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL)
211 // Also update the MSVC section (defined at DEFINE_STUB_FUNCTION)
212 // when changing one of the following values.
213 #define THUNK_RETURN_ADDRESS_OFFSET 64
214 #define PRESERVEDR4_OFFSET 68
216 #elif COMPILER(MSVC) && CPU(X86)
218 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
219 // need to change the assembly trampolines below to match.
220 COMPILE_ASSERT(offsetof(struct JITStackFrame
, code
) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment
);
221 COMPILE_ASSERT(offsetof(struct JITStackFrame
, savedEBX
) == 0x3c, JITStackFrame_stub_argument_space_matches_ctiTrampoline
);
222 COMPILE_ASSERT(offsetof(struct JITStackFrame
, callFrame
) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline
);
223 COMPILE_ASSERT(offsetof(struct JITStackFrame
, code
) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline
);
227 __declspec(naked
) EncodedJSValue
ctiTrampoline(void* code
, RegisterFile
*, CallFrame
*, void* /*unused1*/, Profiler
**, JSGlobalData
*)
237 mov edi
, [esp
+ 0x58];
248 __declspec(naked
) void ctiVMThrowTrampoline()
262 __declspec(naked
) void ctiOpThrowNotCaught()
277 #define PRESERVED_GP_OFFSET 60
278 #define PRESERVED_S0_OFFSET 64
279 #define PRESERVED_S1_OFFSET 68
280 #define PRESERVED_S2_OFFSET 72
281 #define PRESERVED_RETURN_ADDRESS_OFFSET 76
282 #define THUNK_RETURN_ADDRESS_OFFSET 80
283 #define REGISTER_FILE_OFFSET 84
284 #define CALLFRAME_OFFSET 88
285 #define EXCEPTION_OFFSET 92
286 #define ENABLE_PROFILER_REFERENCE_OFFSET 96
287 #define GLOBAL_DATA_OFFSET 100
288 #define STACK_LENGTH 104
290 #define SYMBOL_STRING(name) #name
291 /* code (r4), RegisterFile* (r5), CallFrame* (r6), JSValue* exception (r7), Profiler**(sp), JSGlobalData (sp)*/
295 ".globl " SYMBOL_STRING(ctiTrampoline
) "\n"
296 HIDE_SYMBOL(ctiTrampoline
) "\n"
297 SYMBOL_STRING(ctiTrampoline
) ":" "\n"
298 "mov.l r7, @-r15" "\n"
299 "mov.l r6, @-r15" "\n"
300 "mov.l r5, @-r15" "\n"
301 "mov.l r8, @-r15" "\n"
303 "mov.l r14, @-r15" "\n"
304 "sts.l pr, @-r15" "\n"
305 "mov.l r13, @-r15" "\n"
306 "mov.l r11, @-r15" "\n"
307 "mov.l r10, @-r15" "\n"
313 "mov.l @r15+,r10" "\n"
314 "mov.l @r15+,r11" "\n"
315 "mov.l @r15+,r13" "\n"
316 "lds.l @r15+,pr" "\n"
317 "mov.l @r15+,r14" "\n"
318 "mov.l @r15+,r8" "\n"
325 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
326 HIDE_SYMBOL(ctiVMThrowTrampoline
) "\n"
327 SYMBOL_STRING(ctiVMThrowTrampoline
) ":" "\n"
328 "mov.l .L2"SYMBOL_STRING(cti_vm_throw
)",r0" "\n"
330 "mov.l @(r0,r12),r11" "\n"
334 "mov.l @r15+,r10" "\n"
335 "mov.l @r15+,r11" "\n"
336 "mov.l @r15+,r13" "\n"
337 "lds.l @r15+,pr" "\n"
338 "mov.l @r15+,r14" "\n"
339 "mov.l @r15+,r8" "\n"
344 ".L2"SYMBOL_STRING(cti_vm_throw
)":.long " SYMBOL_STRING(cti_vm_throw
)"@GOT \n"
348 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
349 HIDE_SYMBOL(ctiOpThrowNotCaught
) "\n"
350 SYMBOL_STRING(ctiOpThrowNotCaught
) ":" "\n"
352 "mov.l @r15+,r10" "\n"
353 "mov.l @r15+,r11" "\n"
354 "mov.l @r15+,r13" "\n"
355 "lds.l @r15+,pr" "\n"
356 "mov.l @r15+,r14" "\n"
357 "mov.l @r15+,r8" "\n"
363 #error "JIT not supported on this platform."
366 #else // USE(JSVALUE32_64)
368 #if COMPILER(GCC) && CPU(X86_64)
370 // These ASSERTs remind you that, if you change the layout of JITStackFrame, you
371 // need to change the assembly trampolines below to match.
372 COMPILE_ASSERT(offsetof(struct JITStackFrame
, callFrame
) == 0x58, JITStackFrame_callFrame_offset_matches_ctiTrampoline
);
373 COMPILE_ASSERT(offsetof(struct JITStackFrame
, code
) == 0x48, JITStackFrame_code_offset_matches_ctiTrampoline
);
374 COMPILE_ASSERT(offsetof(struct JITStackFrame
, savedRBX
) == 0x78, JITStackFrame_stub_argument_space_matches_ctiTrampoline
);
378 ".globl " SYMBOL_STRING(ctiTrampoline
) "\n"
379 HIDE_SYMBOL(ctiTrampoline
) "\n"
380 SYMBOL_STRING(ctiTrampoline
) ":" "\n"
382 "movq %rsp, %rbp" "\n"
388 // Form the JIT stubs area
395 "subq $0x48, %rsp" "\n"
396 "movq $512, %r12" "\n"
397 "movq $0xFFFF000000000000, %r14" "\n"
398 "movq $0xFFFF000000000002, %r15" "\n"
399 "movq %rdx, %r13" "\n"
401 "addq $0x78, %rsp" "\n"
409 ".globl " SYMBOL_STRING(ctiTrampolineEnd
) "\n"
410 HIDE_SYMBOL(ctiTrampolineEnd
) "\n"
411 SYMBOL_STRING(ctiTrampolineEnd
) ":" "\n"
415 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
416 HIDE_SYMBOL(ctiVMThrowTrampoline
) "\n"
417 SYMBOL_STRING(ctiVMThrowTrampoline
) ":" "\n"
418 "movq %rsp, %rdi" "\n"
419 "call " SYMBOL_STRING_RELOCATION(cti_vm_throw
) "\n"
424 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
425 HIDE_SYMBOL(ctiOpThrowNotCaught
) "\n"
426 SYMBOL_STRING(ctiOpThrowNotCaught
) ":" "\n"
427 "addq $0x78, %rsp" "\n"
438 #error "JIT not supported on this platform."
441 #endif // USE(JSVALUE32_64)
447 ".set noreorder" "\n"
450 ".globl " SYMBOL_STRING(ctiTrampoline
) "\n"
451 ".ent " SYMBOL_STRING(ctiTrampoline
) "\n"
452 SYMBOL_STRING(ctiTrampoline
) ":" "\n"
453 "addiu $29,$29,-" STRINGIZE_VALUE_OF(STACK_LENGTH
) "\n"
454 "sw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "($29)" "\n"
455 "sw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET
) "($29)" "\n"
456 "sw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET
) "($29)" "\n"
457 "sw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET
) "($29)" "\n"
459 "sw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET
) "($29)" "\n"
461 "move $16,$6 # set callFrameRegister" "\n"
462 "li $17,512 # set timeoutCheckRegister" "\n"
463 "move $25,$4 # move executableAddress to t9" "\n"
464 "sw $5," STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET
) "($29) # store registerFile to current stack" "\n"
465 "sw $6," STRINGIZE_VALUE_OF(CALLFRAME_OFFSET
) "($29) # store callFrame to curent stack" "\n"
466 "sw $7," STRINGIZE_VALUE_OF(EXCEPTION_OFFSET
) "($29) # store exception to current stack" "\n"
467 "lw $8," STRINGIZE_VALUE_OF(STACK_LENGTH
+ 16) "($29) # load enableProfilerReference from previous stack" "\n"
468 "lw $9," STRINGIZE_VALUE_OF(STACK_LENGTH
+ 20) "($29) # load globalData from previous stack" "\n"
469 "sw $8," STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET
) "($29) # store enableProfilerReference to current stack" "\n"
471 "sw $9," STRINGIZE_VALUE_OF(GLOBAL_DATA_OFFSET
) "($29) # store globalData to current stack" "\n"
472 "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET
) "($29)" "\n"
473 "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET
) "($29)" "\n"
474 "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET
) "($29)" "\n"
475 "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "($29)" "\n"
477 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH
) "\n"
480 ".end " SYMBOL_STRING(ctiTrampoline
) "\n"
486 ".set noreorder" "\n"
489 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
490 ".ent " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
491 SYMBOL_STRING(ctiVMThrowTrampoline
) ":" "\n"
493 "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET
) "($29)" "\n"
495 "la $25," SYMBOL_STRING(cti_vm_throw
) "\n"
497 "bal " SYMBOL_STRING(cti_vm_throw
) "\n"
500 "jal " SYMBOL_STRING(cti_vm_throw
) "\n"
503 "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET
) "($29)" "\n"
504 "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET
) "($29)" "\n"
505 "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET
) "($29)" "\n"
506 "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "($29)" "\n"
508 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH
) "\n"
511 ".end " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
517 ".set noreorder" "\n"
520 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
521 ".ent " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
522 SYMBOL_STRING(ctiOpThrowNotCaught
) ":" "\n"
523 "lw $16," STRINGIZE_VALUE_OF(PRESERVED_S0_OFFSET
) "($29)" "\n"
524 "lw $17," STRINGIZE_VALUE_OF(PRESERVED_S1_OFFSET
) "($29)" "\n"
525 "lw $18," STRINGIZE_VALUE_OF(PRESERVED_S2_OFFSET
) "($29)" "\n"
526 "lw $31," STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "($29)" "\n"
528 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH
) "\n"
531 ".end " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
535 #if COMPILER(GCC) && CPU(ARM_THUMB2)
540 ".globl " SYMBOL_STRING(ctiTrampoline
) "\n"
541 HIDE_SYMBOL(ctiTrampoline
) "\n"
543 ".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline
) "\n"
544 SYMBOL_STRING(ctiTrampoline
) ":" "\n"
545 "sub sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET
) "\n"
546 "str lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "]" "\n"
547 "str r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET
) "]" "\n"
548 "str r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET
) "]" "\n"
549 "str r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET
) "]" "\n"
550 "str r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET
) "]" "\n"
551 "str r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET
) "]" "\n"
552 "str r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET
) "]" "\n"
553 "str r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET
) "]" "\n"
554 "str r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET
) "]" "\n"
555 "str r1, [sp, #" STRINGIZE_VALUE_OF(REGISTER_FILE_OFFSET
) "]" "\n"
556 "str r2, [sp, #" STRINGIZE_VALUE_OF(CALLFRAME_OFFSET
) "]" "\n"
557 "str r3, [sp, #" STRINGIZE_VALUE_OF(EXCEPTION_OFFSET
) "]" "\n"
561 "ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET
) "]" "\n"
562 "ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET
) "]" "\n"
563 "ldr r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET
) "]" "\n"
564 "ldr r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET
) "]" "\n"
565 "ldr r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET
) "]" "\n"
566 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET
) "]" "\n"
567 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET
) "]" "\n"
568 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET
) "]" "\n"
569 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "]" "\n"
570 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET
) "\n"
573 ".globl " SYMBOL_STRING(ctiTrampolineEnd
) "\n"
574 HIDE_SYMBOL(ctiTrampolineEnd
) "\n"
576 ".thumb_func " THUMB_FUNC_PARAM(ctiTrampolineEnd
) "\n"
577 SYMBOL_STRING(ctiTrampolineEnd
) ":" "\n"
583 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
584 HIDE_SYMBOL(ctiVMThrowTrampoline
) "\n"
586 ".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline
) "\n"
587 SYMBOL_STRING(ctiVMThrowTrampoline
) ":" "\n"
589 "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw
) "\n"
590 "ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET
) "]" "\n"
591 "ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET
) "]" "\n"
592 "ldr r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET
) "]" "\n"
593 "ldr r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET
) "]" "\n"
594 "ldr r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET
) "]" "\n"
595 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET
) "]" "\n"
596 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET
) "]" "\n"
597 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET
) "]" "\n"
598 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "]" "\n"
599 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET
) "\n"
606 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
607 HIDE_SYMBOL(ctiOpThrowNotCaught
) "\n"
609 ".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught
) "\n"
610 SYMBOL_STRING(ctiOpThrowNotCaught
) ":" "\n"
611 "ldr r11, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R11_OFFSET
) "]" "\n"
612 "ldr r10, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R10_OFFSET
) "]" "\n"
613 "ldr r9, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R9_OFFSET
) "]" "\n"
614 "ldr r8, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R8_OFFSET
) "]" "\n"
615 "ldr r7, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R7_OFFSET
) "]" "\n"
616 "ldr r6, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R6_OFFSET
) "]" "\n"
617 "ldr r5, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R5_OFFSET
) "]" "\n"
618 "ldr r4, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_R4_OFFSET
) "]" "\n"
619 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(PRESERVED_RETURN_ADDRESS_OFFSET
) "]" "\n"
620 "add sp, sp, #" STRINGIZE_VALUE_OF(ENABLE_PROFILER_REFERENCE_OFFSET
) "\n"
624 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
627 ".globl " SYMBOL_STRING(ctiTrampoline
) "\n"
628 HIDE_SYMBOL(ctiTrampoline
) "\n"
629 SYMBOL_STRING(ctiTrampoline
) ":" "\n"
630 "stmdb sp!, {r1-r3}" "\n"
631 "stmdb sp!, {r4-r8, lr}" "\n"
632 "sub sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET
) "\n"
635 // r0 contains the code
638 "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET
) "\n"
639 "ldmia sp!, {r4-r8, lr}" "\n"
640 "add sp, sp, #12" "\n"
645 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline
) "\n"
646 HIDE_SYMBOL(ctiVMThrowTrampoline
) "\n"
647 SYMBOL_STRING(ctiVMThrowTrampoline
) ":" "\n"
649 "bl " SYMBOL_STRING(cti_vm_throw
) "\n"
651 // Both has the same return sequence
652 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught
) "\n"
653 HIDE_SYMBOL(ctiOpThrowNotCaught
) "\n"
654 SYMBOL_STRING(ctiOpThrowNotCaught
) ":" "\n"
655 "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET
) "\n"
656 "ldmia sp!, {r4-r8, lr}" "\n"
657 "add sp, sp, #12" "\n"
661 #elif COMPILER(RVCT) && CPU(ARM_THUMB2)
663 __asm EncodedJSValue
ctiTrampoline(void*, RegisterFile
*, CallFrame
*, JSValue
*, Profiler
**, JSGlobalData
*)
666 sub sp
, sp
, # ENABLE_PROFILER_REFERENCE_OFFSET
667 str lr
, [sp
, # PRESERVED_RETURN_ADDRESS_OFFSET ]
668 str r4
, [sp
, # PRESERVED_R4_OFFSET ]
669 str r5
, [sp
, # PRESERVED_R5_OFFSET ]
670 str r6
, [sp
, # PRESERVED_R6_OFFSET ]
671 str r7
, [sp
, # PRESERVED_R7_OFFSET ]
672 str r8
, [sp
, # PRESERVED_R8_OFFSET ]
673 str r9
, [sp
, # PRESERVED_R9_OFFSET ]
674 str r10
, [sp
, # PRESERVED_R10_OFFSET ]
675 str r11
, [sp
, # PRESERVED_R11_OFFSET ]
676 str r1
, [sp
, # REGISTER_FILE_OFFSET ]
677 str r2
, [sp
, # CALLFRAME_OFFSET ]
678 str r3
, [sp
, # EXCEPTION_OFFSET ]
682 ldr r11
, [sp
, # PRESERVED_R11_OFFSET ]
683 ldr r10
, [sp
, # PRESERVED_R10_OFFSET ]
684 ldr r9
, [sp
, # PRESERVED_R9_OFFSET ]
685 ldr r8
, [sp
, # PRESERVED_R8_OFFSET ]
686 ldr r7
, [sp
, # PRESERVED_R7_OFFSET ]
687 ldr r6
, [sp
, # PRESERVED_R6_OFFSET ]
688 ldr r5
, [sp
, # PRESERVED_R5_OFFSET ]
689 ldr r4
, [sp
, # PRESERVED_R4_OFFSET ]
690 ldr lr
, [sp
, # PRESERVED_RETURN_ADDRESS_OFFSET ]
691 add sp
, sp
, # ENABLE_PROFILER_REFERENCE_OFFSET
695 __asm
void ctiVMThrowTrampoline()
700 ldr r11
, [sp
, # PRESERVED_R11_OFFSET ]
701 ldr r10
, [sp
, # PRESERVED_R10_OFFSET ]
702 ldr r9
, [sp
, # PRESERVED_R9_OFFSET ]
703 ldr r8
, [sp
, # PRESERVED_R8_OFFSET ]
704 ldr r7
, [sp
, # PRESERVED_R7_OFFSET ]
705 ldr r6
, [sp
, # PRESERVED_R6_OFFSET ]
706 ldr r6
, [sp
, # PRESERVED_R6_OFFSET ]
707 ldr r5
, [sp
, # PRESERVED_R5_OFFSET ]
708 ldr r4
, [sp
, # PRESERVED_R4_OFFSET ]
709 ldr lr
, [sp
, # PRESERVED_RETURN_ADDRESS_OFFSET ]
710 add sp
, sp
, # ENABLE_PROFILER_REFERENCE_OFFSET
714 __asm
void ctiOpThrowNotCaught()
717 ldr r11
, [sp
, # PRESERVED_R11_OFFSET ]
718 ldr r10
, [sp
, # PRESERVED_R10_OFFSET ]
719 ldr r9
, [sp
, # PRESERVED_R9_OFFSET ]
720 ldr r8
, [sp
, # PRESERVED_R8_OFFSET ]
721 ldr r7
, [sp
, # PRESERVED_R7_OFFSET ]
722 ldr r6
, [sp
, # PRESERVED_R6_OFFSET ]
723 ldr r6
, [sp
, # PRESERVED_R6_OFFSET ]
724 ldr r5
, [sp
, # PRESERVED_R5_OFFSET ]
725 ldr r4
, [sp
, # PRESERVED_R4_OFFSET ]
726 ldr lr
, [sp
, # PRESERVED_RETURN_ADDRESS_OFFSET ]
727 add sp
, sp
, # ENABLE_PROFILER_REFERENCE_OFFSET
731 #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
733 __asm EncodedJSValue
ctiTrampoline(void*, RegisterFile
*, CallFrame
*, void* /*unused1*/, Profiler
**, JSGlobalData
*)
737 stmdb sp
!, {r4
-r8
, lr
}
738 sub sp
, sp
, # PRESERVEDR4_OFFSET
743 add sp
, sp
, # PRESERVEDR4_OFFSET
744 ldmia sp
!, {r4
-r8
, lr
}
749 __asm
void ctiVMThrowTrampoline()
755 add sp
, sp
, # PRESERVEDR4_OFFSET
756 ldmia sp
!, {r4
-r8
, lr
}
761 __asm
void ctiOpThrowNotCaught()
764 add sp
, sp
, # PRESERVEDR4_OFFSET
765 ldmia sp
!, {r4
-r8
, lr
}
771 #if ENABLE(OPCODE_SAMPLING)
772 #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler()
774 #define CTI_SAMPLER 0
777 JITThunks::JITThunks(JSGlobalData
* globalData
)
778 : m_hostFunctionStubMap(adoptPtr(new HostFunctionStubMap
))
780 if (!globalData
->canUseJIT())
783 m_executableMemory
= JIT::compileCTIMachineTrampolines(globalData
, &m_trampolineStructure
);
784 ASSERT(!!m_executableMemory
);
786 // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types),
787 // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT
789 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedReturnAddress
) == PRESERVED_RETURN_ADDRESS_OFFSET
);
790 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR4
) == PRESERVED_R4_OFFSET
);
791 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR5
) == PRESERVED_R5_OFFSET
);
792 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR6
) == PRESERVED_R6_OFFSET
);
793 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR7
) == PRESERVED_R7_OFFSET
);
794 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR8
) == PRESERVED_R8_OFFSET
);
795 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR9
) == PRESERVED_R9_OFFSET
);
796 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR10
) == PRESERVED_R10_OFFSET
);
797 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR11
) == PRESERVED_R11_OFFSET
);
799 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, registerFile
) == REGISTER_FILE_OFFSET
);
800 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, callFrame
) == CALLFRAME_OFFSET
);
801 // The fifth argument is the first item already on the stack.
802 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, enabledProfilerReference
) == ENABLE_PROFILER_REFERENCE_OFFSET
);
804 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, thunkReturnAddress
) == THUNK_RETURN_ADDRESS_OFFSET
);
806 #elif CPU(ARM_TRADITIONAL)
808 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, thunkReturnAddress
) == THUNK_RETURN_ADDRESS_OFFSET
);
809 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedR4
) == PRESERVEDR4_OFFSET
);
813 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedGP
) == PRESERVED_GP_OFFSET
);
814 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedS0
) == PRESERVED_S0_OFFSET
);
815 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedS1
) == PRESERVED_S1_OFFSET
);
816 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedS2
) == PRESERVED_S2_OFFSET
);
817 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, preservedReturnAddress
) == PRESERVED_RETURN_ADDRESS_OFFSET
);
818 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, thunkReturnAddress
) == THUNK_RETURN_ADDRESS_OFFSET
);
819 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, registerFile
) == REGISTER_FILE_OFFSET
);
820 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, callFrame
) == CALLFRAME_OFFSET
);
821 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, unused1
) == EXCEPTION_OFFSET
);
822 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, enabledProfilerReference
) == ENABLE_PROFILER_REFERENCE_OFFSET
);
823 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame
, globalData
) == GLOBAL_DATA_OFFSET
);
828 JITThunks::~JITThunks()
832 NEVER_INLINE
void JITThunks::tryCachePutByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, ReturnAddressPtr returnAddress
, JSValue baseValue
, const PutPropertySlot
& slot
, StructureStubInfo
* stubInfo
, bool direct
)
834 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
836 if (!baseValue
.isCell())
839 // Uncacheable: give up.
840 if (!slot
.isCacheable()) {
841 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(direct
? cti_op_put_by_id_direct_generic
: cti_op_put_by_id_generic
));
845 JSCell
* baseCell
= baseValue
.asCell();
846 Structure
* structure
= baseCell
->structure();
848 if (structure
->isUncacheableDictionary() || structure
->typeInfo().prohibitsPropertyCaching()) {
849 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(direct
? cti_op_put_by_id_direct_generic
: cti_op_put_by_id_generic
));
853 // If baseCell != base, then baseCell must be a proxy for another object.
854 if (baseCell
!= slot
.base()) {
855 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(direct
? cti_op_put_by_id_direct_generic
: cti_op_put_by_id_generic
));
859 // Cache hit: Specialize instruction and ref Structures.
861 // Structure transition, cache transition info
862 if (slot
.type() == PutPropertySlot::NewProperty
) {
863 if (structure
->isDictionary()) {
864 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(direct
? cti_op_put_by_id_direct_generic
: cti_op_put_by_id_generic
));
868 // put_by_id_transition checks the prototype chain for setters.
869 normalizePrototypeChain(callFrame
, baseCell
);
871 StructureChain
* prototypeChain
= structure
->prototypeChain(callFrame
);
872 stubInfo
->initPutByIdTransition(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
->previousID(), structure
, prototypeChain
, direct
);
873 JIT::compilePutByIdTransition(callFrame
->scopeChain()->globalData
, codeBlock
, stubInfo
, structure
->previousID(), structure
, slot
.cachedOffset(), prototypeChain
, returnAddress
, direct
);
877 stubInfo
->initPutByIdReplace(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
879 JIT::patchPutByIdReplace(codeBlock
, stubInfo
, structure
, slot
.cachedOffset(), returnAddress
, direct
);
882 NEVER_INLINE
void JITThunks::tryCacheGetByID(CallFrame
* callFrame
, CodeBlock
* codeBlock
, ReturnAddressPtr returnAddress
, JSValue baseValue
, const Identifier
& propertyName
, const PropertySlot
& slot
, StructureStubInfo
* stubInfo
)
884 // FIXME: Write a test that proves we need to check for recursion here just
885 // like the interpreter does, then add a check for recursion.
887 // FIXME: Cache property access for immediates.
888 if (!baseValue
.isCell()) {
889 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(cti_op_get_by_id_generic
));
893 JSGlobalData
* globalData
= &callFrame
->globalData();
895 if (isJSArray(baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
896 JIT::compilePatchGetArrayLength(callFrame
->scopeChain()->globalData
, codeBlock
, returnAddress
);
900 if (isJSString(baseValue
) && propertyName
== callFrame
->propertyNames().length
) {
901 // The tradeoff of compiling an patched inline string length access routine does not seem
902 // to pay off, so we currently only do this for arrays.
903 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, globalData
->jitStubs
->ctiStringLengthTrampoline());
907 // Uncacheable: give up.
908 if (!slot
.isCacheable()) {
909 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(cti_op_get_by_id_generic
));
913 JSCell
* baseCell
= baseValue
.asCell();
914 Structure
* structure
= baseCell
->structure();
916 if (structure
->isUncacheableDictionary() || structure
->typeInfo().prohibitsPropertyCaching()) {
917 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(cti_op_get_by_id_generic
));
921 // Cache hit: Specialize instruction and ref Structures.
923 if (slot
.slotBase() == baseValue
) {
924 // set this up, so derefStructures can do it's job.
925 stubInfo
->initGetByIdSelf(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
);
926 if ((slot
.cachedPropertyType() != PropertySlot::Value
) || ((slot
.cachedOffset() * sizeof(JSValue
)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset
))
927 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(cti_op_get_by_id_self_fail
));
929 JIT::patchGetByIdSelf(codeBlock
, stubInfo
, structure
, slot
.cachedOffset(), returnAddress
);
933 if (structure
->isDictionary()) {
934 ctiPatchCallByReturnAddress(codeBlock
, returnAddress
, FunctionPtr(cti_op_get_by_id_generic
));
938 if (slot
.slotBase() == structure
->prototypeForLookup(callFrame
)) {
939 ASSERT(slot
.slotBase().isObject());
941 JSObject
* slotBaseObject
= asObject(slot
.slotBase());
942 size_t offset
= slot
.cachedOffset();
944 // Since we're accessing a prototype in a loop, it's a good bet that it
945 // should not be treated as a dictionary.
946 if (slotBaseObject
->structure()->isDictionary()) {
947 slotBaseObject
->flattenDictionaryObject(callFrame
->globalData());
948 offset
= slotBaseObject
->structure()->get(callFrame
->globalData(), propertyName
);
951 stubInfo
->initGetByIdProto(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
, slotBaseObject
->structure());
953 ASSERT(!structure
->isDictionary());
954 ASSERT(!slotBaseObject
->structure()->isDictionary());
955 JIT::compileGetByIdProto(callFrame
->scopeChain()->globalData
, callFrame
, codeBlock
, stubInfo
, structure
, slotBaseObject
->structure(), propertyName
, slot
, offset
, returnAddress
);
959 size_t offset
= slot
.cachedOffset();
960 size_t count
= normalizePrototypeChain(callFrame
, baseValue
, slot
.slotBase(), propertyName
, offset
);
962 stubInfo
->accessType
= access_get_by_id_generic
;
966 StructureChain
* prototypeChain
= structure
->prototypeChain(callFrame
);
967 stubInfo
->initGetByIdChain(callFrame
->globalData(), codeBlock
->ownerExecutable(), structure
, prototypeChain
);
968 JIT::compileGetByIdChain(callFrame
->scopeChain()->globalData
, callFrame
, codeBlock
, stubInfo
, structure
, prototypeChain
, count
, propertyName
, slot
, offset
, returnAddress
);
975 static void jscGeneratedNativeCode()
977 // When executing a JIT stub function (which might do an allocation), we hack the return address
978 // to pretend to be executing this function, to keep stack logging tools from blowing out
985 ALWAYS_INLINE
StackHack(JITStackFrame
& stackFrame
)
986 : stackFrame(stackFrame
)
987 , savedReturnAddress(*stackFrame
.returnAddressSlot())
989 if (!CodeProfiling::enabled())
990 *stackFrame
.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode
));
993 ALWAYS_INLINE
~StackHack()
995 *stackFrame
.returnAddressSlot() = savedReturnAddress
;
998 JITStackFrame
& stackFrame
;
999 ReturnAddressPtr savedReturnAddress
;
1002 #define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame)
1003 #define STUB_SET_RETURN_ADDRESS(returnAddress) stackHack.savedReturnAddress = ReturnAddressPtr(returnAddress)
1004 #define STUB_RETURN_ADDRESS stackHack.savedReturnAddress
1008 #define STUB_INIT_STACK_FRAME(stackFrame) JITStackFrame& stackFrame = *reinterpret_cast_ptr<JITStackFrame*>(STUB_ARGS)
1009 #define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress)
1010 #define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot()
1014 // The reason this is not inlined is to avoid having to do a PIC branch
1015 // to get the address of the ctiVMThrowTrampoline function. It's also
1016 // good to keep the code size down by leaving as much of the exception
1017 // handling code out of line as possible.
1018 static NEVER_INLINE
void returnToThrowTrampoline(JSGlobalData
* globalData
, ReturnAddressPtr exceptionLocation
, ReturnAddressPtr
& returnAddressSlot
)
1020 ASSERT(globalData
->exception
);
1021 globalData
->exceptionLocation
= exceptionLocation
;
1022 returnAddressSlot
= ReturnAddressPtr(FunctionPtr(ctiVMThrowTrampoline
));
1025 #define VM_THROW_EXCEPTION() \
1027 VM_THROW_EXCEPTION_AT_END(); \
1030 #define VM_THROW_EXCEPTION_AT_END() \
1032 returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\
1035 #define CHECK_FOR_EXCEPTION() \
1037 if (UNLIKELY(stackFrame.globalData->exception)) \
1038 VM_THROW_EXCEPTION(); \
1040 #define CHECK_FOR_EXCEPTION_AT_END() \
1042 if (UNLIKELY(stackFrame.globalData->exception)) \
1043 VM_THROW_EXCEPTION_AT_END(); \
1045 #define CHECK_FOR_EXCEPTION_VOID() \
1047 if (UNLIKELY(stackFrame.globalData->exception)) { \
1048 VM_THROW_EXCEPTION_AT_END(); \
1053 // Helper function for JIT stubs that may throw an exception in the middle of
1054 // processing a function call. This function rolls back the register file to
1055 // our caller, so exception processing can proceed from a valid state.
1056 template<typename T
> static T
throwExceptionFromOpCall(JITStackFrame
& jitStackFrame
, CallFrame
* newCallFrame
, ReturnAddressPtr
& returnAddressSlot
)
1058 CallFrame
* callFrame
= newCallFrame
->callerFrame();
1059 ASSERT(callFrame
->globalData().exception
);
1060 jitStackFrame
.callFrame
= callFrame
;
1061 callFrame
->globalData().topCallFrame
= callFrame
;
1062 returnToThrowTrampoline(&callFrame
->globalData(), ReturnAddressPtr(newCallFrame
->returnPC()), returnAddressSlot
);
1066 template<typename T
> static T
throwExceptionFromOpCall(JITStackFrame
& jitStackFrame
, CallFrame
* newCallFrame
, ReturnAddressPtr
& returnAddressSlot
, JSValue exception
)
1068 newCallFrame
->callerFrame()->globalData().exception
= exception
;
1069 return throwExceptionFromOpCall
<T
>(jitStackFrame
, newCallFrame
, returnAddressSlot
);
1072 #if CPU(ARM_THUMB2) && COMPILER(GCC)
1074 #define DEFINE_STUB_FUNCTION(rtype, op) \
1076 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1081 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1082 HIDE_SYMBOL(cti_##op) "\n" \
1084 ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \
1085 SYMBOL_STRING(cti_##op) ":" "\n" \
1086 "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1087 "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1088 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1091 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \
1095 #define DEFINE_STUB_FUNCTION(rtype, op) \
1097 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1102 ".set noreorder" "\n" \
1103 ".set nomacro" "\n" \
1104 ".set nomips16" "\n" \
1105 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1106 ".ent " SYMBOL_STRING(cti_##op) "\n" \
1107 SYMBOL_STRING(cti_##op) ":" "\n" \
1108 "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n" \
1109 "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
1111 "la $25," SYMBOL_STRING(JITStubThunked_##op) "\n" \
1112 ".set nomacro" "\n" \
1113 ".reloc 1f,R_MIPS_JALR," SYMBOL_STRING(JITStubThunked_##op) "\n" \
1114 "1: jalr $25" "\n" \
1116 "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
1119 ".set reorder" "\n" \
1121 ".end " SYMBOL_STRING(cti_##op) "\n" \
1123 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1125 #else // WTF_MIPS_PIC
1126 #define DEFINE_STUB_FUNCTION(rtype, op) \
1128 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1133 ".set noreorder" "\n" \
1134 ".set nomacro" "\n" \
1135 ".set nomips16" "\n" \
1136 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1137 ".ent " SYMBOL_STRING(cti_##op) "\n" \
1138 SYMBOL_STRING(cti_##op) ":" "\n" \
1139 "sw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
1140 "jal " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1142 "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
1145 ".set reorder" "\n" \
1147 ".end " SYMBOL_STRING(cti_##op) "\n" \
1149 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1153 #elif CPU(ARM_TRADITIONAL) && COMPILER(GCC)
1155 #define DEFINE_STUB_FUNCTION(rtype, op) \
1157 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1160 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1161 SYMBOL_STRING(cti_##op) ":" "\n" \
1162 "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1163 "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \
1164 "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \
1167 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1169 #elif (CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)) && COMPILER(RVCT)
1171 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1173 /* The following is a workaround for RVCT toolchain; precompiler macros are not expanded before the code is passed to the assembler */
1175 /* The following section is a template to generate code for GeneratedJITStubs_RVCT.h */
1176 /* The pattern "#xxx#" will be replaced with "xxx" */
1179 RVCT(extern "C" #rtype# JITStubThunked_#op#(STUB_ARGS_DECLARATION);)
1180 RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION))
1183 RVCT( IMPORT JITStubThunked_#op#)
1184 RVCT( str lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET])
1185 RVCT( bl JITStubThunked_#op#)
1186 RVCT( ldr lr, [sp, # THUNK_RETURN_ADDRESS_OFFSET])
1192 /* Include the generated file */
1193 #include "GeneratedJITStubs_RVCT.h"
1195 #elif CPU(ARM_TRADITIONAL) && COMPILER(MSVC)
1197 #define DEFINE_STUB_FUNCTION(rtype, op) extern "C" rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1199 /* The following is a workaround for MSVC toolchain; inline assembler is not supported */
1201 /* The following section is a template to generate code for GeneratedJITStubs_MSVC.asm */
1202 /* The pattern "#xxx#" will be replaced with "xxx" */
1205 MSVC_BEGIN( AREA Trampoline, CODE)
1207 MSVC_BEGIN( EXPORT ctiTrampoline)
1208 MSVC_BEGIN( EXPORT ctiVMThrowTrampoline)
1209 MSVC_BEGIN( EXPORT ctiOpThrowNotCaught)
1211 MSVC_BEGIN(ctiTrampoline PROC)
1212 MSVC_BEGIN( stmdb sp!, {r1-r3})
1213 MSVC_BEGIN( stmdb sp!, {r4-r8, lr})
1214 MSVC_BEGIN( sub sp, sp, #68 ; sync with PRESERVEDR4_OFFSET)
1215 MSVC_BEGIN( mov r4, r2)
1216 MSVC_BEGIN( mov r5, #512)
1217 MSVC_BEGIN( ; r0 contains the code)
1218 MSVC_BEGIN( mov lr, pc)
1220 MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET)
1221 MSVC_BEGIN( ldmia sp!, {r4-r8, lr})
1222 MSVC_BEGIN( add sp, sp, #12)
1224 MSVC_BEGIN(ctiTrampoline ENDP)
1226 MSVC_BEGIN(ctiVMThrowTrampoline PROC)
1227 MSVC_BEGIN( mov r0, sp)
1228 MSVC_BEGIN( mov lr, pc)
1229 MSVC_BEGIN( bl cti_vm_throw)
1230 MSVC_BEGIN(ctiOpThrowNotCaught)
1231 MSVC_BEGIN( add sp, sp, #68 ; sync with PRESERVEDR4_OFFSET)
1232 MSVC_BEGIN( ldmia sp!, {r4-r8, lr})
1233 MSVC_BEGIN( add sp, sp, #12)
1235 MSVC_BEGIN(ctiVMThrowTrampoline ENDP)
1238 MSVC( EXPORT cti_#op#)
1239 MSVC( IMPORT JITStubThunked_#op#)
1241 MSVC( str lr, [sp, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET)
1242 MSVC( bl JITStubThunked_#op#)
1243 MSVC( ldr lr, [sp, #64] ; sync with THUNK_RETURN_ADDRESS_OFFSET)
1252 #define DEFINE_STUB_FUNCTION(rtype, op) \
1254 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1258 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1259 SYMBOL_STRING(cti_##op) ":" "\n" \
1260 "sts pr, r11" "\n" \
1261 "mov.l r11, @(0x38, r15)" "\n" \
1262 "mov.l .L2"SYMBOL_STRING(JITStubThunked_##op)",r0" "\n" \
1263 "mov.l @(r0,r12),r11" "\n" \
1266 "mov.l @(0x38, r15), r11 " "\n" \
1267 "lds r11, pr " "\n" \
1271 ".L2"SYMBOL_STRING(JITStubThunked_##op)":.long " SYMBOL_STRING(JITStubThunked_##op)"@GOT \n" \
1273 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1275 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION)
1278 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_create_this
)
1280 STUB_INIT_STACK_FRAME(stackFrame
);
1281 CallFrame
* callFrame
= stackFrame
.callFrame
;
1283 JSFunction
* constructor
= jsCast
<JSFunction
*>(callFrame
->callee());
1284 #if !ASSERT_DISABLED
1285 ConstructData constructData
;
1286 ASSERT(constructor
->methodTable()->getConstructData(constructor
, constructData
) == ConstructTypeJS
);
1289 Structure
* structure
;
1290 JSValue proto
= stackFrame
.args
[0].jsValue();
1291 if (proto
.isObject())
1292 structure
= asObject(proto
)->inheritorID(*stackFrame
.globalData
);
1294 structure
= constructor
->scope()->globalObject
->emptyObjectStructure();
1295 JSValue result
= constructEmptyObject(callFrame
, structure
);
1297 return JSValue::encode(result
);
1300 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_convert_this
)
1302 STUB_INIT_STACK_FRAME(stackFrame
);
1304 JSValue v1
= stackFrame
.args
[0].jsValue();
1305 CallFrame
* callFrame
= stackFrame
.callFrame
;
1307 ASSERT(v1
.isPrimitive());
1309 JSObject
* result
= v1
.toThisObject(callFrame
);
1310 CHECK_FOR_EXCEPTION_AT_END();
1311 return JSValue::encode(result
);
1314 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_add
)
1316 STUB_INIT_STACK_FRAME(stackFrame
);
1318 JSValue v1
= stackFrame
.args
[0].jsValue();
1319 JSValue v2
= stackFrame
.args
[1].jsValue();
1320 CallFrame
* callFrame
= stackFrame
.callFrame
;
1322 if (v1
.isString() && !v2
.isObject()) {
1323 JSValue result
= jsString(callFrame
, asString(v1
), v2
.toString(callFrame
));
1324 CHECK_FOR_EXCEPTION_AT_END();
1325 return JSValue::encode(result
);
1328 if (v1
.isNumber() && v2
.isNumber())
1329 return JSValue::encode(jsNumber(v1
.asNumber() + v2
.asNumber()));
1331 // All other cases are pretty uncommon
1332 JSValue result
= jsAddSlowCase(callFrame
, v1
, v2
);
1333 CHECK_FOR_EXCEPTION_AT_END();
1334 return JSValue::encode(result
);
1337 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_pre_inc
)
1339 STUB_INIT_STACK_FRAME(stackFrame
);
1341 JSValue v
= stackFrame
.args
[0].jsValue();
1343 CallFrame
* callFrame
= stackFrame
.callFrame
;
1344 JSValue result
= jsNumber(v
.toNumber(callFrame
) + 1);
1345 CHECK_FOR_EXCEPTION_AT_END();
1346 return JSValue::encode(result
);
1349 DEFINE_STUB_FUNCTION(int, timeout_check
)
1351 STUB_INIT_STACK_FRAME(stackFrame
);
1353 JSGlobalData
* globalData
= stackFrame
.globalData
;
1354 TimeoutChecker
& timeoutChecker
= globalData
->timeoutChecker
;
1356 if (globalData
->terminator
.shouldTerminate()) {
1357 globalData
->exception
= createTerminatedExecutionException(globalData
);
1358 VM_THROW_EXCEPTION_AT_END();
1359 } else if (timeoutChecker
.didTimeOut(stackFrame
.callFrame
)) {
1360 globalData
->exception
= createInterruptedExecutionException(globalData
);
1361 VM_THROW_EXCEPTION_AT_END();
1364 return timeoutChecker
.ticksUntilNextCheck();
1367 DEFINE_STUB_FUNCTION(void*, register_file_check
)
1369 STUB_INIT_STACK_FRAME(stackFrame
);
1370 CallFrame
* callFrame
= stackFrame
.callFrame
;
1372 if (UNLIKELY(!stackFrame
.registerFile
->grow(&callFrame
->registers()[callFrame
->codeBlock()->m_numCalleeRegisters
])))
1373 return throwExceptionFromOpCall
<void*>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
, createStackOverflowError(callFrame
->callerFrame()));
1378 DEFINE_STUB_FUNCTION(JSObject
*, op_new_object
)
1380 STUB_INIT_STACK_FRAME(stackFrame
);
1382 return constructEmptyObject(stackFrame
.callFrame
);
1385 DEFINE_STUB_FUNCTION(void, op_put_by_id_generic
)
1387 STUB_INIT_STACK_FRAME(stackFrame
);
1389 PutPropertySlot
slot(stackFrame
.callFrame
->codeBlock()->isStrictMode());
1390 stackFrame
.args
[0].jsValue().put(stackFrame
.callFrame
, stackFrame
.args
[1].identifier(), stackFrame
.args
[2].jsValue(), slot
);
1391 CHECK_FOR_EXCEPTION_AT_END();
1394 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic
)
1396 STUB_INIT_STACK_FRAME(stackFrame
);
1398 PutPropertySlot
slot(stackFrame
.callFrame
->codeBlock()->isStrictMode());
1399 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1400 ASSERT(baseValue
.isObject());
1401 asObject(baseValue
)->putDirect(stackFrame
.callFrame
->globalData(), stackFrame
.args
[1].identifier(), stackFrame
.args
[2].jsValue(), slot
);
1402 CHECK_FOR_EXCEPTION_AT_END();
1405 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_generic
)
1407 STUB_INIT_STACK_FRAME(stackFrame
);
1409 CallFrame
* callFrame
= stackFrame
.callFrame
;
1410 Identifier
& ident
= stackFrame
.args
[1].identifier();
1412 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1413 PropertySlot
slot(baseValue
);
1414 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
1416 CHECK_FOR_EXCEPTION_AT_END();
1417 return JSValue::encode(result
);
1420 DEFINE_STUB_FUNCTION(void, op_put_by_id
)
1422 STUB_INIT_STACK_FRAME(stackFrame
);
1423 CallFrame
* callFrame
= stackFrame
.callFrame
;
1424 Identifier
& ident
= stackFrame
.args
[1].identifier();
1426 PutPropertySlot
slot(callFrame
->codeBlock()->isStrictMode());
1427 stackFrame
.args
[0].jsValue().put(callFrame
, ident
, stackFrame
.args
[2].jsValue(), slot
);
1429 CodeBlock
* codeBlock
= stackFrame
.callFrame
->codeBlock();
1430 StructureStubInfo
* stubInfo
= &codeBlock
->getStubInfo(STUB_RETURN_ADDRESS
);
1431 if (!stubInfo
->seenOnce())
1432 stubInfo
->setSeen();
1434 JITThunks::tryCachePutByID(callFrame
, codeBlock
, STUB_RETURN_ADDRESS
, stackFrame
.args
[0].jsValue(), slot
, stubInfo
, false);
1436 CHECK_FOR_EXCEPTION_AT_END();
1439 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct
)
1441 STUB_INIT_STACK_FRAME(stackFrame
);
1442 CallFrame
* callFrame
= stackFrame
.callFrame
;
1443 Identifier
& ident
= stackFrame
.args
[1].identifier();
1445 PutPropertySlot
slot(callFrame
->codeBlock()->isStrictMode());
1446 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1447 ASSERT(baseValue
.isObject());
1449 asObject(baseValue
)->putDirect(callFrame
->globalData(), ident
, stackFrame
.args
[2].jsValue(), slot
);
1451 CodeBlock
* codeBlock
= stackFrame
.callFrame
->codeBlock();
1452 StructureStubInfo
* stubInfo
= &codeBlock
->getStubInfo(STUB_RETURN_ADDRESS
);
1453 if (!stubInfo
->seenOnce())
1454 stubInfo
->setSeen();
1456 JITThunks::tryCachePutByID(callFrame
, codeBlock
, STUB_RETURN_ADDRESS
, stackFrame
.args
[0].jsValue(), slot
, stubInfo
, true);
1458 CHECK_FOR_EXCEPTION_AT_END();
1461 DEFINE_STUB_FUNCTION(void, op_put_by_id_fail
)
1463 STUB_INIT_STACK_FRAME(stackFrame
);
1465 CallFrame
* callFrame
= stackFrame
.callFrame
;
1466 Identifier
& ident
= stackFrame
.args
[1].identifier();
1468 PutPropertySlot
slot(callFrame
->codeBlock()->isStrictMode());
1469 stackFrame
.args
[0].jsValue().put(callFrame
, ident
, stackFrame
.args
[2].jsValue(), slot
);
1471 CHECK_FOR_EXCEPTION_AT_END();
1474 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail
)
1476 STUB_INIT_STACK_FRAME(stackFrame
);
1478 CallFrame
* callFrame
= stackFrame
.callFrame
;
1479 Identifier
& ident
= stackFrame
.args
[1].identifier();
1481 PutPropertySlot
slot(callFrame
->codeBlock()->isStrictMode());
1482 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1483 ASSERT(baseValue
.isObject());
1484 asObject(baseValue
)->putDirect(callFrame
->globalData(), ident
, stackFrame
.args
[2].jsValue(), slot
);
1486 CHECK_FOR_EXCEPTION_AT_END();
1489 DEFINE_STUB_FUNCTION(JSObject
*, op_put_by_id_transition_realloc
)
1491 STUB_INIT_STACK_FRAME(stackFrame
);
1493 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1494 int32_t oldSize
= stackFrame
.args
[3].int32();
1495 Structure
* newStructure
= stackFrame
.args
[4].structure();
1496 int32_t newSize
= newStructure
->propertyStorageCapacity();
1498 ASSERT(baseValue
.isObject());
1499 JSObject
* base
= asObject(baseValue
);
1500 JSGlobalData
& globalData
= *stackFrame
.globalData
;
1501 PropertyStorage newStorage
= base
->growPropertyStorage(globalData
, oldSize
, newSize
);
1502 base
->setPropertyStorage(globalData
, newStorage
, newStructure
);
1507 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_method_check
)
1509 STUB_INIT_STACK_FRAME(stackFrame
);
1511 CallFrame
* callFrame
= stackFrame
.callFrame
;
1512 Identifier
& ident
= stackFrame
.args
[1].identifier();
1514 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1515 PropertySlot
slot(baseValue
);
1516 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
1517 CHECK_FOR_EXCEPTION();
1519 CodeBlock
* codeBlock
= stackFrame
.callFrame
->codeBlock();
1520 MethodCallLinkInfo
& methodCallLinkInfo
= codeBlock
->getMethodCallLinkInfo(STUB_RETURN_ADDRESS
);
1521 StructureStubInfo
& stubInfo
= codeBlock
->getStubInfo(STUB_RETURN_ADDRESS
);
1523 if (!methodCallLinkInfo
.seenOnce()) {
1524 methodCallLinkInfo
.setSeen();
1525 return JSValue::encode(result
);
1528 // If we successfully got something, then the base from which it is being accessed must
1529 // be an object. (Assertion to ensure asObject() call below is safe, which comes after
1530 // an isCacheable() chceck.
1531 ASSERT(!slot
.isCacheableValue() || slot
.slotBase().isObject());
1534 // * We're dealing with a JSCell,
1535 // * the property is cachable,
1536 // * it's not a dictionary
1537 // * there is a function cached.
1538 Structure
* structure
;
1540 JSObject
* slotBaseObject
;
1541 if (baseValue
.isCell()
1542 && slot
.isCacheableValue()
1543 && !(structure
= baseValue
.asCell()->structure())->isUncacheableDictionary()
1544 && (slotBaseObject
= asObject(slot
.slotBase()))->getPropertySpecificValue(callFrame
, ident
, specific
)
1548 JSObject
* callee
= asObject(specific
);
1550 // Since we're accessing a prototype in a loop, it's a good bet that it
1551 // should not be treated as a dictionary.
1552 if (slotBaseObject
->structure()->isDictionary())
1553 slotBaseObject
->flattenDictionaryObject(callFrame
->globalData());
1555 // The result fetched should always be the callee!
1556 ASSERT(result
== JSValue(callee
));
1558 // Check to see if the function is on the object's prototype. Patch up the code to optimize.
1559 if (slot
.slotBase() == structure
->prototypeForLookup(callFrame
)) {
1560 JIT::patchMethodCallProto(callFrame
->globalData(), codeBlock
, methodCallLinkInfo
, stubInfo
, callee
, structure
, slotBaseObject
, STUB_RETURN_ADDRESS
);
1561 return JSValue::encode(result
);
1564 // Check to see if the function is on the object itself.
1565 // Since we generate the method-check to check both the structure and a prototype-structure (since this
1566 // is the common case) we have a problem - we need to patch the prototype structure check to do something
1567 // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler
1568 // for now. For now it performs a check on a special object on the global object only used for this
1569 // purpose. The object is in no way exposed, and as such the check will always pass.
1570 if (slot
.slotBase() == baseValue
) {
1571 JIT::patchMethodCallProto(callFrame
->globalData(), codeBlock
, methodCallLinkInfo
, stubInfo
, callee
, structure
, callFrame
->scopeChain()->globalObject
->methodCallDummy(), STUB_RETURN_ADDRESS
);
1572 return JSValue::encode(result
);
1576 // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to.
1577 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id
));
1578 return JSValue::encode(result
);
1581 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_method_check_update
)
1583 STUB_INIT_STACK_FRAME(stackFrame
);
1585 CallFrame
* callFrame
= stackFrame
.callFrame
;
1586 Identifier
& ident
= stackFrame
.args
[1].identifier();
1588 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1589 PropertySlot
slot(baseValue
);
1590 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
1591 CHECK_FOR_EXCEPTION();
1593 CodeBlock
* codeBlock
= stackFrame
.callFrame
->codeBlock();
1594 MethodCallLinkInfo
& methodCallLinkInfo
= codeBlock
->getMethodCallLinkInfo(STUB_RETURN_ADDRESS
);
1595 StructureStubInfo
& stubInfo
= codeBlock
->getStubInfo(STUB_RETURN_ADDRESS
);
1597 ASSERT(methodCallLinkInfo
.seenOnce());
1599 // If we successfully got something, then the base from which it is being accessed must
1600 // be an object. (Assertion to ensure asObject() call below is safe, which comes after
1601 // an isCacheable() chceck.
1602 ASSERT(!slot
.isCacheableValue() || slot
.slotBase().isObject());
1605 // * We're dealing with a JSCell,
1606 // * the property is cachable,
1607 // * it's not a dictionary
1608 // * there is a function cached.
1609 Structure
* structure
;
1611 JSObject
* slotBaseObject
;
1612 if (!(baseValue
.isCell()
1613 && slot
.isCacheableValue()
1614 && !(structure
= baseValue
.asCell()->structure())->isUncacheableDictionary()
1615 && (slotBaseObject
= asObject(slot
.slotBase()))->getPropertySpecificValue(callFrame
, ident
, specific
)
1618 || (slot
.slotBase() != structure
->prototypeForLookup(callFrame
)
1619 && slot
.slotBase() != baseValue
)) {
1620 // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to.
1621 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id
));
1622 return JSValue::encode(result
);
1625 // Now check if the situation has changed sufficiently that we should bail out of
1626 // doing method_check optimizations entirely, or if it changed only slightly, in
1627 // which case we can just repatch.
1629 JSValue proto
= structure
->prototypeForLookup(callFrame
);
1631 bool previousWasProto
= methodCallLinkInfo
.cachedPrototype
.get() != codeBlock
->globalObject()->methodCallDummy();
1632 bool currentIsProto
= slot
.slotBase() == proto
;
1634 JSObject
* callee
= asObject(specific
);
1636 if (previousWasProto
!= currentIsProto
1637 || !structure
->transitivelyTransitionedFrom(methodCallLinkInfo
.cachedStructure
.get())
1638 || (previousWasProto
&& !slotBaseObject
->structure()->transitivelyTransitionedFrom(methodCallLinkInfo
.cachedPrototypeStructure
.get()))
1639 || specific
!= methodCallLinkInfo
.cachedFunction
.get()) {
1640 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id
));
1641 return JSValue::encode(result
);
1644 // It makes sense to simply repatch the method_check.
1646 // Since we're accessing a prototype in a loop, it's a good bet that it
1647 // should not be treated as a dictionary.
1648 if (slotBaseObject
->structure()->isDictionary())
1649 slotBaseObject
->flattenDictionaryObject(callFrame
->globalData());
1651 // The result fetched should always be the callee!
1652 ASSERT(result
== JSValue(callee
));
1654 // Check to see if the function is on the object's prototype. Patch up the code to optimize.
1655 if (slot
.slotBase() == proto
) {
1656 JIT::patchMethodCallProto(callFrame
->globalData(), codeBlock
, methodCallLinkInfo
, stubInfo
, callee
, structure
, slotBaseObject
, STUB_RETURN_ADDRESS
);
1657 return JSValue::encode(result
);
1660 ASSERT(slot
.slotBase() == baseValue
);
1662 // Since we generate the method-check to check both the structure and a prototype-structure (since this
1663 // is the common case) we have a problem - we need to patch the prototype structure check to do something
1664 // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler
1665 // for now. For now it performs a check on a special object on the global object only used for this
1666 // purpose. The object is in no way exposed, and as such the check will always pass.
1667 JIT::patchMethodCallProto(callFrame
->globalData(), codeBlock
, methodCallLinkInfo
, stubInfo
, callee
, structure
, callFrame
->scopeChain()->globalObject
->methodCallDummy(), STUB_RETURN_ADDRESS
);
1668 return JSValue::encode(result
);
1671 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id
)
1673 STUB_INIT_STACK_FRAME(stackFrame
);
1674 CallFrame
* callFrame
= stackFrame
.callFrame
;
1675 Identifier
& ident
= stackFrame
.args
[1].identifier();
1677 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1678 PropertySlot
slot(baseValue
);
1679 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
1681 CodeBlock
* codeBlock
= stackFrame
.callFrame
->codeBlock();
1682 StructureStubInfo
* stubInfo
= &codeBlock
->getStubInfo(STUB_RETURN_ADDRESS
);
1683 if (!stubInfo
->seenOnce())
1684 stubInfo
->setSeen();
1686 JITThunks::tryCacheGetByID(callFrame
, codeBlock
, STUB_RETURN_ADDRESS
, baseValue
, ident
, slot
, stubInfo
);
1688 CHECK_FOR_EXCEPTION_AT_END();
1689 return JSValue::encode(result
);
1692 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_self_fail
)
1694 STUB_INIT_STACK_FRAME(stackFrame
);
1696 CallFrame
* callFrame
= stackFrame
.callFrame
;
1697 Identifier
& ident
= stackFrame
.args
[1].identifier();
1699 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1700 PropertySlot
slot(baseValue
);
1701 JSValue result
= baseValue
.get(callFrame
, ident
, slot
);
1703 CHECK_FOR_EXCEPTION();
1705 if (baseValue
.isCell()
1706 && slot
.isCacheable()
1707 && !baseValue
.asCell()->structure()->isUncacheableDictionary()
1708 && slot
.slotBase() == baseValue
) {
1710 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1711 StructureStubInfo
* stubInfo
= &codeBlock
->getStubInfo(STUB_RETURN_ADDRESS
);
1713 ASSERT(slot
.slotBase().isObject());
1715 PolymorphicAccessStructureList
* polymorphicStructureList
;
1718 if (stubInfo
->accessType
== access_get_by_id_self
) {
1719 ASSERT(!stubInfo
->stubRoutine
);
1720 polymorphicStructureList
= new PolymorphicAccessStructureList(callFrame
->globalData(), codeBlock
->ownerExecutable(), MacroAssemblerCodeRef(), stubInfo
->u
.getByIdSelf
.baseObjectStructure
.get(), true);
1721 stubInfo
->initGetByIdSelfList(polymorphicStructureList
, 1);
1723 polymorphicStructureList
= stubInfo
->u
.getByIdSelfList
.structureList
;
1724 listIndex
= stubInfo
->u
.getByIdSelfList
.listSize
;
1726 if (listIndex
< POLYMORPHIC_LIST_CACHE_SIZE
) {
1727 stubInfo
->u
.getByIdSelfList
.listSize
++;
1728 JIT::compileGetByIdSelfList(callFrame
->scopeChain()->globalData
, codeBlock
, stubInfo
, polymorphicStructureList
, listIndex
, baseValue
.asCell()->structure(), ident
, slot
, slot
.cachedOffset());
1730 if (listIndex
== (POLYMORPHIC_LIST_CACHE_SIZE
- 1))
1731 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id_generic
));
1734 ctiPatchCallByReturnAddress(callFrame
->codeBlock(), STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id_generic
));
1735 return JSValue::encode(result
);
1738 static PolymorphicAccessStructureList
* getPolymorphicAccessStructureListSlot(JSGlobalData
& globalData
, ScriptExecutable
* owner
, StructureStubInfo
* stubInfo
, int& listIndex
)
1740 PolymorphicAccessStructureList
* prototypeStructureList
= 0;
1743 switch (stubInfo
->accessType
) {
1744 case access_get_by_id_proto
:
1745 prototypeStructureList
= new PolymorphicAccessStructureList(globalData
, owner
, stubInfo
->stubRoutine
, stubInfo
->u
.getByIdProto
.baseObjectStructure
.get(), stubInfo
->u
.getByIdProto
.prototypeStructure
.get(), true);
1746 stubInfo
->stubRoutine
= MacroAssemblerCodeRef();
1747 stubInfo
->initGetByIdProtoList(prototypeStructureList
, 2);
1749 case access_get_by_id_chain
:
1750 prototypeStructureList
= new PolymorphicAccessStructureList(globalData
, owner
, stubInfo
->stubRoutine
, stubInfo
->u
.getByIdChain
.baseObjectStructure
.get(), stubInfo
->u
.getByIdChain
.chain
.get(), true);
1751 stubInfo
->stubRoutine
= MacroAssemblerCodeRef();
1752 stubInfo
->initGetByIdProtoList(prototypeStructureList
, 2);
1754 case access_get_by_id_proto_list
:
1755 prototypeStructureList
= stubInfo
->u
.getByIdProtoList
.structureList
;
1756 listIndex
= stubInfo
->u
.getByIdProtoList
.listSize
;
1757 if (listIndex
< POLYMORPHIC_LIST_CACHE_SIZE
)
1758 stubInfo
->u
.getByIdProtoList
.listSize
++;
1761 ASSERT_NOT_REACHED();
1764 ASSERT(listIndex
<= POLYMORPHIC_LIST_CACHE_SIZE
);
1765 return prototypeStructureList
;
1768 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_getter_stub
)
1770 STUB_INIT_STACK_FRAME(stackFrame
);
1771 CallFrame
* callFrame
= stackFrame
.callFrame
;
1772 GetterSetter
* getterSetter
= asGetterSetter(stackFrame
.args
[0].jsObject());
1773 if (!getterSetter
->getter())
1774 return JSValue::encode(jsUndefined());
1775 JSObject
* getter
= asObject(getterSetter
->getter());
1777 CallType callType
= getter
->methodTable()->getCallData(getter
, callData
);
1778 JSValue result
= call(callFrame
, getter
, callType
, callData
, stackFrame
.args
[1].jsObject(), ArgList());
1779 if (callFrame
->hadException())
1780 returnToThrowTrampoline(&callFrame
->globalData(), stackFrame
.args
[2].returnAddress(), STUB_RETURN_ADDRESS
);
1782 return JSValue::encode(result
);
1785 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_custom_stub
)
1787 STUB_INIT_STACK_FRAME(stackFrame
);
1788 CallFrame
* callFrame
= stackFrame
.callFrame
;
1789 JSObject
* slotBase
= stackFrame
.args
[0].jsObject();
1790 PropertySlot::GetValueFunc getter
= reinterpret_cast<PropertySlot::GetValueFunc
>(stackFrame
.args
[1].asPointer
);
1791 const Identifier
& ident
= stackFrame
.args
[2].identifier();
1792 JSValue result
= getter(callFrame
, slotBase
, ident
);
1793 if (callFrame
->hadException())
1794 returnToThrowTrampoline(&callFrame
->globalData(), stackFrame
.args
[3].returnAddress(), STUB_RETURN_ADDRESS
);
1796 return JSValue::encode(result
);
1799 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_proto_list
)
1801 STUB_INIT_STACK_FRAME(stackFrame
);
1803 CallFrame
* callFrame
= stackFrame
.callFrame
;
1804 const Identifier
& propertyName
= stackFrame
.args
[1].identifier();
1806 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1807 PropertySlot
slot(baseValue
);
1808 JSValue result
= baseValue
.get(callFrame
, propertyName
, slot
);
1810 CHECK_FOR_EXCEPTION();
1812 if (!baseValue
.isCell() || !slot
.isCacheable() || baseValue
.asCell()->structure()->isDictionary() || baseValue
.asCell()->structure()->typeInfo().prohibitsPropertyCaching()) {
1813 ctiPatchCallByReturnAddress(callFrame
->codeBlock(), STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id_proto_fail
));
1814 return JSValue::encode(result
);
1817 Structure
* structure
= baseValue
.asCell()->structure();
1818 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1819 StructureStubInfo
* stubInfo
= &codeBlock
->getStubInfo(STUB_RETURN_ADDRESS
);
1821 ASSERT(slot
.slotBase().isObject());
1822 JSObject
* slotBaseObject
= asObject(slot
.slotBase());
1824 size_t offset
= slot
.cachedOffset();
1826 if (slot
.slotBase() == baseValue
)
1827 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id_proto_fail
));
1828 else if (slot
.slotBase() == baseValue
.asCell()->structure()->prototypeForLookup(callFrame
)) {
1829 ASSERT(!baseValue
.asCell()->structure()->isDictionary());
1830 // Since we're accessing a prototype in a loop, it's a good bet that it
1831 // should not be treated as a dictionary.
1832 if (slotBaseObject
->structure()->isDictionary()) {
1833 slotBaseObject
->flattenDictionaryObject(callFrame
->globalData());
1834 offset
= slotBaseObject
->structure()->get(callFrame
->globalData(), propertyName
);
1838 PolymorphicAccessStructureList
* prototypeStructureList
= getPolymorphicAccessStructureListSlot(callFrame
->globalData(), codeBlock
->ownerExecutable(), stubInfo
, listIndex
);
1839 if (listIndex
< POLYMORPHIC_LIST_CACHE_SIZE
) {
1840 JIT::compileGetByIdProtoList(callFrame
->scopeChain()->globalData
, callFrame
, codeBlock
, stubInfo
, prototypeStructureList
, listIndex
, structure
, slotBaseObject
->structure(), propertyName
, slot
, offset
);
1842 if (listIndex
== (POLYMORPHIC_LIST_CACHE_SIZE
- 1))
1843 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id_proto_list_full
));
1845 } else if (size_t count
= normalizePrototypeChain(callFrame
, baseValue
, slot
.slotBase(), propertyName
, offset
)) {
1846 ASSERT(!baseValue
.asCell()->structure()->isDictionary());
1848 PolymorphicAccessStructureList
* prototypeStructureList
= getPolymorphicAccessStructureListSlot(callFrame
->globalData(), codeBlock
->ownerExecutable(), stubInfo
, listIndex
);
1850 if (listIndex
< POLYMORPHIC_LIST_CACHE_SIZE
) {
1851 StructureChain
* protoChain
= structure
->prototypeChain(callFrame
);
1852 JIT::compileGetByIdChainList(callFrame
->scopeChain()->globalData
, callFrame
, codeBlock
, stubInfo
, prototypeStructureList
, listIndex
, structure
, protoChain
, count
, propertyName
, slot
, offset
);
1854 if (listIndex
== (POLYMORPHIC_LIST_CACHE_SIZE
- 1))
1855 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id_proto_list_full
));
1858 ctiPatchCallByReturnAddress(codeBlock
, STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_id_proto_fail
));
1860 return JSValue::encode(result
);
1863 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_proto_list_full
)
1865 STUB_INIT_STACK_FRAME(stackFrame
);
1867 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1868 PropertySlot
slot(baseValue
);
1869 JSValue result
= baseValue
.get(stackFrame
.callFrame
, stackFrame
.args
[1].identifier(), slot
);
1871 CHECK_FOR_EXCEPTION_AT_END();
1872 return JSValue::encode(result
);
1875 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_proto_fail
)
1877 STUB_INIT_STACK_FRAME(stackFrame
);
1879 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1880 PropertySlot
slot(baseValue
);
1881 JSValue result
= baseValue
.get(stackFrame
.callFrame
, stackFrame
.args
[1].identifier(), slot
);
1883 CHECK_FOR_EXCEPTION_AT_END();
1884 return JSValue::encode(result
);
1887 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_array_fail
)
1889 STUB_INIT_STACK_FRAME(stackFrame
);
1891 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1892 PropertySlot
slot(baseValue
);
1893 JSValue result
= baseValue
.get(stackFrame
.callFrame
, stackFrame
.args
[1].identifier(), slot
);
1895 CHECK_FOR_EXCEPTION_AT_END();
1896 return JSValue::encode(result
);
1899 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_id_string_fail
)
1901 STUB_INIT_STACK_FRAME(stackFrame
);
1903 JSValue baseValue
= stackFrame
.args
[0].jsValue();
1904 PropertySlot
slot(baseValue
);
1905 JSValue result
= baseValue
.get(stackFrame
.callFrame
, stackFrame
.args
[1].identifier(), slot
);
1907 CHECK_FOR_EXCEPTION_AT_END();
1908 return JSValue::encode(result
);
1911 DEFINE_STUB_FUNCTION(void, op_check_has_instance
)
1913 STUB_INIT_STACK_FRAME(stackFrame
);
1915 CallFrame
* callFrame
= stackFrame
.callFrame
;
1916 JSValue baseVal
= stackFrame
.args
[0].jsValue();
1918 // ECMA-262 15.3.5.3:
1919 // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
1921 TypeInfo
typeInfo(UnspecifiedType
);
1922 ASSERT(!baseVal
.isObject() || !(typeInfo
= asObject(baseVal
)->structure()->typeInfo()).implementsHasInstance());
1924 stackFrame
.globalData
->exception
= createInvalidParamError(callFrame
, "instanceof", baseVal
);
1925 VM_THROW_EXCEPTION_AT_END();
1929 DEFINE_STUB_FUNCTION(void, optimize_from_loop
)
1931 STUB_INIT_STACK_FRAME(stackFrame
);
1933 CallFrame
* callFrame
= stackFrame
.callFrame
;
1934 CodeBlock
* codeBlock
= callFrame
->codeBlock();
1936 unsigned bytecodeIndex
= stackFrame
.args
[0].int32();
1938 #if ENABLE(JIT_VERBOSE_OSR)
1939 dataLog("%p: Entered optimize_from_loop with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock
, codeBlock
->jitExecuteCounter(), codeBlock
->reoptimizationRetryCounter(), codeBlock
->optimizationDelayCounter());
1942 if (!codeBlock
->checkIfOptimizationThresholdReached())
1945 if (codeBlock
->hasOptimizedReplacement()) {
1946 #if ENABLE(JIT_VERBOSE_OSR)
1947 dataLog("Considering loop OSR into %p(%p) with success/fail %u/%u.\n", codeBlock
, codeBlock
->replacement(), codeBlock
->replacement()->speculativeSuccessCounter(), codeBlock
->replacement()->speculativeFailCounter());
1949 if (codeBlock
->replacement()->shouldReoptimizeFromLoopNow()) {
1950 #if ENABLE(JIT_VERBOSE_OSR)
1951 dataLog("Triggering reoptimization of %p(%p) (in loop).\n", codeBlock
, codeBlock
->replacement());
1953 codeBlock
->reoptimize();
1957 if (!codeBlock
->shouldOptimizeNow()) {
1958 #if ENABLE(JIT_VERBOSE_OSR)
1959 dataLog("Delaying optimization for %p (in loop) because of insufficient profiling.\n", codeBlock
);
1964 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
1966 JSObject
* error
= codeBlock
->compileOptimized(callFrame
, scopeChain
);
1967 #if ENABLE(JIT_VERBOSE_OSR)
1969 dataLog("WARNING: optimized compilation from loop failed.\n");
1971 UNUSED_PARAM(error
);
1974 if (codeBlock
->replacement() == codeBlock
) {
1975 #if ENABLE(JIT_VERBOSE_OSR)
1976 dataLog("Optimizing %p from loop failed.\n", codeBlock
);
1979 ASSERT(codeBlock
->getJITType() == JITCode::BaselineJIT
);
1980 codeBlock
->dontOptimizeAnytimeSoon();
1985 CodeBlock
* optimizedCodeBlock
= codeBlock
->replacement();
1986 ASSERT(optimizedCodeBlock
->getJITType() == JITCode::DFGJIT
);
1988 if (void* address
= DFG::prepareOSREntry(callFrame
, optimizedCodeBlock
, bytecodeIndex
)) {
1989 #if ENABLE(JIT_VERBOSE_OSR)
1990 dataLog("Optimizing %p from loop succeeded, performing OSR after a delay of %u.\n", codeBlock
, codeBlock
->optimizationDelayCounter());
1993 codeBlock
->optimizeSoon();
1994 optimizedCodeBlock
->countSpeculationSuccess();
1995 STUB_SET_RETURN_ADDRESS(address
);
1999 #if ENABLE(JIT_VERBOSE_OSR)
2000 dataLog("Optimizing %p from loop succeeded, OSR failed, after a delay of %u.\n", codeBlock
, codeBlock
->optimizationDelayCounter());
2003 // Count the OSR failure as a speculation failure. If this happens a lot, then
2005 optimizedCodeBlock
->countSpeculationFailure();
2007 #if ENABLE(JIT_VERBOSE_OSR)
2008 dataLog("Encountered loop OSR failure into %p(%p) with success/fail %u/%u.\n", codeBlock
, codeBlock
->replacement(), codeBlock
->replacement()->speculativeSuccessCounter(), codeBlock
->replacement()->speculativeFailCounter());
2011 // We are a lot more conservative about triggering reoptimization after OSR failure than
2012 // before it. If we enter the optimize_from_loop trigger with a bucket full of fail
2013 // already, then we really would like to reoptimize immediately. But this case covers
2014 // something else: there weren't many (or any) speculation failures before, but we just
2015 // failed to enter the speculative code because some variable had the wrong value or
2016 // because the OSR code decided for any spurious reason that it did not want to OSR
2017 // right now. So, we only trigger reoptimization only upon the more conservative (non-loop)
2018 // reoptimization trigger.
2019 if (optimizedCodeBlock
->shouldReoptimizeNow()) {
2020 #if ENABLE(JIT_VERBOSE_OSR)
2021 dataLog("Triggering reoptimization of %p(%p) (in loop after OSR fail).\n", codeBlock
, codeBlock
->replacement());
2023 codeBlock
->reoptimize();
2027 // OSR failed this time, but it might succeed next time! Let the code run a bit
2028 // longer and then try again.
2029 codeBlock
->optimizeAfterWarmUp();
2032 DEFINE_STUB_FUNCTION(void, optimize_from_ret
)
2034 STUB_INIT_STACK_FRAME(stackFrame
);
2036 CallFrame
* callFrame
= stackFrame
.callFrame
;
2037 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2039 #if ENABLE(JIT_VERBOSE_OSR)
2040 dataLog("Entered optimize_from_ret with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock
->jitExecuteCounter(), codeBlock
->reoptimizationRetryCounter(), codeBlock
->optimizationDelayCounter());
2043 if (!codeBlock
->checkIfOptimizationThresholdReached())
2046 if (codeBlock
->hasOptimizedReplacement()) {
2047 #if ENABLE(JIT_VERBOSE_OSR)
2048 dataLog("Returning from old JIT call frame with optimized replacement %p(%p), with success/fail %u/%u", codeBlock
, codeBlock
->replacement(), codeBlock
->replacement()->speculativeSuccessCounter(), codeBlock
->replacement()->speculativeFailCounter());
2049 CallFrame
* callerFrame
= callFrame
->callerFrame();
2051 dataLog(", callerFrame = %p, returnPC = %p, caller code block = %p", callerFrame
, callFrame
->returnPC().value(), callerFrame
->codeBlock());
2054 if (codeBlock
->replacement()->shouldReoptimizeNow()) {
2055 #if ENABLE(JIT_VERBOSE_OSR)
2056 dataLog("Triggering reoptimization of %p(%p) (in return).\n", codeBlock
, codeBlock
->replacement());
2058 codeBlock
->reoptimize();
2061 codeBlock
->optimizeSoon();
2065 if (!codeBlock
->shouldOptimizeNow()) {
2066 #if ENABLE(JIT_VERBOSE_OSR)
2067 dataLog("Delaying optimization for %p (in return) because of insufficient profiling.\n", codeBlock
);
2072 ScopeChainNode
* scopeChain
= callFrame
->scopeChain();
2074 JSObject
* error
= codeBlock
->compileOptimized(callFrame
, scopeChain
);
2076 dataLog("WARNING: optimized compilation from ret failed.\n");
2078 if (codeBlock
->replacement() == codeBlock
) {
2079 #if ENABLE(JIT_VERBOSE_OSR)
2080 dataLog("Optimizing %p from return failed.\n", codeBlock
);
2083 ASSERT(codeBlock
->getJITType() == JITCode::BaselineJIT
);
2084 codeBlock
->dontOptimizeAnytimeSoon();
2088 ASSERT(codeBlock
->replacement()->getJITType() == JITCode::DFGJIT
);
2090 #if ENABLE(JIT_VERBOSE_OSR)
2091 dataLog("Optimizing %p from return succeeded after a delay of %u.\n", codeBlock
, codeBlock
->optimizationDelayCounter());
2094 codeBlock
->optimizeSoon();
2096 #endif // ENABLE(DFG_JIT)
2098 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_instanceof
)
2100 STUB_INIT_STACK_FRAME(stackFrame
);
2102 CallFrame
* callFrame
= stackFrame
.callFrame
;
2103 JSValue value
= stackFrame
.args
[0].jsValue();
2104 JSValue baseVal
= stackFrame
.args
[1].jsValue();
2105 JSValue proto
= stackFrame
.args
[2].jsValue();
2107 bool result
= CommonSlowPaths::opInstanceOfSlow(callFrame
, value
, baseVal
, proto
);
2108 CHECK_FOR_EXCEPTION_AT_END();
2109 return JSValue::encode(jsBoolean(result
));
2112 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_del_by_id
)
2114 STUB_INIT_STACK_FRAME(stackFrame
);
2116 CallFrame
* callFrame
= stackFrame
.callFrame
;
2118 JSObject
* baseObj
= stackFrame
.args
[0].jsValue().toObject(callFrame
);
2120 bool couldDelete
= baseObj
->methodTable()->deleteProperty(baseObj
, callFrame
, stackFrame
.args
[1].identifier());
2121 JSValue result
= jsBoolean(couldDelete
);
2122 if (!couldDelete
&& callFrame
->codeBlock()->isStrictMode())
2123 stackFrame
.globalData
->exception
= createTypeError(stackFrame
.callFrame
, "Unable to delete property.");
2125 CHECK_FOR_EXCEPTION_AT_END();
2126 return JSValue::encode(result
);
2129 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_mul
)
2131 STUB_INIT_STACK_FRAME(stackFrame
);
2133 JSValue src1
= stackFrame
.args
[0].jsValue();
2134 JSValue src2
= stackFrame
.args
[1].jsValue();
2136 if (src1
.isNumber() && src2
.isNumber())
2137 return JSValue::encode(jsNumber(src1
.asNumber() * src2
.asNumber()));
2139 CallFrame
* callFrame
= stackFrame
.callFrame
;
2140 JSValue result
= jsNumber(src1
.toNumber(callFrame
) * src2
.toNumber(callFrame
));
2141 CHECK_FOR_EXCEPTION_AT_END();
2142 return JSValue::encode(result
);
2145 DEFINE_STUB_FUNCTION(JSObject
*, op_new_func
)
2147 STUB_INIT_STACK_FRAME(stackFrame
);
2149 ASSERT(stackFrame
.callFrame
->codeBlock()->codeType() != FunctionCode
|| !stackFrame
.callFrame
->codeBlock()->needsFullScopeChain() || stackFrame
.callFrame
->uncheckedR(stackFrame
.callFrame
->codeBlock()->activationRegister()).jsValue());
2150 return stackFrame
.args
[0].function()->make(stackFrame
.callFrame
, stackFrame
.callFrame
->scopeChain());
2153 inline void* jitCompileFor(CallFrame
* callFrame
, CodeSpecializationKind kind
)
2155 JSFunction
* function
= jsCast
<JSFunction
*>(callFrame
->callee());
2156 ASSERT(!function
->isHostFunction());
2157 FunctionExecutable
* executable
= function
->jsExecutable();
2158 ScopeChainNode
* callDataScopeChain
= function
->scope();
2159 JSObject
* error
= executable
->compileFor(callFrame
, callDataScopeChain
, kind
);
2162 callFrame
->globalData().exception
= error
;
2166 DEFINE_STUB_FUNCTION(void*, op_call_jitCompile
)
2168 STUB_INIT_STACK_FRAME(stackFrame
);
2170 #if !ASSERT_DISABLED
2172 ASSERT(stackFrame
.callFrame
->callee()->methodTable()->getCallData(stackFrame
.callFrame
->callee(), callData
) == CallTypeJS
);
2175 CallFrame
* callFrame
= stackFrame
.callFrame
;
2176 void* result
= jitCompileFor(callFrame
, CodeForCall
);
2178 return throwExceptionFromOpCall
<void*>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
);
2183 DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile
)
2185 STUB_INIT_STACK_FRAME(stackFrame
);
2187 #if !ASSERT_DISABLED
2188 ConstructData constructData
;
2189 ASSERT(jsCast
<JSFunction
*>(stackFrame
.callFrame
->callee())->methodTable()->getConstructData(stackFrame
.callFrame
->callee(), constructData
) == ConstructTypeJS
);
2192 CallFrame
* callFrame
= stackFrame
.callFrame
;
2193 void* result
= jitCompileFor(callFrame
, CodeForConstruct
);
2195 return throwExceptionFromOpCall
<void*>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
);
2200 DEFINE_STUB_FUNCTION(void*, op_call_arityCheck
)
2202 STUB_INIT_STACK_FRAME(stackFrame
);
2204 CallFrame
* callFrame
= stackFrame
.callFrame
;
2206 CallFrame
* newCallFrame
= CommonSlowPaths::arityCheckFor(callFrame
, stackFrame
.registerFile
, CodeForCall
);
2208 return throwExceptionFromOpCall
<void*>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
, createStackOverflowError(callFrame
->callerFrame()));
2210 return newCallFrame
;
2213 DEFINE_STUB_FUNCTION(void*, op_construct_arityCheck
)
2215 STUB_INIT_STACK_FRAME(stackFrame
);
2217 CallFrame
* callFrame
= stackFrame
.callFrame
;
2219 CallFrame
* newCallFrame
= CommonSlowPaths::arityCheckFor(callFrame
, stackFrame
.registerFile
, CodeForConstruct
);
2221 return throwExceptionFromOpCall
<void*>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
, createStackOverflowError(callFrame
->callerFrame()));
2223 return newCallFrame
;
2226 inline void* lazyLinkFor(CallFrame
* callFrame
, CodeSpecializationKind kind
)
2228 JSFunction
* callee
= jsCast
<JSFunction
*>(callFrame
->callee());
2229 ExecutableBase
* executable
= callee
->executable();
2231 MacroAssemblerCodePtr codePtr
;
2232 CodeBlock
* codeBlock
= 0;
2233 CallLinkInfo
* callLinkInfo
= &callFrame
->callerFrame()->codeBlock()->getCallLinkInfo(callFrame
->returnPC());
2235 if (executable
->isHostFunction())
2236 codePtr
= executable
->generatedJITCodeFor(kind
).addressForCall();
2238 FunctionExecutable
* functionExecutable
= static_cast<FunctionExecutable
*>(executable
);
2239 if (JSObject
* error
= functionExecutable
->compileFor(callFrame
, callee
->scope(), kind
)) {
2240 callFrame
->globalData().exception
= error
;
2243 codeBlock
= &functionExecutable
->generatedBytecodeFor(kind
);
2244 if (callFrame
->argumentCountIncludingThis() < static_cast<size_t>(codeBlock
->numParameters())
2245 || callLinkInfo
->callType
== CallLinkInfo::CallVarargs
)
2246 codePtr
= functionExecutable
->generatedJITCodeWithArityCheckFor(kind
);
2248 codePtr
= functionExecutable
->generatedJITCodeFor(kind
).addressForCall();
2251 if (!callLinkInfo
->seenOnce())
2252 callLinkInfo
->setSeen();
2254 JIT::linkFor(callee
, callFrame
->callerFrame()->codeBlock(), codeBlock
, codePtr
, callLinkInfo
, &callFrame
->globalData(), kind
);
2256 return codePtr
.executableAddress();
2259 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall
)
2261 STUB_INIT_STACK_FRAME(stackFrame
);
2263 CallFrame
* callFrame
= stackFrame
.callFrame
;
2264 void* result
= lazyLinkFor(callFrame
, CodeForCall
);
2266 return throwExceptionFromOpCall
<void*>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
);
2271 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct
)
2273 STUB_INIT_STACK_FRAME(stackFrame
);
2275 CallFrame
* callFrame
= stackFrame
.callFrame
;
2276 void* result
= lazyLinkFor(callFrame
, CodeForConstruct
);
2278 return throwExceptionFromOpCall
<void*>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
);
2283 DEFINE_STUB_FUNCTION(JSObject
*, op_push_activation
)
2285 STUB_INIT_STACK_FRAME(stackFrame
);
2287 JSActivation
* activation
= JSActivation::create(stackFrame
.callFrame
->globalData(), stackFrame
.callFrame
, static_cast<FunctionExecutable
*>(stackFrame
.callFrame
->codeBlock()->ownerExecutable()));
2288 stackFrame
.callFrame
->setScopeChain(stackFrame
.callFrame
->scopeChain()->push(activation
));
2292 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_call_NotJSFunction
)
2294 STUB_INIT_STACK_FRAME(stackFrame
);
2296 CallFrame
* callFrame
= stackFrame
.callFrame
;
2298 JSValue callee
= callFrame
->calleeAsValue();
2301 CallType callType
= getCallData(callee
, callData
);
2303 ASSERT(callType
!= CallTypeJS
);
2304 if (callType
!= CallTypeHost
) {
2305 ASSERT(callType
== CallTypeNone
);
2306 return throwExceptionFromOpCall
<EncodedJSValue
>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
, createNotAFunctionError(callFrame
->callerFrame(), callee
));
2309 EncodedJSValue returnValue
;
2311 SamplingTool::HostCallRecord
callRecord(CTI_SAMPLER
);
2312 returnValue
= callData
.native
.function(callFrame
);
2315 if (stackFrame
.globalData
->exception
)
2316 return throwExceptionFromOpCall
<EncodedJSValue
>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
);
2321 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_create_arguments
)
2323 STUB_INIT_STACK_FRAME(stackFrame
);
2325 Arguments
* arguments
= Arguments::create(*stackFrame
.globalData
, stackFrame
.callFrame
);
2326 return JSValue::encode(JSValue(arguments
));
2329 DEFINE_STUB_FUNCTION(void, op_tear_off_activation
)
2331 STUB_INIT_STACK_FRAME(stackFrame
);
2333 CallFrame
* callFrame
= stackFrame
.callFrame
;
2334 ASSERT(callFrame
->codeBlock()->needsFullScopeChain());
2335 JSValue activationValue
= stackFrame
.args
[0].jsValue();
2336 if (!activationValue
) {
2337 if (JSValue v
= stackFrame
.args
[1].jsValue()) {
2338 if (!callFrame
->codeBlock()->isStrictMode())
2339 asArguments(v
)->tearOff(callFrame
);
2343 JSActivation
* activation
= asActivation(stackFrame
.args
[0].jsValue());
2344 activation
->tearOff(*stackFrame
.globalData
);
2345 if (JSValue v
= stackFrame
.args
[1].jsValue())
2346 asArguments(v
)->didTearOffActivation(*stackFrame
.globalData
, activation
);
2349 DEFINE_STUB_FUNCTION(void, op_tear_off_arguments
)
2351 STUB_INIT_STACK_FRAME(stackFrame
);
2353 CallFrame
* callFrame
= stackFrame
.callFrame
;
2354 ASSERT(callFrame
->codeBlock()->usesArguments() && !callFrame
->codeBlock()->needsFullScopeChain());
2355 asArguments(stackFrame
.args
[0].jsValue())->tearOff(callFrame
);
2358 DEFINE_STUB_FUNCTION(void, op_profile_will_call
)
2360 STUB_INIT_STACK_FRAME(stackFrame
);
2362 ASSERT(*stackFrame
.enabledProfilerReference
);
2363 (*stackFrame
.enabledProfilerReference
)->willExecute(stackFrame
.callFrame
, stackFrame
.args
[0].jsValue());
2366 DEFINE_STUB_FUNCTION(void, op_profile_did_call
)
2368 STUB_INIT_STACK_FRAME(stackFrame
);
2370 ASSERT(*stackFrame
.enabledProfilerReference
);
2371 (*stackFrame
.enabledProfilerReference
)->didExecute(stackFrame
.callFrame
, stackFrame
.args
[0].jsValue());
2374 DEFINE_STUB_FUNCTION(JSObject
*, op_new_array
)
2376 STUB_INIT_STACK_FRAME(stackFrame
);
2378 return constructArray(stackFrame
.callFrame
, reinterpret_cast<JSValue
*>(&stackFrame
.callFrame
->registers()[stackFrame
.args
[0].int32()]), stackFrame
.args
[1].int32());
2381 DEFINE_STUB_FUNCTION(JSObject
*, op_new_array_buffer
)
2383 STUB_INIT_STACK_FRAME(stackFrame
);
2385 return constructArray(stackFrame
.callFrame
, stackFrame
.callFrame
->codeBlock()->constantBuffer(stackFrame
.args
[0].int32()), stackFrame
.args
[1].int32());
2388 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_resolve
)
2390 STUB_INIT_STACK_FRAME(stackFrame
);
2392 CallFrame
* callFrame
= stackFrame
.callFrame
;
2394 JSValue result
= CommonSlowPaths::opResolve(callFrame
, stackFrame
.args
[0].identifier());
2395 CHECK_FOR_EXCEPTION_AT_END();
2396 return JSValue::encode(result
);
2399 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_construct_NotJSConstruct
)
2401 STUB_INIT_STACK_FRAME(stackFrame
);
2403 CallFrame
* callFrame
= stackFrame
.callFrame
;
2404 JSValue callee
= callFrame
->calleeAsValue();
2406 ConstructData constructData
;
2407 ConstructType constructType
= getConstructData(callee
, constructData
);
2409 ASSERT(constructType
!= ConstructTypeJS
);
2410 if (constructType
!= ConstructTypeHost
) {
2411 ASSERT(constructType
== ConstructTypeNone
);
2412 return throwExceptionFromOpCall
<EncodedJSValue
>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
, createNotAConstructorError(callFrame
->callerFrame(), callee
));
2415 EncodedJSValue returnValue
;
2417 SamplingTool::HostCallRecord
callRecord(CTI_SAMPLER
);
2418 returnValue
= constructData
.native
.function(callFrame
);
2421 if (stackFrame
.globalData
->exception
)
2422 return throwExceptionFromOpCall
<EncodedJSValue
>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
);
2427 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_val
)
2429 STUB_INIT_STACK_FRAME(stackFrame
);
2431 CallFrame
* callFrame
= stackFrame
.callFrame
;
2433 JSValue baseValue
= stackFrame
.args
[0].jsValue();
2434 JSValue subscript
= stackFrame
.args
[1].jsValue();
2436 if (LIKELY(baseValue
.isCell() && subscript
.isString())) {
2437 if (JSValue result
= baseValue
.asCell()->fastGetOwnProperty(callFrame
, asString(subscript
)->value(callFrame
))) {
2438 CHECK_FOR_EXCEPTION();
2439 return JSValue::encode(result
);
2443 if (subscript
.isUInt32()) {
2444 uint32_t i
= subscript
.asUInt32();
2445 if (isJSString(baseValue
) && asString(baseValue
)->canGetIndex(i
)) {
2446 ctiPatchCallByReturnAddress(callFrame
->codeBlock(), STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_val_string
));
2447 JSValue result
= asString(baseValue
)->getIndex(callFrame
, i
);
2448 CHECK_FOR_EXCEPTION();
2449 return JSValue::encode(result
);
2451 JSValue result
= baseValue
.get(callFrame
, i
);
2452 CHECK_FOR_EXCEPTION();
2453 return JSValue::encode(result
);
2456 Identifier
property(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
2457 JSValue result
= baseValue
.get(callFrame
, property
);
2458 CHECK_FOR_EXCEPTION_AT_END();
2459 return JSValue::encode(result
);
2462 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_get_by_val_string
)
2464 STUB_INIT_STACK_FRAME(stackFrame
);
2466 CallFrame
* callFrame
= stackFrame
.callFrame
;
2468 JSValue baseValue
= stackFrame
.args
[0].jsValue();
2469 JSValue subscript
= stackFrame
.args
[1].jsValue();
2473 if (LIKELY(subscript
.isUInt32())) {
2474 uint32_t i
= subscript
.asUInt32();
2475 if (isJSString(baseValue
) && asString(baseValue
)->canGetIndex(i
))
2476 result
= asString(baseValue
)->getIndex(callFrame
, i
);
2478 result
= baseValue
.get(callFrame
, i
);
2479 if (!isJSString(baseValue
))
2480 ctiPatchCallByReturnAddress(callFrame
->codeBlock(), STUB_RETURN_ADDRESS
, FunctionPtr(cti_op_get_by_val
));
2483 Identifier
property(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
2484 result
= baseValue
.get(callFrame
, property
);
2487 CHECK_FOR_EXCEPTION_AT_END();
2488 return JSValue::encode(result
);
2491 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_sub
)
2493 STUB_INIT_STACK_FRAME(stackFrame
);
2495 JSValue src1
= stackFrame
.args
[0].jsValue();
2496 JSValue src2
= stackFrame
.args
[1].jsValue();
2498 if (src1
.isNumber() && src2
.isNumber())
2499 return JSValue::encode(jsNumber(src1
.asNumber() - src2
.asNumber()));
2501 CallFrame
* callFrame
= stackFrame
.callFrame
;
2502 JSValue result
= jsNumber(src1
.toNumber(callFrame
) - src2
.toNumber(callFrame
));
2503 CHECK_FOR_EXCEPTION_AT_END();
2504 return JSValue::encode(result
);
2507 DEFINE_STUB_FUNCTION(void, op_put_by_val
)
2509 STUB_INIT_STACK_FRAME(stackFrame
);
2511 CallFrame
* callFrame
= stackFrame
.callFrame
;
2512 JSGlobalData
* globalData
= stackFrame
.globalData
;
2514 JSValue baseValue
= stackFrame
.args
[0].jsValue();
2515 JSValue subscript
= stackFrame
.args
[1].jsValue();
2516 JSValue value
= stackFrame
.args
[2].jsValue();
2518 if (LIKELY(subscript
.isUInt32())) {
2519 uint32_t i
= subscript
.asUInt32();
2520 if (isJSArray(baseValue
)) {
2521 JSArray
* jsArray
= asArray(baseValue
);
2522 if (jsArray
->canSetIndex(i
))
2523 jsArray
->setIndex(*globalData
, i
, value
);
2525 JSArray::putByIndex(jsArray
, callFrame
, i
, value
, callFrame
->codeBlock()->isStrictMode());
2527 baseValue
.putByIndex(callFrame
, i
, value
, callFrame
->codeBlock()->isStrictMode());
2529 Identifier
property(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
2530 if (!stackFrame
.globalData
->exception
) { // Don't put to an object if toString threw an exception.
2531 PutPropertySlot
slot(callFrame
->codeBlock()->isStrictMode());
2532 baseValue
.put(callFrame
, property
, value
, slot
);
2536 CHECK_FOR_EXCEPTION_AT_END();
2539 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_less
)
2541 STUB_INIT_STACK_FRAME(stackFrame
);
2543 CallFrame
* callFrame
= stackFrame
.callFrame
;
2544 JSValue result
= jsBoolean(jsLess
<true>(callFrame
, stackFrame
.args
[0].jsValue(), stackFrame
.args
[1].jsValue()));
2545 CHECK_FOR_EXCEPTION_AT_END();
2546 return JSValue::encode(result
);
2549 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_lesseq
)
2551 STUB_INIT_STACK_FRAME(stackFrame
);
2553 CallFrame
* callFrame
= stackFrame
.callFrame
;
2554 JSValue result
= jsBoolean(jsLessEq
<true>(callFrame
, stackFrame
.args
[0].jsValue(), stackFrame
.args
[1].jsValue()));
2555 CHECK_FOR_EXCEPTION_AT_END();
2556 return JSValue::encode(result
);
2559 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_greater
)
2561 STUB_INIT_STACK_FRAME(stackFrame
);
2563 CallFrame
* callFrame
= stackFrame
.callFrame
;
2564 JSValue result
= jsBoolean(jsLess
<false>(callFrame
, stackFrame
.args
[1].jsValue(), stackFrame
.args
[0].jsValue()));
2565 CHECK_FOR_EXCEPTION_AT_END();
2566 return JSValue::encode(result
);
2569 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_greatereq
)
2571 STUB_INIT_STACK_FRAME(stackFrame
);
2573 CallFrame
* callFrame
= stackFrame
.callFrame
;
2574 JSValue result
= jsBoolean(jsLessEq
<false>(callFrame
, stackFrame
.args
[1].jsValue(), stackFrame
.args
[0].jsValue()));
2575 CHECK_FOR_EXCEPTION_AT_END();
2576 return JSValue::encode(result
);
2579 DEFINE_STUB_FUNCTION(void*, op_load_varargs
)
2581 STUB_INIT_STACK_FRAME(stackFrame
);
2583 CallFrame
* callFrame
= stackFrame
.callFrame
;
2584 RegisterFile
* registerFile
= stackFrame
.registerFile
;
2585 JSValue thisValue
= stackFrame
.args
[0].jsValue();
2586 JSValue arguments
= stackFrame
.args
[1].jsValue();
2587 int firstFreeRegister
= stackFrame
.args
[2].int32();
2589 CallFrame
* newCallFrame
= loadVarargs(callFrame
, registerFile
, thisValue
, arguments
, firstFreeRegister
);
2591 VM_THROW_EXCEPTION();
2592 return newCallFrame
;
2595 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_negate
)
2597 STUB_INIT_STACK_FRAME(stackFrame
);
2599 JSValue src
= stackFrame
.args
[0].jsValue();
2602 return JSValue::encode(jsNumber(-src
.asNumber()));
2604 CallFrame
* callFrame
= stackFrame
.callFrame
;
2605 JSValue result
= jsNumber(-src
.toNumber(callFrame
));
2606 CHECK_FOR_EXCEPTION_AT_END();
2607 return JSValue::encode(result
);
2610 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_resolve_base
)
2612 STUB_INIT_STACK_FRAME(stackFrame
);
2614 return JSValue::encode(JSC::resolveBase(stackFrame
.callFrame
, stackFrame
.args
[0].identifier(), stackFrame
.callFrame
->scopeChain(), false));
2617 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_resolve_base_strict_put
)
2619 STUB_INIT_STACK_FRAME(stackFrame
);
2620 JSValue base
= JSC::resolveBase(stackFrame
.callFrame
, stackFrame
.args
[0].identifier(), stackFrame
.callFrame
->scopeChain(), true);
2622 stackFrame
.globalData
->exception
= createErrorForInvalidGlobalAssignment(stackFrame
.callFrame
, stackFrame
.args
[0].identifier().ustring());
2623 VM_THROW_EXCEPTION();
2625 return JSValue::encode(base
);
2628 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_ensure_property_exists
)
2630 STUB_INIT_STACK_FRAME(stackFrame
);
2631 JSValue base
= stackFrame
.callFrame
->r(stackFrame
.args
[0].int32()).jsValue();
2632 JSObject
* object
= asObject(base
);
2633 PropertySlot
slot(object
);
2634 ASSERT(stackFrame
.callFrame
->codeBlock()->isStrictMode());
2635 if (!object
->getPropertySlot(stackFrame
.callFrame
, stackFrame
.args
[1].identifier(), slot
)) {
2636 stackFrame
.globalData
->exception
= createErrorForInvalidGlobalAssignment(stackFrame
.callFrame
, stackFrame
.args
[1].identifier().ustring());
2637 VM_THROW_EXCEPTION();
2640 return JSValue::encode(base
);
2643 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_resolve_skip
)
2645 STUB_INIT_STACK_FRAME(stackFrame
);
2647 JSValue result
= CommonSlowPaths::opResolveSkip(stackFrame
.callFrame
, stackFrame
.args
[0].identifier(), stackFrame
.args
[1].int32());
2648 CHECK_FOR_EXCEPTION_AT_END();
2649 return JSValue::encode(result
);
2652 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_resolve_global
)
2654 STUB_INIT_STACK_FRAME(stackFrame
);
2656 CallFrame
* callFrame
= stackFrame
.callFrame
;
2657 CodeBlock
* codeBlock
= callFrame
->codeBlock();
2658 JSGlobalObject
* globalObject
= codeBlock
->globalObject();
2659 Identifier
& ident
= stackFrame
.args
[0].identifier();
2660 unsigned globalResolveInfoIndex
= stackFrame
.args
[1].int32();
2661 ASSERT(globalObject
->isGlobalObject());
2663 PropertySlot
slot(globalObject
);
2664 if (globalObject
->getPropertySlot(callFrame
, ident
, slot
)) {
2665 JSValue result
= slot
.getValue(callFrame
, ident
);
2666 if (slot
.isCacheableValue() && !globalObject
->structure()->isUncacheableDictionary() && slot
.slotBase() == globalObject
) {
2667 GlobalResolveInfo
& globalResolveInfo
= codeBlock
->globalResolveInfo(globalResolveInfoIndex
);
2668 globalResolveInfo
.structure
.set(callFrame
->globalData(), codeBlock
->ownerExecutable(), globalObject
->structure());
2669 globalResolveInfo
.offset
= slot
.cachedOffset();
2670 return JSValue::encode(result
);
2673 CHECK_FOR_EXCEPTION_AT_END();
2674 return JSValue::encode(result
);
2677 stackFrame
.globalData
->exception
= createUndefinedVariableError(callFrame
, ident
);
2678 VM_THROW_EXCEPTION();
2681 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_div
)
2683 STUB_INIT_STACK_FRAME(stackFrame
);
2685 JSValue src1
= stackFrame
.args
[0].jsValue();
2686 JSValue src2
= stackFrame
.args
[1].jsValue();
2688 if (src1
.isNumber() && src2
.isNumber())
2689 return JSValue::encode(jsNumber(src1
.asNumber() / src2
.asNumber()));
2691 CallFrame
* callFrame
= stackFrame
.callFrame
;
2692 JSValue result
= jsNumber(src1
.toNumber(callFrame
) / src2
.toNumber(callFrame
));
2693 CHECK_FOR_EXCEPTION_AT_END();
2694 return JSValue::encode(result
);
2697 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_pre_dec
)
2699 STUB_INIT_STACK_FRAME(stackFrame
);
2701 JSValue v
= stackFrame
.args
[0].jsValue();
2703 CallFrame
* callFrame
= stackFrame
.callFrame
;
2704 JSValue result
= jsNumber(v
.toNumber(callFrame
) - 1);
2705 CHECK_FOR_EXCEPTION_AT_END();
2706 return JSValue::encode(result
);
2709 DEFINE_STUB_FUNCTION(int, op_jless
)
2711 STUB_INIT_STACK_FRAME(stackFrame
);
2713 JSValue src1
= stackFrame
.args
[0].jsValue();
2714 JSValue src2
= stackFrame
.args
[1].jsValue();
2715 CallFrame
* callFrame
= stackFrame
.callFrame
;
2717 bool result
= jsLess
<true>(callFrame
, src1
, src2
);
2718 CHECK_FOR_EXCEPTION_AT_END();
2722 DEFINE_STUB_FUNCTION(int, op_jlesseq
)
2724 STUB_INIT_STACK_FRAME(stackFrame
);
2726 JSValue src1
= stackFrame
.args
[0].jsValue();
2727 JSValue src2
= stackFrame
.args
[1].jsValue();
2728 CallFrame
* callFrame
= stackFrame
.callFrame
;
2730 bool result
= jsLessEq
<true>(callFrame
, src1
, src2
);
2731 CHECK_FOR_EXCEPTION_AT_END();
2735 DEFINE_STUB_FUNCTION(int, op_jgreater
)
2737 STUB_INIT_STACK_FRAME(stackFrame
);
2739 JSValue src1
= stackFrame
.args
[0].jsValue();
2740 JSValue src2
= stackFrame
.args
[1].jsValue();
2741 CallFrame
* callFrame
= stackFrame
.callFrame
;
2743 bool result
= jsLess
<false>(callFrame
, src2
, src1
);
2744 CHECK_FOR_EXCEPTION_AT_END();
2748 DEFINE_STUB_FUNCTION(int, op_jgreatereq
)
2750 STUB_INIT_STACK_FRAME(stackFrame
);
2752 JSValue src1
= stackFrame
.args
[0].jsValue();
2753 JSValue src2
= stackFrame
.args
[1].jsValue();
2754 CallFrame
* callFrame
= stackFrame
.callFrame
;
2756 bool result
= jsLessEq
<false>(callFrame
, src2
, src1
);
2757 CHECK_FOR_EXCEPTION_AT_END();
2761 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_not
)
2763 STUB_INIT_STACK_FRAME(stackFrame
);
2765 JSValue src
= stackFrame
.args
[0].jsValue();
2767 CallFrame
* callFrame
= stackFrame
.callFrame
;
2769 JSValue result
= jsBoolean(!src
.toBoolean(callFrame
));
2770 CHECK_FOR_EXCEPTION_AT_END();
2771 return JSValue::encode(result
);
2774 DEFINE_STUB_FUNCTION(int, op_jtrue
)
2776 STUB_INIT_STACK_FRAME(stackFrame
);
2778 JSValue src1
= stackFrame
.args
[0].jsValue();
2780 CallFrame
* callFrame
= stackFrame
.callFrame
;
2782 bool result
= src1
.toBoolean(callFrame
);
2783 CHECK_FOR_EXCEPTION_AT_END();
2787 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_post_inc
)
2789 STUB_INIT_STACK_FRAME(stackFrame
);
2791 JSValue v
= stackFrame
.args
[0].jsValue();
2793 CallFrame
* callFrame
= stackFrame
.callFrame
;
2795 double number
= v
.toNumber(callFrame
);
2796 CHECK_FOR_EXCEPTION_AT_END();
2798 callFrame
->registers()[stackFrame
.args
[1].int32()] = jsNumber(number
+ 1);
2799 return JSValue::encode(jsNumber(number
));
2802 DEFINE_STUB_FUNCTION(int, op_eq
)
2804 STUB_INIT_STACK_FRAME(stackFrame
);
2806 JSValue src1
= stackFrame
.args
[0].jsValue();
2807 JSValue src2
= stackFrame
.args
[1].jsValue();
2809 #if USE(JSVALUE32_64)
2811 if (src2
.isUndefined()) {
2812 return src1
.isNull() ||
2813 (src1
.isCell() && src1
.asCell()->structure()->typeInfo().masqueradesAsUndefined())
2814 || src1
.isUndefined();
2817 if (src2
.isNull()) {
2818 return src1
.isUndefined() ||
2819 (src1
.isCell() && src1
.asCell()->structure()->typeInfo().masqueradesAsUndefined())
2823 if (src1
.isInt32()) {
2824 if (src2
.isDouble())
2825 return src1
.asInt32() == src2
.asDouble();
2826 double d
= src2
.toNumber(stackFrame
.callFrame
);
2827 CHECK_FOR_EXCEPTION();
2828 return src1
.asInt32() == d
;
2831 if (src1
.isDouble()) {
2833 return src1
.asDouble() == src2
.asInt32();
2834 double d
= src2
.toNumber(stackFrame
.callFrame
);
2835 CHECK_FOR_EXCEPTION();
2836 return src1
.asDouble() == d
;
2839 if (src1
.isTrue()) {
2842 double d
= src2
.toNumber(stackFrame
.callFrame
);
2843 CHECK_FOR_EXCEPTION();
2847 if (src1
.isFalse()) {
2850 double d
= src2
.toNumber(stackFrame
.callFrame
);
2851 CHECK_FOR_EXCEPTION();
2855 if (src1
.isUndefined())
2856 return src2
.isCell() && src2
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
2859 return src2
.isCell() && src2
.asCell()->structure()->typeInfo().masqueradesAsUndefined();
2861 JSCell
* cell1
= src1
.asCell();
2863 if (cell1
->isString()) {
2865 return jsToNumber(jsCast
<JSString
*>(cell1
)->value(stackFrame
.callFrame
)) == src2
.asInt32();
2867 if (src2
.isDouble())
2868 return jsToNumber(jsCast
<JSString
*>(cell1
)->value(stackFrame
.callFrame
)) == src2
.asDouble();
2871 return jsToNumber(jsCast
<JSString
*>(cell1
)->value(stackFrame
.callFrame
)) == 1.0;
2874 return jsToNumber(jsCast
<JSString
*>(cell1
)->value(stackFrame
.callFrame
)) == 0.0;
2876 JSCell
* cell2
= src2
.asCell();
2877 if (cell2
->isString())
2878 return jsCast
<JSString
*>(cell1
)->value(stackFrame
.callFrame
) == jsCast
<JSString
*>(cell2
)->value(stackFrame
.callFrame
);
2880 src2
= asObject(cell2
)->toPrimitive(stackFrame
.callFrame
);
2881 CHECK_FOR_EXCEPTION();
2885 if (src2
.isObject())
2886 return asObject(cell1
) == asObject(src2
);
2887 src1
= asObject(cell1
)->toPrimitive(stackFrame
.callFrame
);
2888 CHECK_FOR_EXCEPTION();
2891 #else // USE(JSVALUE32_64)
2892 CallFrame
* callFrame
= stackFrame
.callFrame
;
2894 bool result
= JSValue::equalSlowCaseInline(callFrame
, src1
, src2
);
2895 CHECK_FOR_EXCEPTION_AT_END();
2897 #endif // USE(JSVALUE32_64)
2900 DEFINE_STUB_FUNCTION(int, op_eq_strings
)
2902 #if USE(JSVALUE32_64)
2903 STUB_INIT_STACK_FRAME(stackFrame
);
2905 JSString
* string1
= stackFrame
.args
[0].jsString();
2906 JSString
* string2
= stackFrame
.args
[1].jsString();
2908 ASSERT(string1
->isString());
2909 ASSERT(string2
->isString());
2910 return string1
->value(stackFrame
.callFrame
) == string2
->value(stackFrame
.callFrame
);
2913 ASSERT_NOT_REACHED();
2918 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_lshift
)
2920 STUB_INIT_STACK_FRAME(stackFrame
);
2922 JSValue val
= stackFrame
.args
[0].jsValue();
2923 JSValue shift
= stackFrame
.args
[1].jsValue();
2925 CallFrame
* callFrame
= stackFrame
.callFrame
;
2926 JSValue result
= jsNumber((val
.toInt32(callFrame
)) << (shift
.toUInt32(callFrame
) & 0x1f));
2927 CHECK_FOR_EXCEPTION_AT_END();
2928 return JSValue::encode(result
);
2931 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_bitand
)
2933 STUB_INIT_STACK_FRAME(stackFrame
);
2935 JSValue src1
= stackFrame
.args
[0].jsValue();
2936 JSValue src2
= stackFrame
.args
[1].jsValue();
2938 ASSERT(!src1
.isInt32() || !src2
.isInt32());
2939 CallFrame
* callFrame
= stackFrame
.callFrame
;
2940 JSValue result
= jsNumber(src1
.toInt32(callFrame
) & src2
.toInt32(callFrame
));
2941 CHECK_FOR_EXCEPTION_AT_END();
2942 return JSValue::encode(result
);
2945 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_rshift
)
2947 STUB_INIT_STACK_FRAME(stackFrame
);
2949 JSValue val
= stackFrame
.args
[0].jsValue();
2950 JSValue shift
= stackFrame
.args
[1].jsValue();
2952 CallFrame
* callFrame
= stackFrame
.callFrame
;
2953 JSValue result
= jsNumber((val
.toInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
2955 CHECK_FOR_EXCEPTION_AT_END();
2956 return JSValue::encode(result
);
2959 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_resolve_with_base
)
2961 STUB_INIT_STACK_FRAME(stackFrame
);
2963 CallFrame
* callFrame
= stackFrame
.callFrame
;
2964 JSValue result
= CommonSlowPaths::opResolveWithBase(callFrame
, stackFrame
.args
[0].identifier(), callFrame
->registers()[stackFrame
.args
[1].int32()]);
2965 CHECK_FOR_EXCEPTION_AT_END();
2966 return JSValue::encode(result
);
2969 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_resolve_with_this
)
2971 STUB_INIT_STACK_FRAME(stackFrame
);
2973 CallFrame
* callFrame
= stackFrame
.callFrame
;
2974 JSValue result
= CommonSlowPaths::opResolveWithThis(callFrame
, stackFrame
.args
[0].identifier(), callFrame
->registers()[stackFrame
.args
[1].int32()]);
2975 CHECK_FOR_EXCEPTION_AT_END();
2976 return JSValue::encode(result
);
2979 DEFINE_STUB_FUNCTION(JSObject
*, op_new_func_exp
)
2981 STUB_INIT_STACK_FRAME(stackFrame
);
2982 CallFrame
* callFrame
= stackFrame
.callFrame
;
2984 FunctionExecutable
* function
= stackFrame
.args
[0].function();
2985 JSFunction
* func
= function
->make(callFrame
, callFrame
->scopeChain());
2986 ASSERT(callFrame
->codeBlock()->codeType() != FunctionCode
|| !callFrame
->codeBlock()->needsFullScopeChain() || callFrame
->uncheckedR(callFrame
->codeBlock()->activationRegister()).jsValue());
2989 The Identifier in a FunctionExpression can be referenced from inside
2990 the FunctionExpression's FunctionBody to allow the function to call
2991 itself recursively. However, unlike in a FunctionDeclaration, the
2992 Identifier in a FunctionExpression cannot be referenced from and
2993 does not affect the scope enclosing the FunctionExpression.
2995 if (!function
->name().isNull()) {
2996 JSStaticScopeObject
* functionScopeObject
= JSStaticScopeObject::create(callFrame
, function
->name(), func
, ReadOnly
| DontDelete
);
2997 func
->setScope(callFrame
->globalData(), func
->scope()->push(functionScopeObject
));
3003 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_mod
)
3005 STUB_INIT_STACK_FRAME(stackFrame
);
3007 JSValue dividendValue
= stackFrame
.args
[0].jsValue();
3008 JSValue divisorValue
= stackFrame
.args
[1].jsValue();
3010 CallFrame
* callFrame
= stackFrame
.callFrame
;
3011 double d
= dividendValue
.toNumber(callFrame
);
3012 JSValue result
= jsNumber(fmod(d
, divisorValue
.toNumber(callFrame
)));
3013 CHECK_FOR_EXCEPTION_AT_END();
3014 return JSValue::encode(result
);
3017 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_post_dec
)
3019 STUB_INIT_STACK_FRAME(stackFrame
);
3021 JSValue v
= stackFrame
.args
[0].jsValue();
3023 CallFrame
* callFrame
= stackFrame
.callFrame
;
3025 double number
= v
.toNumber(callFrame
);
3026 CHECK_FOR_EXCEPTION_AT_END();
3028 callFrame
->registers()[stackFrame
.args
[1].int32()] = jsNumber(number
- 1);
3029 return JSValue::encode(jsNumber(number
));
3032 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_urshift
)
3034 STUB_INIT_STACK_FRAME(stackFrame
);
3036 JSValue val
= stackFrame
.args
[0].jsValue();
3037 JSValue shift
= stackFrame
.args
[1].jsValue();
3039 CallFrame
* callFrame
= stackFrame
.callFrame
;
3040 JSValue result
= jsNumber((val
.toUInt32(callFrame
)) >> (shift
.toUInt32(callFrame
) & 0x1f));
3041 CHECK_FOR_EXCEPTION_AT_END();
3042 return JSValue::encode(result
);
3045 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_bitxor
)
3047 STUB_INIT_STACK_FRAME(stackFrame
);
3049 JSValue src1
= stackFrame
.args
[0].jsValue();
3050 JSValue src2
= stackFrame
.args
[1].jsValue();
3052 CallFrame
* callFrame
= stackFrame
.callFrame
;
3054 JSValue result
= jsNumber(src1
.toInt32(callFrame
) ^ src2
.toInt32(callFrame
));
3055 CHECK_FOR_EXCEPTION_AT_END();
3056 return JSValue::encode(result
);
3059 DEFINE_STUB_FUNCTION(JSObject
*, op_new_regexp
)
3061 STUB_INIT_STACK_FRAME(stackFrame
);
3063 CallFrame
* callFrame
= stackFrame
.callFrame
;
3065 RegExp
* regExp
= stackFrame
.args
[0].regExp();
3066 if (!regExp
->isValid()) {
3067 stackFrame
.globalData
->exception
= createSyntaxError(callFrame
, "Invalid flags supplied to RegExp constructor.");
3068 VM_THROW_EXCEPTION();
3071 return RegExpObject::create(*stackFrame
.globalData
, stackFrame
.callFrame
->lexicalGlobalObject(), stackFrame
.callFrame
->lexicalGlobalObject()->regExpStructure(), regExp
);
3074 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_bitor
)
3076 STUB_INIT_STACK_FRAME(stackFrame
);
3078 JSValue src1
= stackFrame
.args
[0].jsValue();
3079 JSValue src2
= stackFrame
.args
[1].jsValue();
3081 CallFrame
* callFrame
= stackFrame
.callFrame
;
3083 JSValue result
= jsNumber(src1
.toInt32(callFrame
) | src2
.toInt32(callFrame
));
3084 CHECK_FOR_EXCEPTION_AT_END();
3085 return JSValue::encode(result
);
3088 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_call_eval
)
3090 STUB_INIT_STACK_FRAME(stackFrame
);
3092 CallFrame
* callFrame
= stackFrame
.callFrame
;
3093 CallFrame
* callerFrame
= callFrame
->callerFrame();
3094 ASSERT(callFrame
->callerFrame()->codeBlock()->codeType() != FunctionCode
3095 || !callFrame
->callerFrame()->codeBlock()->needsFullScopeChain()
3096 || callFrame
->callerFrame()->uncheckedR(callFrame
->callerFrame()->codeBlock()->activationRegister()).jsValue());
3098 callFrame
->setScopeChain(callerFrame
->scopeChain());
3099 callFrame
->setReturnPC(static_cast<Instruction
*>((STUB_RETURN_ADDRESS
).value()));
3100 callFrame
->setCodeBlock(0);
3102 if (!isHostFunction(callFrame
->calleeAsValue(), globalFuncEval
))
3103 return JSValue::encode(JSValue());
3105 JSValue result
= eval(callFrame
);
3106 if (stackFrame
.globalData
->exception
)
3107 return throwExceptionFromOpCall
<EncodedJSValue
>(stackFrame
, callFrame
, STUB_RETURN_ADDRESS
);
3109 return JSValue::encode(result
);
3112 DEFINE_STUB_FUNCTION(void*, op_throw
)
3114 STUB_INIT_STACK_FRAME(stackFrame
);
3115 ExceptionHandler handler
= jitThrow(stackFrame
.globalData
, stackFrame
.callFrame
, stackFrame
.args
[0].jsValue(), STUB_RETURN_ADDRESS
);
3116 STUB_SET_RETURN_ADDRESS(handler
.catchRoutine
);
3117 return handler
.callFrame
;
3120 DEFINE_STUB_FUNCTION(JSPropertyNameIterator
*, op_get_pnames
)
3122 STUB_INIT_STACK_FRAME(stackFrame
);
3124 CallFrame
* callFrame
= stackFrame
.callFrame
;
3125 JSObject
* o
= stackFrame
.args
[0].jsObject();
3126 Structure
* structure
= o
->structure();
3127 JSPropertyNameIterator
* jsPropertyNameIterator
= structure
->enumerationCache();
3128 if (!jsPropertyNameIterator
|| jsPropertyNameIterator
->cachedPrototypeChain() != structure
->prototypeChain(callFrame
))
3129 jsPropertyNameIterator
= JSPropertyNameIterator::create(callFrame
, o
);
3130 return jsPropertyNameIterator
;
3133 DEFINE_STUB_FUNCTION(int, has_property
)
3135 STUB_INIT_STACK_FRAME(stackFrame
);
3137 JSObject
* base
= stackFrame
.args
[0].jsObject();
3138 JSString
* property
= stackFrame
.args
[1].jsString();
3139 int result
= base
->hasProperty(stackFrame
.callFrame
, Identifier(stackFrame
.callFrame
, property
->value(stackFrame
.callFrame
)));
3140 CHECK_FOR_EXCEPTION_AT_END();
3144 DEFINE_STUB_FUNCTION(JSObject
*, op_push_scope
)
3146 STUB_INIT_STACK_FRAME(stackFrame
);
3148 JSObject
* o
= stackFrame
.args
[0].jsValue().toObject(stackFrame
.callFrame
);
3149 CHECK_FOR_EXCEPTION();
3150 stackFrame
.callFrame
->setScopeChain(stackFrame
.callFrame
->scopeChain()->push(o
));
3154 DEFINE_STUB_FUNCTION(void, op_pop_scope
)
3156 STUB_INIT_STACK_FRAME(stackFrame
);
3158 stackFrame
.callFrame
->setScopeChain(stackFrame
.callFrame
->scopeChain()->pop());
3161 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_typeof
)
3163 STUB_INIT_STACK_FRAME(stackFrame
);
3165 return JSValue::encode(jsTypeStringForValue(stackFrame
.callFrame
, stackFrame
.args
[0].jsValue()));
3168 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_is_object
)
3170 STUB_INIT_STACK_FRAME(stackFrame
);
3172 return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame
.args
[0].jsValue())));
3175 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_is_function
)
3177 STUB_INIT_STACK_FRAME(stackFrame
);
3179 return JSValue::encode(jsBoolean(jsIsFunctionType(stackFrame
.args
[0].jsValue())));
3182 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_stricteq
)
3184 STUB_INIT_STACK_FRAME(stackFrame
);
3186 JSValue src1
= stackFrame
.args
[0].jsValue();
3187 JSValue src2
= stackFrame
.args
[1].jsValue();
3189 bool result
= JSValue::strictEqual(stackFrame
.callFrame
, src1
, src2
);
3190 CHECK_FOR_EXCEPTION_AT_END();
3191 return JSValue::encode(jsBoolean(result
));
3194 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_to_primitive
)
3196 STUB_INIT_STACK_FRAME(stackFrame
);
3198 return JSValue::encode(stackFrame
.args
[0].jsValue().toPrimitive(stackFrame
.callFrame
));
3201 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_strcat
)
3203 STUB_INIT_STACK_FRAME(stackFrame
);
3205 JSValue result
= jsString(stackFrame
.callFrame
, &stackFrame
.callFrame
->registers()[stackFrame
.args
[0].int32()], stackFrame
.args
[1].int32());
3206 CHECK_FOR_EXCEPTION_AT_END();
3207 return JSValue::encode(result
);
3210 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_nstricteq
)
3212 STUB_INIT_STACK_FRAME(stackFrame
);
3214 JSValue src1
= stackFrame
.args
[0].jsValue();
3215 JSValue src2
= stackFrame
.args
[1].jsValue();
3217 bool result
= !JSValue::strictEqual(stackFrame
.callFrame
, src1
, src2
);
3218 CHECK_FOR_EXCEPTION_AT_END();
3219 return JSValue::encode(jsBoolean(result
));
3222 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_to_jsnumber
)
3224 STUB_INIT_STACK_FRAME(stackFrame
);
3226 JSValue src
= stackFrame
.args
[0].jsValue();
3227 CallFrame
* callFrame
= stackFrame
.callFrame
;
3229 double number
= src
.toNumber(callFrame
);
3230 CHECK_FOR_EXCEPTION_AT_END();
3231 return JSValue::encode(jsNumber(number
));
3234 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_in
)
3236 STUB_INIT_STACK_FRAME(stackFrame
);
3238 CallFrame
* callFrame
= stackFrame
.callFrame
;
3239 JSValue baseVal
= stackFrame
.args
[1].jsValue();
3241 if (!baseVal
.isObject()) {
3242 stackFrame
.globalData
->exception
= createInvalidParamError(stackFrame
.callFrame
, "in", baseVal
);
3243 VM_THROW_EXCEPTION();
3246 JSValue propName
= stackFrame
.args
[0].jsValue();
3247 JSObject
* baseObj
= asObject(baseVal
);
3250 if (propName
.getUInt32(i
))
3251 return JSValue::encode(jsBoolean(baseObj
->hasProperty(callFrame
, i
)));
3253 Identifier
property(callFrame
, propName
.toString(callFrame
)->value(callFrame
));
3254 CHECK_FOR_EXCEPTION();
3255 return JSValue::encode(jsBoolean(baseObj
->hasProperty(callFrame
, property
)));
3258 DEFINE_STUB_FUNCTION(JSObject
*, op_push_new_scope
)
3260 STUB_INIT_STACK_FRAME(stackFrame
);
3262 JSObject
* scope
= JSStaticScopeObject::create(stackFrame
.callFrame
, stackFrame
.args
[0].identifier(), stackFrame
.args
[1].jsValue(), DontDelete
);
3264 CallFrame
* callFrame
= stackFrame
.callFrame
;
3265 callFrame
->setScopeChain(callFrame
->scopeChain()->push(scope
));
3269 DEFINE_STUB_FUNCTION(void, op_jmp_scopes
)
3271 STUB_INIT_STACK_FRAME(stackFrame
);
3273 unsigned count
= stackFrame
.args
[0].int32();
3274 CallFrame
* callFrame
= stackFrame
.callFrame
;
3276 ScopeChainNode
* tmp
= callFrame
->scopeChain();
3279 callFrame
->setScopeChain(tmp
);
3282 DEFINE_STUB_FUNCTION(void, op_put_by_index
)
3284 STUB_INIT_STACK_FRAME(stackFrame
);
3286 CallFrame
* callFrame
= stackFrame
.callFrame
;
3287 unsigned property
= stackFrame
.args
[1].int32();
3289 JSValue arrayValue
= stackFrame
.args
[0].jsValue();
3290 ASSERT(isJSArray(arrayValue
));
3291 asArray(arrayValue
)->putDirectIndex(callFrame
, property
, stackFrame
.args
[2].jsValue(), false);
3294 DEFINE_STUB_FUNCTION(void*, op_switch_imm
)
3296 STUB_INIT_STACK_FRAME(stackFrame
);
3298 JSValue scrutinee
= stackFrame
.args
[0].jsValue();
3299 unsigned tableIndex
= stackFrame
.args
[1].int32();
3300 CallFrame
* callFrame
= stackFrame
.callFrame
;
3301 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3303 if (scrutinee
.isInt32())
3304 return codeBlock
->immediateSwitchJumpTable(tableIndex
).ctiForValue(scrutinee
.asInt32()).executableAddress();
3305 if (scrutinee
.isDouble() && scrutinee
.asDouble() == static_cast<int32_t>(scrutinee
.asDouble()))
3306 return codeBlock
->immediateSwitchJumpTable(tableIndex
).ctiForValue(static_cast<int32_t>(scrutinee
.asDouble())).executableAddress();
3307 return codeBlock
->immediateSwitchJumpTable(tableIndex
).ctiDefault
.executableAddress();
3310 DEFINE_STUB_FUNCTION(void*, op_switch_char
)
3312 STUB_INIT_STACK_FRAME(stackFrame
);
3314 JSValue scrutinee
= stackFrame
.args
[0].jsValue();
3315 unsigned tableIndex
= stackFrame
.args
[1].int32();
3316 CallFrame
* callFrame
= stackFrame
.callFrame
;
3317 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3319 void* result
= codeBlock
->characterSwitchJumpTable(tableIndex
).ctiDefault
.executableAddress();
3321 if (scrutinee
.isString()) {
3322 StringImpl
* value
= asString(scrutinee
)->value(callFrame
).impl();
3323 if (value
->length() == 1)
3324 result
= codeBlock
->characterSwitchJumpTable(tableIndex
).ctiForValue((*value
)[0]).executableAddress();
3327 CHECK_FOR_EXCEPTION_AT_END();
3331 DEFINE_STUB_FUNCTION(void*, op_switch_string
)
3333 STUB_INIT_STACK_FRAME(stackFrame
);
3335 JSValue scrutinee
= stackFrame
.args
[0].jsValue();
3336 unsigned tableIndex
= stackFrame
.args
[1].int32();
3337 CallFrame
* callFrame
= stackFrame
.callFrame
;
3338 CodeBlock
* codeBlock
= callFrame
->codeBlock();
3340 void* result
= codeBlock
->stringSwitchJumpTable(tableIndex
).ctiDefault
.executableAddress();
3342 if (scrutinee
.isString()) {
3343 StringImpl
* value
= asString(scrutinee
)->value(callFrame
).impl();
3344 result
= codeBlock
->stringSwitchJumpTable(tableIndex
).ctiForValue(value
).executableAddress();
3347 CHECK_FOR_EXCEPTION_AT_END();
3351 DEFINE_STUB_FUNCTION(EncodedJSValue
, op_del_by_val
)
3353 STUB_INIT_STACK_FRAME(stackFrame
);
3355 CallFrame
* callFrame
= stackFrame
.callFrame
;
3357 JSValue baseValue
= stackFrame
.args
[0].jsValue();
3358 JSObject
* baseObj
= baseValue
.toObject(callFrame
); // may throw
3360 JSValue subscript
= stackFrame
.args
[1].jsValue();
3363 if (subscript
.getUInt32(i
))
3364 result
= baseObj
->methodTable()->deletePropertyByIndex(baseObj
, callFrame
, i
);
3366 CHECK_FOR_EXCEPTION();
3367 Identifier
property(callFrame
, subscript
.toString(callFrame
)->value(callFrame
));
3368 CHECK_FOR_EXCEPTION();
3369 result
= baseObj
->methodTable()->deleteProperty(baseObj
, callFrame
, property
);
3372 if (!result
&& callFrame
->codeBlock()->isStrictMode())
3373 stackFrame
.globalData
->exception
= createTypeError(stackFrame
.callFrame
, "Unable to delete property.");
3375 CHECK_FOR_EXCEPTION_AT_END();
3376 return JSValue::encode(jsBoolean(result
));
3379 DEFINE_STUB_FUNCTION(void, op_put_getter_setter
)
3381 STUB_INIT_STACK_FRAME(stackFrame
);
3383 CallFrame
* callFrame
= stackFrame
.callFrame
;
3385 ASSERT(stackFrame
.args
[0].jsValue().isObject());
3386 JSObject
* baseObj
= asObject(stackFrame
.args
[0].jsValue());
3388 GetterSetter
* accessor
= GetterSetter::create(callFrame
);
3390 JSValue getter
= stackFrame
.args
[2].jsValue();
3391 JSValue setter
= stackFrame
.args
[3].jsValue();
3392 ASSERT(getter
.isObject() || getter
.isUndefined());
3393 ASSERT(setter
.isObject() || setter
.isUndefined());
3394 ASSERT(getter
.isObject() || setter
.isObject());
3396 if (!getter
.isUndefined())
3397 accessor
->setGetter(callFrame
->globalData(), asObject(getter
));
3398 if (!setter
.isUndefined())
3399 accessor
->setSetter(callFrame
->globalData(), asObject(setter
));
3400 baseObj
->putDirectAccessor(callFrame
->globalData(), stackFrame
.args
[1].identifier(), accessor
, Accessor
);
3403 DEFINE_STUB_FUNCTION(void, op_throw_reference_error
)
3405 STUB_INIT_STACK_FRAME(stackFrame
);
3407 CallFrame
* callFrame
= stackFrame
.callFrame
;
3408 UString message
= stackFrame
.args
[0].jsValue().toString(callFrame
)->value(callFrame
);
3409 stackFrame
.globalData
->exception
= createReferenceError(callFrame
, message
);
3410 VM_THROW_EXCEPTION_AT_END();
3413 DEFINE_STUB_FUNCTION(void, op_debug
)
3415 STUB_INIT_STACK_FRAME(stackFrame
);
3417 CallFrame
* callFrame
= stackFrame
.callFrame
;
3419 int debugHookID
= stackFrame
.args
[0].int32();
3420 int firstLine
= stackFrame
.args
[1].int32();
3421 int lastLine
= stackFrame
.args
[2].int32();
3423 stackFrame
.globalData
->interpreter
->debug(callFrame
, static_cast<DebugHookID
>(debugHookID
), firstLine
, lastLine
);
3426 DEFINE_STUB_FUNCTION(void*, vm_throw
)
3428 STUB_INIT_STACK_FRAME(stackFrame
);
3429 JSGlobalData
* globalData
= stackFrame
.globalData
;
3430 ExceptionHandler handler
= jitThrow(globalData
, stackFrame
.callFrame
, globalData
->exception
, globalData
->exceptionLocation
);
3431 STUB_SET_RETURN_ADDRESS(handler
.catchRoutine
);
3432 return handler
.callFrame
;
3435 DEFINE_STUB_FUNCTION(EncodedJSValue
, to_object
)
3437 STUB_INIT_STACK_FRAME(stackFrame
);
3439 CallFrame
* callFrame
= stackFrame
.callFrame
;
3440 return JSValue::encode(stackFrame
.args
[0].jsValue().toObject(callFrame
));
3443 MacroAssemblerCodeRef
JITThunks::ctiStub(JSGlobalData
* globalData
, ThunkGenerator generator
)
3445 CTIStubMap::AddResult entry
= m_ctiStubMap
.add(generator
, MacroAssemblerCodeRef());
3446 if (entry
.isNewEntry
)
3447 entry
.iterator
->second
= generator(globalData
);
3448 return entry
.iterator
->second
;
3451 NativeExecutable
* JITThunks::hostFunctionStub(JSGlobalData
* globalData
, NativeFunction function
, NativeFunction constructor
)
3453 HostFunctionStubMap::AddResult result
= m_hostFunctionStubMap
->add(function
, PassWeak
<NativeExecutable
>());
3454 if (!result
.iterator
->second
)
3455 result
.iterator
->second
= PassWeak
<NativeExecutable
>(NativeExecutable::create(*globalData
, JIT::compileCTINativeCall(globalData
, function
), function
, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), constructor
, NoIntrinsic
));
3456 return result
.iterator
->second
.get();
3459 NativeExecutable
* JITThunks::hostFunctionStub(JSGlobalData
* globalData
, NativeFunction function
, ThunkGenerator generator
, Intrinsic intrinsic
)
3461 HostFunctionStubMap::AddResult entry
= m_hostFunctionStubMap
->add(function
, PassWeak
<NativeExecutable
>());
3462 if (!entry
.iterator
->second
) {
3463 MacroAssemblerCodeRef code
;
3465 if (globalData
->canUseJIT())
3466 code
= generator(globalData
);
3468 code
= MacroAssemblerCodeRef();
3470 code
= JIT::compileCTINativeCall(globalData
, function
);
3471 entry
.iterator
->second
= PassWeak
<NativeExecutable
>(NativeExecutable::create(*globalData
, code
, function
, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor
, intrinsic
));
3473 return entry
.iterator
->second
.get();
3476 void JITThunks::clearHostFunctionStubs()
3478 m_hostFunctionStubMap
.clear();
3483 #endif // ENABLE(JIT)