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