Home | History | Annotate | Download | only in jit
      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 
     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 
     62 void JIT::compileOpCallSetupArgs(Instruction* instruction)
     63 {
     64     int argCount = instruction[3].u.operand;
     65     int registerOffset = instruction[4].u.operand;
     66 
     67     emitPutJITStubArg(regT1, regT0, 0);
     68     emitPutJITStubArgConstant(registerOffset, 1);
     69     emitPutJITStubArgConstant(argCount, 2);
     70 }
     71 
     72 void JIT::compileOpConstructSetupArgs(Instruction* instruction)
     73 {
     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;
     78 
     79     emitPutJITStubArg(regT1, regT0, 0);
     80     emitPutJITStubArgConstant(registerOffset, 1);
     81     emitPutJITStubArgConstant(argCount, 2);
     82     emitPutJITStubArgFromVirtualRegister(proto, 3, regT2, regT3);
     83     emitPutJITStubArgConstant(thisRegister, 4);
     84 }
     85 
     86 void JIT::compileOpCallVarargsSetupArgs(Instruction*)
     87 {
     88     emitPutJITStubArg(regT1, regT0, 0);
     89     emitPutJITStubArg(regT3, 1); // registerOffset
     90     emitPutJITStubArg(regT2, 2); // argCount
     91 }
     92 
     93 void JIT::compileOpCallVarargs(Instruction* instruction)
     94 {
     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;
     99 
    100     emitLoad(callee, regT1, regT0);
    101     emitLoadPayload(argCountRegister, regT2); // argCount
    102     addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset
    103 
    104     compileOpCallVarargsSetupArgs(instruction);
    105 
    106     emitJumpSlowCaseIfNotJSCell(callee, regT1);
    107     addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
    108 
    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);
    114 
    115     move(regT2, regT1); // argCount
    116 
    117     emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
    118 
    119     emitStore(dst, regT1, regT0);
    120 
    121     sampleCodeBlock(m_codeBlock);
    122 }
    123 
    124 void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
    125 {
    126     int dst = instruction[1].u.operand;
    127     int callee = instruction[2].u.operand;
    128 
    129     linkSlowCaseIfNotJSCell(iter, callee);
    130     linkSlowCase(iter);
    131 
    132     JITStubCall stubCall(this, cti_op_call_NotJSFunction);
    133     stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
    134 
    135     map(m_bytecodeIndex + OPCODE_LENGTH(op_call_varargs), dst, regT1, regT0);
    136     sampleCodeBlock(m_codeBlock);
    137 }
    138 
    139 void JIT::emit_op_ret(Instruction* currentInstruction)
    140 {
    141     unsigned dst = currentInstruction[1].u.operand;
    142 
    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();
    146 
    147     emitLoad(dst, regT1, regT0);
    148     emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT2);
    149     emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister);
    150 
    151     restoreReturnAddressBeforeReturn(regT2);
    152     ret();
    153 }
    154 
    155 void JIT::emit_op_construct_verify(Instruction* currentInstruction)
    156 {
    157     unsigned dst = currentInstruction[1].u.operand;
    158 
    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(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType)));
    163 }
    164 
    165 void JIT::emitSlow_op_construct_verify(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    166 {
    167     unsigned dst = currentInstruction[1].u.operand;
    168     unsigned src = currentInstruction[2].u.operand;
    169 
    170     linkSlowCase(iter);
    171     linkSlowCase(iter);
    172     emitLoad(src, regT1, regT0);
    173     emitStore(dst, regT1, regT0);
    174 }
    175 
    176 void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    177 {
    178     compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call);
    179 }
    180 
    181 void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    182 {
    183     compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval);
    184 }
    185 
    186 void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    187 {
    188     compileOpCallVarargsSlowCase(currentInstruction, iter);
    189 }
    190 
    191 void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
    192 {
    193     compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct);
    194 }
    195 
    196 void JIT::emit_op_call(Instruction* currentInstruction)
    197 {
    198     compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
    199 }
    200 
    201 void JIT::emit_op_call_eval(Instruction* currentInstruction)
    202 {
    203     compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
    204 }
    205 
    206 void JIT::emit_op_load_varargs(Instruction* currentInstruction)
    207 {
    208     int argCountDst = currentInstruction[1].u.operand;
    209     int argsOffset = currentInstruction[2].u.operand;
    210 
    211     JITStubCall stubCall(this, cti_op_load_varargs);
    212     stubCall.addArgument(Imm32(argsOffset));
    213     stubCall.call();
    214     // Stores a naked int32 in the register file.
    215     store32(returnValueRegister, Address(callFrameRegister, argCountDst * sizeof(Register)));
    216 }
    217 
    218 void JIT::emit_op_call_varargs(Instruction* currentInstruction)
    219 {
    220     compileOpCallVarargs(currentInstruction);
    221 }
    222 
    223 void JIT::emit_op_construct(Instruction* currentInstruction)
    224 {
    225     compileOpCall(op_construct, currentInstruction, m_callLinkInfoIndex++);
    226 }
    227 
    228 #if !ENABLE(JIT_OPTIMIZE_CALL)
    229 
    230 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
    231 
    232 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
    233 {
    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;
    238 
    239     Jump wasEval;
    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));
    245         stubCall.call();
    246         wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
    247     }
    248 
    249     emitLoad(callee, regT1, regT0);
    250 
    251     if (opcodeID == op_call)
    252         compileOpCallSetupArgs(instruction);
    253     else if (opcodeID == op_construct)
    254         compileOpConstructSetupArgs(instruction);
    255 
    256     emitJumpSlowCaseIfNotJSCell(callee, regT1);
    257     addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
    258 
    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);
    263     }
    264 
    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);
    269 
    270     emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
    271 
    272     if (opcodeID == op_call_eval)
    273         wasEval.link(this);
    274 
    275     emitStore(dst, regT1, regT0);
    276 
    277     sampleCodeBlock(m_codeBlock);
    278 }
    279 
    280 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
    281 {
    282     int dst = instruction[1].u.operand;
    283     int callee = instruction[2].u.operand;
    284 
    285     linkSlowCaseIfNotJSCell(iter, callee);
    286     linkSlowCase(iter);
    287 
    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.
    290 
    291     sampleCodeBlock(m_codeBlock);
    292 }
    293 
    294 #else // !ENABLE(JIT_OPTIMIZE_CALL)
    295 
    296 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
    297 
    298 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
    299 {
    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;
    304 
    305     Jump wasEval;
    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));
    311         stubCall.call();
    312         wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag));
    313     }
    314 
    315     emitLoad(callee, regT1, regT0);
    316 
    317     DataLabelPtr addressOfLinkedFunctionCheck;
    318 
    319     BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
    320 
    321     Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(0));
    322 
    323     END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
    324 
    325     addSlowCase(jumpToSlow);
    326     ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump);
    327     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
    328 
    329     addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)));
    330 
    331     // The following is the fast case, only used whan a callee can be linked.
    332 
    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;
    337 
    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);
    344 
    345         emitLoad(callee, regT1, regT0);
    346     }
    347 
    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);
    352 
    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);
    358 
    359     // Call to the callee
    360     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
    361 
    362     if (opcodeID == op_call_eval)
    363         wasEval.link(this);
    364 
    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);
    368 
    369     sampleCodeBlock(m_codeBlock);
    370 }
    371 
    372 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
    373 {
    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;
    378 
    379     linkSlowCase(iter);
    380     linkSlowCase(iter);
    381 
    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);
    387 
    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));
    391 
    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);
    396     }
    397 
    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);
    402 
    403     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
    404 
    405     // Put the return value in dst.
    406     emitStore(dst, regT1, regT0);;
    407     sampleCodeBlock(m_codeBlock);
    408 
    409     // If not, we need an extra case in the if below!
    410     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
    411 
    412     // Done! - return back to the hot path.
    413     if (opcodeID == op_construct)
    414         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
    415     else
    416         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
    417 
    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();
    422 
    423     emitStore(dst, regT1, regT0);;
    424     sampleCodeBlock(m_codeBlock);
    425 }
    426 
    427 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
    428 
    429 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
    430 
    431 #else // USE(JSVALUE32_64)
    432 
    433 void JIT::compileOpCallInitializeCallFrame()
    434 {
    435     store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register))));
    436 
    437     loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain
    438 
    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))));
    442 }
    443 
    444 void JIT::compileOpCallSetupArgs(Instruction* instruction)
    445 {
    446     int argCount = instruction[3].u.operand;
    447     int registerOffset = instruction[4].u.operand;
    448 
    449     // ecx holds func
    450     emitPutJITStubArg(regT0, 0);
    451     emitPutJITStubArgConstant(argCount, 2);
    452     emitPutJITStubArgConstant(registerOffset, 1);
    453 }
    454 
    455 void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction)
    456 {
    457     int registerOffset = instruction[4].u.operand;
    458 
    459     // ecx holds func
    460     emitPutJITStubArg(regT0, 0);
    461     emitPutJITStubArg(regT1, 2);
    462     addPtr(Imm32(registerOffset), regT1, regT2);
    463     emitPutJITStubArg(regT2, 1);
    464 }
    465 
    466 void JIT::compileOpConstructSetupArgs(Instruction* instruction)
    467 {
    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;
    472 
    473     // ecx holds func
    474     emitPutJITStubArg(regT0, 0);
    475     emitPutJITStubArgConstant(registerOffset, 1);
    476     emitPutJITStubArgConstant(argCount, 2);
    477     emitPutJITStubArgFromVirtualRegister(proto, 3, regT2);
    478     emitPutJITStubArgConstant(thisRegister, 4);
    479 }
    480 
    481 void JIT::compileOpCallVarargs(Instruction* instruction)
    482 {
    483     int dst = instruction[1].u.operand;
    484     int callee = instruction[2].u.operand;
    485     int argCountRegister = instruction[3].u.operand;
    486 
    487     emitGetVirtualRegister(argCountRegister, regT1);
    488     emitGetVirtualRegister(callee, regT0);
    489     compileOpCallVarargsSetupArgs(instruction);
    490 
    491     // Check for JSFunctions.
    492     emitJumpSlowCaseIfNotJSCell(regT0);
    493     addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
    494 
    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());
    503 
    504     // Put the return value in dst. In the interpreter, op_ret does this.
    505     emitPutVirtualRegister(dst);
    506 
    507     sampleCodeBlock(m_codeBlock);
    508 }
    509 
    510 void JIT::compileOpCallVarargsSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter)
    511 {
    512     int dst = instruction[1].u.operand;
    513 
    514     linkSlowCase(iter);
    515     linkSlowCase(iter);
    516     JITStubCall stubCall(this, cti_op_call_NotJSFunction);
    517     stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
    518 
    519     sampleCodeBlock(m_codeBlock);
    520 }
    521 
    522 #if !ENABLE(JIT_OPTIMIZE_CALL)
    523 
    524 /* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
    525 
    526 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned)
    527 {
    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;
    532 
    533     // Handle eval
    534     Jump wasEval;
    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));
    540         stubCall.call();
    541         wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
    542     }
    543 
    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);
    550 
    551     // Check for JSFunctions.
    552     emitJumpSlowCaseIfNotJSCell(regT0);
    553     addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)));
    554 
    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);
    559     }
    560 
    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);
    565 
    566     emitNakedCall(m_globalData->jitStubs.ctiVirtualCall());
    567 
    568     if (opcodeID == op_call_eval)
    569         wasEval.link(this);
    570 
    571     // Put the return value in dst. In the interpreter, op_ret does this.
    572     emitPutVirtualRegister(dst);
    573 
    574     sampleCodeBlock(m_codeBlock);
    575 }
    576 
    577 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned, OpcodeID opcodeID)
    578 {
    579     int dst = instruction[1].u.operand;
    580 
    581     linkSlowCase(iter);
    582     linkSlowCase(iter);
    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.
    585 
    586     sampleCodeBlock(m_codeBlock);
    587 }
    588 
    589 #else // !ENABLE(JIT_OPTIMIZE_CALL)
    590 
    591 /* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
    592 
    593 void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned callLinkInfoIndex)
    594 {
    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;
    599 
    600     // Handle eval
    601     Jump wasEval;
    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));
    607         stubCall.call();
    608         wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
    609     }
    610 
    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;
    615 
    616     BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
    617 
    618     Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue())));
    619 
    620     END_UNINTERRUPTED_SEQUENCE(sequenceOpCall);
    621 
    622     addSlowCase(jumpToSlow);
    623     ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump);
    624     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
    625 
    626     // The following is the fast case, only used whan a callee can be linked.
    627 
    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;
    632 
    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);
    638     }
    639 
    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);
    649 
    650     // Call to the callee
    651     m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall();
    652 
    653     if (opcodeID == op_call_eval)
    654         wasEval.link(this);
    655 
    656     // Put the return value in dst. In the interpreter, op_ret does this.
    657     emitPutVirtualRegister(dst);
    658 
    659     sampleCodeBlock(m_codeBlock);
    660 }
    661 
    662 void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>::iterator& iter, unsigned callLinkInfoIndex, OpcodeID opcodeID)
    663 {
    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;
    668 
    669     linkSlowCase(iter);
    670 
    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);
    676 
    677     // Fast check for JS function.
    678     Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
    679     Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr));
    680 
    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);
    685     }
    686 
    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);
    691 
    692     move(regT0, regT2);
    693 
    694     m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink());
    695 
    696     // Put the return value in dst.
    697     emitPutVirtualRegister(dst);
    698     sampleCodeBlock(m_codeBlock);
    699 
    700     // If not, we need an extra case in the if below!
    701     ASSERT(OPCODE_LENGTH(op_call) == OPCODE_LENGTH(op_call_eval));
    702 
    703     // Done! - return back to the hot path.
    704     if (opcodeID == op_construct)
    705         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_construct));
    706     else
    707         emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_call));
    708 
    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();
    713 
    714     emitPutVirtualRegister(dst);
    715     sampleCodeBlock(m_codeBlock);
    716 }
    717 
    718 /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_CALL) ------------------------------ */
    719 
    720 #endif // !ENABLE(JIT_OPTIMIZE_CALL)
    721 
    722 #endif // USE(JSVALUE32_64)
    723 
    724 } // namespace JSC
    725 
    726 #endif // ENABLE(JIT)
    727