2 * Copyright (C) 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
31 #include "CodeBlock.h"
32 #include "JITInlineMethods.h"
33 #include "JITStubCall.h"
35 #include "JSFunction.h"
36 #include "Interpreter.h"
37 #include "ResultType.h"
38 #include "SamplingTool.h"
50 void JIT::compileOpCallInitializeCallFrame()
52 // regT0 holds callee, regT1 holds argCount
53 store32(regT1
, Address(callFrameRegister
, RegisterFile::ArgumentCount
* static_cast<int>(sizeof(Register
))));
55 loadPtr(Address(regT0
, OBJECT_OFFSETOF(JSFunction
, m_data
) + OBJECT_OFFSETOF(ScopeChain
, m_node
)), regT1
); // scopeChain
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
62 void JIT::compileOpCallSetupArgs(Instruction
* instruction
)
64 int argCount
= instruction
[3].u
.operand
;
65 int registerOffset
= instruction
[4].u
.operand
;
67 emitPutJITStubArg(regT1
, regT0
, 0);
68 emitPutJITStubArgConstant(registerOffset
, 1);
69 emitPutJITStubArgConstant(argCount
, 2);
72 void JIT::compileOpConstructSetupArgs(Instruction
* instruction
)
74 int argCount
= instruction
[3].u
.operand
;
75 int registerOffset
= instruction
[4].u
.operand
;
76 int proto
= instruction
[5].u
.operand
;
77 int thisRegister
= instruction
[6].u
.operand
;
79 emitPutJITStubArg(regT1
, regT0
, 0);
80 emitPutJITStubArgConstant(registerOffset
, 1);
81 emitPutJITStubArgConstant(argCount
, 2);
82 emitPutJITStubArgFromVirtualRegister(proto
, 3, regT2
, regT3
);
83 emitPutJITStubArgConstant(thisRegister
, 4);
86 void JIT::compileOpCallVarargsSetupArgs(Instruction
*)
88 emitPutJITStubArg(regT1
, regT0
, 0);
89 emitPutJITStubArg(regT3
, 1); // registerOffset
90 emitPutJITStubArg(regT2
, 2); // argCount
93 void JIT::compileOpCallVarargs(Instruction
* instruction
)
95 int dst
= instruction
[1].u
.operand
;
96 int callee
= instruction
[2].u
.operand
;
97 int argCountRegister
= instruction
[3].u
.operand
;
98 int registerOffset
= instruction
[4].u
.operand
;
100 emitLoad(callee
, regT1
, regT0
);
101 emitLoadPayload(argCountRegister
, regT2
); // argCount
102 addPtr(Imm32(registerOffset
), regT2
, regT3
); // registerOffset
104 compileOpCallVarargsSetupArgs(instruction
);
106 emitJumpSlowCaseIfNotJSCell(callee
, regT1
);
107 addSlowCase(branchPtr(NotEqual
, Address(regT0
), ImmPtr(m_globalData
->jsFunctionVPtr
)));
109 // Speculatively roll the callframe, assuming argCount will match the arity.
110 mul32(Imm32(sizeof(Register
)), regT3
, regT3
);
111 addPtr(callFrameRegister
, regT3
);
112 storePtr(callFrameRegister
, Address(regT3
, RegisterFile::CallerFrame
* static_cast<int>(sizeof(Register
))));
113 move(regT3
, callFrameRegister
);
115 move(regT2
, regT1
); // argCount
117 emitNakedCall(m_globalData
->jitStubs
->ctiVirtualCall());
119 emitStore(dst
, regT1
, regT0
);
121 sampleCodeBlock(m_codeBlock
);
124 void JIT::compileOpCallVarargsSlowCase(Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
126 int dst
= instruction
[1].u
.operand
;
127 int callee
= instruction
[2].u
.operand
;
129 linkSlowCaseIfNotJSCell(iter
, callee
);
132 JITStubCall
stubCall(this, cti_op_call_NotJSFunction
);
133 stubCall
.call(dst
); // In the interpreter, the callee puts the return value in dst.
135 map(m_bytecodeIndex
+ OPCODE_LENGTH(op_call_varargs
), dst
, regT1
, regT0
);
136 sampleCodeBlock(m_codeBlock
);
139 void JIT::emit_op_ret(Instruction
* currentInstruction
)
141 unsigned dst
= currentInstruction
[1].u
.operand
;
143 // We could JIT generate the deref, only calling out to C when the refcount hits zero.
144 if (m_codeBlock
->needsFullScopeChain())
145 JITStubCall(this, cti_op_ret_scopeChain
).call();
147 emitLoad(dst
, regT1
, regT0
);
148 emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC
, regT2
);
149 emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame
, callFrameRegister
);
151 restoreReturnAddressBeforeReturn(regT2
);
155 void JIT::emit_op_construct_verify(Instruction
* currentInstruction
)
157 unsigned dst
= currentInstruction
[1].u
.operand
;
159 emitLoad(dst
, regT1
, regT0
);
160 addSlowCase(branch32(NotEqual
, regT1
, Imm32(JSValue::CellTag
)));
161 loadPtr(Address(regT0
, OBJECT_OFFSETOF(JSCell
, m_structure
)), regT2
);
162 addSlowCase(branch8(NotEqual
, Address(regT2
, OBJECT_OFFSETOF(Structure
, m_typeInfo
) + OBJECT_OFFSETOF(TypeInfo
, m_type
)), Imm32(ObjectType
)));
165 void JIT::emitSlow_op_construct_verify(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
167 unsigned dst
= currentInstruction
[1].u
.operand
;
168 unsigned src
= currentInstruction
[2].u
.operand
;
172 emitLoad(src
, regT1
, regT0
);
173 emitStore(dst
, regT1
, regT0
);
176 void JIT::emitSlow_op_call(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
178 compileOpCallSlowCase(currentInstruction
, iter
, m_callLinkInfoIndex
++, op_call
);
181 void JIT::emitSlow_op_call_eval(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
183 compileOpCallSlowCase(currentInstruction
, iter
, m_callLinkInfoIndex
++, op_call_eval
);
186 void JIT::emitSlow_op_call_varargs(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
188 compileOpCallVarargsSlowCase(currentInstruction
, iter
);
191 void JIT::emitSlow_op_construct(Instruction
* currentInstruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
193 compileOpCallSlowCase(currentInstruction
, iter
, m_callLinkInfoIndex
++, op_construct
);
196 void JIT::emit_op_call(Instruction
* currentInstruction
)
198 compileOpCall(op_call
, currentInstruction
, m_callLinkInfoIndex
++);
201 void JIT::emit_op_call_eval(Instruction
* currentInstruction
)
203 compileOpCall(op_call_eval
, currentInstruction
, m_callLinkInfoIndex
++);
206 void JIT::emit_op_load_varargs(Instruction
* currentInstruction
)
208 int argCountDst
= currentInstruction
[1].u
.operand
;
209 int argsOffset
= currentInstruction
[2].u
.operand
;
211 JITStubCall
stubCall(this, cti_op_load_varargs
);
212 stubCall
.addArgument(Imm32(argsOffset
));
214 // Stores a naked int32 in the register file.
215 store32(returnValueRegister
, Address(callFrameRegister
, argCountDst
* sizeof(Register
)));
218 void JIT::emit_op_call_varargs(Instruction
* currentInstruction
)
220 compileOpCallVarargs(currentInstruction
);
223 void JIT::emit_op_construct(Instruction
* currentInstruction
)
225 compileOpCall(op_construct
, currentInstruction
, m_callLinkInfoIndex
++);
228 #if !ENABLE(JIT_OPTIMIZE_CALL)
230 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
232 void JIT::compileOpCall(OpcodeID opcodeID
, Instruction
* instruction
, unsigned)
234 int dst
= instruction
[1].u
.operand
;
235 int callee
= instruction
[2].u
.operand
;
236 int argCount
= instruction
[3].u
.operand
;
237 int registerOffset
= instruction
[4].u
.operand
;
240 if (opcodeID
== op_call_eval
) {
241 JITStubCall
stubCall(this, cti_op_call_eval
);
242 stubCall
.addArgument(callee
);
243 stubCall
.addArgument(JIT::Imm32(registerOffset
));
244 stubCall
.addArgument(JIT::Imm32(argCount
));
246 wasEval
= branch32(NotEqual
, regT1
, Imm32(JSValue::EmptyValueTag
));
249 emitLoad(callee
, regT1
, regT0
);
251 if (opcodeID
== op_call
)
252 compileOpCallSetupArgs(instruction
);
253 else if (opcodeID
== op_construct
)
254 compileOpConstructSetupArgs(instruction
);
256 emitJumpSlowCaseIfNotJSCell(callee
, regT1
);
257 addSlowCase(branchPtr(NotEqual
, Address(regT0
), ImmPtr(m_globalData
->jsFunctionVPtr
)));
259 // First, in the case of a construct, allocate the new object.
260 if (opcodeID
== op_construct
) {
261 JITStubCall(this, cti_op_construct_JSConstruct
).call(registerOffset
- RegisterFile::CallFrameHeaderSize
- argCount
);
262 emitLoad(callee
, regT1
, regT0
);
265 // Speculatively roll the callframe, assuming argCount will match the arity.
266 storePtr(callFrameRegister
, Address(callFrameRegister
, (RegisterFile::CallerFrame
+ registerOffset
) * static_cast<int>(sizeof(Register
))));
267 addPtr(Imm32(registerOffset
* static_cast<int>(sizeof(Register
))), callFrameRegister
);
268 move(Imm32(argCount
), regT1
);
270 emitNakedCall(m_globalData
->jitStubs
.ctiVirtualCall());
272 if (opcodeID
== op_call_eval
)
275 emitStore(dst
, regT1
, regT0
);
277 sampleCodeBlock(m_codeBlock
);
280 void JIT::compileOpCallSlowCase(Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned, OpcodeID opcodeID
)
282 int dst
= instruction
[1].u
.operand
;
283 int callee
= instruction
[2].u
.operand
;
285 linkSlowCaseIfNotJSCell(iter
, callee
);
288 JITStubCall
stubCall(this, opcodeID
== op_construct
? cti_op_construct_NotJSConstruct
: cti_op_call_NotJSFunction
);
289 stubCall
.call(dst
); // In the interpreter, the callee puts the return value in dst.
291 sampleCodeBlock(m_codeBlock
);
294 #else // !ENABLE(JIT_OPTIMIZE_CALL)
296 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
298 void JIT::compileOpCall(OpcodeID opcodeID
, Instruction
* instruction
, unsigned callLinkInfoIndex
)
300 int dst
= instruction
[1].u
.operand
;
301 int callee
= instruction
[2].u
.operand
;
302 int argCount
= instruction
[3].u
.operand
;
303 int registerOffset
= instruction
[4].u
.operand
;
306 if (opcodeID
== op_call_eval
) {
307 JITStubCall
stubCall(this, cti_op_call_eval
);
308 stubCall
.addArgument(callee
);
309 stubCall
.addArgument(JIT::Imm32(registerOffset
));
310 stubCall
.addArgument(JIT::Imm32(argCount
));
312 wasEval
= branch32(NotEqual
, regT1
, Imm32(JSValue::EmptyValueTag
));
315 emitLoad(callee
, regT1
, regT0
);
317 DataLabelPtr addressOfLinkedFunctionCheck
;
319 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
321 Jump jumpToSlow
= branchPtrWithPatch(NotEqual
, regT0
, addressOfLinkedFunctionCheck
, ImmPtr(0));
323 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
325 addSlowCase(jumpToSlow
);
326 ASSERT(differenceBetween(addressOfLinkedFunctionCheck
, jumpToSlow
) == patchOffsetOpCallCompareToJump
);
327 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathBegin
= addressOfLinkedFunctionCheck
;
329 addSlowCase(branch32(NotEqual
, regT1
, Imm32(JSValue::CellTag
)));
331 // The following is the fast case, only used whan a callee can be linked.
333 // In the case of OpConstruct, call out to a cti_ function to create the new object.
334 if (opcodeID
== op_construct
) {
335 int proto
= instruction
[5].u
.operand
;
336 int thisRegister
= instruction
[6].u
.operand
;
338 JITStubCall
stubCall(this, cti_op_construct_JSConstruct
);
339 stubCall
.addArgument(regT1
, regT0
);
340 stubCall
.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
341 stubCall
.addArgument(Imm32(0)); // FIXME: Remove this unused JITStub argument.
342 stubCall
.addArgument(proto
);
343 stubCall
.call(thisRegister
);
345 emitLoad(callee
, regT1
, regT0
);
348 // Fast version of stack frame initialization, directly relative to edi.
349 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
350 emitStore(registerOffset
+ RegisterFile::OptionalCalleeArguments
, JSValue());
351 emitStore(registerOffset
+ RegisterFile::Callee
, regT1
, regT0
);
353 loadPtr(Address(regT0
, OBJECT_OFFSETOF(JSFunction
, m_data
) + OBJECT_OFFSETOF(ScopeChain
, m_node
)), regT1
); // newScopeChain
354 store32(Imm32(argCount
), Address(callFrameRegister
, (registerOffset
+ RegisterFile::ArgumentCount
) * static_cast<int>(sizeof(Register
))));
355 storePtr(callFrameRegister
, Address(callFrameRegister
, (registerOffset
+ RegisterFile::CallerFrame
) * static_cast<int>(sizeof(Register
))));
356 storePtr(regT1
, Address(callFrameRegister
, (registerOffset
+ RegisterFile::ScopeChain
) * static_cast<int>(sizeof(Register
))));
357 addPtr(Imm32(registerOffset
* sizeof(Register
)), callFrameRegister
);
359 // Call to the callee
360 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathOther
= emitNakedCall();
362 if (opcodeID
== op_call_eval
)
365 // Put the return value in dst. In the interpreter, op_ret does this.
366 emitStore(dst
, regT1
, regT0
);
367 map(m_bytecodeIndex
+ opcodeLengths
[opcodeID
], dst
, regT1
, regT0
);
369 sampleCodeBlock(m_codeBlock
);
372 void JIT::compileOpCallSlowCase(Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned callLinkInfoIndex
, OpcodeID opcodeID
)
374 int dst
= instruction
[1].u
.operand
;
375 int callee
= instruction
[2].u
.operand
;
376 int argCount
= instruction
[3].u
.operand
;
377 int registerOffset
= instruction
[4].u
.operand
;
382 // The arguments have been set up on the hot path for op_call_eval
383 if (opcodeID
== op_call
)
384 compileOpCallSetupArgs(instruction
);
385 else if (opcodeID
== op_construct
)
386 compileOpConstructSetupArgs(instruction
);
388 // Fast check for JS function.
389 Jump callLinkFailNotObject
= branch32(NotEqual
, regT1
, Imm32(JSValue::CellTag
));
390 Jump callLinkFailNotJSFunction
= branchPtr(NotEqual
, Address(regT0
), ImmPtr(m_globalData
->jsFunctionVPtr
));
392 // First, in the case of a construct, allocate the new object.
393 if (opcodeID
== op_construct
) {
394 JITStubCall(this, cti_op_construct_JSConstruct
).call(registerOffset
- RegisterFile::CallFrameHeaderSize
- argCount
);
395 emitLoad(callee
, regT1
, regT0
);
398 // Speculatively roll the callframe, assuming argCount will match the arity.
399 storePtr(callFrameRegister
, Address(callFrameRegister
, (RegisterFile::CallerFrame
+ registerOffset
) * static_cast<int>(sizeof(Register
))));
400 addPtr(Imm32(registerOffset
* static_cast<int>(sizeof(Register
))), callFrameRegister
);
401 move(Imm32(argCount
), regT1
);
403 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].callReturnLocation
= emitNakedCall(m_globalData
->jitStubs
->ctiVirtualCallLink());
405 // Put the return value in dst.
406 emitStore(dst
, regT1
, regT0
);;
407 sampleCodeBlock(m_codeBlock
);
409 // If not, we need an extra case in the if below!
410 ASSERT(OPCODE_LENGTH(op_call
) == OPCODE_LENGTH(op_call_eval
));
412 // Done! - return back to the hot path.
413 if (opcodeID
== op_construct
)
414 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct
));
416 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call
));
418 // This handles host functions
419 callLinkFailNotObject
.link(this);
420 callLinkFailNotJSFunction
.link(this);
421 JITStubCall(this, opcodeID
== op_construct
? cti_op_construct_NotJSConstruct
: cti_op_call_NotJSFunction
).call();
423 emitStore(dst
, regT1
, regT0
);;
424 sampleCodeBlock(m_codeBlock
);
427 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
429 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
431 #else // USE(JSVALUE32_64)
433 void JIT::compileOpCallInitializeCallFrame()
435 store32(regT1
, Address(callFrameRegister
, RegisterFile::ArgumentCount
* static_cast<int>(sizeof(Register
))));
437 loadPtr(Address(regT0
, OBJECT_OFFSETOF(JSFunction
, m_data
) + OBJECT_OFFSETOF(ScopeChain
, m_node
)), regT1
); // newScopeChain
439 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister
, RegisterFile::OptionalCalleeArguments
* static_cast<int>(sizeof(Register
))));
440 storePtr(regT0
, Address(callFrameRegister
, RegisterFile::Callee
* static_cast<int>(sizeof(Register
))));
441 storePtr(regT1
, Address(callFrameRegister
, RegisterFile::ScopeChain
* static_cast<int>(sizeof(Register
))));
444 void JIT::compileOpCallSetupArgs(Instruction
* instruction
)
446 int argCount
= instruction
[3].u
.operand
;
447 int registerOffset
= instruction
[4].u
.operand
;
450 emitPutJITStubArg(regT0
, 0);
451 emitPutJITStubArgConstant(argCount
, 2);
452 emitPutJITStubArgConstant(registerOffset
, 1);
455 void JIT::compileOpCallVarargsSetupArgs(Instruction
* instruction
)
457 int registerOffset
= instruction
[4].u
.operand
;
460 emitPutJITStubArg(regT0
, 0);
461 emitPutJITStubArg(regT1
, 2);
462 addPtr(Imm32(registerOffset
), regT1
, regT2
);
463 emitPutJITStubArg(regT2
, 1);
466 void JIT::compileOpConstructSetupArgs(Instruction
* instruction
)
468 int argCount
= instruction
[3].u
.operand
;
469 int registerOffset
= instruction
[4].u
.operand
;
470 int proto
= instruction
[5].u
.operand
;
471 int thisRegister
= instruction
[6].u
.operand
;
474 emitPutJITStubArg(regT0
, 0);
475 emitPutJITStubArgConstant(registerOffset
, 1);
476 emitPutJITStubArgConstant(argCount
, 2);
477 emitPutJITStubArgFromVirtualRegister(proto
, 3, regT2
);
478 emitPutJITStubArgConstant(thisRegister
, 4);
481 void JIT::compileOpCallVarargs(Instruction
* instruction
)
483 int dst
= instruction
[1].u
.operand
;
484 int callee
= instruction
[2].u
.operand
;
485 int argCountRegister
= instruction
[3].u
.operand
;
487 emitGetVirtualRegister(argCountRegister
, regT1
);
488 emitGetVirtualRegister(callee
, regT0
);
489 compileOpCallVarargsSetupArgs(instruction
);
491 // Check for JSFunctions.
492 emitJumpSlowCaseIfNotJSCell(regT0
);
493 addSlowCase(branchPtr(NotEqual
, Address(regT0
), ImmPtr(m_globalData
->jsFunctionVPtr
)));
495 // Speculatively roll the callframe, assuming argCount will match the arity.
496 mul32(Imm32(sizeof(Register
)), regT2
, regT2
);
497 intptr_t offset
= (intptr_t)sizeof(Register
) * (intptr_t)RegisterFile::CallerFrame
;
498 addPtr(Imm32((int32_t)offset
), regT2
, regT3
);
499 addPtr(callFrameRegister
, regT3
);
500 storePtr(callFrameRegister
, regT3
);
501 addPtr(regT2
, callFrameRegister
);
502 emitNakedCall(m_globalData
->jitStubs
->ctiVirtualCall());
504 // Put the return value in dst. In the interpreter, op_ret does this.
505 emitPutVirtualRegister(dst
);
507 sampleCodeBlock(m_codeBlock
);
510 void JIT::compileOpCallVarargsSlowCase(Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
)
512 int dst
= instruction
[1].u
.operand
;
516 JITStubCall
stubCall(this, cti_op_call_NotJSFunction
);
517 stubCall
.call(dst
); // In the interpreter, the callee puts the return value in dst.
519 sampleCodeBlock(m_codeBlock
);
522 #if !ENABLE(JIT_OPTIMIZE_CALL)
524 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
526 void JIT::compileOpCall(OpcodeID opcodeID
, Instruction
* instruction
, unsigned)
528 int dst
= instruction
[1].u
.operand
;
529 int callee
= instruction
[2].u
.operand
;
530 int argCount
= instruction
[3].u
.operand
;
531 int registerOffset
= instruction
[4].u
.operand
;
535 if (opcodeID
== op_call_eval
) {
536 JITStubCall
stubCall(this, cti_op_call_eval
);
537 stubCall
.addArgument(callee
, regT0
);
538 stubCall
.addArgument(JIT::Imm32(registerOffset
));
539 stubCall
.addArgument(JIT::Imm32(argCount
));
541 wasEval
= branchPtr(NotEqual
, regT0
, ImmPtr(JSValue::encode(JSValue())));
544 emitGetVirtualRegister(callee
, regT0
);
545 // The arguments have been set up on the hot path for op_call_eval
546 if (opcodeID
== op_call
)
547 compileOpCallSetupArgs(instruction
);
548 else if (opcodeID
== op_construct
)
549 compileOpConstructSetupArgs(instruction
);
551 // Check for JSFunctions.
552 emitJumpSlowCaseIfNotJSCell(regT0
);
553 addSlowCase(branchPtr(NotEqual
, Address(regT0
), ImmPtr(m_globalData
->jsFunctionVPtr
)));
555 // First, in the case of a construct, allocate the new object.
556 if (opcodeID
== op_construct
) {
557 JITStubCall(this, cti_op_construct_JSConstruct
).call(registerOffset
- RegisterFile::CallFrameHeaderSize
- argCount
);
558 emitGetVirtualRegister(callee
, regT0
);
561 // Speculatively roll the callframe, assuming argCount will match the arity.
562 storePtr(callFrameRegister
, Address(callFrameRegister
, (RegisterFile::CallerFrame
+ registerOffset
) * static_cast<int>(sizeof(Register
))));
563 addPtr(Imm32(registerOffset
* static_cast<int>(sizeof(Register
))), callFrameRegister
);
564 move(Imm32(argCount
), regT1
);
566 emitNakedCall(m_globalData
->jitStubs
.ctiVirtualCall());
568 if (opcodeID
== op_call_eval
)
571 // Put the return value in dst. In the interpreter, op_ret does this.
572 emitPutVirtualRegister(dst
);
574 sampleCodeBlock(m_codeBlock
);
577 void JIT::compileOpCallSlowCase(Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned, OpcodeID opcodeID
)
579 int dst
= instruction
[1].u
.operand
;
583 JITStubCall
stubCall(this, opcodeID
== op_construct
? cti_op_construct_NotJSConstruct
: cti_op_call_NotJSFunction
);
584 stubCall
.call(dst
); // In the interpreter, the callee puts the return value in dst.
586 sampleCodeBlock(m_codeBlock
);
589 #else // !ENABLE(JIT_OPTIMIZE_CALL)
591 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
593 void JIT::compileOpCall(OpcodeID opcodeID
, Instruction
* instruction
, unsigned callLinkInfoIndex
)
595 int dst
= instruction
[1].u
.operand
;
596 int callee
= instruction
[2].u
.operand
;
597 int argCount
= instruction
[3].u
.operand
;
598 int registerOffset
= instruction
[4].u
.operand
;
602 if (opcodeID
== op_call_eval
) {
603 JITStubCall
stubCall(this, cti_op_call_eval
);
604 stubCall
.addArgument(callee
, regT0
);
605 stubCall
.addArgument(JIT::Imm32(registerOffset
));
606 stubCall
.addArgument(JIT::Imm32(argCount
));
608 wasEval
= branchPtr(NotEqual
, regT0
, ImmPtr(JSValue::encode(JSValue())));
611 // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
612 // This deliberately leaves the callee in ecx, used when setting up the stack frame below
613 emitGetVirtualRegister(callee
, regT0
);
614 DataLabelPtr addressOfLinkedFunctionCheck
;
616 BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
618 Jump jumpToSlow
= branchPtrWithPatch(NotEqual
, regT0
, addressOfLinkedFunctionCheck
, ImmPtr(JSValue::encode(JSValue())));
620 END_UNINTERRUPTED_SEQUENCE(sequenceOpCall
);
622 addSlowCase(jumpToSlow
);
623 ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck
, jumpToSlow
), patchOffsetOpCallCompareToJump
);
624 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathBegin
= addressOfLinkedFunctionCheck
;
626 // The following is the fast case, only used whan a callee can be linked.
628 // In the case of OpConstruct, call out to a cti_ function to create the new object.
629 if (opcodeID
== op_construct
) {
630 int proto
= instruction
[5].u
.operand
;
631 int thisRegister
= instruction
[6].u
.operand
;
633 emitPutJITStubArg(regT0
, 0);
634 emitPutJITStubArgFromVirtualRegister(proto
, 3, regT2
);
635 JITStubCall
stubCall(this, cti_op_construct_JSConstruct
);
636 stubCall
.call(thisRegister
);
637 emitGetVirtualRegister(callee
, regT0
);
640 // Fast version of stack frame initialization, directly relative to edi.
641 // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
642 storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister
, (registerOffset
+ RegisterFile::OptionalCalleeArguments
) * static_cast<int>(sizeof(Register
))));
643 storePtr(regT0
, Address(callFrameRegister
, (registerOffset
+ RegisterFile::Callee
) * static_cast<int>(sizeof(Register
))));
644 loadPtr(Address(regT0
, OBJECT_OFFSETOF(JSFunction
, m_data
) + OBJECT_OFFSETOF(ScopeChain
, m_node
)), regT1
); // newScopeChain
645 store32(Imm32(argCount
), Address(callFrameRegister
, (registerOffset
+ RegisterFile::ArgumentCount
) * static_cast<int>(sizeof(Register
))));
646 storePtr(callFrameRegister
, Address(callFrameRegister
, (registerOffset
+ RegisterFile::CallerFrame
) * static_cast<int>(sizeof(Register
))));
647 storePtr(regT1
, Address(callFrameRegister
, (registerOffset
+ RegisterFile::ScopeChain
) * static_cast<int>(sizeof(Register
))));
648 addPtr(Imm32(registerOffset
* sizeof(Register
)), callFrameRegister
);
650 // Call to the callee
651 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].hotPathOther
= emitNakedCall();
653 if (opcodeID
== op_call_eval
)
656 // Put the return value in dst. In the interpreter, op_ret does this.
657 emitPutVirtualRegister(dst
);
659 sampleCodeBlock(m_codeBlock
);
662 void JIT::compileOpCallSlowCase(Instruction
* instruction
, Vector
<SlowCaseEntry
>::iterator
& iter
, unsigned callLinkInfoIndex
, OpcodeID opcodeID
)
664 int dst
= instruction
[1].u
.operand
;
665 int callee
= instruction
[2].u
.operand
;
666 int argCount
= instruction
[3].u
.operand
;
667 int registerOffset
= instruction
[4].u
.operand
;
671 // The arguments have been set up on the hot path for op_call_eval
672 if (opcodeID
== op_call
)
673 compileOpCallSetupArgs(instruction
);
674 else if (opcodeID
== op_construct
)
675 compileOpConstructSetupArgs(instruction
);
677 // Fast check for JS function.
678 Jump callLinkFailNotObject
= emitJumpIfNotJSCell(regT0
);
679 Jump callLinkFailNotJSFunction
= branchPtr(NotEqual
, Address(regT0
), ImmPtr(m_globalData
->jsFunctionVPtr
));
681 // First, in the case of a construct, allocate the new object.
682 if (opcodeID
== op_construct
) {
683 JITStubCall(this, cti_op_construct_JSConstruct
).call(registerOffset
- RegisterFile::CallFrameHeaderSize
- argCount
);
684 emitGetVirtualRegister(callee
, regT0
);
687 // Speculatively roll the callframe, assuming argCount will match the arity.
688 storePtr(callFrameRegister
, Address(callFrameRegister
, (RegisterFile::CallerFrame
+ registerOffset
) * static_cast<int>(sizeof(Register
))));
689 addPtr(Imm32(registerOffset
* static_cast<int>(sizeof(Register
))), callFrameRegister
);
690 move(Imm32(argCount
), regT1
);
694 m_callStructureStubCompilationInfo
[callLinkInfoIndex
].callReturnLocation
= emitNakedCall(m_globalData
->jitStubs
->ctiVirtualCallLink());
696 // Put the return value in dst.
697 emitPutVirtualRegister(dst
);
698 sampleCodeBlock(m_codeBlock
);
700 // If not, we need an extra case in the if below!
701 ASSERT(OPCODE_LENGTH(op_call
) == OPCODE_LENGTH(op_call_eval
));
703 // Done! - return back to the hot path.
704 if (opcodeID
== op_construct
)
705 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct
));
707 emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call
));
709 // This handles host functions
710 callLinkFailNotObject
.link(this);
711 callLinkFailNotJSFunction
.link(this);
712 JITStubCall(this, opcodeID
== op_construct
? cti_op_construct_NotJSConstruct
: cti_op_call_NotJSFunction
).call();
714 emitPutVirtualRegister(dst
);
715 sampleCodeBlock(m_codeBlock
);
718 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
720 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
722 #endif // USE(JSVALUE32_64)
726 #endif // ENABLE(JIT)