Ignore:
Timestamp:
Dec 21, 2008, 5:00:07 PM (16 years ago)
Author:
[email protected]
Message:

2008-12-21 Gavin Barraclough <[email protected]>

Reviewed by Oliver Hunt & Cameron Zwarich.

Add support for call and property access repatching on x86-64.

No change in performance on current configurations (2x impovement on v8-tests with JIT enabled on x86-64).

  • assembler/MacroAssembler.h: (JSC::MacroAssembler::DataLabelPtr::repatch): (JSC::MacroAssembler::DataLabelPtr::operator X86Assembler::JmpDst): (JSC::MacroAssembler::DataLabel32::repatch): (JSC::MacroAssembler::RepatchBuffer::addressOf): (JSC::MacroAssembler::add32): (JSC::MacroAssembler::sub32): (JSC::MacroAssembler::loadPtrWithAddressOffsetRepatch): (JSC::MacroAssembler::storePtrWithAddressOffsetRepatch): (JSC::MacroAssembler::jePtr): (JSC::MacroAssembler::jnePtr): (JSC::MacroAssembler::jnePtrWithRepatch): (JSC::MacroAssembler::differenceBetween):
  • assembler/X86Assembler.h: (JSC::X86Assembler::addl_im): (JSC::X86Assembler::subl_im): (JSC::X86Assembler::cmpl_rm): (JSC::X86Assembler::movq_rm_disp32): (JSC::X86Assembler::movq_mr_disp32): (JSC::X86Assembler::repatchPointer): (JSC::X86Assembler::X86InstructionFormatter::oneByteOp64_disp32):
  • jit/JIT.cpp: (JSC::JIT::privateCompile): (JSC::JIT::privateCompileCTIMachineTrampolines):
  • jit/JIT.h:
  • jit/JITCall.cpp: (JSC::JIT::unlinkCall): (JSC::JIT::linkCall): (JSC::JIT::compileOpCall): (JSC::JIT::compileOpCallSlowCase):
  • jit/JITInlineMethods.h: (JSC::JIT::restoreArgumentReferenceForTrampoline):
  • jit/JITPropertyAccess.cpp: (JSC::JIT::compileGetByIdHotPath): (JSC::JIT::compileGetByIdSlowCase): (JSC::JIT::compilePutByIdHotPath): (JSC::JIT::compilePutByIdSlowCase): (JSC::resizePropertyStorage): (JSC::JIT::privateCompilePutByIdTransition): (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain):
  • wtf/Platform.h:
File:
1 edited

