source: webkit/trunk/JavaScriptCore/jit/JITCall.cpp@ 44433

Last change on this file since 44433 was 43751, checked in by [email protected], 16 years ago

2009-05-14 Gavin Barraclough <[email protected]>

Build fix, not reviewed.

Quick fixes for JIT builds with OPTIMIZE flags disabled.

  • jit/JITCall.cpp: (JSC::JIT::compileOpCall): (JSC::JIT::compileOpCallSlowCase):
  • jit/JITPropertyAccess.cpp: (JSC::JIT::compilePutByIdHotPath):
File size: 14.2 KB
Line 
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 "JITStubCall.h"
34#include "JSArray.h"
35#include "JSFunction.h"
36#include "Interpreter.h"
37#include "ResultType.h"
38#include "SamplingTool.h"
39
40#ifndef NDEBUG
41#include <stdio.h>
42#endif
43
44using namespace std;
45
46namespace JSC {
47
48void JIT::compileOpCallInitializeCallFrame()
49{
50 store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
51
52 loadPtr(Address(regT2, FIELD_OFFSET(JSFunction, m_data) + FIELD_OFFSET(ScopeChain, m_node)), regT1); // newScopeChain
53
54 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register))));
55 storePtr(regT2, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
56 storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
57}
58
59void JIT::compileOpCallSetupArgs(Instruction* instruction)
60{
61 int argCount = instruction[3].u.operand;
62 int registerOffset = instruction[4].u.operand;
63
64 // ecx holds func
65 emitPutJITStubArg(regT2, 1);
66 emitPutJITStubArgConstant(argCount, 3);
67 emitPutJITStubArgConstant(registerOffset, 2);
68}
69
70void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
71{
72 int registerOffset = instruction[4].u.operand;
73
74 // ecx holds func
75 emitPutJITStubArg(regT2, 1);
76 emitPutJITStubArg(regT1, 3);
77 addPtr(Imm32(registerOffset), regT1, regT0);
78 emitPutJITStubArg(regT0, 2);
79}
80
81void JIT::compileOpConstructSetupArgs(Instruction* instruction)
82{
83 int argCount = instruction[3].u.operand;
84 int registerOffset = instruction[4].u.operand;
85 int proto = instruction[5].u.operand;
86 int thisRegister = instruction[6].u.operand;
87
88 // ecx holds func
89 emitPutJITStubArg(regT2, 1);
90 emitPutJITStubArgConstant(registerOffset, 2);
91 emitPutJITStubArgConstant(argCount, 3);
92 emitPutJITStubArgFromVirtualRegister(proto, 4, regT0);
93 emitPutJITStubArgConstant(thisRegister, 5);
94}
95
96void JIT::compileOpCallVarargs(Instruction* instruction)
97{
98 int dst = instruction[1].u.operand;
99 int callee = instruction[2].u.operand;
100 int argCountRegister = instruction[3].u.operand;
101
102 emitGetVirtualRegister(argCountRegister, regT1);
103 emitGetVirtualRegister(callee, regT2);
104 compileOpCallVarargsSetupArgs(instruction);
105
106 // Check for JSFunctions.
107 emitJumpSlowCaseIfNotJSCell(regT2);
108 addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr)));
109
110 // Speculatively roll the callframe, assuming argCount will match the arity.
111 mul32(Imm32(sizeof(Register)), regT0, regT0);
112 intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
113 addPtr(Imm32((int32_t)offset), regT0, regT3);
114 addPtr(callFrameRegister, regT3);
115 storePtr(callFrameRegister, regT3);
116 addPtr(regT0, callFrameRegister);
117 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
118
119 // Put the return value in dst. In the interpreter, op_ret does this.
120 emitPutVirtualRegister(dst);
121
122 sampleCodeBlock(m_codeBlock);
123}
124
125void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
126{
127 int dst = instruction[1].u.operand;
128
129 linkSlowCase(iter);
130 linkSlowCase(iter);
131 JITStubCall stubCall(this, JITStubs::cti_op_call_NotJSFunction);
132 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
133
134 sampleCodeBlock(m_codeBlock);
135}
136
137#if !ENABLE(JIT_OPTIMIZE_CALL)
138
139/* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
140
141void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
142{
143 int dst = instruction[1].u.operand;
144 int callee = instruction[2].u.operand;
145 int argCount = instruction[3].u.operand;
146 int registerOffset = instruction[4].u.operand;
147
148 // Handle eval
149 Jump wasEval;
150 if (opcodeID == op_call_eval) {
151 CallEvalJITStub(this, instruction).call();
152 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
153 }
154
155 emitGetVirtualRegister(callee, regT2);
156 // The arguments have been set up on the hot path for op_call_eval
157 if (opcodeID == op_call)
158 compileOpCallSetupArgs(instruction);
159 else if (opcodeID == op_construct)
160 compileOpConstructSetupArgs(instruction);
161
162 // Check for JSFunctions.
163 emitJumpSlowCaseIfNotJSCell(regT2);
164 addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr)));
165
166 // First, in the case of a construct, allocate the new object.
167 if (opcodeID == op_construct) {
168 JITStubCall(this, JITStubs::cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
169 emitGetVirtualRegister(callee, regT2);
170 }
171
172 // Speculatively roll the callframe, assuming argCount will match the arity.
173 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
174 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
175 move(Imm32(argCount), regT1);
176
177 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
178
179 if (opcodeID == op_call_eval)
180 wasEval.link(this);
181
182 // Put the return value in dst. In the interpreter, op_ret does this.
183 emitPutVirtualRegister(dst);
184
185 sampleCodeBlock(m_codeBlock);
186}
187
188void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
189{
190 int dst = instruction[1].u.operand;
191
192 linkSlowCase(iter);
193 linkSlowCase(iter);
194 JITStubCall stubCall(this, opcodeID == op_construct ? JITStubs::cti_op_construct_NotJSConstruct : JITStubs::cti_op_call_NotJSFunction);
195 stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
196
197 sampleCodeBlock(m_codeBlock);
198}
199
200#else // !ENABLE(JIT_OPTIMIZE_CALL)
201
202/* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
203
204void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
205{
206 int dst = instruction[1].u.operand;
207 int callee = instruction[2].u.operand;
208 int argCount = instruction[3].u.operand;
209 int registerOffset = instruction[4].u.operand;
210
211 // Handle eval
212 Jump wasEval;
213 if (opcodeID == op_call_eval) {
214 CallEvalJITStub(this, instruction).call();
215 wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
216 }
217
218 // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
219 // This deliberately leaves the callee in ecx, used when setting up the stack frame below
220 emitGetVirtualRegister(callee, regT2);
221 DataLabelPtr addressOfLinkedFunctionCheck;
222 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT2, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue())));
223 addSlowCase(jumpToSlow);
224 ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
225 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
226
227 // The following is the fast case, only used whan a callee can be linked.
228
229 // In the case of OpConstruct, call out to a cti_ function to create the new object.
230 if (opcodeID == op_construct) {
231 int proto = instruction[5].u.operand;
232 int thisRegister = instruction[6].u.operand;
233
234 emitPutJITStubArg(regT2, 1);
235 emitPutJITStubArgFromVirtualRegister(proto, 4, regT0);
236 JITStubCall stubCall(this, JITStubs::cti_op_construct_JSConstruct);
237 stubCall.call(thisRegister);
238 emitGetVirtualRegister(callee, regT2);
239 }
240
241 // Fast version of stack frame initialization, directly relative to edi.
242 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
243 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register))));
244 storePtr(regT2, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
245 loadPtr(Address(regT2, FIELD_OFFSET(JSFunction, m_data) + FIELD_OFFSET(ScopeChain, m_node)), regT1); // newScopeChain
246 store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
247 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
248 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
249 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
250
251 // Call to the callee
252 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(reinterpret_cast<void*>(0));
253
254 if (opcodeID == op_call_eval)
255 wasEval.link(this);
256
257 // Put the return value in dst. In the interpreter, op_ret does this.
258 emitPutVirtualRegister(dst);
259
260 sampleCodeBlock(m_codeBlock);
261}
262
263void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
264{
265 int dst = instruction[1].u.operand;
266 int callee = instruction[2].u.operand;
267 int argCount = instruction[3].u.operand;
268 int registerOffset = instruction[4].u.operand;
269
270 linkSlowCase(iter);
271
272 // The arguments have been set up on the hot path for op_call_eval
273 if (opcodeID == op_call)
274 compileOpCallSetupArgs(instruction);
275 else if (opcodeID == op_construct)
276 compileOpConstructSetupArgs(instruction);
277
278 // Fast check for JS function.
279 Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT2);
280 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr));
281
282 // First, in the case of a construct, allocate the new object.
283 if (opcodeID == op_construct) {
284 JITStubCall(this, JITStubs::cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
285 emitGetVirtualRegister(callee, regT2);
286 }
287
288 move(Imm32(argCount), regT1);
289
290 // Speculatively roll the callframe, assuming argCount will match the arity.
291 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
292 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
293
294 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation =
295 emitNakedCall(m_globalData->jitStubs.ctiVirtualCallPreLink());
296
297 Jump storeResultForFirstRun = jump();
298
299 // This is the address for the cold path *after* the first run (which tries to link the call).
300 m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = MacroAssembler::Label(this);
301
302 // The arguments have been set up on the hot path for op_call_eval
303 if (opcodeID == op_call)
304 compileOpCallSetupArgs(instruction);
305 else if (opcodeID == op_construct)
306 compileOpConstructSetupArgs(instruction);
307
308 // Check for JSFunctions.
309 Jump isNotObject = emitJumpIfNotJSCell(regT2);
310 Jump isJSFunction = branchPtr(Equal, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr));
311
312 // This handles host functions
313 isNotObject.link(this);
314 callLinkFailNotObject.link(this);
315 callLinkFailNotJSFunction.link(this);
316 JITStubCall stubCall(this, opcodeID == op_construct ? JITStubs::cti_op_construct_NotJSConstruct : JITStubs::cti_op_call_NotJSFunction);
317 stubCall.call();
318 Jump wasNotJSFunction = jump();
319
320 // Next, handle JSFunctions...
321 isJSFunction.link(this);
322
323 // First, in the case of a construct, allocate the new object.
324 if (opcodeID == op_construct) {
325 JITStubCall stubCall(this, JITStubs::cti_op_construct_JSConstruct);
326 stubCall.call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
327 emitGetVirtualRegister(callee, regT2);
328 }
329
330 // Speculatively roll the callframe, assuming argCount will match the arity.
331 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
332 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
333 move(Imm32(argCount), regT1);
334
335 emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
336
337 // Put the return value in dst. In the interpreter, op_ret does this.
338 wasNotJSFunction.link(this);
339 storeResultForFirstRun.link(this);
340 emitPutVirtualRegister(dst);
341
342 sampleCodeBlock(m_codeBlock);
343}
344
345/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
346
347#endif // !ENABLE(JIT_OPTIMIZE_CALL)
348
349} // namespace JSC
350
351#endif // ENABLE(JIT)
Note: See TracBrowser for help on using the repository browser.