Ignore:
Timestamp:
Sep 6, 2011, 2:23:55 AM (14 years ago)
Author:
[email protected]
Message:

JavaScriptCore does not have tiered compilation
https://bugs.webkit.org/show_bug.cgi?id=67176

Reviewed by Gavin Barraclough.

This adds the ability to have multiple CodeBlocks associated with
a particular role in an Executable. These are stored in
descending order of compiler tier. CodeBlocks are optimized when
a counter (m_executeCounter) that is incremented in loops and
epilogues becomes positive. Optimizing means that all calls to
the old CodeBlock are unlinked.

The DFG can now pull in predictions from ValueProfiles, and
propagate them along the graph. To support the new phase while
maintaing some level of abstraction, a DFGDriver was introduced
that encapsulates how to run the DFG compiler.

This is turned off by default because it's not yet a performance
win on all benchmarks. It speeds up crypto and richards by
10% and 6% respectively, but still does not do as good of a job
as it could. Notably, the DFG backend has not changed, and
is largely oblivious to the new information being made available
to it.

When turned off (the default), this patch is performance neutral.

  • CMakeLists.txt:
  • GNUmakefile.am:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops:
  • JavaScriptCore.vcproj/JavaScriptCore/copy-files.cmd:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • assembler/MacroAssemblerX86.h:

(JSC::MacroAssemblerX86::branchAdd32):

  • assembler/MacroAssemblerX86_64.h:

(JSC::MacroAssemblerX86_64::branchAdd32):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::visitAggregate):
(JSC::CallLinkInfo::unlink):
(JSC::CodeBlock::unlinkCalls):
(JSC::CodeBlock::unlinkIncomingCalls):
(JSC::CodeBlock::clearEvalCache):
(JSC::replaceExistingEntries):
(JSC::CodeBlock::copyDataFromAlternative):
(JSC::ProgramCodeBlock::replacement):
(JSC::EvalCodeBlock::replacement):
(JSC::FunctionCodeBlock::replacement):
(JSC::ProgramCodeBlock::compileOptimized):
(JSC::EvalCodeBlock::compileOptimized):
(JSC::FunctionCodeBlock::compileOptimized):

  • bytecode/CodeBlock.h:

(JSC::GlobalCodeBlock::GlobalCodeBlock):
(JSC::ProgramCodeBlock::ProgramCodeBlock):
(JSC::EvalCodeBlock::EvalCodeBlock):
(JSC::FunctionCodeBlock::FunctionCodeBlock):

  • bytecode/ValueProfile.h:

(JSC::ValueProfile::dump):
(JSC::ValueProfile::computeStatistics):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::BytecodeGenerator):

  • bytecompiler/BytecodeGenerator.h:
  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::ByteCodeParser):
(JSC::DFG::ByteCodeParser::addCall):
(JSC::DFG::ByteCodeParser::dynamicallyPredict):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::parse):

  • dfg/DFGDriver.cpp: Added.

(JSC::DFG::compile):
(JSC::DFG::tryCompile):
(JSC::DFG::tryCompileFunction):

  • dfg/DFGDriver.h: Added.

(JSC::DFG::tryCompile):
(JSC::DFG::tryCompileFunction):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dump):
(JSC::DFG::Graph::predictArgumentTypes):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::predict):
(JSC::DFG::Graph::predictGlobalVar):
(JSC::DFG::Graph::isConstant):
(JSC::DFG::Graph::isJSConstant):
(JSC::DFG::Graph::isInt32Constant):
(JSC::DFG::Graph::isDoubleConstant):
(JSC::DFG::Graph::valueOfJSConstant):
(JSC::DFG::Graph::valueOfInt32Constant):
(JSC::DFG::Graph::valueOfDoubleConstant):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::link):

  • dfg/DFGJITCompiler.h:

