]>
Commit | Line | Data |
---|---|---|
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 | ||
45 | using namespace std; | |
46 | ||
47 | namespace JSC { | |
48 | ||
ba379fdc A |
49 | void 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 | 58 | void 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 |
64 | void 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 | 91 | void 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 |
109 | void 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 | ||
145 | void 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 | |
166 | void 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 | ||
222 | void 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) |