Ignore:
Timestamp:
Jan 29, 2015, 12:33:45 PM (10 years ago)
Author:
[email protected]
Message:

Polymorphic call inlining should be based on polymorphic call inline caching rather than logging
https://bugs.webkit.org/show_bug.cgi?id=140660

Reviewed by Geoffrey Garen.

When we first implemented polymorphic call inlining, we did the profiling based on a call
edge log. The idea was to store each call edge (a tuple of call site and callee) into a
global log that was processed lazily. Processing the log would give precise counts of call
edges, and could be used to drive well-informed inlining decisions - polymorphic or not.
This was a speed-up on throughput tests but a slow-down for latency tests. It was a net win
nonetheless.

Experience with this code shows three things. First, the call edge profiler is buggy and
complex. It would take work to fix the bugs. Second, the call edge profiler incurs lots of
overhead for latency code that we care deeply about. Third, it's not at all clear that
having call edge counts for every possible callee is any better than just having call edge
counts for the limited number of callees that an inline cache would catch.

So, this patch removes the call edge profiler and replaces it with a polymorphic call inline
cache. If we miss the basic call inline cache, we inflate the cache to be a jump to an
out-of-line stub that cases on the previously known callees. If that misses again, then we
rewrite that stub to include the new callee. We do this up to some number of callees. If we
hit the limit then we switch to using a plain virtual call.

Substantial speed-up on V8Spider; undoes the slow-down that the original call edge profiler
caused. Might be a SunSpider speed-up (below 1%), depending on hardware.

(JSC::CallEdge::count):
(JSC::CallEdge::CallEdge):

  • bytecode/CallEdgeProfile.cpp: Removed.
  • bytecode/CallEdgeProfile.h: Removed.
  • bytecode/CallEdgeProfileInlines.h: Removed.
  • bytecode/CallLinkInfo.cpp:

(JSC::CallLinkInfo::unlink):
(JSC::CallLinkInfo::visitWeak):

  • bytecode/CallLinkInfo.h:
  • bytecode/CallLinkStatus.cpp:

(JSC::CallLinkStatus::CallLinkStatus):
(JSC::CallLinkStatus::computeFor):
(JSC::CallLinkStatus::computeFromCallLinkInfo):
(JSC::CallLinkStatus::isClosureCall):
(JSC::CallLinkStatus::makeClosureCall):
(JSC::CallLinkStatus::dump):
(JSC::CallLinkStatus::computeFromCallEdgeProfile): Deleted.

  • bytecode/CallLinkStatus.h:

(JSC::CallLinkStatus::CallLinkStatus):
(JSC::CallLinkStatus::isSet):
(JSC::CallLinkStatus::variants):
(JSC::CallLinkStatus::size):
(JSC::CallLinkStatus::at):
(JSC::CallLinkStatus::operator[]):
(JSC::CallLinkStatus::canOptimize):
(JSC::CallLinkStatus::edges): Deleted.
(JSC::CallLinkStatus::canTrustCounts): Deleted.

  • bytecode/CallVariant.cpp:

(JSC::variantListWithVariant):
(JSC::despecifiedVariantList):

  • bytecode/CallVariant.h:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::linkIncomingPolymorphicCall):
(JSC::CodeBlock::unlinkIncomingCalls):
(JSC::CodeBlock::noticeIncomingCall):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::isIncomingCallAlreadyLinked): Deleted.

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::addCallWithoutSettingResult):
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::handleInlining):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGDriver.cpp:

(JSC::DFG::compileImpl):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::emitCall):
(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGTierUpCheckInjectionPhase.cpp:

(JSC::DFG::TierUpCheckInjectionPhase::run):
(JSC::DFG::TierUpCheckInjectionPhase::removeFTLProfiling): Deleted.

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • heap/Heap.cpp:

(JSC::Heap::collect):

  • jit/BinarySwitch.h:
  • jit/ClosureCallStubRoutine.cpp: Removed.
  • jit/ClosureCallStubRoutine.h: Removed.
  • jit/JITCall.cpp:

(JSC::JIT::compileOpCall):

  • jit/JITCall32_64.cpp:

(JSC::JIT::compileOpCall):

  • jit/JITOperations.cpp:
  • jit/JITOperations.h:

(JSC::operationLinkPolymorphicCallFor):
(JSC::operationLinkClosureCallFor): Deleted.

  • jit/JITStubRoutine.h:
  • jit/JITWriteBarrier.h:
  • jit/PolymorphicCallStubRoutine.cpp: Added.

(JSC::PolymorphicCallNode::~PolymorphicCallNode):
(JSC::PolymorphicCallNode::unlink):
(JSC::PolymorphicCallCase::dump):
(JSC::PolymorphicCallStubRoutine::PolymorphicCallStubRoutine):
(JSC::PolymorphicCallStubRoutine::~PolymorphicCallStubRoutine):
(JSC::PolymorphicCallStubRoutine::variants):
(JSC::PolymorphicCallStubRoutine::edges):
(JSC::PolymorphicCallStubRoutine::visitWeak):
(JSC::PolymorphicCallStubRoutine::markRequiredObjectsInternal):

  • jit/PolymorphicCallStubRoutine.h: Added.

(JSC::PolymorphicCallNode::PolymorphicCallNode):
(JSC::PolymorphicCallCase::PolymorphicCallCase):
(JSC::PolymorphicCallCase::variant):
(JSC::PolymorphicCallCase::codeBlock):

  • jit/Repatch.cpp:

(JSC::linkSlowFor):
(JSC::linkFor):
(JSC::revertCall):
(JSC::unlinkFor):
(JSC::linkVirtualFor):
(JSC::linkPolymorphicCall):
(JSC::linkClosureCall): Deleted.

  • jit/Repatch.h:
  • jit/ThunkGenerators.cpp:

(JSC::linkPolymorphicCallForThunkGenerator):
(JSC::linkPolymorphicCallThunkGenerator):
(JSC::linkPolymorphicCallThatPreservesRegsThunkGenerator):
(JSC::linkClosureCallForThunkGenerator): Deleted.
(JSC::linkClosureCallThunkGenerator): Deleted.
(JSC::linkClosureCallThatPreservesRegsThunkGenerator): Deleted.

  • jit/ThunkGenerators.h:

(JSC::linkPolymorphicCallThunkGeneratorFor):
(JSC::linkClosureCallThunkGeneratorFor): Deleted.

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::jitCompileAndSetHeuristics):

  • runtime/Options.h:
  • runtime/VM.cpp:

