Changeset 121215 in webkit for trunk/Source/JavaScriptCore


Ignore:
Timestamp:
Jun 25, 2012, 7:14:07 PM (13 years ago)
Author:
[email protected]
Message:

Value profiling should use tier-up threshold randomization to get more coverage
https://bugs.webkit.org/show_bug.cgi?id=89802

Source/JavaScriptCore:

Reviewed by Gavin Barraclough.

This patch causes both LLInt and Baseline JIT code to take the OSR slow path several
times before actually doing OSR. If we take the OSR slow path before the execution
count threshold is reached, then we just call CodeBlock::updateAllPredictions() to
compute the current latest least-upper-bound SpecType of all values seen in each
ValueProfile.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
(JSC):
(JSC::CodeBlock::updateAllPredictions):
(JSC::CodeBlock::shouldOptimizeNow):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::llintExecuteCounter):
(JSC::CodeBlock::jitExecuteCounter):
(CodeBlock):
(JSC::CodeBlock::updateAllPredictions):

  • bytecode/ExecutionCounter.cpp:

(JSC::ExecutionCounter::setThreshold):
(JSC::ExecutionCounter::status):
(JSC):

  • bytecode/ExecutionCounter.h:

(JSC::ExecutionCounter::count):
(ExecutionCounter):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGOperations.cpp:
  • dfg/DFGSpeculativeJIT.cpp:

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

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::jitCompileAndSetHeuristics):
(JSC::LLInt::entryOSR):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::JSGlobalObject):
(JSC):

  • runtime/JSGlobalObject.h:

(JSGlobalObject):
(JSC::JSGlobalObject::weakRandomInteger):

  • runtime/Options.cpp:

(Options):
(JSC::Options::initializeOptions):

  • runtime/Options.h:

(Options):

  • runtime/WeakRandom.h:

(WeakRandom):
(JSC::WeakRandom::seedUnsafe):

LayoutTests:

Reviewed by Gavin Barraclough.

  • fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit-expected.txt: Added.
  • fast/js/dfg-store-unexpected-value-into-argument-and-osr-exit.html: Added.
  • fast/js/script-tests/dfg-store-unexpected-value-into-argument-and-osr-exit.js: Added.

(foo):

