• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "JIT.h"
28 
29 #if ENABLE(JIT)
30 
31 #include "CodeBlock.h"
32 #include "JITInlineMethods.h"
33 #include "JITStubCall.h"
34 #include "JSArray.h"
35 #include "JSFunction.h"
36 #include "Interpreter.h"
37 #include "ResultType.h"
38 #include "SamplingTool.h"
39 
40 #ifndef NDEBUG
41 #include <stdio.h>
42 #endif
43 
44 using namespace std;
45 
46 namespace JSC {
47 
48 #if USE(JSVALUE32_64)
49 
compileOpCallInitializeCallFrame()50 void JIT::compileOpCallInitializeCallFrame()
51 {
52     // regT0 holds callee, regT1 holds argCount
53     store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
54 
55     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // scopeChain
56 
57     emitStore(static_cast<unsigned>(RegisterFile::OptionalCalleeArguments), JSValue());
58     storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register)))); // callee
59     storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)))); // scopeChain
60 }
61 
compileOpCallSetupArgs(Instruction * instruction)62 void JIT::compileOpCallSetupArgs(Instruction* instruction)
63 {
64     int argCount = instruction[3].u.operand;
65     int registerOffset = instruction[4].u.operand;
66 
67     emitPutJITStubArg(regT0, 1);
68     emitPutJITStubArg(regT1, 2);
69     emitPutJITStubArgConstant(registerOffset, 3);
70     emitPutJITStubArgConstant(argCount, 5);
71 }
72 
compileOpConstructSetupArgs(Instruction * instruction)73 void JIT::compileOpConstructSetupArgs(Instruction* instruction)
74 {
75     int argCount = instruction[3].u.operand;
76     int registerOffset = instruction[4].u.operand;
77     int proto = instruction[5].u.operand;
78     int thisRegister = instruction[6].u.operand;
79 
80     emitPutJITStubArg(regT0, 1);
81     emitPutJITStubArg(regT1, 2);
82     emitPutJITStubArgConstant(registerOffset, 3);
83     emitPutJITStubArgConstant(argCount, 5);
84     emitPutJITStubArgFromVirtualRegister(proto, 7, regT2, regT3);
85     emitPutJITStubArgConstant(thisRegister, 9);
86 }
87 
compileOpCallVarargsSetupArgs(Instruction *)88 void JIT::compileOpCallVarargsSetupArgs(Instruction*)
89 {
90     emitPutJITStubArg(regT0, 1);
91     emitPutJITStubArg(regT1, 2);
92     emitPutJITStubArg(regT3, 3); // registerOffset
93     emitPutJITStubArg(regT2, 5); // argCount
94 }
95 
compileOpCallVarargs(Instruction * instruction)96 void JIT::compileOpCallVarargs(Instruction* instruction)
97 {
98     int dst = instruction[1].u.operand;
99     int callee = instruction[2].u.operand;
100     int argCountRegister = instruction[3].u.operand;
101     int registerOffset = instruction[4].u.operand;
102 
103     emitLoad(callee, regT1, regT0);
104     emitLoadPayload(argCountRegister, regT2); // argCount
105     addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset
106 
107     compileOpCallVarargsSetupArgs(instruction);
108 
109     emitJumpSlowCaseIfNotJSCell(callee, regT1);
110     addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
111 
112     // Speculatively roll the callframe, assuming argCount will match the arity.
113     mul32(Imm32(sizeof(Register)), regT3, regT3);
114     addPtr(callFrameRegister, regT3);
115     storePtr(callFrameRegister, Address(regT3, RegisterFile::CallerFrame * static_cast<int>(sizeof(Register))));
116     move(regT3, callFrameRegister);
117 
118     move(regT2, regT1); // argCount
119 
120     emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
121 
122     emitStore(dst, regT1, regT0);
123 
124     sampleCodeBlock(m_codeBlock);
125 }
126 
compileOpCallVarargsSlowCase(Instruction * instruction,Vector<SlowCaseEntry>::iterator & iter)127 void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
128 {
129     int dst = instruction[1].u.operand;
130     int callee = instruction[2].u.operand;
131 
132     linkSlowCaseIfNotJSCell(iter, callee);
133     linkSlowCase(iter);
134 
135     JITStubCall stubCall(this, cti_op_call_NotJSFunction);
136     stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
137 
138     map(m_bytecodeIndex + OPCODE_LENGTH(op_call_varargs), dst, regT1, regT0);
139     sampleCodeBlock(m_codeBlock);
140 }
141 
emit_op_ret(Instruction * currentInstruction)142 void JIT::emit_op_ret(Instruction* currentInstruction)
143 {
144     unsigned dst = currentInstruction[1].u.operand;
145 
146     // We could JIT generate the deref, only calling out to C when the refcount hits zero.
147     if (m_codeBlock->needsFullScopeChain())
148         JITStubCall(this, cti_op_ret_scopeChain).call();
149 
150     emitLoad(dst, regT1, regT0);
151     emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
152     emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
153 
154     restoreReturnAddressBeforeReturn(regT2);
155     ret();
156 }
157 
emit_op_construct_verify(Instruction * currentInstruction)158 void JIT::emit_op_construct_verify(Instruction* currentInstruction)
159 {
160     unsigned dst = currentInstruction[1].u.operand;
161 
162     emitLoad(dst, regT1, regT0);
163     addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
164     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2);
165     addSlowCase(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType)));
166 }
167 
emitSlow_op_construct_verify(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)168 void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
169 {
170     unsigned dst = currentInstruction[1].u.operand;
171     unsigned src = currentInstruction[2].u.operand;
172 
173     linkSlowCase(iter);
174     linkSlowCase(iter);
175     emitLoad(src, regT1, regT0);
176     emitStore(dst, regT1, regT0);
177 }
178 
emitSlow_op_call(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)179 void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
180 {
181     compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call);
182 }
183 
emitSlow_op_call_eval(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)184 void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
185 {
186     compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval);
187 }
188 
emitSlow_op_call_varargs(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)189 void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
190 {
191     compileOpCallVarargsSlowCase(currentInstruction, iter);
192 }
193 
emitSlow_op_construct(Instruction * currentInstruction,Vector<SlowCaseEntry>::iterator & iter)194 void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
195 {
196     compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct);
197 }
198 
emit_op_call(Instruction * currentInstruction)199 void JIT::emit_op_call(Instruction* currentInstruction)
200 {
201     compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
202 }
203 
emit_op_call_eval(Instruction * currentInstruction)204 void JIT::emit_op_call_eval(Instruction* currentInstruction)
205 {
206     compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
207 }
208 
emit_op_load_varargs(Instruction * currentInstruction)209 void JIT::emit_op_load_varargs(Instruction* currentInstruction)
210 {
211     int argCountDst = currentInstruction[1].u.operand;
212     int argsOffset = currentInstruction[2].u.operand;
213 
214     JITStubCall stubCall(this, cti_op_load_varargs);
215     stubCall.addArgument(Imm32(argsOffset));
216     stubCall.call();
217     // Stores a naked int32 in the register file.
218     store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register)));
219 }
220 
emit_op_call_varargs(Instruction * currentInstruction)221 void JIT::emit_op_call_varargs(Instruction* currentInstruction)
222 {
223     compileOpCallVarargs(currentInstruction);
224 }
225 
emit_op_construct(Instruction * currentInstruction)226 void JIT::emit_op_construct(Instruction* currentInstruction)
227 {
228     compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++);
229 }
230 
231 #if !ENABLE(JIT_OPTIMIZE_CALL)
232 
233 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
234 
compileOpCall(OpcodeID opcodeID,Instruction * instruction,unsigned)235 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
236 {
237     int dst = instruction[1].u.operand;
238     int callee = instruction[2].u.operand;
239     int argCount = instruction[3].u.operand;
240     int registerOffset = instruction[4].u.operand;
241 
242     Jump wasEval1;
243     Jump wasEval2;
244     if (opcodeID == op_call_eval) {
245         JITStubCall stubCall(this, cti_op_call_eval);
246         stubCall.addArgument(callee);
247         stubCall.addArgument(JIT::Imm32(registerOffset));
248         stubCall.addArgument(JIT::Imm32(argCount));
249         stubCall.call();
250         wasEval1 = branchTest32(NonZero, regT0);
251         wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
252     }
253 
254     emitLoad(callee, regT1, regT2);
255 
256     if (opcodeID == op_call)
257         compileOpCallSetupArgs(instruction);
258     else if (opcodeID == op_construct)
259         compileOpConstructSetupArgs(instruction);
260 
261     emitJumpSlowCaseIfNotJSCell(callee, regT1);
262     addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr)));
263 
264     // First, in the case of a construct, allocate the new object.
265     if (opcodeID == op_construct) {
266         JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
267         emitLoad(callee, regT1, regT2);
268     }
269 
270     // Speculatively roll the callframe, assuming argCount will match the arity.
271     storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
272     addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
273     move(Imm32(argCount), regT1);
274 
275     emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
276 
277     if (opcodeID == op_call_eval) {
278         wasEval1.link(this);
279         wasEval2.link(this);
280     }
281 
282     emitStore(dst, regT1, regT0);;
283 
284     sampleCodeBlock(m_codeBlock);
285 }
286 
compileOpCallSlowCase(Instruction * instruction,Vector<SlowCaseEntry>::iterator & iter,unsigned,OpcodeID opcodeID)287 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
288 {
289     int dst = instruction[1].u.operand;
290     int callee = instruction[2].u.operand;
291 
292     linkSlowCaseIfNotJSCell(iter, callee);
293     linkSlowCase(iter);
294 
295     JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
296     stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
297 
298     sampleCodeBlock(m_codeBlock);
299 }
300 
301 #else // !ENABLE(JIT_OPTIMIZE_CALL)
302 
303 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
304 
compileOpCall(OpcodeID opcodeID,Instruction * instruction,unsigned callLinkInfoIndex)305 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
306 {
307     int dst = instruction[1].u.operand;
308     int callee = instruction[2].u.operand;
309     int argCount = instruction[3].u.operand;
310     int registerOffset = instruction[4].u.operand;
311 
312     Jump wasEval1;
313     Jump wasEval2;
314     if (opcodeID == op_call_eval) {
315         JITStubCall stubCall(this, cti_op_call_eval);
316         stubCall.addArgument(callee);
317         stubCall.addArgument(JIT::Imm32(registerOffset));
318         stubCall.addArgument(JIT::Imm32(argCount));
319         stubCall.call();
320         wasEval1 = branchTest32(NonZero, regT0);
321         wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
322     }
323 
324     emitLoad(callee, regT1, regT0);
325 
326     DataLabelPtr addressOfLinkedFunctionCheck;
327     Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(0));
328     addSlowCase(jumpToSlow);
329     ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
330     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
331 
332     addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
333 
334     // The following is the fast case, only used whan a callee can be linked.
335 
336     // In the case of OpConstruct, call out to a cti_ function to create the new object.
337     if (opcodeID == op_construct) {
338         int proto = instruction[5].u.operand;
339         int thisRegister = instruction[6].u.operand;
340 
341         JITStubCall stubCall(this, cti_op_construct_JSConstruct);
342         stubCall.addArgument(regT1, regT0);
343         stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
344         stubCall.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
345         stubCall.addArgument(proto);
346         stubCall.call(thisRegister);
347 
348         emitLoad(callee, regT1, regT0);
349     }
350 
351     // Fast version of stack frame initialization, directly relative to edi.
352     // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
353     emitStore(registerOffset + RegisterFile::OptionalCalleeArguments, JSValue());
354     emitStore(registerOffset + RegisterFile::Callee, regT1, regT0);
355 
356     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
357     store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
358     storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
359     storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
360     addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
361 
362     // Call to the callee
363     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
364 
365     if (opcodeID == op_call_eval) {
366         wasEval1.link(this);
367         wasEval2.link(this);
368     }
369 
370     // Put the return value in dst. In the interpreter, op_ret does this.
371     emitStore(dst, regT1, regT0);
372     map(m_bytecodeIndex + opcodeLengths[opcodeID], dst, regT1, regT0);
373 
374     sampleCodeBlock(m_codeBlock);
375 }
376 
compileOpCallSlowCase(Instruction * instruction,Vector<SlowCaseEntry>::iterator & iter,unsigned callLinkInfoIndex,OpcodeID opcodeID)377 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
378 {
379     int dst = instruction[1].u.operand;
380     int callee = instruction[2].u.operand;
381     int argCount = instruction[3].u.operand;
382     int registerOffset = instruction[4].u.operand;
383 
384     linkSlowCase(iter);
385     linkSlowCase(iter);
386 
387     // The arguments have been set up on the hot path for op_call_eval
388     if (opcodeID == op_call)
389         compileOpCallSetupArgs(instruction);
390     else if (opcodeID == op_construct)
391         compileOpConstructSetupArgs(instruction);
392 
393     // Fast check for JS function.
394     Jump callLinkFailNotObject = branch32(NotEqual, regT1, Imm32(JSValue::CellTag));
395     Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
396 
397     // First, in the case of a construct, allocate the new object.
398     if (opcodeID == op_construct) {
399         JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
400         emitLoad(callee, regT1, regT0);
401     }
402 
403     // Speculatively roll the callframe, assuming argCount will match the arity.
404     storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
405     addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
406     move(Imm32(argCount), regT1);
407 
408     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
409 
410     // Put the return value in dst.
411     emitStore(dst, regT1, regT0);;
412     sampleCodeBlock(m_codeBlock);
413 
414     // If not, we need an extra case in the if below!
415     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
416 
417     // Done! - return back to the hot path.
418     if (opcodeID == op_construct)
419         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
420     else
421         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
422 
423     // This handles host functions
424     callLinkFailNotObject.link(this);
425     callLinkFailNotJSFunction.link(this);
426     JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
427 
428     emitStore(dst, regT1, regT0);;
429     sampleCodeBlock(m_codeBlock);
430 }
431 
432 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
433 
434 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
435 
436 #else // USE(JSVALUE32_64)
437 
438 void JIT::compileOpCallInitializeCallFrame()
439 {
440     store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
441 
442     loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
443 
444     storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register))));
445     storePtr(regT2, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register))));
446     storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register))));
447 }
448 
449 void JIT::compileOpCallSetupArgs(Instruction* instruction)
450 {
451     int argCount = instruction[3].u.operand;
452     int registerOffset = instruction[4].u.operand;
453 
454     // ecx holds func
455     emitPutJITStubArg(regT2, 1);
456     emitPutJITStubArgConstant(argCount, 3);
457     emitPutJITStubArgConstant(registerOffset, 2);
458 }
459 
460 void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
461 {
462     int registerOffset = instruction[4].u.operand;
463 
464     // ecx holds func
465     emitPutJITStubArg(regT2, 1);
466     emitPutJITStubArg(regT1, 3);
467     addPtr(Imm32(registerOffset), regT1, regT0);
468     emitPutJITStubArg(regT0, 2);
469 }
470 
471 void JIT::compileOpConstructSetupArgs(Instruction* instruction)
472 {
473     int argCount = instruction[3].u.operand;
474     int registerOffset = instruction[4].u.operand;
475     int proto = instruction[5].u.operand;
476     int thisRegister = instruction[6].u.operand;
477 
478     // ecx holds func
479     emitPutJITStubArg(regT2, 1);
480     emitPutJITStubArgConstant(registerOffset, 2);
481     emitPutJITStubArgConstant(argCount, 3);
482     emitPutJITStubArgFromVirtualRegister(proto, 4, regT0);
483     emitPutJITStubArgConstant(thisRegister, 5);
484 }
485 
486 void JIT::compileOpCallVarargs(Instruction* instruction)
487 {
488     int dst = instruction[1].u.operand;
489     int callee = instruction[2].u.operand;
490     int argCountRegister = instruction[3].u.operand;
491 
492     emitGetVirtualRegister(argCountRegister, regT1);
493     emitGetVirtualRegister(callee, regT2);
494     compileOpCallVarargsSetupArgs(instruction);
495 
496     // Check for JSFunctions.
497     emitJumpSlowCaseIfNotJSCell(regT2);
498     addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr)));
499 
500     // Speculatively roll the callframe, assuming argCount will match the arity.
501     mul32(Imm32(sizeof(Register)), regT0, regT0);
502     intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame;
503     addPtr(Imm32((int32_t)offset), regT0, regT3);
504     addPtr(callFrameRegister, regT3);
505     storePtr(callFrameRegister, regT3);
506     addPtr(regT0, callFrameRegister);
507     emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
508 
509     // Put the return value in dst. In the interpreter, op_ret does this.
510     emitPutVirtualRegister(dst);
511 
512     sampleCodeBlock(m_codeBlock);
513 }
514 
515 void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
516 {
517     int dst = instruction[1].u.operand;
518 
519     linkSlowCase(iter);
520     linkSlowCase(iter);
521     JITStubCall stubCall(this, cti_op_call_NotJSFunction);
522     stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
523 
524     sampleCodeBlock(m_codeBlock);
525 }
526 
527 #if !ENABLE(JIT_OPTIMIZE_CALL)
528 
529 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
530 
531 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
532 {
533     int dst = instruction[1].u.operand;
534     int callee = instruction[2].u.operand;
535     int argCount = instruction[3].u.operand;
536     int registerOffset = instruction[4].u.operand;
537 
538     // Handle eval
539     Jump wasEval;
540     if (opcodeID == op_call_eval) {
541         JITStubCall stubCall(this, cti_op_call_eval);
542         stubCall.addArgument(callee, regT2);
543         stubCall.addArgument(JIT::Imm32(registerOffset));
544         stubCall.addArgument(JIT::Imm32(argCount));
545         stubCall.call();
546         wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
547     }
548 
549     emitGetVirtualRegister(callee, regT2);
550     // The arguments have been set up on the hot path for op_call_eval
551     if (opcodeID == op_call)
552         compileOpCallSetupArgs(instruction);
553     else if (opcodeID == op_construct)
554         compileOpConstructSetupArgs(instruction);
555 
556     // Check for JSFunctions.
557     emitJumpSlowCaseIfNotJSCell(regT2);
558     addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr)));
559 
560     // First, in the case of a construct, allocate the new object.
561     if (opcodeID == op_construct) {
562         JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
563         emitGetVirtualRegister(callee, regT2);
564     }
565 
566     // Speculatively roll the callframe, assuming argCount will match the arity.
567     storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
568     addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
569     move(Imm32(argCount), regT1);
570 
571     emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
572 
573     if (opcodeID == op_call_eval)
574         wasEval.link(this);
575 
576     // Put the return value in dst. In the interpreter, op_ret does this.
577     emitPutVirtualRegister(dst);
578 
579     sampleCodeBlock(m_codeBlock);
580 }
581 
582 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
583 {
584     int dst = instruction[1].u.operand;
585 
586     linkSlowCase(iter);
587     linkSlowCase(iter);
588     JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
589     stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
590 
591     sampleCodeBlock(m_codeBlock);
592 }
593 
594 #else // !ENABLE(JIT_OPTIMIZE_CALL)
595 
596 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
597 
598 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
599 {
600     int dst = instruction[1].u.operand;
601     int callee = instruction[2].u.operand;
602     int argCount = instruction[3].u.operand;
603     int registerOffset = instruction[4].u.operand;
604 
605     // Handle eval
606     Jump wasEval;
607     if (opcodeID == op_call_eval) {
608         JITStubCall stubCall(this, cti_op_call_eval);
609         stubCall.addArgument(callee, regT2);
610         stubCall.addArgument(JIT::Imm32(registerOffset));
611         stubCall.addArgument(JIT::Imm32(argCount));
612         stubCall.call();
613         wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
614     }
615 
616     // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
617     // This deliberately leaves the callee in ecx, used when setting up the stack frame below
618     emitGetVirtualRegister(callee, regT2);
619     DataLabelPtr addressOfLinkedFunctionCheck;
620     Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT2, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue())));
621     addSlowCase(jumpToSlow);
622     ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
623     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
624 
625     // The following is the fast case, only used whan a callee can be linked.
626 
627     // In the case of OpConstruct, call out to a cti_ function to create the new object.
628     if (opcodeID == op_construct) {
629         int proto = instruction[5].u.operand;
630         int thisRegister = instruction[6].u.operand;
631 
632         emitPutJITStubArg(regT2, 1);
633         emitPutJITStubArgFromVirtualRegister(proto, 4, regT0);
634         JITStubCall stubCall(this, cti_op_construct_JSConstruct);
635         stubCall.call(thisRegister);
636         emitGetVirtualRegister(callee, regT2);
637     }
638 
639     // Fast version of stack frame initialization, directly relative to edi.
640     // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
641     storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register))));
642     storePtr(regT2, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
643     loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
644     store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
645     storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
646     storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
647     addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
648 
649     // Call to the callee
650     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
651 
652     if (opcodeID == op_call_eval)
653         wasEval.link(this);
654 
655     // Put the return value in dst. In the interpreter, op_ret does this.
656     emitPutVirtualRegister(dst);
657 
658     sampleCodeBlock(m_codeBlock);
659 }
660 
661 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
662 {
663     int dst = instruction[1].u.operand;
664     int callee = instruction[2].u.operand;
665     int argCount = instruction[3].u.operand;
666     int registerOffset = instruction[4].u.operand;
667 
668     linkSlowCase(iter);
669 
670     // The arguments have been set up on the hot path for op_call_eval
671     if (opcodeID == op_call)
672         compileOpCallSetupArgs(instruction);
673     else if (opcodeID == op_construct)
674         compileOpConstructSetupArgs(instruction);
675 
676     // Fast check for JS function.
677     Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT2);
678     Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr));
679 
680     // First, in the case of a construct, allocate the new object.
681     if (opcodeID == op_construct) {
682         JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
683         emitGetVirtualRegister(callee, regT2);
684     }
685 
686     // Speculatively roll the callframe, assuming argCount will match the arity.
687     storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
688     addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
689     move(Imm32(argCount), regT1);
690 
691     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
692 
693     // Put the return value in dst.
694     emitPutVirtualRegister(dst);
695     sampleCodeBlock(m_codeBlock);
696 
697     // If not, we need an extra case in the if below!
698     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
699 
700     // Done! - return back to the hot path.
701     if (opcodeID == op_construct)
702         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
703     else
704         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
705 
706     // This handles host functions
707     callLinkFailNotObject.link(this);
708     callLinkFailNotJSFunction.link(this);
709     JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
710 
711     emitPutVirtualRegister(dst);
712     sampleCodeBlock(m_codeBlock);
713 }
714 
715 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
716 
717 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
718 
719 #endif // USE(JSVALUE32_64)
720 
721 } // namespace JSC
722 
723 #endif // ENABLE(JIT)
724