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/CodeBlock.cpp

    r37366 r37670  
    3131#include "CodeBlock.h"
    3232
     33#include "CTI.h"
    3334#include "JSValue.h"
    3435#include "Machine.h"
     
    932933        if (structureIDInstructions[i].stubRoutine)
    933934            fastFree(structureIDInstructions[i].stubRoutine);
    934     }
    935 #if ENABLE(CTI)
     935        if (CallLinkInfo* callLinkInfo = structureIDInstructions[i].linkInfoPtr) {
     936            callLinkInfo->callee->removeCaller(callLinkInfo);
     937            delete callLinkInfo;
     938        }
     939    }
     940
     941#if ENABLE(CTI)
     942    unlinkCallers();
     943
    936944    if (ctiCode)
    937945        fastFree(ctiCode);
    938946#endif
    939947}
     948
     949#if ENABLE(CTI)
     950void CodeBlock::unlinkCallers()
     951{
     952    size_t size = linkedCallerList.size();
     953    for (size_t i = 0; i < size; ++i) {
     954        CallLinkInfo* currentCaller = linkedCallerList[i];
     955        CTI::unlinkCall(currentCaller->callerStructureStubInfo);
     956        currentCaller->callerStructureStubInfo->linkInfoPtr = 0;
     957        delete currentCaller;
     958    }
     959    linkedCallerList.clear();
     960}
     961#endif
    940962
    941963void CodeBlock::derefStructureIDs(Instruction* vPC) const
     
    974996   
    975997    // These instructions don't ref their StructureIDs.
    976     ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_get_array_length) || vPC[0].u.opcode == machine->getOpcode(op_get_string_length));
     998    ASSERT(vPC[0].u.opcode == machine->getOpcode(op_get_by_id) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id) || vPC[0].u.opcode == machine->getOpcode(op_get_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_put_by_id_generic) || vPC[0].u.opcode == machine->getOpcode(op_get_array_length) || vPC[0].u.opcode == machine->getOpcode(op_get_string_length)
     999        || vPC[0].u.opcode == machine->getOpcode(op_call_eval) || vPC[0].u.opcode == machine->getOpcode(op_call) || vPC[0].u.opcode == machine->getOpcode(op_construct));
    9771000}
    9781001
Note: See TracChangeset for help on using the changeset viewer.