Templatize CodePtr/Refs/FunctionPtrs with PtrTags.
[WebKit-https.git] / Source / JavaScriptCore / jit / JITCall32_64.cpp
1 /*
2  * Copyright (C) 2008-2018 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(JSVALUE32_64)
30 #include "JIT.h"
31
32 #include "CodeBlock.h"
33 #include "Interpreter.h"
34 #include "JITInlines.h"
35 #include "JSArray.h"
36 #include "JSFunction.h"
37 #include "JSCInlines.h"
38 #include "LinkBuffer.h"
39 #include "ResultType.h"
40 #include "SetupVarargsFrame.h"
41 #include "StackAlignment.h"
42 #include "ThunkGenerators.h"
43 #include <wtf/StringPrintStream.h>
44
45 namespace JSC {
46
47 void JIT::emitPutCallResult(Instruction* instruction)
48 {
49     int dst = instruction[1].u.operand;
50     emitValueProfilingSite();
51     emitStore(dst, regT1, regT0);
52 }
53
54 void JIT::emit_op_ret(Instruction* currentInstruction)
55 {
56     unsigned dst = currentInstruction[1].u.operand;
57
58     emitLoad(dst, regT1, regT0);
59
60     checkStackPointerAlignment();
61     emitRestoreCalleeSaves();
62     emitFunctionEpilogue();
63     ret();
64 }
65
66 void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
67 {
68     compileOpCallSlowCase(op_call, currentInstruction, iter, m_callLinkInfoIndex++);
69 }
70
71 void JIT::emitSlow_op_tail_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
72 {
73     compileOpCallSlowCase(op_tail_call, currentInstruction, iter, m_callLinkInfoIndex++);
74 }
75
76 void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
77 {
78     compileOpCallSlowCase(op_call_eval, currentInstruction, iter, m_callLinkInfoIndex);
79 }
80  
81 void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
82 {
83     compileOpCallSlowCase(op_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
84 }
85
86 void JIT::emitSlow_op_tail_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
87 {
88     compileOpCallSlowCase(op_tail_call_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
89 }
90
91 void JIT::emitSlow_op_tail_call_forward_arguments(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
92 {
93     compileOpCallSlowCase(op_tail_call_forward_arguments, currentInstruction, iter, m_callLinkInfoIndex++);
94 }
95     
96 void JIT::emitSlow_op_construct_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
97 {
98     compileOpCallSlowCase(op_construct_varargs, currentInstruction, iter, m_callLinkInfoIndex++);
99 }
100     
101 void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
102 {
103     compileOpCallSlowCase(op_construct, currentInstruction, iter, m_callLinkInfoIndex++);
104 }
105
106 void JIT::emit_op_call(Instruction* currentInstruction)
107 {
108     compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
109 }
110
111 void JIT::emit_op_tail_call(Instruction* currentInstruction)
112 {
113     compileOpCall(op_tail_call, currentInstruction, m_callLinkInfoIndex++);
114 }
115
116 void JIT::emit_op_call_eval(Instruction* currentInstruction)
117 {
118     compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex);
119 }
120
121 void JIT::emit_op_call_varargs(Instruction* currentInstruction)
122 {
123     compileOpCall(op_call_varargs, currentInstruction, m_callLinkInfoIndex++);
124 }
125
126 void JIT::emit_op_tail_call_varargs(Instruction* currentInstruction)
127 {
128     compileOpCall(op_tail_call_varargs, currentInstruction, m_callLinkInfoIndex++);
129 }
130
131 void JIT::emit_op_tail_call_forward_arguments(Instruction* currentInstruction)
132 {
133     compileOpCall(op_tail_call_forward_arguments, currentInstruction, m_callLinkInfoIndex++);
134 }
135     
136 void JIT::emit_op_construct_varargs(Instruction* currentInstruction)
137 {
138     compileOpCall(op_construct_varargs, currentInstruction, m_callLinkInfoIndex++);
139 }
140     
141 void JIT::emit_op_construct(Instruction* currentInstruction)
142 {
143     compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++);
144 }
145
146 void JIT::compileSetupVarargsFrame(OpcodeID opcode, Instruction* instruction, CallLinkInfo* info)
147 {
148     int thisValue = instruction[3].u.operand;
149     int arguments = instruction[4].u.operand;
150     int firstFreeRegister = instruction[5].u.operand;
151     int firstVarArgOffset = instruction[6].u.operand;
152
153     emitLoad(arguments, regT1, regT0);
154     Z_JITOperation_EJZZ sizeOperation;
155     if (opcode == op_tail_call_forward_arguments)
156         sizeOperation = operationSizeFrameForForwardArguments;
157     else
158         sizeOperation = operationSizeFrameForVarargs;
159     callOperation(sizeOperation, JSValueRegs(regT1, regT0), -firstFreeRegister, firstVarArgOffset);
160     move(TrustedImm32(-firstFreeRegister), regT1);
161     emitSetVarargsFrame(*this, returnValueGPR, false, regT1, regT1);
162     addPtr(TrustedImm32(-(sizeof(CallerFrameAndPC) + WTF::roundUpToMultipleOf(stackAlignmentBytes(), 6 * sizeof(void*)))), regT1, stackPointerRegister);
163     emitLoad(arguments, regT2, regT4);
164     F_JITOperation_EFJZZ setupOperation;
165     if (opcode == op_tail_call_forward_arguments)
166         setupOperation = operationSetupForwardArgumentsFrame;
167     else
168         setupOperation = operationSetupVarargsFrame;
169     callOperation(setupOperation, regT1, JSValueRegs(regT2, regT4), firstVarArgOffset, regT0);
170     move(returnValueGPR, regT1);
171
172     // Profile the argument count.
173     load32(Address(regT1, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset), regT2);
174     load32(info->addressOfMaxNumArguments(), regT0);
175     Jump notBiggest = branch32(Above, regT0, regT2);
176     store32(regT2, info->addressOfMaxNumArguments());
177     notBiggest.link(this);
178     
179     // Initialize 'this'.
180     emitLoad(thisValue, regT2, regT0);
181     store32(regT0, Address(regT1, PayloadOffset + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))));
182     store32(regT2, Address(regT1, TagOffset + (CallFrame::thisArgumentOffset() * static_cast<int>(sizeof(Register)))));
183     
184     addPtr(TrustedImm32(sizeof(CallerFrameAndPC)), regT1, stackPointerRegister);
185 }
186
187 void JIT::compileCallEval(Instruction* instruction)
188 {
189     addPtr(TrustedImm32(-static_cast<ptrdiff_t>(sizeof(CallerFrameAndPC))), stackPointerRegister, regT1);
190     storePtr(callFrameRegister, Address(regT1, CallFrame::callerFrameOffset()));
191
192     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
193
194     callOperation(operationCallEval, regT1);
195
196     addSlowCase(branch32(Equal, regT1, TrustedImm32(JSValue::EmptyValueTag)));
197
198     sampleCodeBlock(m_codeBlock);
199     
200     emitPutCallResult(instruction);
201 }
202
203 void JIT::compileCallEvalSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
204 {
205     linkAllSlowCases(iter);
206
207     CallLinkInfo* info = m_codeBlock->addCallLinkInfo();
208     info->setUpCall(CallLinkInfo::Call, CodeOrigin(m_bytecodeOffset), regT0);
209
210     int registerOffset = -instruction[4].u.operand;
211     int callee = instruction[2].u.operand;
212
213     addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
214
215     emitLoad(callee, regT1, regT0);
216     emitDumbVirtualCall(*vm(), info);
217     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
218     checkStackPointerAlignment();
219
220     sampleCodeBlock(m_codeBlock);
221     
222     emitPutCallResult(instruction);
223 }
224
225 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
226 {
227     int callee = instruction[2].u.operand;
228
229     /* Caller always:
230         - Updates callFrameRegister to callee callFrame.
231         - Initializes ArgumentCount; CallerFrame; Callee.
232
233        For a JS call:
234         - Callee initializes ReturnPC; CodeBlock.
235         - Callee restores callFrameRegister before return.
236
237        For a non-JS call:
238         - Caller initializes ReturnPC; CodeBlock.
239         - Caller restores callFrameRegister after return.
240     */
241     CallLinkInfo* info = nullptr;
242     if (opcodeID != op_call_eval)
243         info = m_codeBlock->addCallLinkInfo();
244     if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs || opcodeID == op_tail_call_varargs || opcodeID == op_tail_call_forward_arguments)
245         compileSetupVarargsFrame(opcodeID, instruction, info);
246     else {
247         int argCount = instruction[3].u.operand;
248         int registerOffset = -instruction[4].u.operand;
249         
250         if (opcodeID == op_call && shouldEmitProfiling()) {
251             emitLoad(registerOffset + CallFrame::argumentOffsetIncludingThis(0), regT0, regT1);
252             Jump done = branch32(NotEqual, regT0, TrustedImm32(JSValue::CellTag));
253             loadPtr(Address(regT1, JSCell::structureIDOffset()), regT1);
254             storePtr(regT1, instruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile->addressOfLastSeenStructureID());
255             done.link(this);
256         }
257     
258         addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
259
260         store32(TrustedImm32(argCount), Address(stackPointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
261     } // SP holds newCallFrame + sizeof(CallerFrameAndPC), with ArgumentCount initialized.
262     
263     uint32_t locationBits = CallSiteIndex(instruction).bits();
264     store32(TrustedImm32(locationBits), tagFor(CallFrameSlot::argumentCount, callFrameRegister));
265     emitLoad(callee, regT1, regT0); // regT1, regT0 holds callee.
266
267     store32(regT0, Address(stackPointerRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
268     store32(regT1, Address(stackPointerRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)) + TagOffset - sizeof(CallerFrameAndPC)));
269
270     if (opcodeID == op_call_eval) {
271         compileCallEval(instruction);
272         return;
273     }
274
275     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs)
276         emitRestoreCalleeSaves();
277
278     addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
279
280     DataLabelPtr addressOfLinkedFunctionCheck;
281     Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(nullptr));
282
283     addSlowCase(slowCase);
284
285     ASSERT(m_callCompilationInfo.size() == callLinkInfoIndex);
286     info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), CodeOrigin(m_bytecodeOffset), regT0);
287     m_callCompilationInfo.append(CallCompilationInfo());
288     m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
289     m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
290
291     checkStackPointerAlignment();
292     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs || opcodeID == op_tail_call_forward_arguments) {
293         prepareForTailCallSlow();
294         m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedTailCall();
295         return;
296     }
297
298     m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
299
300     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
301     checkStackPointerAlignment();
302
303     sampleCodeBlock(m_codeBlock);
304     emitPutCallResult(instruction);
305 }
306
307 void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex)
308 {
309     if (opcodeID == op_call_eval) {
310         compileCallEvalSlowCase(instruction, iter);
311         return;
312     }
313
314     linkAllSlowCases(iter);
315
316     move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
317
318     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs)
319         emitRestoreCalleeSaves();
320
321     m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).retaggedCode<NoPtrTag>());
322
323     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
324         abortWithReason(JITDidReturnFromTailCall);
325         return;
326     }
327
328     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
329     checkStackPointerAlignment();
330
331     sampleCodeBlock(m_codeBlock);
332     emitPutCallResult(instruction);
333 }
334
335 } // namespace JSC
336
337 #endif // USE(JSVALUE32_64)
338 #endif // ENABLE(JIT)