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