⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 254480 in webkit


Ignore:
Timestamp:
Jan 13, 2020, 5:43:03 PM (7 years ago)
Author:
sbarati@apple.com
Message:

Throw away baseline code if there is an optimized replacement
​https://bugs.webkit.org/show_bug.cgi?id=202503

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/dfg-compare-eq-via-nonSpeculativeNonPeepholeCompareNullOrUndefined.js:
  • stress/getter-setter-inlining-should-emit-movhint.js:
  • stress/make-dictionary-repatch.js:
  • stress/merging-ic-variants-should-bail-if-structures-overlap.js:
  • stress/proxy-getter-stack-overflow.js:
  • stress/regress-192717.js:
  • stress/retry-cache-later.js:

Source/JavaScriptCore:

This patch's goal is to help us save JIT executable memory by throwing
away baseline code when it has an optimized replacement. To make it
easy to reason about, we do this when finalizing a GC, and when the
CodeBlock is not on the stack. When we do this, we throw away all JIT
data and unlink all incoming calls.

This patch also paves the way for the LOL tier by making it so we always
exit to the LLInt. This allows the code in CodeBlock finalization to not
have to consider whether or not an an OSR exit is wired to baseline
JIT code, since all exits are now to the LLInt. Because of this, this
patch removes the forceOSRExitToLLInt option. Also, this patch renames
the useLLInt option to forceBaseline and inverts its meaning.
Options::forceBaseline=true implies that code will start off executing in
the baseline JIT instead of the LLInt. However, it won't prevent us from
emitting an OSR exit which jumps to LLInt code.

  • API/tests/ExecutionTimeLimitTest.cpp:

(testExecutionTimeLimit):

  • API/tests/PingPongStackOverflowTest.cpp:

(testPingPongStackOverflow):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::finishCreation):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::resetJITData):
(JSC::CodeBlock::optimizedReplacement):
(JSC::CodeBlock::hasOptimizedReplacement):
(JSC::CodeBlock::tallyFrequentExitSites):
(JSC::CodeBlock::findStubInfo): Deleted.
(JSC::CodeBlock::getCallLinkInfoForBytecodeIndex): Deleted.

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::setJITCode):

  • dfg/DFGDriver.cpp:

(JSC::DFG::compileImpl):

  • dfg/DFGOSRExitCompilerCommon.cpp:

(JSC::DFG::callerReturnPC):
(JSC::DFG::reifyInlinedCallFrames):
(JSC::DFG::adjustAndJumpToTarget):

  • dfg/DFGOSRExitCompilerCommon.h:
  • heap/CodeBlockSet.cpp:

(JSC::CodeBlockSet::isCurrentlyExecuting):

  • heap/CodeBlockSet.h:
  • heap/Heap.cpp:

(JSC::Heap::finalizeUnconditionalFinalizers):
(JSC::Heap::runEndPhase):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::dispatchToNextInstruction):

  • runtime/Options.cpp:

(JSC::recomputeDependentOptions):
(JSC::Options::initialize):
(JSC::Options::ensureOptionsAreCoherent):

  • runtime/OptionsList.h:
  • runtime/ScriptExecutable.cpp:

(JSC::ScriptExecutable::prepareForExecutionImpl):

Tools:

  • Scripts/run-jsc-stress-tests:
