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