Replace jsFunctionVPtr compares with a type check on the Structure.
[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     emitValueProfilingSite(FirstProfilingSite);
62     emitPutVirtualRegister(dst);
63 }
64
65 void JIT::compileOpCallVarargs(Instruction* instruction)
66 {
67     int callee = instruction[1].u.operand;
68     int argCountRegister = instruction[2].u.operand;
69     int registerOffset = instruction[3].u.operand;
70
71     emitGetVirtualRegister(argCountRegister, regT1);
72     emitFastArithImmToInt(regT1);
73     emitGetVirtualRegister(callee, regT0);
74     addPtr(Imm32(registerOffset), regT1, regT2);
75
76     // Check for JSFunctions.
77     emitJumpSlowCaseIfNotJSCell(regT0);
78     addSlowCase(emitJumpIfNotType(regT0, regT3, JSFunctionType));
79
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());
88
89     sampleCodeBlock(m_codeBlock);
90 }
91
92 void JIT::compileOpCallVarargsSlowCase(Instruction*, Vector<SlowCaseEntry>::iterator& iter)
93 {
94     linkSlowCase(iter);
95     linkSlowCase(iter);
96
97     JITStubCall stubCall(this, cti_op_call_NotJSFunction);
98     stubCall.addArgument(regT0);
99     stubCall.addArgument(regT2);
100     stubCall.addArgument(regT1);
101     stubCall.call();
102     
103     sampleCodeBlock(m_codeBlock);
104 }
105     
106 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
107 {
108     int callee = instruction[1].u.operand;
109     int argCount = instruction[2].u.operand;
110     int registerOffset = instruction[3].u.operand;
111
112     // Handle eval
113     Jump wasEval;
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));
119         stubCall.call();
120         wasEval = branchPtr(NotEqual, regT0, TrustedImmPtr(JSValue::encode(JSValue())));
121     }
122
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;
127
128     BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
129
130     Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(JSValue::encode(JSValue())));
131
132     END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
133
134     addSlowCase(jumpToSlow);
135     ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
136     
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;
141
142     // The following is the fast case, only used whan a callee can be linked.
143
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
146
147     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_scopeChain)), regT1); // newScopeChain
148     
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);
155
156     // Call to the callee
157     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
158     
159     if (opcodeID == op_call_eval)
160         wasEval.link(this);
161
162     sampleCodeBlock(m_codeBlock);
163 }
164
165 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
166 {
167     int argCount = instruction[2].u.operand;
168     int registerOffset = instruction[3].u.operand;
169
170     linkSlowCase(iter);
171
172     // Fast check for JS function.
173     Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
174     Jump callLinkFailNotJSFunction = emitJumpIfNotType(regT0, regT3, JSFunctionType);
175
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);
180
181     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(opcodeID == op_construct ? m_globalData->jitStubs->ctiVirtualConstructLink() : m_globalData->jitStubs->ctiVirtualCallLink());
182
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));
187
188     // This handles host functions
189     callLinkFailNotObject.link(this);
190     callLinkFailNotJSFunction.link(this);
191
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));
196     stubCall.call();
197
198     sampleCodeBlock(m_codeBlock);
199 }
200
201 } // namespace JSC
202
203 #endif // USE(JSVALUE64)
204 #endif // ENABLE(JIT)