]>
Commit | Line | Data |
---|---|---|
14957cd0 A |
1 | /* |
2 | * Copyright (C) 2011 Apple Inc. All rights reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted provided that the following conditions | |
6 | * are met: | |
7 | * 1. Redistributions of source code must retain the above copyright | |
8 | * notice, this list of conditions and the following disclaimer. | |
9 | * 2. Redistributions in binary form must reproduce the above copyright | |
10 | * notice, this list of conditions and the following disclaimer in the | |
11 | * documentation and/or other materials provided with the distribution. | |
12 | * | |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 | */ | |
25 | ||
26 | #include "config.h" | |
27 | #include "DFGOperations.h" | |
28 | ||
93a37866 A |
29 | #include "Arguments.h" |
30 | #include "ButterflyInlines.h" | |
14957cd0 | 31 | #include "CodeBlock.h" |
93a37866 | 32 | #include "CopiedSpaceInlines.h" |
6fe7ccc8 A |
33 | #include "DFGOSRExit.h" |
34 | #include "DFGRepatch.h" | |
93a37866 | 35 | #include "DFGThunks.h" |
6fe7ccc8 A |
36 | #include "HostCallReturnValue.h" |
37 | #include "GetterSetter.h" | |
14957cd0 | 38 | #include "Interpreter.h" |
93a37866 | 39 | #include "JIT.h" |
6fe7ccc8 A |
40 | #include "JITExceptions.h" |
41 | #include "JSActivation.h" | |
93a37866 A |
42 | #include "VM.h" |
43 | #include "JSNameScope.h" | |
44 | #include "NameInstance.h" | |
45 | #include "ObjectConstructor.h" | |
14957cd0 | 46 | #include "Operations.h" |
93a37866 A |
47 | #include "StringConstructor.h" |
48 | #include <wtf/InlineASM.h> | |
49 | ||
50 | #if ENABLE(JIT) | |
51 | ||
52 | #if CPU(MIPS) | |
53 | #if WTF_MIPS_PIC | |
54 | #define LOAD_FUNCTION_TO_T9(function) \ | |
55 | ".set noreorder" "\n" \ | |
56 | ".cpload $25" "\n" \ | |
57 | ".set reorder" "\n" \ | |
58 | "la $t9, " LOCAL_REFERENCE(function) "\n" | |
59 | #else | |
60 | #define LOAD_FUNCTION_TO_T9(function) "" "\n" | |
61 | #endif | |
62 | #endif | |
14957cd0 | 63 | |
6fe7ccc8 A |
64 | #if ENABLE(DFG_JIT) |
65 | ||
93a37866 | 66 | #if COMPILER(GCC) && CPU(X86_64) |
6fe7ccc8 A |
67 | |
68 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \ | |
69 | asm( \ | |
70 | ".globl " SYMBOL_STRING(function) "\n" \ | |
71 | HIDE_SYMBOL(function) "\n" \ | |
72 | SYMBOL_STRING(function) ":" "\n" \ | |
73 | "mov (%rsp), %" STRINGIZE(register) "\n" \ | |
93a37866 | 74 | "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ |
6fe7ccc8 A |
75 | ); |
76 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rsi) | |
77 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx) | |
78 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx) | |
79 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, r8) | |
80 | ||
93a37866 | 81 | #elif COMPILER(GCC) && CPU(X86) |
6fe7ccc8 A |
82 | |
83 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, offset) \ | |
84 | asm( \ | |
85 | ".text" "\n" \ | |
86 | ".globl " SYMBOL_STRING(function) "\n" \ | |
87 | HIDE_SYMBOL(function) "\n" \ | |
88 | SYMBOL_STRING(function) ":" "\n" \ | |
89 | "mov (%esp), %eax\n" \ | |
90 | "mov %eax, " STRINGIZE(offset) "(%esp)\n" \ | |
93a37866 | 91 | "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ |
6fe7ccc8 A |
92 | ); |
93 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 8) | |
94 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 16) | |
95 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 20) | |
96 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 24) | |
97 | ||
93a37866 A |
98 | #elif CPU(ARM64) |
99 | ||
100 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ | |
101 | asm ( \ | |
102 | ".text" "\n" \ | |
103 | ".align 2" "\n" \ | |
104 | ".globl " SYMBOL_STRING(function) "\n" \ | |
105 | HIDE_SYMBOL(function) "\n" \ | |
106 | SYMBOL_STRING(function) ":" "\n" \ | |
107 | "mov x1, lr" "\n" \ | |
108 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
109 | ); | |
110 | ||
111 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ | |
112 | asm ( \ | |
113 | ".text" "\n" \ | |
114 | ".align 2" "\n" \ | |
115 | ".globl " SYMBOL_STRING(function) "\n" \ | |
116 | HIDE_SYMBOL(function) "\n" \ | |
117 | SYMBOL_STRING(function) ":" "\n" \ | |
118 | "mov x3, lr" "\n" \ | |
119 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
120 | ); | |
121 | ||
122 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ | |
123 | asm ( \ | |
124 | ".text" "\n" \ | |
125 | ".align 2" "\n" \ | |
126 | ".globl " SYMBOL_STRING(function) "\n" \ | |
127 | HIDE_SYMBOL(function) "\n" \ | |
128 | SYMBOL_STRING(function) ":" "\n" \ | |
129 | "mov x3, lr" "\n" \ | |
130 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
131 | ); | |
132 | ||
133 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ | |
134 | asm ( \ | |
135 | ".text" "\n" \ | |
136 | ".align 2" "\n" \ | |
137 | ".globl " SYMBOL_STRING(function) "\n" \ | |
138 | HIDE_SYMBOL(function) "\n" \ | |
139 | SYMBOL_STRING(function) ":" "\n" \ | |
140 | "mov x4, lr" "\n" \ | |
141 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
142 | ); | |
143 | ||
6fe7ccc8 A |
144 | #elif COMPILER(GCC) && CPU(ARM_THUMB2) |
145 | ||
146 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ | |
147 | asm ( \ | |
148 | ".text" "\n" \ | |
149 | ".align 2" "\n" \ | |
150 | ".globl " SYMBOL_STRING(function) "\n" \ | |
151 | HIDE_SYMBOL(function) "\n" \ | |
152 | ".thumb" "\n" \ | |
153 | ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ | |
154 | SYMBOL_STRING(function) ":" "\n" \ | |
155 | "mov a2, lr" "\n" \ | |
93a37866 | 156 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ |
6fe7ccc8 A |
157 | ); |
158 | ||
159 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ | |
160 | asm ( \ | |
161 | ".text" "\n" \ | |
162 | ".align 2" "\n" \ | |
163 | ".globl " SYMBOL_STRING(function) "\n" \ | |
164 | HIDE_SYMBOL(function) "\n" \ | |
165 | ".thumb" "\n" \ | |
166 | ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ | |
167 | SYMBOL_STRING(function) ":" "\n" \ | |
168 | "mov a4, lr" "\n" \ | |
93a37866 | 169 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ |
6fe7ccc8 A |
170 | ); |
171 | ||
93a37866 A |
172 | // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). |
173 | // As a result, return address will be at a 4-byte further location in the following cases. | |
174 | #if COMPILER_SUPPORTS(EABI) && CPU(ARM) | |
175 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #4]" | |
176 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #8]" | |
177 | #else | |
178 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #0]" | |
179 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #4]" | |
180 | #endif | |
181 | ||
6fe7ccc8 A |
182 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ |
183 | asm ( \ | |
184 | ".text" "\n" \ | |
185 | ".align 2" "\n" \ | |
186 | ".globl " SYMBOL_STRING(function) "\n" \ | |
187 | HIDE_SYMBOL(function) "\n" \ | |
188 | ".thumb" "\n" \ | |
189 | ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ | |
190 | SYMBOL_STRING(function) ":" "\n" \ | |
93a37866 A |
191 | INSTRUCTION_STORE_RETURN_ADDRESS_EJI "\n" \ |
192 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
6fe7ccc8 A |
193 | ); |
194 | ||
195 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ | |
196 | asm ( \ | |
197 | ".text" "\n" \ | |
198 | ".align 2" "\n" \ | |
199 | ".globl " SYMBOL_STRING(function) "\n" \ | |
200 | HIDE_SYMBOL(function) "\n" \ | |
201 | ".thumb" "\n" \ | |
202 | ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ | |
203 | SYMBOL_STRING(function) ":" "\n" \ | |
93a37866 A |
204 | INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "\n" \ |
205 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
206 | ); | |
207 | ||
208 | #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) | |
209 | ||
210 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ | |
211 | asm ( \ | |
212 | ".text" "\n" \ | |
213 | ".globl " SYMBOL_STRING(function) "\n" \ | |
214 | HIDE_SYMBOL(function) "\n" \ | |
215 | INLINE_ARM_FUNCTION(function) \ | |
216 | SYMBOL_STRING(function) ":" "\n" \ | |
217 | "mov a2, lr" "\n" \ | |
218 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
219 | ); | |
220 | ||
221 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ | |
222 | asm ( \ | |
223 | ".text" "\n" \ | |
224 | ".globl " SYMBOL_STRING(function) "\n" \ | |
225 | HIDE_SYMBOL(function) "\n" \ | |
226 | INLINE_ARM_FUNCTION(function) \ | |
227 | SYMBOL_STRING(function) ":" "\n" \ | |
228 | "mov a4, lr" "\n" \ | |
229 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
230 | ); | |
231 | ||
232 | // EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). | |
233 | // As a result, return address will be at a 4-byte further location in the following cases. | |
234 | #if COMPILER_SUPPORTS(EABI) && CPU(ARM) | |
235 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #4]" | |
236 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #8]" | |
237 | #else | |
238 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #0]" | |
239 | #define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #4]" | |
240 | #endif | |
241 | ||
242 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ | |
243 | asm ( \ | |
244 | ".text" "\n" \ | |
245 | ".globl " SYMBOL_STRING(function) "\n" \ | |
246 | HIDE_SYMBOL(function) "\n" \ | |
247 | INLINE_ARM_FUNCTION(function) \ | |
248 | SYMBOL_STRING(function) ":" "\n" \ | |
249 | INSTRUCTION_STORE_RETURN_ADDRESS_EJI "\n" \ | |
250 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
251 | ); | |
252 | ||
253 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ | |
254 | asm ( \ | |
255 | ".text" "\n" \ | |
256 | ".globl " SYMBOL_STRING(function) "\n" \ | |
257 | HIDE_SYMBOL(function) "\n" \ | |
258 | INLINE_ARM_FUNCTION(function) \ | |
259 | SYMBOL_STRING(function) ":" "\n" \ | |
260 | INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "\n" \ | |
261 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
262 | ); | |
263 | ||
264 | #elif COMPILER(GCC) && CPU(MIPS) | |
265 | ||
266 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ | |
267 | asm( \ | |
268 | ".text" "\n" \ | |
269 | ".globl " SYMBOL_STRING(function) "\n" \ | |
270 | HIDE_SYMBOL(function) "\n" \ | |
271 | SYMBOL_STRING(function) ":" "\n" \ | |
272 | LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ | |
273 | "move $a1, $ra" "\n" \ | |
274 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
275 | ); | |
276 | ||
277 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ | |
278 | asm( \ | |
279 | ".text" "\n" \ | |
280 | ".globl " SYMBOL_STRING(function) "\n" \ | |
281 | HIDE_SYMBOL(function) "\n" \ | |
282 | SYMBOL_STRING(function) ":" "\n" \ | |
283 | LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ | |
284 | "move $a3, $ra" "\n" \ | |
285 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
286 | ); | |
287 | ||
288 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ | |
289 | asm( \ | |
290 | ".text" "\n" \ | |
291 | ".globl " SYMBOL_STRING(function) "\n" \ | |
292 | HIDE_SYMBOL(function) "\n" \ | |
293 | SYMBOL_STRING(function) ":" "\n" \ | |
294 | LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ | |
295 | "sw $ra, 20($sp)" "\n" \ | |
296 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
297 | ); | |
298 | ||
299 | #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ | |
300 | asm( \ | |
301 | ".text" "\n" \ | |
302 | ".globl " SYMBOL_STRING(function) "\n" \ | |
303 | HIDE_SYMBOL(function) "\n" \ | |
304 | SYMBOL_STRING(function) ":" "\n" \ | |
305 | LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ | |
306 | "sw $ra, 24($sp)" "\n" \ | |
307 | "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ | |
6fe7ccc8 A |
308 | ); |
309 | ||
310 | #endif | |
311 | ||
312 | #define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ | |
93a37866 | 313 | void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ |
6fe7ccc8 A |
314 | FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) |
315 | ||
316 | #define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ | |
93a37866 | 317 | EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ |
6fe7ccc8 A |
318 | FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) |
319 | ||
320 | #define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ | |
93a37866 | 321 | EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ |
6fe7ccc8 A |
322 | FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) |
323 | ||
324 | #define V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ | |
93a37866 | 325 | void DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ |
6fe7ccc8 A |
326 | FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) |
327 | ||
14957cd0 A |
328 | namespace JSC { namespace DFG { |
329 | ||
6fe7ccc8 A |
330 | template<bool strict> |
331 | static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value) | |
332 | { | |
93a37866 A |
333 | VM& vm = exec->vm(); |
334 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 | 335 | |
93a37866 A |
336 | if (baseValue.isObject()) { |
337 | JSObject* object = asObject(baseValue); | |
338 | if (object->canSetIndexQuickly(index)) { | |
339 | object->setIndexQuickly(vm, index, value); | |
6fe7ccc8 A |
340 | return; |
341 | } | |
342 | ||
93a37866 | 343 | object->methodTable()->putByIndex(object, exec, index, value, strict); |
6fe7ccc8 A |
344 | return; |
345 | } | |
346 | ||
347 | baseValue.putByIndex(exec, index, value, strict); | |
348 | } | |
349 | ||
350 | template<bool strict> | |
351 | ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) | |
14957cd0 | 352 | { |
93a37866 A |
353 | VM* vm = &exec->vm(); |
354 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
355 | |
356 | JSValue baseValue = JSValue::decode(encodedBase); | |
357 | JSValue property = JSValue::decode(encodedProperty); | |
358 | JSValue value = JSValue::decode(encodedValue); | |
359 | ||
360 | if (LIKELY(property.isUInt32())) { | |
361 | putByVal<strict>(exec, baseValue, property.asUInt32(), value); | |
362 | return; | |
363 | } | |
364 | ||
365 | if (property.isDouble()) { | |
366 | double propertyAsDouble = property.asDouble(); | |
367 | uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); | |
368 | if (propertyAsDouble == propertyAsUInt32) { | |
369 | putByVal<strict>(exec, baseValue, propertyAsUInt32, value); | |
370 | return; | |
371 | } | |
372 | } | |
373 | ||
93a37866 A |
374 | if (isName(property)) { |
375 | PutPropertySlot slot(strict); | |
376 | baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot); | |
377 | return; | |
378 | } | |
6fe7ccc8 A |
379 | |
380 | // Don't put to an object if toString throws an exception. | |
381 | Identifier ident(exec, property.toString(exec)->value(exec)); | |
93a37866 | 382 | if (!vm->exception) { |
6fe7ccc8 A |
383 | PutPropertySlot slot(strict); |
384 | baseValue.put(exec, ident, value, slot); | |
385 | } | |
386 | } | |
387 | ||
388 | extern "C" { | |
389 | ||
390 | EncodedJSValue DFG_OPERATION operationConvertThis(ExecState* exec, EncodedJSValue encodedOp) | |
391 | { | |
93a37866 A |
392 | VM* vm = &exec->vm(); |
393 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 394 | |
14957cd0 A |
395 | return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec)); |
396 | } | |
397 | ||
93a37866 | 398 | JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, int32_t inlineCapacity) |
14957cd0 | 399 | { |
93a37866 A |
400 | VM* vm = &exec->vm(); |
401 | NativeCallFrameTracer tracer(vm, exec); | |
402 | ||
6fe7ccc8 A |
403 | #if !ASSERT_DISABLED |
404 | ConstructData constructData; | |
93a37866 | 405 | ASSERT(jsCast<JSFunction*>(constructor)->methodTable()->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS); |
6fe7ccc8 A |
406 | #endif |
407 | ||
93a37866 | 408 | return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->allocationProfile(exec, inlineCapacity)->structure()); |
6fe7ccc8 A |
409 | } |
410 | ||
93a37866 | 411 | JSCell* DFG_OPERATION operationNewObject(ExecState* exec, Structure* structure) |
6fe7ccc8 | 412 | { |
93a37866 A |
413 | VM* vm = &exec->vm(); |
414 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 415 | |
93a37866 | 416 | return constructEmptyObject(exec, structure); |
6fe7ccc8 A |
417 | } |
418 | ||
419 | EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) | |
420 | { | |
93a37866 A |
421 | VM* vm = &exec->vm(); |
422 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 423 | |
14957cd0 A |
424 | JSValue op1 = JSValue::decode(encodedOp1); |
425 | JSValue op2 = JSValue::decode(encodedOp2); | |
6fe7ccc8 A |
426 | |
427 | return JSValue::encode(jsAdd(exec, op1, op2)); | |
428 | } | |
14957cd0 | 429 | |
6fe7ccc8 A |
430 | EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
431 | { | |
93a37866 A |
432 | VM* vm = &exec->vm(); |
433 | NativeCallFrameTracer tracer(vm, exec); | |
14957cd0 | 434 | |
6fe7ccc8 A |
435 | JSValue op1 = JSValue::decode(encodedOp1); |
436 | JSValue op2 = JSValue::decode(encodedOp2); | |
437 | ||
438 | ASSERT(!op1.isNumber() || !op2.isNumber()); | |
439 | ||
440 | if (op1.isString() && !op2.isObject()) | |
441 | return JSValue::encode(jsString(exec, asString(op1), op2.toString(exec))); | |
14957cd0 A |
442 | |
443 | return JSValue::encode(jsAddSlowCase(exec, op1, op2)); | |
444 | } | |
445 | ||
6fe7ccc8 A |
446 | static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index) |
447 | { | |
93a37866 A |
448 | VM& vm = exec->vm(); |
449 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 | 450 | |
93a37866 A |
451 | if (base->isObject()) { |
452 | JSObject* object = asObject(base); | |
453 | if (object->canGetIndexQuickly(index)) | |
454 | return JSValue::encode(object->getIndexQuickly(index)); | |
455 | } | |
6fe7ccc8 | 456 | |
6fe7ccc8 A |
457 | if (isJSString(base) && asString(base)->canGetIndex(index)) |
458 | return JSValue::encode(asString(base)->getIndex(exec, index)); | |
459 | ||
460 | return JSValue::encode(JSValue(base).get(exec, index)); | |
461 | } | |
462 | ||
463 | EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) | |
14957cd0 | 464 | { |
93a37866 A |
465 | VM* vm = &exec->vm(); |
466 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 467 | |
14957cd0 A |
468 | JSValue baseValue = JSValue::decode(encodedBase); |
469 | JSValue property = JSValue::decode(encodedProperty); | |
470 | ||
471 | if (LIKELY(baseValue.isCell())) { | |
472 | JSCell* base = baseValue.asCell(); | |
473 | ||
474 | if (property.isUInt32()) { | |
6fe7ccc8 A |
475 | return getByVal(exec, base, property.asUInt32()); |
476 | } else if (property.isDouble()) { | |
477 | double propertyAsDouble = property.asDouble(); | |
478 | uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); | |
479 | if (propertyAsUInt32 == propertyAsDouble) | |
480 | return getByVal(exec, base, propertyAsUInt32); | |
481 | } else if (property.isString()) { | |
482 | if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) | |
483 | return JSValue::encode(result); | |
484 | } | |
485 | } | |
14957cd0 | 486 | |
93a37866 A |
487 | if (isName(property)) |
488 | return JSValue::encode(baseValue.get(exec, jsCast<NameInstance*>(property.asCell())->privateName())); | |
489 | ||
6fe7ccc8 A |
490 | Identifier ident(exec, property.toString(exec)->value(exec)); |
491 | return JSValue::encode(baseValue.get(exec, ident)); | |
492 | } | |
14957cd0 | 493 | |
6fe7ccc8 A |
494 | EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) |
495 | { | |
93a37866 A |
496 | VM* vm = &exec->vm(); |
497 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
498 | |
499 | JSValue property = JSValue::decode(encodedProperty); | |
14957cd0 | 500 | |
6fe7ccc8 A |
501 | if (property.isUInt32()) |
502 | return getByVal(exec, base, property.asUInt32()); | |
503 | if (property.isDouble()) { | |
504 | double propertyAsDouble = property.asDouble(); | |
505 | uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); | |
506 | if (propertyAsUInt32 == propertyAsDouble) | |
507 | return getByVal(exec, base, propertyAsUInt32); | |
508 | } else if (property.isString()) { | |
509 | if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) | |
510 | return JSValue::encode(result); | |
511 | } | |
14957cd0 | 512 | |
93a37866 A |
513 | if (isName(property)) |
514 | return JSValue::encode(JSValue(base).get(exec, jsCast<NameInstance*>(property.asCell())->privateName())); | |
515 | ||
6fe7ccc8 A |
516 | Identifier ident(exec, property.toString(exec)->value(exec)); |
517 | return JSValue::encode(JSValue(base).get(exec, ident)); | |
518 | } | |
14957cd0 | 519 | |
93a37866 A |
520 | EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index) |
521 | { | |
522 | VM* vm = &exec->vm(); | |
523 | NativeCallFrameTracer tracer(vm, exec); | |
524 | ||
525 | if (index < 0) { | |
526 | // Go the slowest way possible becase negative indices don't use indexed storage. | |
527 | return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index))); | |
528 | } | |
529 | ||
530 | // Use this since we know that the value is out of bounds. | |
531 | return JSValue::encode(JSValue(base).get(exec, index)); | |
532 | } | |
533 | ||
6fe7ccc8 A |
534 | EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, Identifier* propertyName) |
535 | { | |
93a37866 A |
536 | VM* vm = &exec->vm(); |
537 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
538 | |
539 | JSValue baseValue = JSValue::decode(base); | |
540 | PropertySlot slot(baseValue); | |
541 | return JSValue::encode(baseValue.get(exec, *propertyName, slot)); | |
542 | } | |
14957cd0 | 543 | |
6fe7ccc8 A |
544 | J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdBuildList); |
545 | EncodedJSValue DFG_OPERATION operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
546 | { | |
93a37866 A |
547 | VM* vm = &exec->vm(); |
548 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 549 | |
93a37866 A |
550 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
551 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
552 | ||
6fe7ccc8 A |
553 | JSValue baseValue = JSValue::decode(base); |
554 | PropertySlot slot(baseValue); | |
555 | JSValue result = baseValue.get(exec, *propertyName, slot); | |
556 | ||
93a37866 A |
557 | if (accessType == static_cast<AccessType>(stubInfo.accessType)) |
558 | dfgBuildGetByIDList(exec, baseValue, *propertyName, slot, stubInfo); | |
6fe7ccc8 A |
559 | |
560 | return JSValue::encode(result); | |
14957cd0 A |
561 | } |
562 | ||
6fe7ccc8 A |
563 | J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdProtoBuildList); |
564 | EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
14957cd0 | 565 | { |
93a37866 A |
566 | VM* vm = &exec->vm(); |
567 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 568 | |
93a37866 A |
569 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
570 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
571 | ||
6fe7ccc8 | 572 | JSValue baseValue = JSValue::decode(base); |
14957cd0 | 573 | PropertySlot slot(baseValue); |
6fe7ccc8 | 574 | JSValue result = baseValue.get(exec, *propertyName, slot); |
93a37866 A |
575 | |
576 | if (accessType == static_cast<AccessType>(stubInfo.accessType)) | |
577 | dfgBuildGetByIDProtoList(exec, baseValue, *propertyName, slot, stubInfo); | |
6fe7ccc8 A |
578 | |
579 | return JSValue::encode(result); | |
14957cd0 A |
580 | } |
581 | ||
6fe7ccc8 A |
582 | J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdOptimize); |
583 | EncodedJSValue DFG_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
14957cd0 | 584 | { |
93a37866 A |
585 | VM* vm = &exec->vm(); |
586 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 587 | |
93a37866 A |
588 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
589 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
590 | ||
6fe7ccc8 A |
591 | JSValue baseValue = JSValue::decode(base); |
592 | PropertySlot slot(baseValue); | |
593 | JSValue result = baseValue.get(exec, *propertyName, slot); | |
594 | ||
93a37866 A |
595 | if (accessType == static_cast<AccessType>(stubInfo.accessType)) { |
596 | if (stubInfo.seen) | |
597 | dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo); | |
598 | else | |
599 | stubInfo.seen = true; | |
600 | } | |
14957cd0 | 601 | |
6fe7ccc8 A |
602 | return JSValue::encode(result); |
603 | } | |
14957cd0 | 604 | |
6fe7ccc8 A |
605 | EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState* exec, JSCell* base, PropertySlot::GetValueFunc function, Identifier* ident) |
606 | { | |
93a37866 A |
607 | VM* vm = &exec->vm(); |
608 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
609 | |
610 | return JSValue::encode(function(exec, asObject(base), *ident)); | |
611 | } | |
14957cd0 | 612 | |
6fe7ccc8 A |
613 | EncodedJSValue DFG_OPERATION operationCallGetter(ExecState* exec, JSCell* base, JSCell* value) |
614 | { | |
93a37866 A |
615 | VM* vm = &exec->vm(); |
616 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
617 | |
618 | GetterSetter* getterSetter = asGetterSetter(value); | |
619 | JSObject* getter = getterSetter->getter(); | |
620 | if (!getter) | |
621 | return JSValue::encode(jsUndefined()); | |
622 | CallData callData; | |
623 | CallType callType = getter->methodTable()->getCallData(getter, callData); | |
624 | return JSValue::encode(call(exec, getter, callType, callData, asObject(base), ArgList())); | |
625 | } | |
14957cd0 | 626 | |
6fe7ccc8 A |
627 | void DFG_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
628 | { | |
93a37866 A |
629 | VM* vm = &exec->vm(); |
630 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
631 | |
632 | operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue); | |
633 | } | |
14957cd0 | 634 | |
6fe7ccc8 A |
635 | void DFG_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) |
636 | { | |
93a37866 A |
637 | VM* vm = &exec->vm(); |
638 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
639 | |
640 | operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue); | |
641 | } | |
642 | ||
643 | void DFG_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) | |
644 | { | |
93a37866 A |
645 | VM* vm = &exec->vm(); |
646 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
647 | |
648 | operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); | |
649 | } | |
650 | ||
651 | void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) | |
652 | { | |
93a37866 A |
653 | VM* vm = &exec->vm(); |
654 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
655 | |
656 | operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); | |
657 | } | |
658 | ||
93a37866 | 659 | void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) |
6fe7ccc8 | 660 | { |
93a37866 A |
661 | VM* vm = &exec->vm(); |
662 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
663 | |
664 | if (index >= 0) { | |
93a37866 | 665 | array->putByIndexInline(exec, index, JSValue::decode(encodedValue), true); |
6fe7ccc8 A |
666 | return; |
667 | } | |
668 | ||
669 | PutPropertySlot slot(true); | |
670 | array->methodTable()->put( | |
671 | array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot); | |
672 | } | |
14957cd0 | 673 | |
93a37866 | 674 | void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) |
6fe7ccc8 | 675 | { |
93a37866 A |
676 | VM* vm = &exec->vm(); |
677 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
678 | |
679 | if (index >= 0) { | |
93a37866 | 680 | array->putByIndexInline(exec, index, JSValue::decode(encodedValue), false); |
14957cd0 A |
681 | return; |
682 | } | |
6fe7ccc8 A |
683 | |
684 | PutPropertySlot slot(false); | |
685 | array->methodTable()->put( | |
686 | array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot); | |
687 | } | |
14957cd0 | 688 | |
93a37866 A |
689 | void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value) |
690 | { | |
691 | VM* vm = &exec->vm(); | |
692 | NativeCallFrameTracer tracer(vm, exec); | |
693 | ||
694 | JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value); | |
695 | ||
696 | if (index >= 0) { | |
697 | array->putByIndexInline(exec, index, jsValue, true); | |
698 | return; | |
699 | } | |
700 | ||
701 | PutPropertySlot slot(true); | |
702 | array->methodTable()->put( | |
703 | array, exec, Identifier::from(exec, index), jsValue, slot); | |
704 | } | |
705 | ||
706 | void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value) | |
707 | { | |
708 | VM* vm = &exec->vm(); | |
709 | NativeCallFrameTracer tracer(vm, exec); | |
710 | ||
711 | JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value); | |
712 | ||
713 | if (index >= 0) { | |
714 | array->putByIndexInline(exec, index, jsValue, false); | |
715 | return; | |
716 | } | |
717 | ||
718 | PutPropertySlot slot(false); | |
719 | array->methodTable()->put( | |
720 | array, exec, Identifier::from(exec, index), jsValue, slot); | |
721 | } | |
722 | ||
6fe7ccc8 A |
723 | EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array) |
724 | { | |
93a37866 A |
725 | VM* vm = &exec->vm(); |
726 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
727 | |
728 | array->push(exec, JSValue::decode(encodedValue)); | |
729 | return JSValue::encode(jsNumber(array->length())); | |
730 | } | |
731 | ||
93a37866 A |
732 | EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array) |
733 | { | |
734 | VM* vm = &exec->vm(); | |
735 | NativeCallFrameTracer tracer(vm, exec); | |
736 | ||
737 | array->push(exec, JSValue(JSValue::EncodeAsDouble, value)); | |
738 | return JSValue::encode(jsNumber(array->length())); | |
739 | } | |
740 | ||
741 | EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array) | |
742 | { | |
743 | VM* vm = &exec->vm(); | |
744 | NativeCallFrameTracer tracer(vm, exec); | |
745 | ||
746 | return JSValue::encode(array->pop(exec)); | |
747 | } | |
748 | ||
749 | EncodedJSValue DFG_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array) | |
750 | { | |
751 | VM* vm = &exec->vm(); | |
752 | NativeCallFrameTracer tracer(vm, exec); | |
753 | ||
754 | array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1); | |
755 | ||
756 | return JSValue::encode(array->pop(exec)); | |
757 | } | |
758 | ||
6fe7ccc8 A |
759 | EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument) |
760 | { | |
93a37866 A |
761 | VM& vm = exec->vm(); |
762 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 A |
763 | |
764 | if (!base->inherits(&RegExpObject::s_info)) | |
765 | return throwVMTypeError(exec); | |
766 | ||
767 | ASSERT(argument->isString() || argument->isObject()); | |
768 | JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); | |
769 | return JSValue::encode(asRegExpObject(base)->exec(exec, input)); | |
770 | } | |
771 | ||
772 | size_t DFG_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument) | |
773 | { | |
93a37866 A |
774 | VM& vm = exec->vm(); |
775 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 A |
776 | |
777 | if (!base->inherits(&RegExpObject::s_info)) { | |
778 | throwTypeError(exec); | |
779 | return false; | |
14957cd0 | 780 | } |
6fe7ccc8 A |
781 | |
782 | ASSERT(argument->isString() || argument->isObject()); | |
783 | JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); | |
784 | return asRegExpObject(base)->test(exec, input); | |
785 | } | |
786 | ||
6fe7ccc8 A |
787 | void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) |
788 | { | |
93a37866 A |
789 | VM* vm = &exec->vm(); |
790 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
791 | |
792 | PutPropertySlot slot(true); | |
793 | base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot); | |
14957cd0 A |
794 | } |
795 | ||
6fe7ccc8 | 796 | void DFG_OPERATION operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) |
14957cd0 | 797 | { |
93a37866 A |
798 | VM* vm = &exec->vm(); |
799 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
800 | |
801 | PutPropertySlot slot(false); | |
802 | base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot); | |
14957cd0 A |
803 | } |
804 | ||
6fe7ccc8 | 805 | void DFG_OPERATION operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) |
14957cd0 | 806 | { |
93a37866 A |
807 | VM* vm = &exec->vm(); |
808 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
809 | |
810 | PutPropertySlot slot(true); | |
811 | ASSERT(base->isObject()); | |
93a37866 | 812 | asObject(base)->putDirect(exec->vm(), *propertyName, JSValue::decode(encodedValue), slot); |
6fe7ccc8 A |
813 | } |
814 | ||
815 | void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) | |
816 | { | |
93a37866 A |
817 | VM* vm = &exec->vm(); |
818 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
819 | |
820 | PutPropertySlot slot(false); | |
821 | ASSERT(base->isObject()); | |
93a37866 | 822 | asObject(base)->putDirect(exec->vm(), *propertyName, JSValue::decode(encodedValue), slot); |
6fe7ccc8 A |
823 | } |
824 | ||
825 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictOptimize); | |
826 | void DFG_OPERATION operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
827 | { | |
93a37866 A |
828 | VM* vm = &exec->vm(); |
829 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 830 | |
93a37866 A |
831 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
832 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
833 | ||
6fe7ccc8 A |
834 | JSValue value = JSValue::decode(encodedValue); |
835 | JSValue baseValue(base); | |
836 | PutPropertySlot slot(true); | |
837 | ||
838 | baseValue.put(exec, *propertyName, value, slot); | |
839 | ||
93a37866 A |
840 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) |
841 | return; | |
842 | ||
6fe7ccc8 A |
843 | if (stubInfo.seen) |
844 | dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); | |
845 | else | |
846 | stubInfo.seen = true; | |
847 | } | |
848 | ||
849 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictOptimize); | |
850 | void DFG_OPERATION operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
851 | { | |
93a37866 A |
852 | VM* vm = &exec->vm(); |
853 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 854 | |
93a37866 A |
855 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
856 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
857 | ||
6fe7ccc8 A |
858 | JSValue value = JSValue::decode(encodedValue); |
859 | JSValue baseValue(base); | |
860 | PutPropertySlot slot(false); | |
861 | ||
862 | baseValue.put(exec, *propertyName, value, slot); | |
863 | ||
93a37866 A |
864 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) |
865 | return; | |
866 | ||
6fe7ccc8 A |
867 | if (stubInfo.seen) |
868 | dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); | |
869 | else | |
870 | stubInfo.seen = true; | |
871 | } | |
872 | ||
873 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictOptimize); | |
874 | void DFG_OPERATION operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
875 | { | |
93a37866 A |
876 | VM* vm = &exec->vm(); |
877 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 878 | |
93a37866 A |
879 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
880 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
881 | ||
6fe7ccc8 A |
882 | JSValue value = JSValue::decode(encodedValue); |
883 | PutPropertySlot slot(true); | |
884 | ||
885 | ASSERT(base->isObject()); | |
93a37866 A |
886 | asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); |
887 | ||
888 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) | |
889 | return; | |
6fe7ccc8 | 890 | |
6fe7ccc8 A |
891 | if (stubInfo.seen) |
892 | dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct); | |
893 | else | |
894 | stubInfo.seen = true; | |
895 | } | |
896 | ||
897 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictOptimize); | |
898 | void DFG_OPERATION operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
899 | { | |
93a37866 A |
900 | VM* vm = &exec->vm(); |
901 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 902 | |
93a37866 A |
903 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
904 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
905 | ||
6fe7ccc8 A |
906 | JSValue value = JSValue::decode(encodedValue); |
907 | PutPropertySlot slot(false); | |
908 | ||
909 | ASSERT(base->isObject()); | |
93a37866 A |
910 | asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); |
911 | ||
912 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) | |
913 | return; | |
6fe7ccc8 | 914 | |
6fe7ccc8 A |
915 | if (stubInfo.seen) |
916 | dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct); | |
917 | else | |
918 | stubInfo.seen = true; | |
14957cd0 A |
919 | } |
920 | ||
6fe7ccc8 A |
921 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictBuildList); |
922 | void DFG_OPERATION operationPutByIdStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
14957cd0 | 923 | { |
93a37866 A |
924 | VM* vm = &exec->vm(); |
925 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 926 | |
93a37866 A |
927 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
928 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
929 | ||
6fe7ccc8 A |
930 | JSValue value = JSValue::decode(encodedValue); |
931 | JSValue baseValue(base); | |
14957cd0 | 932 | PutPropertySlot slot(true); |
6fe7ccc8 A |
933 | |
934 | baseValue.put(exec, *propertyName, value, slot); | |
935 | ||
93a37866 A |
936 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) |
937 | return; | |
938 | ||
6fe7ccc8 | 939 | dfgBuildPutByIdList(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); |
14957cd0 A |
940 | } |
941 | ||
6fe7ccc8 A |
942 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictBuildList); |
943 | void DFG_OPERATION operationPutByIdNonStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
14957cd0 | 944 | { |
93a37866 A |
945 | VM* vm = &exec->vm(); |
946 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 947 | |
93a37866 A |
948 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
949 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
950 | ||
6fe7ccc8 A |
951 | JSValue value = JSValue::decode(encodedValue); |
952 | JSValue baseValue(base); | |
14957cd0 | 953 | PutPropertySlot slot(false); |
6fe7ccc8 A |
954 | |
955 | baseValue.put(exec, *propertyName, value, slot); | |
956 | ||
93a37866 A |
957 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) |
958 | return; | |
959 | ||
6fe7ccc8 | 960 | dfgBuildPutByIdList(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); |
14957cd0 A |
961 | } |
962 | ||
6fe7ccc8 A |
963 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictBuildList); |
964 | void DFG_OPERATION operationPutByIdDirectStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
14957cd0 | 965 | { |
93a37866 A |
966 | VM* vm = &exec->vm(); |
967 | NativeCallFrameTracer tracer(vm, exec); | |
968 | ||
969 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); | |
970 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
6fe7ccc8 A |
971 | |
972 | JSValue value = JSValue::decode(encodedValue); | |
14957cd0 | 973 | PutPropertySlot slot(true); |
6fe7ccc8 A |
974 | |
975 | ASSERT(base->isObject()); | |
93a37866 A |
976 | asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); |
977 | ||
978 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) | |
979 | return; | |
6fe7ccc8 | 980 | |
6fe7ccc8 | 981 | dfgBuildPutByIdList(exec, base, *propertyName, slot, stubInfo, Direct); |
14957cd0 A |
982 | } |
983 | ||
6fe7ccc8 A |
984 | V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictBuildList); |
985 | void DFG_OPERATION operationPutByIdDirectNonStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) | |
14957cd0 | 986 | { |
93a37866 A |
987 | VM* vm = &exec->vm(); |
988 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 989 | |
93a37866 A |
990 | StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); |
991 | AccessType accessType = static_cast<AccessType>(stubInfo.accessType); | |
992 | ||
6fe7ccc8 | 993 | JSValue value = JSValue::decode(encodedValue); |
14957cd0 | 994 | PutPropertySlot slot(false); |
6fe7ccc8 A |
995 | |
996 | ASSERT(base->isObject()); | |
93a37866 A |
997 | asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); |
998 | ||
999 | if (accessType != static_cast<AccessType>(stubInfo.accessType)) | |
1000 | return; | |
6fe7ccc8 | 1001 | |
6fe7ccc8 | 1002 | dfgBuildPutByIdList(exec, base, *propertyName, slot, stubInfo, Direct); |
14957cd0 A |
1003 | } |
1004 | ||
6fe7ccc8 | 1005 | size_t DFG_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
14957cd0 | 1006 | { |
93a37866 A |
1007 | VM* vm = &exec->vm(); |
1008 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1009 | |
1010 | return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); | |
14957cd0 A |
1011 | } |
1012 | ||
6fe7ccc8 | 1013 | size_t DFG_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
14957cd0 | 1014 | { |
93a37866 A |
1015 | VM* vm = &exec->vm(); |
1016 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1017 | |
1018 | return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); | |
14957cd0 A |
1019 | } |
1020 | ||
6fe7ccc8 | 1021 | size_t DFG_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
14957cd0 | 1022 | { |
93a37866 A |
1023 | VM* vm = &exec->vm(); |
1024 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1025 | |
1026 | return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); | |
14957cd0 A |
1027 | } |
1028 | ||
6fe7ccc8 | 1029 | size_t DFG_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
14957cd0 | 1030 | { |
93a37866 A |
1031 | VM* vm = &exec->vm(); |
1032 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1033 | |
1034 | return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); | |
14957cd0 A |
1035 | } |
1036 | ||
6fe7ccc8 | 1037 | size_t DFG_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
14957cd0 | 1038 | { |
93a37866 A |
1039 | VM* vm = &exec->vm(); |
1040 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1041 | |
1042 | return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); | |
1043 | } | |
1044 | ||
93a37866 A |
1045 | #if USE(JSVALUE64) |
1046 | EncodedJSValue DFG_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right) | |
1047 | #else | |
1048 | size_t DFG_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right) | |
1049 | #endif | |
1050 | { | |
1051 | VM* vm = &exec->vm(); | |
1052 | NativeCallFrameTracer tracer(vm, exec); | |
1053 | ||
1054 | bool result = asString(left)->value(exec) == asString(right)->value(exec); | |
1055 | #if USE(JSVALUE64) | |
1056 | return JSValue::encode(jsBoolean(result)); | |
1057 | #else | |
1058 | return result; | |
1059 | #endif | |
1060 | } | |
1061 | ||
6fe7ccc8 A |
1062 | size_t DFG_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) |
1063 | { | |
93a37866 A |
1064 | VM* vm = &exec->vm(); |
1065 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1066 | |
1067 | JSValue op1 = JSValue::decode(encodedOp1); | |
1068 | JSValue op2 = JSValue::decode(encodedOp2); | |
1069 | ||
1070 | ASSERT(op1.isCell()); | |
1071 | ASSERT(op2.isCell()); | |
1072 | ||
1073 | return JSValue::strictEqualSlowCaseInline(exec, op1, op2); | |
1074 | } | |
1075 | ||
1076 | size_t DFG_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) | |
1077 | { | |
93a37866 A |
1078 | VM* vm = &exec->vm(); |
1079 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1080 | |
1081 | JSValue src1 = JSValue::decode(encodedOp1); | |
1082 | JSValue src2 = JSValue::decode(encodedOp2); | |
1083 | ||
1084 | return JSValue::strictEqual(exec, src1, src2); | |
1085 | } | |
1086 | ||
1087 | static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind) | |
1088 | { | |
1089 | ExecState* exec = execCallee->callerFrame(); | |
93a37866 | 1090 | VM* vm = &exec->vm(); |
6fe7ccc8 | 1091 | |
93a37866 | 1092 | execCallee->setScope(exec->scope()); |
6fe7ccc8 | 1093 | execCallee->setCodeBlock(0); |
6fe7ccc8 A |
1094 | |
1095 | if (kind == CodeForCall) { | |
1096 | CallData callData; | |
1097 | CallType callType = getCallData(callee, callData); | |
1098 | ||
1099 | ASSERT(callType != CallTypeJS); | |
1100 | ||
1101 | if (callType == CallTypeHost) { | |
93a37866 | 1102 | NativeCallFrameTracer tracer(vm, execCallee); |
6fe7ccc8 | 1103 | execCallee->setCallee(asObject(callee)); |
93a37866 A |
1104 | vm->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); |
1105 | if (vm->exception) | |
1106 | return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); | |
6fe7ccc8 A |
1107 | |
1108 | return reinterpret_cast<void*>(getHostCallReturnValue); | |
1109 | } | |
1110 | ||
1111 | ASSERT(callType == CallTypeNone); | |
93a37866 A |
1112 | exec->vm().exception = createNotAFunctionError(exec, callee); |
1113 | return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); | |
6fe7ccc8 A |
1114 | } |
1115 | ||
1116 | ASSERT(kind == CodeForConstruct); | |
1117 | ||
1118 | ConstructData constructData; | |
1119 | ConstructType constructType = getConstructData(callee, constructData); | |
1120 | ||
1121 | ASSERT(constructType != ConstructTypeJS); | |
1122 | ||
1123 | if (constructType == ConstructTypeHost) { | |
93a37866 | 1124 | NativeCallFrameTracer tracer(vm, execCallee); |
6fe7ccc8 | 1125 | execCallee->setCallee(asObject(callee)); |
93a37866 A |
1126 | vm->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); |
1127 | if (vm->exception) | |
1128 | return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); | |
6fe7ccc8 A |
1129 | |
1130 | return reinterpret_cast<void*>(getHostCallReturnValue); | |
1131 | } | |
1132 | ||
1133 | ASSERT(constructType == ConstructTypeNone); | |
93a37866 A |
1134 | exec->vm().exception = createNotAConstructorError(exec, callee); |
1135 | return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); | |
6fe7ccc8 A |
1136 | } |
1137 | ||
93a37866 | 1138 | inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind) |
6fe7ccc8 A |
1139 | { |
1140 | ExecState* exec = execCallee->callerFrame(); | |
93a37866 A |
1141 | VM* vm = &exec->vm(); |
1142 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1143 | |
1144 | JSValue calleeAsValue = execCallee->calleeAsValue(); | |
1145 | JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); | |
1146 | if (!calleeAsFunctionCell) | |
93a37866 | 1147 | return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); |
6fe7ccc8 A |
1148 | |
1149 | JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); | |
93a37866 | 1150 | execCallee->setScope(callee->scopeUnchecked()); |
6fe7ccc8 A |
1151 | ExecutableBase* executable = callee->executable(); |
1152 | ||
1153 | MacroAssemblerCodePtr codePtr; | |
1154 | CodeBlock* codeBlock = 0; | |
1155 | if (executable->isHostFunction()) | |
1156 | codePtr = executable->generatedJITCodeFor(kind).addressForCall(); | |
1157 | else { | |
1158 | FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); | |
1159 | JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind); | |
1160 | if (error) { | |
93a37866 A |
1161 | vm->exception = createStackOverflowError(exec); |
1162 | return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); | |
6fe7ccc8 A |
1163 | } |
1164 | codeBlock = &functionExecutable->generatedBytecodeFor(kind); | |
1165 | if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) | |
1166 | codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); | |
1167 | else | |
1168 | codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); | |
1169 | } | |
93a37866 | 1170 | CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC()); |
6fe7ccc8 A |
1171 | if (!callLinkInfo.seenOnce()) |
1172 | callLinkInfo.setSeen(); | |
1173 | else | |
1174 | dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); | |
93a37866 | 1175 | return reinterpret_cast<char*>(codePtr.executableAddress()); |
6fe7ccc8 A |
1176 | } |
1177 | ||
93a37866 | 1178 | char* DFG_OPERATION operationLinkCall(ExecState* execCallee) |
6fe7ccc8 | 1179 | { |
93a37866 | 1180 | return linkFor(execCallee, CodeForCall); |
6fe7ccc8 A |
1181 | } |
1182 | ||
93a37866 | 1183 | char* DFG_OPERATION operationLinkConstruct(ExecState* execCallee) |
6fe7ccc8 | 1184 | { |
93a37866 | 1185 | return linkFor(execCallee, CodeForConstruct); |
6fe7ccc8 A |
1186 | } |
1187 | ||
93a37866 | 1188 | inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell) |
6fe7ccc8 A |
1189 | { |
1190 | ExecState* exec = execCallee->callerFrame(); | |
93a37866 A |
1191 | VM* vm = &exec->vm(); |
1192 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1193 | |
1194 | JSValue calleeAsValue = execCallee->calleeAsValue(); | |
93a37866 | 1195 | calleeAsFunctionCell = getJSFunction(calleeAsValue); |
6fe7ccc8 | 1196 | if (UNLIKELY(!calleeAsFunctionCell)) |
93a37866 | 1197 | return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); |
6fe7ccc8 A |
1198 | |
1199 | JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell); | |
93a37866 | 1200 | execCallee->setScope(function->scopeUnchecked()); |
6fe7ccc8 A |
1201 | ExecutableBase* executable = function->executable(); |
1202 | if (UNLIKELY(!executable->hasJITCodeFor(kind))) { | |
1203 | FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); | |
1204 | JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind); | |
1205 | if (error) { | |
93a37866 A |
1206 | exec->vm().exception = error; |
1207 | return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); | |
6fe7ccc8 A |
1208 | } |
1209 | } | |
93a37866 | 1210 | return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress()); |
6fe7ccc8 A |
1211 | } |
1212 | ||
93a37866 A |
1213 | inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) |
1214 | { | |
1215 | JSCell* calleeAsFunctionCellIgnored; | |
1216 | return virtualForWithFunction(execCallee, kind, calleeAsFunctionCellIgnored); | |
6fe7ccc8 A |
1217 | } |
1218 | ||
93a37866 | 1219 | static bool attemptToOptimizeClosureCall(ExecState* execCallee, JSCell* calleeAsFunctionCell, CallLinkInfo& callLinkInfo) |
6fe7ccc8 | 1220 | { |
93a37866 A |
1221 | if (!calleeAsFunctionCell) |
1222 | return false; | |
1223 | ||
1224 | JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); | |
1225 | JSFunction* oldCallee = callLinkInfo.callee.get(); | |
1226 | ||
1227 | if (!oldCallee | |
1228 | || oldCallee->structure() != callee->structure() | |
1229 | || oldCallee->executable() != callee->executable()) | |
1230 | return false; | |
1231 | ||
1232 | ASSERT(callee->executable()->hasJITCodeForCall()); | |
1233 | MacroAssemblerCodePtr codePtr = callee->executable()->generatedJITCodeForCall().addressForCall(); | |
1234 | ||
1235 | CodeBlock* codeBlock; | |
1236 | if (callee->executable()->isHostFunction()) | |
1237 | codeBlock = 0; | |
1238 | else { | |
1239 | codeBlock = &jsCast<FunctionExecutable*>(callee->executable())->generatedBytecodeForCall(); | |
1240 | if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) | |
1241 | return false; | |
1242 | } | |
1243 | ||
1244 | dfgLinkClosureCall( | |
1245 | execCallee, callLinkInfo, codeBlock, | |
1246 | callee->structure(), callee->executable(), codePtr); | |
1247 | ||
1248 | return true; | |
6fe7ccc8 A |
1249 | } |
1250 | ||
93a37866 | 1251 | char* DFG_OPERATION operationLinkClosureCall(ExecState* execCallee) |
6fe7ccc8 | 1252 | { |
93a37866 A |
1253 | JSCell* calleeAsFunctionCell; |
1254 | char* result = virtualForWithFunction(execCallee, CodeForCall, calleeAsFunctionCell); | |
1255 | CallLinkInfo& callLinkInfo = execCallee->callerFrame()->codeBlock()->getCallLinkInfo(execCallee->returnPC()); | |
1256 | ||
1257 | if (!attemptToOptimizeClosureCall(execCallee, calleeAsFunctionCell, callLinkInfo)) | |
1258 | dfgLinkSlowFor(execCallee, callLinkInfo, CodeForCall); | |
6fe7ccc8 | 1259 | |
93a37866 A |
1260 | return result; |
1261 | } | |
6fe7ccc8 | 1262 | |
93a37866 A |
1263 | char* DFG_OPERATION operationVirtualCall(ExecState* execCallee) |
1264 | { | |
1265 | return virtualFor(execCallee, CodeForCall); | |
1266 | } | |
6fe7ccc8 | 1267 | |
93a37866 A |
1268 | char* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) |
1269 | { | |
1270 | return virtualFor(execCallee, CodeForConstruct); | |
6fe7ccc8 A |
1271 | } |
1272 | ||
93a37866 | 1273 | void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) |
6fe7ccc8 | 1274 | { |
93a37866 | 1275 | watchpointSet->notifyWrite(); |
6fe7ccc8 A |
1276 | } |
1277 | ||
93a37866 | 1278 | EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName, ResolveOperations* operations) |
6fe7ccc8 | 1279 | { |
93a37866 A |
1280 | VM* vm = &exec->vm(); |
1281 | NativeCallFrameTracer tracer(vm, exec); | |
1282 | return JSValue::encode(JSScope::resolve(exec, *propertyName, operations)); | |
6fe7ccc8 A |
1283 | } |
1284 | ||
93a37866 | 1285 | EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) |
6fe7ccc8 | 1286 | { |
93a37866 A |
1287 | VM* vm = &exec->vm(); |
1288 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 1289 | |
93a37866 A |
1290 | return JSValue::encode(JSScope::resolveBase(exec, *propertyName, false, operations, putToBaseOperations)); |
1291 | } | |
6fe7ccc8 | 1292 | |
93a37866 A |
1293 | EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) |
1294 | { | |
1295 | VM* vm = &exec->vm(); | |
1296 | NativeCallFrameTracer tracer(vm, exec); | |
1297 | ||
1298 | return JSValue::encode(JSScope::resolveBase(exec, *propertyName, true, operations, putToBaseOperations)); | |
1299 | } | |
6fe7ccc8 | 1300 | |
93a37866 A |
1301 | EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, ResolveOperation* resolveOperation, JSGlobalObject* globalObject, Identifier* propertyName) |
1302 | { | |
1303 | VM* vm = &exec->vm(); | |
1304 | NativeCallFrameTracer tracer(vm, exec); | |
1305 | ASSERT(globalObject); | |
1306 | UNUSED_PARAM(resolveOperation); | |
1307 | UNUSED_PARAM(globalObject); | |
1308 | ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty); | |
1309 | return JSValue::encode(JSScope::resolveGlobal(exec, *propertyName, globalObject, resolveOperation)); | |
6fe7ccc8 A |
1310 | } |
1311 | ||
1312 | EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value) | |
1313 | { | |
93a37866 A |
1314 | VM* vm = &exec->vm(); |
1315 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1316 | |
1317 | return JSValue::encode(JSValue::decode(value).toPrimitive(exec)); | |
1318 | } | |
1319 | ||
93a37866 | 1320 | char* DFG_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size) |
6fe7ccc8 | 1321 | { |
93a37866 A |
1322 | VM* vm = &exec->vm(); |
1323 | NativeCallFrameTracer tracer(vm, exec); | |
1324 | ||
1325 | return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size)); | |
1326 | } | |
6fe7ccc8 | 1327 | |
93a37866 A |
1328 | char* DFG_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure) |
1329 | { | |
1330 | VM* vm = &exec->vm(); | |
1331 | NativeCallFrameTracer tracer(vm, exec); | |
1332 | ||
1333 | return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure)); | |
6fe7ccc8 A |
1334 | } |
1335 | ||
93a37866 | 1336 | char* DFG_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size) |
6fe7ccc8 | 1337 | { |
93a37866 A |
1338 | VM* vm = &exec->vm(); |
1339 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 1340 | |
93a37866 A |
1341 | if (UNLIKELY(size < 0)) |
1342 | return bitwise_cast<char*>(throwError(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")))); | |
1343 | ||
1344 | return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure, size)); | |
6fe7ccc8 A |
1345 | } |
1346 | ||
93a37866 | 1347 | char* DFG_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size) |
6fe7ccc8 | 1348 | { |
93a37866 A |
1349 | VM& vm = exec->vm(); |
1350 | NativeCallFrameTracer tracer(&vm, exec); | |
1351 | return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size)); | |
6fe7ccc8 A |
1352 | } |
1353 | ||
1354 | EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr) | |
1355 | { | |
93a37866 A |
1356 | VM& vm = exec->vm(); |
1357 | NativeCallFrameTracer tracer(&vm, exec); | |
6fe7ccc8 A |
1358 | RegExp* regexp = static_cast<RegExp*>(regexpPtr); |
1359 | if (!regexp->isValid()) { | |
1360 | throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); | |
1361 | return JSValue::encode(jsUndefined()); | |
1362 | } | |
1363 | ||
93a37866 | 1364 | return JSValue::encode(RegExpObject::create(exec->vm(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp)); |
6fe7ccc8 A |
1365 | } |
1366 | ||
1367 | JSCell* DFG_OPERATION operationCreateActivation(ExecState* exec) | |
1368 | { | |
93a37866 A |
1369 | VM& vm = exec->vm(); |
1370 | NativeCallFrameTracer tracer(&vm, exec); | |
1371 | JSActivation* activation = JSActivation::create(vm, exec, exec->codeBlock()); | |
1372 | exec->setScope(activation); | |
6fe7ccc8 A |
1373 | return activation; |
1374 | } | |
1375 | ||
93a37866 A |
1376 | JSCell* DFG_OPERATION operationCreateArguments(ExecState* exec) |
1377 | { | |
1378 | VM& vm = exec->vm(); | |
1379 | NativeCallFrameTracer tracer(&vm, exec); | |
1380 | // NB: This needs to be exceedingly careful with top call frame tracking, since it | |
1381 | // may be called from OSR exit, while the state of the call stack is bizarre. | |
1382 | Arguments* result = Arguments::create(vm, exec); | |
1383 | ASSERT(!vm.exception); | |
1384 | return result; | |
1385 | } | |
1386 | ||
1387 | JSCell* DFG_OPERATION operationCreateInlinedArguments( | |
1388 | ExecState* exec, InlineCallFrame* inlineCallFrame) | |
1389 | { | |
1390 | VM& vm = exec->vm(); | |
1391 | NativeCallFrameTracer tracer(&vm, exec); | |
1392 | // NB: This needs to be exceedingly careful with top call frame tracking, since it | |
1393 | // may be called from OSR exit, while the state of the call stack is bizarre. | |
1394 | Arguments* result = Arguments::create(vm, exec, inlineCallFrame); | |
1395 | ASSERT(!vm.exception); | |
1396 | return result; | |
1397 | } | |
1398 | ||
1399 | void DFG_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsCell, JSCell* activationCell) | |
1400 | { | |
1401 | ASSERT(exec->codeBlock()->usesArguments()); | |
1402 | if (activationCell) { | |
1403 | jsCast<Arguments*>(argumentsCell)->didTearOffActivation(exec, jsCast<JSActivation*>(activationCell)); | |
1404 | return; | |
1405 | } | |
1406 | jsCast<Arguments*>(argumentsCell)->tearOff(exec); | |
1407 | } | |
1408 | ||
1409 | void DFG_OPERATION operationTearOffInlinedArguments( | |
1410 | ExecState* exec, JSCell* argumentsCell, JSCell* activationCell, InlineCallFrame* inlineCallFrame) | |
1411 | { | |
1412 | ASSERT_UNUSED(activationCell, !activationCell); // Currently, we don't inline functions with activations. | |
1413 | jsCast<Arguments*>(argumentsCell)->tearOff(exec, inlineCallFrame); | |
1414 | } | |
1415 | ||
1416 | EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState* exec, int32_t argumentsRegister) | |
1417 | { | |
1418 | VM& vm = exec->vm(); | |
1419 | NativeCallFrameTracer tracer(&vm, exec); | |
1420 | // Here we can assume that the argumernts were created. Because otherwise the JIT code would | |
1421 | // have not made this call. | |
1422 | Identifier ident(&vm, "length"); | |
1423 | JSValue baseValue = exec->uncheckedR(argumentsRegister).jsValue(); | |
1424 | PropertySlot slot(baseValue); | |
1425 | return JSValue::encode(baseValue.get(exec, ident, slot)); | |
1426 | } | |
1427 | ||
1428 | EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index) | |
6fe7ccc8 | 1429 | { |
93a37866 A |
1430 | VM& vm = exec->vm(); |
1431 | NativeCallFrameTracer tracer(&vm, exec); | |
1432 | ||
1433 | JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); | |
1434 | ||
1435 | // If there are no arguments, and we're accessing out of bounds, then we have to create the | |
1436 | // arguments in case someone has installed a getter on a numeric property. | |
1437 | if (!argumentsValue) | |
1438 | exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->vm(), exec); | |
1439 | ||
1440 | return JSValue::encode(argumentsValue.get(exec, index)); | |
1441 | } | |
1442 | ||
1443 | EncodedJSValue DFG_OPERATION operationGetInlinedArgumentByVal( | |
1444 | ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index) | |
1445 | { | |
1446 | VM& vm = exec->vm(); | |
1447 | NativeCallFrameTracer tracer(&vm, exec); | |
1448 | ||
1449 | JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); | |
1450 | ||
1451 | // If there are no arguments, and we're accessing out of bounds, then we have to create the | |
1452 | // arguments in case someone has installed a getter on a numeric property. | |
1453 | if (!argumentsValue) { | |
1454 | exec->uncheckedR(argumentsRegister) = argumentsValue = | |
1455 | Arguments::create(exec->vm(), exec, inlineCallFrame); | |
1456 | } | |
1457 | ||
1458 | return JSValue::encode(argumentsValue.get(exec, index)); | |
1459 | } | |
1460 | ||
1461 | JSCell* DFG_OPERATION operationNewFunctionNoCheck(ExecState* exec, JSCell* functionExecutable) | |
1462 | { | |
1463 | ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info)); | |
1464 | VM& vm = exec->vm(); | |
1465 | NativeCallFrameTracer tracer(&vm, exec); | |
1466 | return JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope()); | |
6fe7ccc8 A |
1467 | } |
1468 | ||
93a37866 | 1469 | EncodedJSValue DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable) |
6fe7ccc8 A |
1470 | { |
1471 | ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info)); | |
93a37866 A |
1472 | VM& vm = exec->vm(); |
1473 | NativeCallFrameTracer tracer(&vm, exec); | |
1474 | return JSValue::encode(JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope())); | |
6fe7ccc8 A |
1475 | } |
1476 | ||
1477 | JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* functionExecutableAsCell) | |
1478 | { | |
1479 | ASSERT(functionExecutableAsCell->inherits(&FunctionExecutable::s_info)); | |
93a37866 A |
1480 | |
1481 | VM& vm = exec->vm(); | |
1482 | NativeCallFrameTracer tracer(&vm, exec); | |
1483 | ||
6fe7ccc8 A |
1484 | FunctionExecutable* functionExecutable = |
1485 | static_cast<FunctionExecutable*>(functionExecutableAsCell); | |
93a37866 | 1486 | return JSFunction::create(exec, functionExecutable, exec->scope()); |
6fe7ccc8 A |
1487 | } |
1488 | ||
93a37866 | 1489 | size_t DFG_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value) |
6fe7ccc8 | 1490 | { |
93a37866 | 1491 | return jsIsObjectType(exec, JSValue::decode(value)); |
6fe7ccc8 A |
1492 | } |
1493 | ||
1494 | size_t DFG_OPERATION operationIsFunction(EncodedJSValue value) | |
1495 | { | |
1496 | return jsIsFunctionType(JSValue::decode(value)); | |
1497 | } | |
1498 | ||
93a37866 A |
1499 | JSCell* DFG_OPERATION operationTypeOf(ExecState* exec, JSCell* value) |
1500 | { | |
1501 | return jsTypeStringForValue(exec, JSValue(value)).asCell(); | |
1502 | } | |
1503 | ||
1504 | void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value) | |
1505 | { | |
1506 | VM& vm = exec->vm(); | |
1507 | NativeCallFrameTracer tracer(&vm, exec); | |
1508 | ||
1509 | ASSERT(structure->outOfLineCapacity() > base->structure()->outOfLineCapacity()); | |
1510 | ASSERT(!vm.heap.storageAllocator().fastPathShouldSucceed(structure->outOfLineCapacity() * sizeof(JSValue))); | |
1511 | base->setStructureAndReallocateStorageIfNecessary(vm, structure); | |
1512 | base->putDirect(vm, offset, JSValue::decode(value)); | |
1513 | } | |
1514 | ||
1515 | char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec) | |
1516 | { | |
1517 | VM& vm = exec->vm(); | |
1518 | NativeCallFrameTracer tracer(&vm, exec); | |
1519 | ||
1520 | return reinterpret_cast<char*>( | |
1521 | Butterfly::createUninitialized(vm, 0, initialOutOfLineCapacity, false, 0)); | |
1522 | } | |
1523 | ||
1524 | char* DFG_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize) | |
1525 | { | |
1526 | VM& vm = exec->vm(); | |
1527 | NativeCallFrameTracer tracer(&vm, exec); | |
1528 | ||
1529 | return reinterpret_cast<char*>( | |
1530 | Butterfly::createUninitialized(vm, 0, newSize, false, 0)); | |
1531 | } | |
1532 | ||
1533 | char* DFG_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object) | |
1534 | { | |
1535 | VM& vm = exec->vm(); | |
1536 | NativeCallFrameTracer tracer(&vm, exec); | |
1537 | ||
1538 | ASSERT(!object->structure()->outOfLineCapacity()); | |
1539 | Butterfly* result = object->growOutOfLineStorage(vm, 0, initialOutOfLineCapacity); | |
1540 | object->setButterflyWithoutChangingStructure(result); | |
1541 | return reinterpret_cast<char*>(result); | |
1542 | } | |
1543 | ||
1544 | char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize) | |
1545 | { | |
1546 | VM& vm = exec->vm(); | |
1547 | NativeCallFrameTracer tracer(&vm, exec); | |
1548 | ||
1549 | Butterfly* result = object->growOutOfLineStorage(vm, object->structure()->outOfLineCapacity(), newSize); | |
1550 | object->setButterflyWithoutChangingStructure(result); | |
1551 | return reinterpret_cast<char*>(result); | |
1552 | } | |
1553 | ||
1554 | char* DFG_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell) | |
1555 | { | |
1556 | VM& vm = exec->vm(); | |
1557 | NativeCallFrameTracer tracer(&vm, exec); | |
1558 | ||
1559 | if (!cell->isObject()) | |
1560 | return 0; | |
1561 | ||
1562 | return reinterpret_cast<char*>(asObject(cell)->ensureInt32(vm).data()); | |
1563 | } | |
1564 | ||
1565 | char* DFG_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell) | |
1566 | { | |
1567 | VM& vm = exec->vm(); | |
1568 | NativeCallFrameTracer tracer(&vm, exec); | |
1569 | ||
1570 | if (!cell->isObject()) | |
1571 | return 0; | |
1572 | ||
1573 | return reinterpret_cast<char*>(asObject(cell)->ensureDouble(vm).data()); | |
1574 | } | |
1575 | ||
1576 | char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) | |
1577 | { | |
1578 | VM& vm = exec->vm(); | |
1579 | NativeCallFrameTracer tracer(&vm, exec); | |
1580 | ||
1581 | if (!cell->isObject()) | |
1582 | return 0; | |
1583 | ||
1584 | return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data()); | |
1585 | } | |
1586 | ||
1587 | char* DFG_OPERATION operationRageEnsureContiguous(ExecState* exec, JSCell* cell) | |
1588 | { | |
1589 | VM& vm = exec->vm(); | |
1590 | NativeCallFrameTracer tracer(&vm, exec); | |
1591 | ||
1592 | if (!cell->isObject()) | |
1593 | return 0; | |
1594 | ||
1595 | return reinterpret_cast<char*>(asObject(cell)->rageEnsureContiguous(vm).data()); | |
1596 | } | |
1597 | ||
1598 | char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell) | |
1599 | { | |
1600 | VM& vm = exec->vm(); | |
1601 | NativeCallFrameTracer tracer(&vm, exec); | |
1602 | ||
1603 | if (!cell->isObject()) | |
1604 | return 0; | |
1605 | ||
1606 | return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm)); | |
1607 | } | |
1608 | ||
1609 | StringImpl* DFG_OPERATION operationResolveRope(ExecState* exec, JSString* string) | |
1610 | { | |
1611 | VM& vm = exec->vm(); | |
1612 | NativeCallFrameTracer tracer(&vm, exec); | |
1613 | ||
1614 | return string->value(exec).impl(); | |
1615 | } | |
1616 | ||
1617 | JSCell* DFG_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure) | |
1618 | { | |
1619 | VM& vm = exec->vm(); | |
1620 | NativeCallFrameTracer tracer(&vm, exec); | |
1621 | ||
1622 | return StringObject::create(exec, structure, string); | |
1623 | } | |
1624 | ||
1625 | JSCell* DFG_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell) | |
1626 | { | |
1627 | VM& vm = exec->vm(); | |
1628 | NativeCallFrameTracer tracer(&vm, exec); | |
1629 | ||
1630 | return JSValue(cell).toString(exec); | |
1631 | } | |
1632 | ||
1633 | JSCell* DFG_OPERATION operationToString(ExecState* exec, EncodedJSValue value) | |
1634 | { | |
1635 | VM& vm = exec->vm(); | |
1636 | NativeCallFrameTracer tracer(&vm, exec); | |
1637 | ||
1638 | return JSValue::decode(value).toString(exec); | |
1639 | } | |
1640 | ||
1641 | JSCell* DFG_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right) | |
1642 | { | |
1643 | VM& vm = exec->vm(); | |
1644 | NativeCallFrameTracer tracer(&vm, exec); | |
1645 | ||
1646 | return JSRopeString::create(vm, left, right); | |
1647 | } | |
1648 | ||
1649 | JSCell* DFG_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c) | |
1650 | { | |
1651 | VM& vm = exec->vm(); | |
1652 | NativeCallFrameTracer tracer(&vm, exec); | |
1653 | ||
1654 | return JSRopeString::create(vm, a, b, c); | |
1655 | } | |
1656 | ||
6fe7ccc8 A |
1657 | double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b) |
1658 | { | |
1659 | return fmod(a, b); | |
1660 | } | |
1661 | ||
93a37866 A |
1662 | JSCell* DFG_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1) |
1663 | { | |
1664 | VM* vm = &exec->vm(); | |
1665 | NativeCallFrameTracer tracer(vm, exec); | |
1666 | return JSC::stringFromCharCode(exec, op1); | |
1667 | } | |
1668 | ||
6fe7ccc8 A |
1669 | DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t callIndex) |
1670 | { | |
93a37866 A |
1671 | VM* vm = &exec->vm(); |
1672 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 1673 | |
14957cd0 A |
1674 | JSValue exceptionValue = exec->exception(); |
1675 | ASSERT(exceptionValue); | |
6fe7ccc8 A |
1676 | |
1677 | unsigned vPCIndex = exec->codeBlock()->bytecodeOffsetForCallAtIndex(callIndex); | |
93a37866 | 1678 | ExceptionHandler handler = genericThrow(vm, exec, exceptionValue, vPCIndex); |
6fe7ccc8 A |
1679 | ASSERT(handler.catchRoutine); |
1680 | return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine); | |
1681 | } | |
14957cd0 | 1682 | |
6fe7ccc8 A |
1683 | DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState* exec, StructureStubInfo* stubInfo) |
1684 | { | |
93a37866 A |
1685 | VM* vm = &exec->vm(); |
1686 | NativeCallFrameTracer tracer(vm, exec); | |
14957cd0 | 1687 | |
6fe7ccc8 A |
1688 | JSValue exceptionValue = exec->exception(); |
1689 | ASSERT(exceptionValue); | |
1690 | ||
1691 | CodeOrigin codeOrigin = stubInfo->codeOrigin; | |
1692 | while (codeOrigin.inlineCallFrame) | |
1693 | codeOrigin = codeOrigin.inlineCallFrame->caller; | |
1694 | ||
93a37866 | 1695 | ExceptionHandler handler = genericThrow(vm, exec, exceptionValue, codeOrigin.bytecodeIndex); |
6fe7ccc8 A |
1696 | ASSERT(handler.catchRoutine); |
1697 | return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine); | |
14957cd0 A |
1698 | } |
1699 | ||
6fe7ccc8 | 1700 | size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) |
14957cd0 | 1701 | { |
93a37866 A |
1702 | VM* vm = &exec->vm(); |
1703 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1704 | |
1705 | // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register. | |
1706 | return JSValue::decode(value).toUInt32(exec); | |
14957cd0 A |
1707 | } |
1708 | ||
6fe7ccc8 | 1709 | size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp) |
14957cd0 | 1710 | { |
93a37866 A |
1711 | VM* vm = &exec->vm(); |
1712 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 | 1713 | |
14957cd0 A |
1714 | return JSValue::decode(encodedOp).toBoolean(exec); |
1715 | } | |
1716 | ||
93a37866 | 1717 | void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw, void* scratch) |
6fe7ccc8 | 1718 | { |
93a37866 A |
1719 | VM* vm = &exec->vm(); |
1720 | NativeCallFrameTracer tracer(vm, exec); | |
6fe7ccc8 A |
1721 | |
1722 | SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw); | |
1723 | CodeBlock* codeBlock = debugInfo->codeBlock; | |
1724 | CodeBlock* alternative = codeBlock->alternative(); | |
93a37866 A |
1725 | dataLog( |
1726 | "Speculation failure in ", *codeBlock, " with "); | |
1727 | if (alternative) { | |
1728 | dataLog( | |
1729 | "executeCounter = ", alternative->jitExecuteCounter(), | |
1730 | ", reoptimizationRetryCounter = ", alternative->reoptimizationRetryCounter(), | |
1731 | ", optimizationDelayCounter = ", alternative->optimizationDelayCounter()); | |
1732 | } else | |
1733 | dataLog("no alternative code block (i.e. we've been jettisoned)"); | |
1734 | dataLog(", osrExitCounter = ", codeBlock->osrExitCounter(), "\n"); | |
1735 | dataLog(" GPRs at time of exit:"); | |
1736 | char* scratchPointer = static_cast<char*>(scratch); | |
1737 | for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) { | |
1738 | GPRReg gpr = GPRInfo::toRegister(i); | |
1739 | dataLog(" ", GPRInfo::debugName(gpr), ":", RawPointer(*reinterpret_cast_ptr<void**>(scratchPointer))); | |
1740 | scratchPointer += sizeof(EncodedJSValue); | |
1741 | } | |
1742 | dataLog("\n"); | |
1743 | dataLog(" FPRs at time of exit:"); | |
1744 | for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) { | |
1745 | FPRReg fpr = FPRInfo::toRegister(i); | |
1746 | dataLog(" ", FPRInfo::debugName(fpr), ":"); | |
1747 | uint64_t bits = *reinterpret_cast_ptr<uint64_t*>(scratchPointer); | |
1748 | double value = *reinterpret_cast_ptr<double*>(scratchPointer); | |
1749 | dataLogF("%llx:%lf", static_cast<long long>(bits), value); | |
1750 | scratchPointer += sizeof(EncodedJSValue); | |
1751 | } | |
1752 | dataLog("\n"); | |
6fe7ccc8 | 1753 | } |
93a37866 A |
1754 | |
1755 | extern "C" void DFG_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock) | |
1756 | { | |
1757 | #if ENABLE(JIT_VERBOSE_OSR) | |
1758 | dataLog(*codeBlock, ": Entered reoptimize\n"); | |
6fe7ccc8 | 1759 | #endif |
93a37866 A |
1760 | // We must be called with the baseline code block. |
1761 | ASSERT(JITCode::isBaselineCode(codeBlock->getJITType())); | |
1762 | ||
1763 | // If I am my own replacement, then reoptimization has already been triggered. | |
1764 | // This can happen in recursive functions. | |
1765 | if (codeBlock->replacement() == codeBlock) | |
1766 | return; | |
1767 | ||
1768 | // Otherwise, the replacement must be optimized code. Use this as an opportunity | |
1769 | // to check our logic. | |
1770 | ASSERT(codeBlock->hasOptimizedReplacement()); | |
1771 | ASSERT(codeBlock->replacement()->getJITType() == JITCode::DFGJIT); | |
1772 | ||
1773 | codeBlock->reoptimize(); | |
1774 | } | |
6fe7ccc8 A |
1775 | |
1776 | } // extern "C" | |
14957cd0 A |
1777 | } } // namespace JSC::DFG |
1778 | ||
93a37866 | 1779 | #endif // ENABLE(DFG_JIT) |
6fe7ccc8 A |
1780 | |
1781 | namespace JSC { | |
1782 | ||
93a37866 | 1783 | #if COMPILER(GCC) && CPU(X86_64) |
6fe7ccc8 A |
1784 | asm ( |
1785 | ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" | |
1786 | HIDE_SYMBOL(getHostCallReturnValue) "\n" | |
1787 | SYMBOL_STRING(getHostCallReturnValue) ":" "\n" | |
1788 | "mov -40(%r13), %r13\n" | |
1789 | "mov %r13, %rdi\n" | |
93a37866 | 1790 | "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" |
6fe7ccc8 | 1791 | ); |
93a37866 | 1792 | #elif COMPILER(GCC) && CPU(X86) |
6fe7ccc8 A |
1793 | asm ( |
1794 | ".text" "\n" \ | |
1795 | ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" | |
1796 | HIDE_SYMBOL(getHostCallReturnValue) "\n" | |
1797 | SYMBOL_STRING(getHostCallReturnValue) ":" "\n" | |
1798 | "mov -40(%edi), %edi\n" | |
1799 | "mov %edi, 4(%esp)\n" | |
93a37866 | 1800 | "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" |
6fe7ccc8 | 1801 | ); |
93a37866 | 1802 | #elif COMPILER(GCC) && CPU(ARM_THUMB2) |
6fe7ccc8 A |
1803 | asm ( |
1804 | ".text" "\n" | |
1805 | ".align 2" "\n" | |
1806 | ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" | |
1807 | HIDE_SYMBOL(getHostCallReturnValue) "\n" | |
1808 | ".thumb" "\n" | |
1809 | ".thumb_func " THUMB_FUNC_PARAM(getHostCallReturnValue) "\n" | |
1810 | SYMBOL_STRING(getHostCallReturnValue) ":" "\n" | |
1811 | "ldr r5, [r5, #-40]" "\n" | |
1812 | "mov r0, r5" "\n" | |
93a37866 A |
1813 | "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" |
1814 | ); | |
1815 | #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) | |
1816 | asm ( | |
1817 | ".text" "\n" | |
1818 | ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" | |
1819 | HIDE_SYMBOL(getHostCallReturnValue) "\n" | |
1820 | INLINE_ARM_FUNCTION(getHostCallReturnValue) | |
1821 | SYMBOL_STRING(getHostCallReturnValue) ":" "\n" | |
1822 | "ldr r5, [r5, #-40]" "\n" | |
1823 | "mov r0, r5" "\n" | |
1824 | "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" | |
1825 | ); | |
1826 | #elif CPU(ARM64) | |
1827 | asm ( | |
1828 | ".text" "\n" | |
1829 | ".align 2" "\n" | |
1830 | ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" | |
1831 | HIDE_SYMBOL(getHostCallReturnValue) "\n" | |
1832 | SYMBOL_STRING(getHostCallReturnValue) ":" "\n" | |
1833 | "ldur x25, [x25, #-40]" "\n" | |
1834 | "mov x0, x25" "\n" | |
1835 | "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" | |
1836 | ); | |
1837 | #elif COMPILER(GCC) && CPU(MIPS) | |
1838 | asm( | |
1839 | ".text" "\n" | |
1840 | ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" | |
1841 | HIDE_SYMBOL(getHostCallReturnValue) "\n" | |
1842 | SYMBOL_STRING(getHostCallReturnValue) ":" "\n" | |
1843 | LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState) | |
1844 | "lw $s0, -40($s0)" "\n" | |
1845 | "move $a0, $s0" "\n" | |
1846 | "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" | |
1847 | ); | |
1848 | #elif COMPILER(GCC) && CPU(SH4) | |
1849 | asm( | |
1850 | ".text" "\n" | |
1851 | ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" | |
1852 | HIDE_SYMBOL(getHostCallReturnValue) "\n" | |
1853 | SYMBOL_STRING(getHostCallReturnValue) ":" "\n" | |
1854 | "add #-40, r14" "\n" | |
1855 | "mov.l @r14, r14" "\n" | |
1856 | "mov r14, r4" "\n" | |
1857 | "bra " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" | |
1858 | "nop" "\n" | |
6fe7ccc8 A |
1859 | ); |
1860 | #endif | |
1861 | ||
1862 | extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec) | |
1863 | { | |
1864 | if (!exec) | |
1865 | return JSValue::encode(JSValue()); | |
93a37866 | 1866 | return JSValue::encode(exec->vm().hostCallReturnValue); |
6fe7ccc8 A |
1867 | } |
1868 | ||
1869 | } // namespace JSC | |
1870 | ||
93a37866 | 1871 | #endif // ENABLE(JIT) |