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 "CodeBlock.h"
33 #include "JITInlineMethods.h"
34 #include "JITStubCall.h"
36 #include "JSFunction.h"
37 #include "Interpreter.h"
38 #include "ResultType.h"
39 #include "SamplingTool.h"
49 void JIT::compileOpCallInitializeCallFrame()
51 // regT0 holds callee, regT1 holds argCount
52 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT3); // scopeChain
53 emitPutIntToCallFrameHeader(regT1, RegisterFile::ArgumentCount);
54 emitPutCellToCallFrameHeader(regT0, RegisterFile::Callee);
55 emitPutCellToCallFrameHeader(regT3, RegisterFile::ScopeChain);
58 void JIT::emit_op_call_put_result(Instruction* instruction)
60 int dst = instruction[1].u.operand;
61 emitValueProfilingSite(FirstProfilingSite);
62 emitPutVirtualRegister(dst);
65 void JIT::compileOpCallVarargs(Instruction* instruction)
67 int callee = instruction[1].u.operand;
68 int argCountRegister = instruction[2].u.operand;
69 int registerOffset = instruction[3].u.operand;
71 emitGetVirtualRegister(argCountRegister, regT1);
72 emitFastArithImmToInt(regT1);
73 emitGetVirtualRegister(callee, regT0);
74 addPtr(Imm32(registerOffset), regT1, regT2);
76 // Check for JSFunctions.
77 emitJumpSlowCaseIfNotJSCell(regT0);
78 addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
80 // Speculatively roll the callframe, assuming argCount will match the arity.
81 mul32(TrustedImm32(sizeof(Register)), regT2, regT2);
82 intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
83 addPtr(Imm32((int32_t)offset), regT2, regT3);
84 addPtr(callFrameRegister, regT3);
85 storePtr(callFrameRegister, regT3);
86 addPtr(regT2, callFrameRegister);
87 emitNakedCall(m_globalData->jitStubs->ctiVirtualCall());
89 sampleCodeBlock(m_codeBlock);
92 void JIT::compileOpCallVarargsSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator& iter)
97 JITStubCall stubCall(this, cti_op_call_NotJSFunction);
98 stubCall.addArgument(regT0);
99 stubCall.addArgument(regT2);
100 stubCall.addArgument(regT1);
103 sampleCodeBlock(m_codeBlock);
106 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
108 int callee = instruction[1].u.operand;
109 int argCount = instruction[2].u.operand;
110 int registerOffset = instruction[3].u.operand;
114 if (opcodeID == op_call_eval) {
115 JITStubCall stubCall(this, cti_op_call_eval);
116 stubCall.addArgument(callee, regT0);
117 stubCall.addArgument(JIT::Imm32(registerOffset));
118 stubCall.addArgument(JIT::Imm32(argCount));
120 wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())));
123 // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
124 // This deliberately leaves the callee in ecx, used when setting up the stack frame below
125 emitGetVirtualRegister(callee, regT0);
126 DataLabelPtr addressOfLinkedFunctionCheck;
128 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
130 Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(JSValue::encode(JSValue())));
132 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
134 addSlowCase(jumpToSlow);
135 ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
137 ASSERT(m_callStructureStubCompilationInfo.size() == callLinkInfoIndex);
138 m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo());
139 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
140 m_callStructureStubCompilationInfo[callLinkInfoIndex].isCall = opcodeID != op_construct;
142 // The following is the fast case, only used whan a callee can be linked.
144 // Fast version of stack frame initialization, directly relative to edi.
145 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
147 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1); // newScopeChain
149 store32(TrustedImm32(Int32Tag), intTagFor(registerOffset + RegisterFile::ArgumentCount));
150 store32(Imm32(argCount), intPayloadFor(registerOffset + RegisterFile::ArgumentCount));
151 storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
152 storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
153 storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
154 addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
156 // Call to the callee
157 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
159 if (opcodeID == op_call_eval)
162 sampleCodeBlock(m_codeBlock);
165 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
167 int argCount = instruction[2].u.operand;
168 int registerOffset = instruction[3].u.operand;
172 // Fast check for JS function.
173 Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
174 Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr));
176 // Speculatively roll the callframe, assuming argCount will match the arity.
177 storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
178 addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
179 move(Imm32(argCount), regT1);
181 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink());
183 // Done! - return back to the hot path.
184 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
185 ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
186 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
188 // This handles host functions
189 callLinkFailNotObject.link(this);
190 callLinkFailNotJSFunction.link(this);
192 JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
193 stubCall.addArgument(regT0);
194 stubCall.addArgument(JIT::Imm32(registerOffset));
195 stubCall.addArgument(JIT::Imm32(argCount));
198 sampleCodeBlock(m_codeBlock);
203 #endif // USE(JSVALUE64)
204 #endif // ENABLE(JIT)