Location:
trunk/Source/JavaScriptCore
Files:
16 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r121196 r121215  
     12012-06-22  Filip Pizlo  <[email protected]>
     2
     3        Value profiling should use tier-up threshold randomization to get more coverage
     4        https://bugs.webkit.org/show_bug.cgi?id=89802
     5
     6        Reviewed by Gavin Barraclough.
     7       
     8        This patch causes both LLInt and Baseline JIT code to take the OSR slow path several
     9        times before actually doing OSR. If we take the OSR slow path before the execution
     10        count threshold is reached, then we just call CodeBlock::updateAllPredictions() to
     11        compute the current latest least-upper-bound SpecType of all values seen in each
     12        ValueProfile.
     13
     14        * bytecode/CodeBlock.cpp:
     15        (JSC::CodeBlock::stronglyVisitStrongReferences):
     16        (JSC::CodeBlock::updateAllPredictionsAndCountLiveness):
     17        (JSC):
     18        (JSC::CodeBlock::updateAllPredictions):
     19        (JSC::CodeBlock::shouldOptimizeNow):
     20        * bytecode/CodeBlock.h:
     21        (JSC::CodeBlock::llintExecuteCounter):
     22        (JSC::CodeBlock::jitExecuteCounter):
     23        (CodeBlock):
     24        (JSC::CodeBlock::updateAllPredictions):
     25        * bytecode/ExecutionCounter.cpp:
     26        (JSC::ExecutionCounter::setThreshold):
     27        (JSC::ExecutionCounter::status):
     28        (JSC):
     29        * bytecode/ExecutionCounter.h:
     30        (JSC::ExecutionCounter::count):
     31        (ExecutionCounter):
     32        * dfg/DFGAbstractState.cpp:
     33        (JSC::DFG::AbstractState::execute):
     34        * dfg/DFGOperations.cpp:
     35        * dfg/DFGSpeculativeJIT.cpp:
     36        (JSC::DFG::SpeculativeJIT::compile):
     37        * jit/JITStubs.cpp:
     38        (JSC::DEFINE_STUB_FUNCTION):
     39        * llint/LLIntSlowPaths.cpp:
     40        (JSC::LLInt::jitCompileAndSetHeuristics):
     41        (JSC::LLInt::entryOSR):
     42        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     43        * runtime/JSGlobalObject.cpp:
     44        (JSC::JSGlobalObject::JSGlobalObject):
     45        (JSC):
     46        * runtime/JSGlobalObject.h:
     47        (JSGlobalObject):
     48        (JSC::JSGlobalObject::weakRandomInteger):
     49        * runtime/Options.cpp:
     50        (Options):
     51        (JSC::Options::initializeOptions):
     52        * runtime/Options.h:
     53        (Options):
     54        * runtime/WeakRandom.h:
     55        (WeakRandom):
     56        (JSC::WeakRandom::seedUnsafe):
     57
    1582012-06-25  Yong Li  <[email protected]>
    259
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def

    r121098 r121215  
    1010    ??0DynamicGlobalObjectScope@JSC@@QAE@AAVJSGlobalData@1@PAVJSGlobalObject@1@@Z
    1111    ??0InternalFunction@JSC@@IAE@PAVJSGlobalObject@1@PAVStructure@1@@Z
     12    ??0JSGlobalObject@JSC@@IAE@AAVJSGlobalData@1@PAVStructure@1@PBUGlobalObjectMethodTable@1@@Z
    1213    ??0JSLock@JSC@@QAE@PAVExecState@1@@Z
    1314    ??0MD5@WTF@@QAE@XZ
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r121073 r121215  
    21052105#endif
    21062106
    2107 #if ENABLE(DFG_JIT)
    2108     if (hasCodeOrigins()) {
    2109         // Make sure that executables that we have inlined don't die.
    2110         // FIXME: If they would have otherwise died, we should probably trigger recompilation.
    2111         for (size_t i = 0; i < inlineCallFrames().size(); ++i) {
    2112             InlineCallFrame& inlineCallFrame = inlineCallFrames()[i];
    2113             visitor.append(&inlineCallFrame.executable);
    2114             visitor.append(&inlineCallFrame.callee);
    2115         }
    2116     }
    2117    
    2118     m_lazyOperandValueProfiles.computeUpdatedPredictions(Collection);
    2119 #endif
    2120 
    2121 #if ENABLE(VALUE_PROFILER)
    2122     for (unsigned profileIndex = 0; profileIndex < numberOfArgumentValueProfiles(); ++profileIndex)
    2123         valueProfileForArgument(profileIndex)->computeUpdatedPrediction(Collection);
    2124     for (unsigned profileIndex = 0; profileIndex < numberOfValueProfiles(); ++profileIndex)
    2125         valueProfile(profileIndex)->computeUpdatedPrediction(Collection);
    2126 #endif
     2107    updateAllPredictions(Collection);
    21272108}
    21282109
     
    25752556
    25762557#if ENABLE(VALUE_PROFILER)
    2577 bool CodeBlock::shouldOptimizeNow()
    2578 {
    2579 #if ENABLE(JIT_VERBOSE_OSR)
    2580     dataLog("Considering optimizing %p...\n", this);
    2581 #endif
    2582 
    2583 #if ENABLE(VERBOSE_VALUE_PROFILE)
    2584     dumpValueProfiles();
    2585 #endif
    2586 
    2587     if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay)
    2588         return true;
    2589    
    2590     unsigned numberOfLiveNonArgumentValueProfiles = 0;
    2591     unsigned numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
     2558void CodeBlock::updateAllPredictionsAndCountLiveness(
     2559    OperationInProgress operation, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles)
     2560{
     2561    numberOfLiveNonArgumentValueProfiles = 0;
     2562    numberOfSamplesInProfiles = 0; // If this divided by ValueProfile::numberOfBuckets equals numberOfValueProfiles() then value profiles are full.
    25922563    for (unsigned i = 0; i < totalNumberOfValueProfiles(); ++i) {
    25932564        ValueProfile* profile = getFromAllValueProfiles(i);
     
    25972568        numberOfSamplesInProfiles += numSamples;
    25982569        if (profile->m_bytecodeOffset < 0) {
    2599             profile->computeUpdatedPrediction();
     2570            profile->computeUpdatedPrediction(operation);
    26002571            continue;
    26012572        }
    26022573        if (profile->numberOfSamples() || profile->m_prediction != SpecNone)
    26032574            numberOfLiveNonArgumentValueProfiles++;
    2604         profile->computeUpdatedPrediction();
    2605     }
     2575        profile->computeUpdatedPrediction(operation);
     2576    }
     2577   
     2578#if ENABLE(DFG_JIT)
     2579    m_lazyOperandValueProfiles.computeUpdatedPredictions(operation);
     2580#endif
     2581}
     2582
     2583void CodeBlock::updateAllPredictions(OperationInProgress operation)
     2584{
     2585    unsigned ignoredValue1, ignoredValue2;
     2586    updateAllPredictionsAndCountLiveness(operation, ignoredValue1, ignoredValue2);
     2587}
     2588
     2589bool CodeBlock::shouldOptimizeNow()
     2590{
     2591#if ENABLE(JIT_VERBOSE_OSR)
     2592    dataLog("Considering optimizing %p...\n", this);
     2593#endif
     2594
     2595#if ENABLE(VERBOSE_VALUE_PROFILE)
     2596    dumpValueProfiles();
     2597#endif
     2598
     2599    if (m_optimizationDelayCounter >= Options::maximumOptimizationDelay)
     2600        return true;
     2601   
     2602    unsigned numberOfLiveNonArgumentValueProfiles;
     2603    unsigned numberOfSamplesInProfiles;
     2604    updateAllPredictionsAndCountLiveness(NoOperation, numberOfLiveNonArgumentValueProfiles, numberOfSamplesInProfiles);
    26062605
    26072606#if ENABLE(JIT_VERBOSE_OSR)
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r121073 r121215  
    914914        }
    915915       
    916         int32_t llintExecuteCounter() const
    917         {
    918             return m_llintExecuteCounter.m_counter;
     916        const ExecutionCounter& llintExecuteCounter() const
     917        {
     918            return m_llintExecuteCounter;
    919919        }
    920920       
     
    972972        static ptrdiff_t offsetOfJITExecutionTotalCount() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_totalCount); }
    973973
    974         int32_t jitExecuteCounter() const { return m_jitExecuteCounter.m_counter; }
     974        const ExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; }
    975975       
    976976        unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; }
     
    11011101#if ENABLE(VALUE_PROFILER)
    11021102        bool shouldOptimizeNow();
     1103        void updateAllPredictions(OperationInProgress = NoOperation);
    11031104#else
    11041105        bool shouldOptimizeNow() { return false; }
     1106        void updateAllPredictions(OperationInProgress = NoOperation) { }
    11051107#endif
    11061108       
     
    11341136#else
    11351137        void tallyFrequentExitSites() { }
     1138#endif
     1139#if ENABLE(VALUE_PROFILER)
     1140        void updateAllPredictionsAndCountLiveness(OperationInProgress, unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles);
    11361141#endif
    11371142       
  • trunk/Source/JavaScriptCore/bytecode/ExecutionCounter.cpp

    r110453 r121215  
    2929#include "CodeBlock.h"
    3030#include "ExecutableAllocator.h"
     31#include <wtf/StringExtras.h>
    3132
    3233namespace JSC {
     
    126127       
    127128    // Compute the true total count.
    128     double trueTotalCount = static_cast<double>(m_totalCount) + m_counter;
     129    double trueTotalCount = count();
    129130       
    130131    // Correct the threshold for current memory usage.
     
    144145    }
    145146
    146     if (threshold > std::numeric_limits<int32_t>::max())
    147         threshold = std::numeric_limits<int32_t>::max();
    148        
     147    int32_t maxThreshold =
     148        codeBlock->globalObject()->weakRandomInteger() % Options::maximumExecutionCountsBetweenCheckpoints;
     149    if (threshold > maxThreshold)
     150        threshold = maxThreshold;
     151   
    149152    m_counter = static_cast<int32_t>(-threshold);
    150153       
     
    161164}
    162165
     166const char* ExecutionCounter::status() const
     167{
     168    static char result[80];
     169    snprintf(result, sizeof(result), "%lf/%lf, %d", count(), static_cast<double>(m_activeThreshold), m_counter);
     170    return result;
     171}
     172
    163173} // namespace JSC
    164174
  • trunk/Source/JavaScriptCore/bytecode/ExecutionCounter.h

    r109802 r121215  
    3939    void setNewThreshold(int32_t threshold, CodeBlock*);
    4040    void deferIndefinitely();
     41    double count() const { return static_cast<double>(m_totalCount) + m_counter; }
     42    const char* status() const;
    4143    static double applyMemoryUsageHeuristics(int32_t value, CodeBlock*);
    4244    static int32_t applyMemoryUsageHeuristicsAndConvertToInt(int32_t value, CodeBlock*);
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp

    r120767 r121215  
    13931393        // FIXME: Turn CheckStructure into StructureTransitionWatchpoint when possible!
    13941394        AbstractValue& value = forNode(node.child1());
    1395         ASSERT(isCellSpeculation(value.m_type));
     1395        ASSERT(value.isClear() || isCellSpeculation(value.m_type)); // Value could be clear if we've proven must-exit due to a speculation statically known to be bad.
    13961396        value.filter(node.structure());
    13971397        node.setCanExit(true);
  • trunk/Source/JavaScriptCore/dfg/DFGOperations.cpp

    r121073 r121215  
    12391239    CodeBlock* codeBlock = debugInfo->codeBlock;
    12401240    CodeBlock* alternative = codeBlock->alternative();
    1241     dataLog("Speculation failure in %p at @%u with executeCounter = %d, "
     1241    dataLog("Speculation failure in %p at @%u with executeCounter = %s, "
    12421242            "reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, "
    12431243            "success/fail %u/(%u+%u)\n",
    12441244            codeBlock,
    12451245            debugInfo->nodeIndex,
    1246             alternative ? alternative->jitExecuteCounter() : 0,
     1246            alternative ? alternative->jitExecuteCounter().status() : 0,
    12471247            alternative ? alternative->reoptimizationRetryCounter() : 0,
    12481248            alternative ? alternative->optimizationDelayCounter() : 0,
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r120834 r121215  
    987987
    988988    ASSERT(m_arguments.size() == block.variablesAtHead.numberOfArguments());
    989     for (size_t i = 0; i < m_arguments.size(); ++i) {
    990         NodeIndex nodeIndex = block.variablesAtHead.argument(i);
    991         if (nodeIndex == NoNode || m_jit.codeBlock()->argumentIsCaptured(i))
    992             m_arguments[i] = ValueSource(ValueInRegisterFile);
    993         else
    994             m_arguments[i] = ValueSource::forSpeculation(at(nodeIndex).variableAccessData()->prediction());
    995     }
     989    for (size_t i = 0; i < m_arguments.size(); ++i)
     990        m_arguments[i] = ValueSource(ValueInRegisterFile);
    996991   
    997992    m_state.reset();
  • trunk/Source/JavaScriptCore/jit/JITStubs.cpp

    r121073 r121215  
    19291929
    19301930#if ENABLE(JIT_VERBOSE_OSR)
    1931     dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
     1931    dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %s, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter().status(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
    19321932#endif
    19331933
    1934     if (!codeBlock->checkIfOptimizationThresholdReached())
     1934    if (!codeBlock->checkIfOptimizationThresholdReached()) {
     1935        codeBlock->updateAllPredictions();
    19351936        return;
     1937    }
    19361938
    19371939    if (codeBlock->hasOptimizedReplacement()) {
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r120499 r121215  
    265265inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec)
    266266{
     267    codeBlock->updateAllPredictions();
     268   
    267269    if (!codeBlock->checkIfJITThresholdReached()) {
    268270#if ENABLE(JIT_VERBOSE_OSR)
     
    301303{
    302304#if ENABLE(JIT_VERBOSE_OSR)
    303     dataLog("%p: Entered %s with executeCounter = %d\n", codeBlock, name, codeBlock->llintExecuteCounter());
     305    dataLog("%p: Entered %s with executeCounter = %s\n", codeBlock, name,
     306            codeBlock->llintExecuteCounter().status());
    304307#endif
    305308   
     
    347350   
    348351#if ENABLE(JIT_VERBOSE_OSR)
    349     dataLog("%p: Entered loop_osr with executeCounter = %d\n", codeBlock, codeBlock->llintExecuteCounter());
     352    dataLog("%p: Entered loop_osr with executeCounter = %s\n", codeBlock,
     353            codeBlock->llintExecuteCounter().status());
    350354#endif
    351355   
     
    377381   
    378382#if ENABLE(JIT_VERBOSE_OSR)
    379     dataLog("%p: Entered replace with executeCounter = %d\n", codeBlock, codeBlock->llintExecuteCounter());
     383    dataLog("%p: Entered replace with executeCounter = %s\n", codeBlock,
     384            codeBlock->llintExecuteCounter().status());
    380385#endif
    381386   
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r121098 r121215  
    113113}
    114114
     115JSGlobalObject::JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable)
     116    : JSSegmentedVariableObject(globalData, structure, &m_symbolTable)
     117    , m_globalScopeChain()
     118    , m_weakRandom(Options::forceWeakRandomSeed ? Options::forcedWeakRandomSeed : static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
     119    , m_evalEnabled(true)
     120    , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
     121{
     122}
     123
    115124JSGlobalObject::~JSGlobalObject()
    116125{
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r119779 r121215  
    176176
    177177    protected:
    178         explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0)
    179             : JSSegmentedVariableObject(globalData, structure, &m_symbolTable)
    180             , m_globalScopeChain()
    181             , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
    182             , m_evalEnabled(true)
    183             , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
    184         {
    185         }
     178        JS_EXPORT_PRIVATE explicit JSGlobalObject(JSGlobalData&, Structure*, const GlobalObjectMethodTable* = 0);
    186179
    187180        void finishCreation(JSGlobalData& globalData)
     
    329322
    330323        double weakRandomNumber() { return m_weakRandom.get(); }
     324        unsigned weakRandomInteger() { return m_weakRandom.getUint32(); }
    331325    protected:
    332326
  • trunk/Source/JavaScriptCore/runtime/Options.cpp

    r120834 r121215  
    6868int32_t executionCounterIncrementForReturn;
    6969
     70int32_t maximumExecutionCountsBetweenCheckpoints;
     71
    7072unsigned desiredSpeculativeSuccessFailRatio;
    7173
     
    9597unsigned numberOfGCMarkers;
    9698unsigned opaqueRootMergeThreshold;
     99
     100bool forceWeakRandomSeed;
     101unsigned forcedWeakRandomSeed;
    97102
    98103#if ENABLE(RUN_TIME_HEURISTICS)
     
    185190    SET(executionCounterIncrementForLoop,   1);
    186191    SET(executionCounterIncrementForReturn, 15);
     192   
     193    SET(maximumExecutionCountsBetweenCheckpoints, 1000);
    187194
    188195    SET(desiredSpeculativeSuccessFailRatio, 6);
     
    228235    ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) > 0);
    229236    ASSERT((static_cast<int64_t>(thresholdForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) <= static_cast<int64_t>(std::numeric_limits<int32_t>::max()));
     237   
     238    SET(forceWeakRandomSeed, false);
     239    SET(forcedWeakRandomSeed, 0);
    230240}
    231241
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r120834 r121215  
    5454extern int32_t executionCounterIncrementForReturn;
    5555
     56extern int32_t maximumExecutionCountsBetweenCheckpoints;
     57
    5658extern unsigned desiredSpeculativeSuccessFailRatio;
    5759
     
    8284JS_EXPORTDATA extern unsigned opaqueRootMergeThreshold;
    8385
     86extern bool forceWeakRandomSeed;
     87extern unsigned forcedWeakRandomSeed;
     88
    8489void initializeOptions();
    8590
  • trunk/Source/JavaScriptCore/runtime/WeakRandom.h

    r95901 r121215  
    6363    {
    6464    }
     65   
     66    // Returns the seed provided that you've never called get() or getUint32().
     67    unsigned seedUnsafe() const { return m_high; }
    6568
    6669    double get()
Note: See TracChangeset for help on using the changeset viewer.