2011-07-05 Filip Pizlo <fpizlo@apple.com>
[WebKit-https.git] / Source / JavaScriptCore / jit / JITCall.cpp
1 /*
2  * Copyright (C) 2008 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 "CodeBlock.h"
33 #include "JITInlineMethods.h"
34 #include "JITStubCall.h"
35 #include "JSArray.h"
36 #include "JSFunction.h"
37 #include "Interpreter.h"
38 #include "ResultType.h"
39 #include "SamplingTool.h"
40
41 #ifndef NDEBUG
42 #include <stdio.h>
43 #endif
44
45 using namespace std;
46
47 namespace JSC {
48
49 void JIT::compileOpCallInitializeCallFrame()
50 {
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);
56 }
57
58 void JIT::emit_op_call_put_result(Instruction* instruction)
59 {
60     int dst = instruction[1].u.operand;
61     emitPutVirtualRegister(dst);
62 }
63
64 void JIT::compileOpCallVarargs(Instruction* instruction)
65 {
66     int callee = instruction[1].u.operand;
67     int argCountRegister = instruction[2].u.operand;
68     int registerOffset = instruction[3].u.operand;
69
70     emitGetVirtualRegister(argCountRegister, regT1);
71     emitFastArithImmToInt(regT1);
72     emitGetVirtualRegister(callee, regT0);
73     addPtr(Imm32(registerOffset), regT1, regT2);
74
75     // Check for JSFunctions.
76     emitJumpSlowCaseIfNotJSCell(regT0);
77     addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
78
79     // Speculatively roll the callframe, assuming argCount will match the arity.
80     mul32(TrustedImm32(sizeof(Register)), regT2, regT2);
81     intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
82     addPtr(Imm32((int32_t)offset), regT2, regT3);
83     addPtr(callFrameRegister, regT3);
84     storePtr(callFrameRegister, regT3);
85     addPtr(regT2, callFrameRegister);
86     emitNakedCall(m_globalData->jitStubs->ctiVirtualCall());
87
88     sampleCodeBlock(m_codeBlock);
89 }
90
91 void JIT::compileOpCallVarargsSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator& iter)
92 {
93     linkSlowCase(iter);
94     linkSlowCase(iter);
95
96     JITStubCall stubCall(this, cti_op_call_NotJSFunction);
97     stubCall.addArgument(regT0);
98     stubCall.addArgument(regT2);
99     stubCall.addArgument(regT1);
100     stubCall.call();
101     
102     sampleCodeBlock(m_codeBlock);
103 }
104     
105 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
106 {
107     int callee = instruction[1].u.operand;
108     int argCount = instruction[2].u.operand;
109     int registerOffset = instruction[3].u.operand;
110
111     // Handle eval
112     Jump wasEval;
113     if (opcodeID == op_call_eval) {
114         JITStubCall stubCall(this, cti_op_call_eval);
115         stubCall.addArgument(callee, regT0);
116         stubCall.addArgument(JIT::Imm32(registerOffset));
117         stubCall.addArgument(JIT::Imm32(argCount));
118         stubCall.call();
119         wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())));
120     }
121
122     // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
123     // This deliberately leaves the callee in ecx, used when setting up the stack frame below
124     emitGetVirtualRegister(callee, regT0);
125     DataLabelPtr addressOfLinkedFunctionCheck;
126
127     BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
128
129     Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(JSValue::encode(JSValue())));
130
131     END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
132
133     addSlowCase(jumpToSlow);
134     ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
135     
136     ASSERT(m_callStructureStubCompilationInfo.size() == callLinkInfoIndex);
137     m_callStructureStubCompilationInfo.append(StructureStubCompilationInfo());
138     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
139     m_callStructureStubCompilationInfo[callLinkInfoIndex].isCall = opcodeID != op_construct;
140
141     // The following is the fast case, only used whan a callee can be linked.
142
143     // Fast version of stack frame initialization, directly relative to edi.
144     // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
145
146     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1); // newScopeChain
147     
148     store32(TrustedImm32(Int32Tag), intTagFor(registerOffset + RegisterFile::ArgumentCount));
149     store32(Imm32(argCount), intPayloadFor(registerOffset + RegisterFile::ArgumentCount));
150     storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
151     storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
152     storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
153     addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
154
155     // Call to the callee
156     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
157     
158     if (opcodeID == op_call_eval)
159         wasEval.link(this);
160
161     sampleCodeBlock(m_codeBlock);
162 }
163
164 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
165 {
166     int argCount = instruction[2].u.operand;
167     int registerOffset = instruction[3].u.operand;
168
169     linkSlowCase(iter);
170
171     // Fast check for JS function.
172     Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
173     Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr));
174
175     // Speculatively roll the callframe, assuming argCount will match the arity.
176     storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
177     addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
178     move(Imm32(argCount), regT1);
179
180     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink());
181
182     // Done! - return back to the hot path.
183     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
184     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_construct));
185     emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
186
187     // This handles host functions
188     callLinkFailNotObject.link(this);
189     callLinkFailNotJSFunction.link(this);
190
191     JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
192     stubCall.addArgument(regT0);
193     stubCall.addArgument(JIT::Imm32(registerOffset));
194     stubCall.addArgument(JIT::Imm32(argCount));
195     stubCall.call();
196
197     sampleCodeBlock(m_codeBlock);
198 }
199
200 } // namespace JSC
201
202 #endif // USE(JSVALUE64)
203 #endif // ENABLE(JIT)