(JSC::VM::prepareToDiscardCode):
(JSC::VM::ensureCallEdgeLog): Deleted.

  • runtime/VM.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r179015 r179357  
    11/*
    2  * Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2008-2010, 2012-2015 Apple Inc. All rights reserved.
    33 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
    44 *
     
    21822182    while (m_incomingCalls.begin() != m_incomingCalls.end())
    21832183        m_incomingCalls.begin()->remove();
     2184    while (m_incomingPolymorphicCalls.begin() != m_incomingPolymorphicCalls.end())
     2185        m_incomingPolymorphicCalls.begin()->remove();
    21842186   
    21852187    // Note that our outgoing calls will be removed from other CodeBlocks'
     
    30483050    m_incomingCalls.push(incoming);
    30493051}
     3052
     3053void CodeBlock::linkIncomingPolymorphicCall(ExecState* callerFrame, PolymorphicCallNode* incoming)
     3054{
     3055    noticeIncomingCall(callerFrame);
     3056    m_incomingPolymorphicCalls.push(incoming);
     3057}
    30503058#endif // ENABLE(JIT)
    30513059
     
    30553063        m_incomingLLIntCalls.begin()->unlink();
    30563064#if ENABLE(JIT)
    3057     if (m_incomingCalls.isEmpty())
     3065    if (m_incomingCalls.isEmpty() && m_incomingPolymorphicCalls.isEmpty())
    30583066        return;
    30593067    RepatchBuffer repatchBuffer(this);
    30603068    while (m_incomingCalls.begin() != m_incomingCalls.end())
    30613069        m_incomingCalls.begin()->unlink(repatchBuffer);
     3070    while (m_incomingPolymorphicCalls.begin() != m_incomingPolymorphicCalls.end())
     3071        m_incomingPolymorphicCalls.begin()->unlink(repatchBuffer);
    30623072#endif // ENABLE(JIT)
    30633073}
     
    32533263   
    32543264    if (Options::verboseCallLink())
    3255         dataLog("Noticing call link from ", *callerCodeBlock, " to ", *this, "\n");
    3256    
     3265        dataLog("Noticing call link from ", pointerDump(callerCodeBlock), " to ", *this, "\n");
     3266   
     3267#if ENABLE(DFG_JIT)
    32573268    if (!m_shouldAlwaysBeInlined)
    32583269        return;
    3259 
    3260 #if ENABLE(DFG_JIT)
     3270   
     3271    if (!callerCodeBlock) {
     3272        m_shouldAlwaysBeInlined = false;
     3273        if (Options::verboseCallLink())
     3274            dataLog("    Clearing SABI because caller is native.\n");
     3275        return;
     3276    }
     3277
    32613278    if (!hasBaselineJITProfiling())
    32623279        return;
     
    32863303    }
    32873304   
     3305    if (JITCode::isOptimizingJIT(callerCodeBlock->jitType())) {
     3306        m_shouldAlwaysBeInlined = false;
     3307        if (Options::verboseCallLink())
     3308            dataLog("    Clearing SABI bcause caller was already optimized.\n");
     3309        return;
     3310    }
     3311   
    32883312    if (callerCodeBlock->codeType() != FunctionCode) {
    32893313        // If the caller is either eval or global code, assume that that won't be
     
    33063330        return;
    33073331    }
    3308 
    3309     RELEASE_ASSERT(callerCodeBlock->m_capabilityLevelState != DFG::CapabilityLevelNotSet);
     3332   
     3333    if (callerCodeBlock->m_capabilityLevelState == DFG::CapabilityLevelNotSet) {
     3334        dataLog("In call from ", *callerCodeBlock, " ", callerFrame->codeOrigin(), " to ", *this, ": caller's DFG capability level is not set.\n");
     3335        CRASH();
     3336    }
    33103337   
    33113338    if (canCompile(callerCodeBlock->m_capabilityLevelState))
Note: See TracChangeset for help on using the changeset viewer.