]> git.saurik.com Git - apple/javascriptcore.git/blob - jit/JITStubs.cpp
JavaScriptCore-903.5.tar.gz
[apple/javascriptcore.git] / jit / JITStubs.cpp
1 /*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
4 * Copyright (C) Research In Motion Limited 2010, 2011. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "config.h"
32
33 #if ENABLE(JIT)
34 #include "JITStubs.h"
35
36 #include "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
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
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
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
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
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
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
754 JITThunks::JITThunks(JSGlobalData* globalData)
755 : m_hostFunctionStubMap(adoptPtr(new HostFunctionStubMap))
756 {
757 if (!globalData->executableAllocator.isValid())
758 return;
759
760 JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_trampolineStructure);
761 ASSERT(m_executablePool);
762 #if CPU(ARM_THUMB2)
763 // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types),
764 // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT
765 // macros.
766 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET);
767 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVED_R4_OFFSET);
768 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == PRESERVED_R5_OFFSET);
769 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == PRESERVED_R6_OFFSET);
770
771 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET);
772 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET);
773 // The fifth argument is the first item already on the stack.
774 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET);
775
776 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
777
778 #elif CPU(ARM_TRADITIONAL)
779
780 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
781 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == PRESERVEDR4_OFFSET);
782
783
784 #elif CPU(MIPS)
785 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedGP) == PRESERVED_GP_OFFSET);
786 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS0) == PRESERVED_S0_OFFSET);
787 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS1) == PRESERVED_S1_OFFSET);
788 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedS2) == PRESERVED_S2_OFFSET);
789 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == PRESERVED_RETURN_ADDRESS_OFFSET);
790 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET);
791 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == REGISTER_FILE_OFFSET);
792 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == CALLFRAME_OFFSET);
793 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, unused1) == EXCEPTION_OFFSET);
794 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == ENABLE_PROFILER_REFERENCE_OFFSET);
795 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, globalData) == GLOBAL_DATA_OFFSET);
796
797 #endif
798 }
799
800 JITThunks::~JITThunks()
801 {
802 }
803
804 #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
805
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() || structure->typeInfo().prohibitsPropertyCaching()) {
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
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() || structure->typeInfo().prohibitsPropertyCaching()) {
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) || ((slot.cachedOffset() * sizeof(JSValue)) > (unsigned)MacroAssembler::MaximumCompactPtrAlignedAddressOffset))
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
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 {
961 ALWAYS_INLINE StackHack(JITStackFrame& stackFrame)
962 : stackFrame(stackFrame)
963 , savedReturnAddress(*stackFrame.returnAddressSlot())
964 {
965 *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode));
966 }
967
968 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.
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
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 };
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
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
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
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
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
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
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
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
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
1390 DEFINE_STUB_FUNCTION(JSObject*, op_new_object)
1391 {
1392 STUB_INIT_STACK_FRAME(stackFrame);
1393
1394 return constructEmptyObject(stackFrame.callFrame);
1395 }
1396
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
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
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
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
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
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
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
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
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 JSObjectWithGlobalObject* callee = (JSObjectWithGlobalObject*)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
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
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
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
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
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
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() || baseValue.asCell()->structure()->typeInfo().prohibitsPropertyCaching()) {
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
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
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
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
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
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
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
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
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
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
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
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
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
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 ASSERT((void*)callFrame <= stackFrame.registerFile->end());
2076 callFrame = CallFrame::create(r);
2077 callFrame->setCallerFrame(oldCallFrame);
2078 callFrame->setArgumentCountIncludingThis(argCount);
2079 callFrame->setCallee(callee);
2080 callFrame->setScopeChain(callee->scope());
2081 callFrame->setReturnPC(pc.value());
2082
2083 ASSERT((void*)callFrame <= stackFrame.registerFile->end());
2084 return callFrame;
2085 }
2086
2087 #if ENABLE(JIT_OPTIMIZE_CALL)
2088 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall)
2089 {
2090 STUB_INIT_STACK_FRAME(stackFrame);
2091 CallFrame* callFrame = stackFrame.callFrame;
2092 JSFunction* callee = asFunction(callFrame->callee());
2093 ExecutableBase* executable = callee->executable();
2094
2095 MacroAssemblerCodePtr codePtr;
2096 CodeBlock* codeBlock = 0;
2097 if (executable->isHostFunction())
2098 codePtr = executable->generatedJITCodeForCall().addressForCall();
2099 else {
2100 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
2101 JSObject* error = functionExecutable->compileForCall(callFrame, callee->scope());
2102 if (error) {
2103 callFrame->globalData().exception = createStackOverflowError(callFrame);
2104 return 0;
2105 }
2106 codeBlock = &functionExecutable->generatedBytecodeForCall();
2107 if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters))
2108 codePtr = functionExecutable->generatedJITCodeForCall().addressForCall();
2109 else
2110 codePtr = functionExecutable->generatedJITCodeForCallWithArityCheck();
2111 }
2112 CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
2113
2114 if (!callLinkInfo->seenOnce())
2115 callLinkInfo->setSeen();
2116 else
2117 JIT::linkCall(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData);
2118
2119 return codePtr.executableAddress();
2120 }
2121
2122 DEFINE_STUB_FUNCTION(void*, vm_lazyLinkConstruct)
2123 {
2124 STUB_INIT_STACK_FRAME(stackFrame);
2125 CallFrame* callFrame = stackFrame.callFrame;
2126 JSFunction* callee = asFunction(callFrame->callee());
2127 ExecutableBase* executable = callee->executable();
2128
2129 MacroAssemblerCodePtr codePtr;
2130 CodeBlock* codeBlock = 0;
2131 if (executable->isHostFunction())
2132 codePtr = executable->generatedJITCodeForConstruct().addressForCall();
2133 else {
2134 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
2135 JSObject* error = functionExecutable->compileForConstruct(callFrame, callee->scope());
2136 if (error) {
2137 throwStackOverflowError(callFrame, stackFrame.globalData, ReturnAddressPtr(callFrame->returnPC()), STUB_RETURN_ADDRESS);
2138 return 0;
2139 }
2140 codeBlock = &functionExecutable->generatedBytecodeForConstruct();
2141 if (callFrame->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters))
2142 codePtr = functionExecutable->generatedJITCodeForConstruct().addressForCall();
2143 else
2144 codePtr = functionExecutable->generatedJITCodeForConstructWithArityCheck();
2145 }
2146 CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(callFrame->returnPC());
2147
2148 if (!callLinkInfo->seenOnce())
2149 callLinkInfo->setSeen();
2150 else
2151 JIT::linkConstruct(callee, stackFrame.callFrame->callerFrame()->codeBlock(), codeBlock, codePtr, callLinkInfo, callFrame->argumentCountIncludingThis(), stackFrame.globalData);
2152
2153 return codePtr.executableAddress();
2154 }
2155 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
2156
2157 DEFINE_STUB_FUNCTION(JSObject*, op_push_activation)
2158 {
2159 STUB_INIT_STACK_FRAME(stackFrame);
2160
2161 JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable()));
2162 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(activation));
2163 return activation;
2164 }
2165
2166 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction)
2167 {
2168 STUB_INIT_STACK_FRAME(stackFrame);
2169
2170 JSValue funcVal = stackFrame.args[0].jsValue();
2171
2172 CallData callData;
2173 CallType callType = getCallData(funcVal, callData);
2174
2175 ASSERT(callType != CallTypeJS);
2176
2177 if (callType == CallTypeHost) {
2178 int registerOffset = stackFrame.args[1].int32();
2179 int argCount = stackFrame.args[2].int32();
2180 CallFrame* previousCallFrame = stackFrame.callFrame;
2181 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
2182 if (!stackFrame.registerFile->grow(callFrame->registers())) {
2183 throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
2184 VM_THROW_EXCEPTION();
2185 }
2186
2187 callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(funcVal));
2188
2189 EncodedJSValue returnValue;
2190 {
2191 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
2192 returnValue = callData.native.function(callFrame);
2193 }
2194
2195 CHECK_FOR_EXCEPTION_AT_END();
2196 return returnValue;
2197 }
2198
2199 ASSERT(callType == CallTypeNone);
2200
2201 stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal);
2202 VM_THROW_EXCEPTION();
2203 }
2204
2205 DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments)
2206 {
2207 STUB_INIT_STACK_FRAME(stackFrame);
2208
2209 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame);
2210 return JSValue::encode(JSValue(arguments));
2211 }
2212
2213 DEFINE_STUB_FUNCTION(EncodedJSValue, op_create_arguments_no_params)
2214 {
2215 STUB_INIT_STACK_FRAME(stackFrame);
2216
2217 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters);
2218 return JSValue::encode(JSValue(arguments));
2219 }
2220
2221 DEFINE_STUB_FUNCTION(void, op_tear_off_activation)
2222 {
2223 STUB_INIT_STACK_FRAME(stackFrame);
2224
2225 ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain());
2226 JSValue activationValue = stackFrame.args[0].jsValue();
2227 if (!activationValue) {
2228 if (JSValue v = stackFrame.args[1].jsValue()) {
2229 if (!stackFrame.callFrame->codeBlock()->isStrictMode())
2230 asArguments(v)->copyRegisters(*stackFrame.globalData);
2231 }
2232 return;
2233 }
2234 JSActivation* activation = asActivation(stackFrame.args[0].jsValue());
2235 activation->copyRegisters(*stackFrame.globalData);
2236 if (JSValue v = stackFrame.args[1].jsValue()) {
2237 if (!stackFrame.callFrame->codeBlock()->isStrictMode())
2238 asArguments(v)->setActivation(*stackFrame.globalData, activation);
2239 }
2240 }
2241
2242 DEFINE_STUB_FUNCTION(void, op_tear_off_arguments)
2243 {
2244 STUB_INIT_STACK_FRAME(stackFrame);
2245
2246 ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain());
2247 asArguments(stackFrame.args[0].jsValue())->copyRegisters(*stackFrame.globalData);
2248 }
2249
2250 DEFINE_STUB_FUNCTION(void, op_profile_will_call)
2251 {
2252 STUB_INIT_STACK_FRAME(stackFrame);
2253
2254 ASSERT(*stackFrame.enabledProfilerReference);
2255 (*stackFrame.enabledProfilerReference)->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
2256 }
2257
2258 DEFINE_STUB_FUNCTION(void, op_profile_did_call)
2259 {
2260 STUB_INIT_STACK_FRAME(stackFrame);
2261
2262 ASSERT(*stackFrame.enabledProfilerReference);
2263 (*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
2264 }
2265
2266 DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
2267 {
2268 STUB_INIT_STACK_FRAME(stackFrame);
2269
2270 ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
2271 return constructArray(stackFrame.callFrame, argList);
2272 }
2273
2274 DEFINE_STUB_FUNCTION(JSObject*, op_new_array_buffer)
2275 {
2276 STUB_INIT_STACK_FRAME(stackFrame);
2277
2278 ArgList argList(stackFrame.callFrame->codeBlock()->constantBuffer(stackFrame.args[0].int32()), stackFrame.args[1].int32());
2279 return constructArray(stackFrame.callFrame, argList);
2280 }
2281
2282 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
2283 {
2284 STUB_INIT_STACK_FRAME(stackFrame);
2285
2286 CallFrame* callFrame = stackFrame.callFrame;
2287 ScopeChainNode* scopeChain = callFrame->scopeChain();
2288
2289 ScopeChainIterator iter = scopeChain->begin();
2290 ScopeChainIterator end = scopeChain->end();
2291 ASSERT(iter != end);
2292
2293 Identifier& ident = stackFrame.args[0].identifier();
2294 do {
2295 JSObject* o = iter->get();
2296 PropertySlot slot(o);
2297 if (o->getPropertySlot(callFrame, ident, slot)) {
2298 JSValue result = slot.getValue(callFrame, ident);
2299 CHECK_FOR_EXCEPTION_AT_END();
2300 return JSValue::encode(result);
2301 }
2302 } while (++iter != end);
2303
2304 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
2305 VM_THROW_EXCEPTION();
2306 }
2307
2308 DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
2309 {
2310 STUB_INIT_STACK_FRAME(stackFrame);
2311
2312 JSValue constrVal = stackFrame.args[0].jsValue();
2313
2314 ConstructData constructData;
2315 ConstructType constructType = getConstructData(constrVal, constructData);
2316
2317 ASSERT(constructType != ConstructTypeJS);
2318
2319 if (constructType == ConstructTypeHost) {
2320 int registerOffset = stackFrame.args[1].int32();
2321 int argCount = stackFrame.args[2].int32();
2322 CallFrame* previousCallFrame = stackFrame.callFrame;
2323 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
2324 if (!stackFrame.registerFile->grow(callFrame->registers())) {
2325 throwStackOverflowError(previousCallFrame, stackFrame.globalData, callFrame->returnPC(), STUB_RETURN_ADDRESS);
2326 VM_THROW_EXCEPTION();
2327 }
2328
2329 callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, argCount, asObject(constrVal));
2330
2331 EncodedJSValue returnValue;
2332 {
2333 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
2334 returnValue = constructData.native.function(callFrame);
2335 }
2336
2337 CHECK_FOR_EXCEPTION_AT_END();
2338 return returnValue;
2339 }
2340
2341 ASSERT(constructType == ConstructTypeNone);
2342
2343 stackFrame.globalData->exception = createNotAConstructorError(stackFrame.callFrame, constrVal);
2344 VM_THROW_EXCEPTION();
2345 }
2346
2347 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val)
2348 {
2349 STUB_INIT_STACK_FRAME(stackFrame);
2350
2351 CallFrame* callFrame = stackFrame.callFrame;
2352 JSGlobalData* globalData = stackFrame.globalData;
2353
2354 JSValue baseValue = stackFrame.args[0].jsValue();
2355 JSValue subscript = stackFrame.args[1].jsValue();
2356
2357 if (LIKELY(baseValue.isCell() && subscript.isString())) {
2358 Identifier propertyName(callFrame, asString(subscript)->value(callFrame));
2359 PropertySlot slot(baseValue.asCell());
2360 // JSString::value may have thrown, but we shouldn't find a property with a null identifier,
2361 // so we should miss this case and wind up in the CHECK_FOR_EXCEPTION_AT_END, below.
2362 if (baseValue.asCell()->fastGetOwnPropertySlot(callFrame, propertyName, slot)) {
2363 JSValue result = slot.getValue(callFrame, propertyName);
2364 CHECK_FOR_EXCEPTION();
2365 return JSValue::encode(result);
2366 }
2367 }
2368
2369 if (subscript.isUInt32()) {
2370 uint32_t i = subscript.asUInt32();
2371 if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) {
2372 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string));
2373 JSValue result = asString(baseValue)->getIndex(callFrame, i);
2374 CHECK_FOR_EXCEPTION();
2375 return JSValue::encode(result);
2376 }
2377 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2378 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2379 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array));
2380 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i));
2381 }
2382 JSValue result = baseValue.get(callFrame, i);
2383 CHECK_FOR_EXCEPTION();
2384 return JSValue::encode(result);
2385 }
2386
2387 Identifier property(callFrame, subscript.toString(callFrame));
2388 JSValue result = baseValue.get(callFrame, property);
2389 CHECK_FOR_EXCEPTION_AT_END();
2390 return JSValue::encode(result);
2391 }
2392
2393 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string)
2394 {
2395 STUB_INIT_STACK_FRAME(stackFrame);
2396
2397 CallFrame* callFrame = stackFrame.callFrame;
2398 JSGlobalData* globalData = stackFrame.globalData;
2399
2400 JSValue baseValue = stackFrame.args[0].jsValue();
2401 JSValue subscript = stackFrame.args[1].jsValue();
2402
2403 JSValue result;
2404
2405 if (LIKELY(subscript.isUInt32())) {
2406 uint32_t i = subscript.asUInt32();
2407 if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
2408 result = asString(baseValue)->getIndex(callFrame, i);
2409 else {
2410 result = baseValue.get(callFrame, i);
2411 if (!isJSString(globalData, baseValue))
2412 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val));
2413 }
2414 } else {
2415 Identifier property(callFrame, subscript.toString(callFrame));
2416 result = baseValue.get(callFrame, property);
2417 }
2418
2419 CHECK_FOR_EXCEPTION_AT_END();
2420 return JSValue::encode(result);
2421 }
2422
2423 DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array)
2424 {
2425 STUB_INIT_STACK_FRAME(stackFrame);
2426
2427 CallFrame* callFrame = stackFrame.callFrame;
2428 JSGlobalData* globalData = stackFrame.globalData;
2429
2430 JSValue baseValue = stackFrame.args[0].jsValue();
2431 JSValue subscript = stackFrame.args[1].jsValue();
2432
2433 JSValue result;
2434
2435 if (LIKELY(subscript.isUInt32())) {
2436 uint32_t i = subscript.asUInt32();
2437 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2438 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2439 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i));
2440 }
2441
2442 result = baseValue.get(callFrame, i);
2443 if (!isJSByteArray(globalData, baseValue))
2444 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val));
2445 } else {
2446 Identifier property(callFrame, subscript.toString(callFrame));
2447 result = baseValue.get(callFrame, property);
2448 }
2449
2450 CHECK_FOR_EXCEPTION_AT_END();
2451 return JSValue::encode(result);
2452 }
2453
2454 DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub)
2455 {
2456 STUB_INIT_STACK_FRAME(stackFrame);
2457
2458 JSValue src1 = stackFrame.args[0].jsValue();
2459 JSValue src2 = stackFrame.args[1].jsValue();
2460
2461 double left;
2462 double right;
2463 if (src1.getNumber(left) && src2.getNumber(right))
2464 return JSValue::encode(jsNumber(left - right));
2465
2466 CallFrame* callFrame = stackFrame.callFrame;
2467 JSValue result = jsNumber(src1.toNumber(callFrame) - src2.toNumber(callFrame));
2468 CHECK_FOR_EXCEPTION_AT_END();
2469 return JSValue::encode(result);
2470 }
2471
2472 DEFINE_STUB_FUNCTION(void, op_put_by_val)
2473 {
2474 STUB_INIT_STACK_FRAME(stackFrame);
2475
2476 CallFrame* callFrame = stackFrame.callFrame;
2477 JSGlobalData* globalData = stackFrame.globalData;
2478
2479 JSValue baseValue = stackFrame.args[0].jsValue();
2480 JSValue subscript = stackFrame.args[1].jsValue();
2481 JSValue value = stackFrame.args[2].jsValue();
2482
2483 if (LIKELY(subscript.isUInt32())) {
2484 uint32_t i = subscript.asUInt32();
2485 if (isJSArray(globalData, baseValue)) {
2486 JSArray* jsArray = asArray(baseValue);
2487 if (jsArray->canSetIndex(i))
2488 jsArray->setIndex(*globalData, i, value);
2489 else
2490 jsArray->JSArray::put(callFrame, i, value);
2491 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2492 JSByteArray* jsByteArray = asByteArray(baseValue);
2493 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array));
2494 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2495 if (value.isInt32()) {
2496 jsByteArray->setIndex(i, value.asInt32());
2497 return;
2498 } else {
2499 double dValue = 0;
2500 if (value.getNumber(dValue)) {
2501 jsByteArray->setIndex(i, dValue);
2502 return;
2503 }
2504 }
2505
2506 baseValue.put(callFrame, i, value);
2507 } else
2508 baseValue.put(callFrame, i, value);
2509 } else {
2510 Identifier property(callFrame, subscript.toString(callFrame));
2511 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
2512 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
2513 baseValue.put(callFrame, property, value, slot);
2514 }
2515 }
2516
2517 CHECK_FOR_EXCEPTION_AT_END();
2518 }
2519
2520 DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array)
2521 {
2522 STUB_INIT_STACK_FRAME(stackFrame);
2523
2524 CallFrame* callFrame = stackFrame.callFrame;
2525 JSGlobalData* globalData = stackFrame.globalData;
2526
2527 JSValue baseValue = stackFrame.args[0].jsValue();
2528 JSValue subscript = stackFrame.args[1].jsValue();
2529 JSValue value = stackFrame.args[2].jsValue();
2530
2531 if (LIKELY(subscript.isUInt32())) {
2532 uint32_t i = subscript.asUInt32();
2533 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
2534 JSByteArray* jsByteArray = asByteArray(baseValue);
2535
2536 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
2537 if (value.isInt32()) {
2538 jsByteArray->setIndex(i, value.asInt32());
2539 return;
2540 } else {
2541 double dValue = 0;
2542 if (value.getNumber(dValue)) {
2543 jsByteArray->setIndex(i, dValue);
2544 return;
2545 }
2546 }
2547 }
2548
2549 if (!isJSByteArray(globalData, baseValue))
2550 ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val));
2551 baseValue.put(callFrame, i, value);
2552 } else {
2553 Identifier property(callFrame, subscript.toString(callFrame));
2554 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
2555 PutPropertySlot slot(callFrame->codeBlock()->isStrictMode());
2556 baseValue.put(callFrame, property, value, slot);
2557 }
2558 }
2559
2560 CHECK_FOR_EXCEPTION_AT_END();
2561 }
2562
2563 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lesseq)
2564 {
2565 STUB_INIT_STACK_FRAME(stackFrame);
2566
2567 CallFrame* callFrame = stackFrame.callFrame;
2568 JSValue result = jsBoolean(jsLessEq(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue()));
2569 CHECK_FOR_EXCEPTION_AT_END();
2570 return JSValue::encode(result);
2571 }
2572
2573 DEFINE_STUB_FUNCTION(int, op_load_varargs)
2574 {
2575 STUB_INIT_STACK_FRAME(stackFrame);
2576
2577 CallFrame* callFrame = stackFrame.callFrame;
2578 RegisterFile* registerFile = stackFrame.registerFile;
2579 int argsOffset = stackFrame.args[0].int32();
2580 JSValue arguments = callFrame->registers()[argsOffset].jsValue();
2581 uint32_t argCount = 0;
2582 if (!arguments) {
2583 int providedParams = callFrame->registers()[RegisterFile::ArgumentCount].i() - 1;
2584 argCount = providedParams;
2585 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2586 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2587 Register* newEnd = callFrame->registers() + sizeDelta;
2588 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2589 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2590 VM_THROW_EXCEPTION();
2591 }
2592 int32_t expectedParams = asFunction(callFrame->callee())->jsExecutable()->parameterCount();
2593 int32_t inplaceArgs = min(providedParams, expectedParams);
2594
2595 Register* inplaceArgsDst = callFrame->registers() + argsOffset;
2596
2597 Register* inplaceArgsEnd = inplaceArgsDst + inplaceArgs;
2598 Register* inplaceArgsEnd2 = inplaceArgsDst + providedParams;
2599
2600 Register* inplaceArgsSrc = callFrame->registers() - RegisterFile::CallFrameHeaderSize - expectedParams;
2601 Register* inplaceArgsSrc2 = inplaceArgsSrc - providedParams - 1 + inplaceArgs;
2602
2603 // First step is to copy the "expected" parameters from their normal location relative to the callframe
2604 while (inplaceArgsDst < inplaceArgsEnd)
2605 *inplaceArgsDst++ = *inplaceArgsSrc++;
2606
2607 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
2608 while (inplaceArgsDst < inplaceArgsEnd2)
2609 *inplaceArgsDst++ = *inplaceArgsSrc2++;
2610
2611 } else if (!arguments.isUndefinedOrNull()) {
2612 if (!arguments.isObject()) {
2613 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
2614 VM_THROW_EXCEPTION();
2615 }
2616 if (asObject(arguments)->classInfo() == &Arguments::s_info) {
2617 Arguments* argsObject = asArguments(arguments);
2618 argCount = argsObject->numProvidedArguments(callFrame);
2619 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2620 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2621 Register* newEnd = callFrame->registers() + sizeDelta;
2622 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2623 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2624 VM_THROW_EXCEPTION();
2625 }
2626 argsObject->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
2627 } else if (isJSArray(&callFrame->globalData(), arguments)) {
2628 JSArray* array = asArray(arguments);
2629 argCount = array->length();
2630 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2631 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2632 Register* newEnd = callFrame->registers() + sizeDelta;
2633 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2634 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2635 VM_THROW_EXCEPTION();
2636 }
2637 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
2638 } else if (asObject(arguments)->inherits(&JSArray::s_info)) {
2639 JSObject* argObject = asObject(arguments);
2640 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
2641 argCount = min(argCount, static_cast<uint32_t>(Arguments::MaxArguments));
2642 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
2643 Register* newEnd = callFrame->registers() + sizeDelta;
2644 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
2645 stackFrame.globalData->exception = createStackOverflowError(callFrame);
2646 VM_THROW_EXCEPTION();
2647 }
2648 Register* argsBuffer = callFrame->registers() + argsOffset;
2649 for (unsigned i = 0; i < argCount; ++i) {
2650 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
2651 CHECK_FOR_EXCEPTION();
2652 }
2653 } else {
2654 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments);
2655 VM_THROW_EXCEPTION();
2656 }
2657 }
2658
2659 return argCount + 1;
2660 }
2661
2662 DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate)
2663 {
2664 STUB_INIT_STACK_FRAME(stackFrame);
2665
2666 JSValue src = stackFrame.args[0].jsValue();
2667
2668 double v;
2669 if (src.getNumber(v))
2670 return JSValue::encode(jsNumber(-v));
2671
2672 CallFrame* callFrame = stackFrame.callFrame;
2673 JSValue result = jsNumber(-src.toNumber(callFrame));
2674 CHECK_FOR_EXCEPTION_AT_END();
2675 return JSValue::encode(result);
2676 }
2677
2678 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base)
2679 {
2680 STUB_INIT_STACK_FRAME(stackFrame);
2681
2682 return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), false));
2683 }
2684
2685 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base_strict_put)
2686 {
2687 STUB_INIT_STACK_FRAME(stackFrame);
2688 JSValue base = JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain(), true);
2689 if (!base) {
2690 stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[0].identifier().ustring());
2691 VM_THROW_EXCEPTION();
2692 }
2693 return JSValue::encode(base);
2694 }
2695
2696 DEFINE_STUB_FUNCTION(EncodedJSValue, op_ensure_property_exists)
2697 {
2698 STUB_INIT_STACK_FRAME(stackFrame);
2699 JSValue base = stackFrame.callFrame->r(stackFrame.args[0].int32()).jsValue();
2700 JSObject* object = asObject(base);
2701 PropertySlot slot(object);
2702 ASSERT(stackFrame.callFrame->codeBlock()->isStrictMode());
2703 if (!object->getPropertySlot(stackFrame.callFrame, stackFrame.args[1].identifier(), slot)) {
2704 stackFrame.globalData->exception = createErrorForInvalidGlobalAssignment(stackFrame.callFrame, stackFrame.args[1].identifier().ustring());
2705 VM_THROW_EXCEPTION();
2706 }
2707
2708 return JSValue::encode(base);
2709 }
2710
2711 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip)
2712 {
2713 STUB_INIT_STACK_FRAME(stackFrame);
2714
2715 CallFrame* callFrame = stackFrame.callFrame;
2716 ScopeChainNode* scopeChain = callFrame->scopeChain();
2717
2718 int skip = stackFrame.args[1].int32();
2719
2720 ScopeChainIterator iter = scopeChain->begin();
2721 ScopeChainIterator end = scopeChain->end();
2722 ASSERT(iter != end);
2723 CodeBlock* codeBlock = callFrame->codeBlock();
2724 bool checkTopLevel = codeBlock->codeType() == FunctionCode && codeBlock->needsFullScopeChain();
2725 ASSERT(skip || !checkTopLevel);
2726 if (checkTopLevel && skip--) {
2727 if (callFrame->uncheckedR(codeBlock->activationRegister()).jsValue())
2728 ++iter;
2729 }
2730 while (skip--) {
2731 ++iter;
2732 ASSERT(iter != end);
2733 }
2734 Identifier& ident = stackFrame.args[0].identifier();
2735 do {
2736 JSObject* o = iter->get();
2737 PropertySlot slot(o);
2738 if (o->getPropertySlot(callFrame, ident, slot)) {
2739 JSValue result = slot.getValue(callFrame, ident);
2740 CHECK_FOR_EXCEPTION_AT_END();
2741 return JSValue::encode(result);
2742 }
2743 } while (++iter != end);
2744
2745 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
2746 VM_THROW_EXCEPTION();
2747 }
2748
2749 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
2750 {
2751 STUB_INIT_STACK_FRAME(stackFrame);
2752
2753 CallFrame* callFrame = stackFrame.callFrame;
2754 CodeBlock* codeBlock = callFrame->codeBlock();
2755 JSGlobalObject* globalObject = codeBlock->globalObject();
2756 Identifier& ident = stackFrame.args[0].identifier();
2757 unsigned globalResolveInfoIndex = stackFrame.args[1].int32();
2758 ASSERT(globalObject->isGlobalObject());
2759
2760 PropertySlot slot(globalObject);
2761 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
2762 JSValue result = slot.getValue(callFrame, ident);
2763 if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
2764 GlobalResolveInfo& globalResolveInfo = codeBlock->globalResolveInfo(globalResolveInfoIndex);
2765 globalResolveInfo.structure.set(callFrame->globalData(), codeBlock->ownerExecutable(), globalObject->structure());
2766 globalResolveInfo.offset = slot.cachedOffset();
2767 return JSValue::encode(result);
2768 }
2769
2770 CHECK_FOR_EXCEPTION_AT_END();
2771 return JSValue::encode(result);
2772 }
2773
2774 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
2775 VM_THROW_EXCEPTION();
2776 }
2777
2778 DEFINE_STUB_FUNCTION(EncodedJSValue, op_div)
2779 {
2780 STUB_INIT_STACK_FRAME(stackFrame);
2781
2782 JSValue src1 = stackFrame.args[0].jsValue();
2783 JSValue src2 = stackFrame.args[1].jsValue();
2784
2785 double left;
2786 double right;
2787 if (src1.getNumber(left) && src2.getNumber(right))
2788 return JSValue::encode(jsNumber(left / right));
2789
2790 CallFrame* callFrame = stackFrame.callFrame;
2791 JSValue result = jsNumber(src1.toNumber(callFrame) / src2.toNumber(callFrame));
2792 CHECK_FOR_EXCEPTION_AT_END();
2793 return JSValue::encode(result);
2794 }
2795
2796 DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec)
2797 {
2798 STUB_INIT_STACK_FRAME(stackFrame);
2799
2800 JSValue v = stackFrame.args[0].jsValue();
2801
2802 CallFrame* callFrame = stackFrame.callFrame;
2803 JSValue result = jsNumber(v.toNumber(callFrame) - 1);
2804 CHECK_FOR_EXCEPTION_AT_END();
2805 return JSValue::encode(result);
2806 }
2807
2808 DEFINE_STUB_FUNCTION(int, op_jless)
2809 {
2810 STUB_INIT_STACK_FRAME(stackFrame);
2811
2812 JSValue src1 = stackFrame.args[0].jsValue();
2813 JSValue src2 = stackFrame.args[1].jsValue();
2814 CallFrame* callFrame = stackFrame.callFrame;
2815
2816 bool result = jsLess(callFrame, src1, src2);
2817 CHECK_FOR_EXCEPTION_AT_END();
2818 return result;
2819 }
2820
2821 DEFINE_STUB_FUNCTION(int, op_jlesseq)
2822 {
2823 STUB_INIT_STACK_FRAME(stackFrame);
2824
2825 JSValue src1 = stackFrame.args[0].jsValue();
2826 JSValue src2 = stackFrame.args[1].jsValue();
2827 CallFrame* callFrame = stackFrame.callFrame;
2828
2829 bool result = jsLessEq(callFrame, src1, src2);
2830 CHECK_FOR_EXCEPTION_AT_END();
2831 return result;
2832 }
2833
2834 DEFINE_STUB_FUNCTION(EncodedJSValue, op_not)
2835 {
2836 STUB_INIT_STACK_FRAME(stackFrame);
2837
2838 JSValue src = stackFrame.args[0].jsValue();
2839
2840 CallFrame* callFrame = stackFrame.callFrame;
2841
2842 JSValue result = jsBoolean(!src.toBoolean(callFrame));
2843 CHECK_FOR_EXCEPTION_AT_END();
2844 return JSValue::encode(result);
2845 }
2846
2847 DEFINE_STUB_FUNCTION(int, op_jtrue)
2848 {
2849 STUB_INIT_STACK_FRAME(stackFrame);
2850
2851 JSValue src1 = stackFrame.args[0].jsValue();
2852
2853 CallFrame* callFrame = stackFrame.callFrame;
2854
2855 bool result = src1.toBoolean(callFrame);
2856 CHECK_FOR_EXCEPTION_AT_END();
2857 return result;
2858 }
2859
2860 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc)
2861 {
2862 STUB_INIT_STACK_FRAME(stackFrame);
2863
2864 JSValue v = stackFrame.args[0].jsValue();
2865
2866 CallFrame* callFrame = stackFrame.callFrame;
2867
2868 JSValue number = v.toJSNumber(callFrame);
2869 CHECK_FOR_EXCEPTION_AT_END();
2870
2871 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() + 1);
2872 return JSValue::encode(number);
2873 }
2874
2875 DEFINE_STUB_FUNCTION(int, op_eq)
2876 {
2877 STUB_INIT_STACK_FRAME(stackFrame);
2878
2879 JSValue src1 = stackFrame.args[0].jsValue();
2880 JSValue src2 = stackFrame.args[1].jsValue();
2881
2882 #if USE(JSVALUE32_64)
2883 start:
2884 if (src2.isUndefined()) {
2885 return src1.isNull() ||
2886 (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined())
2887 || src1.isUndefined();
2888 }
2889
2890 if (src2.isNull()) {
2891 return src1.isUndefined() ||
2892 (src1.isCell() && src1.asCell()->structure()->typeInfo().masqueradesAsUndefined())
2893 || src1.isNull();
2894 }
2895
2896 if (src1.isInt32()) {
2897 if (src2.isDouble())
2898 return src1.asInt32() == src2.asDouble();
2899 double d = src2.toNumber(stackFrame.callFrame);
2900 CHECK_FOR_EXCEPTION();
2901 return src1.asInt32() == d;
2902 }
2903
2904 if (src1.isDouble()) {
2905 if (src2.isInt32())
2906 return src1.asDouble() == src2.asInt32();
2907 double d = src2.toNumber(stackFrame.callFrame);
2908 CHECK_FOR_EXCEPTION();
2909 return src1.asDouble() == d;
2910 }
2911
2912 if (src1.isTrue()) {
2913 if (src2.isFalse())
2914 return false;
2915 double d = src2.toNumber(stackFrame.callFrame);
2916 CHECK_FOR_EXCEPTION();
2917 return d == 1.0;
2918 }
2919
2920 if (src1.isFalse()) {
2921 if (src2.isTrue())
2922 return false;
2923 double d = src2.toNumber(stackFrame.callFrame);
2924 CHECK_FOR_EXCEPTION();
2925 return d == 0.0;
2926 }
2927
2928 if (src1.isUndefined())
2929 return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
2930
2931 if (src1.isNull())
2932 return src2.isCell() && src2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
2933
2934 JSCell* cell1 = src1.asCell();
2935
2936 if (cell1->isString()) {
2937 if (src2.isInt32())
2938 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asInt32();
2939
2940 if (src2.isDouble())
2941 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == src2.asDouble();
2942
2943 if (src2.isTrue())
2944 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 1.0;
2945
2946 if (src2.isFalse())
2947 return jsToNumber(static_cast<JSString*>(cell1)->value(stackFrame.callFrame)) == 0.0;
2948
2949 JSCell* cell2 = src2.asCell();
2950 if (cell2->isString())
2951 return static_cast<JSString*>(cell1)->value(stackFrame.callFrame) == static_cast<JSString*>(cell2)->value(stackFrame.callFrame);
2952
2953 src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame);
2954 CHECK_FOR_EXCEPTION();
2955 goto start;
2956 }
2957
2958 if (src2.isObject())
2959 return asObject(cell1) == asObject(src2);
2960 src1 = asObject(cell1)->toPrimitive(stackFrame.callFrame);
2961 CHECK_FOR_EXCEPTION();
2962 goto start;
2963
2964 #else // USE(JSVALUE32_64)
2965 CallFrame* callFrame = stackFrame.callFrame;
2966
2967 bool result = JSValue::equalSlowCaseInline(callFrame, src1, src2);
2968 CHECK_FOR_EXCEPTION_AT_END();
2969 return result;
2970 #endif // USE(JSVALUE32_64)
2971 }
2972
2973 DEFINE_STUB_FUNCTION(int, op_eq_strings)
2974 {
2975 #if USE(JSVALUE32_64)
2976 STUB_INIT_STACK_FRAME(stackFrame);
2977
2978 JSString* string1 = stackFrame.args[0].jsString();
2979 JSString* string2 = stackFrame.args[1].jsString();
2980
2981 ASSERT(string1->isString());
2982 ASSERT(string2->isString());
2983 return string1->value(stackFrame.callFrame) == string2->value(stackFrame.callFrame);
2984 #else
2985 UNUSED_PARAM(args);
2986 ASSERT_NOT_REACHED();
2987 return 0;
2988 #endif
2989 }
2990
2991 DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift)
2992 {
2993 STUB_INIT_STACK_FRAME(stackFrame);
2994
2995 JSValue val = stackFrame.args[0].jsValue();
2996 JSValue shift = stackFrame.args[1].jsValue();
2997
2998 CallFrame* callFrame = stackFrame.callFrame;
2999 JSValue result = jsNumber((val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
3000 CHECK_FOR_EXCEPTION_AT_END();
3001 return JSValue::encode(result);
3002 }
3003
3004 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand)
3005 {
3006 STUB_INIT_STACK_FRAME(stackFrame);
3007
3008 JSValue src1 = stackFrame.args[0].jsValue();
3009 JSValue src2 = stackFrame.args[1].jsValue();
3010
3011 ASSERT(!src1.isInt32() || !src2.isInt32());
3012 CallFrame* callFrame = stackFrame.callFrame;
3013 JSValue result = jsNumber(src1.toInt32(callFrame) & src2.toInt32(callFrame));
3014 CHECK_FOR_EXCEPTION_AT_END();
3015 return JSValue::encode(result);
3016 }
3017
3018 DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift)
3019 {
3020 STUB_INIT_STACK_FRAME(stackFrame);
3021
3022 JSValue val = stackFrame.args[0].jsValue();
3023 JSValue shift = stackFrame.args[1].jsValue();
3024
3025 CallFrame* callFrame = stackFrame.callFrame;
3026 JSValue result = jsNumber((val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
3027
3028 CHECK_FOR_EXCEPTION_AT_END();
3029 return JSValue::encode(result);
3030 }
3031
3032 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot)
3033 {
3034 STUB_INIT_STACK_FRAME(stackFrame);
3035
3036 JSValue src = stackFrame.args[0].jsValue();
3037
3038 ASSERT(!src.isInt32());
3039 CallFrame* callFrame = stackFrame.callFrame;
3040 JSValue result = jsNumber(~src.toInt32(callFrame));
3041 CHECK_FOR_EXCEPTION_AT_END();
3042 return JSValue::encode(result);
3043 }
3044
3045 DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base)
3046 {
3047 STUB_INIT_STACK_FRAME(stackFrame);
3048
3049 CallFrame* callFrame = stackFrame.callFrame;
3050 ScopeChainNode* scopeChain = callFrame->scopeChain();
3051
3052 ScopeChainIterator iter = scopeChain->begin();
3053 ScopeChainIterator end = scopeChain->end();
3054
3055 // FIXME: add scopeDepthIsZero optimization
3056
3057 ASSERT(iter != end);
3058
3059 Identifier& ident = stackFrame.args[0].identifier();
3060 JSObject* base;
3061 do {
3062 base = iter->get();
3063 PropertySlot slot(base);
3064 if (base->getPropertySlot(callFrame, ident, slot)) {
3065 JSValue result = slot.getValue(callFrame, ident);
3066 CHECK_FOR_EXCEPTION_AT_END();
3067
3068 callFrame->registers()[stackFrame.args[1].int32()] = JSValue(base);
3069 return JSValue::encode(result);
3070 }
3071 ++iter;
3072 } while (iter != end);
3073
3074 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident);
3075 VM_THROW_EXCEPTION_AT_END();
3076 return JSValue::encode(JSValue());
3077 }
3078
3079 DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp)
3080 {
3081 STUB_INIT_STACK_FRAME(stackFrame);
3082 CallFrame* callFrame = stackFrame.callFrame;
3083
3084 FunctionExecutable* function = stackFrame.args[0].function();
3085 JSFunction* func = function->make(callFrame, callFrame->scopeChain());
3086 ASSERT(callFrame->codeBlock()->codeType() != FunctionCode || !callFrame->codeBlock()->needsFullScopeChain() || callFrame->uncheckedR(callFrame->codeBlock()->activationRegister()).jsValue());
3087
3088 /*
3089 The Identifier in a FunctionExpression can be referenced from inside
3090 the FunctionExpression's FunctionBody to allow the function to call
3091 itself recursively. However, unlike in a FunctionDeclaration, the
3092 Identifier in a FunctionExpression cannot be referenced from and
3093 does not affect the scope enclosing the FunctionExpression.
3094 */
3095 if (!function->name().isNull()) {
3096 JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete);
3097 func->setScope(callFrame->globalData(), func->scope()->push(functionScopeObject));
3098 }
3099
3100 return func;
3101 }
3102
3103 DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod)
3104 {
3105 STUB_INIT_STACK_FRAME(stackFrame);
3106
3107 JSValue dividendValue = stackFrame.args[0].jsValue();
3108 JSValue divisorValue = stackFrame.args[1].jsValue();
3109
3110 CallFrame* callFrame = stackFrame.callFrame;
3111 double d = dividendValue.toNumber(callFrame);
3112 JSValue result = jsNumber(fmod(d, divisorValue.toNumber(callFrame)));
3113 CHECK_FOR_EXCEPTION_AT_END();
3114 return JSValue::encode(result);
3115 }
3116
3117 DEFINE_STUB_FUNCTION(EncodedJSValue, op_less)
3118 {
3119 STUB_INIT_STACK_FRAME(stackFrame);
3120
3121 CallFrame* callFrame = stackFrame.callFrame;
3122 JSValue result = jsBoolean(jsLess(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue()));
3123 CHECK_FOR_EXCEPTION_AT_END();
3124 return JSValue::encode(result);
3125 }
3126
3127 DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec)
3128 {
3129 STUB_INIT_STACK_FRAME(stackFrame);
3130
3131 JSValue v = stackFrame.args[0].jsValue();
3132
3133 CallFrame* callFrame = stackFrame.callFrame;
3134
3135 JSValue number = v.toJSNumber(callFrame);
3136 CHECK_FOR_EXCEPTION_AT_END();
3137
3138 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(number.uncheckedGetNumber() - 1);
3139 return JSValue::encode(number);
3140 }
3141
3142 DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift)
3143 {
3144 STUB_INIT_STACK_FRAME(stackFrame);
3145
3146 JSValue val = stackFrame.args[0].jsValue();
3147 JSValue shift = stackFrame.args[1].jsValue();
3148
3149 CallFrame* callFrame = stackFrame.callFrame;
3150 JSValue result = jsNumber((val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
3151 CHECK_FOR_EXCEPTION_AT_END();
3152 return JSValue::encode(result);
3153 }
3154
3155 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor)
3156 {
3157 STUB_INIT_STACK_FRAME(stackFrame);
3158
3159 JSValue src1 = stackFrame.args[0].jsValue();
3160 JSValue src2 = stackFrame.args[1].jsValue();
3161
3162 CallFrame* callFrame = stackFrame.callFrame;
3163
3164 JSValue result = jsNumber(src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
3165 CHECK_FOR_EXCEPTION_AT_END();
3166 return JSValue::encode(result);
3167 }
3168
3169 DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp)
3170 {
3171 STUB_INIT_STACK_FRAME(stackFrame);
3172
3173 CallFrame* callFrame = stackFrame.callFrame;
3174
3175 RegExp* regExp = stackFrame.args[0].regExp();
3176 if (!regExp->isValid()) {
3177 stackFrame.globalData->exception = createSyntaxError(callFrame, "Invalid flags supplied to RegExp constructor.");
3178 VM_THROW_EXCEPTION();
3179 }
3180
3181 return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject(), stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), regExp);
3182 }
3183
3184 DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor)
3185 {
3186 STUB_INIT_STACK_FRAME(stackFrame);
3187
3188 JSValue src1 = stackFrame.args[0].jsValue();
3189 JSValue src2 = stackFrame.args[1].jsValue();
3190
3191 CallFrame* callFrame = stackFrame.callFrame;
3192
3193 JSValue result = jsNumber(src1.toInt32(callFrame) | src2.toInt32(callFrame));
3194 CHECK_FOR_EXCEPTION_AT_END();
3195 return JSValue::encode(result);
3196 }
3197
3198 DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval)
3199 {
3200 STUB_INIT_STACK_FRAME(stackFrame);
3201 ASSERT(stackFrame.callFrame->codeBlock()->codeType() != FunctionCode || !stackFrame.callFrame->codeBlock()->needsFullScopeChain() || stackFrame.callFrame->uncheckedR(stackFrame.callFrame->codeBlock()->activationRegister()).jsValue());
3202
3203 CallFrame* callFrame = stackFrame.callFrame;
3204 RegisterFile* registerFile = stackFrame.registerFile;
3205
3206 Interpreter* interpreter = stackFrame.globalData->interpreter;
3207
3208 JSValue funcVal = stackFrame.args[0].jsValue();
3209 int registerOffset = stackFrame.args[1].int32();
3210 int argCount = stackFrame.args[2].int32();
3211
3212 Register* newCallFrame = callFrame->registers() + registerOffset;
3213 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
3214 JSValue baseValue = argv[0].jsValue();
3215 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject.get();
3216
3217 if (baseValue == globalObject && funcVal == globalObject->evalFunction()) {
3218 JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset);
3219 CHECK_FOR_EXCEPTION_AT_END();
3220 return JSValue::encode(result);
3221 }
3222
3223 return JSValue::encode(JSValue());
3224 }
3225
3226 DEFINE_STUB_FUNCTION(void*, op_throw)
3227 {
3228 STUB_INIT_STACK_FRAME(stackFrame);
3229 ExceptionHandler handler = jitThrow(stackFrame.globalData, stackFrame.callFrame, stackFrame.args[0].jsValue(), STUB_RETURN_ADDRESS);
3230 STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
3231 return handler.callFrame;
3232 }
3233
3234 DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames)
3235 {
3236 STUB_INIT_STACK_FRAME(stackFrame);
3237
3238 CallFrame* callFrame = stackFrame.callFrame;
3239 JSObject* o = stackFrame.args[0].jsObject();
3240 Structure* structure = o->structure();
3241 JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache();
3242 if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame))
3243 jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o);
3244 return jsPropertyNameIterator;
3245 }
3246
3247 DEFINE_STUB_FUNCTION(int, has_property)
3248 {
3249 STUB_INIT_STACK_FRAME(stackFrame);
3250
3251 JSObject* base = stackFrame.args[0].jsObject();
3252 JSString* property = stackFrame.args[1].jsString();
3253 int result = base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value(stackFrame.callFrame)));
3254 CHECK_FOR_EXCEPTION_AT_END();
3255 return result;
3256 }
3257
3258 DEFINE_STUB_FUNCTION(JSObject*, op_push_scope)
3259 {
3260 STUB_INIT_STACK_FRAME(stackFrame);
3261
3262 JSObject* o = stackFrame.args[0].jsValue().toObject(stackFrame.callFrame);
3263 CHECK_FOR_EXCEPTION();
3264 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(o));
3265 return o;
3266 }
3267
3268 DEFINE_STUB_FUNCTION(void, op_pop_scope)
3269 {
3270 STUB_INIT_STACK_FRAME(stackFrame);
3271
3272 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->pop());
3273 }
3274
3275 DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof)
3276 {
3277 STUB_INIT_STACK_FRAME(stackFrame);
3278
3279 return JSValue::encode(jsTypeStringForValue(stackFrame.callFrame, stackFrame.args[0].jsValue()));
3280 }
3281
3282 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_undefined)
3283 {
3284 STUB_INIT_STACK_FRAME(stackFrame);
3285
3286 JSValue v = stackFrame.args[0].jsValue();
3287 return JSValue::encode(jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined()));
3288 }
3289
3290 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_boolean)
3291 {
3292 STUB_INIT_STACK_FRAME(stackFrame);
3293
3294 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isBoolean()));
3295 }
3296
3297 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_number)
3298 {
3299 STUB_INIT_STACK_FRAME(stackFrame);
3300
3301 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isNumber()));
3302 }
3303
3304 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_string)
3305 {
3306 STUB_INIT_STACK_FRAME(stackFrame);
3307
3308 return JSValue::encode(jsBoolean(isJSString(stackFrame.globalData, stackFrame.args[0].jsValue())));
3309 }
3310
3311 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_object)
3312 {
3313 STUB_INIT_STACK_FRAME(stackFrame);
3314
3315 return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame.args[0].jsValue())));
3316 }
3317
3318 DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_function)
3319 {
3320 STUB_INIT_STACK_FRAME(stackFrame);
3321
3322 return JSValue::encode(jsBoolean(jsIsFunctionType(stackFrame.args[0].jsValue())));
3323 }
3324
3325 DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq)
3326 {
3327 STUB_INIT_STACK_FRAME(stackFrame);
3328
3329 JSValue src1 = stackFrame.args[0].jsValue();
3330 JSValue src2 = stackFrame.args[1].jsValue();
3331
3332 bool result = JSValue::strictEqual(stackFrame.callFrame, src1, src2);
3333 CHECK_FOR_EXCEPTION_AT_END();
3334 return JSValue::encode(jsBoolean(result));
3335 }
3336
3337 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive)
3338 {
3339 STUB_INIT_STACK_FRAME(stackFrame);
3340
3341 return JSValue::encode(stackFrame.args[0].jsValue().toPrimitive(stackFrame.callFrame));
3342 }
3343
3344 DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat)
3345 {
3346 STUB_INIT_STACK_FRAME(stackFrame);
3347
3348 JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
3349 CHECK_FOR_EXCEPTION_AT_END();
3350 return JSValue::encode(result);
3351 }
3352
3353 DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq)
3354 {
3355 STUB_INIT_STACK_FRAME(stackFrame);
3356
3357 JSValue src1 = stackFrame.args[0].jsValue();
3358 JSValue src2 = stackFrame.args[1].jsValue();
3359
3360 bool result = !JSValue::strictEqual(stackFrame.callFrame, src1, src2);
3361 CHECK_FOR_EXCEPTION_AT_END();
3362 return JSValue::encode(jsBoolean(result));
3363 }
3364
3365 DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber)
3366 {
3367 STUB_INIT_STACK_FRAME(stackFrame);
3368
3369 JSValue src = stackFrame.args[0].jsValue();
3370 CallFrame* callFrame = stackFrame.callFrame;
3371
3372 JSValue result = src.toJSNumber(callFrame);
3373 CHECK_FOR_EXCEPTION_AT_END();
3374 return JSValue::encode(result);
3375 }
3376
3377 DEFINE_STUB_FUNCTION(EncodedJSValue, op_in)
3378 {
3379 STUB_INIT_STACK_FRAME(stackFrame);
3380
3381 CallFrame* callFrame = stackFrame.callFrame;
3382 JSValue baseVal = stackFrame.args[1].jsValue();
3383
3384 if (!baseVal.isObject()) {
3385 stackFrame.globalData->exception = createInvalidParamError(stackFrame.callFrame, "in", baseVal);
3386 VM_THROW_EXCEPTION();
3387 }
3388
3389 JSValue propName = stackFrame.args[0].jsValue();
3390 JSObject* baseObj = asObject(baseVal);
3391
3392 uint32_t i;
3393 if (propName.getUInt32(i))
3394 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i)));
3395
3396 Identifier property(callFrame, propName.toString(callFrame));
3397 CHECK_FOR_EXCEPTION();
3398 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property)));
3399 }
3400
3401 DEFINE_STUB_FUNCTION(JSObject*, op_push_new_scope)
3402 {
3403 STUB_INIT_STACK_FRAME(stackFrame);
3404
3405 JSObject* scope = new (stackFrame.globalData) JSStaticScopeObject(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].jsValue(), DontDelete);
3406
3407 CallFrame* callFrame = stackFrame.callFrame;
3408 callFrame->setScopeChain(callFrame->scopeChain()->push(scope));
3409 return scope;
3410 }
3411
3412 DEFINE_STUB_FUNCTION(void, op_jmp_scopes)
3413 {
3414 STUB_INIT_STACK_FRAME(stackFrame);
3415
3416 unsigned count = stackFrame.args[0].int32();
3417 CallFrame* callFrame = stackFrame.callFrame;
3418
3419 ScopeChainNode* tmp = callFrame->scopeChain();
3420 while (count--)
3421 tmp = tmp->pop();
3422 callFrame->setScopeChain(tmp);
3423 }
3424
3425 DEFINE_STUB_FUNCTION(void, op_put_by_index)
3426 {
3427 STUB_INIT_STACK_FRAME(stackFrame);
3428
3429 CallFrame* callFrame = stackFrame.callFrame;
3430 unsigned property = stackFrame.args[1].int32();
3431
3432 stackFrame.args[0].jsValue().put(callFrame, property, stackFrame.args[2].jsValue());
3433 }
3434
3435 DEFINE_STUB_FUNCTION(void*, op_switch_imm)
3436 {
3437 STUB_INIT_STACK_FRAME(stackFrame);
3438
3439 JSValue scrutinee = stackFrame.args[0].jsValue();
3440 unsigned tableIndex = stackFrame.args[1].int32();
3441 CallFrame* callFrame = stackFrame.callFrame;
3442 CodeBlock* codeBlock = callFrame->codeBlock();
3443
3444 if (scrutinee.isInt32())
3445 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.asInt32()).executableAddress();
3446 else {
3447 double value;
3448 int32_t intValue;
3449 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
3450 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(intValue).executableAddress();
3451 else
3452 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3453 }
3454 }
3455
3456 DEFINE_STUB_FUNCTION(void*, op_switch_char)
3457 {
3458 STUB_INIT_STACK_FRAME(stackFrame);
3459
3460 JSValue scrutinee = stackFrame.args[0].jsValue();
3461 unsigned tableIndex = stackFrame.args[1].int32();
3462 CallFrame* callFrame = stackFrame.callFrame;
3463 CodeBlock* codeBlock = callFrame->codeBlock();
3464
3465 void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3466
3467 if (scrutinee.isString()) {
3468 StringImpl* value = asString(scrutinee)->value(callFrame).impl();
3469 if (value->length() == 1)
3470 result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->characters()[0]).executableAddress();
3471 }
3472
3473 CHECK_FOR_EXCEPTION_AT_END();
3474 return result;
3475 }
3476
3477 DEFINE_STUB_FUNCTION(void*, op_switch_string)
3478 {
3479 STUB_INIT_STACK_FRAME(stackFrame);
3480
3481 JSValue scrutinee = stackFrame.args[0].jsValue();
3482 unsigned tableIndex = stackFrame.args[1].int32();
3483 CallFrame* callFrame = stackFrame.callFrame;
3484 CodeBlock* codeBlock = callFrame->codeBlock();
3485
3486 void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
3487
3488 if (scrutinee.isString()) {
3489 StringImpl* value = asString(scrutinee)->value(callFrame).impl();
3490 result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress();
3491 }
3492
3493 CHECK_FOR_EXCEPTION_AT_END();
3494 return result;
3495 }
3496
3497 DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val)
3498 {
3499 STUB_INIT_STACK_FRAME(stackFrame);
3500
3501 CallFrame* callFrame = stackFrame.callFrame;
3502
3503 JSValue baseValue = stackFrame.args[0].jsValue();
3504 JSObject* baseObj = baseValue.toObject(callFrame); // may throw
3505
3506 JSValue subscript = stackFrame.args[1].jsValue();
3507 bool result;
3508 uint32_t i;
3509 if (subscript.getUInt32(i))
3510 result = baseObj->deleteProperty(callFrame, i);
3511 else {
3512 CHECK_FOR_EXCEPTION();
3513 Identifier property(callFrame, subscript.toString(callFrame));
3514 CHECK_FOR_EXCEPTION();
3515 result = baseObj->deleteProperty(callFrame, property);
3516 }
3517
3518 if (!result && callFrame->codeBlock()->isStrictMode())
3519 stackFrame.globalData->exception = createTypeError(stackFrame.callFrame, "Unable to delete property.");
3520
3521 CHECK_FOR_EXCEPTION_AT_END();
3522 return JSValue::encode(jsBoolean(result));
3523 }
3524
3525 DEFINE_STUB_FUNCTION(void, op_put_getter)
3526 {
3527 STUB_INIT_STACK_FRAME(stackFrame);
3528
3529 CallFrame* callFrame = stackFrame.callFrame;
3530
3531 ASSERT(stackFrame.args[0].jsValue().isObject());
3532 JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
3533 ASSERT(stackFrame.args[2].jsValue().isObject());
3534 baseObj->defineGetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()));
3535 }
3536
3537 DEFINE_STUB_FUNCTION(void, op_put_setter)
3538 {
3539 STUB_INIT_STACK_FRAME(stackFrame);
3540
3541 CallFrame* callFrame = stackFrame.callFrame;
3542
3543 ASSERT(stackFrame.args[0].jsValue().isObject());
3544 JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
3545 ASSERT(stackFrame.args[2].jsValue().isObject());
3546 baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()));
3547 }
3548
3549 DEFINE_STUB_FUNCTION(void, op_throw_reference_error)
3550 {
3551 STUB_INIT_STACK_FRAME(stackFrame);
3552
3553 CallFrame* callFrame = stackFrame.callFrame;
3554 UString message = stackFrame.args[0].jsValue().toString(callFrame);
3555 stackFrame.globalData->exception = createReferenceError(callFrame, message);
3556 VM_THROW_EXCEPTION_AT_END();
3557 }
3558
3559 DEFINE_STUB_FUNCTION(void, op_debug)
3560 {
3561 STUB_INIT_STACK_FRAME(stackFrame);
3562
3563 CallFrame* callFrame = stackFrame.callFrame;
3564
3565 int debugHookID = stackFrame.args[0].int32();
3566 int firstLine = stackFrame.args[1].int32();
3567 int lastLine = stackFrame.args[2].int32();
3568
3569 stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
3570 }
3571
3572 DEFINE_STUB_FUNCTION(void*, vm_throw)
3573 {
3574 STUB_INIT_STACK_FRAME(stackFrame);
3575 JSGlobalData* globalData = stackFrame.globalData;
3576 ExceptionHandler handler = jitThrow(globalData, stackFrame.callFrame, globalData->exception, globalData->exceptionLocation);
3577 STUB_SET_RETURN_ADDRESS(handler.catchRoutine);
3578 return handler.callFrame;
3579 }
3580
3581 DEFINE_STUB_FUNCTION(EncodedJSValue, to_object)
3582 {
3583 STUB_INIT_STACK_FRAME(stackFrame);
3584
3585 CallFrame* callFrame = stackFrame.callFrame;
3586 return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame));
3587 }
3588
3589 MacroAssemblerCodePtr JITThunks::ctiStub(JSGlobalData* globalData, ThunkGenerator generator)
3590 {
3591 std::pair<CTIStubMap::iterator, bool> entry = m_ctiStubMap.add(generator, MacroAssemblerCodePtr());
3592 if (entry.second)
3593 entry.first->second = generator(globalData, m_executablePool.get());
3594 return entry.first->second;
3595 }
3596
3597 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function)
3598 {
3599 std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Weak<NativeExecutable>());
3600 if (!*entry.first->second)
3601 entry.first->second.set(*globalData, NativeExecutable::create(*globalData, JIT::compileCTINativeCall(globalData, m_executablePool, function), function, ctiNativeConstruct(), callHostFunctionAsConstructor));
3602 return entry.first->second.get();
3603 }
3604
3605 NativeExecutable* JITThunks::hostFunctionStub(JSGlobalData* globalData, NativeFunction function, ThunkGenerator generator)
3606 {
3607 std::pair<HostFunctionStubMap::iterator, bool> entry = m_hostFunctionStubMap->add(function, Weak<NativeExecutable>());
3608 if (!*entry.first->second) {
3609 MacroAssemblerCodePtr code = globalData->canUseJIT() ? generator(globalData, m_executablePool.get()) : MacroAssemblerCodePtr();
3610 entry.first->second.set(*globalData, NativeExecutable::create(*globalData, code, function, ctiNativeConstruct(), callHostFunctionAsConstructor));
3611 }
3612 return entry.first->second.get();
3613 }
3614
3615 void JITThunks::clearHostFunctionStubs()
3616 {
3617 m_hostFunctionStubMap.clear();
3618 }
3619
3620 } // namespace JSC
3621
3622 #endif // ENABLE(JIT)