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