2 * Copyright (C) 2008, 2013-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
32 #include "CodeBlock.h"
33 #include "Interpreter.h"
34 #include "JITInlines.h"
36 #include "JSFunction.h"
37 #include "JSCInlines.h"
38 #include "LinkBuffer.h"
39 #include "RepatchBuffer.h"
40 #include "ResultType.h"
41 #include "SamplingTool.h"
42 #include "SetupVarargsFrame.h"
43 #include "StackAlignment.h"
44 #include <wtf/StringPrintStream.h>
49 void JIT::emitPutCallResult(Instruction
* instruction
)
51 int dst
= instruction
[1].u
.operand
;
52 emitValueProfilingSite();
53 emitStore(dst
, regT1
, regT0
);
56 void JIT::emit_op_ret(Instruction
* currentInstruction
)
58 unsigned dst
= currentInstruction
[1].u
.operand
;
60 emitLoad(dst
, regT1
, regT0
);
62 checkStackPointerAlignment();
63 emitFunctionEpilogue();
67 void JIT::emitSlow_op_call(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
69 compileOpCallSlowCase(op_call
, currentInstruction
, iter
, m_callLinkInfoIndex
++);
72 void JIT::emitSlow_op_call_eval(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
74 compileOpCallSlowCase(op_call_eval
, currentInstruction
, iter
, m_callLinkInfoIndex
);
77 void JIT::emitSlow_op_call_varargs(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
79 compileOpCallSlowCase(op_call_varargs
, currentInstruction
, iter
, m_callLinkInfoIndex
++);
82 void JIT::emitSlow_op_construct_varargs(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
84 compileOpCallSlowCase(op_construct_varargs
, currentInstruction
, iter
, m_callLinkInfoIndex
++);
87 void JIT::emitSlow_op_construct(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
89 compileOpCallSlowCase(op_construct
, currentInstruction
, iter
, m_callLinkInfoIndex
++);
92 void JIT::emit_op_call(Instruction
* currentInstruction
)
94 compileOpCall(op_call
, currentInstruction
, m_callLinkInfoIndex
++);
97 void JIT::emit_op_call_eval(Instruction
* currentInstruction
)
99 compileOpCall(op_call_eval
, currentInstruction
, m_callLinkInfoIndex
);
102 void JIT::emit_op_call_varargs(Instruction
* currentInstruction
)
104 compileOpCall(op_call_varargs
, currentInstruction
, m_callLinkInfoIndex
++);
107 void JIT::emit_op_construct_varargs(Instruction
* currentInstruction
)
109 compileOpCall(op_construct_varargs
, currentInstruction
, m_callLinkInfoIndex
++);
112 void JIT::emit_op_construct(Instruction
* currentInstruction
)
114 compileOpCall(op_construct
, currentInstruction
, m_callLinkInfoIndex
++);
117 void JIT::compileSetupVarargsFrame(Instruction
* instruction
, CallLinkInfo
* info
)
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
;
124 emitLoad(arguments
, regT1
, regT0
);
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
);
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);
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
)))));
148 addPtr(TrustedImm32(sizeof(CallerFrameAndPC
)), regT1
, stackPointerRegister
);
151 void JIT::compileCallEval(Instruction
* instruction
)
153 addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC
))), stackPointerRegister
, regT1
);
154 storePtr(callFrameRegister
, Address(regT1
, CallFrame::callerFrameOffset()));
156 addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock
) * sizeof(Register
)), callFrameRegister
, stackPointerRegister
);
158 callOperation(operationCallEval
, regT1
);
160 addSlowCase(branch32(Equal
, regT1
, TrustedImm32(JSValue::EmptyValueTag
)));
162 sampleCodeBlock(m_codeBlock
);
164 emitPutCallResult(instruction
);
167 void JIT::compileCallEvalSlowCase(Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
171 int registerOffset
= -instruction
[4].u
.operand
;
173 addPtr(TrustedImm32(registerOffset
* sizeof(Register
) + sizeof(CallerFrameAndPC
)), callFrameRegister
, stackPointerRegister
);
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
);
179 emitLoad(JSStack::Callee
, regT1
, regT0
);
180 emitNakedCall(m_vm
->getCTIStub(virtualCallThunkGenerator
).code());
181 addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock
) * sizeof(Register
)), callFrameRegister
, stackPointerRegister
);
182 checkStackPointerAlignment();
184 sampleCodeBlock(m_codeBlock
);
186 emitPutCallResult(instruction
);
189 void JIT::compileOpCall(OpcodeID opcodeID
, Instruction
* instruction
, unsigned callLinkInfoIndex
)
191 CallLinkInfo
* info
= m_codeBlock
->addCallLinkInfo();
192 int callee
= instruction
[2].u
.operand
;
195 - Updates callFrameRegister to callee callFrame.
196 - Initializes ArgumentCount; CallerFrame; Callee.
199 - Callee initializes ReturnPC; CodeBlock.
200 - Callee restores callFrameRegister before return.
203 - Caller initializes ReturnPC; CodeBlock.
204 - Caller restores callFrameRegister after return.
207 if (opcodeID
== op_call_varargs
|| opcodeID
== op_construct_varargs
)
208 compileSetupVarargsFrame(instruction
, info
);
210 int argCount
= instruction
[3].u
.operand
;
211 int registerOffset
= -instruction
[4].u
.operand
;
213 if (opcodeID
== op_call
&& shouldEmitProfiling()) {
214 emitLoad(registerOffset
+ CallFrame::argumentOffsetIncludingThis(0), regT0
, regT1
);
215 Jump done
= branch32(NotEqual
, regT0
, TrustedImm32(JSValue::CellTag
));
216 loadPtr(Address(regT1
, JSCell::structureIDOffset()), regT1
);
217 storePtr(regT1
, instruction
[OPCODE_LENGTH(op_call
) - 2].u
.arrayProfile
->addressOfLastSeenStructureID());
221 addPtr(TrustedImm32(registerOffset
* sizeof(Register
) + sizeof(CallerFrameAndPC
)), callFrameRegister
, stackPointerRegister
);
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.
226 uint32_t locationBits
= CallFrame::Location::encodeAsBytecodeInstruction(instruction
);
227 store32(TrustedImm32(locationBits
), tagFor(JSStack::ArgumentCount
, callFrameRegister
));
228 emitLoad(callee
, regT1
, regT0
); // regT1, regT0 holds callee.
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
)));
233 if (opcodeID
== op_call_eval
) {
234 compileCallEval(instruction
);
238 addSlowCase(branch32(NotEqual
, regT1
, TrustedImm32(JSValue::CellTag
)));
240 DataLabelPtr addressOfLinkedFunctionCheck
;
241 Jump slowCase
= branchPtrWithPatch(NotEqual
, regT0
, addressOfLinkedFunctionCheck
, TrustedImmPtr(0));
243 addSlowCase(slowCase
);
245 ASSERT(m_callCompilationInfo
.size() == callLinkInfoIndex
);
246 info
->setUpCall(CallLinkInfo::callTypeFor(opcodeID
), CodeOrigin(m_bytecodeOffset
), regT0
);
247 m_callCompilationInfo
.append(CallCompilationInfo());
248 m_callCompilationInfo
[callLinkInfoIndex
].hotPathBegin
= addressOfLinkedFunctionCheck
;
249 m_callCompilationInfo
[callLinkInfoIndex
].callLinkInfo
= info
;
251 checkStackPointerAlignment();
252 m_callCompilationInfo
[callLinkInfoIndex
].hotPathOther
= emitNakedCall();
254 addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock
) * sizeof(Register
)), callFrameRegister
, stackPointerRegister
);
255 checkStackPointerAlignment();
257 sampleCodeBlock(m_codeBlock
);
258 emitPutCallResult(instruction
);
261 void JIT::compileOpCallSlowCase(OpcodeID opcodeID
, Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned callLinkInfoIndex
)
263 if (opcodeID
== op_call_eval
) {
264 compileCallEvalSlowCase(instruction
, iter
);
271 ThunkGenerator generator
= linkThunkGeneratorFor(
272 (opcodeID
== op_construct
|| opcodeID
== op_construct_varargs
) ? CodeForConstruct
: CodeForCall
,
273 RegisterPreservationNotRequired
);
275 move(TrustedImmPtr(m_callCompilationInfo
[callLinkInfoIndex
].callLinkInfo
), regT2
);
276 m_callCompilationInfo
[callLinkInfoIndex
].callReturnLocation
= emitNakedCall(m_vm
->getCTIStub(generator
).code());
278 addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock
) * sizeof(Register
)), callFrameRegister
, stackPointerRegister
);
279 checkStackPointerAlignment();
281 sampleCodeBlock(m_codeBlock
);
282 emitPutCallResult(instruction
);
287 #endif // USE(JSVALUE32_64)
288 #endif // ENABLE(JIT)