6acde8231421894e03900bccff7efb4d208ea70b
[WebKit-https.git] / Source / JavaScriptCore / jit / JITOperations.cpp
1 /*
2  * Copyright (C) 2013 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 #if ENABLE(JIT)
28 #include "JITOperations.h"
29
30 #include "CommonSlowPaths.h"
31 #include "Error.h"
32 #include "GetterSetter.h"
33 #include "HostCallReturnValue.h"
34 #include "JITOperationWrappers.h"
35 #include "JSGlobalObjectFunctions.h"
36 #include "Operations.h"
37 #include "Repatch.h"
38
39 namespace JSC {
40
41 extern "C" {
42
43 #if COMPILER(MSVC)
44 void * _ReturnAddress(void);
45 #pragma intrinsic(_ReturnAddress)
46
47 #define OUR_RETURN_ADDRESS _ReturnAddress()
48 #else
49 #define OUR_RETURN_ADDRESS __builtin_return_address(0)
50 #endif
51
52 #if ENABLE(OPCODE_SAMPLING)
53 #define CTI_SAMPLER vm->interpreter->sampler()
54 #else
55 #define CTI_SAMPLER 0
56 #endif
57
58
59 void JIT_OPERATION operationStackCheck(ExecState* exec, CodeBlock* codeBlock)
60 {
61     // We pass in our own code block, because the callframe hasn't been populated.
62     VM* vm = codeBlock->vm();
63     CallFrame* callerFrame = exec->callerFrame();
64     NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
65
66     JSStack& stack = vm->interpreter->stack();
67
68     if (UNLIKELY(!stack.grow(&exec->registers()[-codeBlock->m_numCalleeRegisters])))
69         vm->throwException(callerFrame, createStackOverflowError(callerFrame));
70 }
71
72 int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec)
73 {
74     VM* vm = &exec->vm();
75     CallFrame* callerFrame = exec->callerFrame();
76     NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
77
78     JSStack& stack = vm->interpreter->stack();
79
80     int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForCall);
81     if (missingArgCount < 0)
82         vm->throwException(callerFrame, createStackOverflowError(callerFrame));
83
84     return missingArgCount;
85 }
86
87 int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec)
88 {
89     VM* vm = &exec->vm();
90     CallFrame* callerFrame = exec->callerFrame();
91     NativeCallFrameTracer tracer(vm, callerFrame->removeHostCallFrameFlag());
92
93     JSStack& stack = vm->interpreter->stack();
94
95     int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForConstruct);
96     if (missingArgCount < 0)
97         vm->throwException(callerFrame, createStackOverflowError(callerFrame));
98
99     return missingArgCount;
100 }
101
102 EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, StringImpl* uid)
103 {
104     VM* vm = &exec->vm();
105     NativeCallFrameTracer tracer(vm, exec);
106     
107     JSValue baseValue = JSValue::decode(base);
108     PropertySlot slot(baseValue);
109     Identifier ident(vm, uid);
110     return JSValue::encode(baseValue.get(exec, ident, slot));
111 }
112
113 J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdBuildList);
114 EncodedJSValue JIT_OPERATION operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, StringImpl* uid, ReturnAddressPtr returnAddress)
115 {
116     VM* vm = &exec->vm();
117     NativeCallFrameTracer tracer(vm, exec);
118
119     Identifier ident(vm, uid);
120     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
121     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
122
123     JSValue baseValue = JSValue::decode(base);
124     PropertySlot slot(baseValue);
125     JSValue result = baseValue.get(exec, ident, slot);
126
127     if (accessType == static_cast<AccessType>(stubInfo.accessType))
128         buildGetByIDList(exec, baseValue, ident, slot, stubInfo);
129
130     return JSValue::encode(result);
131 }
132
133 J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdOptimize);
134 EncodedJSValue JIT_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue base, StringImpl* uid, ReturnAddressPtr returnAddress)
135 {
136     VM* vm = &exec->vm();
137     NativeCallFrameTracer tracer(vm, exec);
138     Identifier ident = uid->isEmptyUnique() ? Identifier::from(PrivateName(uid)) : Identifier(vm, uid);
139     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
140     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
141
142     JSValue baseValue = JSValue::decode(base);
143     PropertySlot slot(baseValue);
144     JSValue result = baseValue.get(exec, ident, slot);
145     
146     if (accessType == static_cast<AccessType>(stubInfo.accessType)) {
147         if (stubInfo.seen)
148             repatchGetByID(exec, baseValue, ident, slot, stubInfo);
149         else
150             stubInfo.seen = true;
151     }
152
153     return JSValue::encode(result);
154 }
155
156 J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(operationInOptimize);
157 EncodedJSValue JIT_OPERATION operationInOptimizeWithReturnAddress(ExecState* exec, JSCell* base, StringImpl* key, ReturnAddressPtr returnAddress)
158 {
159     VM* vm = &exec->vm();
160     NativeCallFrameTracer tracer(vm, exec);
161     
162     if (!base->isObject()) {
163         vm->throwException(exec, createInvalidParameterError(exec, "in", base));
164         return JSValue::encode(jsUndefined());
165     }
166     
167     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
168     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
169
170     Identifier ident(vm, key);
171     PropertySlot slot(base);
172     bool result = asObject(base)->getPropertySlot(exec, ident, slot);
173     
174     RELEASE_ASSERT(accessType == stubInfo.accessType);
175     
176     if (stubInfo.seen)
177         repatchIn(exec, base, ident, result, slot, stubInfo);
178     else
179         stubInfo.seen = true;
180     
181     return JSValue::encode(jsBoolean(result));
182 }
183
184 EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, JSCell* base, StringImpl* key)
185 {
186     VM* vm = &exec->vm();
187     NativeCallFrameTracer tracer(vm, exec);
188
189     if (!base->isObject()) {
190         vm->throwException(exec, createInvalidParameterError(exec, "in", base));
191         return JSValue::encode(jsUndefined());
192     }
193
194     Identifier ident(vm, key);
195     return JSValue::encode(jsBoolean(asObject(base)->hasProperty(exec, ident)));
196 }
197
198 EncodedJSValue JIT_OPERATION operationGenericIn(ExecState* exec, JSCell* base, EncodedJSValue key)
199 {
200     VM* vm = &exec->vm();
201     NativeCallFrameTracer tracer(vm, exec);
202
203     return JSValue::encode(jsBoolean(CommonSlowPaths::opIn(exec, JSValue::decode(key), base)));
204 }
205
206 EncodedJSValue JIT_OPERATION operationCallCustomGetter(ExecState* exec, JSCell* base, PropertySlot::GetValueFunc function, StringImpl* uid)
207 {
208     VM* vm = &exec->vm();
209     NativeCallFrameTracer tracer(vm, exec);
210     
211     Identifier ident(vm, uid);
212     
213     return JSValue::encode(function(exec, asObject(base), ident));
214 }
215
216 EncodedJSValue JIT_OPERATION operationCallGetter(ExecState* exec, JSCell* base, JSCell* getterSetter)
217 {
218     VM* vm = &exec->vm();
219     NativeCallFrameTracer tracer(vm, exec);
220
221     return JSValue::encode(callGetter(exec, base, getterSetter));
222 }
223
224 void JIT_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid)
225 {
226     VM* vm = &exec->vm();
227     NativeCallFrameTracer tracer(vm, exec);
228     
229     Identifier ident(vm, uid);
230     PutPropertySlot slot(true, exec->codeBlock()->putByIdContext());
231     base->methodTable()->put(base, exec, ident, JSValue::decode(encodedValue), slot);
232 }
233
234 void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid)
235 {
236     VM* vm = &exec->vm();
237     NativeCallFrameTracer tracer(vm, exec);
238     
239     Identifier ident(vm, uid);
240     PutPropertySlot slot(false, exec->codeBlock()->putByIdContext());
241     base->methodTable()->put(base, exec, ident, JSValue::decode(encodedValue), slot);
242 }
243
244 void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid)
245 {
246     VM* vm = &exec->vm();
247     NativeCallFrameTracer tracer(vm, exec);
248     
249     Identifier ident(vm, uid);
250     PutPropertySlot slot(true, exec->codeBlock()->putByIdContext());
251     ASSERT(base->isObject());
252     asObject(base)->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
253 }
254
255 void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid)
256 {
257     VM* vm = &exec->vm();
258     NativeCallFrameTracer tracer(vm, exec);
259     
260     Identifier ident(vm, uid);
261     PutPropertySlot slot(false, exec->codeBlock()->putByIdContext());
262     ASSERT(base->isObject());
263     asObject(base)->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
264 }
265
266 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictOptimize);
267 void JIT_OPERATION operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
268 {
269     VM* vm = &exec->vm();
270     NativeCallFrameTracer tracer(vm, exec);
271     
272     Identifier ident(vm, uid);
273     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
274     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
275
276     JSValue value = JSValue::decode(encodedValue);
277     JSValue baseValue(base);
278     PutPropertySlot slot(true, exec->codeBlock()->putByIdContext());
279     
280     baseValue.put(exec, ident, value, slot);
281     
282     if (accessType != static_cast<AccessType>(stubInfo.accessType))
283         return;
284     
285     if (stubInfo.seen)
286         repatchPutByID(exec, baseValue, ident, slot, stubInfo, NotDirect);
287     else
288         stubInfo.seen = true;
289 }
290
291 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictOptimize);
292 void JIT_OPERATION operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
293 {
294     VM* vm = &exec->vm();
295     NativeCallFrameTracer tracer(vm, exec);
296     
297     Identifier ident(vm, uid);
298     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
299     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
300
301     JSValue value = JSValue::decode(encodedValue);
302     JSValue baseValue(base);
303     PutPropertySlot slot(false, exec->codeBlock()->putByIdContext());
304     
305     baseValue.put(exec, ident, value, slot);
306     
307     if (accessType != static_cast<AccessType>(stubInfo.accessType))
308         return;
309     
310     if (stubInfo.seen)
311         repatchPutByID(exec, baseValue, ident, slot, stubInfo, NotDirect);
312     else
313         stubInfo.seen = true;
314 }
315
316 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictOptimize);
317 void JIT_OPERATION operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
318 {
319     VM* vm = &exec->vm();
320     NativeCallFrameTracer tracer(vm, exec);
321     
322     Identifier ident(vm, uid);
323     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
324     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
325
326     JSValue value = JSValue::decode(encodedValue);
327     PutPropertySlot slot(true, exec->codeBlock()->putByIdContext());
328     
329     ASSERT(base->isObject());
330     asObject(base)->putDirect(exec->vm(), ident, value, slot);
331     
332     if (accessType != static_cast<AccessType>(stubInfo.accessType))
333         return;
334     
335     if (stubInfo.seen)
336         repatchPutByID(exec, base, ident, slot, stubInfo, Direct);
337     else
338         stubInfo.seen = true;
339 }
340
341 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictOptimize);
342 void JIT_OPERATION operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
343 {
344     VM* vm = &exec->vm();
345     NativeCallFrameTracer tracer(vm, exec);
346     
347     Identifier ident(vm, uid);
348     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
349     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
350
351     JSValue value = JSValue::decode(encodedValue);
352     PutPropertySlot slot(false, exec->codeBlock()->putByIdContext());
353     
354     ASSERT(base->isObject());
355     asObject(base)->putDirect(exec->vm(), ident, value, slot);
356     
357     if (accessType != static_cast<AccessType>(stubInfo.accessType))
358         return;
359     
360     if (stubInfo.seen)
361         repatchPutByID(exec, base, ident, slot, stubInfo, Direct);
362     else
363         stubInfo.seen = true;
364 }
365
366 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictBuildList);
367 void JIT_OPERATION operationPutByIdStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
368 {
369     VM* vm = &exec->vm();
370     NativeCallFrameTracer tracer(vm, exec);
371     
372     Identifier ident(vm, uid);
373     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
374     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
375
376     JSValue value = JSValue::decode(encodedValue);
377     JSValue baseValue(base);
378     PutPropertySlot slot(true, exec->codeBlock()->putByIdContext());
379     
380     baseValue.put(exec, ident, value, slot);
381     
382     if (accessType != static_cast<AccessType>(stubInfo.accessType))
383         return;
384     
385     buildPutByIdList(exec, baseValue, ident, slot, stubInfo, NotDirect);
386 }
387
388 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictBuildList);
389 void JIT_OPERATION operationPutByIdNonStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
390 {
391     VM* vm = &exec->vm();
392     NativeCallFrameTracer tracer(vm, exec);
393     
394     Identifier ident(vm, uid);
395     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
396     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
397
398     JSValue value = JSValue::decode(encodedValue);
399     JSValue baseValue(base);
400     PutPropertySlot slot(false, exec->codeBlock()->putByIdContext());
401     
402     baseValue.put(exec, ident, value, slot);
403     
404     if (accessType != static_cast<AccessType>(stubInfo.accessType))
405         return;
406     
407     buildPutByIdList(exec, baseValue, ident, slot, stubInfo, NotDirect);
408 }
409
410 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictBuildList);
411 void JIT_OPERATION operationPutByIdDirectStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
412 {
413     VM* vm = &exec->vm();
414     NativeCallFrameTracer tracer(vm, exec);
415     
416     Identifier ident(vm, uid);
417     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
418     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
419     
420     JSValue value = JSValue::decode(encodedValue);
421     PutPropertySlot slot(true, exec->codeBlock()->putByIdContext());
422     
423     ASSERT(base->isObject());
424     asObject(base)->putDirect(exec->vm(), ident, value, slot);
425     
426     if (accessType != static_cast<AccessType>(stubInfo.accessType))
427         return;
428     
429     buildPutByIdList(exec, base, ident, slot, stubInfo, Direct);
430 }
431
432 V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictBuildList);
433 void JIT_OPERATION operationPutByIdDirectNonStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, StringImpl* uid, ReturnAddressPtr returnAddress)
434 {
435     VM* vm = &exec->vm();
436     NativeCallFrameTracer tracer(vm, exec);
437     
438     Identifier ident(vm, uid);
439     StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
440     AccessType accessType = static_cast<AccessType>(stubInfo.accessType);
441
442     JSValue value = JSValue::decode(encodedValue);
443     PutPropertySlot slot(false, exec->codeBlock()->putByIdContext());
444     
445     ASSERT(base->isObject());
446     asObject(base)->putDirect(exec->vm(), ident, value, slot);
447     
448     if (accessType != static_cast<AccessType>(stubInfo.accessType))
449         return;
450     
451     buildPutByIdList(exec, base, ident, slot, stubInfo, Direct);
452 }
453
454 void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value)
455 {
456     VM& vm = exec->vm();
457     NativeCallFrameTracer tracer(&vm, exec);
458
459     ASSERT(structure->outOfLineCapacity() > base->structure()->outOfLineCapacity());
460     ASSERT(!vm.heap.storageAllocator().fastPathShouldSucceed(structure->outOfLineCapacity() * sizeof(JSValue)));
461     base->setStructureAndReallocateStorageIfNecessary(vm, structure);
462     base->putDirect(vm, offset, JSValue::decode(value));
463 }
464
465 EncodedJSValue JIT_OPERATION operationCallEval(ExecState* execCallee)
466 {
467     CallFrame* callerFrame = execCallee->callerFrame();
468     ASSERT(execCallee->callerFrame()->codeBlock()->codeType() != FunctionCode
469         || !execCallee->callerFrame()->codeBlock()->needsFullScopeChain()
470         || execCallee->callerFrame()->uncheckedR(execCallee->callerFrame()->codeBlock()->activationRegister().offset()).jsValue());
471
472     execCallee->setScope(callerFrame->scope());
473     execCallee->setReturnPC(static_cast<Instruction*>(OUR_RETURN_ADDRESS));
474     execCallee->setCodeBlock(0);
475
476     if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval))
477         return JSValue::encode(JSValue());
478
479     VM* vm = &execCallee->vm();
480     JSValue result = eval(execCallee);
481     if (vm->exception())
482         return EncodedJSValue();
483     
484     return JSValue::encode(result);
485 }
486
487 static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind)
488 {
489     ExecState* exec = execCallee->callerFrame();
490     VM* vm = &exec->vm();
491
492     execCallee->setScope(exec->scope());
493     execCallee->setCodeBlock(0);
494
495     if (kind == CodeForCall) {
496         CallData callData;
497         CallType callType = getCallData(callee, callData);
498     
499         ASSERT(callType != CallTypeJS);
500     
501         if (callType == CallTypeHost) {
502             NativeCallFrameTracer tracer(vm, execCallee);
503             execCallee->setCallee(asObject(callee));
504             vm->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee));
505             if (vm->exception())
506                 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
507
508             return reinterpret_cast<void*>(getHostCallReturnValue);
509         }
510     
511         ASSERT(callType == CallTypeNone);
512         exec->vm().throwException(exec, createNotAFunctionError(exec, callee));
513         return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
514     }
515
516     ASSERT(kind == CodeForConstruct);
517     
518     ConstructData constructData;
519     ConstructType constructType = getConstructData(callee, constructData);
520     
521     ASSERT(constructType != ConstructTypeJS);
522     
523     if (constructType == ConstructTypeHost) {
524         NativeCallFrameTracer tracer(vm, execCallee);
525         execCallee->setCallee(asObject(callee));
526         vm->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee));
527         if (vm->exception())
528             return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
529
530         return reinterpret_cast<void*>(getHostCallReturnValue);
531     }
532     
533     ASSERT(constructType == ConstructTypeNone);
534     exec->vm().throwException(exec, createNotAConstructorError(exec, callee));
535     return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
536 }
537
538 inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind)
539 {
540     ExecState* exec = execCallee->callerFrame();
541     VM* vm = &exec->vm();
542     NativeCallFrameTracer tracer(vm, exec);
543     
544     JSValue calleeAsValue = execCallee->calleeAsValue();
545     JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
546     if (!calleeAsFunctionCell)
547         return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
548
549     JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
550     execCallee->setScope(callee->scopeUnchecked());
551     ExecutableBase* executable = callee->executable();
552
553     MacroAssemblerCodePtr codePtr;
554     CodeBlock* codeBlock = 0;
555     CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC());
556     if (executable->isHostFunction())
557         codePtr = executable->generatedJITCodeFor(kind)->addressForCall();
558     else {
559         FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
560         JSObject* error = functionExecutable->prepareForExecution(execCallee, callee->scope(), kind);
561         if (error) {
562             vm->throwException(exec, createStackOverflowError(exec));
563             return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
564         }
565         codeBlock = functionExecutable->codeBlockFor(kind);
566         if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo.callType == CallLinkInfo::CallVarargs)
567             codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind);
568         else
569             codePtr = functionExecutable->generatedJITCodeFor(kind)->addressForCall();
570     }
571     if (!callLinkInfo.seenOnce())
572         callLinkInfo.setSeen();
573     else
574         linkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind);
575     return reinterpret_cast<char*>(codePtr.executableAddress());
576 }
577
578 char* JIT_OPERATION operationLinkCall(ExecState* execCallee)
579 {
580     return linkFor(execCallee, CodeForCall);
581 }
582
583 char* JIT_OPERATION operationLinkConstruct(ExecState* execCallee)
584 {
585     return linkFor(execCallee, CodeForConstruct);
586 }
587
588 inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell)
589 {
590     ExecState* exec = execCallee->callerFrame();
591     VM* vm = &exec->vm();
592     NativeCallFrameTracer tracer(vm, exec);
593
594     JSValue calleeAsValue = execCallee->calleeAsValue();
595     calleeAsFunctionCell = getJSFunction(calleeAsValue);
596     if (UNLIKELY(!calleeAsFunctionCell))
597         return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
598     
599     JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell);
600     execCallee->setScope(function->scopeUnchecked());
601     ExecutableBase* executable = function->executable();
602     if (UNLIKELY(!executable->hasJITCodeFor(kind))) {
603         FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
604         JSObject* error = functionExecutable->prepareForExecution(execCallee, function->scope(), kind);
605         if (error) {
606             exec->vm().throwException(execCallee, error);
607             return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
608         }
609     }
610     return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress());
611 }
612
613 inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
614 {
615     JSCell* calleeAsFunctionCellIgnored;
616     return virtualForWithFunction(execCallee, kind, calleeAsFunctionCellIgnored);
617 }
618
619 static bool attemptToOptimizeClosureCall(ExecState* execCallee, JSCell* calleeAsFunctionCell, CallLinkInfo& callLinkInfo)
620 {
621     if (!calleeAsFunctionCell)
622         return false;
623     
624     JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
625     JSFunction* oldCallee = callLinkInfo.callee.get();
626     
627     if (!oldCallee
628         || oldCallee->structure() != callee->structure()
629         || oldCallee->executable() != callee->executable())
630         return false;
631     
632     ASSERT(callee->executable()->hasJITCodeForCall());
633     MacroAssemblerCodePtr codePtr = callee->executable()->generatedJITCodeForCall()->addressForCall();
634     
635     CodeBlock* codeBlock;
636     if (callee->executable()->isHostFunction())
637         codeBlock = 0;
638     else {
639         codeBlock = jsCast<FunctionExecutable*>(callee->executable())->codeBlockForCall();
640         if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()))
641             return false;
642     }
643     
644     linkClosureCall(
645         execCallee, callLinkInfo, codeBlock,
646         callee->structure(), callee->executable(), codePtr);
647     
648     return true;
649 }
650
651 char* JIT_OPERATION operationLinkClosureCall(ExecState* execCallee)
652 {
653     JSCell* calleeAsFunctionCell;
654     char* result = virtualForWithFunction(execCallee, CodeForCall, calleeAsFunctionCell);
655     CallLinkInfo& callLinkInfo = execCallee->callerFrame()->codeBlock()->getCallLinkInfo(execCallee->returnPC());
656
657     if (!attemptToOptimizeClosureCall(execCallee, calleeAsFunctionCell, callLinkInfo))
658         linkSlowFor(execCallee, callLinkInfo, CodeForCall);
659     
660     return result;
661 }
662
663 char* JIT_OPERATION operationVirtualCall(ExecState* execCallee)
664 {    
665     return virtualFor(execCallee, CodeForCall);
666 }
667
668 char* JIT_OPERATION operationVirtualConstruct(ExecState* execCallee)
669 {
670     return virtualFor(execCallee, CodeForConstruct);
671 }
672
673
674 size_t JIT_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
675 {
676     VM* vm = &exec->vm();
677     NativeCallFrameTracer tracer(vm, exec);
678     
679     return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
680 }
681
682 size_t JIT_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
683 {
684     VM* vm = &exec->vm();
685     NativeCallFrameTracer tracer(vm, exec);
686
687     return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
688 }
689
690 size_t JIT_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
691 {
692     VM* vm = &exec->vm();
693     NativeCallFrameTracer tracer(vm, exec);
694
695     return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
696 }
697
698 size_t JIT_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
699 {
700     VM* vm = &exec->vm();
701     NativeCallFrameTracer tracer(vm, exec);
702
703     return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
704 }
705
706 size_t JIT_OPERATION operationConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp)
707 {
708     VM* vm = &exec->vm();
709     NativeCallFrameTracer tracer(vm, exec);
710     
711     return JSValue::decode(encodedOp).toBoolean(exec);
712 }
713
714 size_t JIT_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
715 {
716     VM* vm = &exec->vm();
717     NativeCallFrameTracer tracer(vm, exec);
718
719     return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
720 }
721
722 #if USE(JSVALUE64)
723 EncodedJSValue JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right)
724 #else
725 size_t JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right)
726 #endif
727 {
728     VM* vm = &exec->vm();
729     NativeCallFrameTracer tracer(vm, exec);
730
731     bool result = asString(left)->value(exec) == asString(right)->value(exec);
732 #if USE(JSVALUE64)
733     return JSValue::encode(jsBoolean(result));
734 #else
735     return result;
736 #endif
737 }
738
739 size_t JIT_OPERATION operationHasProperty(ExecState* exec, JSObject* base, JSString* property)
740 {
741     int result = base->hasProperty(exec, Identifier(exec, property->value(exec)));
742     return result;
743 }
744     
745
746 EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr)
747 {
748     VM& vm = exec->vm();
749     NativeCallFrameTracer tracer(&vm, exec);
750     RegExp* regexp = static_cast<RegExp*>(regexpPtr);
751     if (!regexp->isValid()) {
752         vm.throwException(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
753         return JSValue::encode(jsUndefined());
754     }
755
756     return JSValue::encode(RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regexp));
757 }
758
759 JITHandlerEncoded JIT_OPERATION lookupExceptionHandler(ExecState* exec)
760 {
761     VM* vm = &exec->vm();
762     NativeCallFrameTracer tracer(vm, exec);
763
764     JSValue exceptionValue = exec->exception();
765     ASSERT(exceptionValue);
766     
767     ExceptionHandler handler = genericUnwind(vm, exec, exceptionValue);
768     ASSERT(handler.catchRoutine);
769     return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine);
770 }
771
772 } // extern "C"
773
774 // Note: getHostCallReturnValueWithExecState() needs to be placed before the
775 // definition of getHostCallReturnValue() below because the Windows build
776 // requires it.
777 extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec)
778 {
779     if (!exec)
780         return JSValue::encode(JSValue());
781     return JSValue::encode(exec->vm().hostCallReturnValue);
782 }
783
784 #if COMPILER(GCC) && CPU(X86_64)
785 asm (
786 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
787 HIDE_SYMBOL(getHostCallReturnValue) "\n"
788 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
789     "mov 40(%r13), %r13\n"
790     "mov %r13, %rdi\n"
791     "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
792 );
793
794 #elif COMPILER(GCC) && CPU(X86)
795 asm (
796 ".text" "\n" \
797 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
798 HIDE_SYMBOL(getHostCallReturnValue) "\n"
799 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
800     "mov 40(%edi), %edi\n"
801     "mov %edi, 4(%esp)\n"
802     "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
803 );
804
805 #elif COMPILER(GCC) && CPU(ARM_THUMB2)
806 asm (
807 ".text" "\n"
808 ".align 2" "\n"
809 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
810 HIDE_SYMBOL(getHostCallReturnValue) "\n"
811 ".thumb" "\n"
812 ".thumb_func " THUMB_FUNC_PARAM(getHostCallReturnValue) "\n"
813 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
814     "ldr r5, [r5, #40]" "\n"
815     "mov r0, r5" "\n"
816     "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
817 );
818
819 #elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
820 asm (
821 ".text" "\n"
822 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
823 HIDE_SYMBOL(getHostCallReturnValue) "\n"
824 INLINE_ARM_FUNCTION(getHostCallReturnValue)
825 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
826     "ldr r5, [r5, #40]" "\n"
827     "mov r0, r5" "\n"
828     "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
829 );
830
831 #elif COMPILER(GCC) && CPU(MIPS)
832 asm (
833 ".text" "\n"
834 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
835 HIDE_SYMBOL(getHostCallReturnValue) "\n"
836 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
837     LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState)
838     "lw $s0, 40($s0)" "\n"
839     "move $a0, $s0" "\n"
840     "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
841 );
842
843 #elif COMPILER(GCC) && CPU(SH4)
844 asm (
845 ".text" "\n"
846 ".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
847 HIDE_SYMBOL(getHostCallReturnValue) "\n"
848 SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
849     "add #40, r14" "\n"
850     "mov.l @r14, r14" "\n"
851     "mov r14, r4" "\n"
852     "mov.l 2f, " SH4_SCRATCH_REGISTER "\n"
853     "braf " SH4_SCRATCH_REGISTER "\n"
854     "nop" "\n"
855     "1: .balign 4" "\n"
856     "2: .long " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "-1b\n"
857 );
858
859 #elif COMPILER(MSVC) && CPU(X86)
860 extern "C" {
861     __declspec(naked) EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValue()
862     {
863         __asm {
864             mov edi, [edi + 40];
865             mov [esp + 4], edi;
866             jmp getHostCallReturnValueWithExecState
867         }
868     }
869 }
870 #endif
871
872 } // namespace JSC
873
874 #endif // ENABLE(JIT)