2 * Copyright (C) 2008 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 "Arguments.h"
33 #include "CodeBlock.h"
34 #include "Interpreter.h"
35 #include "JITInlineMethods.h"
36 #include "JITStubCall.h"
38 #include "JSFunction.h"
39 #include "ResultType.h"
40 #include "SamplingTool.h"
50 void JIT::emit_op_call_put_result(Instruction
* instruction
)
52 int dst
= instruction
[1].u
.operand
;
53 emitValueProfilingSite();
54 emitStore(dst
, regT1
, regT0
);
57 void JIT::emit_op_ret(Instruction
* currentInstruction
)
59 emitOptimizationCheck(RetOptimizationCheck
);
61 unsigned dst
= currentInstruction
[1].u
.operand
;
63 emitLoad(dst
, regT1
, regT0
);
64 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC
, regT2
);
65 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame
, callFrameRegister
);
67 restoreReturnAddressBeforeReturn(regT2
);
71 void JIT::emit_op_ret_object_or_this(Instruction
* currentInstruction
)
73 emitOptimizationCheck(RetOptimizationCheck
);
75 unsigned result
= currentInstruction
[1].u
.operand
;
76 unsigned thisReg
= currentInstruction
[2].u
.operand
;
78 emitLoad(result
, regT1
, regT0
);
79 Jump notJSCell
= branch32(NotEqual
, regT1
, TrustedImm32(JSValue::CellTag
));
80 loadPtr(Address(regT0
, JSCell::structureOffset()), regT2
);
81 Jump notObject
= emitJumpIfNotObject(regT2
);
83 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC
, regT2
);
84 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame
, callFrameRegister
);
86 restoreReturnAddressBeforeReturn(regT2
);
91 emitLoad(thisReg
, regT1
, regT0
);
93 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC
, regT2
);
94 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame
, callFrameRegister
);
96 restoreReturnAddressBeforeReturn(regT2
);
100 void JIT::emitSlow_op_call(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
102 compileOpCallSlowCase(op_call
, currentInstruction
, iter
, m_callLinkInfoIndex
++);
105 void JIT::emitSlow_op_call_eval(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
107 compileOpCallSlowCase(op_call_eval
, currentInstruction
, iter
, m_callLinkInfoIndex
);
110 void JIT::emitSlow_op_call_varargs(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
112 compileOpCallSlowCase(op_call_varargs
, currentInstruction
, iter
, m_callLinkInfoIndex
++);
115 void JIT::emitSlow_op_construct(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
117 compileOpCallSlowCase(op_construct
, currentInstruction
, iter
, m_callLinkInfoIndex
++);
120 void JIT::emit_op_call(Instruction
* currentInstruction
)
122 compileOpCall(op_call
, currentInstruction
, m_callLinkInfoIndex
++);
125 void JIT::emit_op_call_eval(Instruction
* currentInstruction
)
127 compileOpCall(op_call_eval
, currentInstruction
, m_callLinkInfoIndex
);
130 void JIT::emit_op_call_varargs(Instruction
* currentInstruction
)
132 compileOpCall(op_call_varargs
, currentInstruction
, m_callLinkInfoIndex
++);
135 void JIT::emit_op_construct(Instruction
* currentInstruction
)
137 compileOpCall(op_construct
, currentInstruction
, m_callLinkInfoIndex
++);
140 void JIT::compileLoadVarargs(Instruction
* instruction
)
142 int thisValue
= instruction
[2].u
.operand
;
143 int arguments
= instruction
[3].u
.operand
;
144 int firstFreeRegister
= instruction
[4].u
.operand
;
148 if (m_codeBlock
->usesArguments() && arguments
== m_codeBlock
->argumentsRegister()) {
149 emitLoadTag(arguments
, regT1
);
150 slowCase
.append(branch32(NotEqual
, regT1
, TrustedImm32(JSValue::EmptyValueTag
)));
152 load32(payloadFor(RegisterFile::ArgumentCount
), regT2
);
153 slowCase
.append(branch32(Above
, regT2
, TrustedImm32(Arguments::MaxArguments
+ 1)));
154 // regT2: argumentCountIncludingThis
157 add32(TrustedImm32(firstFreeRegister
+ RegisterFile::CallFrameHeaderSize
), regT3
);
158 lshift32(TrustedImm32(3), regT3
);
159 addPtr(callFrameRegister
, regT3
);
160 // regT3: newCallFrame
162 slowCase
.append(branchPtr(Below
, AbsoluteAddress(m_globalData
->interpreter
->registerFile().addressOfEnd()), regT3
));
164 // Initialize ArgumentCount.
165 store32(regT2
, payloadFor(RegisterFile::ArgumentCount
, regT3
));
167 // Initialize 'this'.
168 emitLoad(thisValue
, regT1
, regT0
);
169 store32(regT0
, Address(regT3
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
) + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)))));
170 store32(regT1
, Address(regT3
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
) + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)))));
174 end
.append(branchAdd32(Zero
, TrustedImm32(1), regT2
));
175 // regT2: -argumentCount;
177 Label copyLoop
= label();
178 load32(BaseIndex(callFrameRegister
, regT2
, TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)))), regT0
);
179 load32(BaseIndex(callFrameRegister
, regT2
, TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)))), regT1
);
180 store32(regT0
, BaseIndex(regT3
, regT2
, TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.payload
) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)))));
181 store32(regT1
, BaseIndex(regT3
, regT2
, TimesEight
, OBJECT_OFFSETOF(JSValue
, u
.asBits
.tag
) +(CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
)))));
182 branchAdd32(NonZero
, TrustedImm32(1), regT2
).linkTo(copyLoop
, this);
187 if (m_codeBlock
->usesArguments() && arguments
== m_codeBlock
->argumentsRegister())
190 JITStubCall
stubCall(this, cti_op_load_varargs
);
191 stubCall
.addArgument(thisValue
);
192 stubCall
.addArgument(arguments
);
193 stubCall
.addArgument(Imm32(firstFreeRegister
));
194 stubCall
.call(regT3
);
196 if (m_codeBlock
->usesArguments() && arguments
== m_codeBlock
->argumentsRegister())
200 void JIT::compileCallEval()
202 JITStubCall
stubCall(this, cti_op_call_eval
); // Initializes ScopeChain; ReturnPC; CodeBlock.
204 addSlowCase(branch32(Equal
, regT1
, TrustedImm32(JSValue::EmptyValueTag
)));
205 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame
, callFrameRegister
);
207 sampleCodeBlock(m_codeBlock
);
210 void JIT::compileCallEvalSlowCase(Vector
<SlowCaseEntry
>::iterator
& iter
)
214 emitLoad(RegisterFile::Callee
, regT1
, regT0
);
215 emitNakedCall(m_globalData
->jitStubs
->ctiVirtualCall());
217 sampleCodeBlock(m_codeBlock
);
220 void JIT::compileOpCall(OpcodeID opcodeID
, Instruction
* instruction
, unsigned callLinkInfoIndex
)
222 int callee
= instruction
[1].u
.operand
;
225 - Updates callFrameRegister to callee callFrame.
226 - Initializes ArgumentCount; CallerFrame; Callee.
229 - Caller initializes ScopeChain.
230 - Callee initializes ReturnPC; CodeBlock.
231 - Callee restores callFrameRegister before return.
234 - Caller initializes ScopeChain; ReturnPC; CodeBlock.
235 - Caller restores callFrameRegister after return.
238 if (opcodeID
== op_call_varargs
)
239 compileLoadVarargs(instruction
);
241 int argCount
= instruction
[2].u
.operand
;
242 int registerOffset
= instruction
[3].u
.operand
;
244 addPtr(TrustedImm32(registerOffset
* sizeof(Register
)), callFrameRegister
, regT3
);
246 store32(TrustedImm32(argCount
), payloadFor(RegisterFile::ArgumentCount
, regT3
));
247 } // regT3 holds newCallFrame with ArgumentCount initialized.
249 storePtr(TrustedImmPtr(instruction
), tagFor(RegisterFile::ArgumentCount
, callFrameRegister
));
250 emitLoad(callee
, regT1
, regT0
); // regT1, regT0 holds callee.
252 storePtr(callFrameRegister
, Address(regT3
, RegisterFile::CallerFrame
* static_cast<int>(sizeof(Register
))));
253 emitStore(RegisterFile::Callee
, regT1
, regT0
, regT3
);
254 move(regT3
, callFrameRegister
);
256 if (opcodeID
== op_call_eval
) {
261 DataLabelPtr addressOfLinkedFunctionCheck
;
262 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
263 Jump slowCase
= branchPtrWithPatch(NotEqual
, regT0
, addressOfLinkedFunctionCheck
, TrustedImmPtr(0));
264 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
266 addSlowCase(slowCase
);
267 addSlowCase(branch32(NotEqual
, regT1
, TrustedImm32(JSValue::CellTag
)));
269 ASSERT(m_callStructureStubCompilationInfo
.size() == callLinkInfoIndex
);
270 m_callStructureStubCompilationInfo
.append(StructureStubCompilationInfo());
271 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathBegin
= addressOfLinkedFunctionCheck
;
272 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].callType
= CallLinkInfo::callTypeFor(opcodeID
);
273 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].bytecodeIndex
= m_bytecodeOffset
;
275 loadPtr(Address(regT0
, OBJECT_OFFSETOF(JSFunction
, m_scopeChain
)), regT1
);
276 emitPutCellToCallFrameHeader(regT1
, RegisterFile::ScopeChain
);
277 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathOther
= emitNakedCall();
279 sampleCodeBlock(m_codeBlock
);
282 void JIT::compileOpCallSlowCase(OpcodeID opcodeID
, Instruction
*, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned callLinkInfoIndex
)
284 if (opcodeID
== op_call_eval
) {
285 compileCallEvalSlowCase(iter
);
292 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].callReturnLocation
= emitNakedCall(opcodeID
== op_construct
? m_globalData
->jitStubs
->ctiVirtualConstructLink() : m_globalData
->jitStubs
->ctiVirtualCallLink());
294 sampleCodeBlock(m_codeBlock
);
299 #endif // USE(JSVALUE32_64)
300 #endif // ENABLE(JIT)