]>
Commit | Line | Data |
---|---|---|
14957cd0 | 1 | /* |
ed1e77d3 | 2 | * Copyright (C) 2008, 2013-2015 Apple Inc. All rights reserved. |
14957cd0 A |
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 | ||
28 | #if ENABLE(JIT) | |
29 | #if USE(JSVALUE32_64) | |
30 | #include "JIT.h" | |
31 | ||
32 | #include "CodeBlock.h" | |
33 | #include "Interpreter.h" | |
93a37866 | 34 | #include "JITInlines.h" |
14957cd0 A |
35 | #include "JSArray.h" |
36 | #include "JSFunction.h" | |
81345200 A |
37 | #include "JSCInlines.h" |
38 | #include "LinkBuffer.h" | |
93a37866 | 39 | #include "RepatchBuffer.h" |
14957cd0 A |
40 | #include "ResultType.h" |
41 | #include "SamplingTool.h" | |
ed1e77d3 | 42 | #include "SetupVarargsFrame.h" |
81345200 | 43 | #include "StackAlignment.h" |
93a37866 | 44 | #include <wtf/StringPrintStream.h> |
14957cd0 | 45 | |
14957cd0 A |
46 | |
47 | namespace JSC { | |
48 | ||
81345200 | 49 | void JIT::emitPutCallResult(Instruction* instruction) |
14957cd0 A |
50 | { |
51 | int dst = instruction[1].u.operand; | |
6fe7ccc8 | 52 | emitValueProfilingSite(); |
14957cd0 A |
53 | emitStore(dst, regT1, regT0); |
54 | } | |
55 | ||
14957cd0 A |
56 | void JIT::emit_op_ret(Instruction* currentInstruction) |
57 | { | |
58 | unsigned dst = currentInstruction[1].u.operand; | |
59 | ||
60 | emitLoad(dst, regT1, regT0); | |
14957cd0 | 61 | |
81345200 A |
62 | checkStackPointerAlignment(); |
63 | emitFunctionEpilogue(); | |
14957cd0 A |
64 | ret(); |
65 | } | |
66 | ||
14957cd0 A |
67 | void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
68 | { | |
6fe7ccc8 | 69 | compileOpCallSlowCase(op_call, currentInstruction, iter, m_callLinkInfoIndex++); |
14957cd0 A |
70 | } |
71 | ||
72 | void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
73 | { | |
6fe7ccc8 | 74 | compileOpCallSlowCase(op_call_eval, currentInstruction, iter, m_callLinkInfoIndex); |
14957cd0 | 75 | } |
6fe7ccc8 | 76 | |
14957cd0 A |
77 | void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
78 | { | |
6fe7ccc8 | 79 | compileOpCallSlowCase(op_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++); |
14957cd0 | 80 | } |
81345200 A |
81 | |
82 | void JIT::emitSlow_op_construct_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) | |
83 | { | |
84 | compileOpCallSlowCase(op_construct_varargs, currentInstruction, iter, m_callLinkInfoIndex++); | |
85 | } | |
86 | ||
14957cd0 A |
87 | void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) |
88 | { | |
6fe7ccc8 | 89 | compileOpCallSlowCase(op_construct, currentInstruction, iter, m_callLinkInfoIndex++); |
14957cd0 A |
90 | } |
91 | ||
92 | void JIT::emit_op_call(Instruction* currentInstruction) | |
93 | { | |
94 | compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++); | |
95 | } | |
96 | ||
97 | void JIT::emit_op_call_eval(Instruction* currentInstruction) | |
98 | { | |
6fe7ccc8 | 99 | compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex); |
14957cd0 A |
100 | } |
101 | ||
102 | void JIT::emit_op_call_varargs(Instruction* currentInstruction) | |
103 | { | |
6fe7ccc8 | 104 | compileOpCall(op_call_varargs, currentInstruction, m_callLinkInfoIndex++); |
14957cd0 | 105 | } |
81345200 A |
106 | |
107 | void JIT::emit_op_construct_varargs(Instruction* currentInstruction) | |
108 | { | |
109 | compileOpCall(op_construct_varargs, currentInstruction, m_callLinkInfoIndex++); | |
110 | } | |
111 | ||
14957cd0 A |
112 | void JIT::emit_op_construct(Instruction* currentInstruction) |
113 | { | |
114 | compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++); | |
115 | } | |
116 | ||
ed1e77d3 | 117 | void JIT::compileSetupVarargsFrame(Instruction* instruction, CallLinkInfo* info) |
14957cd0 | 118 | { |
81345200 A |
119 | int thisValue = instruction[3].u.operand; |
120 | int arguments = instruction[4].u.operand; | |
121 | int firstFreeRegister = instruction[5].u.operand; | |
122 | int firstVarArgOffset = instruction[6].u.operand; | |
6fe7ccc8 | 123 | |
81345200 | 124 | emitLoad(arguments, regT1, regT0); |
ed1e77d3 A |
125 | callOperation(operationSizeFrameForVarargs, regT1, regT0, -firstFreeRegister, firstVarArgOffset); |
126 | move(TrustedImm32(-firstFreeRegister), regT1); | |
127 | emitSetVarargsFrame(*this, returnValueGPR, false, regT1, regT1); | |
128 | addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 6 * sizeof(void*)))), regT1, stackPointerRegister); | |
129 | emitLoad(arguments, regT2, regT4); | |
130 | callOperation(operationSetupVarargsFrame, regT1, regT2, regT4, firstVarArgOffset, regT0); | |
131 | move(returnValueGPR, regT1); | |
132 | ||
133 | // Profile the argument count. | |
134 | load32(Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), regT2); | |
135 | load8(info->addressOfMaxNumArguments(), regT0); | |
136 | Jump notBiggest = branch32(Above, regT0, regT2); | |
137 | Jump notSaturated = branch32(BelowOrEqual, regT2, TrustedImm32(255)); | |
138 | move(TrustedImm32(255), regT2); | |
139 | notSaturated.link(this); | |
140 | store8(regT2, info->addressOfMaxNumArguments()); | |
141 | notBiggest.link(this); | |
142 | ||
143 | // Initialize 'this'. | |
144 | emitLoad(thisValue, regT2, regT0); | |
145 | store32(regT0, Address(regT1, PayloadOffset + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); | |
146 | store32(regT2, Address(regT1, TagOffset + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))))); | |
147 | ||
148 | addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), regT1, stackPointerRegister); | |
6fe7ccc8 | 149 | } |
14957cd0 | 150 | |
81345200 | 151 | void JIT::compileCallEval(Instruction* instruction) |
6fe7ccc8 | 152 | { |
81345200 | 153 | addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), stackPointerRegister, regT1); |
ed1e77d3 | 154 | storePtr(callFrameRegister, Address(regT1, CallFrame::callerFrameOffset())); |
81345200 | 155 | |
81345200 | 156 | addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister); |
81345200 | 157 | |
ed1e77d3 | 158 | callOperation(operationCallEval, regT1); |
81345200 | 159 | |
ed1e77d3 | 160 | addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag))); |
14957cd0 A |
161 | |
162 | sampleCodeBlock(m_codeBlock); | |
81345200 A |
163 | |
164 | emitPutCallResult(instruction); | |
14957cd0 A |
165 | } |
166 | ||
81345200 | 167 | void JIT::compileCallEvalSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter) |
14957cd0 | 168 | { |
14957cd0 A |
169 | linkSlowCase(iter); |
170 | ||
ed1e77d3 A |
171 | int registerOffset = -instruction[4].u.operand; |
172 | ||
173 | addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister); | |
174 | ||
81345200 A |
175 | loadPtr(Address(stackPointerRegister, sizeof(Register) * JSStack::Callee - sizeof(CallerFrameAndPC)), regT0); |
176 | loadPtr(Address(stackPointerRegister, sizeof(Register) * JSStack::Callee - sizeof(CallerFrameAndPC)), regT1); | |
177 | move(TrustedImmPtr(&CallLinkInfo::dummy()), regT2); | |
178 | ||
93a37866 | 179 | emitLoad(JSStack::Callee, regT1, regT0); |
81345200 A |
180 | emitNakedCall(m_vm->getCTIStub(virtualCallThunkGenerator).code()); |
181 | addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister); | |
182 | checkStackPointerAlignment(); | |
14957cd0 A |
183 | |
184 | sampleCodeBlock(m_codeBlock); | |
81345200 A |
185 | |
186 | emitPutCallResult(instruction); | |
14957cd0 A |
187 | } |
188 | ||
14957cd0 A |
189 | void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex) |
190 | { | |
ed1e77d3 | 191 | CallLinkInfo* info = m_codeBlock->addCallLinkInfo(); |
81345200 | 192 | int callee = instruction[2].u.operand; |
14957cd0 | 193 | |
6fe7ccc8 A |
194 | /* Caller always: |
195 | - Updates callFrameRegister to callee callFrame. | |
196 | - Initializes ArgumentCount; CallerFrame; Callee. | |
14957cd0 | 197 | |
6fe7ccc8 | 198 | For a JS call: |
6fe7ccc8 A |
199 | - Callee initializes ReturnPC; CodeBlock. |
200 | - Callee restores callFrameRegister before return. | |
14957cd0 | 201 | |
6fe7ccc8 | 202 | For a non-JS call: |
ed1e77d3 | 203 | - Caller initializes ReturnPC; CodeBlock. |
6fe7ccc8 A |
204 | - Caller restores callFrameRegister after return. |
205 | */ | |
206 | ||
81345200 | 207 | if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs) |
ed1e77d3 | 208 | compileSetupVarargsFrame(instruction, info); |
6fe7ccc8 | 209 | else { |
81345200 A |
210 | int argCount = instruction[3].u.operand; |
211 | int registerOffset = -instruction[4].u.operand; | |
93a37866 A |
212 | |
213 | if (opcodeID == op_call && shouldEmitProfiling()) { | |
214 | emitLoad(registerOffset + CallFrame::argumentOffsetIncludingThis(0), regT0, regT1); | |
215 | Jump done = branch32(NotEqual, regT0, TrustedImm32(JSValue::CellTag)); | |
81345200 A |
216 | loadPtr(Address(regT1, JSCell::structureIDOffset()), regT1); |
217 | storePtr(regT1, instruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile->addressOfLastSeenStructureID()); | |
93a37866 A |
218 | done.link(this); |
219 | } | |
220 | ||
81345200 | 221 | addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister); |
14957cd0 | 222 | |
81345200 A |
223 | store32(TrustedImm32(argCount), Address(stackPointerRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC))); |
224 | } // SP holds newCallFrame + sizeof(CallerFrameAndPC), with ArgumentCount initialized. | |
6fe7ccc8 | 225 | |
81345200 A |
226 | uint32_t locationBits = CallFrame::Location::encodeAsBytecodeInstruction(instruction); |
227 | store32(TrustedImm32(locationBits), tagFor(JSStack::ArgumentCount, callFrameRegister)); | |
6fe7ccc8 | 228 | emitLoad(callee, regT1, regT0); // regT1, regT0 holds callee. |
14957cd0 | 229 | |
81345200 A |
230 | store32(regT0, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC))); |
231 | store32(regT1, Address(stackPointerRegister, JSStack::Callee * static_cast<int>(sizeof(Register)) + TagOffset - sizeof(CallerFrameAndPC))); | |
14957cd0 | 232 | |
6fe7ccc8 | 233 | if (opcodeID == op_call_eval) { |
81345200 | 234 | compileCallEval(instruction); |
6fe7ccc8 A |
235 | return; |
236 | } | |
14957cd0 | 237 | |
4be4e309 A |
238 | addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag))); |
239 | ||
6fe7ccc8 | 240 | DataLabelPtr addressOfLinkedFunctionCheck; |
6fe7ccc8 | 241 | Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0)); |
14957cd0 | 242 | |
6fe7ccc8 | 243 | addSlowCase(slowCase); |
14957cd0 | 244 | |
81345200 | 245 | ASSERT(m_callCompilationInfo.size() == callLinkInfoIndex); |
ed1e77d3 | 246 | info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), CodeOrigin(m_bytecodeOffset), regT0); |
81345200 A |
247 | m_callCompilationInfo.append(CallCompilationInfo()); |
248 | m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; | |
249 | m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info; | |
14957cd0 | 250 | |
81345200 A |
251 | checkStackPointerAlignment(); |
252 | m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(); | |
253 | ||
254 | addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister); | |
255 | checkStackPointerAlignment(); | |
14957cd0 A |
256 | |
257 | sampleCodeBlock(m_codeBlock); | |
81345200 | 258 | emitPutCallResult(instruction); |
14957cd0 A |
259 | } |
260 | ||
81345200 | 261 | void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex) |
14957cd0 | 262 | { |
6fe7ccc8 | 263 | if (opcodeID == op_call_eval) { |
81345200 | 264 | compileCallEvalSlowCase(instruction, iter); |
6fe7ccc8 A |
265 | return; |
266 | } | |
14957cd0 A |
267 | |
268 | linkSlowCase(iter); | |
269 | linkSlowCase(iter); | |
81345200 A |
270 | |
271 | ThunkGenerator generator = linkThunkGeneratorFor( | |
272 | (opcodeID == op_construct || opcodeID == op_construct_varargs) ? CodeForConstruct : CodeForCall, | |
273 | RegisterPreservationNotRequired); | |
6fe7ccc8 | 274 | |
81345200 A |
275 | move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2); |
276 | m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getCTIStub(generator).code()); | |
277 | ||
278 | addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister); | |
279 | checkStackPointerAlignment(); | |
14957cd0 | 280 | |
14957cd0 | 281 | sampleCodeBlock(m_codeBlock); |
81345200 | 282 | emitPutCallResult(instruction); |
14957cd0 A |
283 | } |
284 | ||
14957cd0 A |
285 | } // namespace JSC |
286 | ||
287 | #endif // USE(JSVALUE32_64) | |
288 | #endif // ENABLE(JIT) |