Changeset 167600 in webkit


Ignore:
Timestamp:
Apr 21, 2014, 11:43:01 AM (11 years ago)
Author:
fpizlo@apple.com
Message:

Take block execution count estimates into account when voting double
https://bugs.webkit.org/show_bug.cgi?id=131906

Reviewed by Geoffrey Garen.

This was a drama in three acts.

Act I: Slurp in BasicBlock::executionCount and use it as a weight when counting the

number of uses of a variable that want double or non-double. Easy as pie. This
gave me a huge speed-up on FloatMM and a huge slow-down on basically everything
else.


Act II: Realize that there were some programs where our previous double voting was

just on the edge of disaster and making it more precise tipped it over. In
particular, if you had an integer variable that would infrequently be used in a
computation that resulted in a variable that was frequently used as an array index,
the outer infrequentness would be the thing we'd use in the vote. So, an array
index would become double. We fix this by reviving global backwards propagation
and introducing the concept of ReallyWantsInt, which is used just for array
indices. Any variable transitively flagged as ReallyWantsInt will never be forced
double. We need that flag to be separate from UsedAsInt, since UsedAsInt needs to
be set in bitops for RageConversion but using it for double forcing is too much.
Basically, it's cheaper to have to convert a double to an int for a bitop than it
is to convert a double to an int for an array index; also a variable being used as
an array index is a much stronger hint that it ought to be an int. This recovered
performance on everything except programs that used FTL OSR entry.


Act III: Realize that OSR entrypoint creation creates blocks that have NaN execution

count, which then completely pollutes the weighting - essentially all votes go
NaN. Fix this with some surgical defenses. Basically, any client of execution
counts should allow for them to be NaN and shouldn't completely fall off a cliff
when it happens.


This is awesome. 75% speed-up on FloatMM. 11% speed-up on audio-dft. This leads to
7% speed-up on AsmBench and 2% speed-up on Kraken.

  • CMakeLists.txt:
  • JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • dfg/DFGBackwardsPropagationPhase.cpp:

(JSC::DFG::BackwardsPropagationPhase::run):
(JSC::DFG::BackwardsPropagationPhase::propagate):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::dumpBlockHeader):

  • dfg/DFGGraph.h:

(JSC::DFG::Graph::voteNode):
(JSC::DFG::Graph::voteChildren):

  • dfg/DFGNodeFlags.cpp:

(JSC::DFG::dumpNodeFlags):

  • dfg/DFGNodeFlags.h:
  • dfg/DFGOSREntrypointCreationPhase.cpp:

(JSC::DFG::OSREntrypointCreationPhase::run):

  • dfg/DFGPlan.cpp:

(JSC::DFG::Plan::compileInThreadImpl):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):

  • dfg/DFGVariableAccessData.cpp: Added.

(JSC::DFG::VariableAccessData::VariableAccessData):
(JSC::DFG::VariableAccessData::mergeIsCaptured):
(JSC::DFG::VariableAccessData::mergeShouldNeverUnbox):
(JSC::DFG::VariableAccessData::predict):
(JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction):
(JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote):
(JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat):
(JSC::DFG::VariableAccessData::mergeDoubleFormatState):
(JSC::DFG::VariableAccessData::makePredictionForDoubleFormat):
(JSC::DFG::VariableAccessData::flushFormat):

  • dfg/DFGVariableAccessData.h:

(JSC::DFG::VariableAccessData::vote):
(JSC::DFG::VariableAccessData::VariableAccessData): Deleted.
(JSC::DFG::VariableAccessData::mergeIsCaptured): Deleted.
(JSC::DFG::VariableAccessData::mergeShouldNeverUnbox): Deleted.
(JSC::DFG::VariableAccessData::predict): Deleted.
(JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): Deleted.
(JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote): Deleted.
(JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat): Deleted.
(JSC::DFG::VariableAccessData::mergeDoubleFormatState): Deleted.
(JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): Deleted.
(JSC::DFG::VariableAccessData::flushFormat): Deleted.

