Ignore:
Timestamp:
Jul 30, 2009, 1:57:44 PM (16 years ago)
Author:
[email protected]
Message:

Merged nitro-extreme branch into trunk.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/jit/JITCall.cpp

    r44889 r46598  
    4646namespace JSC {
    4747
     48#if USE(JSVALUE32_64)
     49
     50void 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
     62void 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         
     73void 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
     88void JIT::compileOpCallVarargsSetupArgs(Instruction*)
     89{
     90    emitPutJITStubArg(regT0, 1);
     91    emitPutJITStubArg(regT1, 2);
     92    emitPutJITStubArg(regT3, 3); // registerOffset
     93    emitPutJITStubArg(regT2, 5); // argCount
     94}
     95
     96void 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
     127void 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
     142void 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
     158void 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
     168void 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
     179void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     180{
     181    compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call);
     182}
     183
     184void JIT::emitSlow_op_call_eval(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     185{
     186    compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_call_eval);
     187}
     188
     189void JIT::emitSlow_op_call_varargs(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     190{
     191    compileOpCallVarargsSlowCase(currentInstruction, iter);
     192}
     193
     194void JIT::emitSlow_op_construct(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
     195{
     196    compileOpCallSlowCase(currentInstruction, iter, m_callLinkInfoIndex++, op_construct);
     197}
     198
     199void JIT::emit_op_call(Instruction* currentInstruction)
     200{
     201    compileOpCall(op_call, currentInstruction, m_callLinkInfoIndex++);
     202}
     203
     204void JIT::emit_op_call_eval(Instruction* currentInstruction)
     205{
     206    compileOpCall(op_call_eval, currentInstruction, m_callLinkInfoIndex++);
     207}
     208
     209void 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
     221void JIT::emit_op_call_varargs(Instruction* currentInstruction)
     222{
     223    compileOpCallVarargs(currentInstruction);
     224}
     225
     226void 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
     235void 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
     287void 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
     305void 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
     377void 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.ctiVirtualCallPreLink());
     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
    48438void JIT::compileOpCallInitializeCallFrame()
    49439{
     
    129519    linkSlowCase(iter);
    130520    linkSlowCase(iter);
    131     JITStubCall stubCall(this, JITStubs::cti_op_call_NotJSFunction);
     521    JITStubCall stubCall(this, cti_op_call_NotJSFunction);
    132522    stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
    133523   
     
    149539    Jump wasEval;
    150540    if (opcodeID == op_call_eval) {
    151         CallEvalJITStub(this, instruction).call();
     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();
    152546        wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
    153547    }
     
    166560    // First, in the case of a construct, allocate the new object.
    167561    if (opcodeID == op_construct) {
    168         JITStubCall(this, JITStubs::cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
     562        JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
    169563        emitGetVirtualRegister(callee, regT2);
    170564    }
     
    192586    linkSlowCase(iter);
    193587    linkSlowCase(iter);
    194     JITStubCall stubCall(this, opcodeID == op_construct ? JITStubs::cti_op_construct_NotJSConstruct : JITStubs::cti_op_call_NotJSFunction);
     588    JITStubCall stubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction);
    195589    stubCall.call(dst); // In the interpreter, the callee puts the return value in dst.
    196590
     
    212606    Jump wasEval;
    213607    if (opcodeID == op_call_eval) {
    214         CallEvalJITStub(this, instruction).call();
     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();
    215613        wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue())));
    216614    }
     
    234632        emitPutJITStubArg(regT2, 1);
    235633        emitPutJITStubArgFromVirtualRegister(proto, 4, regT0);
    236         JITStubCall stubCall(this, JITStubs::cti_op_construct_JSConstruct);
     634        JITStubCall stubCall(this, cti_op_construct_JSConstruct);
    237635        stubCall.call(thisRegister);
    238636        emitGetVirtualRegister(callee, regT2);
     
    282680    // First, in the case of a construct, allocate the new object.
    283681    if (opcodeID == op_construct) {
    284         JITStubCall(this, JITStubs::cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
     682        JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount);
    285683        emitGetVirtualRegister(callee, regT2);
    286684    }
     
    309707    callLinkFailNotObject.link(this);
    310708    callLinkFailNotJSFunction.link(this);
    311     JITStubCall(this, opcodeID == op_construct ? JITStubs::cti_op_construct_NotJSConstruct : JITStubs::cti_op_call_NotJSFunction).call();
     709    JITStubCall(this, opcodeID == op_construct ? cti_op_construct_NotJSConstruct : cti_op_call_NotJSFunction).call();
    312710
    313711    emitPutVirtualRegister(dst);
     
    319717#endif // !ENABLE(JIT_OPTIMIZE_CALL)
    320718
     719#endif // USE(JSVALUE32_64)
     720
    321721} // namespace JSC
    322722
Note: See TracChangeset for help on using the changeset viewer.