2 * Copyright (C) 2008, 2013 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 "JITInlines.h"
35 #include "JITStubCall.h"
37 #include "JSFunction.h"
38 #include "Interpreter.h"
39 #include "Operations.h"
40 #include "RepatchBuffer.h"
41 #include "ResultType.h"
42 #include "SamplingTool.h"
43 #include "ThunkGenerators.h"
44 #include <wtf/StringPrintStream.h>
54 void JIT::emit_op_call_put_result(Instruction
* instruction
)
56 int dst
= instruction
[1].u
.operand
;
57 emitValueProfilingSite();
58 emitPutVirtualRegister(dst
);
59 if (canBeOptimizedOrInlined())
60 killLastResultRegister(); // Make lastResultRegister tracking simpler in the DFG.
63 void JIT::compileLoadVarargs(Instruction
* instruction
)
65 int thisValue
= instruction
[2].u
.operand
;
66 int arguments
= instruction
[3].u
.operand
;
67 int firstFreeRegister
= instruction
[4].u
.operand
;
69 killLastResultRegister();
73 bool canOptimize
= m_codeBlock
->usesArguments()
74 && arguments
== m_codeBlock
->argumentsRegister()
75 && !m_codeBlock
->symbolTable()->slowArguments();
78 emitGetVirtualRegister(arguments
, regT0
);
79 slowCase
.append(branch64(NotEqual
, regT0
, TrustedImm64(JSValue::encode(JSValue()))));
81 emitGetFromCallFrameHeader32(JSStack::ArgumentCount
, regT0
);
82 slowCase
.append(branch32(Above
, regT0
, TrustedImm32(Arguments::MaxArguments
+ 1)));
83 // regT0: argumentCountIncludingThis
86 add32(TrustedImm32(firstFreeRegister
+ JSStack::CallFrameHeaderSize
), regT1
);
87 lshift32(TrustedImm32(3), regT1
);
88 addPtr(callFrameRegister
, regT1
);
89 // regT1: newCallFrame
91 slowCase
.append(branchPtr(Below
, AbsoluteAddress(m_vm
->interpreter
->stack().addressOfEnd()), regT1
));
93 // Initialize ArgumentCount.
94 store32(regT0
, Address(regT1
, JSStack::ArgumentCount
* static_cast<int>(sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)));
97 emitGetVirtualRegister(thisValue
, regT2
);
98 store64(regT2
, Address(regT1
, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
))));
102 signExtend32ToPtr(regT0
, regT0
);
103 end
.append(branchAdd64(Zero
, TrustedImm32(1), regT0
));
104 // regT0: -argumentCount
106 Label copyLoop
= label();
107 load64(BaseIndex(callFrameRegister
, regT0
, TimesEight
, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
))), regT2
);
108 store64(regT2
, BaseIndex(regT1
, regT0
, TimesEight
, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register
))));
109 branchAdd64(NonZero
, TrustedImm32(1), regT0
).linkTo(copyLoop
, this);
117 JITStubCall
stubCall(this, cti_op_load_varargs
);
118 stubCall
.addArgument(thisValue
, regT0
);
119 stubCall
.addArgument(arguments
, regT0
);
120 stubCall
.addArgument(Imm32(firstFreeRegister
));
121 stubCall
.call(regT1
);
127 void JIT::compileCallEval()
129 JITStubCall
stubCall(this, cti_op_call_eval
); // Initializes ScopeChain; ReturnPC; CodeBlock.
131 addSlowCase(branch64(Equal
, regT0
, TrustedImm64(JSValue::encode(JSValue()))));
132 emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame
, callFrameRegister
);
134 sampleCodeBlock(m_codeBlock
);
137 void JIT::compileCallEvalSlowCase(Vector
<SlowCaseEntry
>::iterator
& iter
)
141 emitGetFromCallFrameHeader64(JSStack::Callee
, regT0
);
142 emitNakedCall(m_vm
->getCTIStub(virtualCallGenerator
).code());
144 sampleCodeBlock(m_codeBlock
);
147 void JIT::compileOpCall(OpcodeID opcodeID
, Instruction
* instruction
, unsigned callLinkInfoIndex
)
149 int callee
= instruction
[1].u
.operand
;
152 - Updates callFrameRegister to callee callFrame.
153 - Initializes ArgumentCount; CallerFrame; Callee.
156 - Caller initializes ScopeChain.
157 - Callee initializes ReturnPC; CodeBlock.
158 - Callee restores callFrameRegister before return.
161 - Caller initializes ScopeChain; ReturnPC; CodeBlock.
162 - Caller restores callFrameRegister after return.
165 if (opcodeID
== op_call_varargs
)
166 compileLoadVarargs(instruction
);
168 int argCount
= instruction
[2].u
.operand
;
169 int registerOffset
= instruction
[3].u
.operand
;
171 if (opcodeID
== op_call
&& shouldEmitProfiling()) {
172 emitGetVirtualRegister(registerOffset
+ CallFrame::argumentOffsetIncludingThis(0), regT0
);
173 Jump done
= emitJumpIfNotJSCell(regT0
);
174 loadPtr(Address(regT0
, JSCell::structureOffset()), regT0
);
175 storePtr(regT0
, instruction
[5].u
.arrayProfile
->addressOfLastSeenStructure());
179 addPtr(TrustedImm32(registerOffset
* sizeof(Register
)), callFrameRegister
, regT1
);
180 store32(TrustedImm32(argCount
), Address(regT1
, JSStack::ArgumentCount
* static_cast<int>(sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.payload
)));
181 } // regT1 holds newCallFrame with ArgumentCount initialized.
183 store32(TrustedImm32(instruction
- m_codeBlock
->instructions().begin()), Address(callFrameRegister
, JSStack::ArgumentCount
* static_cast<int>(sizeof(Register
)) + OBJECT_OFFSETOF(EncodedValueDescriptor
, asBits
.tag
)));
184 emitGetVirtualRegister(callee
, regT0
); // regT0 holds callee.
186 store64(callFrameRegister
, Address(regT1
, JSStack::CallerFrame
* static_cast<int>(sizeof(Register
))));
187 store64(regT0
, Address(regT1
, JSStack::Callee
* static_cast<int>(sizeof(Register
))));
188 move(regT1
, callFrameRegister
);
190 if (opcodeID
== op_call_eval
) {
195 DataLabelPtr addressOfLinkedFunctionCheck
;
196 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
197 Jump slowCase
= branchPtrWithPatch(NotEqual
, regT0
, addressOfLinkedFunctionCheck
, TrustedImmPtr(0));
198 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
199 addSlowCase(slowCase
);
201 ASSERT(m_callStructureStubCompilationInfo
.size() == callLinkInfoIndex
);
202 m_callStructureStubCompilationInfo
.append(StructureStubCompilationInfo());
203 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathBegin
= addressOfLinkedFunctionCheck
;
204 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].callType
= CallLinkInfo::callTypeFor(opcodeID
);
205 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].bytecodeIndex
= m_bytecodeOffset
;
207 loadPtr(Address(regT0
, OBJECT_OFFSETOF(JSFunction
, m_scope
)), regT1
);
208 emitPutToCallFrameHeader(regT1
, JSStack::ScopeChain
);
209 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathOther
= emitNakedCall();
211 sampleCodeBlock(m_codeBlock
);
214 void JIT::compileOpCallSlowCase(OpcodeID opcodeID
, Instruction
*, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned callLinkInfoIndex
)
216 if (opcodeID
== op_call_eval
) {
217 compileCallEvalSlowCase(iter
);
223 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].callReturnLocation
= emitNakedCall(opcodeID
== op_construct
? m_vm
->getCTIStub(linkConstructGenerator
).code() : m_vm
->getCTIStub(linkCallGenerator
).code());
225 sampleCodeBlock(m_codeBlock
);
228 void JIT::privateCompileClosureCall(CallLinkInfo
* callLinkInfo
, CodeBlock
* calleeCodeBlock
, Structure
* expectedStructure
, ExecutableBase
* expectedExecutable
, MacroAssemblerCodePtr codePtr
)
232 slowCases
.append(branchTestPtr(NonZero
, regT0
, tagMaskRegister
));
233 slowCases
.append(branchPtr(NotEqual
, Address(regT0
, JSCell::structureOffset()), TrustedImmPtr(expectedStructure
)));
234 slowCases
.append(branchPtr(NotEqual
, Address(regT0
, JSFunction::offsetOfExecutable()), TrustedImmPtr(expectedExecutable
)));
236 loadPtr(Address(regT0
, JSFunction::offsetOfScopeChain()), regT1
);
237 emitPutToCallFrameHeader(regT1
, JSStack::ScopeChain
);
239 Call call
= nearCall();
242 slowCases
.link(this);
243 move(TrustedImmPtr(callLinkInfo
->callReturnLocation
.executableAddress()), regT2
);
244 restoreReturnAddressBeforeReturn(regT2
);
247 LinkBuffer
patchBuffer(*m_vm
, this, m_codeBlock
);
249 patchBuffer
.link(call
, FunctionPtr(codePtr
.executableAddress()));
250 patchBuffer
.link(done
, callLinkInfo
->hotPathOther
.labelAtOffset(0));
251 patchBuffer
.link(slow
, CodeLocationLabel(m_vm
->getCTIStub(virtualCallGenerator
).code()));
253 RefPtr
<ClosureCallStubRoutine
> stubRoutine
= adoptRef(new ClosureCallStubRoutine(
256 ("Baseline closure call stub for %s, return point %p, target %p (%s)",
257 toCString(*m_codeBlock
).data(),
258 callLinkInfo
->hotPathOther
.labelAtOffset(0).executableAddress(),
259 codePtr
.executableAddress(),
260 toCString(pointerDump(calleeCodeBlock
)).data())),
261 *m_vm
, m_codeBlock
->ownerExecutable(), expectedStructure
, expectedExecutable
,
262 callLinkInfo
->codeOrigin
));
264 RepatchBuffer
repatchBuffer(m_codeBlock
);
266 repatchBuffer
.replaceWithJump(
267 RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo
->hotPathBegin
),
268 CodeLocationLabel(stubRoutine
->code().code()));
269 repatchBuffer
.relink(callLinkInfo
->callReturnLocation
, m_vm
->getCTIStub(virtualCallGenerator
).code());
271 callLinkInfo
->stub
= stubRoutine
.release();
276 #endif // USE(JSVALUE64)
277 #endif // ENABLE(JIT)