DFG JIT cannot compile op_new_object, op_new_array,
[WebKit.git] / Source / JavaScriptCore / dfg / DFGOperations.cpp
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
29 #if ENABLE(DFG_JIT)
30
31 #include "CodeBlock.h"
32 #include "DFGRepatch.h"
33 #include "Interpreter.h"
34 #include "JSByteArray.h"
35 #include "JSGlobalData.h"
36 #include "Operations.h"
37
38
39 #if OS(DARWIN) || (OS(WINDOWS) && CPU(X86))
40 #define SYMBOL_STRING(name) "_" #name
41 #else
42 #define SYMBOL_STRING(name) #name
43 #endif
44
45 #if CPU(X86_64)
46 #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \
47     asm( \
48     ".globl " SYMBOL_STRING(function) "\n" \
49     SYMBOL_STRING(function) ":" "\n" \
50         "mov (%rsp), %" STRINGIZE(register) "\n" \
51         "jmp " SYMBOL_STRING(function) "WithReturnAddress" "\n" \
52     );
53 #elif CPU(X86)
54 #define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \
55     asm( \
56     ".globl " SYMBOL_STRING(function) "\n" \
57     SYMBOL_STRING(function) ":" "\n" \
58         "push (%esp)\n" \
59         "jmp " SYMBOL_STRING(function) "WithReturnAddress" "\n" \
60     );
61 #endif
62 #define FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rsi)
63 #define FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx)
64 #define FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, r8)
65
66 namespace JSC { namespace DFG {
67
68 static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
69 {
70     JSGlobalData* globalData = &exec->globalData();
71
72     if (isJSArray(globalData, baseValue)) {
73         JSArray* array = asArray(baseValue);
74         if (array->canSetIndex(index)) {
75             array->setIndex(*globalData, index, value);
76             return;
77         }
78
79         array->JSArray::put(exec, index, value);
80         return;
81     }
82
83     if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(index)) {
84         JSByteArray* byteArray = asByteArray(baseValue);
85         // FIXME: the JITstub used to relink this to an optimized form!
86         if (value.isInt32()) {
87             byteArray->setIndex(index, value.asInt32());
88             return;
89         }
90
91         double dValue = 0;
92         if (value.getNumber(dValue)) {
93             byteArray->setIndex(index, dValue);
94             return;
95         }
96     }
97
98     baseValue.put(exec, index, value);
99 }
100
101 template<bool strict>
102 ALWAYS_INLINE static void operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
103 {
104     JSValue baseValue = JSValue::decode(encodedBase);
105     JSValue property = JSValue::decode(encodedProperty);
106     JSValue value = JSValue::decode(encodedValue);
107
108     if (LIKELY(property.isUInt32())) {
109         putByVal(exec, baseValue, property.asUInt32(), value);
110         return;
111     }
112
113     if (property.isDouble()) {
114         double propertyAsDouble = property.asDouble();
115         uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
116         if (propertyAsDouble == propertyAsUInt32) {
117             putByVal(exec, baseValue, propertyAsUInt32, value);
118             return;
119         }
120     }
121
122     JSGlobalData* globalData = &exec->globalData();
123
124     // Don't put to an object if toString throws an exception.
125     Identifier ident(exec, property.toString(exec));
126     if (!globalData->exception) {
127         PutPropertySlot slot(strict);
128         baseValue.put(exec, ident, value, slot);
129     }
130 }
131
132 extern "C" {
133
134 EncodedJSValue operationConvertThis(ExecState* exec, EncodedJSValue encodedOp)
135 {
136     return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
137 }
138
139 EncodedJSValue operationCreateThis(ExecState* exec, EncodedJSValue encodedOp)
140 {
141     JSFunction* constructor = asFunction(exec->callee());
142     
143 #if !ASSERT_DISABLED
144     ConstructData constructData;
145     ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
146 #endif
147     
148     JSGlobalData& globalData = exec->globalData();
149     
150     Structure* structure;
151     JSValue proto = JSValue::decode(encodedOp);
152     if (proto.isObject())
153         structure = asObject(proto)->inheritorID(globalData);
154     else
155         structure = constructor->scope()->globalObject->emptyObjectStructure();
156     
157     return JSValue::encode(constructEmptyObject(exec, structure));
158 }
159
160 EncodedJSValue operationNewObject(ExecState* exec)
161 {
162     return JSValue::encode(constructEmptyObject(exec));
163 }
164
165 EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
166 {
167     JSValue op1 = JSValue::decode(encodedOp1);
168     JSValue op2 = JSValue::decode(encodedOp2);
169     
170     return JSValue::encode(jsAdd(exec, op1, op2));
171 }
172
173 EncodedJSValue operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
174 {
175     JSValue op1 = JSValue::decode(encodedOp1);
176     JSValue op2 = JSValue::decode(encodedOp2);
177     
178     ASSERT(!op1.isNumber() || !op2.isNumber());
179     
180     if (op1.isString()) {
181         if (op2.isString())
182             return JSValue::encode(jsString(exec, asString(op1), asString(op2)));
183         return JSValue::encode(jsString(exec, asString(op1), op2.toPrimitiveString(exec)));
184     }
185
186     return JSValue::encode(jsAddSlowCase(exec, op1, op2));
187 }
188
189 EncodedJSValue operationArithAdd(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
190 {
191     double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
192     double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
193     return JSValue::encode(jsNumber(num1 + num2));
194 }
195
196 EncodedJSValue operationArithSub(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
197 {
198     double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
199     double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
200     return JSValue::encode(jsNumber(num1 - num2));
201 }
202
203 EncodedJSValue operationArithMul(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
204 {
205     double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
206     double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
207     return JSValue::encode(jsNumber(num1 * num2));
208 }
209
210 EncodedJSValue operationArithDiv(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
211 {
212     double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
213     double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
214     return JSValue::encode(jsNumber(num1 / num2));
215 }
216
217 EncodedJSValue operationArithMod(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
218 {
219     double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
220     double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
221     return JSValue::encode(jsNumber(fmod(num1, num2)));
222 }
223
224 static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
225 {
226     JSGlobalData* globalData = &exec->globalData();
227
228     // FIXME: the JIT used to handle these in compiled code!
229     if (isJSArray(globalData, base) && asArray(base)->canGetIndex(index))
230         return JSValue::encode(asArray(base)->getIndex(index));
231
232     // FIXME: the JITstub used to relink this to an optimized form!
233     if (isJSString(globalData, base) && asString(base)->canGetIndex(index))
234         return JSValue::encode(asString(base)->getIndex(exec, index));
235
236     // FIXME: the JITstub used to relink this to an optimized form!
237     if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(index))
238         return JSValue::encode(asByteArray(base)->getIndex(exec, index));
239
240     return JSValue::encode(JSValue(base).get(exec, index));
241 }
242
243 EncodedJSValue operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
244 {
245     JSValue baseValue = JSValue::decode(encodedBase);
246     JSValue property = JSValue::decode(encodedProperty);
247
248     if (LIKELY(baseValue.isCell())) {
249         JSCell* base = baseValue.asCell();
250
251         if (property.isUInt32()) {
252             return getByVal(exec, base, property.asUInt32());
253         } else if (property.isDouble()) {
254             double propertyAsDouble = property.asDouble();
255             uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
256             if (propertyAsUInt32 == propertyAsDouble)
257                 return getByVal(exec, base, propertyAsUInt32);
258         } else if (property.isString()) {
259             if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec)))
260                 return JSValue::encode(result);
261         }
262     }
263
264     Identifier ident(exec, property.toString(exec));
265     return JSValue::encode(baseValue.get(exec, ident));
266 }
267
268 EncodedJSValue operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
269 {
270     JSValue baseValue = JSValue::decode(encodedBase);
271     PropertySlot slot(baseValue);
272     return JSValue::encode(baseValue.get(exec, *propertyName, slot));
273 }
274
275 #if CPU(X86_64)
276 EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
277 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetMethodOptimize);
278 EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
279 #elif CPU(X86)
280 EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName);
281 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetMethodOptimize);
282 EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
283 #endif
284 {
285     JSValue baseValue = JSValue::decode(encodedBase);
286     PropertySlot slot(baseValue);
287     JSValue result = baseValue.get(exec, *propertyName, slot);
288
289     MethodCallLinkInfo& methodInfo = exec->codeBlock()->getMethodCallLinkInfo(returnAddress);
290     if (methodInfo.seenOnce())
291         dfgRepatchGetMethod(exec, baseValue, *propertyName, slot, methodInfo);
292     else
293         methodInfo.setSeen();
294
295     return JSValue::encode(result);
296 }
297
298 #if CPU(X86_64)
299 EncodedJSValue operationGetByIdBuildListWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
300 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdBuildList);
301 EncodedJSValue operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
302 #elif CPU(X86)
303 EncodedJSValue operationGetByIdBuildListWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName);
304 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdBuildList);
305 EncodedJSValue operationGetByIdBuildListWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
306 #endif
307 {
308     JSValue baseValue = JSValue::decode(encodedBase);
309     PropertySlot slot(baseValue);
310     JSValue result = baseValue.get(exec, *propertyName, slot);
311
312     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
313     dfgBuildGetByIDList(exec, baseValue, *propertyName, slot, stubInfo);
314
315     return JSValue::encode(result);
316 }
317
318 #if CPU(X86_64)
319 EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
320 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdProtoBuildList);
321 EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
322 #elif CPU(X86)
323 EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName);
324 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdProtoBuildList);
325 EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
326 #endif
327 {
328     JSValue baseValue = JSValue::decode(encodedBase);
329     PropertySlot slot(baseValue);
330     JSValue result = baseValue.get(exec, *propertyName, slot);
331
332     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
333     dfgBuildGetByIDProtoList(exec, baseValue, *propertyName, slot, stubInfo);
334
335     return JSValue::encode(result);
336 }
337
338 #if CPU(X86_64)
339 EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
340 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdOptimize);
341 EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
342 #elif CPU(X86)
343 EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName);
344 FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdOptimize);
345 EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
346 #endif
347 {
348     JSValue baseValue = JSValue::decode(encodedBase);
349     PropertySlot slot(baseValue);
350     JSValue result = baseValue.get(exec, *propertyName, slot);
351
352     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
353     if (stubInfo.seen)
354         dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo);
355     else
356         stubInfo.seen = true;
357
358     return JSValue::encode(result);
359 }
360
361 void operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
362 {
363     operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue);
364 }
365
366 void operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
367 {
368     operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
369 }
370
371 void operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
372 {
373     // We should only get here if index is outside the existing vector.
374     ASSERT(!array->canSetIndex(index));
375     array->JSArray::put(exec, index, JSValue::decode(encodedValue));
376 }
377
378 void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
379 {
380     PutPropertySlot slot(true);
381     JSValue::decode(encodedBase).put(exec, *propertyName, JSValue::decode(encodedValue), slot);
382 }
383
384 void operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
385 {
386     PutPropertySlot slot(false);
387     JSValue::decode(encodedBase).put(exec, *propertyName, JSValue::decode(encodedValue), slot);
388 }
389
390 void operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
391 {
392     PutPropertySlot slot(true);
393     JSValue::decode(encodedBase).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
394 }
395
396 void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
397 {
398     PutPropertySlot slot(false);
399     JSValue::decode(encodedBase).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
400 }
401
402 #if CPU(X86_64)
403 void operationPutByIdStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*, ReturnAddressPtr);
404 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdStrictOptimize);
405 void operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
406 #elif CPU(X86)
407 void operationPutByIdStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName);
408 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdStrictOptimize);
409 void operationPutByIdStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
410 #endif
411 {
412     JSValue value = JSValue::decode(encodedValue);
413     JSValue base = JSValue::decode(encodedBase);
414     PutPropertySlot slot(true);
415     
416     base.put(exec, *propertyName, value, slot);
417     
418     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
419     if (stubInfo.seen)
420         dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, NotDirect);
421     else
422         stubInfo.seen = true;
423 }
424
425 #if CPU(X86_64)
426 void operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*, ReturnAddressPtr);
427 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdNonStrictOptimize);
428 void operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
429 #elif CPU(X86)
430 void operationPutByIdNonStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName);
431 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdNonStrictOptimize);
432 void operationPutByIdNonStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
433 #endif
434 {
435     JSValue value = JSValue::decode(encodedValue);
436     JSValue base = JSValue::decode(encodedBase);
437     PutPropertySlot slot(false);
438     
439     base.put(exec, *propertyName, value, slot);
440     
441     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
442     if (stubInfo.seen)
443         dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, NotDirect);
444     else
445         stubInfo.seen = true;
446 }
447
448 #if CPU(X86_64)
449 void operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*, ReturnAddressPtr);
450 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectStrictOptimize);
451 void operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
452 #elif CPU(X86)
453 void operationPutByIdDirectStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName);
454 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectStrictOptimize);
455 void operationPutByIdDirectStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
456 #endif
457 {
458     JSValue value = JSValue::decode(encodedValue);
459     JSValue base = JSValue::decode(encodedBase);
460     PutPropertySlot slot(true);
461     
462     base.putDirect(exec, *propertyName, value, slot);
463     
464     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
465     if (stubInfo.seen)
466         dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct);
467     else
468         stubInfo.seen = true;
469 }
470
471 #if CPU(X86_64)
472 void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue, EncodedJSValue, Identifier*, ReturnAddressPtr);
473 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectNonStrictOptimize);
474 void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
475 #elif CPU(X86)
476 void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName);
477 FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectNonStrictOptimize);
478 void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
479 #endif
480 {
481     JSValue value = JSValue::decode(encodedValue);
482     JSValue base = JSValue::decode(encodedBase);
483     PutPropertySlot slot(false);
484     
485     base.putDirect(exec, *propertyName, value, slot);
486     
487     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
488     if (stubInfo.seen)
489         dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct);
490     else
491         stubInfo.seen = true;
492 }
493
494 RegisterSizedBoolean operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
495 {
496     return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
497 }
498
499 RegisterSizedBoolean operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
500 {
501     return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
502 }
503
504 RegisterSizedBoolean operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
505 {
506     return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
507 }
508
509 RegisterSizedBoolean operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
510 {
511     return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
512 }
513
514 RegisterSizedBoolean operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
515 {
516     return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
517 }
518
519 RegisterSizedBoolean operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
520 {
521     JSValue op1 = JSValue::decode(encodedOp1);
522     JSValue op2 = JSValue::decode(encodedOp2);
523     
524     ASSERT(op1.isCell());
525     ASSERT(op2.isCell());
526     
527     return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
528 }
529
530 RegisterSizedBoolean operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
531 {
532     return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
533 }
534
535 EncodedJSValue getHostCallReturnValue();
536 EncodedJSValue getHostCallReturnValueWithExecState(ExecState*);
537
538 #if CPU(X86_64)
539 asm (
540 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
541 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
542     "mov -40(%r13), %r13\n"
543     "mov %r13, %rdi\n"
544     "jmp " SYMBOL_STRING(getHostCallReturnValueWithExecState) "\n"
545 );
546 #elif CPU(X86)
547 asm (
548 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
549 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
550     "mov -40(%edi), %edi\n"
551     "push %edi\n"
552     "jmp " SYMBOL_STRING(getHostCallReturnValueWithExecState) "\n"
553 );
554 #endif
555
556 EncodedJSValue getHostCallReturnValueWithExecState(ExecState* exec)
557 {
558     return JSValue::encode(exec->globalData().hostCallReturnValue);
559 }
560
561 static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind)
562 {
563     ExecState* exec = execCallee->callerFrame();
564     JSGlobalData* globalData = &exec->globalData();
565     if (kind == CodeForCall) {
566         CallData callData;
567         CallType callType = getCallData(callee, callData);
568     
569         ASSERT(callType != CallTypeJS);
570     
571         if (callType == CallTypeHost) {
572             if (!globalData->interpreter->registerFile().grow(execCallee->registers())) {
573                 globalData->exception = createStackOverflowError(exec);
574                 return 0;
575             }
576         
577             execCallee->setScopeChain(exec->scopeChain());
578         
579             globalData->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee));
580         
581             if (globalData->exception)
582                 return 0;
583             return reinterpret_cast<void*>(getHostCallReturnValue);
584         }
585     
586         ASSERT(callType == CallTypeNone);
587         exec->globalData().exception = createNotAFunctionError(exec, callee);
588         return 0;
589     }
590
591     ASSERT(kind == CodeForConstruct);
592     
593     ConstructData constructData;
594     ConstructType constructType = getConstructData(callee, constructData);
595     
596     ASSERT(constructType != ConstructTypeJS);
597     
598     if (constructType == ConstructTypeHost) {
599         if (!globalData->interpreter->registerFile().grow(execCallee->registers())) {
600             globalData->exception = createStackOverflowError(exec);
601             return 0;
602         }
603         
604         execCallee->setScopeChain(exec->scopeChain());
605         
606         globalData->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee));
607         
608         if (globalData->exception)
609             return 0;
610         return reinterpret_cast<void*>(getHostCallReturnValue);
611     }
612     
613     ASSERT(constructType == ConstructTypeNone);
614     exec->globalData().exception = createNotAConstructorError(exec, callee);
615     return 0;
616 }
617
618 inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, CodeSpecializationKind kind)
619 {
620     ExecState* exec = execCallee->callerFrame();
621     JSGlobalData* globalData = &exec->globalData();
622     JSValue calleeAsValue = execCallee->calleeAsValue();
623     JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
624     if (!calleeAsFunctionCell)
625         return handleHostCall(execCallee, calleeAsValue, kind);
626     JSFunction* callee = asFunction(calleeAsFunctionCell);
627     ExecutableBase* executable = callee->executable();
628     
629     MacroAssemblerCodePtr codePtr;
630     CodeBlock* codeBlock = 0;
631     if (executable->isHostFunction())
632         codePtr = executable->generatedJITCodeFor(kind).addressForCall();
633     else {
634         execCallee->setScopeChain(callee->scope());
635         FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
636         JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind);
637         if (error) {
638             globalData->exception = createStackOverflowError(exec);
639             return 0;
640         }
641         codeBlock = &functionExecutable->generatedBytecodeFor(kind);
642         if (execCallee->argumentCountIncludingThis() == static_cast<size_t>(codeBlock->m_numParameters))
643             codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall();
644         else
645             codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind);
646     }
647     CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(returnAddress);
648     if (!callLinkInfo.seenOnce())
649         callLinkInfo.setSeen();
650     else
651         dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind);
652     return codePtr.executableAddress();
653 }
654
655 #if CPU(X86_64)
656 void* operationLinkCallWithReturnAddress(ExecState*, ReturnAddressPtr);
657 FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(operationLinkCall);
658 void* operationLinkCallWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress)
659 #elif CPU(X86)
660 void* operationLinkCallWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* execCallee);
661 FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(operationLinkCall);
662 void* operationLinkCallWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* execCallee)
663 #endif
664 {
665     return linkFor(execCallee, returnAddress, CodeForCall);
666 }
667
668 #if CPU(X86_64)
669 void* operationLinkConstructWithReturnAddress(ExecState*, ReturnAddressPtr);
670 FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(operationLinkConstruct);
671 void* operationLinkConstructWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress)
672 #elif CPU(X86)
673 void* operationLinkConstructWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* execCallee);
674 FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(operationLinkConstruct);
675 void* operationLinkConstructWithReturnAddress(ReturnAddressPtr returnAddress, ExecState* execCallee)
676 #endif
677 {
678     return linkFor(execCallee, returnAddress, CodeForConstruct);
679 }
680
681 inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
682 {
683     ExecState* exec = execCallee->callerFrame();
684     JSValue calleeAsValue = execCallee->calleeAsValue();
685     JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
686     if (UNLIKELY(!calleeAsFunctionCell))
687         return handleHostCall(execCallee, calleeAsValue, kind);
688     
689     JSFunction* function = asFunction(calleeAsFunctionCell);
690     execCallee->setScopeChain(function->scopeUnchecked());
691     ExecutableBase* executable = function->executable();
692     if (UNLIKELY(!executable->hasJITCodeFor(kind))) {
693         FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
694         JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind);
695         if (error) {
696             exec->globalData().exception = error;
697             return 0;
698         }
699     }
700     return executable->generatedJITCodeWithArityCheckFor(kind).executableAddress();
701 }
702
703 void* operationVirtualCall(ExecState* execCallee)
704 {
705     return virtualFor(execCallee, CodeForCall);
706 }
707
708 void* operationVirtualConstruct(ExecState* execCallee)
709 {
710     return virtualFor(execCallee, CodeForConstruct);
711 }
712
713 EncodedJSValue operationInstanceOf(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, EncodedJSValue encodedPrototype)
714 {
715     JSValue value = JSValue::decode(encodedValue);
716     JSValue base = JSValue::decode(encodedBase);
717     JSValue prototype = JSValue::decode(encodedPrototype);
718
719     // Otherwise CheckHasInstance should have failed.
720     ASSERT(base.isCell());
721     // At least one of these checks must have failed to get to the slow case.
722     ASSERT(!value.isCell()
723         || !prototype.isCell()
724         || !prototype.isObject()
725         || !base.asCell()->structure()->typeInfo().implementsDefaultHasInstance());
726
727
728     // ECMA-262 15.3.5.3:
729     // Throw an exception either if base is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
730     TypeInfo typeInfo(UnspecifiedType);
731     if (!base.isObject() || !(typeInfo = asObject(base)->structure()->typeInfo()).implementsHasInstance()) {
732         throwError(exec, createInvalidParamError(exec, "instanceof", base));
733         return JSValue::encode(jsUndefined());
734     }
735
736     return JSValue::encode(jsBoolean(asObject(base)->hasInstance(exec, value, prototype)));
737 }
738
739 EncodedJSValue operationResolve(ExecState* exec, Identifier* propertyName)
740 {
741     ScopeChainNode* scopeChain = exec->scopeChain();
742     ScopeChainIterator iter = scopeChain->begin();
743     ScopeChainIterator end = scopeChain->end();
744     ASSERT(iter != end);
745
746     do {
747         JSObject* record = iter->get();
748         PropertySlot slot(record);
749         if (record->getPropertySlot(exec, *propertyName, slot))
750             return JSValue::encode(slot.getValue(exec, *propertyName));
751     } while (++iter != end);
752
753     return throwVMError(exec, createUndefinedVariableError(exec, *propertyName));
754 }
755
756 EncodedJSValue operationResolveBase(ExecState* exec, Identifier* propertyName)
757 {
758     return JSValue::encode(resolveBase(exec, *propertyName, exec->scopeChain(), false));
759 }
760
761 EncodedJSValue operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName)
762 {
763     JSValue base = resolveBase(exec, *propertyName, exec->scopeChain(), true);
764     if (!base)
765         throwError(exec, createErrorForInvalidGlobalAssignment(exec, propertyName->ustring()));
766     return JSValue::encode(base);
767 }
768
769 EncodedJSValue operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, Identifier* propertyName)
770 {
771     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
772
773     PropertySlot slot(globalObject);
774     if (globalObject->getPropertySlot(exec, *propertyName, slot)) {
775         JSValue result = slot.getValue(exec, *propertyName);
776
777         if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) {
778             resolveInfo->structure.set(exec->globalData(), exec->codeBlock()->ownerExecutable(), globalObject->structure());
779             resolveInfo->offset = slot.cachedOffset();
780         }
781
782         return JSValue::encode(result);
783     }
784
785     return throwVMError(exec, createUndefinedVariableError(exec, *propertyName));
786 }
787
788 EncodedJSValue operationToPrimitive(ExecState* exec, EncodedJSValue value)
789 {
790     return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
791 }
792
793 EncodedJSValue operationStrCat(ExecState* exec, void* start, size_t size)
794 {
795     return JSValue::encode(jsString(exec, static_cast<Register*>(start), size));
796 }
797
798 EncodedJSValue operationNewArray(ExecState* exec, void* start, size_t size)
799 {
800     ArgList argList(static_cast<Register*>(start), size);
801     return JSValue::encode(constructArray(exec, argList));
802 }
803
804 EncodedJSValue operationNewArrayBuffer(ExecState* exec, size_t start, size_t size)
805 {
806     ArgList argList(exec->codeBlock()->constantBuffer(start), size);
807     return JSValue::encode(constructArray(exec, argList));
808 }
809
810 EncodedJSValue operationNewRegexp(ExecState* exec, void* regexpPtr)
811 {
812     RegExp* regexp = static_cast<RegExp*>(regexpPtr);
813     if (!regexp->isValid()) {
814         throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
815         return JSValue::encode(jsUndefined());
816     }
817     
818     return RegExpObject::create(exec->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp);
819 }
820
821 void operationThrowHasInstanceError(ExecState* exec, EncodedJSValue encodedBase)
822 {
823     JSValue base = JSValue::decode(encodedBase);
824
825     // We should only call this function if base is not an object, or if it does not implement 'HasInstance'.
826     ASSERT(!base.isObject() || !asObject(base)->structure()->typeInfo().implementsHasInstance());
827
828     throwError(exec, createInvalidParamError(exec, "instanceof", base));
829 }
830
831 DFGHandler lookupExceptionHandler(ExecState* exec, ReturnAddressPtr faultLocation)
832 {
833     JSValue exceptionValue = exec->exception();
834     ASSERT(exceptionValue);
835
836     unsigned vPCIndex = exec->codeBlock()->bytecodeOffset(faultLocation);
837     HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex);
838
839     void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
840     ASSERT(catchRoutine);
841     return DFGHandler(exec, catchRoutine);
842 }
843
844 double dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
845 {
846     return JSValue::decode(value).toNumber(exec);
847 }
848
849 int32_t dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
850 {
851     return JSValue::decode(value).toInt32(exec);
852 }
853
854 RegisterSizedBoolean dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp)
855 {
856     return JSValue::decode(encodedOp).toBoolean(exec);
857 }
858
859 #if ENABLE(DFG_VERBOSE_SPECULATION_FAILURE)
860 void debugOperationPrintSpeculationFailure(ExecState*, void* debugInfoRaw)
861 {
862     SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
863     CodeBlock* codeBlock = debugInfo->codeBlock;
864     printf("Speculation failure in %p at 0x%x with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, success/fail %u/%u\n", codeBlock, debugInfo->debugOffset, codeBlock->alternative()->executeCounter(), codeBlock->alternative()->reoptimizationRetryCounter(), codeBlock->alternative()->optimizationDelayCounter(), codeBlock->speculativeSuccessCounter(), codeBlock->speculativeFailCounter());
865 }
866 #endif
867
868 } // extern "C"
869 } } // namespace JSC::DFG
870
871 #endif