d78822661ab5c39ffd3059e6bdf78273dab307e7
[WebKit-https.git] / JavaScriptCore / jit / JITCall.cpp
1 /*
2  * Copyright (C) 2008 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 "JIT.h"
28
29 #if ENABLE(JIT)
30
31 #include "CodeBlock.h"
32 #include "JITInlineMethods.h"
33 #include "JSArray.h"
34 #include "JSFunction.h"
35 #include "Interpreter.h"
36 #include "ResultType.h"
37 #include "SamplingTool.h"
38
39 #ifndef NDEBUG
40 #include <stdio.h>
41 #endif
42
43 using namespace std;
44
45 namespace JSC {
46
47 void JIT::unlinkCall(CallLinkInfo* callLinkInfo)
48 {
49     // When the JSFunction is deleted the pointer embedded in the instruction stream will no longer be valid
50     // (and, if a new JSFunction happened to be constructed at the same location, we could get a false positive
51     // match).  Reset the check so it no longer matches.
52     reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = asPointer(JSImmediate::impossibleValue());
53 }
54
55 void JIT::linkCall(JSFunction* callee, CodeBlock* calleeCodeBlock, void* ctiCode, CallLinkInfo* callLinkInfo, int callerArgCount)
56 {
57     // Currently we only link calls with the exact number of arguments.
58     if (callerArgCount == calleeCodeBlock->m_numParameters) {
59         ASSERT(!callLinkInfo->isLinked());
60     
61         calleeCodeBlock->addCaller(callLinkInfo);
62     
63         reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = callee;
64         ctiRepatchCallByReturnAddress(callLinkInfo->hotPathOther, ctiCode);
65     }
66
67     // repatch the instruction that jumps out to the cold path, so that we only try to link once.
68     void* repatchCheck = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(callLinkInfo->hotPathBegin) + repatchOffsetOpCallCall);
69     ctiRepatchCallByReturnAddress(repatchCheck, callLinkInfo->coldPathOther);
70 }
71
72 void JIT::compileOpCallInitializeCallFrame()
73 {
74     store32(X86::edx, Address(X86::edi, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
75
76     loadPtr(Address(X86::ecx, FIELD_OFFSET(JSFunction, m_scopeChain) + FIELD_OFFSET(ScopeChain, m_node)), X86::edx); // newScopeChain
77
78     storePtr(ImmPtr(noValue()), Address(X86::edi, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register))));
79     storePtr(X86::ecx, Address(X86::edi, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
80     storePtr(X86::edx, Address(X86::edi, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
81 }
82
83 void JIT::compileOpCallSetupArgs(Instruction* instruction)
84 {
85     int argCount = instruction[3].u.operand;
86     int registerOffset = instruction[4].u.operand;
87
88     // ecx holds func
89     emitPutCTIArg(X86::ecx, 0);
90     emitPutCTIArgConstant(registerOffset, 4);
91     emitPutCTIArgConstant(argCount, 8);
92     emitPutCTIArgConstant(reinterpret_cast<unsigned>(instruction), 12);
93 }
94
95 void JIT::compileOpCallEvalSetupArgs(Instruction* instruction)
96 {
97     int argCount = instruction[3].u.operand;
98     int registerOffset = instruction[4].u.operand;
99
100     // ecx holds func
101     emitPutCTIArg(X86::ecx, 0);
102     emitPutCTIArgConstant(registerOffset, 4);
103     emitPutCTIArgConstant(argCount, 8);
104 }
105
106 void JIT::compileOpConstructSetupArgs(Instruction* instruction)
107 {
108     int argCount = instruction[3].u.operand;
109     int registerOffset = instruction[4].u.operand;
110     int proto = instruction[5].u.operand;
111     int thisRegister = instruction[6].u.operand;
112
113     // ecx holds func
114     emitPutCTIArg(X86::ecx, 0);
115     emitPutCTIArgConstant(registerOffset, 4);
116     emitPutCTIArgConstant(argCount, 8);
117     emitPutCTIArgFromVirtualRegister(proto, 12, X86::eax);
118     emitPutCTIArgConstant(thisRegister, 16);
119 }
120
121 #if !ENABLE(JIT_OPTIMIZE_CALL)
122
123 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
124 {
125     int dst = instruction[1].u.operand;
126     int callee = instruction[2].u.operand;
127     int argCount = instruction[3].u.operand;
128     int registerOffset = instruction[4].u.operand;
129
130     // Handle eval
131     Jump wasEval;
132     if (opcodeID == op_call_eval) {
133         emitGetVirtualRegister(callee, X86::ecx);
134         compileOpCallEvalSetupArgs(instruction);
135
136         emitCTICall(Interpreter::cti_op_call_eval);
137         wasEval = jnePtr(ImmPtr(JSImmediate::impossibleValue()), X86::eax);
138     }
139
140     emitGetVirtualRegister(callee, X86::ecx);
141     // The arguments have been set up on the hot path for op_call_eval
142     if (opcodeID == op_call)
143         compileOpCallSetupArgs(instruction);
144     else if (opcodeID == op_construct)
145         compileOpConstructSetupArgs(instruction);
146
147     // Check for JSFunctions.
148     emitJumpSlowCaseIfNotJSCell(X86::ecx);
149     addSlowCase(jnePtr(X86::ecx, ImmPtr(m_interpreter->m_jsFunctionVptr)));
150
151     // First, in the case of a construct, allocate the new object.
152     if (opcodeID == op_construct) {
153         emitCTICall(Interpreter::cti_op_construct_JSConstruct);
154         emitPutVirtualRegister(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
155         emitGetVirtualRegister(callee, X86::ecx);
156     }
157
158     // Speculatively roll the callframe, assuming argCount will match the arity.
159     storePtr(X86::edi, Address(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
160     addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), X86::edi);
161     move(Imm32(argCount), X86::edx);
162
163     emitNakedCall(m_interpreter->m_ctiVirtualCall);
164
165     if (opcodeID == op_call_eval)
166         wasEval.link(this);
167
168     // Put the return value in dst. In the interpreter, op_ret does this.
169     emitPutVirtualRegister(dst);
170
171 #if ENABLE(CODEBLOCK_SAMPLING)
172     storePtr(ImmPtr(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
173 #endif
174 }
175
176 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
177 {
178     int dst = instruction[1].u.operand;
179
180     linkSlowCase(iter);
181     linkSlowCase(iter);
182
183     // This handles host functions
184     emitCTICall(((opcodeID == op_construct) ? Interpreter::cti_op_construct_NotJSConstruct : Interpreter::cti_op_call_NotJSFunction));
185     // Put the return value in dst. In the interpreter, op_ret does this.
186     emitPutVirtualRegister(dst);
187
188 #if ENABLE(CODEBLOCK_SAMPLING)
189     storePtr(ImmPtr(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
190 #endif
191 }
192
193 #else
194
195 static void unreachable()
196 {
197     ASSERT_NOT_REACHED();
198     exit(1);
199 }
200
201 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
202 {
203     int dst = instruction[1].u.operand;
204     int callee = instruction[2].u.operand;
205     int argCount = instruction[3].u.operand;
206     int registerOffset = instruction[4].u.operand;
207
208     // Handle eval
209     JmpSrc wasEval;
210     if (opcodeID == op_call_eval) {
211         emitGetVirtualRegister(callee, X86::ecx);
212         compileOpCallEvalSetupArgs(instruction);
213
214         emitCTICall(Interpreter::cti_op_call_eval);
215         __ cmpl_i32r(asInteger(JSImmediate::impossibleValue()), X86::eax);
216         wasEval = __ jne();
217     }
218
219     // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
220     // This deliberately leaves the callee in ecx, used when setting up the stack frame below
221     emitGetVirtualRegister(callee, X86::ecx);
222     __ cmpl_i32r(asInteger(JSImmediate::impossibleValue()), X86::ecx);
223     JmpDst addressOfLinkedFunctionCheck = __ label();
224     addSlowCase(__ jne());
225     ASSERT(X86Assembler::getDifferenceBetweenLabels(addressOfLinkedFunctionCheck, __ label()) == repatchOffsetOpCallCall);
226     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
227
228     // The following is the fast case, only used whan a callee can be linked.
229
230     // In the case of OpConstruct, call out to a cti_ function to create the new object.
231     if (opcodeID == op_construct) {
232         int proto = instruction[5].u.operand;
233         int thisRegister = instruction[6].u.operand;
234
235         emitPutCTIArg(X86::ecx, 0);
236         emitPutCTIArgFromVirtualRegister(proto, 12, X86::eax);
237         emitCTICall(Interpreter::cti_op_construct_JSConstruct);
238         emitPutVirtualRegister(thisRegister);
239         emitGetVirtualRegister(callee, X86::ecx);
240     }
241
242     // Fast version of stack frame initialization, directly relative to edi.
243     // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
244     __ movl_i32m(asInteger(noValue()), (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register)), X86::edi);
245     __ movl_rm(X86::ecx, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)), X86::edi);
246     __ movl_mr(FIELD_OFFSET(JSFunction, m_scopeChain) + FIELD_OFFSET(ScopeChain, m_node), X86::ecx, X86::edx); // newScopeChain
247     __ movl_i32m(argCount, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register)), X86::edi);
248     __ movl_rm(X86::edi, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)), X86::edi);
249     __ movl_rm(X86::edx, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)), X86::edi);
250     __ addl_i32r(registerOffset * sizeof(Register), X86::edi);
251
252     // Call to the callee
253     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(reinterpret_cast<void*>(unreachable));
254     
255     if (opcodeID == op_call_eval)
256         __ link(wasEval, __ label());
257
258     // Put the return value in dst. In the interpreter, op_ret does this.
259     emitPutVirtualRegister(dst);
260
261 #if ENABLE(CODEBLOCK_SAMPLING)
262         __ movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
263 #endif
264 }
265
266 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
267 {
268     int dst = instruction[1].u.operand;
269     int callee = instruction[2].u.operand;
270     int argCount = instruction[3].u.operand;
271     int registerOffset = instruction[4].u.operand;
272
273     linkSlowCase(iter);
274
275     // The arguments have been set up on the hot path for op_call_eval
276     if (opcodeID == op_call)
277         compileOpCallSetupArgs(instruction);
278     else if (opcodeID == op_construct)
279         compileOpConstructSetupArgs(instruction);
280
281     // Fast check for JS function.
282     __ testl_i32r(JSImmediate::TagMask, X86::ecx);
283     JmpSrc callLinkFailNotObject = __ jne();
284     __ cmpl_i32m(reinterpret_cast<unsigned>(m_interpreter->m_jsFunctionVptr), X86::ecx);
285     JmpSrc callLinkFailNotJSFunction = __ jne();
286
287     // First, in the case of a construct, allocate the new object.
288     if (opcodeID == op_construct) {
289         emitCTICall(Interpreter::cti_op_construct_JSConstruct);
290         emitPutVirtualRegister(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
291         emitGetVirtualRegister(callee, X86::ecx);
292     }
293
294     __ movl_i32r(argCount, X86::edx);
295
296     // Speculatively roll the callframe, assuming argCount will match the arity.
297     __ movl_rm(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)), X86::edi);
298     __ addl_i32r(registerOffset * static_cast<int>(sizeof(Register)), X86::edi);
299
300     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation =
301         emitNakedCall(m_interpreter->m_ctiVirtualCallPreLink);
302
303     JmpSrc storeResultForFirstRun = __ jmp();
304
305     // This is the address for the cold path *after* the first run (which tries to link the call).
306     m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = __ label();
307
308     // The arguments have been set up on the hot path for op_call_eval
309     if (opcodeID == op_call)
310         compileOpCallSetupArgs(instruction);
311     else if (opcodeID == op_construct)
312         compileOpConstructSetupArgs(instruction);
313
314     // Check for JSFunctions.
315     __ testl_i32r(JSImmediate::TagMask, X86::ecx);
316     JmpSrc isNotObject = __ jne();
317     __ cmpl_i32m(reinterpret_cast<unsigned>(m_interpreter->m_jsFunctionVptr), X86::ecx);
318     JmpSrc isJSFunction = __ je();
319
320     // This handles host functions
321     JmpDst notJSFunctionlabel = __ label();
322     __ link(isNotObject, notJSFunctionlabel);
323     __ link(callLinkFailNotObject, notJSFunctionlabel);
324     __ link(callLinkFailNotJSFunction, notJSFunctionlabel);
325     emitCTICall(((opcodeID == op_construct) ? Interpreter::cti_op_construct_NotJSConstruct : Interpreter::cti_op_call_NotJSFunction));
326     JmpSrc wasNotJSFunction = __ jmp();
327
328     // Next, handle JSFunctions...
329     __ link(isJSFunction, __ label());
330
331     // First, in the case of a construct, allocate the new object.
332     if (opcodeID == op_construct) {
333         emitCTICall(Interpreter::cti_op_construct_JSConstruct);
334         emitPutVirtualRegister(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
335         emitGetVirtualRegister(callee, X86::ecx);
336     }
337
338     // Speculatively roll the callframe, assuming argCount will match the arity.
339     __ movl_rm(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)), X86::edi);
340     __ addl_i32r(registerOffset * static_cast<int>(sizeof(Register)), X86::edi);
341     __ movl_i32r(argCount, X86::edx);
342
343     emitNakedCall(m_interpreter->m_ctiVirtualCall);
344
345     // Put the return value in dst. In the interpreter, op_ret does this.
346     JmpDst storeResult = __ label();
347     __ link(wasNotJSFunction, storeResult);
348     __ link(storeResultForFirstRun, storeResult);
349     emitPutVirtualRegister(dst);
350
351 #if ENABLE(CODEBLOCK_SAMPLING)
352     __ movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
353 #endif
354 }
355
356 #endif
357
358 } // namespace JSC
359
360 #endif // ENABLE(JIT)