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


Ignore:
Timestamp:
Oct 23, 2008, 3:29:54 PM (17 years ago)
Author:
[email protected]
Message:

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

Reviewed by Oliver Hunt.

Fix hideous pathological case performance when looking up repatch info, bug #21727.

When repatching JIT code to optimize we look up records providing information about
the generated code (also used to track recsources used in linking to be later released).
The lookup was being performed using a linear scan of all such records.

(1) Split up the different types of reptach information. This means we can search them

separately, and in some cases should reduce their size.

(2) In the case of property accesses, search with a binary chop over the data.
(3) In the case of calls, pass a pointer to the repatch info into the relink function.

  • VM/CTI.cpp: (JSC::CTI::CTI): (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::dump): (JSC::CodeBlock::~CodeBlock): (JSC::CodeBlock::unlinkCallers): (JSC::CodeBlock::derefStructureIDs):
  • VM/CodeBlock.h: (JSC::StructureStubInfo::StructureStubInfo): (JSC::CallLinkInfo::CallLinkInfo): (JSC::CallLinkInfo::setUnlinked): (JSC::CallLinkInfo::isLinked): (JSC::getStructureStubInfoReturnLocation): (JSC::binaryChop): (JSC::CodeBlock::addCaller): (JSC::CodeBlock::getStubInfo):
  • VM/CodeGenerator.cpp: (JSC::CodeGenerator::emitResolve): (JSC::CodeGenerator::emitGetById): (JSC::CodeGenerator::emitPutById): (JSC::CodeGenerator::emitCall): (JSC::CodeGenerator::emitConstruct):
  • VM/Machine.cpp: (JSC::Machine::cti_vm_lazyLinkCall):
File:
1 edited