Legend:

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

    r39371 r39428  
    4141#endif
    4242
    43 #define __ m_assembler.
    44 
    4543using namespace std;
    4644
     
    5250    // (and, if a new JSFunction happened to be constructed at the same location, we could get a false positive
    5351    // match).  Reset the check so it no longer matches.
    54     reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = asPointer(JSImmediate::impossibleValue());
     52    DataLabelPtr::repatch(callLinkInfo->hotPathBegin, JSImmediate::impossibleValue());
    5553}
    5654
     
    6361        calleeCodeBlock->addCaller(callLinkInfo);
    6462   
    65         reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = callee;
    66         ctiRepatchCallByReturnAddress(callLinkInfo->hotPathOther, ctiCode);
     63        DataLabelPtr::repatch(callLinkInfo->hotPathBegin, callee);
     64        Jump::repatch(callLinkInfo->hotPathOther, ctiCode);
    6765    }
    6866
    6967    // repatch the instruction that jumps out to the cold path, so that we only try to link once.
    70     void* repatchCheck = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(callLinkInfo->hotPathBegin) + repatchOffsetOpCallCall);
    71     ctiRepatchCallByReturnAddress(repatchCheck, callLinkInfo->coldPathOther);
     68    void* repatchCheck = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(callLinkInfo->hotPathBegin) + repatchOffsetOpCallCompareToJump);
     69    Jump::repatch(repatchCheck, callLinkInfo->coldPathOther);
    7270}
    7371
     
    194192#else
    195193
    196 typedef X86Assembler::JmpSrc JmpSrc;
    197 typedef X86Assembler::JmpDst JmpDst;
    198 
    199194static void unreachable()
    200195{
     
    211206
    212207    // Handle eval
    213     JmpSrc wasEval;
     208    Jump wasEval;
    214209    if (opcodeID == op_call_eval) {
    215210        emitGetVirtualRegister(callee, X86::ecx);
     
    217212
    218213        emitCTICall(Interpreter::cti_op_call_eval);
    219         __ cmpl_ir(asInteger(JSImmediate::impossibleValue()), X86::eax);
    220         wasEval = __ jne();
     214        wasEval = jnePtr(X86::eax, ImmPtr(JSImmediate::impossibleValue()));
    221215    }
    222216
     
    224218    // This deliberately leaves the callee in ecx, used when setting up the stack frame below
    225219    emitGetVirtualRegister(callee, X86::ecx);
    226     __ cmpl_ir_force32(asInteger(JSImmediate::impossibleValue()), X86::ecx);
    227     JmpDst addressOfLinkedFunctionCheck = __ label();
    228     addSlowCase(__ jne());
    229     ASSERT(X86Assembler::getDifferenceBetweenLabels(addressOfLinkedFunctionCheck, __ label()) == repatchOffsetOpCallCall);
     220    DataLabelPtr addressOfLinkedFunctionCheck;
     221    Jump jumpToSlow = jnePtrWithRepatch(X86::ecx, addressOfLinkedFunctionCheck, ImmPtr(JSImmediate::impossibleValue()));
     222    addSlowCase(jumpToSlow);
     223    ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == repatchOffsetOpCallCompareToJump);
    230224    m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
    231225
     
    246240    // Fast version of stack frame initialization, directly relative to edi.
    247241    // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
    248     __ movl_i32m(asInteger(noValue()), (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register)), X86::edi);
    249     __ movl_rm(X86::ecx, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)), X86::edi);
    250     __ movl_mr(FIELD_OFFSET(JSFunction, m_scopeChain) + FIELD_OFFSET(ScopeChain, m_node), X86::ecx, X86::edx); // newScopeChain
    251     __ movl_i32m(argCount, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register)), X86::edi);
    252     __ movl_rm(X86::edi, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)), X86::edi);
    253     __ movl_rm(X86::edx, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)), X86::edi);
    254     __ addl_ir(registerOffset * sizeof(Register), X86::edi);
     242    storePtr(ImmPtr(noValue()), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register))));
     243    storePtr(X86::ecx, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register))));
     244    loadPtr(Address(X86::ecx, FIELD_OFFSET(JSFunction, m_scopeChain) + FIELD_OFFSET(ScopeChain, m_node)), X86::edx); // newScopeChain
     245    store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register))));
     246    storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register))));
     247    storePtr(X86::edx, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register))));
     248    addPtr(Imm32(registerOffset * sizeof(Register)), callFrameRegister);
    255249
    256250    // Call to the callee
     
    258252   
    259253    if (opcodeID == op_call_eval)
    260         __ link(wasEval, __ label());
     254        wasEval.link(this);
    261255
    262256    // Put the return value in dst. In the interpreter, op_ret does this.
     
    264258
    265259#if ENABLE(CODEBLOCK_SAMPLING)
    266         __ movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
     260        storePtr(ImmPtr(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
    267261#endif
    268262}
     
    284278
    285279    // Fast check for JS function.
    286     __ testl_i32r(JSImmediate::TagMask, X86::ecx);
    287     JmpSrc callLinkFailNotObject = __ jne();
    288     __ cmpl_im(reinterpret_cast<unsigned>(m_interpreter->m_jsFunctionVptr), 0, X86::ecx);
    289     JmpSrc callLinkFailNotJSFunction = __ jne();
     280    Jump callLinkFailNotObject = jnz32(X86::ecx, Imm32(JSImmediate::TagMask));
     281    Jump callLinkFailNotJSFunction = jnePtr(Address(X86::ecx), ImmPtr(m_interpreter->m_jsFunctionVptr));
    290282
    291283    // First, in the case of a construct, allocate the new object.
     
    296288    }
    297289
    298     __ movl_i32r(argCount, X86::edx);
     290    move(Imm32(argCount), X86::edx);
    299291
    300292    // Speculatively roll the callframe, assuming argCount will match the arity.
    301     __ movl_rm(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)), X86::edi);
    302     __ addl_ir(registerOffset * static_cast<int>(sizeof(Register)), X86::edi);
     293    storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
     294    addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
    303295
    304296    m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation =
    305297        emitNakedCall(m_interpreter->m_ctiVirtualCallPreLink);
    306298
    307     JmpSrc storeResultForFirstRun = __ jmp();
    308 
     299    Jump storeResultForFirstRun = jump();
     300
     301// FIXME: this label can be removed, since it is a fixed offset from 'callReturnLocation'.
    309302    // This is the address for the cold path *after* the first run (which tries to link the call).
    310     m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = __ label();
     303    m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = Label(this);
    311304
    312305    // The arguments have been set up on the hot path for op_call_eval
     
    317310
    318311    // Check for JSFunctions.
    319     __ testl_i32r(JSImmediate::TagMask, X86::ecx);
    320     JmpSrc isNotObject = __ jne();
    321     __ cmpl_im(reinterpret_cast<unsigned>(m_interpreter->m_jsFunctionVptr), 0, X86::ecx);
    322     JmpSrc isJSFunction = __ je();
     312    Jump isNotObject = jnzPtr(X86::ecx, Imm32(JSImmediate::TagMask));
     313    Jump isJSFunction = jePtr(Address(X86::ecx), ImmPtr(m_interpreter->m_jsFunctionVptr));
    323314
    324315    // This handles host functions
    325     JmpDst notJSFunctionlabel = __ label();
    326     __ link(isNotObject, notJSFunctionlabel);
    327     __ link(callLinkFailNotObject, notJSFunctionlabel);
    328     __ link(callLinkFailNotJSFunction, notJSFunctionlabel);
     316    isNotObject.link(this);
     317    callLinkFailNotObject.link(this);
     318    callLinkFailNotJSFunction.link(this);
    329319    emitCTICall(((opcodeID == op_construct) ? Interpreter::cti_op_construct_NotJSConstruct : Interpreter::cti_op_call_NotJSFunction));
    330     JmpSrc wasNotJSFunction = __ jmp();
     320    Jump wasNotJSFunction = jump();
    331321
    332322    // Next, handle JSFunctions...
    333     __ link(isJSFunction, __ label());
     323    isJSFunction.link(this);
    334324
    335325    // First, in the case of a construct, allocate the new object.
     
    341331
    342332    // Speculatively roll the callframe, assuming argCount will match the arity.
    343     __ movl_rm(X86::edi, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register)), X86::edi);
    344     __ addl_ir(registerOffset * static_cast<int>(sizeof(Register)), X86::edi);
    345     __ movl_i32r(argCount, X86::edx);
     333    storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
     334    addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister);
     335    move(Imm32(argCount), X86::edx);
    346336
    347337    emitNakedCall(m_interpreter->m_ctiVirtualCall);
    348338
    349339    // Put the return value in dst. In the interpreter, op_ret does this.
    350     JmpDst storeResult = __ label();
    351     __ link(wasNotJSFunction, storeResult);
    352     __ link(storeResultForFirstRun, storeResult);
     340    wasNotJSFunction.link(this);
     341    storeResultForFirstRun.link(this);
    353342    emitPutVirtualRegister(dst);
    354343
    355344#if ENABLE(CODEBLOCK_SAMPLING)
    356     __ movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
     345    storePtr(ImmPtr(m_codeBlock), m_interpreter->sampler()->codeBlockSlot());
    357346#endif
    358347}
Note: See TracChangeset for help on using the changeset viewer.