]> git.saurik.com Git - apple/javascriptcore.git/blame - jit/JITCall.cpp
JavaScriptCore-1218.34.tar.gz
[apple/javascriptcore.git] / jit / JITCall.cpp
CommitLineData
9dae56ea 1/*
93a37866 2 * Copyright (C) 2008, 2013 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 31
6fe7ccc8 32#include "Arguments.h"
9dae56ea 33#include "CodeBlock.h"
93a37866 34#include "JITInlines.h"
ba379fdc 35#include "JITStubCall.h"
9dae56ea
A
36#include "JSArray.h"
37#include "JSFunction.h"
38#include "Interpreter.h"
93a37866
A
39#include "Operations.h"
40#include "RepatchBuffer.h"
9dae56ea
A
41#include "ResultType.h"
42#include "SamplingTool.h"
93a37866
A
43#include "ThunkGenerators.h"
44#include <wtf/StringPrintStream.h>
9dae56ea
A
45
46#ifndef NDEBUG
47#include <stdio.h>
48#endif
49
50using namespace std;
51
52namespace JSC {
53
14957cd0 54void JIT::emit_op_call_put_result(Instruction* instruction)
ba379fdc
A
55{
56 int dst = instruction[1].u.operand;
6fe7ccc8 57 emitValueProfilingSite();
14957cd0 58 emitPutVirtualRegister(dst);
93a37866 59 if (canBeOptimizedOrInlined())
6fe7ccc8 60 killLastResultRegister(); // Make lastResultRegister tracking simpler in the DFG.
9dae56ea
A
61}
62
6fe7ccc8 63void JIT::compileLoadVarargs(Instruction* instruction)
ba379fdc 64{
6fe7ccc8
A
65 int thisValue = instruction[2].u.operand;
66 int arguments = instruction[3].u.operand;
67 int firstFreeRegister = instruction[4].u.operand;
ba379fdc 68
6fe7ccc8 69 killLastResultRegister();
ba379fdc 70
6fe7ccc8
A
71 JumpList slowCase;
72 JumpList end;
93a37866
A
73 bool canOptimize = m_codeBlock->usesArguments()
74 && arguments == m_codeBlock->argumentsRegister()
75 && !m_codeBlock->symbolTable()->slowArguments();
76
77 if (canOptimize) {
6fe7ccc8 78 emitGetVirtualRegister(arguments, regT0);
93a37866 79 slowCase.append(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(JSValue()))));
14957cd0 80
93a37866 81 emitGetFromCallFrameHeader32(JSStack::ArgumentCount, regT0);
6fe7ccc8
A
82 slowCase.append(branch32(Above, regT0, TrustedImm32(Arguments::MaxArguments + 1)));
83 // regT0: argumentCountIncludingThis
9dae56ea 84
6fe7ccc8 85 move(regT0, regT1);
93a37866 86 add32(TrustedImm32(firstFreeRegister + JSStack::CallFrameHeaderSize), regT1);
6fe7ccc8
A
87 lshift32(TrustedImm32(3), regT1);
88 addPtr(callFrameRegister, regT1);
89 // regT1: newCallFrame
ba379fdc 90
93a37866 91 slowCase.append(branchPtr(Below, AbsoluteAddress(m_vm->interpreter->stack().addressOfEnd()), regT1));
9dae56ea 92
6fe7ccc8 93 // Initialize ArgumentCount.
93a37866 94 store32(regT0, Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
9dae56ea 95
6fe7ccc8
A
96 // Initialize 'this'.
97 emitGetVirtualRegister(thisValue, regT2);
93a37866 98 store64(regT2, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))));
9dae56ea 99
6fe7ccc8
A
100 // Copy arguments.
101 neg32(regT0);
102 signExtend32ToPtr(regT0, regT0);
93a37866 103 end.append(branchAdd64(Zero, TrustedImm32(1), regT0));
6fe7ccc8 104 // regT0: -argumentCount
9dae56ea 105
6fe7ccc8 106 Label copyLoop = label();
93a37866
A
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);
9dae56ea 110
6fe7ccc8
A
111 end.append(jump());
112 }
9dae56ea 113
93a37866 114 if (canOptimize)
6fe7ccc8 115 slowCase.link(this);
9dae56ea 116
6fe7ccc8
A
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);
122
93a37866 123 if (canOptimize)
6fe7ccc8 124 end.link(this);
9dae56ea
A
125}
126
6fe7ccc8 127void JIT::compileCallEval()
9dae56ea 128{
6fe7ccc8 129 JITStubCall stubCall(this, cti_op_call_eval); // Initializes ScopeChain; ReturnPC; CodeBlock.
14957cd0 130 stubCall.call();
93a37866
A
131 addSlowCase(branch64(Equal, regT0, TrustedImm64(JSValue::encode(JSValue()))));
132 emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, callFrameRegister);
9dae56ea
A
133
134 sampleCodeBlock(m_codeBlock);
135}
136
6fe7ccc8
A
137void JIT::compileCallEvalSlowCase(Vector<SlowCaseEntry>::iterator& iter)
138{
139 linkSlowCase(iter);
140
93a37866
A
141 emitGetFromCallFrameHeader64(JSStack::Callee, regT0);
142 emitNakedCall(m_vm->getCTIStub(virtualCallGenerator).code());
9dae56ea 143
6fe7ccc8
A
144 sampleCodeBlock(m_codeBlock);
145}
9dae56ea
A
146
147void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
148{
14957cd0 149 int callee = instruction[1].u.operand;
9dae56ea 150
6fe7ccc8
A
151 /* Caller always:
152 - Updates callFrameRegister to callee callFrame.
153 - Initializes ArgumentCount; CallerFrame; Callee.
154
155 For a JS call:
156 - Caller initializes ScopeChain.
157 - Callee initializes ReturnPC; CodeBlock.
158 - Callee restores callFrameRegister before return.
159
160 For a non-JS call:
161 - Caller initializes ScopeChain; ReturnPC; CodeBlock.
162 - Caller restores callFrameRegister after return.
163 */
164
165 if (opcodeID == op_call_varargs)
166 compileLoadVarargs(instruction);
167 else {
168 int argCount = instruction[2].u.operand;
169 int registerOffset = instruction[3].u.operand;
170
93a37866
A
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());
176 done.link(this);
177 }
178
6fe7ccc8 179 addPtr(TrustedImm32(registerOffset * sizeof(Register)), callFrameRegister, regT1);
93a37866 180 store32(TrustedImm32(argCount), Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
6fe7ccc8
A
181 } // regT1 holds newCallFrame with ArgumentCount initialized.
182
93a37866 183 store32(TrustedImm32(instruction - m_codeBlock->instructions().begin()), Address(callFrameRegister, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
6fe7ccc8
A
184 emitGetVirtualRegister(callee, regT0); // regT0 holds callee.
185
93a37866
A
186 store64(callFrameRegister, Address(regT1, JSStack::CallerFrame * static_cast<int>(sizeof(Register))));
187 store64(regT0, Address(regT1, JSStack::Callee * static_cast<int>(sizeof(Register))));
6fe7ccc8
A
188 move(regT1, callFrameRegister);
189
9dae56ea 190 if (opcodeID == op_call_eval) {
6fe7ccc8
A
191 compileCallEval();
192 return;
9dae56ea
A
193 }
194
9dae56ea 195 DataLabelPtr addressOfLinkedFunctionCheck;
f9bf01c6 196 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
93a37866 197 Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
f9bf01c6 198 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
6fe7ccc8 199 addSlowCase(slowCase);
f9bf01c6 200
6fe7ccc8
A
201 ASSERT(m_callStructureStubCompilationInfo.size() == callLinkInfoIndex);
202 m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo());
9dae56ea 203 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
6fe7ccc8
A
204 m_callStructureStubCompilationInfo[callLinkInfoIndex].callType = CallLinkInfo::callTypeFor(opcodeID);
205 m_callStructureStubCompilationInfo[callLinkInfoIndex].bytecodeIndex = m_bytecodeOffset;
9dae56ea 206
93a37866
A
207 loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scope)), regT1);
208 emitPutToCallFrameHeader(regT1, JSStack::ScopeChain);
ba379fdc 209 m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
9dae56ea 210
9dae56ea
A
211 sampleCodeBlock(m_codeBlock);
212}
213
6fe7ccc8 214void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction*, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex)
9dae56ea 215{
6fe7ccc8
A
216 if (opcodeID == op_call_eval) {
217 compileCallEvalSlowCase(iter);
218 return;
219 }
9dae56ea
A
220
221 linkSlowCase(iter);
6fe7ccc8 222
93a37866 223 m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_vm->getCTIStub(linkConstructGenerator).code() : m_vm->getCTIStub(linkCallGenerator).code());
9dae56ea 224
9dae56ea
A
225 sampleCodeBlock(m_codeBlock);
226}
227
93a37866
A
228void JIT::privateCompileClosureCall(CallLinkInfo* callLinkInfo, CodeBlock* calleeCodeBlock, Structure* expectedStructure, ExecutableBase* expectedExecutable, MacroAssemblerCodePtr codePtr)
229{
230 JumpList slowCases;
231
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)));
235
236 loadPtr(Address(regT0, JSFunction::offsetOfScopeChain()), regT1);
237 emitPutToCallFrameHeader(regT1, JSStack::ScopeChain);
238
239 Call call = nearCall();
240 Jump done = jump();
241
242 slowCases.link(this);
243 move(TrustedImmPtr(callLinkInfo->callReturnLocation.executableAddress()), regT2);
244 restoreReturnAddressBeforeReturn(regT2);
245 Jump slow = jump();
246
247 LinkBuffer patchBuffer(*m_vm, this, m_codeBlock);
248
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()));
252
253 RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine(
254 FINALIZE_CODE(
255 patchBuffer,
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));
263
264 RepatchBuffer repatchBuffer(m_codeBlock);
265
266 repatchBuffer.replaceWithJump(
267 RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo->hotPathBegin),
268 CodeLocationLabel(stubRoutine->code().code()));
269 repatchBuffer.relink(callLinkInfo->callReturnLocation, m_vm->getCTIStub(virtualCallGenerator).code());
270
271 callLinkInfo->stub = stubRoutine.release();
272}
273
9dae56ea
A
274} // namespace JSC
275
14957cd0 276#endif // USE(JSVALUE64)
9dae56ea 277#endif // ENABLE(JIT)