Location:
trunk
Files:
25 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r254464 r254480  
     12020-01-13  Saam Barati  <sbarati@apple.com>
     2
     3        Throw away baseline code if there is an optimized replacement
     4        https://bugs.webkit.org/show_bug.cgi?id=202503
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        * stress/dfg-compare-eq-via-nonSpeculativeNonPeepholeCompareNullOrUndefined.js:
     9        * stress/getter-setter-inlining-should-emit-movhint.js:
     10        * stress/make-dictionary-repatch.js:
     11        * stress/merging-ic-variants-should-bail-if-structures-overlap.js:
     12        * stress/proxy-getter-stack-overflow.js:
     13        * stress/regress-192717.js:
     14        * stress/retry-cache-later.js:
     15
    1162020-01-13  Mark Lam  <mark.lam@apple.com>
    217
  • trunk/JSTests/stress/dfg-compare-eq-via-nonSpeculativeNonPeepholeCompareNullOrUndefined.js

    r249075 r254480  
    1 //@ runDefault("--collectContinuously=true", "--collectContinuouslyPeriodMS=0.15", "--useLLInt=false", "--useFTLJIT=false", "--jitPolicyScale=0")
     1//@ runDefault("--collectContinuously=true", "--collectContinuouslyPeriodMS=0.15", "--forceBaseline=true", "--useFTLJIT=false", "--jitPolicyScale=0")
    22
    33// This test exercises DFG::SpeculativeJIT::nonSpeculativeNonPeepholeCompareNullOrUndefined().
  • trunk/JSTests/stress/getter-setter-inlining-should-emit-movhint.js

    r244864 r254480  
    1 //@ runDefault("--useRandomizingFuzzerAgent=1", "--usePolymorphicCallInliningForNonStubStatus=1", "--seedOfRandomizingFuzzerAgent=2896922505", "--useLLInt=0", "--useConcurrentJIT=0")
     1//@ runDefault("--useRandomizingFuzzerAgent=1", "--usePolymorphicCallInliningForNonStubStatus=1", "--seedOfRandomizingFuzzerAgent=2896922505", "--forceBaseline=1", "--useConcurrentJIT=0")
    22function foo(o) {
    33    o.f = 0;
  • trunk/JSTests/stress/make-dictionary-repatch.js

    r208692 r254480  
    1 //@ if $jitTests then runNoCJIT("--useDFGJIT=false", "--useLLInt=false") else skip end
     1//@ if $jitTests then runNoCJIT("--useDFGJIT=false", "--forceBaseline=true") else skip end
    22
    33function foo(o) {
  • trunk/JSTests/stress/merging-ic-variants-should-bail-if-structures-overlap.js

    r238411 r254480  
    1 //@ runDefault("--validateGraphAtEachPhase=1", "--useLLInt=0")
     1//@ runDefault("--validateGraphAtEachPhase=1", "--forceBaseline=1")
    22
    33let items = [];
  • trunk/JSTests/stress/proxy-getter-stack-overflow.js

    r244069 r254480  
    1 //@ if $jitTests then runDefault("--useLLInt=0") else skip end
     1//@ if $jitTests then runDefault("--forceBaseline=1") else skip end
    22
    33const o = {};
  • trunk/JSTests/stress/regress-192717.js

    r239867 r254480  
    11//@ skip if $memoryLimited or $buildType == "debug"
    2 //@ runDefault("--useLLInt=false", "--forceCodeBlockToJettisonDueToOldAge=true", "--maxPerThreadStackUsage=200000", "--exceptionStackTraceLimit=1", "--defaultErrorStackTraceLimit=1")
     2//@ runDefault("--forceBaseline=true", "--forceCodeBlockToJettisonDueToOldAge=true", "--maxPerThreadStackUsage=200000", "--exceptionStackTraceLimit=1", "--defaultErrorStackTraceLimit=1")
    33
    44let foo = 'let a';
  • trunk/JSTests/stress/retry-cache-later.js

    r208692 r254480  
    1 //@ runNoCJIT("--useLLInt=false", "--useDFGJIT=false")
     1//@ runNoCJIT("--forceBaseline=true", "--useDFGJIT=false")
    22
    33function foo(o) {
  • trunk/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp

    r253975 r254480  
    120120{
    121121    static const TierOptions tierOptionsList[] = {
    122         { "LLINT",    0_ms,   "--useConcurrentJIT=false --useLLInt=true --useJIT=false" },
    123         { "Baseline", 0_ms,   "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=false" },
    124         { "DFG",      200_ms,   "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=false" },
     122        { "LLINT",    0_ms,   "--useConcurrentJIT=false --useJIT=false" },
     123        { "Baseline", 0_ms,   "--useConcurrentJIT=false --useJIT=true --useDFGJIT=false" },
     124        { "DFG",      200_ms,   "--useConcurrentJIT=false --useJIT=true --useDFGJIT=true --useFTLJIT=false" },
    125125#if ENABLE(FTL_JIT)
    126         { "FTL",      500_ms, "--useConcurrentJIT=false --useLLInt=true --useJIT=true --useDFGJIT=true --useFTLJIT=true" },
     126        { "FTL",      500_ms, "--useConcurrentJIT=false --useJIT=true --useDFGJIT=true --useFTLJIT=true" },
    127127#endif
    128128    };
  • trunk/Source/JavaScriptCore/API/tests/PingPongStackOverflowTest.cpp

    r237919 r254480  
    123123    auto origSoftReservedZoneSize = Options::softReservedZoneSize();
    124124    auto origReservedZoneSize = Options::reservedZoneSize();
    125     auto origUseLLInt = Options::useLLInt();
     125    auto origForceBaseline = Options::forceBaseline();
    126126    auto origMaxPerThreadStackUsage = Options::maxPerThreadStackUsage();
    127127
    … …  
    132132    // reproducing the regression in https://bugs.webkit.org/show_bug.cgi?id=148749. However, we only
    133133    // want to do this if the LLINT isn't the only available execution engine.
    134     Options::useLLInt() = false;
     134    Options::forceBaseline() = true;
    135135#endif
    136136
    … …  
    179179    Options::softReservedZoneSize() = origSoftReservedZoneSize;
    180180    Options::reservedZoneSize() = origReservedZoneSize;
    181     Options::useLLInt() = origUseLLInt;
     181    Options::forceBaseline() = origForceBaseline;
    182182    Options::maxPerThreadStackUsage() = origMaxPerThreadStackUsage;
    183183
  • trunk/Source/JavaScriptCore/ChangeLog

    r254464 r254480  
     12020-01-13  Saam Barati  <sbarati@apple.com>
     2
     3        Throw away baseline code if there is an optimized replacement
     4        https://bugs.webkit.org/show_bug.cgi?id=202503
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        This patch's goal is to help us save JIT executable memory by throwing
     9        away baseline code when it has an optimized replacement. To make it
     10        easy to reason about, we do this when finalizing a GC, and when the
     11        CodeBlock is not on the stack. When we do this, we throw away all JIT
     12        data and unlink all incoming calls.
     13       
     14        This patch also paves the way for the LOL tier by making it so we always
     15        exit to the LLInt. This allows the code in CodeBlock finalization to not
     16        have to consider whether or not an an OSR exit is wired to baseline
     17        JIT code, since all exits are now to the LLInt. Because of this, this
     18        patch removes the forceOSRExitToLLInt option. Also, this patch renames
     19        the useLLInt option to forceBaseline and inverts its meaning.
     20        Options::forceBaseline=true implies that code will start off executing in
     21        the baseline JIT instead of the LLInt. However, it won't prevent us from
     22        emitting an OSR exit which jumps to LLInt code.
     23
     24        * API/tests/ExecutionTimeLimitTest.cpp:
     25        (testExecutionTimeLimit):
     26        * API/tests/PingPongStackOverflowTest.cpp:
     27        (testPingPongStackOverflow):
     28        * bytecode/CodeBlock.cpp:
     29        (JSC::CodeBlock::finishCreation):
     30        (JSC::CodeBlock::finalizeUnconditionally):
     31        (JSC::CodeBlock::resetJITData):
     32        (JSC::CodeBlock::optimizedReplacement):
     33        (JSC::CodeBlock::hasOptimizedReplacement):
     34        (JSC::CodeBlock::tallyFrequentExitSites):
     35        (JSC::CodeBlock::findStubInfo): Deleted.
     36        (JSC::CodeBlock::getCallLinkInfoForBytecodeIndex): Deleted.
     37        * bytecode/CodeBlock.h:
     38        (JSC::CodeBlock::setJITCode):
     39        * dfg/DFGDriver.cpp:
     40        (JSC::DFG::compileImpl):
     41        * dfg/DFGOSRExitCompilerCommon.cpp:
     42        (JSC::DFG::callerReturnPC):
     43        (JSC::DFG::reifyInlinedCallFrames):
     44        (JSC::DFG::adjustAndJumpToTarget):
     45        * dfg/DFGOSRExitCompilerCommon.h:
     46        * heap/CodeBlockSet.cpp:
     47        (JSC::CodeBlockSet::isCurrentlyExecuting):
     48        * heap/CodeBlockSet.h:
     49        * heap/Heap.cpp:
     50        (JSC::Heap::finalizeUnconditionalFinalizers):
     51        (JSC::Heap::runEndPhase):
     52        * llint/LLIntSlowPaths.cpp:
     53        (JSC::LLInt::dispatchToNextInstruction):
     54        * runtime/Options.cpp:
     55        (JSC::recomputeDependentOptions):
     56        (JSC::Options::initialize):
     57        (JSC::Options::ensureOptionsAreCoherent):
     58        * runtime/OptionsList.h:
     59        * runtime/ScriptExecutable.cpp:
     60        (JSC::ScriptExecutable::prepareForExecutionImpl):
     61
    1622020-01-13  Mark Lam  <mark.lam@apple.com>
    263
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r254464 r254480  
    443443                HandlerInfo& handler = m_rareData->m_exceptionHandlers[i];
    444444#if ENABLE(JIT)
    445                 auto instruction = instructions().at(unlinkedHandler.target);
    446                 MacroAssemblerCodePtr<BytecodePtrTag> codePtr;
    447                 if (instruction->isWide32())
    448                     codePtr = LLInt::getWide32CodePtr<BytecodePtrTag>(op_catch);
    449                 else if (instruction->isWide16())
    450                     codePtr = LLInt::getWide16CodePtr<BytecodePtrTag>(op_catch);
    451                 else
    452                     codePtr = LLInt::getCodePtr<BytecodePtrTag>(op_catch);
     445                auto& instruction = *instructions().at(unlinkedHandler.target).ptr();
     446                MacroAssemblerCodePtr<BytecodePtrTag> codePtr = LLInt::getCodePtr<BytecodePtrTag>(instruction);
    453447                handler.initialize(unlinkedHandler, CodeLocationLabel<ExceptionHandlerPtrTag>(codePtr.retagged<ExceptionHandlerPtrTag>()));
    454448#else
    … …  
    13891383
    13901384    updateAllPredictions();
     1385
     1386#if ENABLE(JIT)
     1387    // If BaselineJIT code is not executing, and an optimized replacement exists, we attempt
     1388    // to discard baseline JIT code and reinstall LLInt code to save JIT memory.
     1389    if (!Options::forceBaseline() && jitType() == JITType::BaselineJIT && !m_vm->heap.codeBlockSet().isCurrentlyExecuting(this)) {
     1390        if (CodeBlock* optimizedCodeBlock = optimizedReplacement()) {
     1391            if (!optimizedCodeBlock->m_osrExitCounter) {
     1392                m_jitCode = nullptr;
     1393                LLInt::setEntrypoint(this);
     1394                RELEASE_ASSERT(jitType() == JITType::InterpreterThunk);
     1395
     1396                for (size_t i = 0; i < m_unlinkedCode->numberOfExceptionHandlers(); i++) {
     1397                    const UnlinkedHandlerInfo& unlinkedHandler = m_unlinkedCode->exceptionHandler(i);
     1398                    HandlerInfo& handler = m_rareData->m_exceptionHandlers[i];
     1399                    auto& instruction = *instructions().at(unlinkedHandler.target).ptr();
     1400                    MacroAssemblerCodePtr<BytecodePtrTag> codePtr = LLInt::getCodePtr<BytecodePtrTag>(instruction);
     1401                    handler.initialize(unlinkedHandler, CodeLocationLabel<ExceptionHandlerPtrTag>(codePtr.retagged<ExceptionHandlerPtrTag>()));
     1402                }
     1403
     1404                unlinkIncomingCalls();
     1405
     1406                // It's safe to clear these out here because in finalizeUnconditionally all compiler threads
     1407                // are safepointed, meaning they're running either before or after bytecode parser, and bytecode
     1408                // parser is the only data structure pointing into the various *infos.
     1409                resetJITData();
     1410            }
     1411        }
     1412    }
     1413
     1414#endif
    13911415   
    13921416    if (JITCode::couldBeInterpreted(jitType()))
    … …  
    15161540}
    15171541
    1518 StructureStubInfo* CodeBlock::findStubInfo(CodeOrigin codeOrigin)
    1519 {
    1520     ConcurrentJSLocker locker(m_lock);
    1521     if (auto* jitData = m_jitData.get()) {
    1522         for (StructureStubInfo* stubInfo : jitData->m_stubInfos) {
    1523             if (stubInfo->codeOrigin == codeOrigin)
    1524                 return stubInfo;
    1525         }
    1526     }
    1527     return nullptr;
    1528 }
    1529 
    15301542ByValInfo* CodeBlock::addByValInfo()
    15311543{
    … …  
    15381550    ConcurrentJSLocker locker(m_lock);
    15391551    return ensureJITData(locker).m_callLinkInfos.add();
    1540 }
    1541 
    1542 CallLinkInfo* CodeBlock::getCallLinkInfoForBytecodeIndex(BytecodeIndex index)
    1543 {
    1544     ConcurrentJSLocker locker(m_lock);
    1545     if (auto* jitData = m_jitData.get()) {
    1546         for (CallLinkInfo* callLinkInfo : jitData->m_callLinkInfos) {
    1547             if (callLinkInfo->codeOrigin() == CodeOrigin(index))
    1548                 return callLinkInfo;
    1549         }
    1550     }
    1551     return nullptr;
    15521552}
    15531553
    … …  
    15991599        // link infos, or by val infos if we don't have JIT code. Attempts to query these data
    16001600        // structures using the concurrent API (getICStatusMap and friends) will return nothing if we
    1601         // don't have JIT code.
    1602         jitData->m_stubInfos.clear();
    1603         jitData->m_callLinkInfos.clear();
    1604         jitData->m_byValInfos.clear();
     1601        // don't have JIT code. So it's safe to call this if we fail a baseline JIT compile.
     1602        //
     1603        // We also call this from finalizeUnconditionally when we degrade from baseline JIT to LLInt
     1604        // code. This is safe to do since all compiler threads are safepointed in finalizeUnconditionally,
     1605        // which means we've made it past bytecode parsing. Only the bytecode parser will hold onto
     1606        // references to these various *infos via its use of ICStatusMap.
     1607
     1608        for (StructureStubInfo* stubInfo : jitData->m_stubInfos) {
     1609            stubInfo->aboutToDie();
     1610            stubInfo->deref();
     1611        }
     1612
    16051613        // We can clear this because the DFG's queries to these data structures are guarded by whether
    16061614        // there is JIT code.
    1607         jitData->m_rareCaseProfiles.clear();
     1615
     1616        m_jitData = nullptr;
    16081617    }
    16091618}
    … …  
    17371746
    17381747#if ENABLE(JIT)
     1748CodeBlock* CodeBlock::optimizedReplacement(JITType typeToReplace)
     1749{
     1750    CodeBlock* replacement = this->replacement();
     1751    if (!replacement)
     1752        return nullptr;
     1753    if (JITCode::isHigherTier(replacement->jitType(), typeToReplace))
     1754        return replacement;
     1755    return nullptr;
     1756}
     1757
     1758CodeBlock* CodeBlock::optimizedReplacement()
     1759{
     1760    return optimizedReplacement(jitType());
     1761}
     1762
    17391763bool CodeBlock::hasOptimizedReplacement(JITType typeToReplace)
    17401764{
    1741     CodeBlock* replacement = this->replacement();
    1742     return replacement && JITCode::isHigherTier(replacement->jitType(), typeToReplace);
     1765    return !!optimizedReplacement(typeToReplace);
    17431766}
    17441767
    … …  
    28022825{
    28032826    ASSERT(JITCode::isOptimizingJIT(jitType()));
    2804     ASSERT(alternative()->jitType() == JITType::BaselineJIT);
     2827    ASSERT(JITCode::isBaselineCode(alternative()->jitType()));
    28052828   
    28062829    CodeBlock* profiledBlock = alternative();
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r253987 r254480  
    259259    Optional<BytecodeIndex> bytecodeIndexFromCallSiteIndex(CallSiteIndex);
    260260
     261    // Because we might throw out baseline JIT code and all its baseline JIT data (m_jitData),
     262    // you need to be careful about the lifetime of when you use the return value of this function.
     263    // The return value may have raw pointers into this data structure that gets thrown away.
     264    // Specifically, you need to ensure that no GC can be finalized (typically that means no
     265    // allocations) between calling this and the last use of it.
    261266    void getICStatusMap(const ConcurrentJSLocker&, ICStatusMap& result);
    262267    void getICStatusMap(ICStatusMap& result);
    … …  
    278283        std::unique_ptr<PCToCodeOriginMap> m_pcToCodeOriginMap;
    279284        std::unique_ptr<RegisterAtOffsetList> m_calleeSaveRegisters;
     285        // FIXME: Now that we unconditionally OSR exit to the LLInt, we might be able to prune
     286        // the number of entries we have in this to contain entries only for opcodes we use
     287        // it for. Today, that's only for loop OSR entry.
     288        // https://bugs.webkit.org/show_bug.cgi?id=206207
    280289        JITCodeMap m_jitCodeMap;
    281290    };
    … …  
    308317    StructureStubInfo* addStubInfo(AccessType);
    309318
    310     // O(n) operation. Use getStubInfoMap() unless you really only intend to get one
    311     // stub info.
    312     StructureStubInfo* findStubInfo(CodeOrigin);
    313 
    314319    ByValInfo* addByValInfo();
    315320
    316321    CallLinkInfo* addCallLinkInfo();
    317 
    318     // This is a slow function call used primarily for compiling OSR exits in the case
    319     // that there had been inlining. Chances are if you want to use this, you're really
    320     // looking for a CallLinkInfoMap to amortize the cost of calling this.
    321     CallLinkInfo* getCallLinkInfoForBytecodeIndex(BytecodeIndex);
    322322   
    323323    void setJITCodeMap(JITCodeMap&& jitCodeMap)
    … …  
    413413    void setJITCode(Ref<JITCode>&& code)
    414414    {
    415         ASSERT(heap()->isDeferred());
    416415        if (!code->isShared())
    417416            heap()->reportExtraMemoryAllocated(code->size());
    … …  
    445444    DFG::CapabilityLevel capabilityLevelState() { return static_cast<DFG::CapabilityLevel>(m_capabilityLevelState); }
    446445
     446    CodeBlock* optimizedReplacement(JITType typeToReplace);
     447    CodeBlock* optimizedReplacement(); // the typeToReplace is my JITType
    447448    bool hasOptimizedReplacement(JITType typeToReplace);
    448449    bool hasOptimizedReplacement(); // the typeToReplace is my JITType
  • trunk/Source/JavaScriptCore/dfg/DFGDriver.cpp

    r253896 r254480  
    8282    ASSERT(codeBlock);
    8383    ASSERT(codeBlock->alternative());
    84     ASSERT(codeBlock->alternative()->jitType() == JITType::BaselineJIT);
     84    ASSERT(JITCode::isBaselineCode(codeBlock->alternative()->jitType()));
    8585    ASSERT(!profiledDFGCodeBlock || profiledDFGCodeBlock->jitType() == JITType::DFGJIT);
    8686   
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.cpp

    r254143 r254480  
    143143}
    144144
    145 MacroAssemblerCodePtr<JSEntryPtrTag> callerReturnPC(CodeBlock* baselineCodeBlockForCaller, BytecodeIndex callBytecodeIndex, InlineCallFrame::Kind trueCallerCallKind, bool& callerIsLLInt)
    146 {
    147     callerIsLLInt = Options::forceOSRExitToLLInt() || baselineCodeBlockForCaller->jitType() == JITType::InterpreterThunk;
    148 
     145static MacroAssemblerCodePtr<JSEntryPtrTag> callerReturnPC(CodeBlock* baselineCodeBlockForCaller, BytecodeIndex callBytecodeIndex, InlineCallFrame::Kind trueCallerCallKind)
     146{
    149147    if (callBytecodeIndex.checkpoint())
    150148        return LLInt::getCodePtr<JSEntryPtrTag>(checkpoint_osr_exit_from_inlined_call_trampoline);
    … …  
    152150    MacroAssemblerCodePtr<JSEntryPtrTag> jumpTarget;
    153151
    154     if (callerIsLLInt) {
    155         const Instruction& callInstruction = *baselineCodeBlockForCaller->instructions().at(callBytecodeIndex).ptr();
     152    const Instruction& callInstruction = *baselineCodeBlockForCaller->instructions().at(callBytecodeIndex).ptr();
    156153#define LLINT_RETURN_LOCATION(name) (callInstruction.isWide16() ? LLInt::getWide16CodePtr<JSEntryPtrTag>(name##_return_location) : (callInstruction.isWide32() ? LLInt::getWide32CodePtr<JSEntryPtrTag>(name##_return_location) : LLInt::getCodePtr<JSEntryPtrTag>(name##_return_location)))
    157154
    158         switch (trueCallerCallKind) {
    159         case InlineCallFrame::Call:
    160             jumpTarget = LLINT_RETURN_LOCATION(op_call);
    161             break;
    162         case InlineCallFrame::Construct:
    163             jumpTarget = LLINT_RETURN_LOCATION(op_construct);
    164             break;
    165         case InlineCallFrame::CallVarargs:
    166             jumpTarget = LLINT_RETURN_LOCATION(op_call_varargs_slow);
    167             break;
    168         case InlineCallFrame::ConstructVarargs:
    169             jumpTarget = LLINT_RETURN_LOCATION(op_construct_varargs_slow);
    170             break;
    171         case InlineCallFrame::GetterCall: {
    172             if (callInstruction.opcodeID() == op_get_by_id)
    173                 jumpTarget = LLINT_RETURN_LOCATION(op_get_by_id);
    174             else if (callInstruction.opcodeID() == op_get_by_val)
    175                 jumpTarget = LLINT_RETURN_LOCATION(op_get_by_val);
    176             else
    177                 RELEASE_ASSERT_NOT_REACHED();
    178             break;
    179         }
    180         case InlineCallFrame::SetterCall: {
    181             if (callInstruction.opcodeID() == op_put_by_id)
    182                 jumpTarget = LLINT_RETURN_LOCATION(op_put_by_id);
    183             else if (callInstruction.opcodeID() == op_put_by_val)
    184                 jumpTarget = LLINT_RETURN_LOCATION(op_put_by_val);
    185             else
    186                 RELEASE_ASSERT_NOT_REACHED();
    187             break;
    188         }
    189         default:
     155    switch (trueCallerCallKind) {
     156    case InlineCallFrame::Call:
     157        jumpTarget = LLINT_RETURN_LOCATION(op_call);
     158        break;
     159    case InlineCallFrame::Construct:
     160        jumpTarget = LLINT_RETURN_LOCATION(op_construct);
     161        break;
     162    case InlineCallFrame::CallVarargs:
     163        jumpTarget = LLINT_RETURN_LOCATION(op_call_varargs_slow);
     164        break;
     165    case InlineCallFrame::ConstructVarargs:
     166        jumpTarget = LLINT_RETURN_LOCATION(op_construct_varargs_slow);
     167        break;
     168    case InlineCallFrame::GetterCall: {
     169        if (callInstruction.opcodeID() == op_get_by_id)
     170            jumpTarget = LLINT_RETURN_LOCATION(op_get_by_id);
     171        else if (callInstruction.opcodeID() == op_get_by_val)
     172            jumpTarget = LLINT_RETURN_LOCATION(op_get_by_val);
     173        else
    190174            RELEASE_ASSERT_NOT_REACHED();
    191         }
     175        break;
     176    }
     177    case InlineCallFrame::SetterCall: {
     178        if (callInstruction.opcodeID() == op_put_by_id)
     179            jumpTarget = LLINT_RETURN_LOCATION(op_put_by_id);
     180        else if (callInstruction.opcodeID() == op_put_by_val)
     181            jumpTarget = LLINT_RETURN_LOCATION(op_put_by_val);
     182        else
     183            RELEASE_ASSERT_NOT_REACHED();
     184        break;
     185    }
     186    default:
     187        RELEASE_ASSERT_NOT_REACHED();
     188    }
    192189
    193190#undef LLINT_RETURN_LOCATION
    194 
    195     } else {
    196         switch (trueCallerCallKind) {
    197         case InlineCallFrame::Call:
    198         case InlineCallFrame::Construct:
    199         case InlineCallFrame::CallVarargs:
    200         case InlineCallFrame::ConstructVarargs: {
    201             CallLinkInfo* callLinkInfo =
    202                 baselineCodeBlockForCaller->getCallLinkInfoForBytecodeIndex(callBytecodeIndex);
    203             RELEASE_ASSERT(callLinkInfo);
    204 
    205             jumpTarget = callLinkInfo->callReturnLocation().retagged<JSEntryPtrTag>();
    206             break;
    207         }
    208 
    209         case InlineCallFrame::GetterCall:
    210         case InlineCallFrame::SetterCall: {
    211             StructureStubInfo* stubInfo =
    212                 baselineCodeBlockForCaller->findStubInfo(CodeOrigin(callBytecodeIndex));
    213             RELEASE_ASSERT(stubInfo);
    214 
    215             jumpTarget = stubInfo->doneLocation.retagged<JSEntryPtrTag>();
    216             break;
    217         }
    218 
    219         default:
    220             RELEASE_ASSERT_NOT_REACHED();
    221         }
    222     }
    223191
    224192    return jumpTarget;
    … …  
    254222        CodeOrigin* trueCaller = inlineCallFrame->getCallerSkippingTailCalls(&trueCallerCallKind);
    255223        GPRReg callerFrameGPR = GPRInfo::callFrameRegister;
    256 
    257         bool callerIsLLInt = false;
    258224
    259225        if (!trueCaller) {
    … …  
    272238            CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(*trueCaller);
    273239            auto callBytecodeIndex = trueCaller->bytecodeIndex();
    274             MacroAssemblerCodePtr<JSEntryPtrTag> jumpTarget = callerReturnPC(baselineCodeBlockForCaller, callBytecodeIndex, trueCallerCallKind, callerIsLLInt);
     240            MacroAssemblerCodePtr<JSEntryPtrTag> jumpTarget = callerReturnPC(baselineCodeBlockForCaller, callBytecodeIndex, trueCallerCallKind);
    275241
    276242            if (trueCaller->inlineCallFrame()) {
    … …  
    303269            GPRInfo::regT2);
    304270
    305         if (callerIsLLInt) {
     271        if (trueCaller) {
     272            // Set up LLInt registers for our caller in our callee saves.
    306273            CodeBlock* baselineCodeBlockForCaller = jit.baselineCodeBlockFor(*trueCaller);
    307274            jit.storePtr(CCallHelpers::TrustedImmPtr(baselineCodeBlockForCaller->metadataTable()), calleeSaveSlot(inlineCallFrame, baselineCodeBlock, LLInt::Registers::metadataTableGPR));
    … …  
    389356    ASSERT(JITCode::isBaselineCode(codeBlockForExit->jitType()));
    390357
    391     void* jumpTarget;
    392     bool exitToLLInt = Options::forceOSRExitToLLInt() || codeBlockForExit->jitType() == JITType::InterpreterThunk;
    393     if (exitToLLInt) {
    394         auto bytecodeIndex = exit.m_codeOrigin.bytecodeIndex();
    395         const Instruction& currentInstruction = *codeBlockForExit->instructions().at(bytecodeIndex).ptr();
    396         MacroAssemblerCodePtr<JSEntryPtrTag> destination;
    397         if (bytecodeIndex.checkpoint())
    398             destination = LLInt::getCodePtr<JSEntryPtrTag>(checkpoint_osr_exit_trampoline);
    399         else
    400             destination = LLInt::getCodePtr<JSEntryPtrTag>(currentInstruction);
    401 
    402         if (exit.isExceptionHandler()) {
    403             jit.move(CCallHelpers::TrustedImmPtr(&currentInstruction), GPRInfo::regT2);
    404             jit.storePtr(GPRInfo::regT2, &vm.targetInterpreterPCForThrow);
    405         }
    406 
    407         jit.move(CCallHelpers::TrustedImmPtr(codeBlockForExit->metadataTable()), LLInt::Registers::metadataTableGPR);
     358    auto bytecodeIndex = exit.m_codeOrigin.bytecodeIndex();
     359    const Instruction& currentInstruction = *codeBlockForExit->instructions().at(bytecodeIndex).ptr();
     360    MacroAssemblerCodePtr<JSEntryPtrTag> destination;
     361    if (bytecodeIndex.checkpoint())
     362        destination = LLInt::getCodePtr<JSEntryPtrTag>(checkpoint_osr_exit_trampoline);
     363    else
     364        destination = LLInt::getCodePtr<JSEntryPtrTag>(currentInstruction);
     365
     366    if (exit.isExceptionHandler()) {
     367        jit.move(CCallHelpers::TrustedImmPtr(&currentInstruction), GPRInfo::regT2);
     368        jit.storePtr(GPRInfo::regT2, &vm.targetInterpreterPCForThrow);
     369    }
     370
     371    jit.move(CCallHelpers::TrustedImmPtr(codeBlockForExit->metadataTable()), LLInt::Registers::metadataTableGPR);
    408372#if USE(JSVALUE64)
    409         jit.move(CCallHelpers::TrustedImmPtr(codeBlockForExit->instructionsRawPointer()), LLInt::Registers::pbGPR);
    410         jit.move(CCallHelpers::TrustedImm32(bytecodeIndex.offset()), LLInt::Registers::pcGPR);
     373    jit.move(CCallHelpers::TrustedImmPtr(codeBlockForExit->instructionsRawPointer()), LLInt::Registers::pbGPR);
     374    jit.move(CCallHelpers::TrustedImm32(bytecodeIndex.offset()), LLInt::Registers::pcGPR);
    411375#else
    412         jit.move(CCallHelpers::TrustedImmPtr(&currentInstruction), LLInt::Registers::pcGPR);
    413 #endif
    414         jumpTarget = destination.retagged<OSRExitPtrTag>().executableAddress();
    415     } else {
    416         BytecodeIndex exitIndex = exit.m_codeOrigin.bytecodeIndex();
    417         MacroAssemblerCodePtr<JSEntryPtrTag> destination;
    418         if (exitIndex.checkpoint())
    419             destination = LLInt::getCodePtr<JSEntryPtrTag>(checkpoint_osr_exit_trampoline);
    420         else {
    421             ASSERT(codeBlockForExit->bytecodeIndexForExit(exitIndex) == exitIndex);
    422             destination = codeBlockForExit->jitCodeMap().find(exitIndex);
    423         }
    424 
    425         ASSERT(destination);
    426 
    427         jumpTarget = destination.retagged<OSRExitPtrTag>().executableAddress();
    428     }
     376    jit.move(CCallHelpers::TrustedImmPtr(&currentInstruction), LLInt::Registers::pcGPR);
     377#endif
    429378
    430379    jit.addPtr(AssemblyHelpers::TrustedImm32(JIT::stackPointerOffsetFor(codeBlockForExit) * sizeof(Register)), GPRInfo::callFrameRegister, AssemblyHelpers::stackPointerRegister);
    … …  
    434383    }
    435384   
    436     jit.move(AssemblyHelpers::TrustedImmPtr(jumpTarget), GPRInfo::regT2);
     385    jit.move(AssemblyHelpers::TrustedImmPtr(destination.retagged<OSRExitPtrTag>().executableAddress()), GPRInfo::regT2);
    437386    jit.farJump(GPRInfo::regT2, OSRExitPtrTag);
    438387}
  • trunk/Source/JavaScriptCore/dfg/DFGOSRExitCompilerCommon.h

    r254142 r254480  
    4040void reifyInlinedCallFrames(CCallHelpers&, const OSRExitBase&);
    4141void adjustAndJumpToTarget(VM&, CCallHelpers&, const OSRExitBase&);
    42 MacroAssemblerCodePtr<JSEntryPtrTag> callerReturnPC(CodeBlock* baselineCodeBlockForCaller, BytecodeIndex callBytecodeIndex, InlineCallFrame::Kind callerKind, bool& callerIsLLInt);
    4342CCallHelpers::Address calleeSaveSlot(InlineCallFrame*, CodeBlock* baselineCodeBlock, GPRReg calleeSave);
    4443
  • trunk/Source/JavaScriptCore/heap/CodeBlockSet.cpp

    r226783 r254480  
    5656}
    5757
     58bool CodeBlockSet::isCurrentlyExecuting(CodeBlock* codeBlock)
     59{
     60    return m_currentlyExecuting.contains(codeBlock);
     61}
     62
    5863void CodeBlockSet::dump(PrintStream& out) const
    5964{
  • trunk/Source/JavaScriptCore/heap/CodeBlockSet.h

    r229180 r254480  
    5757    Lock& getLock() { return m_lock; }
    5858
     59    // This is expected to run only when we're not adding to the set for now. If
     60    // this needs to run concurrently in the future, we'll need to lock around this.
     61    bool isCurrentlyExecuting(CodeBlock*);
     62
    5963    // Visits each CodeBlock in the heap until the visitor function returns true
    6064    // to indicate that it is done iterating, or until every CodeBlock has been
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r254393 r254480  
    614614    finalizeMarkedUnconditionalFinalizers<FunctionExecutable>(vm().functionExecutableSpace.space);
    615615    finalizeMarkedUnconditionalFinalizers<SymbolTable>(vm().symbolTableSpace);
     616    finalizeMarkedUnconditionalFinalizers<ExecutableToCodeBlockEdge>(vm().executableToCodeBlockEdgesWithFinalizers); // We run this before CodeBlock's unconditional finalizer since CodeBlock looks at the owner executable's installed CodeBlock in its finalizeUnconditionally.
    616617    vm().forEachCodeBlockSpace(
    617618        [&] (auto& space) {
    618619            this->finalizeMarkedUnconditionalFinalizers<CodeBlock>(space.set);
    619620        });
    620     finalizeMarkedUnconditionalFinalizers<ExecutableToCodeBlockEdge>(vm().executableToCodeBlockEdgesWithFinalizers);
    621621    finalizeMarkedUnconditionalFinalizers<StructureRareData>(vm().structureRareDataSpace);
    622622    finalizeMarkedUnconditionalFinalizers<UnlinkedFunctionExecutable>(vm().unlinkedFunctionExecutableSpace.set);
    … …  
    15231523    sweepArrayBuffers();
    15241524    snapshotUnswept();
    1525     finalizeUnconditionalFinalizers();
     1525    finalizeUnconditionalFinalizers(); // We rely on these unconditional finalizers running before clearCurrentlyExecuting since CodeBlock's finalizer relies on querying currently executing.
    15261526    removeDeadCompilerWorklistEntries();
    15271527    notifyIncrementalSweeper();
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r253896 r254480  
    19941994{
    19951995    RELEASE_ASSERT(!codeBlock->vm().exceptionForInspection());
    1996     if (Options::forceOSRExitToLLInt() || codeBlock->jitType() == JITType::InterpreterThunk) {
    1997         const Instruction* nextPC = pc.next().ptr();
    1998         auto nextBytecode = LLInt::getCodePtr<JSEntryPtrTag>(*pc.next().ptr());
    1999         return encodeResult(nextPC, nextBytecode.executableAddress());
    2000     }
    2001 
    2002 #if ENABLE(JIT)
    2003     ASSERT(codeBlock->jitType() == JITType::BaselineJIT);
    2004     BytecodeIndex nextBytecodeIndex = pc.next().index();
    2005     auto nextBytecode = codeBlock->jitCodeMap().find(nextBytecodeIndex);
    2006     return encodeResult(nullptr, nextBytecode.executableAddress());
    2007 #endif
    2008     RELEASE_ASSERT_NOT_REACHED();
     1996    const Instruction* nextPC = pc.next().ptr();
     1997    auto nextBytecode = LLInt::getCodePtr<JSEntryPtrTag>(*pc.next().ptr());
     1998    return encodeResult(nextPC, nextBytecode.executableAddress());
    20091999}
    20102000
  • trunk/Source/JavaScriptCore/runtime/Options.cpp

    r253975 r254480  
    388388#endif
    389389#if !ENABLE(JIT)
    390     Options::useLLInt() = true;
     390    Options::forceBaseline() = false;
    391391    Options::useJIT() = false;
    392392    Options::useBaselineJIT() = false;
    … …  
    420420
    421421    if (!jitEnabledByDefault() && !Options::useJIT())
    422         Options::useLLInt() = true;
     422        Options::forceBaseline() = false;
    423423
    424424    if (!Options::useWebAssembly())
    … …  
    547547            RELEASE_ASSERT(Options::addressOfOption(gcMaxHeapSizeID) ==  &Options::gcMaxHeapSize());
    548548            RELEASE_ASSERT(Options::addressOfOptionDefault(gcMaxHeapSizeID) ==  &Options::gcMaxHeapSizeDefault());
    549             RELEASE_ASSERT(Options::addressOfOption(forceOSRExitToLLIntID) ==  &Options::forceOSRExitToLLInt());
    550             RELEASE_ASSERT(Options::addressOfOptionDefault(forceOSRExitToLLIntID) ==  &Options::forceOSRExitToLLIntDefault());
    551549
    552550#ifndef NDEBUG
    … …  
    946944{
    947945    bool coherent = true;
    948     if (!(useLLInt() || useJIT())) {
     946    if (forceBaseline() && !useJIT()) {
    949947        coherent = false;
    950         dataLog("INCOHERENT OPTIONS: at least one of useLLInt or useJIT must be true\n");
     948        dataLog("INCOHERENT OPTIONS: forceBaseline can't be true if useJIT is false\n");
    951949    }
    952950    if (!coherent)
  • trunk/Source/JavaScriptCore/runtime/OptionsList.h

    r254230 r254480  
    8282    v(OptionString, configFile, nullptr, Normal, "file to configure JSC options and logging location") \
    8383    \
    84     v(Bool, useLLInt,  true, Normal, "allows the LLINT to be used if true") \
     84    v(Bool, forceBaseline, false, Normal, "If true, we'll start running code in the baseline JIT and skip starting in the LLInt") \
    8585    v(Bool, useJIT, jitEnabledByDefault(), Normal, "allows the executable pages to be allocated for JIT and thunks if true") \
    8686    v(Bool, useBaselineJIT, true, Normal, "allows the baseline JIT to be used if true") \
    … …  
    495495    v(Double, dumpJITMemoryFlushInterval, 10, Restricted, "Maximum time in between flushes of the JIT memory dump in seconds.") \
    496496    v(Bool, useUnlinkedCodeBlockJettisoning, false, Normal, "If true, UnlinkedCodeBlock can be jettisoned.") \
    497     v(Bool, forceOSRExitToLLInt, false, Normal, "If true, we always exit to the LLInt. If false, we exit to whatever is most convenient.") \
    498497    v(Unsigned, getByValICMaxNumberOfIdentifiers, 4, Normal, "Number of identifiers we see in the LLInt that could cause us to bail on generating an IC for get_by_val.") \
    499498
  • trunk/Source/JavaScriptCore/runtime/ScriptExecutable.cpp

    r251425 r254480  
    427427        codeBlock->validate();
    428428   
    429     if (Options::useLLInt())
     429    if (Options::forceBaseline())
     430        setupJIT(vm, codeBlock);
     431    else
    430432        setupLLInt(codeBlock);
    431     else
    432         setupJIT(vm, codeBlock);
    433433   
    434434    installCode(vm, codeBlock, codeBlock->codeType(), codeBlock->specializationKind());
  • trunk/Tools/ChangeLog

    r254479 r254480  
     12020-01-13  Saam Barati  <sbarati@apple.com>
     2
     3        Throw away baseline code if there is an optimized replacement
     4        https://bugs.webkit.org/show_bug.cgi?id=202503
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        * Scripts/run-jsc-stress-tests:
     9
    1102020-01-13  Yoshiaki Jitsukawa  <yoshiaki.jitsukawa@sony.com>
    211
  • trunk/Tools/Scripts/run-jsc-stress-tests

    r254290 r254480  
    499499B3O0_OPTIONS = ["--maxDFGNodesInBasicBlockForPreciseAnalysis=100", "--defaultB3OptLevel=0"]
    500500FTL_OPTIONS = ["--useFTLJIT=true"]
    501 FORCE_LLINT_EXIT_OPTIONS = ["--forceOSRExitToLLInt=true"]
    502501
    503502require_relative "webkitruby/jsc-stress-test-writer-#{$testWriter}"
    … …  
    656655def runNoLLInt(*optionalTestSpecificOptions)
    657656    if $jitTests
    658         run("no-llint", "--useLLInt=false", *optionalTestSpecificOptions)
     657        run("no-llint", "--forceBaseline=true", *optionalTestSpecificOptions)
    659658    end
    660659end
    … …  
    709708
    710709def runFTLNoCJITB3O0(*optionalTestSpecificOptions)
    711     run("ftl-no-cjit-b3o0", "--useArrayAllocationProfiling=false", "--forcePolyProto=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS + B3O0_OPTIONS + FORCE_LLINT_EXIT_OPTIONS + optionalTestSpecificOptions))
     710    run("ftl-no-cjit-b3o0", "--useArrayAllocationProfiling=false", "--forcePolyProto=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS + B3O0_OPTIONS + optionalTestSpecificOptions))
    712711end
    713712
    … …  
    729728
    730729def runDFGEager(*optionalTestSpecificOptions)
    731     run("dfg-eager", *(EAGER_OPTIONS + COLLECT_CONTINUOUSLY_OPTIONS + FORCE_LLINT_EXIT_OPTIONS + optionalTestSpecificOptions))
     730    run("dfg-eager", *(EAGER_OPTIONS + COLLECT_CONTINUOUSLY_OPTIONS + optionalTestSpecificOptions))
    732731end
    733732
    … …  
    746745
    747746def runFTLEagerNoCJITValidate(*optionalTestSpecificOptions)
    748     run("ftl-eager-no-cjit", "--validateGraph=true", "--airForceIRCAllocator=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS + EAGER_OPTIONS + COLLECT_CONTINUOUSLY_OPTIONS + FORCE_LLINT_EXIT_OPTIONS + optionalTestSpecificOptions))
     747    run("ftl-eager-no-cjit", "--validateGraph=true", "--airForceIRCAllocator=true", *(FTL_OPTIONS + NO_CJIT_OPTIONS + EAGER_OPTIONS + COLLECT_CONTINUOUSLY_OPTIONS + optionalTestSpecificOptions))
    749748end
    750749
    … …  
    10611060    end
    10621061
    1063     run("no-llint-modules", "-m", "--useLLInt=false") if noLLInt
     1062    run("no-llint-modules", "-m", "--forceBaseline=true") if noLLInt
    10641063    run("no-cjit-validate-phases-modules", "-m", "--validateBytecode=true", "--validateGraphAtEachPhase=true", *NO_CJIT_OPTIONS)
    10651064    run("dfg-eager-modules", "-m", *EAGER_OPTIONS)
    … …  
    12621261
    12631262def runLayoutTestNoLLInt
    1264     runLayoutTest("no-llint", "--useLLInt=false")
     1263    runLayoutTest("no-llint", "--forceBaseline=true")
    12651264end
    12661265
    … …  
    14281427
    14291428def runMozillaTestBaselineJIT(mode, *extraFiles)
    1430     runMozillaTest("baseline", mode, extraFiles, "--useLLInt=false", "--useDFGJIT=false")
     1429    runMozillaTest("baseline", mode, extraFiles, "--forceBaseline=true", "--useDFGJIT=false")
    14311430end
    14321431
Note: See TracChangeset for help on using the changeset viewer.