Changeset 37670 in webkit for trunk/JavaScriptCore/VM/CTI.cpp


Ignore:
Timestamp:
Oct 17, 2008, 7:51:52 PM (17 years ago)
Author:
[email protected]
Message:

2008-10-17 Gavin Barraclough <[email protected]>

Optimize op_call by allowing call sites to be directly linked to callees.

For the hot path of op_call, CTI now generates a check (initially for an impossible
value), and the first time the call is executed we attempt to link the call directly
to the callee. WWe can currently only do so if the arity of the caller and callee
match. The (optimized) setup for the call on the hot path is linked directly to
the ctiCode for the callee, without indirection.


Two forms of the slow case of the call are generated, the first will be executed the
first time the call is reached. As well as this path attempting to link the call to
a callee, it also relinks the slow case to a second slow case, which will not continue
to attempt relinking the call. (This policy could be changed in future, but for not
this is intended to prevent thrashing).

If a callee that the caller has been linked to is garbage collected, then the link
in the caller's JIt code will be reset back to a value that cannot match - to prevent
any false positive matches.

~20% progression on deltablue & richards, >12% overall reduction in v8-tests
runtime, one or two percent progression on sunspider.

Reviewed by Oliver Hunt.

  • VM/CTI.cpp: (JSC::): (JSC::CTI::emitNakedCall): (JSC::unreachable): (JSC::CTI::compileOpCallInitializeCallFrame): (JSC::CTI::compileOpCallSetupArgs): (JSC::CTI::compileOpCall): (JSC::CTI::privateCompileMainPass): (JSC::CTI::privateCompileSlowCases): (JSC::CTI::privateCompile): (JSC::CTI::unlinkCall): (JSC::CTI::linkCall):
  • VM/CTI.h:
  • VM/CodeBlock.cpp: (JSC::CodeBlock::~CodeBlock): (JSC::CodeBlock::unlinkCallers): (JSC::CodeBlock::derefStructureIDs):
  • VM/CodeBlock.h: (JSC::StructureStubInfo::StructureStubInfo): (JSC::CallLinkInfo::CallLinkInfo): (JSC::CodeBlock::addCaller): (JSC::CodeBlock::removeCaller): (JSC::CodeBlock::getStubInfo):
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::emitCall): (JSC::CodeGenerator::emitConstruct):
  • VM/Machine.cpp: (JSC::Machine::cti_op_call_profiler): (JSC::Machine::cti_op_call_JSFunction): (JSC::Machine::cti_vm_lazyLinkCall): (JSC::Machine::cti_op_construct_JSConstructFast): (JSC::Machine::cti_op_construct_JSConstruct): (JSC::Machine::cti_op_construct_NotJSConstruct):
  • VM/Machine.h:
  • kjs/JSFunction.cpp: (JSC::JSFunction::~JSFunction):
  • kjs/JSFunction.h:
  • kjs/nodes.h: (JSC::FunctionBodyNode::):
  • masm/X86Assembler.h: (JSC::X86Assembler::getDifferenceBetweenLabels):
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/VM/CTI.cpp

    r37653 r37670  
    9696    "pushl %esi" "\n"
    9797    "pushl %edi" "\n"
    98     "subl $0x24, %esp" "\n"
     98    "pushl %ebx" "\n"
     99    "subl $0x20, %esp" "\n"
    99100    "movl $512, %esi" "\n"
    100101    "movl 0x38(%esp), %edi" "\n" // Ox38 = 0x0E * 4, 0x0E = CTI_ARGS_callFrame (see assertion above)
    101102    "call *0x30(%esp)" "\n" // Ox30 = 0x0C * 4, 0x0C = CTI_ARGS_code (see assertion above)
    102     "addl $0x24, %esp" "\n"
     103    "addl $0x20, %esp" "\n"
     104    "popl %ebx" "\n"
    103105    "popl %edi" "\n"
    104106    "popl %esi" "\n"
     
    119121    "call " SYMBOL_STRING(_ZN3JSC7Machine12cti_vm_throwEPvz) "\n"
    120122#endif
    121     "addl $0x24, %esp" "\n"
     123    "addl $0x20, %esp" "\n"
     124    "popl %ebx" "\n"
    122125    "popl %edi" "\n"
    123126    "popl %esi" "\n"
     
    134137            push esi;
    135138            push edi;
    136             sub esp, 0x24;
     139            push ebx;
     140            sub esp, 0x20;
    137141            mov esi, 512;
    138142            mov ecx, esp;
    139143            mov edi, [esp + 0x38];
    140144            call [esp + 0x30]; // Ox30 = 0x0C * 4, 0x0C = CTI_ARGS_code (see assertion above)
    141             add esp, 0x24;
     145            add esp, 0x20;
     146            pop ebx;
    142147            pop edi;
    143148            pop esi;
     
    151156            mov ecx, esp;
    152157            call JSC::Machine::cti_vm_throw;
    153             add esp, 0x24;
     158            add esp, 0x20;
     159            pop ebx;
    154160            pop edi;
    155161            pop esi;
     
    304310#endif
    305311
    306 ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCall(unsigned opcodeIndex, X86::RegisterID r)
    307 {
    308     m_jit.emitRestoreArgumentReference();
     312ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitNakedCall(unsigned opcodeIndex, X86::RegisterID r)
     313{
    309314    X86Assembler::JmpSrc call = m_jit.emitCall(r);
    310315    m_calls.append(CallRecord(call, opcodeIndex));
    311316
     317    return call;
     318}
     319
     320ALWAYS_INLINE  X86Assembler::JmpSrc CTI::emitNakedCall(unsigned opcodeIndex, void(*function)())
     321{
     322    X86Assembler::JmpSrc call = m_jit.emitCall();
     323    m_calls.append(CallRecord(call, reinterpret_cast<CTIHelper_v>(function), opcodeIndex));
    312324    return call;
    313325}
     
    512524#endif
    513525
     526static void unreachable()
     527{
     528    ASSERT_NOT_REACHED();
     529    exit(1);
     530}
     531
    514532void CTI::compileOpCallInitializeCallFrame(unsigned callee, unsigned argCount)
    515533{
     
    519537    m_jit.movl_rm(X86::ecx, RegisterFile::Callee * static_cast<int>(sizeof(Register)), X86::edx);
    520538
    521     m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_scopeChain) + OBJECT_OFFSET(ScopeChain, m_node), X86::ecx, X86::ecx); // newScopeChain
     539    m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_scopeChain) + OBJECT_OFFSET(ScopeChain, m_node), X86::ecx, X86::ebx); // newScopeChain
    522540    m_jit.movl_i32m(argCount, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register)), X86::edx);
    523541    m_jit.movl_rm(X86::edi, RegisterFile::CallerFrame * static_cast<int>(sizeof(Register)), X86::edx);
    524     m_jit.movl_rm(X86::ecx, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)), X86::edx);
    525 }
    526 
    527 void CTI::compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType type)
    528 {
    529     int dst = instruction[i + 1].u.operand;
    530     int callee = instruction[i + 2].u.operand;
    531     int firstArg = instruction[i + 4].u.operand;
    532     int argCount = instruction[i + 5].u.operand;
    533     int registerOffset = instruction[i + 6].u.operand;
    534 
    535     if (type == OpCallEval)
    536         emitGetPutArg(instruction[i + 3].u.operand, 16, X86::ecx);
    537 
    538     if (type == OpConstruct) {
    539         emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 20);
    540         emitPutArgConstant(argCount, 16);
    541         emitPutArgConstant(registerOffset, 12);
    542         emitPutArgConstant(firstArg, 8);
    543         emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
    544     } else {
    545         emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 12);
    546         emitPutArgConstant(argCount, 8);
    547         emitPutArgConstant(registerOffset, 4);
    548 
    549         int thisVal = instruction[i + 3].u.operand;
     542    m_jit.movl_rm(X86::ebx, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)), X86::edx);
     543}
     544
     545void CTI::compileOpCallSetupArgs(Instruction* instruction, bool isConstruct, bool isEval)
     546{
     547    int firstArg = instruction[4].u.operand;
     548    int argCount = instruction[5].u.operand;
     549    int registerOffset = instruction[6].u.operand;
     550
     551    emitPutArg(X86::ecx, 0);
     552    emitPutArgConstant(registerOffset, 4);
     553    emitPutArgConstant(argCount, 8);
     554    emitPutArgConstant(reinterpret_cast<unsigned>(instruction), 12);
     555    if (isConstruct) {
     556        emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
     557        emitPutArgConstant(firstArg, 20);
     558    } else if (isEval)
     559        emitGetPutArg(instruction[3].u.operand, 16, X86::eax);
     560}
     561
     562void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned structureIDInstructionIndex, CompileOpCallType type)
     563{
     564    int dst = instruction[1].u.operand;
     565    int callee = instruction[2].u.operand;
     566    int firstArg = instruction[4].u.operand;
     567    int argCount = instruction[5].u.operand;
     568    int registerOffset = instruction[6].u.operand;
     569
     570    // Setup this value as the first argument (does not apply to constructors)
     571    if (type != OpConstruct) {
     572        int thisVal = instruction[3].u.operand;
    550573        if (thisVal == missingThisObjectMarker()) {
    551574            // FIXME: should this be loaded dynamically off m_callFrame?
    552575            m_jit.movl_i32m(reinterpret_cast<unsigned>(m_callFrame->globalThisValue()), firstArg * sizeof(Register), X86::edi);
    553576        } else {
    554             emitGetArg(thisVal, X86::ecx);
    555             emitPutResult(firstArg, X86::ecx);
     577            emitGetArg(thisVal, X86::eax);
     578            emitPutResult(firstArg);
    556579        }
    557580    }
    558581
     582    // Handle eval
    559583    X86Assembler::JmpSrc wasEval;
    560584    if (type == OpCallEval) {
    561         emitGetPutArg(callee, 0, X86::ecx);
     585        emitGetArg(callee, X86::ecx);
     586        compileOpCallSetupArgs(instruction, false, true);
     587
    562588        emitCTICall(i, Machine::cti_op_call_eval);
    563 
    564589        m_jit.cmpl_i32r(reinterpret_cast<unsigned>(JSImmediate::impossibleValue()), X86::eax);
    565590        wasEval = m_jit.emitUnlinkedJne();
    566 
    567         // this sets up the first arg to op_cti_call (func), and explicitly leaves the value in ecx (checked just below).
     591    }
     592
     593    // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee.
     594    // This deliberately leaves the callee in ecx, used when setting up the stack frame below
     595    emitGetArg(callee, X86::ecx);
     596    m_jit.cmpl_i32r(reinterpret_cast<unsigned>(JSImmediate::impossibleValue()), X86::ecx);
     597    X86Assembler::JmpDst addressOfLinkedFunctionCheck = m_jit.label();
     598    m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
     599    ASSERT(X86Assembler::getDifferenceBetweenLabels(addressOfLinkedFunctionCheck, m_jit.label()) == repatchOffsetOpCallCall);
     600    m_structureStubCompilationInfo[structureIDInstructionIndex].hotPathBegin = addressOfLinkedFunctionCheck;
     601
     602    // The following is the fast case, only used whan a callee can be linked.
     603
     604    emitGetCTIParam(CTI_ARGS_profilerReference, X86::eax);
     605    m_jit.cmpl_i32m(0, X86::eax);
     606    X86Assembler::JmpSrc noProfile = m_jit.emitUnlinkedJe();
     607    emitPutArg(X86::ecx, 0);
     608    emitCTICall(i, Machine::cti_op_call_profiler);
     609    emitGetArg(callee, X86::ecx);
     610    m_jit.link(noProfile, m_jit.label());
     611
     612    // In the case of OpConstruct, call oout to a cti_ function to create the new object.
     613    if (type == OpConstruct) {
     614        emitPutArg(X86::ecx, 0);
     615        emitGetPutArg(instruction[3].u.operand, 4, X86::eax);
     616        emitCTICall(i, Machine::cti_op_construct_JSConstructFast);
     617        emitPutResult(instruction[4].u.operand);
    568618        emitGetArg(callee, X86::ecx);
    569     } else {
    570         // this sets up the first arg to op_cti_call (func), and explicitly leaves the value in ecx (checked just below).
    571         emitGetPutArg(callee, 0, X86::ecx);
    572619    }
    573620
    574     // Fast check for JS function.
    575     m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
    576     X86Assembler::JmpSrc isNotObject = m_jit.emitUnlinkedJne();
    577     m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsFunctionVptr), X86::ecx);
    578     X86Assembler::JmpSrc isJSFunction = m_jit.emitUnlinkedJe();
    579     m_jit.link(isNotObject, m_jit.label());
    580 
    581     // This handles host functions
    582     emitCTICall(i, ((type == OpConstruct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
    583 
    584     X86Assembler::JmpSrc wasNotJSFunction = m_jit.emitUnlinkedJmp();
    585     m_jit.link(isJSFunction, m_jit.label());
    586 
    587     // This handles JSFunctions
    588     emitCTICall(i, (type == OpConstruct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
    589 
    590     compileOpCallInitializeCallFrame(callee, argCount);
    591 
    592     // load ctiCode from the new codeBlock.
    593     m_jit.movl_mr(OBJECT_OFFSET(CodeBlock, ctiCode), X86::eax, X86::eax);
    594 
    595     // Put the new value of 'callFrame' into edi and onto the stack, too.
    596     m_jit.movl_rr(X86::edx, X86::edi);
    597 
    598     // Check the ctiCode has been generated - if not, this is handled in a slow case.
    599     m_jit.testl_rr(X86::eax, X86::eax);
    600     m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i));
    601     emitCall(i, X86::eax);
     621    // Fast version of stack frame initialization, directly relative to edi.
     622    // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee
     623    m_jit.movl_i32m(reinterpret_cast<unsigned>(nullJSValue), (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register)), X86::edi);
     624    m_jit.movl_rm(X86::ecx, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)), X86::edi);
     625    m_jit.movl_mr(OBJECT_OFFSET(JSFunction, m_scopeChain) + OBJECT_OFFSET(ScopeChain, m_node), X86::ecx, X86::edx); // newScopeChain
     626    m_jit.movl_i32m(argCount, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register)), X86::edi);
     627    m_jit.movl_rm(X86::edi, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)), X86::edi);
     628    m_jit.movl_rm(X86::edx, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)), X86::edi);
     629    m_jit.addl_i32r(registerOffset * sizeof(Register), X86::edi);
     630
     631    // Call to the callee
     632    m_structureStubCompilationInfo[structureIDInstructionIndex].hotPathOther = emitNakedCall(i, unreachable);
    602633   
    603     X86Assembler::JmpDst end = m_jit.label();
    604     m_jit.link(wasNotJSFunction, end);
    605634    if (type == OpCallEval)
    606         m_jit.link(wasEval, end);
     635        m_jit.link(wasEval, m_jit.label());
    607636
    608637    // Put the return value in dst. In the interpreter, op_ret does this.
     
    12151244        }
    12161245        case op_call: {
    1217             compileOpCall(instruction, i);
     1246            compileOpCall(instruction + i, i, structureIDInstructionIndex++);
    12181247            i += 7;
    12191248            break;
     
    13221351        }
    13231352        case op_construct: {
    1324             compileOpCall(instruction, i, OpConstruct);
     1353            compileOpCall(instruction + i, i, structureIDInstructionIndex++, OpConstruct);
    13251354            i += 7;
    13261355            break;
     
    17551784        }
    17561785        case op_call_eval: {
    1757             compileOpCall(instruction, i, OpCallEval);
     1786            compileOpCall(instruction + i, i, structureIDInstructionIndex++, OpCallEval);
    17581787            i += 7;
    17591788            break;
     
    17621791            emitGetPutArg(instruction[i + 1].u.operand, 0, X86::ecx);
    17631792            emitCTICall(i, Machine::cti_op_throw);
    1764             m_jit.addl_i8r(0x24, X86::esp);
     1793            m_jit.addl_i8r(0x20, X86::esp);
     1794            m_jit.popl_r(X86::ebx);
    17651795            m_jit.popl_r(X86::edi);
    17661796            m_jit.popl_r(X86::esi);
     
    21132143    for (Vector<SlowCaseEntry>::iterator iter = m_slowCases.begin(); iter != m_slowCases.end(); ++iter) {
    21142144        unsigned i = iter->to;
    2115         switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
     2145        switch (OpcodeID opcodeID = m_machine->getOpcodeID(instruction[i].u.opcode)) {
    21162146        case op_convert_this: {
    21172147            m_jit.link(iter->from, m_jit.label());
     
    25782608        case op_call_eval:
    25792609        case op_construct: {
     2610            int dst = instruction[i + 1].u.operand;
     2611            int callee = instruction[i + 2].u.operand;
     2612            int argCount = instruction[i + 5].u.operand;
     2613
    25802614            m_jit.link(iter->from, m_jit.label());
    25812615
    2582             // We jump to this slow case if the ctiCode for the codeBlock has not yet been generated; compile it now.
     2616            // The arguments have been set up on the hot path for op_call_eval
     2617            if (opcodeID != op_call_eval)
     2618                compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
     2619
     2620            // Fast check for JS function.
     2621            m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
     2622            X86Assembler::JmpSrc callLinkFailNotObject = m_jit.emitUnlinkedJne();
     2623            m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsFunctionVptr), X86::ecx);
     2624            X86Assembler::JmpSrc callLinkFailNotJSFunction = m_jit.emitUnlinkedJne();
     2625
     2626            // This handles JSFunctions
     2627            emitGetCTIParam(CTI_ARGS_profilerReference, X86::eax);
     2628            m_jit.cmpl_i32m(0, X86::eax);
     2629            X86Assembler::JmpSrc noProfile1 = m_jit.emitUnlinkedJe();
     2630            emitCTICall(i, Machine::cti_op_call_profiler);
     2631            m_jit.link(noProfile1, m_jit.label());
     2632
     2633            emitCTICall(i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
     2634            // initialize the new call frame (pointed to by edx, after the last call), then set edi to point to it.
     2635            compileOpCallInitializeCallFrame(callee, argCount);
     2636            m_jit.movl_rr(X86::edx, X86::edi);
     2637
     2638            // Try to link & repatch this call.
     2639            m_structureStubCompilationInfo[structureIDInstructionIndex].callReturnLocation =
     2640                emitCTICall(i, Machine::cti_vm_lazyLinkCall);
     2641            emitNakedCall(i, X86::eax);
     2642            X86Assembler::JmpSrc storeResultForFirstRun = m_jit.emitUnlinkedJmp();
     2643
     2644            // This is the address for the cold path *after* the first run (which tries to link the call).
     2645            m_structureStubCompilationInfo[structureIDInstructionIndex].coldPathOther = m_jit.label();
     2646
     2647            // The arguments have been set up on the hot path for op_call_eval
     2648            if (opcodeID != op_call_eval)
     2649                compileOpCallSetupArgs(instruction + i, (opcodeID == op_construct), false);
     2650
     2651            // Check for JSFunctions.
     2652            m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
     2653            X86Assembler::JmpSrc isNotObject = m_jit.emitUnlinkedJne();
     2654            m_jit.cmpl_i32m(reinterpret_cast<unsigned>(m_machine->m_jsFunctionVptr), X86::ecx);
     2655            X86Assembler::JmpSrc isJSFunction = m_jit.emitUnlinkedJe();
     2656
     2657            // This handles host functions
     2658            X86Assembler::JmpDst notJSFunctionlabel = m_jit.label();
     2659            m_jit.link(isNotObject, notJSFunctionlabel);
     2660            m_jit.link(callLinkFailNotObject, notJSFunctionlabel);
     2661            m_jit.link(callLinkFailNotJSFunction, notJSFunctionlabel);
     2662            emitCTICall(i, ((opcodeID == op_construct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
     2663            X86Assembler::JmpSrc wasNotJSFunction = m_jit.emitUnlinkedJmp();
     2664
     2665            // Next, handle JSFunctions...
     2666            m_jit.link(isJSFunction, m_jit.label());
     2667
     2668            // Profiler check
     2669            emitGetCTIParam(CTI_ARGS_profilerReference, X86::eax);
     2670            m_jit.cmpl_i32m(0, X86::eax);
     2671            X86Assembler::JmpSrc noProfile = m_jit.emitUnlinkedJe();
     2672            emitCTICall(i, Machine::cti_op_call_profiler);
     2673            m_jit.link(noProfile, m_jit.label());
     2674
     2675            emitCTICall(i, (opcodeID == op_construct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction);
     2676            // initialize the new call frame (pointed to by edx, after the last call).
     2677            compileOpCallInitializeCallFrame(callee, argCount);
     2678            m_jit.movl_rr(X86::edx, X86::edi);
     2679
     2680            // load ctiCode from the new codeBlock.
     2681            m_jit.movl_mr(OBJECT_OFFSET(CodeBlock, ctiCode), X86::eax, X86::eax);
     2682
     2683            // Move the new callframe into edi.
     2684            m_jit.movl_rr(X86::edx, X86::edi);
     2685
     2686            // Check the ctiCode has been generated (if not compile it now), and make the call.
     2687            m_jit.testl_rr(X86::eax, X86::eax);
     2688            X86Assembler::JmpSrc hasCode = m_jit.emitUnlinkedJne();
    25832689            emitCTICall(i, Machine::cti_vm_compile);
    2584             emitCall(i, X86::eax);
    2585 
    2586             // Instead of checking for 0 we could initialize the CodeBlock::ctiCode to point to a trampoline that would trigger the translation.
     2690            m_jit.link(hasCode, m_jit.label());
     2691
     2692            emitNakedCall(i, X86::eax);
    25872693
    25882694            // Put the return value in dst. In the interpreter, op_ret does this.
    2589             emitPutResult(instruction[i + 1].u.operand);
     2695            X86Assembler::JmpDst storeResult = m_jit.label();
     2696            m_jit.link(wasNotJSFunction, storeResult);
     2697            m_jit.link(storeResultForFirstRun, storeResult);
     2698            emitPutResult(dst);
     2699
     2700            ++structureIDInstructionIndex;
    25902701            i += 7;
    25912702            break;
     
    26232734    X86Assembler::JmpDst afterRegisterFileCheck;
    26242735    if (m_codeBlock->codeType == FunctionCode) {
     2736        // In the case of a fast linked call, we do not set this up in the caller.
     2737        m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), RegisterFile::CodeBlock * static_cast<int>(sizeof(Register)), X86::edi);
     2738
    26252739        emitGetCTIParam(CTI_ARGS_registerFile, X86::eax);
    26262740        m_jit.leal_mr(m_codeBlock->numCalleeRegisters * sizeof(Register), X86::edi, X86::edx);
     
    26912805        info.callReturnLocation = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].callReturnLocation);
    26922806        info.hotPathBegin = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].hotPathBegin);
     2807        info.hotPathOther = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].hotPathOther);
     2808        info.coldPathOther = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].coldPathOther);
    26932809    }
    26942810
     
    29713087   
    29723088    ctiRepatchCallByReturnAddress(returnAddress, code);
     3089}
     3090
     3091void CTI::unlinkCall(StructureStubInfo* structureStubInfo)
     3092{
     3093    // When the JSFunction is deleted the pointer embedded in the instruction stream will no longer be valid
     3094    // (and, if a new JSFunction happened to be constructed at the same location, we could get a false positive
     3095    // match).  Reset the check so it no longer matches.
     3096    reinterpret_cast<void**>(structureStubInfo->hotPathBegin)[-1] = JSImmediate::impossibleValue();
     3097}
     3098
     3099void CTI::linkCall(CodeBlock* callerCodeBlock, JSFunction* callee, CodeBlock* calleeCodeBlock, void* ctiCode, void* returnAddress, int callerArgCount)
     3100{
     3101    StructureStubInfo& stubInfo = callerCodeBlock->getStubInfo(returnAddress);
     3102
     3103    // Currently we only link calls with the exact number of arguments.
     3104    if (callerArgCount == calleeCodeBlock->numParameters) {
     3105        ASSERT(!stubInfo.linkInfoPtr);
     3106   
     3107        calleeCodeBlock->addCaller(&stubInfo);
     3108   
     3109        reinterpret_cast<void**>(stubInfo.hotPathBegin)[-1] = callee;
     3110        ctiRepatchCallByReturnAddress(stubInfo.hotPathOther, ctiCode);
     3111    }
     3112
     3113    // repatch the instruction that jumps out to the cold path, so that we only try to link once.
     3114    void* repatchCheck = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(stubInfo.hotPathBegin) + repatchOffsetOpCallCall);
     3115    ctiRepatchCallByReturnAddress(repatchCheck, stubInfo.coldPathOther);
    29733116}
    29743117
Note: See TracChangeset for help on using the changeset viewer.