]> git.saurik.com Git - apple/javascriptcore.git/blame - jit/JITCall.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / jit / JITCall.cpp
CommitLineData
9dae56ea
A
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"
9dae56ea
A
27
28#if ENABLE(JIT)
14957cd0
A
29#if USE(JSVALUE64)
30#include "JIT.h"
9dae56ea
A
31
32#include "CodeBlock.h"
33#include "JITInlineMethods.h"
ba379fdc 34#include "JITStubCall.h"
9dae56ea
A
35#include "JSArray.h"
36#include "JSFunction.h"
37#include "Interpreter.h"
38#include "ResultType.h"
39#include "SamplingTool.h"
40
41#ifndef NDEBUG
42#include <stdio.h>
43#endif
44
45using namespace std;
46
47namespace JSC {
48
ba379fdc
A
49void JIT::compileOpCallInitializeCallFrame()
50{
51 // regT0 holds callee, regT1 holds argCount
14957cd0
A
52 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT3); // scopeChain
53 emitPutIntToCallFrameHeader(regT1, RegisterFile::ArgumentCount);
54 emitPutCellToCallFrameHeader(regT0, RegisterFile::Callee);
55 emitPutCellToCallFrameHeader(regT3, RegisterFile::ScopeChain);
ba379fdc
A
56}
57
14957cd0 58void JIT::emit_op_call_put_result(Instruction* instruction)
ba379fdc
A
59{
60 int dst = instruction[1].u.operand;
14957cd0 61 emitPutVirtualRegister(dst);
9dae56ea
A
62}
63
ba379fdc
A
64void JIT::compileOpCallVarargs(Instruction* instruction)
65{
14957cd0
A
66 int callee = instruction[1].u.operand;
67 int argCountRegister = instruction[2].u.operand;
68 int registerOffset = instruction[3].u.operand;
ba379fdc
A
69
70 emitGetVirtualRegister(argCountRegister, regT1);
14957cd0 71 emitFastArithImmToInt(regT1);
f9bf01c6 72 emitGetVirtualRegister(callee, regT0);
14957cd0 73 addPtr(Imm32(registerOffset), regT1, regT2);
ba379fdc
A
74
75 // Check for JSFunctions.
f9bf01c6 76 emitJumpSlowCaseIfNotJSCell(regT0);
14957cd0 77 addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
f9bf01c6 78
ba379fdc 79 // Speculatively roll the callframe, assuming argCount will match the arity.
14957cd0 80 mul32(TrustedImm32(sizeof(Register)), regT2, regT2);
ba379fdc 81 intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
f9bf01c6 82 addPtr(Imm32((int32_t)offset), regT2, regT3);
ba379fdc
A
83 addPtr(callFrameRegister, regT3);
84 storePtr(callFrameRegister, regT3);
f9bf01c6 85 addPtr(regT2, callFrameRegister);
4e4e5a6f 86 emitNakedCall(m_globalData->jitStubs->ctiVirtualCall());
ba379fdc 87
ba379fdc
A
88 sampleCodeBlock(m_codeBlock);
89}
90
14957cd0 91void JIT::compileOpCallVarargsSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator& iter)
ba379fdc 92{
ba379fdc
A
93 linkSlowCase(iter);
94 linkSlowCase(iter);
14957cd0 95
ba379fdc 96 JITStubCall stubCall(this, cti_op_call_NotJSFunction);
14957cd0
A
97 stubCall.addArgument(regT0);
98 stubCall.addArgument(regT2);
99 stubCall.addArgument(regT1);
100 stubCall.call();
ba379fdc
A
101
102 sampleCodeBlock(m_codeBlock);
103}
104
9dae56ea
A
105#if !ENABLE(JIT_OPTIMIZE_CALL)
106
ba379fdc
A
107/* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
108
9dae56ea
A
109void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
110{
14957cd0
A
111 int callee = instruction[1].u.operand;
112 int argCount = instruction[2].u.operand;
113 int registerOffset = instruction[3].u.operand;
9dae56ea
A
114
115 // Handle eval
116 Jump wasEval;
117 if (opcodeID == op_call_eval) {
ba379fdc 118 JITStubCall stubCall(this, cti_op_call_eval);
f9bf01c6 119 stubCall.addArgument(callee, regT0);
ba379fdc
A
120 stubCall.addArgument(JIT::Imm32(registerOffset));
121 stubCall.addArgument(JIT::Imm32(argCount));
122 stubCall.call();
14957cd0 123 wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())));
9dae56ea
A
124 }
125
f9bf01c6 126 emitGetVirtualRegister(callee, regT0);
9dae56ea
A
127
128 // Check for JSFunctions.
f9bf01c6 129 emitJumpSlowCaseIfNotJSCell(regT0);
14957cd0 130 addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
9dae56ea
A
131
132 // Speculatively roll the callframe, assuming argCount will match the arity.
133 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
134 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
ba379fdc 135 move(Imm32(argCount), regT1);
9dae56ea 136
14957cd0 137 emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstruct() : m_globalData->jitStubs->ctiVirtualCall());
9dae56ea
A
138
139 if (opcodeID == op_call_eval)
140 wasEval.link(this);
141
9dae56ea
A
142 sampleCodeBlock(m_codeBlock);
143}
144
145void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
146{
14957cd0
A
147 int argCount = instruction[2].u.operand;
148 int registerOffset = instruction[3].u.operand;
9dae56ea
A
149
150 linkSlowCase(iter);
151 linkSlowCase(iter);
14957cd0 152
ba379fdc 153 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
14957cd0
A
154 stubCall.addArgument(regT0);
155 stubCall.addArgument(JIT::Imm32(registerOffset));
156 stubCall.addArgument(JIT::Imm32(argCount));
157 stubCall.call();
9dae56ea
A
158
159 sampleCodeBlock(m_codeBlock);
160}
161
ba379fdc 162#else // !ENABLE(JIT_OPTIMIZE_CALL)
9dae56ea 163
ba379fdc 164/* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
9dae56ea
A
165
166void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
167{
14957cd0
A
168 int callee = instruction[1].u.operand;
169 int argCount = instruction[2].u.operand;
170 int registerOffset = instruction[3].u.operand;
9dae56ea
A
171
172 // Handle eval
173 Jump wasEval;
174 if (opcodeID == op_call_eval) {
ba379fdc 175 JITStubCall stubCall(this, cti_op_call_eval);
f9bf01c6 176 stubCall.addArgument(callee, regT0);
ba379fdc
A
177 stubCall.addArgument(JIT::Imm32(registerOffset));
178 stubCall.addArgument(JIT::Imm32(argCount));
179 stubCall.call();
14957cd0 180 wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())));
9dae56ea
A
181 }
182
183 // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
184 // This deliberately leaves the callee in ecx, used when setting up the stack frame below
f9bf01c6 185 emitGetVirtualRegister(callee, regT0);
9dae56ea 186 DataLabelPtr addressOfLinkedFunctionCheck;
f9bf01c6
A
187
188 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
189
14957cd0 190 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(JSValue::encode(JSValue())));
f9bf01c6
A
191
192 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
193
9dae56ea 194 addSlowCase(jumpToSlow);
f9bf01c6 195 ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
9dae56ea 196 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
14957cd0 197 m_callStructureStubCompilationInfo[callLinkInfoIndex].isCall = opcodeID != op_construct;
9dae56ea
A
198
199 // The following is the fast case, only used whan a callee can be linked.
200
9dae56ea
A
201 // Fast version of stack frame initialization, directly relative to edi.
202 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
14957cd0
A
203
204 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1); // newScopeChain
205
206 store32(TrustedImm32(Int32Tag), intTagFor(registerOffset + RegisterFile::ArgumentCount));
207 store32(Imm32(argCount), intPayloadFor(registerOffset + RegisterFile::ArgumentCount));
9dae56ea 208 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
14957cd0 209 storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
ba379fdc 210 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
9dae56ea
A
211 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
212
213 // Call to the callee
ba379fdc 214 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
9dae56ea
A
215
216 if (opcodeID == op_call_eval)
217 wasEval.link(this);
218
9dae56ea
A
219 sampleCodeBlock(m_codeBlock);
220}
221
222void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
223{
14957cd0
A
224 int argCount = instruction[2].u.operand;
225 int registerOffset = instruction[3].u.operand;
9dae56ea
A
226
227 linkSlowCase(iter);
228
9dae56ea 229 // Fast check for JS function.
f9bf01c6 230 Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
14957cd0 231 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr));
9dae56ea 232
9dae56ea
A
233 // Speculatively roll the callframe, assuming argCount will match the arity.
234 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
235 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
ba379fdc 236 move(Imm32(argCount), regT1);
9dae56ea 237
14957cd0 238 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink());
9dae56ea 239
ba379fdc 240 // Done! - return back to the hot path.
14957cd0
A
241 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
242 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
243 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
9dae56ea
A
244
245 // This handles host functions
9dae56ea
A
246 callLinkFailNotObject.link(this);
247 callLinkFailNotJSFunction.link(this);
9dae56ea 248
14957cd0
A
249 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
250 stubCall.addArgument(regT0);
251 stubCall.addArgument(JIT::Imm32(registerOffset));
252 stubCall.addArgument(JIT::Imm32(argCount));
253 stubCall.call();
254
9dae56ea
A
255 sampleCodeBlock(m_codeBlock);
256}
257
ba379fdc
A
258/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
259
260#endif // !ENABLE(JIT_OPTIMIZE_CALL)
261
9dae56ea
A
262} // namespace JSC
263
14957cd0 264#endif // USE(JSVALUE64)
9dae56ea 265#endif // ENABLE(JIT)