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(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, Strong<NativeExecutable>());
3591 if (entry.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, Strong<NativeExecutable>());
3599 if (entry.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