Location:
trunk/Source/JavaScriptCore
Files:
1 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/CMakeLists.txt

    r167530 r167600  
    198198    dfg/DFGValidate.cpp
    199199    dfg/DFGValueSource.cpp
     200    dfg/DFGVariableAccessData.cpp
    200201    dfg/DFGVariableAccessDataDump.cpp
    201202    dfg/DFGVariableEvent.cpp
  • trunk/Source/JavaScriptCore/ChangeLog

    r167599 r167600  
     12014-04-19  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Take block execution count estimates into account when voting double
     4        https://bugs.webkit.org/show_bug.cgi?id=131906
     5
     6        Reviewed by Geoffrey Garen.
     7       
     8        This was a drama in three acts.
     9       
     10        Act I: Slurp in BasicBlock::executionCount and use it as a weight when counting the
     11            number of uses of a variable that want double or non-double. Easy as pie. This
     12            gave me a huge speed-up on FloatMM and a huge slow-down on basically everything
     13            else.
     14       
     15        Act II: Realize that there were some programs where our previous double voting was
     16            just on the edge of disaster and making it more precise tipped it over. In
     17            particular, if you had an integer variable that would infrequently be used in a
     18            computation that resulted in a variable that was frequently used as an array index,
     19            the outer infrequentness would be the thing we'd use in the vote. So, an array
     20            index would become double. We fix this by reviving global backwards propagation
     21            and introducing the concept of ReallyWantsInt, which is used just for array
     22            indices. Any variable transitively flagged as ReallyWantsInt will never be forced
     23            double. We need that flag to be separate from UsedAsInt, since UsedAsInt needs to
     24            be set in bitops for RageConversion but using it for double forcing is too much.
     25            Basically, it's cheaper to have to convert a double to an int for a bitop than it
     26            is to convert a double to an int for an array index; also a variable being used as
     27            an array index is a much stronger hint that it ought to be an int. This recovered
     28            performance on everything except programs that used FTL OSR entry.
     29       
     30        Act III: Realize that OSR entrypoint creation creates blocks that have NaN execution
     31            count, which then completely pollutes the weighting - essentially all votes go
     32            NaN. Fix this with some surgical defenses. Basically, any client of execution
     33            counts should allow for them to be NaN and shouldn't completely fall off a cliff
     34            when it happens.
     35       
     36        This is awesome. 75% speed-up on FloatMM. 11% speed-up on audio-dft. This leads to
     37        7% speed-up on AsmBench and 2% speed-up on Kraken.
     38
     39        * CMakeLists.txt:
     40        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
     41        * JavaScriptCore.xcodeproj/project.pbxproj:
     42        * dfg/DFGBackwardsPropagationPhase.cpp:
     43        (JSC::DFG::BackwardsPropagationPhase::run):
     44        (JSC::DFG::BackwardsPropagationPhase::propagate):
     45        * dfg/DFGGraph.cpp:
     46        (JSC::DFG::Graph::dumpBlockHeader):
     47        * dfg/DFGGraph.h:
     48        (JSC::DFG::Graph::voteNode):
     49        (JSC::DFG::Graph::voteChildren):
     50        * dfg/DFGNodeFlags.cpp:
     51        (JSC::DFG::dumpNodeFlags):
     52        * dfg/DFGNodeFlags.h:
     53        * dfg/DFGOSREntrypointCreationPhase.cpp:
     54        (JSC::DFG::OSREntrypointCreationPhase::run):
     55        * dfg/DFGPlan.cpp:
     56        (JSC::DFG::Plan::compileInThreadImpl):
     57        * dfg/DFGPredictionPropagationPhase.cpp:
     58        (JSC::DFG::PredictionPropagationPhase::doDoubleVoting):
     59        (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
     60        * dfg/DFGVariableAccessData.cpp: Added.
     61        (JSC::DFG::VariableAccessData::VariableAccessData):
     62        (JSC::DFG::VariableAccessData::mergeIsCaptured):
     63        (JSC::DFG::VariableAccessData::mergeShouldNeverUnbox):
     64        (JSC::DFG::VariableAccessData::predict):
     65        (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction):
     66        (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote):
     67        (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat):
     68        (JSC::DFG::VariableAccessData::mergeDoubleFormatState):
     69        (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat):
     70        (JSC::DFG::VariableAccessData::flushFormat):
     71        * dfg/DFGVariableAccessData.h:
     72        (JSC::DFG::VariableAccessData::vote):
     73        (JSC::DFG::VariableAccessData::VariableAccessData): Deleted.
     74        (JSC::DFG::VariableAccessData::mergeIsCaptured): Deleted.
     75        (JSC::DFG::VariableAccessData::mergeShouldNeverUnbox): Deleted.
     76        (JSC::DFG::VariableAccessData::predict): Deleted.
     77        (JSC::DFG::VariableAccessData::mergeArgumentAwarePrediction): Deleted.
     78        (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote): Deleted.
     79        (JSC::DFG::VariableAccessData::tallyVotesForShouldUseDoubleFormat): Deleted.
     80        (JSC::DFG::VariableAccessData::mergeDoubleFormatState): Deleted.
     81        (JSC::DFG::VariableAccessData::makePredictionForDoubleFormat): Deleted.
     82        (JSC::DFG::VariableAccessData::flushFormat): Deleted.
     83
    1842014-04-21  Michael Saboff  <msaboff@apple.com>
    285
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj

    r167530 r167600  
    451451    <ClCompile Include="..\dfg\DFGValidate.cpp" />
    452452    <ClCompile Include="..\dfg\DFGValueSource.cpp" />
     453    <ClCompile Include="..\dfg\DFGVariableAccessData.cpp" />
    453454    <ClCompile Include="..\dfg\DFGVariableAccessDataDump.cpp" />
    454455    <ClCompile Include="..\dfg\DFGVariableEvent.cpp" />
  • trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj

    r167530 r167600  
    326326                0F6B1CC918641DF800845D97 /* ArityCheckFailReturnThunks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */; };
    327327                0F6B1CCA18641DF800845D97 /* ArityCheckFailReturnThunks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */; settings = {ATTRIBUTES = (Private, ); }; };
     328                0F6E845A19030BEF00562741 /* DFGVariableAccessData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */; };
    328329                0F7025A91714B0FA00382C0E /* DFGOSRExitCompilerCommon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */; };
    329330                0F7025AA1714B0FC00382C0E /* DFGOSRExitCompilerCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F7025A81714B0F800382C0E /* DFGOSRExitCompilerCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    21282129                0F6B1CC718641DF800845D97 /* ArityCheckFailReturnThunks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArityCheckFailReturnThunks.cpp; sourceTree = "<group>"; };
    21292130                0F6B1CC818641DF800845D97 /* ArityCheckFailReturnThunks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArityCheckFailReturnThunks.h; sourceTree = "<group>"; };
     2131                0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGVariableAccessData.cpp; path = dfg/DFGVariableAccessData.cpp; sourceTree = "<group>"; };
    21302132                0F7025A71714B0F800382C0E /* DFGOSRExitCompilerCommon.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGOSRExitCompilerCommon.cpp; path = dfg/DFGOSRExitCompilerCommon.cpp; sourceTree = "<group>"; };
    21312133                0F7025A81714B0F800382C0E /* DFGOSRExitCompilerCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGOSRExitCompilerCommon.h; path = dfg/DFGOSRExitCompilerCommon.h; sourceTree = "<group>"; };
     
    48114813                                0F2BDC4E15228BE700CD8910 /* DFGValueSource.cpp */,
    48124814                                0F2BDC401522801700CD8910 /* DFGValueSource.h */,
     4815                                0F6E845919030BEF00562741 /* DFGVariableAccessData.cpp */,
    48134816                                0F620172143FCD2F0068B77C /* DFGVariableAccessData.h */,
    48144817                                0FDDBFB21666EED500C55FEF /* DFGVariableAccessDataDump.cpp */,
     
    70897092                                BCDD51EB0FB8DF74004A8BDC /* JITOpcodes.cpp in Sources */,
    70907093                                A71236E51195F33C00BD2174 /* JITOpcodes32_64.cpp in Sources */,
     7094                                0F6E845A19030BEF00562741 /* DFGVariableAccessData.cpp in Sources */,
    70917095                                0F24E54C17EE274900ABB217 /* JITOperations.cpp in Sources */,
    70927096                                86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */,
  • trunk/Source/JavaScriptCore/dfg/DFGBackwardsPropagationPhase.cpp

    r167325 r167600  
    4545    bool run()
    4646    {
    47         for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
    48             BasicBlock* block = m_graph.block(blockIndex);
    49             if (!block)
    50                 continue;
    51            
    52             // Prevent a tower of overflowing additions from creating a value that is out of the
    53             // safe 2^48 range.
    54             m_allowNestedOverflowingAdditions = block->size() < (1 << 16);
    55            
    56             for (unsigned indexInBlock = block->size(); indexInBlock--;)
    57                 propagate(block->at(indexInBlock));
     47        m_changed = true;
     48        while (m_changed) {
     49            m_changed = false;
     50            for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
     51                BasicBlock* block = m_graph.block(blockIndex);
     52                if (!block)
     53                    continue;
     54           
     55                // Prevent a tower of overflowing additions from creating a value that is out of the
     56                // safe 2^48 range.
     57                m_allowNestedOverflowingAdditions = block->size() < (1 << 16);
     58           
     59                for (unsigned indexInBlock = block->size(); indexInBlock--;)
     60                    propagate(block->at(indexInBlock));
     61            }
    5862        }
    5963       
     
    175179        case GetLocal: {
    176180            VariableAccessData* variableAccessData = node->variableAccessData();
    177             variableAccessData->mergeFlags(flags);
     181            flags &= ~NodeBytecodeUsesAsInt; // We don't care about cross-block uses-as-int.
     182            m_changed |= variableAccessData->mergeFlags(flags);
    178183            break;
    179184        }
     
    183188            if (!variableAccessData->isLoadedFrom())
    184189                break;
    185             node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
     190            flags = variableAccessData->flags();
     191            RELEASE_ASSERT(!(flags & ~NodeBytecodeBackPropMask));
     192            flags |= NodeBytecodeUsesAsNumber; // Account for the fact that control flow may cause overflows that our modeling can't handle.
     193            node->child1()->mergeFlags(flags);
     194            break;
     195        }
     196           
     197        case Flush: {
     198            VariableAccessData* variableAccessData = node->variableAccessData();
     199            m_changed |= variableAccessData->mergeFlags(NodeBytecodeUsesAsValue);
    186200            break;
    187201        }
     
    200214            flags |= NodeBytecodeUsesAsInt;
    201215            flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
     216            flags &= ~NodeBytecodeUsesAsArrayIndex;
    202217            node->child1()->mergeFlags(flags);
    203218            node->child2()->mergeFlags(flags);
     
    207222        case StringCharCodeAt: {
    208223            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
    209             node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt);
     224            node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
    210225            break;
    211226        }
     
    306321        case GetByVal: {
    307322            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
    308             node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt);
     323            node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
    309324            break;
    310325        }
    311326           
    312327        case GetMyArgumentByValSafe: {
    313             node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt);
     328            node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
    314329            break;
    315330        }
    316331           
    317332        case NewArrayWithSize: {
    318             node->child1()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt);
     333            node->child1()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
    319334            break;
    320335        }
     
    324339            // in that you would get a different exception message. So, like, whatever: we
    325340            // claim here that NaN v. undefined is observable.
    326             node->child1()->mergeFlags(NodeBytecodeUsesAsInt | NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
     341            node->child1()->mergeFlags(NodeBytecodeUsesAsInt | NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsArrayIndex);
    327342            break;
    328343        }
     
    330345        case StringCharAt: {
    331346            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
    332             node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt);
     347            node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
    333348            break;
    334349        }
     
    347362        case PutByVal: {
    348363            m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
    349             m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt);
     364            m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
    350365            m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue);
    351366            break;
     
    397412   
    398413    bool m_allowNestedOverflowingAdditions;
     414    bool m_changed;
    399415};
    400416
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp

    r167467 r167600  
    358358{
    359359    out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "): ", block->isReachable ? "" : "(skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
     360    if (block->executionCount == block->executionCount)
     361        out.print(prefix, "  Execution count: ", block->executionCount, "\n");
    360362    out.print(prefix, "  Predecessors:");
    361363    for (size_t i = 0; i < block->predecessors.size(); ++i)
  • trunk/Source/JavaScriptCore/dfg/DFGGraph.h

    r167467 r167600  
    702702    }
    703703   
    704     void voteNode(Node* node, unsigned ballot)
     704    void voteNode(Node* node, unsigned ballot, float weight = 1)
    705705    {
    706706        switch (node->op()) {
     
    714714       
    715715        if (node->op() == GetLocal)
    716             node->variableAccessData()->vote(ballot);
    717     }
    718    
    719     void voteNode(Edge edge, unsigned ballot)
    720     {
    721         voteNode(edge.node(), ballot);
    722     }
    723    
    724     void voteChildren(Node* node, unsigned ballot)
     716            node->variableAccessData()->vote(ballot, weight);
     717    }
     718   
     719    void voteNode(Edge edge, unsigned ballot, float weight = 1)
     720    {
     721        voteNode(edge.node(), ballot, weight);
     722    }
     723   
     724    void voteChildren(Node* node, unsigned ballot, float weight = 1)
    725725    {
    726726        if (node->flags() & NodeHasVarArgs) {
     
    729729                childIdx++) {
    730730                if (!!m_varArgChildren[childIdx])
    731                     voteNode(m_varArgChildren[childIdx], ballot);
     731                    voteNode(m_varArgChildren[childIdx], ballot, weight);
    732732            }
    733733            return;
     
    736736        if (!node->child1())
    737737            return;
    738         voteNode(node->child1(), ballot);
     738        voteNode(node->child1(), ballot, weight);
    739739        if (!node->child2())
    740740            return;
    741         voteNode(node->child2(), ballot);
     741        voteNode(node->child2(), ballot, weight);
    742742        if (!node->child3())
    743743            return;
    744         voteNode(node->child3(), ballot);
     744        voteNode(node->child3(), ballot, weight);
    745745    }
    746746   
  • trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.cpp

    r167325 r167600  
    100100    if (flags & NodeBytecodeUsesAsInt)
    101101        out.print(comma, "UseAsInt");
     102
     103    if (flags & NodeBytecodeUsesAsArrayIndex)
     104        out.print(comma, "ReallyWantsInt");
    102105   
    103106    if (!(flags & NodeDoesNotExit))
  • trunk/Source/JavaScriptCore/dfg/DFGNodeFlags.h

    r167325 r167600  
    5454#define NodeMayNegZero                   0x0100
    5555                               
    56 #define NodeBytecodeBackPropMask         0x1E00
     56#define NodeBytecodeBackPropMask         0x3E00
    5757#define NodeBytecodeUseBottom            0x0000
    5858#define NodeBytecodeUsesAsNumber         0x0200 // The result of this computation may be used in a context that observes fractional, or bigger-than-int32, results.
     
    6161#define NodeBytecodeUsesAsValue          (NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther)
    6262#define NodeBytecodeUsesAsInt            0x1000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
     63#define NodeBytecodeUsesAsArrayIndex     0x2000 // The result of this computation is known to be used in a context that strongly prefers integer values, to the point that we should avoid using doubles if at all possible.
    6364
    6465#define NodeArithFlagsMask               (NodeBehaviorMask | NodeBytecodeBackPropMask)
    6566
    66 #define NodeDoesNotExit                  0x2000 // This flag is negated to make it natural for the default to be that a node does exit.
     67#define NodeDoesNotExit                  0x4000 // This flag is negated to make it natural for the default to be that a node does exit.
    6768
    68 #define NodeRelevantToOSR                0x4000
     69#define NodeRelevantToOSR                0x8000
    6970
    70 #define NodeIsFlushed                    0x8000 // Used by Graph::computeIsFlushed(), will tell you which local nodes are backwards-reachable from a Flush.
     71#define NodeIsFlushed                   0x10000 // Used by Graph::computeIsFlushed(), will tell you which local nodes are backwards-reachable from a Flush.
    7172
    7273typedef uint32_t NodeFlags;
  • trunk/Source/JavaScriptCore/dfg/DFGOSREntrypointCreationPhase.cpp

    r167394 r167600  
    8484        BlockInsertionSet insertionSet(m_graph);
    8585       
    86         BasicBlock* newRoot = insertionSet.insert(0, PNaN);
     86        // We say that the execution count of the entry block is 1, because we know for sure
     87        // that this must be the case. Under our definition of executionCount, "1" means "once
     88        // per invocation". We could have said NaN here, since that would ask any clients of
     89        // executionCount to use best judgement - but that seems unnecessary since we know for
     90        // sure what the executionCount should be in this case.
     91        BasicBlock* newRoot = insertionSet.insert(0, 1);
    8792        NodeOrigin origin = target->at(0)->origin;
    8893       
  • trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp

    r167467 r167600  
    210210    performPredictionInjection(dfg);
    211211   
    212     if (isFTL(mode))
    213         performStaticExecutionCountEstimation(dfg);
     212    performStaticExecutionCountEstimation(dfg);
    214213   
    215214    if (mode == FTLForOSREntryMode) {
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r167455 r167600  
    642642    }
    643643   
    644     void doDoubleVoting(Node* node)
    645     {
     644    void doDoubleVoting(Node* node, float weight)
     645    {
     646        // Loop pre-headers created by OSR entrypoint creation may have NaN weight to indicate
     647        // that we actually don't know they weight. Assume that they execute once. This turns
     648        // out to be an OK assumption since the pre-header doesn't have any meaningful code.
     649        if (weight != weight)
     650            weight = 1;
     651       
    646652        switch (node->op()) {
    647653        case ValueAdd:
     
    660666                ballot = VoteValue;
    661667               
    662             m_graph.voteNode(node->child1(), ballot);
    663             m_graph.voteNode(node->child2(), ballot);
     668            m_graph.voteNode(node->child1(), ballot, weight);
     669            m_graph.voteNode(node->child2(), ballot, weight);
    664670            break;
    665671        }
     
    678684                ballot = VoteValue;
    679685               
    680             m_graph.voteNode(node->child1(), ballot);
    681             m_graph.voteNode(node->child2(), ballot);
     686            m_graph.voteNode(node->child1(), ballot, weight);
     687            m_graph.voteNode(node->child2(), ballot, weight);
    682688            break;
    683689        }
     
    698704                ballot = VoteValue;
    699705               
    700             m_graph.voteNode(node->child1(), ballot);
    701             m_graph.voteNode(node->child2(), ballot);
     706            m_graph.voteNode(node->child1(), ballot, weight);
     707            m_graph.voteNode(node->child2(), ballot, weight);
    702708            break;
    703709        }
     
    710716                ballot = VoteValue;
    711717               
    712             m_graph.voteNode(node->child1(), ballot);
     718            m_graph.voteNode(node->child1(), ballot, weight);
    713719            break;
    714720               
     
    716722        case ArithCos:
    717723        case ArithSin:
    718             m_graph.voteNode(node->child1(), VoteDouble);
     724            m_graph.voteNode(node->child1(), VoteDouble, weight);
    719725            break;
    720726               
     
    722728            SpeculatedType prediction = node->child1()->prediction();
    723729            if (isDoubleSpeculation(prediction))
    724                 node->variableAccessData()->vote(VoteDouble);
     730                node->variableAccessData()->vote(VoteDouble, weight);
    725731            else if (
    726732                !isFullNumberSpeculation(prediction)
    727733                || isInt32Speculation(prediction) || isMachineIntSpeculation(prediction))
    728                 node->variableAccessData()->vote(VoteValue);
     734                node->variableAccessData()->vote(VoteValue, weight);
    729735            break;
    730736        }
     
    736742            Edge child2 = m_graph.varArgChild(node, 1);
    737743            Edge child3 = m_graph.varArgChild(node, 2);
    738             m_graph.voteNode(child1, VoteValue);
    739             m_graph.voteNode(child2, VoteValue);
     744            m_graph.voteNode(child1, VoteValue, weight);
     745            m_graph.voteNode(child2, VoteValue, weight);
    740746            switch (node->arrayMode().type()) {
    741747            case Array::Double:
    742                 m_graph.voteNode(child3, VoteDouble);
     748                m_graph.voteNode(child3, VoteDouble, weight);
    743749                break;
    744750            default:
    745                 m_graph.voteNode(child3, VoteValue);
     751                m_graph.voteNode(child3, VoteValue, weight);
    746752                break;
    747753            }
     
    754760           
    755761        default:
    756             m_graph.voteChildren(node, VoteValue);
     762            m_graph.voteChildren(node, VoteValue, weight);
    757763            break;
    758764        }
     
    770776            for (unsigned i = 0; i < block->size(); ++i) {
    771777                m_currentNode = block->at(i);
    772                 doDoubleVoting(m_currentNode);
     778                doDoubleVoting(m_currentNode, block->executionCount);
    773779            }
    774780        }
  • trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h

    r167394 r167600  
    11/*
    2  * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
     2 * Copyright (C) 2011-2014 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2727#define DFGVariableAccessData_h
    2828
     29#if ENABLE(DFG_JIT)
     30
    2931#include "DFGCommon.h"
    3032#include "DFGDoubleFormatState.h"
     
    4648class VariableAccessData : public UnionFind<VariableAccessData> {
    4749public:
    48     VariableAccessData()
    49         : m_local(static_cast<VirtualRegister>(std::numeric_limits<int>::min()))
    50         , m_prediction(SpecNone)
    51         , m_argumentAwarePrediction(SpecNone)
    52         , m_flags(0)
    53         , m_isCaptured(false)
    54         , m_shouldNeverUnbox(false)
    55         , m_isArgumentsAlias(false)
    56         , m_structureCheckHoistingFailed(false)
    57         , m_checkArrayHoistingFailed(false)
    58         , m_isProfitableToUnbox(false)
    59         , m_isLoadedFrom(false)
    60         , m_doubleFormatState(EmptyDoubleFormatState)
    61     {
    62         clearVotes();
    63     }
    64    
    65     VariableAccessData(VirtualRegister local, bool isCaptured)
    66         : m_local(local)
    67         , m_prediction(SpecNone)
    68         , m_argumentAwarePrediction(SpecNone)
    69         , m_flags(0)
    70         , m_isCaptured(isCaptured)
    71         , m_shouldNeverUnbox(isCaptured)
    72         , m_isArgumentsAlias(false)
    73         , m_structureCheckHoistingFailed(false)
    74         , m_checkArrayHoistingFailed(false)
    75         , m_isProfitableToUnbox(false)
    76         , m_isLoadedFrom(false)
    77         , m_doubleFormatState(EmptyDoubleFormatState)
    78     {
    79         clearVotes();
    80     }
     50    VariableAccessData();
     51    VariableAccessData(VirtualRegister local, bool isCaptured);
    8152   
    8253    VirtualRegister local()
     
    9263    }
    9364
    94     bool mergeIsCaptured(bool isCaptured)
    95     {
    96         return checkAndSet(m_shouldNeverUnbox, m_shouldNeverUnbox | isCaptured)
    97             | checkAndSet(m_isCaptured, m_isCaptured | isCaptured);
    98     }
     65    bool mergeIsCaptured(bool isCaptured);
    9966   
    10067    bool isCaptured()
     
    11380    }
    11481   
    115     bool mergeShouldNeverUnbox(bool shouldNeverUnbox)
    116     {
    117         bool newShouldNeverUnbox = m_shouldNeverUnbox | shouldNeverUnbox;
    118         if (newShouldNeverUnbox == m_shouldNeverUnbox)
    119             return false;
    120         m_shouldNeverUnbox = newShouldNeverUnbox;
    121         return true;
    122     }
     82    bool mergeShouldNeverUnbox(bool shouldNeverUnbox);
    12383   
    12484    // Returns true if it would be unsound to store the value in an unboxed fashion.
     
    184144    }
    185145   
    186     bool predict(SpeculatedType prediction)
    187     {
    188         VariableAccessData* self = find();
    189         bool result = mergeSpeculation(self->m_prediction, prediction);
    190         if (result)
    191             mergeSpeculation(m_argumentAwarePrediction, m_prediction);
    192         return result;
    193     }
     146    bool predict(SpeculatedType prediction);
    194147   
    195148    SpeculatedType nonUnifiedPrediction()
     
    208161    }
    209162   
    210     bool mergeArgumentAwarePrediction(SpeculatedType prediction)
    211     {
    212         return mergeSpeculation(find()->m_argumentAwarePrediction, prediction);
    213     }
     163    bool mergeArgumentAwarePrediction(SpeculatedType prediction);
    214164   
    215165    void clearVotes()
     
    220170    }
    221171   
    222     void vote(unsigned ballot)
     172    void vote(unsigned ballot, float weight = 1)
    223173    {
    224174        ASSERT(ballot < 2);
    225         m_votes[ballot]++;
     175        m_votes[ballot] += weight;
    226176    }
    227177   
     
    232182    }
    233183   
    234     bool shouldUseDoubleFormatAccordingToVote()
    235     {
    236         // We don't support this facility for arguments, yet.
    237         // FIXME: make this work for arguments.
    238         if (local().isArgument())
    239             return false;
    240        
    241         // If the variable is not a number prediction, then this doesn't
    242         // make any sense.
    243         if (!isFullNumberSpeculation(prediction())) {
    244             // FIXME: we may end up forcing a local in inlined argument position to be a double even
    245             // if it is sometimes not even numeric, since this never signals the fact that it doesn't
    246             // want doubles. https://bugs.webkit.org/show_bug.cgi?id=109511
    247             return false;
    248         }
    249        
    250         // If the variable is predicted to hold only doubles, then it's a
    251         // no-brainer: it should be formatted as a double.
    252         if (isDoubleSpeculation(prediction()))
    253             return true;
    254        
    255         // If the variable is known to be used as an integer, then be safe -
    256         // don't force it to be a double.
    257         if (flags() & NodeBytecodeUsesAsInt)
    258             return false;
    259        
    260         // If the variable has been voted to become a double, then make it a
    261         // double.
    262         if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat())
    263             return true;
    264        
    265         return false;
    266     }
     184    bool shouldUseDoubleFormatAccordingToVote();
    267185   
    268186    DoubleFormatState doubleFormatState()
     
    280198    }
    281199   
    282     bool tallyVotesForShouldUseDoubleFormat()
    283     {
    284         ASSERT(isRoot());
    285        
    286         if (local().isArgument() || shouldNeverUnbox())
    287             return DFG::mergeDoubleFormatState(m_doubleFormatState, NotUsingDoubleFormat);
    288        
    289         if (m_doubleFormatState == CantUseDoubleFormat)
    290             return false;
    291        
    292         bool newValueOfShouldUseDoubleFormat = shouldUseDoubleFormatAccordingToVote();
    293         if (!newValueOfShouldUseDoubleFormat) {
    294             // We monotonically convert to double. Hence, if the fixpoint leads us to conclude that we should
    295             // switch back to int, we instead ignore this and stick with double.
    296             return false;
    297         }
    298        
    299         if (m_doubleFormatState == UsingDoubleFormat)
    300             return false;
    301        
    302         return DFG::mergeDoubleFormatState(m_doubleFormatState, UsingDoubleFormat);
    303     }
    304    
    305     bool mergeDoubleFormatState(DoubleFormatState doubleFormatState)
    306     {
    307         return DFG::mergeDoubleFormatState(find()->m_doubleFormatState, doubleFormatState);
    308     }
    309    
    310     bool makePredictionForDoubleFormat()
    311     {
    312         ASSERT(isRoot());
    313        
    314         if (m_doubleFormatState != UsingDoubleFormat)
    315             return false;
    316        
    317         SpeculatedType type = m_prediction;
    318         if (type & ~SpecBytecodeNumber)
    319             type |= SpecDoublePureNaN;
    320         if (type & SpecMachineInt)
    321             type |= SpecInt52AsDouble;
    322         return checkAndSet(m_prediction, type);
    323     }
     200    bool tallyVotesForShouldUseDoubleFormat();
     201   
     202    bool mergeDoubleFormatState(DoubleFormatState);
     203   
     204    bool makePredictionForDoubleFormat();
    324205   
    325206    NodeFlags flags() const { return m_flags; }
     
    330211    }
    331212   
    332     FlushFormat flushFormat()
    333     {
    334         ASSERT(find() == this);
    335        
    336         if (isArgumentsAlias())
    337             return FlushedArguments;
    338        
    339         if (!shouldUnboxIfPossible())
    340             return FlushedJSValue;
    341        
    342         if (shouldUseDoubleFormat())
    343             return FlushedDouble;
    344        
    345         SpeculatedType prediction = argumentAwarePrediction();
    346         if (isInt32Speculation(prediction))
    347             return FlushedInt32;
    348        
    349         if (enableInt52() && !m_local.isArgument() && isMachineIntSpeculation(prediction))
    350             return FlushedInt52;
    351        
    352         if (isCellSpeculation(prediction))
    353             return FlushedCell;
    354        
    355         if (isBooleanSpeculation(prediction))
    356             return FlushedBoolean;
    357        
    358         return FlushedJSValue;
    359     }
     213    FlushFormat flushFormat();
    360214   
    361215    FlushedAt flushedAt()
     
    390244} } // namespace JSC::DFG
    391245
     246#endif // ENABLE(DFG_JIT)
     247
    392248#endif // DFGVariableAccessData_h
Note: See TracChangeset for help on using the changeset viewer.