Legend:

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

    r37812 r37831  
    514514    , m_codeBlock(codeBlock)
    515515    , m_labels(codeBlock ? codeBlock->instructions.size() : 0)
    516     , m_structureStubCompilationInfo(codeBlock ? codeBlock->structureIDInstructions.size() : 0)
     516    , m_propertyAccessCompilationInfo(codeBlock ? codeBlock->propertyAccessInstructions.size() : 0)
     517    , m_callStructureStubCompilationInfo(codeBlock ? codeBlock->callLinkInfos.size() : 0)
    517518{
    518519}
     
    577578}
    578579
    579 void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned structureIDInstructionIndex, CompileOpCallType type)
     580void CTI::compileOpCall(Instruction* instruction, unsigned i, unsigned callLinkInfoIndex, CompileOpCallType type)
    580581{
    581582    int dst = instruction[1].u.operand;
     
    615616    m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJne(), i));
    616617    ASSERT(X86Assembler::getDifferenceBetweenLabels(addressOfLinkedFunctionCheck, m_jit.label()) == repatchOffsetOpCallCall);
    617     m_structureStubCompilationInfo[structureIDInstructionIndex].hotPathBegin = addressOfLinkedFunctionCheck;
     618    m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck;
    618619
    619620    // The following is the fast case, only used whan a callee can be linked.
     
    639640
    640641    // Call to the callee
    641     m_structureStubCompilationInfo[structureIDInstructionIndex].hotPathOther = emitNakedCall(i, unreachable);
     642    m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(i, unreachable);
    642643   
    643644    if (type == OpCallEval)
     
    950951    unsigned instructionCount = m_codeBlock->instructions.size();
    951952
    952     unsigned structureIDInstructionIndex = 0;
     953    unsigned propertyAccessInstructionIndex = 0;
     954    unsigned callLinkInfoIndex = 0;
    953955
    954956    for (unsigned i = 0; i < instructionCount; ) {
     
    10951097            emitGetArg(instruction[i + 3].u.operand, X86::edx);
    10961098
    1097             ASSERT(m_codeBlock->structureIDInstructions[structureIDInstructionIndex].opcodeIndex == i);
     1099            ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
    10981100            X86Assembler::JmpDst hotPathBegin = m_jit.label();
    1099             m_structureStubCompilationInfo[structureIDInstructionIndex].hotPathBegin = hotPathBegin;
    1100             ++structureIDInstructionIndex;
     1101            m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
     1102            ++propertyAccessInstructionIndex;
    11011103
    11021104            // Jump to a slow case if either the base object is an immediate, or if the StructureID does not match.
     
    11231125            emitGetArg(instruction[i + 2].u.operand, X86::eax);
    11241126
    1125             ASSERT(m_codeBlock->structureIDInstructions[structureIDInstructionIndex].opcodeIndex == i);
     1127            ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
    11261128
    11271129            X86Assembler::JmpDst hotPathBegin = m_jit.label();
    1128             m_structureStubCompilationInfo[structureIDInstructionIndex].hotPathBegin = hotPathBegin;
    1129             ++structureIDInstructionIndex;
     1130            m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin;
     1131            ++propertyAccessInstructionIndex;
    11301132
    11311133            emitJumpSlowCaseIfNotJSCell(X86::eax, i);
     
    12531255        }
    12541256        case op_call: {
    1255             compileOpCall(instruction + i, i, structureIDInstructionIndex++);
     1257            compileOpCall(instruction + i, i, callLinkInfoIndex++);
    12561258            i += 7;
    12571259            break;
     
    13491351        }
    13501352        case op_construct: {
    1351             compileOpCall(instruction + i, i, structureIDInstructionIndex++, OpConstruct);
     1353            compileOpCall(instruction + i, i, callLinkInfoIndex++, OpConstruct);
    13521354            i += 7;
    13531355            break;
     
    14911493            m_jit.movl_mr(structureIDAddr, X86::edx);
    14921494            m_jit.cmpl_rm(X86::edx, OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
    1493             X86Assembler::JmpSrc slowCase = m_jit.emitUnlinkedJne(); // StructureIDs don't match
    1494             m_slowCases.append(SlowCaseEntry(slowCase, i));
     1495            X86Assembler::JmpSrc noMatch = m_jit.emitUnlinkedJne(); // StructureIDs don't match
    14951496
    14961497            // Load cached property
     
    15021503
    15031504            // Slow case
    1504             m_jit.link(slowCase, m_jit.label());
     1505            m_jit.link(noMatch, m_jit.label());
    15051506            emitPutArgConstant(globalObject, 0);
    15061507            emitPutArgConstant(reinterpret_cast<unsigned>(ident), 4);
     
    15101511            m_jit.link(end, m_jit.label());
    15111512            i += 6;
    1512             ++structureIDInstructionIndex;
    15131513            break;
    15141514        }
     
    18421842        }
    18431843        case op_call_eval: {
    1844             compileOpCall(instruction + i, i, structureIDInstructionIndex++, OpCallEval);
     1844            compileOpCall(instruction + i, i, callLinkInfoIndex++, OpCallEval);
    18451845            i += 7;
    18461846            break;
     
    21932193    }
    21942194
    2195     ASSERT(structureIDInstructionIndex == m_codeBlock->structureIDInstructions.size());
     2195    ASSERT(propertyAccessInstructionIndex == m_codeBlock->propertyAccessInstructions.size());
     2196    ASSERT(callLinkInfoIndex == m_codeBlock->callLinkInfos.size());
    21962197}
    21972198
     
    22182219void CTI::privateCompileSlowCases()
    22192220{
    2220     unsigned structureIDInstructionIndex = 0;
     2221    unsigned propertyAccessInstructionIndex = 0;
     2222    unsigned callLinkInfoIndex = 0;
    22212223
    22222224    Instruction* instruction = m_codeBlock->instructions.begin();
     
    23622364
    23632365            // Track the location of the call; this will be used to recover repatch information.
    2364             ASSERT(m_codeBlock->structureIDInstructions[structureIDInstructionIndex].opcodeIndex == i);
    2365             m_structureStubCompilationInfo[structureIDInstructionIndex].callReturnLocation = call;
    2366             ++structureIDInstructionIndex;
     2366            ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
     2367            m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
     2368            ++propertyAccessInstructionIndex;
    23672369
    23682370            i += 8;
     
    23902392
    23912393            // Track the location of the call; this will be used to recover repatch information.
    2392             ASSERT(m_codeBlock->structureIDInstructions[structureIDInstructionIndex].opcodeIndex == i);
    2393             m_structureStubCompilationInfo[structureIDInstructionIndex].callReturnLocation = call;
    2394             ++structureIDInstructionIndex;
     2394            ASSERT(m_codeBlock->propertyAccessInstructions[propertyAccessInstructionIndex].opcodeIndex == i);
     2395            m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
     2396            ++propertyAccessInstructionIndex;
    23952397
    23962398            i += 8;
    2397             break;
    2398         }
    2399         case op_resolve_global: {
    2400             ++structureIDInstructionIndex;
    2401             i += 6;
    24022399            break;
    24032400        }
     
    27112708
    27122709            // Try to link & repatch this call.
    2713             m_structureStubCompilationInfo[structureIDInstructionIndex].callReturnLocation =
     2710            CallLinkInfo* info = &(m_codeBlock->callLinkInfos[callLinkInfoIndex]);
     2711            emitPutArgConstant(reinterpret_cast<unsigned>(info), 4);
     2712            m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation =
    27142713                emitCTICall(i, Machine::cti_vm_lazyLinkCall);
    27152714            emitNakedCall(i, X86::eax);
     
    27172716
    27182717            // This is the address for the cold path *after* the first run (which tries to link the call).
    2719             m_structureStubCompilationInfo[structureIDInstructionIndex].coldPathOther = m_jit.label();
     2718            m_callStructureStubCompilationInfo[callLinkInfoIndex].coldPathOther = m_jit.label();
    27202719
    27212720            // The arguments have been set up on the hot path for op_call_eval
     
    27642763            emitPutResult(dst);
    27652764
    2766             ++structureIDInstructionIndex;
     2765            ++callLinkInfoIndex;
    27672766            i += 7;
    27682767            break;
     
    27882787    }
    27892788
    2790     ASSERT(structureIDInstructionIndex == m_codeBlock->structureIDInstructions.size());
     2789    ASSERT(propertyAccessInstructionIndex == m_codeBlock->propertyAccessInstructions.size());
     2790    ASSERT(callLinkInfoIndex == m_codeBlock->callLinkInfos.size());
    27912791}
    27922792
     
    28672867        X86Assembler::linkAbsoluteAddress(code, iter->addrPosition, iter->target);
    28682868
    2869     for (unsigned i = 0; i < m_codeBlock->structureIDInstructions.size(); ++i) {
    2870         StructureStubInfo& info = m_codeBlock->structureIDInstructions[i];
    2871         info.callReturnLocation = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].callReturnLocation);
    2872         info.hotPathBegin = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].hotPathBegin);
    2873         info.hotPathOther = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].hotPathOther);
    2874         info.coldPathOther = X86Assembler::getRelocatedAddress(code, m_structureStubCompilationInfo[i].coldPathOther);
     2869    for (unsigned i = 0; i < m_codeBlock->propertyAccessInstructions.size(); ++i) {
     2870        StructureStubInfo& info = m_codeBlock->propertyAccessInstructions[i];
     2871        info.callReturnLocation = X86Assembler::getRelocatedAddress(code, m_propertyAccessCompilationInfo[i].callReturnLocation);
     2872        info.hotPathBegin = X86Assembler::getRelocatedAddress(code, m_propertyAccessCompilationInfo[i].hotPathBegin);
     2873    }
     2874    for (unsigned i = 0; i < m_codeBlock->callLinkInfos.size(); ++i) {
     2875        CallLinkInfo& info = m_codeBlock->callLinkInfos[i];
     2876        info.callReturnLocation = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].callReturnLocation);
     2877        info.hotPathBegin = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].hotPathBegin);
     2878        info.hotPathOther = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].hotPathOther);
     2879        info.coldPathOther = X86Assembler::getRelocatedAddress(code, m_callStructureStubCompilationInfo[i].coldPathOther);
    28752880    }
    28762881
     
    31553160}
    31563161
    3157 void CTI::unlinkCall(StructureStubInfo* structureStubInfo)
     3162void CTI::unlinkCall(CallLinkInfo* callLinkInfo)
    31583163{
    31593164    // When the JSFunction is deleted the pointer embedded in the instruction stream will no longer be valid
    31603165    // (and, if a new JSFunction happened to be constructed at the same location, we could get a false positive
    31613166    // match).  Reset the check so it no longer matches.
    3162     reinterpret_cast<void**>(structureStubInfo->hotPathBegin)[-1] = asPointer(JSImmediate::impossibleValue());
    3163 }
    3164 
    3165 void CTI::linkCall(CodeBlock* callerCodeBlock, JSFunction* callee, CodeBlock* calleeCodeBlock, void* ctiCode, void* returnAddress, int callerArgCount)
    3166 {
    3167     StructureStubInfo& stubInfo = callerCodeBlock->getStubInfo(returnAddress);
    3168 
     3167    reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = asPointer(JSImmediate::impossibleValue());
     3168}
     3169
     3170void CTI::linkCall(JSFunction* callee, CodeBlock* calleeCodeBlock, void* ctiCode, CallLinkInfo* callLinkInfo, int callerArgCount)
     3171{
    31693172    // Currently we only link calls with the exact number of arguments.
    31703173    if (callerArgCount == calleeCodeBlock->numParameters) {
    3171         ASSERT(!stubInfo.linkInfoPtr);
     3174        ASSERT(!callLinkInfo->isLinked());
    31723175   
    3173         calleeCodeBlock->addCaller(&stubInfo);
     3176        calleeCodeBlock->addCaller(callLinkInfo);
    31743177   
    3175         reinterpret_cast<void**>(stubInfo.hotPathBegin)[-1] = callee;
    3176         ctiRepatchCallByReturnAddress(stubInfo.hotPathOther, ctiCode);
     3178        reinterpret_cast<void**>(callLinkInfo->hotPathBegin)[-1] = callee;
     3179        ctiRepatchCallByReturnAddress(callLinkInfo->hotPathOther, ctiCode);
    31773180    }
    31783181
    31793182    // repatch the instruction that jumps out to the cold path, so that we only try to link once.
    3180     void* repatchCheck = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(stubInfo.hotPathBegin) + repatchOffsetOpCallCall);
    3181     ctiRepatchCallByReturnAddress(repatchCheck, stubInfo.coldPathOther);
     3183    void* repatchCheck = reinterpret_cast<void*>(reinterpret_cast<ptrdiff_t>(callLinkInfo->hotPathBegin) + repatchOffsetOpCallCall);
     3184    ctiRepatchCallByReturnAddress(repatchCheck, callLinkInfo->coldPathOther);
    31823185}
    31833186
Note: See TracChangeset for help on using the changeset viewer.