(JSC::DFG::JITCompiler::isConstant):
(JSC::DFG::JITCompiler::isJSConstant):
(JSC::DFG::JITCompiler::isInt32Constant):
(JSC::DFG::JITCompiler::isDoubleConstant):
(JSC::DFG::JITCompiler::valueOfJSConstant):
(JSC::DFG::JITCompiler::valueOfInt32Constant):
(JSC::DFG::JITCompiler::valueOfDoubleConstant):

  • dfg/DFGNode.h:

(JSC::DFG::isCellPrediction):
(JSC::DFG::isNumberPrediction):
(JSC::DFG::predictionToString):
(JSC::DFG::mergePrediction):
(JSC::DFG::makePrediction):
(JSC::DFG::Node::valueOfJSConstant):
(JSC::DFG::Node::isInt32Constant):
(JSC::DFG::Node::isDoubleConstant):
(JSC::DFG::Node::valueOfInt32Constant):
(JSC::DFG::Node::valueOfDoubleConstant):
(JSC::DFG::Node::predict):

  • dfg/DFGPropagation.cpp: Added.

(JSC::DFG::Propagator::Propagator):
(JSC::DFG::Propagator::fixpoint):
(JSC::DFG::Propagator::setPrediction):
(JSC::DFG::Propagator::mergePrediction):
(JSC::DFG::Propagator::propagateNode):
(JSC::DFG::Propagator::propagateForward):
(JSC::DFG::Propagator::propagateBackward):
(JSC::DFG::propagate):

  • dfg/DFGPropagation.h: Added.

(JSC::DFG::propagate):

  • dfg/DFGRepatch.cpp:

(JSC::DFG::dfgLinkFor):

  • heap/HandleHeap.h:

(JSC::HandleHeap::Node::Node):

  • jit/JIT.cpp:

(JSC::JIT::emitOptimizationCheck):
(JSC::JIT::emitTimeoutCheck):
(JSC::JIT::privateCompile):
(JSC::JIT::linkFor):

  • jit/JIT.h:

(JSC::JIT::emitOptimizationCheck):

  • jit/JITCall32_64.cpp:

(JSC::JIT::emit_op_ret):
(JSC::JIT::emit_op_ret_object_or_this):

  • jit/JITCode.h:

(JSC::JITCode::JITCode):
(JSC::JITCode::bottomTierJIT):
(JSC::JITCode::topTierJIT):
(JSC::JITCode::nextTierJIT):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_ret):
(JSC::JIT::emit_op_ret_object_or_this):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jit/JITStubs.h:
  • runtime/Executable.cpp:

(JSC::EvalExecutable::compileOptimized):
(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileOptimized):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::compileOptimizedForCall):
(JSC::FunctionExecutable::compileOptimizedForConstruct):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):

  • runtime/Executable.h:

(JSC::EvalExecutable::compile):
(JSC::ProgramExecutable::compile):
(JSC::FunctionExecutable::compileForCall):
(JSC::FunctionExecutable::compileForConstruct):
(JSC::FunctionExecutable::compileOptimizedFor):

  • wtf/Platform.h:
  • wtf/SentinelLinkedList.h:

(WTF::BasicRawSentinelNode::BasicRawSentinelNode):
(WTF::BasicRawSentinelNode::setPrev):
(WTF::BasicRawSentinelNode::setNext):
(WTF::BasicRawSentinelNode::prev):
(WTF::BasicRawSentinelNode::next):
(WTF::BasicRawSentinelNode::isOnList):
(WTF::::remove):
(WTF::::SentinelLinkedList):
(WTF::::begin):
(WTF::::end):
(WTF::::push):

File:
1 edited

