1/*
2 * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
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"
27
28#if ENABLE(JIT)
29#if USE(JSVALUE64)
30#include "JIT.h"
31
32#include "Arguments.h"
33#include "CodeBlock.h"
34#include "JITInlines.h"
35#include "JITStubCall.h"
36#include "JSArray.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>
45
46#ifndef NDEBUG
47#include <stdio.h>
48#endif
49
50using namespace std;
51
52namespace JSC {
53
54void JIT::emit_op_call_put_result(Instruction* instruction)
55{
56    int dst = instruction[1].u.operand;
57    emitValueProfilingSite();
58    emitPutVirtualRegister(dst);
59    if (canBeOptimizedOrInlined())
60        killLastResultRegister(); // Make lastResultRegister tracking simpler in the DFG.
61}
62
63void JIT::compileLoadVarargs(Instruction* instruction)
64{
65    int thisValue = instruction[2].u.operand;
66    int arguments = instruction[3].u.operand;
67    int firstFreeRegister = instruction[4].u.operand;
68
69    killLastResultRegister();
70
71    JumpList slowCase;
72    JumpList end;
73    bool canOptimize = m_codeBlock->usesArguments()
74        && arguments == m_codeBlock->argumentsRegister()
75        && !m_codeBlock->symbolTable()->slowArguments();
76
77    if (canOptimize) {
78        emitGetVirtualRegister(arguments, regT0);
79        slowCase.append(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(JSValue()))));
80
81        emitGetFromCallFrameHeader32(JSStack::ArgumentCount, regT0);
82        slowCase.append(branch32(Above, regT0, TrustedImm32(Arguments::MaxArguments + 1)));
83        // regT0: argumentCountIncludingThis
84
85        move(regT0, regT1);
86        add32(TrustedImm32(firstFreeRegister + JSStack::CallFrameHeaderSize), regT1);
87        lshift32(TrustedImm32(3), regT1);
88        addPtr(callFrameRegister, regT1);
89        // regT1: newCallFrame
90
91        slowCase.append(branchPtr(Below, AbsoluteAddress(m_vm->interpreter->stack().addressOfEnd()), regT1));
92
93        // Initialize ArgumentCount.
94        store32(regT0, Address(regT1, JSStack::ArgumentCount * static_cast<int>(sizeof(Register)) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
95
96        // Initialize 'this'.
97        emitGetVirtualRegister(thisValue, regT2);
98        store64(regT2, Address(regT1, CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register))));
99
100        // Copy arguments.
101        neg32(regT0);
102        signExtend32ToPtr(regT0, regT0);
103        end.append(branchAdd64(Zero, TrustedImm32(1), regT0));
104        // regT0: -argumentCount
105
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);
110
111        end.append(jump());
112    }
113
114    if (canOptimize)
115        slowCase.link(this);
116
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
123    if (canOptimize)
124        end.link(this);
125}
126
127void JIT::compileCallEval()
128{
129    JITStubCall stubCall(this, cti_op_call_eval); // Initializes ScopeChain; ReturnPC; CodeBlock.
130    stubCall.call();
131    addSlowCase(branch64(Equal, regT0, TrustedImm64(JSValue::encode(JSValue()))));
132    emitGetFromCallFrameHeaderPtr(JSStack::CallerFrame, callFrameRegister);
133
134    sampleCodeBlock(m_codeBlock);
135}
136
137void JIT::compileCallEvalSlowCase(Vector<SlowCaseEntry>::iterator& iter)
138{
139    linkSlowCase(iter);
140
141    emitGetFromCallFrameHeader64(JSStack::Callee, regT0);
142    emitNakedCall(m_vm->getCTIStub(virtualCallGenerator).code());
143
144    sampleCodeBlock(m_codeBlock);
145}
146
147void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
148{
149    int callee = instruction[1].u.operand;
150
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
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
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.
182
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.
185
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);
189
190    if (opcodeID == op_call_eval) {
191        compileCallEval();
192        return;
193    }
194
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);
200
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;
206
207    loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scope)), regT1);
208    emitPutToCallFrameHeader(regT1, JSStack::ScopeChain);
209    m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
210
211    sampleCodeBlock(m_codeBlock);
212}
213
214void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction*, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex)
215{
216    if (opcodeID == op_call_eval) {
217        compileCallEvalSlowCase(iter);
218        return;
219    }
220
221    linkSlowCase(iter);
222
223    m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_vm->getCTIStub(linkConstructGenerator).code() : m_vm->getCTIStub(linkCallGenerator).code());
224
225    sampleCodeBlock(m_codeBlock);
226}
227
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
274} // namespace JSC
275
276#endif // USE(JSVALUE64)
277#endif // ENABLE(JIT)
278