]> git.saurik.com Git - apple/javascriptcore.git/blob - jit/JITStubs.cpp
JavaScriptCore-1097.3.3.tar.gz
[apple/javascriptcore.git] / jit / JITStubs.cpp
1 /*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 * Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
18 *
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.
29 */
30
31 #include "config.h"
32
33 #if ENABLE(JIT)
34 #include "JITStubs.h"
35
36 #include "CommonSlowPaths.h"
37 #include "Arguments.h"
38 #include "CallFrame.h"
39 #include "CodeBlock.h"
40 #include "CodeProfiling.h"
41 #include "DFGOSREntry.h"
42 #include "Debugger.h"
43 #include "ExceptionHelpers.h"
44 #include "GetterSetter.h"
45 #include "Heap.h"
46 #include <wtf/InlineASM.h>
47 #include "JIT.h"
48 #include "JITExceptions.h"
49 #include "JSActivation.h"
50 #include "JSArray.h"
51 #include "JSFunction.h"
52 #include "JSGlobalObjectFunctions.h"
53 #include "JSNotAnObject.h"
54 #include "JSPropertyNameIterator.h"
55 #include "JSStaticScopeObject.h"
56 #include "JSString.h"
57 #include "ObjectPrototype.h"
58 #include "Operations.h"
59 #include "Parser.h"
60 #include "Profiler.h"
61 #include "RegExpObject.h"
62 #include "RegExpPrototype.h"
63 #include "Register.h"
64 #include "SamplingTool.h"
65 #include "Strong.h"
66 #include <wtf/StdLibExtras.h>
67 #include <stdarg.h>
68 #include <stdio.h>
69
70 using namespace std;
71
72 namespace JSC {
73
74 #if USE(JSVALUE32_64)
75
76 #if COMPILER(GCC) && CPU(X86)
77
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);
84
85 asm (
86 ".text\n"
87 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
88 HIDE_SYMBOL(ctiTrampoline) "\n"
89 SYMBOL_STRING(ctiTrampoline) ":" "\n"
90 "pushl %ebp" "\n"
91 "movl %esp, %ebp" "\n"
92 "pushl %esi" "\n"
93 "pushl %edi" "\n"
94 "pushl %ebx" "\n"
95 "subl $0x3c, %esp" "\n"
96 "movl 0x58(%esp), %edi" "\n"
97 "call *0x50(%esp)" "\n"
98 "addl $0x3c, %esp" "\n"
99 "popl %ebx" "\n"
100 "popl %edi" "\n"
101 "popl %esi" "\n"
102 "popl %ebp" "\n"
103 "ret" "\n"
104 ".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n"
105 HIDE_SYMBOL(ctiTrampolineEnd) "\n"
106 SYMBOL_STRING(ctiTrampolineEnd) ":" "\n"
107 );
108
109 asm (
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"
115 "int3" "\n"
116 );
117
118 asm (
119 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
120 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
121 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
122 "addl $0x3c, %esp" "\n"
123 "popl %ebx" "\n"
124 "popl %edi" "\n"
125 "popl %esi" "\n"
126 "popl %ebp" "\n"
127 "ret" "\n"
128 );
129
130 #elif COMPILER(GCC) && CPU(X86_64)
131
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);
138
139 asm (
140 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
141 HIDE_SYMBOL(ctiTrampoline) "\n"
142 SYMBOL_STRING(ctiTrampoline) ":" "\n"
143 "pushq %rbp" "\n"
144 "movq %rsp, %rbp" "\n"
145 "pushq %r12" "\n"
146 "pushq %r13" "\n"
147 "pushq %r14" "\n"
148 "pushq %r15" "\n"
149 "pushq %rbx" "\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"
157 "popq %rbx" "\n"
158 "popq %r15" "\n"
159 "popq %r14" "\n"
160 "popq %r13" "\n"
161 "popq %r12" "\n"
162 "popq %rbp" "\n"
163 "ret" "\n"
164 ".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n"
165 HIDE_SYMBOL(ctiTrampolineEnd) "\n"
166 SYMBOL_STRING(ctiTrampolineEnd) ":" "\n"
167 );
168
169 asm (
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"
175 "int3" "\n"
176 );
177
178 asm (
179 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
180 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
181 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
182 "addq $0x48, %rsp" "\n"
183 "popq %rbx" "\n"
184 "popq %r15" "\n"
185 "popq %r14" "\n"
186 "popq %r13" "\n"
187 "popq %r12" "\n"
188 "popq %rbp" "\n"
189 "ret" "\n"
190 );
191
192 #elif (COMPILER(GCC) || COMPILER(RVCT)) && CPU(ARM_THUMB2)
193
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
208
209 #elif (COMPILER(GCC) || COMPILER(MSVC) || COMPILER(RVCT)) && CPU(ARM_TRADITIONAL)
210
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
215
216 #elif COMPILER(MSVC) && CPU(X86)
217
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);
224
225 extern "C" {
226
227 __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*)
228 {
229 __asm {
230 push ebp;
231 mov ebp, esp;
232 push esi;
233 push edi;
234 push ebx;
235 sub esp, 0x3c;
236 mov ecx, esp;
237 mov edi, [esp + 0x58];
238 call [esp + 0x50];
239 add esp, 0x3c;
240 pop ebx;
241 pop edi;
242 pop esi;
243 pop ebp;
244 ret;
245 }
246 }
247
248 __declspec(naked) void ctiVMThrowTrampoline()
249 {
250 __asm {
251 mov ecx, esp;
252 call cti_vm_throw;
253 add esp, 0x3c;
254 pop ebx;
255 pop edi;
256 pop esi;
257 pop ebp;
258 ret;
259 }
260 }
261
262 __declspec(naked) void ctiOpThrowNotCaught()
263 {
264 __asm {
265 add esp, 0x3c;
266 pop ebx;
267 pop edi;
268 pop esi;
269 pop ebp;
270 ret;
271 }
272 }
273 }
274
275 #elif CPU(MIPS)
276
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
289 #elif CPU(SH4)
290 #define SYMBOL_STRING(name) #name
291 /* code (r4), RegisterFile* (r5), CallFrame* (r6), JSValue* exception (r7), Profiler**(sp), JSGlobalData (sp)*/
292
293 asm volatile (
294 ".text\n"
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"
302 "mov #127, r8" "\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"
308 "add #-60, r15" "\n"
309 "mov r6, r14" "\n"
310 "jsr @r4" "\n"
311 "nop" "\n"
312 "add #60, 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"
319 "add #12, r15" "\n"
320 "rts" "\n"
321 "nop" "\n"
322 );
323
324 asm volatile (
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"
329 "mov r15, r4" "\n"
330 "mov.l @(r0,r12),r11" "\n"
331 "jsr @r11" "\n"
332 "nop" "\n"
333 "add #60, r15" "\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"
340 "add #12, r15" "\n"
341 "rts" "\n"
342 "nop" "\n"
343 ".align 2" "\n"
344 ".L2"SYMBOL_STRING(cti_vm_throw)":.long " SYMBOL_STRING(cti_vm_throw)"@GOT \n"
345 );
346
347 asm volatile (
348 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
349 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
350 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
351 "add #60, r15" "\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"
358 "add #12, r15" "\n"
359 "rts" "\n"
360 "nop" "\n"
361 );
362 #else
363 #error "JIT not supported on this platform."
364 #endif
365
366 #else // USE(JSVALUE32_64)
367
368 #if COMPILER(GCC) && CPU(X86_64)
369
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);
375
376 asm (
377 ".text\n"
378 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
379 HIDE_SYMBOL(ctiTrampoline) "\n"
380 SYMBOL_STRING(ctiTrampoline) ":" "\n"
381 "pushq %rbp" "\n"
382 "movq %rsp, %rbp" "\n"
383 "pushq %r12" "\n"
384 "pushq %r13" "\n"
385 "pushq %r14" "\n"
386 "pushq %r15" "\n"
387 "pushq %rbx" "\n"
388 // Form the JIT stubs area
389 "pushq %r9" "\n"
390 "pushq %r8" "\n"
391 "pushq %rcx" "\n"
392 "pushq %rdx" "\n"
393 "pushq %rsi" "\n"
394 "pushq %rdi" "\n"
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"
400 "call *%rdi" "\n"
401 "addq $0x78, %rsp" "\n"
402 "popq %rbx" "\n"
403 "popq %r15" "\n"
404 "popq %r14" "\n"
405 "popq %r13" "\n"
406 "popq %r12" "\n"
407 "popq %rbp" "\n"
408 "ret" "\n"
409 ".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n"
410 HIDE_SYMBOL(ctiTrampolineEnd) "\n"
411 SYMBOL_STRING(ctiTrampolineEnd) ":" "\n"
412 );
413
414 asm (
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"
420 "int3" "\n"
421 );
422
423 asm (
424 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
425 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
426 SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
427 "addq $0x78, %rsp" "\n"
428 "popq %rbx" "\n"
429 "popq %r15" "\n"
430 "popq %r14" "\n"
431 "popq %r13" "\n"
432 "popq %r12" "\n"
433 "popq %rbp" "\n"
434 "ret" "\n"
435 );
436
437 #else
438 #error "JIT not supported on this platform."
439 #endif
440
441 #endif // USE(JSVALUE32_64)
442
443 #if CPU(MIPS)
444 asm (
445 ".text" "\n"
446 ".align 2" "\n"
447 ".set noreorder" "\n"
448 ".set nomacro" "\n"
449 ".set nomips16" "\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"
458 #if WTF_MIPS_PIC
459 "sw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n"
460 #endif
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"
470 "jalr $25" "\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"
476 "jr $31" "\n"
477 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
478 ".set reorder" "\n"
479 ".set macro" "\n"
480 ".end " SYMBOL_STRING(ctiTrampoline) "\n"
481 );
482
483 asm (
484 ".text" "\n"
485 ".align 2" "\n"
486 ".set noreorder" "\n"
487 ".set nomacro" "\n"
488 ".set nomips16" "\n"
489 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
490 ".ent " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
491 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
492 #if WTF_MIPS_PIC
493 "lw $28," STRINGIZE_VALUE_OF(PRESERVED_GP_OFFSET) "($29)" "\n"
494 ".set macro" "\n"
495 "la $25," SYMBOL_STRING(cti_vm_throw) "\n"
496 ".set nomacro" "\n"
497 "bal " SYMBOL_STRING(cti_vm_throw) "\n"
498 "move $4,$29" "\n"
499 #else
500 "jal " SYMBOL_STRING(cti_vm_throw) "\n"
501 "move $4,$29" "\n"
502 #endif
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"
507 "jr $31" "\n"
508 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
509 ".set reorder" "\n"
510 ".set macro" "\n"
511 ".end " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
512 );
513
514 asm (
515 ".text" "\n"
516 ".align 2" "\n"
517 ".set noreorder" "\n"
518 ".set nomacro" "\n"
519 ".set nomips16" "\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"
527 "jr $31" "\n"
528 "addiu $29,$29," STRINGIZE_VALUE_OF(STACK_LENGTH) "\n"
529 ".set reorder" "\n"
530 ".set macro" "\n"
531 ".end " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
532 );
533 #endif
534
535 #if COMPILER(GCC) && CPU(ARM_THUMB2)
536
537 asm (
538 ".text" "\n"
539 ".align 2" "\n"
540 ".globl " SYMBOL_STRING(ctiTrampoline) "\n"
541 HIDE_SYMBOL(ctiTrampoline) "\n"
542 ".thumb" "\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"
558 "mov r5, r2" "\n"
559 "mov r6, #512" "\n"
560 "blx r0" "\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"
571 "bx lr" "\n"
572 ".align 2" "\n"
573 ".globl " SYMBOL_STRING(ctiTrampolineEnd) "\n"
574 HIDE_SYMBOL(ctiTrampolineEnd) "\n"
575 ".thumb" "\n"
576 ".thumb_func " THUMB_FUNC_PARAM(ctiTrampolineEnd) "\n"
577 SYMBOL_STRING(ctiTrampolineEnd) ":" "\n"
578 );
579
580 asm (
581 ".text" "\n"
582 ".align 2" "\n"
583 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
584 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
585 ".thumb" "\n"
586 ".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n"
587 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
588 "mov r0, sp" "\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"
600 "bx lr" "\n"
601 );
602
603 asm (
604 ".text" "\n"
605 ".align 2" "\n"
606 ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
607 HIDE_SYMBOL(ctiOpThrowNotCaught) "\n"
608 ".thumb" "\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"
621 "bx lr" "\n"
622 );
623
624 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
625
626 asm (
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"
633 "mov r4, r2" "\n"
634 "mov r5, #512" "\n"
635 // r0 contains the code
636 "mov lr, pc" "\n"
637 "mov pc, r0" "\n"
638 "add sp, sp, #" STRINGIZE_VALUE_OF(PRESERVEDR4_OFFSET) "\n"
639 "ldmia sp!, {r4-r8, lr}" "\n"
640 "add sp, sp, #12" "\n"
641 "mov pc, lr" "\n"
642 );
643
644 asm (
645 ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
646 HIDE_SYMBOL(ctiVMThrowTrampoline) "\n"
647 SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
648 "mov r0, sp" "\n"
649 "bl " SYMBOL_STRING(cti_vm_throw) "\n"
650
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"
658 "mov pc, lr" "\n"
659 );
660
661 #elif COMPILER(RVCT) && CPU(ARM_THUMB2)
662
663 __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, JSValue*, Profiler**, JSGlobalData*)
664 {
665 PRESERVE8
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 ]
679 mov r5, r2
680 mov r6, #512
681 blx r0
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
692 bx lr
693 }
694
695 __asm void ctiVMThrowTrampoline()
696 {
697 PRESERVE8
698 mov r0, sp
699 bl cti_vm_throw
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
711 bx lr
712 }
713
714 __asm void ctiOpThrowNotCaught()
715 {
716 PRESERVE8
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
728 bx lr
729 }
730
731 #elif COMPILER(RVCT) && CPU(ARM_TRADITIONAL)
732
733 __asm EncodedJSValue ctiTrampoline(void*, RegisterFile*, CallFrame*, void* /*unused1*/, Profiler**, JSGlobalData*)
734 {
735 ARM
736 stmdb sp!, {r1-r3}
737 stmdb sp!, {r4-r8, lr}
738 sub sp, sp, # PRESERVEDR4_OFFSET
739 mov r4, r2
740 mov r5, #512
741 mov lr, pc
742 bx r0
743 add sp, sp, # PRESERVEDR4_OFFSET
744 ldmia sp!, {r4-r8, lr}
745 add sp, sp, #12
746 bx lr
747 }
748
749 __asm void ctiVMThrowTrampoline()
750 {
751 ARM
752 PRESERVE8
753 mov r0, sp
754 bl cti_vm_throw
755 add sp, sp, # PRESERVEDR4_OFFSET
756 ldmia sp!, {r4-r8, lr}
757 add sp, sp, #12
758 bx lr
759 }
760
761 __asm void ctiOpThrowNotCaught()
762 {
763 ARM
764 add sp, sp, # PRESERVEDR4_OFFSET
765 ldmia sp!, {r4-r8, lr}
766 add sp, sp, #12
767 bx lr
768 }
769 #endif
770
771 #if ENABLE(OPCODE_SAMPLING)
772 #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler()
773 #else
774 #define CTI_SAMPLER 0
775 #endif
776
777 JITThunks::JITThunks(JSGlobalData* globalData)
778 : m_hostFunctionStubMap(adoptPtr(new HostFunctionStubMap))
779 {
780 if (!globalData->canUseJIT())
781 return;
782
783 m_executableMemory = JIT::compileCTIMachineTrampolines(globalData, &m_trampolineStructure);
784 ASSERT(!!m_executableMemory);
785 #if CPU(ARM_THUMB2)
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
788 // macros.
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);
798
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);
803
804 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
805
806 #elif CPU(ARM_TRADITIONAL)
807
808 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
809 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVEDR4_OFFSET);
810
811
812 #elif CPU(MIPS)
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);
824
825 #endif
826 }
827
828 JITThunks::~JITThunks()
829 {
830 }
831
832 NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot, StructureStubInfo* stubInfo, bool direct)
833 {
834 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
835
836 if (!baseValue.isCell())
837 return;
838
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));
842 return;
843 }
844
845 JSCell* baseCell = baseValue.asCell();
846 Structure* structure = baseCell->structure();
847
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));
850 return;
851 }
852
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));
856 return;
857 }
858
859 // Cache hit: Specialize instruction and ref Structures.
860
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));
865 return;
866 }
867
868 // put_by_id_transition checks the prototype chain for setters.
869 normalizePrototypeChain(callFrame, baseCell);
870
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);
874 return;
875 }
876
877 stubInfo->initPutByIdReplace(callFrame->globalData(), codeBlock->ownerExecutable(), structure);
878
879 JIT::patchPutByIdReplace(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress, direct);
880 }
881
882 NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot, StructureStubInfo* stubInfo)
883 {
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.
886
887 // FIXME: Cache property access for immediates.
888 if (!baseValue.isCell()) {
889 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
890 return;
891 }
892
893 JSGlobalData* globalData = &callFrame->globalData();
894
895 if (isJSArray(baseValue) && propertyName == callFrame->propertyNames().length) {
896 JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress);
897 return;
898 }
899
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());
904 return;
905 }
906
907 // Uncacheable: give up.
908 if (!slot.isCacheable()) {
909 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
910 return;
911 }
912
913 JSCell* baseCell = baseValue.asCell();
914 Structure* structure = baseCell->structure();
915
916 if (structure->isUncacheableDictionary() || structure->typeInfo().prohibitsPropertyCaching()) {
917 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
918 return;
919 }
920
921 // Cache hit: Specialize instruction and ref Structures.
922
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));
928 else
929 JIT::patchGetByIdSelf(codeBlock, stubInfo, structure, slot.cachedOffset(), returnAddress);
930 return;
931 }
932
933 if (structure->isDictionary()) {
934 ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic));
935 return;
936 }
937
938 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
939 ASSERT(slot.slotBase().isObject());
940
941 JSObject* slotBaseObject = asObject(slot.slotBase());
942 size_t offset = slot.cachedOffset();
943
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);
949 }
950
951 stubInfo->initGetByIdProto(callFrame->globalData(), codeBlock->ownerExecutable(), structure, slotBaseObject->structure());
952
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);
956 return;
957 }
958
959 size_t offset = slot.cachedOffset();
960 size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset);
961 if (!count) {
962 stubInfo->accessType = access_get_by_id_generic;
963 return;
964 }
965
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);
969 }
970
971 #if !defined(NDEBUG)
972
973 extern "C" {
974
975 static void jscGeneratedNativeCode()
976 {
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
979 // memory.
980 }
981
982 }
983
984 struct StackHack {
985 ALWAYS_INLINE StackHack(JITStackFrame& stackFrame)
986 : stackFrame(stackFrame)
987 , savedReturnAddress(*stackFrame.returnAddressSlot())
988 {
989 if (!CodeProfiling::enabled())
990 *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode));
991 }
992
993 ALWAYS_INLINE ~StackHack()
994 {
995 *stackFrame.returnAddressSlot() = savedReturnAddress;
996 }
997
998 JITStackFrame& stackFrame;
999 ReturnAddressPtr savedReturnAddress;
1000 };
1001
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
1005
1006 #else
1007
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()
1011
1012 #endif
1013
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)
1019 {
1020 ASSERT(globalData->exception);
1021 globalData->exceptionLocation = exceptionLocation;
1022 returnAddressSlot = ReturnAddressPtr(FunctionPtr(ctiVMThrowTrampoline));
1023 }
1024
1025 #define VM_THROW_EXCEPTION() \
1026 do { \
1027 VM_THROW_EXCEPTION_AT_END(); \
1028 return 0; \
1029 } while (0)
1030 #define VM_THROW_EXCEPTION_AT_END() \
1031 do {\
1032 returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS);\
1033 } while (0)
1034
1035 #define CHECK_FOR_EXCEPTION() \
1036 do { \
1037 if (UNLIKELY(stackFrame.globalData->exception)) \
1038 VM_THROW_EXCEPTION(); \
1039 } while (0)
1040 #define CHECK_FOR_EXCEPTION_AT_END() \
1041 do { \
1042 if (UNLIKELY(stackFrame.globalData->exception)) \
1043 VM_THROW_EXCEPTION_AT_END(); \
1044 } while (0)
1045 #define CHECK_FOR_EXCEPTION_VOID() \
1046 do { \
1047 if (UNLIKELY(stackFrame.globalData->exception)) { \
1048 VM_THROW_EXCEPTION_AT_END(); \
1049 return; \
1050 } \
1051 } while (0)
1052
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)
1057 {
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);
1063 return T();
1064 }
1065
1066 template<typename T> static T throwExceptionFromOpCall(JITStackFrame& jitStackFrame, CallFrame* newCallFrame, ReturnAddressPtr& returnAddressSlot, JSValue exception)
1067 {
1068 newCallFrame->callerFrame()->globalData().exception = exception;
1069 return throwExceptionFromOpCall<T>(jitStackFrame, newCallFrame, returnAddressSlot);
1070 }
1071
1072 #if CPU(ARM_THUMB2) && COMPILER(GCC)
1073
1074 #define DEFINE_STUB_FUNCTION(rtype, op) \
1075 extern "C" { \
1076 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1077 }; \
1078 asm ( \
1079 ".text" "\n" \
1080 ".align 2" "\n" \
1081 ".globl " SYMBOL_STRING(cti_##op) "\n" \
1082 HIDE_SYMBOL(cti_##op) "\n" \
1083 ".thumb" "\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" \
1089 "bx lr" "\n" \
1090 ); \
1091 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \
1092
1093 #elif CPU(MIPS)
1094 #if WTF_MIPS_PIC
1095 #define DEFINE_STUB_FUNCTION(rtype, op) \
1096 extern "C" { \
1097 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1098 }; \
1099 asm ( \
1100 ".text" "\n" \
1101 ".align 2" "\n" \
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" \
1110 ".set macro" "\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" \
1115 "nop" "\n" \
1116 "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
1117 "jr $31" "\n" \
1118 "nop" "\n" \
1119 ".set reorder" "\n" \
1120 ".set macro" "\n" \
1121 ".end " SYMBOL_STRING(cti_##op) "\n" \
1122 ); \
1123 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1124
1125 #else // WTF_MIPS_PIC
1126 #define DEFINE_STUB_FUNCTION(rtype, op) \
1127 extern "C" { \
1128 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1129 }; \
1130 asm ( \
1131 ".text" "\n" \
1132 ".align 2" "\n" \
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" \
1141 "nop" "\n" \
1142 "lw $31," STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "($29)" "\n" \
1143 "jr $31" "\n" \
1144 "nop" "\n" \
1145 ".set reorder" "\n" \
1146 ".set macro" "\n" \
1147 ".end " SYMBOL_STRING(cti_##op) "\n" \
1148 ); \
1149 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1150
1151 #endif
1152
1153 #elif CPU(ARM_TRADITIONAL) && COMPILER(GCC)
1154
1155 #define DEFINE_STUB_FUNCTION(rtype, op) \
1156 extern "C" { \
1157 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1158 }; \
1159 asm ( \
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" \
1165 "mov pc, lr" "\n" \
1166 ); \
1167 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1168
1169 #elif (CPU(ARM_THUMB2) || CPU(ARM_TRADITIONAL)) && COMPILER(RVCT)
1170
1171 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1172
1173 /* The following is a workaround for RVCT toolchain; precompiler macros are not expanded before the code is passed to the assembler */
1174
1175 /* The following section is a template to generate code for GeneratedJITStubs_RVCT.h */
1176 /* The pattern "#xxx#" will be replaced with "xxx" */
1177
1178 /*
1179 RVCT(extern "C" #rtype# JITStubThunked_#op#(STUB_ARGS_DECLARATION);)
1180 RVCT(__asm #rtype# cti_#op#(STUB_ARGS_DECLARATION))
1181 RVCT({)
1182 RVCT( PRESERVE8)
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])
1187 RVCT( bx lr)
1188 RVCT(})
1189 RVCT()
1190 */
1191
1192 /* Include the generated file */
1193 #include "GeneratedJITStubs_RVCT.h"
1194
1195 #elif CPU(ARM_TRADITIONAL) && COMPILER(MSVC)
1196
1197 #define DEFINE_STUB_FUNCTION(rtype, op) extern "C" rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1198
1199 /* The following is a workaround for MSVC toolchain; inline assembler is not supported */
1200
1201 /* The following section is a template to generate code for GeneratedJITStubs_MSVC.asm */
1202 /* The pattern "#xxx#" will be replaced with "xxx" */
1203
1204 /*
1205 MSVC_BEGIN( AREA Trampoline, CODE)
1206 MSVC_BEGIN()
1207 MSVC_BEGIN( EXPORT ctiTrampoline)
1208 MSVC_BEGIN( EXPORT ctiVMThrowTrampoline)
1209 MSVC_BEGIN( EXPORT ctiOpThrowNotCaught)
1210 MSVC_BEGIN()
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)
1219 MSVC_BEGIN( bx r0)
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)
1223 MSVC_BEGIN( bx lr)
1224 MSVC_BEGIN(ctiTrampoline ENDP)
1225 MSVC_BEGIN()
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)
1234 MSVC_BEGIN( bx lr)
1235 MSVC_BEGIN(ctiVMThrowTrampoline ENDP)
1236 MSVC_BEGIN()
1237
1238 MSVC( EXPORT cti_#op#)
1239 MSVC( IMPORT JITStubThunked_#op#)
1240 MSVC(cti_#op# PROC)
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)
1244 MSVC( bx lr)
1245 MSVC(cti_#op# ENDP)
1246 MSVC()
1247
1248 MSVC_END( END)
1249 */
1250
1251 #elif CPU(SH4)
1252 #define DEFINE_STUB_FUNCTION(rtype, op) \
1253 extern "C" { \
1254 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
1255 }; \
1256 asm volatile( \
1257 ".align 2" "\n" \
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" \
1264 "jsr @r11" "\n" \
1265 "nop" "\n" \
1266 "mov.l @(0x38, r15), r11 " "\n" \
1267 "lds r11, pr " "\n" \
1268 "rts" "\n" \
1269 "nop" "\n" \
1270 ".align 2" "\n" \
1271 ".L2"SYMBOL_STRING(JITStubThunked_##op)":.long " SYMBOL_STRING(JITStubThunked_##op)"@GOT \n" \
1272 ); \
1273 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION)
1274 #else
1275 #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION)
1276 #endif
1277
1278 DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_this)
1279 {
1280 STUB_INIT_STACK_FRAME(stackFrame);
1281 CallFrame* callFrame = stackFrame.callFrame;
1282
1283 JSFunction* constructor = jsCast<JSFunction*>(callFrame->callee());
1284 #if !ASSERT_DISABLED
1285 ConstructData constructData;
1286 ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
1287 #endif
1288
1289 Structure* structure;
1290 JSValue proto = stackFrame.args[0].jsValue();
1291 if (proto.isObject())
1292 structure = asObject(proto)->inheritorID(*stackFrame.globalData);
1293 else
1294 structure = constructor->scope()->globalObject->emptyObjectStructure();
1295 JSValue result = constructEmptyObject(callFrame, structure);
1296
1297 return JSValue::encode(result);
1298 }
1299
1300 DEFINE_STUB_FUNCTION(EncodedJSValue, op_convert_this)
1301 {
1302 STUB_INIT_STACK_FRAME(stackFrame);
1303
1304 JSValue v1 = stackFrame.args[0].jsValue();
1305 CallFrame* callFrame = stackFrame.callFrame;
1306
1307 ASSERT(v1.isPrimitive());
1308
1309 JSObject* result = v1.toThisObject(callFrame);
1310 CHECK_FOR_EXCEPTION_AT_END();
1311 return JSValue::encode(result);
1312 }
1313
1314 DEFINE_STUB_FUNCTION(EncodedJSValue, op_add)
1315 {
1316 STUB_INIT_STACK_FRAME(stackFrame);
1317
1318 JSValue v1 = stackFrame.args[0].jsValue();
1319 JSValue v2 = stackFrame.args[1].jsValue();
1320 CallFrame* callFrame = stackFrame.callFrame;
1321
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);
1326 }
1327
1328 if (v1.isNumber() && v2.isNumber())
1329 return JSValue::encode(jsNumber(v1.asNumber() + v2.asNumber()));
1330
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);
1335 }
1336
1337 DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc)
1338 {
1339 STUB_INIT_STACK_FRAME(stackFrame);
1340
1341 JSValue v = stackFrame.args[0].jsValue();
1342
1343 CallFrame* callFrame = stackFrame.callFrame;
1344 JSValue result = jsNumber(v.toNumber(callFrame) + 1);
1345 CHECK_FOR_EXCEPTION_AT_END();
1346 return JSValue::encode(result);
1347 }
1348
1349 DEFINE_STUB_FUNCTION(int, timeout_check)
1350 {
1351 STUB_INIT_STACK_FRAME(stackFrame);
1352
1353 JSGlobalData* globalData = stackFrame.globalData;
1354 TimeoutChecker& timeoutChecker = globalData->timeoutChecker;
1355
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();
1362 }
1363
1364 return timeoutChecker.ticksUntilNextCheck();
1365 }
1366
1367 DEFINE_STUB_FUNCTION(void*, register_file_check)
1368 {
1369 STUB_INIT_STACK_FRAME(stackFrame);
1370 CallFrame* callFrame = stackFrame.callFrame;
1371
1372 if (UNLIKELY(!stackFrame.registerFile->grow(&callFrame->registers()[callFrame->codeBlock()->m_numCalleeRegisters])))
1373 return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS, createStackOverflowError(callFrame->callerFrame()));
1374
1375 return callFrame;
1376 }
1377
1378 DEFINE_STUB_FUNCTION(JSObject*, op_new_object)
1379 {
1380 STUB_INIT_STACK_FRAME(stackFrame);
1381
1382 return constructEmptyObject(stackFrame.callFrame);
1383 }
1384
1385 DEFINE_STUB_FUNCTION(void, op_put_by_id_generic)
1386 {
1387 STUB_INIT_STACK_FRAME(stackFrame);
1388
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();
1392 }
1393
1394 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_generic)
1395 {
1396 STUB_INIT_STACK_FRAME(stackFrame);
1397
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();
1403 }
1404
1405 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic)
1406 {
1407 STUB_INIT_STACK_FRAME(stackFrame);
1408
1409 CallFrame* callFrame = stackFrame.callFrame;
1410 Identifier& ident = stackFrame.args[1].identifier();
1411
1412 JSValue baseValue = stackFrame.args[0].jsValue();
1413 PropertySlot slot(baseValue);
1414 JSValue result = baseValue.get(callFrame, ident, slot);
1415
1416 CHECK_FOR_EXCEPTION_AT_END();
1417 return JSValue::encode(result);
1418 }
1419
1420 DEFINE_STUB_FUNCTION(void, op_put_by_id)
1421 {
1422 STUB_INIT_STACK_FRAME(stackFrame);
1423 CallFrame* callFrame = stackFrame.callFrame;
1424 Identifier& ident = stackFrame.args[1].identifier();
1425
1426 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
1427 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
1428
1429 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1430 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1431 if (!stubInfo->seenOnce())
1432 stubInfo->setSeen();
1433 else
1434 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, false);
1435
1436 CHECK_FOR_EXCEPTION_AT_END();
1437 }
1438
1439 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct)
1440 {
1441 STUB_INIT_STACK_FRAME(stackFrame);
1442 CallFrame* callFrame = stackFrame.callFrame;
1443 Identifier& ident = stackFrame.args[1].identifier();
1444
1445 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
1446 JSValue baseValue = stackFrame.args[0].jsValue();
1447 ASSERT(baseValue.isObject());
1448
1449 asObject(baseValue)->putDirect(callFrame->globalData(), ident, stackFrame.args[2].jsValue(), slot);
1450
1451 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1452 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1453 if (!stubInfo->seenOnce())
1454 stubInfo->setSeen();
1455 else
1456 JITThunks::tryCachePutByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot, stubInfo, true);
1457
1458 CHECK_FOR_EXCEPTION_AT_END();
1459 }
1460
1461 DEFINE_STUB_FUNCTION(void, op_put_by_id_fail)
1462 {
1463 STUB_INIT_STACK_FRAME(stackFrame);
1464
1465 CallFrame* callFrame = stackFrame.callFrame;
1466 Identifier& ident = stackFrame.args[1].identifier();
1467
1468 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
1469 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
1470
1471 CHECK_FOR_EXCEPTION_AT_END();
1472 }
1473
1474 DEFINE_STUB_FUNCTION(void, op_put_by_id_direct_fail)
1475 {
1476 STUB_INIT_STACK_FRAME(stackFrame);
1477
1478 CallFrame* callFrame = stackFrame.callFrame;
1479 Identifier& ident = stackFrame.args[1].identifier();
1480
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);
1485
1486 CHECK_FOR_EXCEPTION_AT_END();
1487 }
1488
1489 DEFINE_STUB_FUNCTION(JSObject*, op_put_by_id_transition_realloc)
1490 {
1491 STUB_INIT_STACK_FRAME(stackFrame);
1492
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();
1497
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);
1503
1504 return base;
1505 }
1506
1507 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check)
1508 {
1509 STUB_INIT_STACK_FRAME(stackFrame);
1510
1511 CallFrame* callFrame = stackFrame.callFrame;
1512 Identifier& ident = stackFrame.args[1].identifier();
1513
1514 JSValue baseValue = stackFrame.args[0].jsValue();
1515 PropertySlot slot(baseValue);
1516 JSValue result = baseValue.get(callFrame, ident, slot);
1517 CHECK_FOR_EXCEPTION();
1518
1519 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1520 MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS);
1521 StructureStubInfo& stubInfo = codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1522
1523 if (!methodCallLinkInfo.seenOnce()) {
1524 methodCallLinkInfo.setSeen();
1525 return JSValue::encode(result);
1526 }
1527
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());
1532
1533 // Check that:
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;
1539 JSCell* specific;
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)
1545 && specific
1546 ) {
1547
1548 JSObject* callee = asObject(specific);
1549
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());
1554
1555 // The result fetched should always be the callee!
1556 ASSERT(result == JSValue(callee));
1557
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);
1562 }
1563
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);
1573 }
1574 }
1575
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);
1579 }
1580
1581 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_update)
1582 {
1583 STUB_INIT_STACK_FRAME(stackFrame);
1584
1585 CallFrame* callFrame = stackFrame.callFrame;
1586 Identifier& ident = stackFrame.args[1].identifier();
1587
1588 JSValue baseValue = stackFrame.args[0].jsValue();
1589 PropertySlot slot(baseValue);
1590 JSValue result = baseValue.get(callFrame, ident, slot);
1591 CHECK_FOR_EXCEPTION();
1592
1593 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1594 MethodCallLinkInfo& methodCallLinkInfo = codeBlock->getMethodCallLinkInfo(STUB_RETURN_ADDRESS);
1595 StructureStubInfo& stubInfo = codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1596
1597 ASSERT(methodCallLinkInfo.seenOnce());
1598
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());
1603
1604 // Check that:
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;
1610 JSCell* specific;
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)
1616 && specific
1617 )
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);
1623 }
1624
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.
1628
1629 JSValue proto = structure->prototypeForLookup(callFrame);
1630
1631 bool previousWasProto = methodCallLinkInfo.cachedPrototype.get() != codeBlock->globalObject()->methodCallDummy();
1632 bool currentIsProto = slot.slotBase() == proto;
1633
1634 JSObject* callee = asObject(specific);
1635
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);
1642 }
1643
1644 // It makes sense to simply repatch the method_check.
1645
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());
1650
1651 // The result fetched should always be the callee!
1652 ASSERT(result == JSValue(callee));
1653
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);
1658 }
1659
1660 ASSERT(slot.slotBase() == baseValue);
1661
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);
1669 }
1670
1671 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id)
1672 {
1673 STUB_INIT_STACK_FRAME(stackFrame);
1674 CallFrame* callFrame = stackFrame.callFrame;
1675 Identifier& ident = stackFrame.args[1].identifier();
1676
1677 JSValue baseValue = stackFrame.args[0].jsValue();
1678 PropertySlot slot(baseValue);
1679 JSValue result = baseValue.get(callFrame, ident, slot);
1680
1681 CodeBlock* codeBlock = stackFrame.callFrame->codeBlock();
1682 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1683 if (!stubInfo->seenOnce())
1684 stubInfo->setSeen();
1685 else
1686 JITThunks::tryCacheGetByID(callFrame, codeBlock, STUB_RETURN_ADDRESS, baseValue, ident, slot, stubInfo);
1687
1688 CHECK_FOR_EXCEPTION_AT_END();
1689 return JSValue::encode(result);
1690 }
1691
1692 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
1693 {
1694 STUB_INIT_STACK_FRAME(stackFrame);
1695
1696 CallFrame* callFrame = stackFrame.callFrame;
1697 Identifier& ident = stackFrame.args[1].identifier();
1698
1699 JSValue baseValue = stackFrame.args[0].jsValue();
1700 PropertySlot slot(baseValue);
1701 JSValue result = baseValue.get(callFrame, ident, slot);
1702
1703 CHECK_FOR_EXCEPTION();
1704
1705 if (baseValue.isCell()
1706 && slot.isCacheable()
1707 && !baseValue.asCell()->structure()->isUncacheableDictionary()
1708 && slot.slotBase() == baseValue) {
1709
1710 CodeBlock* codeBlock = callFrame->codeBlock();
1711 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1712
1713 ASSERT(slot.slotBase().isObject());
1714
1715 PolymorphicAccessStructureList* polymorphicStructureList;
1716 int listIndex = 1;
1717
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);
1722 } else {
1723 polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList;
1724 listIndex = stubInfo->u.getByIdSelfList.listSize;
1725 }
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());
1729
1730 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1731 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
1732 }
1733 } else
1734 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
1735 return JSValue::encode(result);
1736 }
1737
1738 static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(JSGlobalData& globalData, ScriptExecutable* owner, StructureStubInfo* stubInfo, int& listIndex)
1739 {
1740 PolymorphicAccessStructureList* prototypeStructureList = 0;
1741 listIndex = 1;
1742
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);
1748 break;
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);
1753 break;
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++;
1759 break;
1760 default:
1761 ASSERT_NOT_REACHED();
1762 }
1763
1764 ASSERT(listIndex <= POLYMORPHIC_LIST_CACHE_SIZE);
1765 return prototypeStructureList;
1766 }
1767
1768 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_getter_stub)
1769 {
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());
1776 CallData callData;
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);
1781
1782 return JSValue::encode(result);
1783 }
1784
1785 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_custom_stub)
1786 {
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);
1795
1796 return JSValue::encode(result);
1797 }
1798
1799 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
1800 {
1801 STUB_INIT_STACK_FRAME(stackFrame);
1802
1803 CallFrame* callFrame = stackFrame.callFrame;
1804 const Identifier& propertyName = stackFrame.args[1].identifier();
1805
1806 JSValue baseValue = stackFrame.args[0].jsValue();
1807 PropertySlot slot(baseValue);
1808 JSValue result = baseValue.get(callFrame, propertyName, slot);
1809
1810 CHECK_FOR_EXCEPTION();
1811
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);
1815 }
1816
1817 Structure* structure = baseValue.asCell()->structure();
1818 CodeBlock* codeBlock = callFrame->codeBlock();
1819 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1820
1821 ASSERT(slot.slotBase().isObject());
1822 JSObject* slotBaseObject = asObject(slot.slotBase());
1823
1824 size_t offset = slot.cachedOffset();
1825
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);
1835 }
1836
1837 int listIndex;
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);
1841
1842 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1843 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
1844 }
1845 } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase(), propertyName, offset)) {
1846 ASSERT(!baseValue.asCell()->structure()->isDictionary());
1847 int listIndex;
1848 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(callFrame->globalData(), codeBlock->ownerExecutable(), stubInfo, listIndex);
1849
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);
1853
1854 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1855 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
1856 }
1857 } else
1858 ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1859
1860 return JSValue::encode(result);
1861 }
1862
1863 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list_full)
1864 {
1865 STUB_INIT_STACK_FRAME(stackFrame);
1866
1867 JSValue baseValue = stackFrame.args[0].jsValue();
1868 PropertySlot slot(baseValue);
1869 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1870
1871 CHECK_FOR_EXCEPTION_AT_END();
1872 return JSValue::encode(result);
1873 }
1874
1875 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_fail)
1876 {
1877 STUB_INIT_STACK_FRAME(stackFrame);
1878
1879 JSValue baseValue = stackFrame.args[0].jsValue();
1880 PropertySlot slot(baseValue);
1881 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1882
1883 CHECK_FOR_EXCEPTION_AT_END();
1884 return JSValue::encode(result);
1885 }
1886
1887 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_array_fail)
1888 {
1889 STUB_INIT_STACK_FRAME(stackFrame);
1890
1891 JSValue baseValue = stackFrame.args[0].jsValue();
1892 PropertySlot slot(baseValue);
1893 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1894
1895 CHECK_FOR_EXCEPTION_AT_END();
1896 return JSValue::encode(result);
1897 }
1898
1899 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail)
1900 {
1901 STUB_INIT_STACK_FRAME(stackFrame);
1902
1903 JSValue baseValue = stackFrame.args[0].jsValue();
1904 PropertySlot slot(baseValue);
1905 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1906
1907 CHECK_FOR_EXCEPTION_AT_END();
1908 return JSValue::encode(result);
1909 }
1910
1911 DEFINE_STUB_FUNCTION(void, op_check_has_instance)
1912 {
1913 STUB_INIT_STACK_FRAME(stackFrame);
1914
1915 CallFrame* callFrame = stackFrame.callFrame;
1916 JSValue baseVal = stackFrame.args[0].jsValue();
1917
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).
1920 #ifndef NDEBUG
1921 TypeInfo typeInfo(UnspecifiedType);
1922 ASSERT(!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance());
1923 #endif
1924 stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal);
1925 VM_THROW_EXCEPTION_AT_END();
1926 }
1927
1928 #if ENABLE(DFG_JIT)
1929 DEFINE_STUB_FUNCTION(void, optimize_from_loop)
1930 {
1931 STUB_INIT_STACK_FRAME(stackFrame);
1932
1933 CallFrame* callFrame = stackFrame.callFrame;
1934 CodeBlock* codeBlock = callFrame->codeBlock();
1935
1936 unsigned bytecodeIndex = stackFrame.args[0].int32();
1937
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());
1940 #endif
1941
1942 if (!codeBlock->checkIfOptimizationThresholdReached())
1943 return;
1944
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());
1948 #endif
1949 if (codeBlock->replacement()->shouldReoptimizeFromLoopNow()) {
1950 #if ENABLE(JIT_VERBOSE_OSR)
1951 dataLog("Triggering reoptimization of %p(%p) (in loop).\n", codeBlock, codeBlock->replacement());
1952 #endif
1953 codeBlock->reoptimize();
1954 return;
1955 }
1956 } else {
1957 if (!codeBlock->shouldOptimizeNow()) {
1958 #if ENABLE(JIT_VERBOSE_OSR)
1959 dataLog("Delaying optimization for %p (in loop) because of insufficient profiling.\n", codeBlock);
1960 #endif
1961 return;
1962 }
1963
1964 ScopeChainNode* scopeChain = callFrame->scopeChain();
1965
1966 JSObject* error = codeBlock->compileOptimized(callFrame, scopeChain);
1967 #if ENABLE(JIT_VERBOSE_OSR)
1968 if (error)
1969 dataLog("WARNING: optimized compilation from loop failed.\n");
1970 #else
1971 UNUSED_PARAM(error);
1972 #endif
1973
1974 if (codeBlock->replacement() == codeBlock) {
1975 #if ENABLE(JIT_VERBOSE_OSR)
1976 dataLog("Optimizing %p from loop failed.\n", codeBlock);
1977 #endif
1978
1979 ASSERT(codeBlock->getJITType() == JITCode::BaselineJIT);
1980 codeBlock->dontOptimizeAnytimeSoon();
1981 return;
1982 }
1983 }
1984
1985 CodeBlock* optimizedCodeBlock = codeBlock->replacement();
1986 ASSERT(optimizedCodeBlock->getJITType() == JITCode::DFGJIT);
1987
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());
1991 #endif
1992
1993 codeBlock->optimizeSoon();
1994 optimizedCodeBlock->countSpeculationSuccess();
1995 STUB_SET_RETURN_ADDRESS(address);
1996 return;
1997 }
1998
1999 #if ENABLE(JIT_VERBOSE_OSR)
2000 dataLog("Optimizing %p from loop succeeded, OSR failed, after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter());
2001 #endif
2002
2003 // Count the OSR failure as a speculation failure. If this happens a lot, then
2004 // reoptimize.
2005 optimizedCodeBlock->countSpeculationFailure();
2006
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());
2009 #endif
2010
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());
2022 #endif
2023 codeBlock->reoptimize();
2024 return;
2025 }
2026
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();
2030 }
2031
2032 DEFINE_STUB_FUNCTION(void, optimize_from_ret)
2033 {
2034 STUB_INIT_STACK_FRAME(stackFrame);
2035
2036 CallFrame* callFrame = stackFrame.callFrame;
2037 CodeBlock* codeBlock = callFrame->codeBlock();
2038
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());
2041 #endif
2042
2043 if (!codeBlock->checkIfOptimizationThresholdReached())
2044 return;
2045
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();
2050 if (callerFrame)
2051 dataLog(", callerFrame = %p, returnPC = %p, caller code block = %p", callerFrame, callFrame->returnPC().value(), callerFrame->codeBlock());
2052 dataLog("\n");
2053 #endif
2054 if (codeBlock->replacement()->shouldReoptimizeNow()) {
2055 #if ENABLE(JIT_VERBOSE_OSR)
2056 dataLog("Triggering reoptimization of %p(%p) (in return).\n", codeBlock, codeBlock->replacement());
2057 #endif
2058 codeBlock->reoptimize();
2059 }
2060
2061 codeBlock->optimizeSoon();
2062 return;
2063 }
2064
2065 if (!codeBlock->shouldOptimizeNow()) {
2066 #if ENABLE(JIT_VERBOSE_OSR)
2067 dataLog("Delaying optimization for %p (in return) because of insufficient profiling.\n", codeBlock);
2068 #endif
2069 return;
2070 }
2071
2072 ScopeChainNode* scopeChain = callFrame->scopeChain();
2073
2074 JSObject* error = codeBlock->compileOptimized(callFrame, scopeChain);
2075 if (error)
2076 dataLog("WARNING: optimized compilation from ret failed.\n");
2077
2078 if (codeBlock->replacement() == codeBlock) {
2079 #if ENABLE(JIT_VERBOSE_OSR)
2080 dataLog("Optimizing %p from return failed.\n", codeBlock);
2081 #endif
2082
2083 ASSERT(codeBlock->getJITType() == JITCode::BaselineJIT);
2084 codeBlock->dontOptimizeAnytimeSoon();
2085 return;
2086 }
2087
2088 ASSERT(codeBlock->replacement()->getJITType() == JITCode::DFGJIT);
2089
2090 #if ENABLE(JIT_VERBOSE_OSR)
2091 dataLog("Optimizing %p from return succeeded after a delay of %u.\n", codeBlock, codeBlock->optimizationDelayCounter());
2092 #endif
2093
2094 codeBlock->optimizeSoon();
2095 }
2096 #endif // ENABLE(DFG_JIT)
2097
2098 DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof)
2099 {
2100 STUB_INIT_STACK_FRAME(stackFrame);
2101
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();
2106
2107 bool result = CommonSlowPaths::opInstanceOfSlow(callFrame, value, baseVal, proto);
2108 CHECK_FOR_EXCEPTION_AT_END();
2109 return JSValue::encode(jsBoolean(result));
2110 }
2111
2112 DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id)
2113 {
2114 STUB_INIT_STACK_FRAME(stackFrame);
2115
2116 CallFrame* callFrame = stackFrame.callFrame;
2117
2118 JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame);
2119
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.");
2124
2125 CHECK_FOR_EXCEPTION_AT_END();
2126 return JSValue::encode(result);
2127 }
2128
2129 DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul)
2130 {
2131 STUB_INIT_STACK_FRAME(stackFrame);
2132
2133 JSValue src1 = stackFrame.args[0].jsValue();
2134 JSValue src2 = stackFrame.args[1].jsValue();
2135
2136 if (src1.isNumber() && src2.isNumber())
2137 return JSValue::encode(jsNumber(src1.asNumber() * src2.asNumber()));
2138
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);
2143 }
2144
2145 DEFINE_STUB_FUNCTION(JSObject*, op_new_func)
2146 {
2147 STUB_INIT_STACK_FRAME(stackFrame);
2148
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());
2151 }
2152
2153 inline void* jitCompileFor(CallFrame* callFrame, CodeSpecializationKind kind)
2154 {
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);
2160 if (!error)
2161 return function;
2162 callFrame->globalData().exception = error;
2163 return 0;
2164 }
2165
2166 DEFINE_STUB_FUNCTION(void*, op_call_jitCompile)
2167 {
2168 STUB_INIT_STACK_FRAME(stackFrame);
2169
2170 #if !ASSERT_DISABLED
2171 CallData callData;
2172 ASSERT(stackFrame.callFrame->callee()->methodTable()->getCallData(stackFrame.callFrame->callee(), callData) == CallTypeJS);
2173 #endif
2174
2175 CallFrame* callFrame = stackFrame.callFrame;
2176 void* result = jitCompileFor(callFrame, CodeForCall);
2177 if (!result)
2178 return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS);
2179
2180 return result;
2181 }
2182
2183 DEFINE_STUB_FUNCTION(void*, op_construct_jitCompile)
2184 {
2185 STUB_INIT_STACK_FRAME(stackFrame);
2186
2187 #if !ASSERT_DISABLED
2188 ConstructData constructData;
2189 ASSERT(jsCast<JSFunction*>(stackFrame.callFrame->callee())->methodTable()->getConstructData(stackFrame.callFrame->callee(), constructData) == ConstructTypeJS);
2190 #endif
2191
2192 CallFrame* callFrame = stackFrame.callFrame;
2193 void* result = jitCompileFor(callFrame, CodeForConstruct);
2194 if (!result)
2195 return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS);
2196
2197 return result;
2198 }
2199
2200 DEFINE_STUB_FUNCTION(void*, op_call_arityCheck)
2201 {
2202 STUB_INIT_STACK_FRAME(stackFrame);
2203
2204 CallFrame* callFrame = stackFrame.callFrame;
2205
2206 CallFrame* newCallFrame = CommonSlowPaths::arityCheckFor(callFrame, stackFrame.registerFile, CodeForCall);
2207 if (!newCallFrame)
2208 return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS, createStackOverflowError(callFrame->callerFrame()));
2209
2210 return newCallFrame;
2211 }
2212
2213 DEFINE_STUB_FUNCTION(void*, op_construct_arityCheck)
2214 {
2215 STUB_INIT_STACK_FRAME(stackFrame);
2216
2217 CallFrame* callFrame = stackFrame.callFrame;
2218
2219 CallFrame* newCallFrame = CommonSlowPaths::arityCheckFor(callFrame, stackFrame.registerFile, CodeForConstruct);
2220 if (!newCallFrame)
2221 return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS, createStackOverflowError(callFrame->callerFrame()));
2222
2223 return newCallFrame;
2224 }
2225
2226 inline void* lazyLinkFor(CallFrame* callFrame, CodeSpecializationKind kind)
2227 {
2228 JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
2229 ExecutableBase* executable = callee->executable();
2230
2231 MacroAssemblerCodePtr codePtr;
2232 CodeBlock* codeBlock = 0;
2233 CallLinkInfo* callLinkInfo = &callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
2234
2235 if (executable->isHostFunction())
2236 codePtr = executable->generatedJITCodeFor(kind).addressForCall();
2237 else {
2238 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
2239 if (JSObject* error = functionExecutable->compileFor(callFrame, callee->scope(), kind)) {
2240 callFrame->globalData().exception = error;
2241 return 0;
2242 }
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);
2247 else
2248 codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall();
2249 }
2250
2251 if (!callLinkInfo->seenOnce())
2252 callLinkInfo->setSeen();
2253 else
2254 JIT::linkFor(callee, callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, &callFrame->globalData(), kind);
2255
2256 return codePtr.executableAddress();
2257 }
2258
2259 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall)
2260 {
2261 STUB_INIT_STACK_FRAME(stackFrame);
2262
2263 CallFrame* callFrame = stackFrame.callFrame;
2264 void* result = lazyLinkFor(callFrame, CodeForCall);
2265 if (!result)
2266 return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS);
2267
2268 return result;
2269 }
2270
2271 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct)
2272 {
2273 STUB_INIT_STACK_FRAME(stackFrame);
2274
2275 CallFrame* callFrame = stackFrame.callFrame;
2276 void* result = lazyLinkFor(callFrame, CodeForConstruct);
2277 if (!result)
2278 return throwExceptionFromOpCall<void*>(stackFrame, callFrame, STUB_RETURN_ADDRESS);
2279
2280 return result;
2281 }
2282
2283 DEFINE_STUB_FUNCTION(JSObject*, op_push_activation)
2284 {
2285 STUB_INIT_STACK_FRAME(stackFrame);
2286
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));
2289 return activation;
2290 }
2291
2292 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction)
2293 {
2294 STUB_INIT_STACK_FRAME(stackFrame);
2295
2296 CallFrame* callFrame = stackFrame.callFrame;
2297
2298 JSValue callee = callFrame->calleeAsValue();
2299
2300 CallData callData;
2301 CallType callType = getCallData(callee, callData);
2302
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));
2307 }
2308
2309 EncodedJSValue returnValue;
2310 {
2311 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
2312 returnValue = callData.native.function(callFrame);
2313 }
2314
2315 if (stackFrame.globalData->exception)
2316 return throwExceptionFromOpCall<EncodedJSValue>(stackFrame, callFrame, STUB_RETURN_ADDRESS);
2317
2318 return returnValue;
2319 }
2320
2321 DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments)
2322 {
2323 STUB_INIT_STACK_FRAME(stackFrame);
2324
2325 Arguments* arguments = Arguments::create(*stackFrame.globalData, stackFrame.callFrame);
2326 return JSValue::encode(JSValue(arguments));
2327 }
2328
2329 DEFINE_STUB_FUNCTION(void, op_tear_off_activation)
2330 {
2331 STUB_INIT_STACK_FRAME(stackFrame);
2332
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);
2340 }
2341 return;
2342 }
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);
2347 }
2348
2349 DEFINE_STUB_FUNCTION(void, op_tear_off_arguments)
2350 {
2351 STUB_INIT_STACK_FRAME(stackFrame);
2352
2353 CallFrame* callFrame = stackFrame.callFrame;
2354 ASSERT(callFrame->codeBlock()->usesArguments() && !callFrame->codeBlock()->needsFullScopeChain());
2355 asArguments(stackFrame.args[0].jsValue())->tearOff(callFrame);
2356 }
2357
2358 DEFINE_STUB_FUNCTION(void, op_profile_will_call)
2359 {
2360 STUB_INIT_STACK_FRAME(stackFrame);
2361
2362 ASSERT(*stackFrame.enabledProfilerReference);
2363 (*stackFrame.enabledProfilerReference)->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
2364 }
2365
2366 DEFINE_STUB_FUNCTION(void, op_profile_did_call)
2367 {
2368 STUB_INIT_STACK_FRAME(stackFrame);
2369
2370 ASSERT(*stackFrame.enabledProfilerReference);
2371 (*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
2372 }
2373
2374 DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
2375 {
2376 STUB_INIT_STACK_FRAME(stackFrame);
2377
2378 return constructArray(stackFrame.callFrame, reinterpret_cast<JSValue*>(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()]), stackFrame.args[1].int32());
2379 }
2380
2381 DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer)
2382 {
2383 STUB_INIT_STACK_FRAME(stackFrame);
2384
2385 return constructArray(stackFrame.callFrame, stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
2386 }
2387
2388 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
2389 {
2390 STUB_INIT_STACK_FRAME(stackFrame);
2391
2392 CallFrame* callFrame = stackFrame.callFrame;
2393
2394 JSValue result = CommonSlowPaths::opResolve(callFrame, stackFrame.args[0].identifier());
2395 CHECK_FOR_EXCEPTION_AT_END();
2396 return JSValue::encode(result);
2397 }
2398
2399 DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
2400 {
2401 STUB_INIT_STACK_FRAME(stackFrame);
2402
2403 CallFrame* callFrame = stackFrame.callFrame;
2404 JSValue callee = callFrame->calleeAsValue();
2405
2406 ConstructData constructData;
2407 ConstructType constructType = getConstructData(callee, constructData);
2408
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));
2413 }
2414
2415 EncodedJSValue returnValue;
2416 {
2417 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
2418 returnValue = constructData.native.function(callFrame);
2419 }
2420
2421 if (stackFrame.globalData->exception)
2422 return throwExceptionFromOpCall<EncodedJSValue>(stackFrame, callFrame, STUB_RETURN_ADDRESS);
2423
2424 return returnValue;
2425 }
2426
2427 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val)
2428 {
2429 STUB_INIT_STACK_FRAME(stackFrame);
2430
2431 CallFrame* callFrame = stackFrame.callFrame;
2432
2433 JSValue baseValue = stackFrame.args[0].jsValue();
2434 JSValue subscript = stackFrame.args[1].jsValue();
2435
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);
2440 }
2441 }
2442
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);
2450 }
2451 JSValue result = baseValue.get(callFrame, i);
2452 CHECK_FOR_EXCEPTION();
2453 return JSValue::encode(result);
2454 }
2455
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);
2460 }
2461
2462 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string)
2463 {
2464 STUB_INIT_STACK_FRAME(stackFrame);
2465
2466 CallFrame* callFrame = stackFrame.callFrame;
2467
2468 JSValue baseValue = stackFrame.args[0].jsValue();
2469 JSValue subscript = stackFrame.args[1].jsValue();
2470
2471 JSValue result;
2472
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);
2477 else {
2478 result = baseValue.get(callFrame, i);
2479 if (!isJSString(baseValue))
2480 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val));
2481 }
2482 } else {
2483 Identifier property(callFrame, subscript.toString(callFrame)->value(callFrame));
2484 result = baseValue.get(callFrame, property);
2485 }
2486
2487 CHECK_FOR_EXCEPTION_AT_END();
2488 return JSValue::encode(result);
2489 }
2490
2491 DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub)
2492 {
2493 STUB_INIT_STACK_FRAME(stackFrame);
2494
2495 JSValue src1 = stackFrame.args[0].jsValue();
2496 JSValue src2 = stackFrame.args[1].jsValue();
2497
2498 if (src1.isNumber() && src2.isNumber())
2499 return JSValue::encode(jsNumber(src1.asNumber() - src2.asNumber()));
2500
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);
2505 }
2506
2507 DEFINE_STUB_FUNCTION(void, op_put_by_val)
2508 {
2509 STUB_INIT_STACK_FRAME(stackFrame);
2510
2511 CallFrame* callFrame = stackFrame.callFrame;
2512 JSGlobalData* globalData = stackFrame.globalData;
2513
2514 JSValue baseValue = stackFrame.args[0].jsValue();
2515 JSValue subscript = stackFrame.args[1].jsValue();
2516 JSValue value = stackFrame.args[2].jsValue();
2517
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);
2524 else
2525 JSArray::putByIndex(jsArray, callFrame, i, value, callFrame->codeBlock()->isStrictMode());
2526 } else
2527 baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode());
2528 } else {
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);
2533 }
2534 }
2535
2536 CHECK_FOR_EXCEPTION_AT_END();
2537 }
2538
2539 DEFINE_STUB_FUNCTION(EncodedJSValue, op_less)
2540 {
2541 STUB_INIT_STACK_FRAME(stackFrame);
2542
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);
2547 }
2548
2549 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lesseq)
2550 {
2551 STUB_INIT_STACK_FRAME(stackFrame);
2552
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);
2557 }
2558
2559 DEFINE_STUB_FUNCTION(EncodedJSValue, op_greater)
2560 {
2561 STUB_INIT_STACK_FRAME(stackFrame);
2562
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);
2567 }
2568
2569 DEFINE_STUB_FUNCTION(EncodedJSValue, op_greatereq)
2570 {
2571 STUB_INIT_STACK_FRAME(stackFrame);
2572
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);
2577 }
2578
2579 DEFINE_STUB_FUNCTION(void*, op_load_varargs)
2580 {
2581 STUB_INIT_STACK_FRAME(stackFrame);
2582
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();
2588
2589 CallFrame* newCallFrame = loadVarargs(callFrame, registerFile, thisValue, arguments, firstFreeRegister);
2590 if (!newCallFrame)
2591 VM_THROW_EXCEPTION();
2592 return newCallFrame;
2593 }
2594
2595 DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate)
2596 {
2597 STUB_INIT_STACK_FRAME(stackFrame);
2598
2599 JSValue src = stackFrame.args[0].jsValue();
2600
2601 if (src.isNumber())
2602 return JSValue::encode(jsNumber(-src.asNumber()));
2603
2604 CallFrame* callFrame = stackFrame.callFrame;
2605 JSValue result = jsNumber(-src.toNumber(callFrame));
2606 CHECK_FOR_EXCEPTION_AT_END();
2607 return JSValue::encode(result);
2608 }
2609
2610 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base)
2611 {
2612 STUB_INIT_STACK_FRAME(stackFrame);
2613
2614 return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), false));
2615 }
2616
2617 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put)
2618 {
2619 STUB_INIT_STACK_FRAME(stackFrame);
2620 JSValue base = JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), true);
2621 if (!base) {
2622 stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[0].identifier().ustring());
2623 VM_THROW_EXCEPTION();
2624 }
2625 return JSValue::encode(base);
2626 }
2627
2628 DEFINE_STUB_FUNCTION(EncodedJSValue, op_ensure_property_exists)
2629 {
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();
2638 }
2639
2640 return JSValue::encode(base);
2641 }
2642
2643 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip)
2644 {
2645 STUB_INIT_STACK_FRAME(stackFrame);
2646
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);
2650 }
2651
2652 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
2653 {
2654 STUB_INIT_STACK_FRAME(stackFrame);
2655
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());
2662
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);
2671 }
2672
2673 CHECK_FOR_EXCEPTION_AT_END();
2674 return JSValue::encode(result);
2675 }
2676
2677 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
2678 VM_THROW_EXCEPTION();
2679 }
2680
2681 DEFINE_STUB_FUNCTION(EncodedJSValue, op_div)
2682 {
2683 STUB_INIT_STACK_FRAME(stackFrame);
2684
2685 JSValue src1 = stackFrame.args[0].jsValue();
2686 JSValue src2 = stackFrame.args[1].jsValue();
2687
2688 if (src1.isNumber() && src2.isNumber())
2689 return JSValue::encode(jsNumber(src1.asNumber() / src2.asNumber()));
2690
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);
2695 }
2696
2697 DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec)
2698 {
2699 STUB_INIT_STACK_FRAME(stackFrame);
2700
2701 JSValue v = stackFrame.args[0].jsValue();
2702
2703 CallFrame* callFrame = stackFrame.callFrame;
2704 JSValue result = jsNumber(v.toNumber(callFrame) - 1);
2705 CHECK_FOR_EXCEPTION_AT_END();
2706 return JSValue::encode(result);
2707 }
2708
2709 DEFINE_STUB_FUNCTION(int, op_jless)
2710 {
2711 STUB_INIT_STACK_FRAME(stackFrame);
2712
2713 JSValue src1 = stackFrame.args[0].jsValue();
2714 JSValue src2 = stackFrame.args[1].jsValue();
2715 CallFrame* callFrame = stackFrame.callFrame;
2716
2717 bool result = jsLess<true>(callFrame, src1, src2);
2718 CHECK_FOR_EXCEPTION_AT_END();
2719 return result;
2720 }
2721
2722 DEFINE_STUB_FUNCTION(int, op_jlesseq)
2723 {
2724 STUB_INIT_STACK_FRAME(stackFrame);
2725
2726 JSValue src1 = stackFrame.args[0].jsValue();
2727 JSValue src2 = stackFrame.args[1].jsValue();
2728 CallFrame* callFrame = stackFrame.callFrame;
2729
2730 bool result = jsLessEq<true>(callFrame, src1, src2);
2731 CHECK_FOR_EXCEPTION_AT_END();
2732 return result;
2733 }
2734
2735 DEFINE_STUB_FUNCTION(int, op_jgreater)
2736 {
2737 STUB_INIT_STACK_FRAME(stackFrame);
2738
2739 JSValue src1 = stackFrame.args[0].jsValue();
2740 JSValue src2 = stackFrame.args[1].jsValue();
2741 CallFrame* callFrame = stackFrame.callFrame;
2742
2743 bool result = jsLess<false>(callFrame, src2, src1);
2744 CHECK_FOR_EXCEPTION_AT_END();
2745 return result;
2746 }
2747
2748 DEFINE_STUB_FUNCTION(int, op_jgreatereq)
2749 {
2750 STUB_INIT_STACK_FRAME(stackFrame);
2751
2752 JSValue src1 = stackFrame.args[0].jsValue();
2753 JSValue src2 = stackFrame.args[1].jsValue();
2754 CallFrame* callFrame = stackFrame.callFrame;
2755
2756 bool result = jsLessEq<false>(callFrame, src2, src1);
2757 CHECK_FOR_EXCEPTION_AT_END();
2758 return result;
2759 }
2760
2761 DEFINE_STUB_FUNCTION(EncodedJSValue, op_not)
2762 {
2763 STUB_INIT_STACK_FRAME(stackFrame);
2764
2765 JSValue src = stackFrame.args[0].jsValue();
2766
2767 CallFrame* callFrame = stackFrame.callFrame;
2768
2769 JSValue result = jsBoolean(!src.toBoolean(callFrame));
2770 CHECK_FOR_EXCEPTION_AT_END();
2771 return JSValue::encode(result);
2772 }
2773
2774 DEFINE_STUB_FUNCTION(int, op_jtrue)
2775 {
2776 STUB_INIT_STACK_FRAME(stackFrame);
2777
2778 JSValue src1 = stackFrame.args[0].jsValue();
2779
2780 CallFrame* callFrame = stackFrame.callFrame;
2781
2782 bool result = src1.toBoolean(callFrame);
2783 CHECK_FOR_EXCEPTION_AT_END();
2784 return result;
2785 }
2786
2787 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc)
2788 {
2789 STUB_INIT_STACK_FRAME(stackFrame);
2790
2791 JSValue v = stackFrame.args[0].jsValue();
2792
2793 CallFrame* callFrame = stackFrame.callFrame;
2794
2795 double number = v.toNumber(callFrame);
2796 CHECK_FOR_EXCEPTION_AT_END();
2797
2798 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number + 1);
2799 return JSValue::encode(jsNumber(number));
2800 }
2801
2802 DEFINE_STUB_FUNCTION(int, op_eq)
2803 {
2804 STUB_INIT_STACK_FRAME(stackFrame);
2805
2806 JSValue src1 = stackFrame.args[0].jsValue();
2807 JSValue src2 = stackFrame.args[1].jsValue();
2808
2809 #if USE(JSVALUE32_64)
2810 start:
2811 if (src2.isUndefined()) {
2812 return src1.isNull() ||
2813 (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined())
2814 || src1.isUndefined();
2815 }
2816
2817 if (src2.isNull()) {
2818 return src1.isUndefined() ||
2819 (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined())
2820 || src1.isNull();
2821 }
2822
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;
2829 }
2830
2831 if (src1.isDouble()) {
2832 if (src2.isInt32())
2833 return src1.asDouble() == src2.asInt32();
2834 double d = src2.toNumber(stackFrame.callFrame);
2835 CHECK_FOR_EXCEPTION();
2836 return src1.asDouble() == d;
2837 }
2838
2839 if (src1.isTrue()) {
2840 if (src2.isFalse())
2841 return false;
2842 double d = src2.toNumber(stackFrame.callFrame);
2843 CHECK_FOR_EXCEPTION();
2844 return d == 1.0;
2845 }
2846
2847 if (src1.isFalse()) {
2848 if (src2.isTrue())
2849 return false;
2850 double d = src2.toNumber(stackFrame.callFrame);
2851 CHECK_FOR_EXCEPTION();
2852 return d == 0.0;
2853 }
2854
2855 if (src1.isUndefined())
2856 return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
2857
2858 if (src1.isNull())
2859 return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
2860
2861 JSCell* cell1 = src1.asCell();
2862
2863 if (cell1->isString()) {
2864 if (src2.isInt32())
2865 return jsToNumber(jsCast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asInt32();
2866
2867 if (src2.isDouble())
2868 return jsToNumber(jsCast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asDouble();
2869
2870 if (src2.isTrue())
2871 return jsToNumber(jsCast<JSString*>(cell1)->value(stackFrame.callFrame)) == 1.0;
2872
2873 if (src2.isFalse())
2874 return jsToNumber(jsCast<JSString*>(cell1)->value(stackFrame.callFrame)) == 0.0;
2875
2876 JSCell* cell2 = src2.asCell();
2877 if (cell2->isString())
2878 return jsCast<JSString*>(cell1)->value(stackFrame.callFrame) == jsCast<JSString*>(cell2)->value(stackFrame.callFrame);
2879
2880 src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame);
2881 CHECK_FOR_EXCEPTION();
2882 goto start;
2883 }
2884
2885 if (src2.isObject())
2886 return asObject(cell1) == asObject(src2);
2887 src1 = asObject(cell1)->toPrimitive(stackFrame.callFrame);
2888 CHECK_FOR_EXCEPTION();
2889 goto start;
2890
2891 #else // USE(JSVALUE32_64)
2892 CallFrame* callFrame = stackFrame.callFrame;
2893
2894 bool result = JSValue::equalSlowCaseInline(callFrame, src1, src2);
2895 CHECK_FOR_EXCEPTION_AT_END();
2896 return result;
2897 #endif // USE(JSVALUE32_64)
2898 }
2899
2900 DEFINE_STUB_FUNCTION(int, op_eq_strings)
2901 {
2902 #if USE(JSVALUE32_64)
2903 STUB_INIT_STACK_FRAME(stackFrame);
2904
2905 JSString* string1 = stackFrame.args[0].jsString();
2906 JSString* string2 = stackFrame.args[1].jsString();
2907
2908 ASSERT(string1->isString());
2909 ASSERT(string2->isString());
2910 return string1->value(stackFrame.callFrame) == string2->value(stackFrame.callFrame);
2911 #else
2912 UNUSED_PARAM(args);
2913 ASSERT_NOT_REACHED();
2914 return 0;
2915 #endif
2916 }
2917
2918 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift)
2919 {
2920 STUB_INIT_STACK_FRAME(stackFrame);
2921
2922 JSValue val = stackFrame.args[0].jsValue();
2923 JSValue shift = stackFrame.args[1].jsValue();
2924
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);
2929 }
2930
2931 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand)
2932 {
2933 STUB_INIT_STACK_FRAME(stackFrame);
2934
2935 JSValue src1 = stackFrame.args[0].jsValue();
2936 JSValue src2 = stackFrame.args[1].jsValue();
2937
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);
2943 }
2944
2945 DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift)
2946 {
2947 STUB_INIT_STACK_FRAME(stackFrame);
2948
2949 JSValue val = stackFrame.args[0].jsValue();
2950 JSValue shift = stackFrame.args[1].jsValue();
2951
2952 CallFrame* callFrame = stackFrame.callFrame;
2953 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2954
2955 CHECK_FOR_EXCEPTION_AT_END();
2956 return JSValue::encode(result);
2957 }
2958
2959 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base)
2960 {
2961 STUB_INIT_STACK_FRAME(stackFrame);
2962
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);
2967 }
2968
2969 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_this)
2970 {
2971 STUB_INIT_STACK_FRAME(stackFrame);
2972
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);
2977 }
2978
2979 DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp)
2980 {
2981 STUB_INIT_STACK_FRAME(stackFrame);
2982 CallFrame* callFrame = stackFrame.callFrame;
2983
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());
2987
2988 /*
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.
2994 */
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));
2998 }
2999
3000 return func;
3001 }
3002
3003 DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod)
3004 {
3005 STUB_INIT_STACK_FRAME(stackFrame);
3006
3007 JSValue dividendValue = stackFrame.args[0].jsValue();
3008 JSValue divisorValue = stackFrame.args[1].jsValue();
3009
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);
3015 }
3016
3017 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec)
3018 {
3019 STUB_INIT_STACK_FRAME(stackFrame);
3020
3021 JSValue v = stackFrame.args[0].jsValue();
3022
3023 CallFrame* callFrame = stackFrame.callFrame;
3024
3025 double number = v.toNumber(callFrame);
3026 CHECK_FOR_EXCEPTION_AT_END();
3027
3028 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number - 1);
3029 return JSValue::encode(jsNumber(number));
3030 }
3031
3032 DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift)
3033 {
3034 STUB_INIT_STACK_FRAME(stackFrame);
3035
3036 JSValue val = stackFrame.args[0].jsValue();
3037 JSValue shift = stackFrame.args[1].jsValue();
3038
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);
3043 }
3044
3045 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor)
3046 {
3047 STUB_INIT_STACK_FRAME(stackFrame);
3048
3049 JSValue src1 = stackFrame.args[0].jsValue();
3050 JSValue src2 = stackFrame.args[1].jsValue();
3051
3052 CallFrame* callFrame = stackFrame.callFrame;
3053
3054 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
3055 CHECK_FOR_EXCEPTION_AT_END();
3056 return JSValue::encode(result);
3057 }
3058
3059 DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp)
3060 {
3061 STUB_INIT_STACK_FRAME(stackFrame);
3062
3063 CallFrame* callFrame = stackFrame.callFrame;
3064
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();
3069 }
3070
3071 return RegExpObject::create(*stackFrame.globalData, stackFrame.callFrame->lexicalGlobalObject(), stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), regExp);
3072 }
3073
3074 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor)
3075 {
3076 STUB_INIT_STACK_FRAME(stackFrame);
3077
3078 JSValue src1 = stackFrame.args[0].jsValue();
3079 JSValue src2 = stackFrame.args[1].jsValue();
3080
3081 CallFrame* callFrame = stackFrame.callFrame;
3082
3083 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
3084 CHECK_FOR_EXCEPTION_AT_END();
3085 return JSValue::encode(result);
3086 }
3087
3088 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval)
3089 {
3090 STUB_INIT_STACK_FRAME(stackFrame);
3091
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());
3097
3098 callFrame->setScopeChain(callerFrame->scopeChain());
3099 callFrame->setReturnPC(static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()));
3100 callFrame->setCodeBlock(0);
3101
3102 if (!isHostFunction(callFrame->calleeAsValue(), globalFuncEval))
3103 return JSValue::encode(JSValue());
3104
3105 JSValue result = eval(callFrame);
3106 if (stackFrame.globalData->exception)
3107 return throwExceptionFromOpCall<EncodedJSValue>(stackFrame, callFrame, STUB_RETURN_ADDRESS);
3108
3109 return JSValue::encode(result);
3110 }
3111
3112 DEFINE_STUB_FUNCTION(void*, op_throw)
3113 {
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;
3118 }
3119
3120 DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames)
3121 {
3122 STUB_INIT_STACK_FRAME(stackFrame);
3123
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;
3131 }
3132
3133 DEFINE_STUB_FUNCTION(int, has_property)
3134 {
3135 STUB_INIT_STACK_FRAME(stackFrame);
3136
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();
3141 return result;
3142 }
3143
3144 DEFINE_STUB_FUNCTION(JSObject*, op_push_scope)
3145 {
3146 STUB_INIT_STACK_FRAME(stackFrame);
3147
3148 JSObject* o = stackFrame.args[0].jsValue().toObject(stackFrame.callFrame);
3149 CHECK_FOR_EXCEPTION();
3150 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(o));
3151 return o;
3152 }
3153
3154 DEFINE_STUB_FUNCTION(void, op_pop_scope)
3155 {
3156 STUB_INIT_STACK_FRAME(stackFrame);
3157
3158 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->pop());
3159 }
3160
3161 DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof)
3162 {
3163 STUB_INIT_STACK_FRAME(stackFrame);
3164
3165 return JSValue::encode(jsTypeStringForValue(stackFrame.callFrame, stackFrame.args[0].jsValue()));
3166 }
3167
3168 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_object)
3169 {
3170 STUB_INIT_STACK_FRAME(stackFrame);
3171
3172 return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame.args[0].jsValue())));
3173 }
3174
3175 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_function)
3176 {
3177 STUB_INIT_STACK_FRAME(stackFrame);
3178
3179 return JSValue::encode(jsBoolean(jsIsFunctionType(stackFrame.args[0].jsValue())));
3180 }
3181
3182 DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq)
3183 {
3184 STUB_INIT_STACK_FRAME(stackFrame);
3185
3186 JSValue src1 = stackFrame.args[0].jsValue();
3187 JSValue src2 = stackFrame.args[1].jsValue();
3188
3189 bool result = JSValue::strictEqual(stackFrame.callFrame, src1, src2);
3190 CHECK_FOR_EXCEPTION_AT_END();
3191 return JSValue::encode(jsBoolean(result));
3192 }
3193
3194 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive)
3195 {
3196 STUB_INIT_STACK_FRAME(stackFrame);
3197
3198 return JSValue::encode(stackFrame.args[0].jsValue().toPrimitive(stackFrame.callFrame));
3199 }
3200
3201 DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat)
3202 {
3203 STUB_INIT_STACK_FRAME(stackFrame);
3204
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);
3208 }
3209
3210 DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq)
3211 {
3212 STUB_INIT_STACK_FRAME(stackFrame);
3213
3214 JSValue src1 = stackFrame.args[0].jsValue();
3215 JSValue src2 = stackFrame.args[1].jsValue();
3216
3217 bool result = !JSValue::strictEqual(stackFrame.callFrame, src1, src2);
3218 CHECK_FOR_EXCEPTION_AT_END();
3219 return JSValue::encode(jsBoolean(result));
3220 }
3221
3222 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber)
3223 {
3224 STUB_INIT_STACK_FRAME(stackFrame);
3225
3226 JSValue src = stackFrame.args[0].jsValue();
3227 CallFrame* callFrame = stackFrame.callFrame;
3228
3229 double number = src.toNumber(callFrame);
3230 CHECK_FOR_EXCEPTION_AT_END();
3231 return JSValue::encode(jsNumber(number));
3232 }
3233
3234 DEFINE_STUB_FUNCTION(EncodedJSValue, op_in)
3235 {
3236 STUB_INIT_STACK_FRAME(stackFrame);
3237
3238 CallFrame* callFrame = stackFrame.callFrame;
3239 JSValue baseVal = stackFrame.args[1].jsValue();
3240
3241 if (!baseVal.isObject()) {
3242 stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal);
3243 VM_THROW_EXCEPTION();
3244 }
3245
3246 JSValue propName = stackFrame.args[0].jsValue();
3247 JSObject* baseObj = asObject(baseVal);
3248
3249 uint32_t i;
3250 if (propName.getUInt32(i))
3251 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i)));
3252
3253 Identifier property(callFrame, propName.toString(callFrame)->value(callFrame));
3254 CHECK_FOR_EXCEPTION();
3255 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property)));
3256 }
3257
3258 DEFINE_STUB_FUNCTION(JSObject*, op_push_new_scope)
3259 {
3260 STUB_INIT_STACK_FRAME(stackFrame);
3261
3262 JSObject* scope = JSStaticScopeObject::create(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].jsValue(), DontDelete);
3263
3264 CallFrame* callFrame = stackFrame.callFrame;
3265 callFrame->setScopeChain(callFrame->scopeChain()->push(scope));
3266 return scope;
3267 }
3268
3269 DEFINE_STUB_FUNCTION(void, op_jmp_scopes)
3270 {
3271 STUB_INIT_STACK_FRAME(stackFrame);
3272
3273 unsigned count = stackFrame.args[0].int32();
3274 CallFrame* callFrame = stackFrame.callFrame;
3275
3276 ScopeChainNode* tmp = callFrame->scopeChain();
3277 while (count--)
3278 tmp = tmp->pop();
3279 callFrame->setScopeChain(tmp);
3280 }
3281
3282 DEFINE_STUB_FUNCTION(void, op_put_by_index)
3283 {
3284 STUB_INIT_STACK_FRAME(stackFrame);
3285
3286 CallFrame* callFrame = stackFrame.callFrame;
3287 unsigned property = stackFrame.args[1].int32();
3288
3289 JSValue arrayValue = stackFrame.args[0].jsValue();
3290 ASSERT(isJSArray(arrayValue));
3291 asArray(arrayValue)->putDirectIndex(callFrame, property, stackFrame.args[2].jsValue(), false);
3292 }
3293
3294 DEFINE_STUB_FUNCTION(void*, op_switch_imm)
3295 {
3296 STUB_INIT_STACK_FRAME(stackFrame);
3297
3298 JSValue scrutinee = stackFrame.args[0].jsValue();
3299 unsigned tableIndex = stackFrame.args[1].int32();
3300 CallFrame* callFrame = stackFrame.callFrame;
3301 CodeBlock* codeBlock = callFrame->codeBlock();
3302
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();
3308 }
3309
3310 DEFINE_STUB_FUNCTION(void*, op_switch_char)
3311 {
3312 STUB_INIT_STACK_FRAME(stackFrame);
3313
3314 JSValue scrutinee = stackFrame.args[0].jsValue();
3315 unsigned tableIndex = stackFrame.args[1].int32();
3316 CallFrame* callFrame = stackFrame.callFrame;
3317 CodeBlock* codeBlock = callFrame->codeBlock();
3318
3319 void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3320
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();
3325 }
3326
3327 CHECK_FOR_EXCEPTION_AT_END();
3328 return result;
3329 }
3330
3331 DEFINE_STUB_FUNCTION(void*, op_switch_string)
3332 {
3333 STUB_INIT_STACK_FRAME(stackFrame);
3334
3335 JSValue scrutinee = stackFrame.args[0].jsValue();
3336 unsigned tableIndex = stackFrame.args[1].int32();
3337 CallFrame* callFrame = stackFrame.callFrame;
3338 CodeBlock* codeBlock = callFrame->codeBlock();
3339
3340 void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3341
3342 if (scrutinee.isString()) {
3343 StringImpl* value = asString(scrutinee)->value(callFrame).impl();
3344 result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress();
3345 }
3346
3347 CHECK_FOR_EXCEPTION_AT_END();
3348 return result;
3349 }
3350
3351 DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val)
3352 {
3353 STUB_INIT_STACK_FRAME(stackFrame);
3354
3355 CallFrame* callFrame = stackFrame.callFrame;
3356
3357 JSValue baseValue = stackFrame.args[0].jsValue();
3358 JSObject* baseObj = baseValue.toObject(callFrame); // may throw
3359
3360 JSValue subscript = stackFrame.args[1].jsValue();
3361 bool result;
3362 uint32_t i;
3363 if (subscript.getUInt32(i))
3364 result = baseObj->methodTable()->deletePropertyByIndex(baseObj, callFrame, i);
3365 else {
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);
3370 }
3371
3372 if (!result && callFrame->codeBlock()->isStrictMode())
3373 stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property.");
3374
3375 CHECK_FOR_EXCEPTION_AT_END();
3376 return JSValue::encode(jsBoolean(result));
3377 }
3378
3379 DEFINE_STUB_FUNCTION(void, op_put_getter_setter)
3380 {
3381 STUB_INIT_STACK_FRAME(stackFrame);
3382
3383 CallFrame* callFrame = stackFrame.callFrame;
3384
3385 ASSERT(stackFrame.args[0].jsValue().isObject());
3386 JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
3387
3388 GetterSetter* accessor = GetterSetter::create(callFrame);
3389
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());
3395
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);
3401 }
3402
3403 DEFINE_STUB_FUNCTION(void, op_throw_reference_error)
3404 {
3405 STUB_INIT_STACK_FRAME(stackFrame);
3406
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();
3411 }
3412
3413 DEFINE_STUB_FUNCTION(void, op_debug)
3414 {
3415 STUB_INIT_STACK_FRAME(stackFrame);
3416
3417 CallFrame* callFrame = stackFrame.callFrame;
3418
3419 int debugHookID = stackFrame.args[0].int32();
3420 int firstLine = stackFrame.args[1].int32();
3421 int lastLine = stackFrame.args[2].int32();
3422
3423 stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3424 }
3425
3426 DEFINE_STUB_FUNCTION(void*, vm_throw)
3427 {
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;
3433 }
3434
3435 DEFINE_STUB_FUNCTION(EncodedJSValue, to_object)
3436 {
3437 STUB_INIT_STACK_FRAME(stackFrame);
3438
3439 CallFrame* callFrame = stackFrame.callFrame;
3440 return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame));
3441 }
3442
3443 MacroAssemblerCodeRef JITThunks::ctiStub(JSGlobalData* globalData, ThunkGenerator generator)
3444 {
3445 CTIStubMap::AddResult entry = m_ctiStubMap.add(generator, MacroAssemblerCodeRef());
3446 if (entry.isNewEntry)
3447 entry.iterator->second = generator(globalData);
3448 return entry.iterator->second;
3449 }
3450
3451 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, NativeFunction constructor)
3452 {
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();
3457 }
3458
3459 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator, Intrinsic intrinsic)
3460 {
3461 HostFunctionStubMap::AddResult entry = m_hostFunctionStubMap->add(function, PassWeak<NativeExecutable>());
3462 if (!entry.iterator->second) {
3463 MacroAssemblerCodeRef code;
3464 if (generator) {
3465 if (globalData->canUseJIT())
3466 code = generator(globalData);
3467 else
3468 code = MacroAssemblerCodeRef();
3469 } else
3470 code = JIT::compileCTINativeCall(globalData, function);
3471 entry.iterator->second = PassWeak<NativeExecutable>(NativeExecutable::create(*globalData, code, function, MacroAssemblerCodeRef::createSelfManagedCodeRef(ctiNativeConstruct()), callHostFunctionAsConstructor, intrinsic));
3472 }
3473 return entry.iterator->second.get();
3474 }
3475
3476 void JITThunks::clearHostFunctionStubs()
3477 {
3478 m_hostFunctionStubMap.clear();
3479 }
3480
3481 } // namespace JSC
3482
3483 #endif // ENABLE(JIT)