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