Changeset 37670 in webkit for trunk/JavaScriptCore/VM/Machine.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/Machine.cpp

    r37651 r37670  
    45454545}
    45464546
     4547void Machine::cti_op_call_profiler(CTI_ARGS)
     4548{
     4549    ASSERT(*ARG_profilerReference);
     4550    (*ARG_profilerReference)->willExecute(ARG_callFrame, static_cast<JSFunction*>(ARG_src1));
     4551}
     4552
    45474553VoidPtrPair Machine::cti_op_call_JSFunction(CTI_ARGS)
    45484554{
     
    45514557    ASSERT(ARG_src1->getCallData(callData) == CallTypeJS);
    45524558#endif
    4553 
    4554     if (UNLIKELY(*ARG_profilerReference != 0))
    4555         (*ARG_profilerReference)->willExecute(ARG_callFrame, static_cast<JSFunction*>(ARG_src1));
    45564559
    45574560    ScopeChainNode* callDataScopeChain = static_cast<JSFunction*>(ARG_src1)->m_scopeChain.node();
     
    45924595    VoidPtrPair pair = { newCodeBlock, CallFrame::create(r) };
    45934596    return pair;
     4597}
     4598
     4599void* Machine::cti_vm_lazyLinkCall(CTI_ARGS)
     4600{
     4601    Machine* machine = ARG_globalData->machine;
     4602    CallFrame* callFrame = CallFrame::create(ARG_callFrame);
     4603    CallFrame* callerCallFrame = callFrame->callerFrame();
     4604    CodeBlock* callerCodeBlock = callerCallFrame->codeBlock();
     4605
     4606    JSFunction* callee = static_cast<JSFunction*>(ARG_src1);
     4607    CodeBlock* codeBlock = &callee->m_body->byteCode(callee->m_scopeChain.node());
     4608    if (!codeBlock->ctiCode)
     4609        CTI::compile(machine, callFrame, codeBlock);
     4610
     4611    int argCount = ARG_int3;
     4612    CTI::linkCall(callerCodeBlock, callee, codeBlock, codeBlock->ctiCode, CTI_RETURN_ADDRESS, argCount);
     4613
     4614    return codeBlock->ctiCode;
    45944615}
    45954616
     
    47164737}
    47174738
    4718 VoidPtrPair Machine::cti_op_construct_JSConstruct(CTI_ARGS)
    4719 {
    4720     CallFrame* callFrame = ARG_callFrame;
    4721 
    4722     JSFunction* constructor = static_cast<JSFunction*>(ARG_src1);
    4723     JSValue* constrProtoVal = ARG_src2;
    4724     int firstArg = ARG_int3;
    4725     int registerOffset = ARG_int4;
    4726     int argCount = ARG_int5;
    4727 
     4739JSValue* Machine::cti_op_construct_JSConstructFast(CTI_ARGS)
     4740{
    47284741#ifndef NDEBUG
    47294742    ConstructData constructData;
    4730     ASSERT(ARG_src1->getConstructData(constructData) == ConstructTypeJS);
     4743    ASSERT(static_cast<JSFunction*>(ARG_src1)->getConstructData(constructData) == ConstructTypeJS);
    47314744#endif
    47324745
    4733     if (*ARG_profilerReference)
    4734         (*ARG_profilerReference)->willExecute(callFrame, constructor);
     4746    StructureID* structure;
     4747    if (ARG_src2->isObject())
     4748        structure = static_cast<JSObject*>(ARG_src2)->inheritorID();
     4749    else
     4750        structure = static_cast<JSFunction*>(ARG_src1)->m_scopeChain.node()->globalObject()->emptyObjectStructure();
     4751    return new (ARG_globalData) JSObject(structure);
     4752}
     4753
     4754VoidPtrPair Machine::cti_op_construct_JSConstruct(CTI_ARGS)
     4755{
     4756    CallFrame* callFrame = ARG_callFrame;
     4757
     4758    JSFunction* constructor = static_cast<JSFunction*>(ARG_src1);
     4759    int registerOffset = ARG_int2;
     4760    int argCount = ARG_int3;
     4761    JSValue* constrProtoVal = ARG_src5;
     4762    int firstArg = ARG_int6;
     4763
     4764#ifndef NDEBUG
     4765    ConstructData constructData;
     4766    ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
     4767#endif
    47354768
    47364769    ScopeChainNode* callDataScopeChain = constructor->m_scopeChain.node();
     
    47844817
    47854818    JSValue* constrVal = ARG_src1;
    4786     int firstArg = ARG_int3;
    4787     int argCount = ARG_int5;
     4819    int argCount = ARG_int3;
     4820    int firstArg = ARG_int6;
    47884821
    47894822    ConstructData constructData;
     
    48114844    ASSERT(constructType == ConstructTypeNone);
    48124845
    4813     ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr6, callFrame->codeBlock());
     4846    ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr4, callFrame->codeBlock());
    48144847    VM_THROW_EXCEPTION();
    48154848}
Note: See TracChangeset for help on using the changeset viewer.