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