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