42d112160ef113a70e76acb82378e915fbd36e35
[WebKit-https.git] / Source / JavaScriptCore / jit / JITCall32_64.cpp
1 /*
2  * Copyright (C) 2008, 2013-2015 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 <wtf/StringPrintStream.h>
43
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, 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, 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     CallLinkInfo* info = m_codeBlock->addCallLinkInfo();
206     info->setUpCall(CallLinkInfo::Call, CodeOrigin(m_bytecodeOffset), regT0);
207
208     linkSlowCase(iter);
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     move(TrustedImmPtr(info), regT2);
216
217     emitLoad(callee, regT1, regT0);
218     MacroAssemblerCodeRef virtualThunk = virtualThunkFor(m_vm, *info);
219     info->setSlowStub(createJITStubRoutine(virtualThunk, *m_vm, nullptr, true));
220     emitNakedCall(virtualThunk.code());
221     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
222     checkStackPointerAlignment();
223
224     sampleCodeBlock(m_codeBlock);
225     
226     emitPutCallResult(instruction);
227 }
228
229 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
230 {
231     int callee = instruction[2].u.operand;
232
233     /* Caller always:
234         - Updates callFrameRegister to callee callFrame.
235         - Initializes ArgumentCount; CallerFrame; Callee.
236
237        For a JS call:
238         - Callee initializes ReturnPC; CodeBlock.
239         - Callee restores callFrameRegister before return.
240
241        For a non-JS call:
242         - Caller initializes ReturnPC; CodeBlock.
243         - Caller restores callFrameRegister after return.
244     */
245     CallLinkInfo* info = nullptr;
246     if (opcodeID != op_call_eval)
247         info = m_codeBlock->addCallLinkInfo();
248     if (opcodeID == op_call_varargs || opcodeID == op_construct_varargs || opcodeID == op_tail_call_varargs || opcodeID == op_tail_call_forward_arguments)
249         compileSetupVarargsFrame(opcodeID, instruction, info);
250     else {
251         int argCount = instruction[3].u.operand;
252         int registerOffset = -instruction[4].u.operand;
253         
254         if (opcodeID == op_call && shouldEmitProfiling()) {
255             emitLoad(registerOffset + CallFrame::argumentOffsetIncludingThis(0), regT0, regT1);
256             Jump done = branch32(NotEqual, regT0, TrustedImm32(JSValue::CellTag));
257             loadPtr(Address(regT1, JSCell::structureIDOffset()), regT1);
258             storePtr(regT1, instruction[OPCODE_LENGTH(op_call) - 2].u.arrayProfile->addressOfLastSeenStructureID());
259             done.link(this);
260         }
261     
262         addPtr(TrustedImm32(registerOffset * sizeof(Register) + sizeof(CallerFrameAndPC)), callFrameRegister, stackPointerRegister);
263
264         store32(TrustedImm32(argCount), Address(stackPointerRegister, CallFrameSlot::argumentCount * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
265     } // SP holds newCallFrame + sizeof(CallerFrameAndPC), with ArgumentCount initialized.
266     
267     uint32_t locationBits = CallSiteIndex(instruction).bits();
268     store32(TrustedImm32(locationBits), tagFor(CallFrameSlot::argumentCount, callFrameRegister));
269     emitLoad(callee, regT1, regT0); // regT1, regT0 holds callee.
270
271     store32(regT0, Address(stackPointerRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)) + PayloadOffset - sizeof(CallerFrameAndPC)));
272     store32(regT1, Address(stackPointerRegister, CallFrameSlot::callee * static_cast<int>(sizeof(Register)) + TagOffset - sizeof(CallerFrameAndPC)));
273
274     if (opcodeID == op_call_eval) {
275         compileCallEval(instruction);
276         return;
277     }
278
279     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs)
280         emitRestoreCalleeSaves();
281
282     addSlowCase(branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag)));
283
284     DataLabelPtr addressOfLinkedFunctionCheck;
285     Jump slowCase = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, TrustedImmPtr(0));
286
287     addSlowCase(slowCase);
288
289     ASSERT(m_callCompilationInfo.size() == callLinkInfoIndex);
290     info->setUpCall(CallLinkInfo::callTypeFor(opcodeID), CodeOrigin(m_bytecodeOffset), regT0);
291     m_callCompilationInfo.append(CallCompilationInfo());
292     m_callCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
293     m_callCompilationInfo[callLinkInfoIndex].callLinkInfo = info;
294
295     checkStackPointerAlignment();
296     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs || opcodeID == op_tail_call_forward_arguments) {
297         prepareForTailCallSlow();
298         m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedTailCall();
299         return;
300     }
301
302     m_callCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
303
304     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
305     checkStackPointerAlignment();
306
307     sampleCodeBlock(m_codeBlock);
308     emitPutCallResult(instruction);
309 }
310
311 void JIT::compileOpCallSlowCase(OpcodeID opcodeID, Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex)
312 {
313     if (opcodeID == op_call_eval) {
314         compileCallEvalSlowCase(instruction, iter);
315         return;
316     }
317
318     linkSlowCase(iter);
319     linkSlowCase(iter);
320
321     move(TrustedImmPtr(m_callCompilationInfo[callLinkInfoIndex].callLinkInfo), regT2);
322
323     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs)
324         emitRestoreCalleeSaves();
325
326     m_callCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_vm->getCTIStub(linkCallThunkGenerator).code());
327
328     if (opcodeID == op_tail_call || opcodeID == op_tail_call_varargs) {
329         abortWithReason(JITDidReturnFromTailCall);
330         return;
331     }
332
333     addPtr(TrustedImm32(stackPointerOffsetFor(m_codeBlock) * sizeof(Register)), callFrameRegister, stackPointerRegister);
334     checkStackPointerAlignment();
335
336     sampleCodeBlock(m_codeBlock);
337     emitPutCallResult(instruction);
338 }
339
340 } // namespace JSC
341
342 #endif // USE(JSVALUE32_64)
343 #endif // ENABLE(JIT)