Legend:

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

    r94477 r94559  
    14021402}
    14031403
    1404 CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject *globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab, bool isConstructor)
     1404CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlobalObject *globalObject, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab, bool isConstructor, PassOwnPtr<CodeBlock> alternative)
    14051405    : m_globalObject(globalObject->globalData(), ownerExecutable, globalObject)
    14061406    , m_heap(&m_globalObject->globalData().heap)
     1407    , m_executeCounter(-1000) // trigger optimization when sign bit clears
    14071408    , m_numCalleeRegisters(0)
    14081409    , m_numVars(0)
     
    14231424    , m_sourceOffset(sourceOffset)
    14241425    , m_symbolTable(symTab)
     1426    , m_alternative(alternative)
    14251427{
    14261428    ASSERT(m_source);
     
    14421444        } else
    14431445            fprintf(stderr, "   bc = %d: ", profile->bytecodeOffset);
    1444         fprintf(stderr,
    1445                 "samples = %u, int32 = %u, double = %u, cell = %u, array = %u\n",
    1446                 profile->numberOfSamples(),
    1447                 profile->probabilityOfInt32(),
    1448                 profile->probabilityOfDouble(),
    1449                 profile->probabilityOfCell(),
    1450                 profile->probabilityOfArray());
    1451     }
    1452 #endif
     1446        profile->dump(stderr);
     1447        fprintf(stderr, "\n");
     1448    }
     1449#endif
     1450   
     1451    // We should not be garbage collected if there are incoming calls. But
     1452    // if this is called during heap destruction, then there may still be
     1453    // incoming calls, which is harmless.
     1454   
     1455    // Note that our outgoing calls will be removed from other CodeBlocks'
     1456    // m_incomingCalls linked lists through the execution of the ~CallLinkInfo
     1457    // destructors.
    14531458
    14541459#if ENABLE(JIT)
     
    15201525    bool handleWeakReferences = false;
    15211526   
     1527    if (!!m_alternative)
     1528        m_alternative->visitAggregate(visitor);
    15221529    visitor.append(&m_globalObject);
    15231530    visitor.append(&m_ownerExecutable);
     
    17901797   
    17911798#if ENABLE(JIT)
     1799void CallLinkInfo::unlink(JSGlobalData& globalData, RepatchBuffer& repatchBuffer)
     1800{
     1801    ASSERT(isLinked());
     1802   
     1803    if (isDFG) {
     1804#if ENABLE(DFG_JIT)
     1805        repatchBuffer.relink(CodeLocationCall(callReturnLocation), isCall ? operationLinkCall : operationLinkConstruct);
     1806#else
     1807        ASSERT_NOT_REACHED();
     1808#endif
     1809    } else
     1810        repatchBuffer.relink(CodeLocationNearCall(callReturnLocation), isCall? globalData.jitStubs->ctiVirtualCallLink() : globalData.jitStubs->ctiVirtualConstructLink());
     1811    hasSeenShouldRepatch = false;
     1812    callee.clear();
     1813
     1814    // It will be on a list if the callee has a code block.
     1815    if (isOnList())
     1816        remove();
     1817}
     1818
    17921819void CodeBlock::unlinkCalls()
    17931820{
     1821    if (!!m_alternative)
     1822        m_alternative->unlinkCalls();
    17941823    if (!(m_callLinkInfos.size() || m_methodCallLinkInfos.size()))
    17951824        return;
     
    18001829        if (!m_callLinkInfos[i].isLinked())
    18011830            continue;
    1802         if (getJITCode().jitType() == JITCode::DFGJIT) {
    1803 #if ENABLE(DFG_JIT)
    1804             repatchBuffer.relink(CodeLocationCall(m_callLinkInfos[i].callReturnLocation), m_callLinkInfos[i].isCall ? operationLinkCall : operationLinkConstruct);
    1805 #else
    1806             ASSERT_NOT_REACHED();
    1807 #endif
    1808         } else
    1809             repatchBuffer.relink(CodeLocationNearCall(m_callLinkInfos[i].callReturnLocation), m_callLinkInfos[i].isCall ? m_globalData->jitStubs->ctiVirtualCallLink() : m_globalData->jitStubs->ctiVirtualConstructLink());
    1810         m_callLinkInfos[i].unlink();
    1811     }
     1831        m_callLinkInfos[i].unlink(*m_globalData, repatchBuffer);
     1832    }
     1833}
     1834
     1835void CodeBlock::unlinkIncomingCalls()
     1836{
     1837    RepatchBuffer repatchBuffer(this);
     1838    while (m_incomingCalls.begin() != m_incomingCalls.end())
     1839        m_incomingCalls.begin()->unlink(*m_globalData, repatchBuffer);
    18121840}
    18131841#endif
     
    18151843void CodeBlock::clearEvalCache()
    18161844{
     1845    if (!!m_alternative)
     1846        m_alternative->clearEvalCache();
    18171847    if (!m_rareData)
    18181848        return;
     
    18201850}
    18211851
     1852template<typename T>
     1853inline void replaceExistingEntries(Vector<T>& target, Vector<T>& source)
     1854{
     1855    ASSERT(target.size() <= source.size());
     1856    for (size_t i = 0; i < target.size(); ++i)
     1857        target[i] = source[i];
     1858}
     1859
     1860void CodeBlock::copyDataFromAlternative()
     1861{
     1862    if (!m_alternative)
     1863        return;
     1864   
     1865    replaceExistingEntries(m_constantRegisters, m_alternative->m_constantRegisters);
     1866    replaceExistingEntries(m_functionDecls, m_alternative->m_functionDecls);
     1867    replaceExistingEntries(m_functionExprs, m_alternative->m_functionExprs);
     1868}
     1869
     1870// FIXME: Implement OSR. If compileOptimized() is called from somewhere other than the
     1871// epilogue, do OSR from the old code block to the new one.
     1872
     1873// FIXME: After doing successful optimized compilation, reset the profiling counter to -1, so
     1874// that the next execution of the old code block will jump straight into compileOptimized()
     1875// and perform OSR.
     1876
     1877// FIXME: Ensure that a call to compileOptimized() just does OSR (and resets the counter to -1)
     1878// if the code had already been compiled.
     1879
     1880CodeBlock* ProgramCodeBlock::replacement()
     1881{
     1882    return &static_cast<ProgramExecutable*>(ownerExecutable())->generatedBytecode();
     1883}
     1884
     1885CodeBlock* EvalCodeBlock::replacement()
     1886{
     1887    return &static_cast<EvalExecutable*>(ownerExecutable())->generatedBytecode();
     1888}
     1889
     1890CodeBlock* FunctionCodeBlock::replacement()
     1891{
     1892    return &static_cast<FunctionExecutable*>(ownerExecutable())->generatedBytecodeFor(m_isConstructor ? CodeForConstruct : CodeForCall);
     1893}
     1894
     1895JSObject* ProgramCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
     1896{
     1897    if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType())) {
     1898        // No OSR yet, so make sure we don't hit this again anytime soon.
     1899        dontOptimizeAnytimeSoon();
     1900        return 0;
     1901    }
     1902    JSObject* error = static_cast<ProgramExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode);
     1903    return error;
     1904}
     1905
     1906JSObject* EvalCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
     1907{
     1908    if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType())) {
     1909        // No OSR yet, so make sure we don't hit this again anytime soon.
     1910        dontOptimizeAnytimeSoon();
     1911        return 0;
     1912    }
     1913    JSObject* error = static_cast<EvalExecutable*>(ownerExecutable())->compileOptimized(exec, scopeChainNode);
     1914    return error;
     1915}
     1916
     1917JSObject* FunctionCodeBlock::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
     1918{
     1919    if (replacement()->getJITType() == JITCode::nextTierJIT(getJITType())) {
     1920        // No OSR yet, so make sure we don't hit this again anytime soon.
     1921        dontOptimizeAnytimeSoon();
     1922        return 0;
     1923    }
     1924    JSObject* error = static_cast<FunctionExecutable*>(ownerExecutable())->compileOptimizedFor(exec, scopeChainNode, m_isConstructor ? CodeForConstruct : CodeForCall);
     1925    return error;
     1926}
     1927
    18221928} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.