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