DFG double voting may be overzealous in the case of variables that end up
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Mar 2012 00:46:21 +0000 (00:46 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 25 Mar 2012 00:46:21 +0000 (00:46 +0000)
being used as integers
https://bugs.webkit.org/show_bug.cgi?id=82008

Reviewed by Oliver Hunt.

Cleaned up propagation, making the intent more explicit in most places.
Back-propagate NodeUsedAsInt for cases where a node was used in a context
that is known to strongly prefer integers.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::handleCall):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dumpCodeOrigin):
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(Graph):
* dfg/DFGNodeFlags.cpp:
(JSC::DFG::nodeFlagsAsString):
* dfg/DFGNodeFlags.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::run):
(JSC::DFG::PredictionPropagationPhase::propagate):
(PredictionPropagationPhase):
(JSC::DFG::PredictionPropagationPhase::mergeDefaultFlags):
(JSC::DFG::PredictionPropagationPhase::vote):
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
(JSC::DFG::PredictionPropagationPhase::fixupNode):
* dfg/DFGVariableAccessData.h:
(JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@112015 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGGraph.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGNodeFlags.cpp
Source/JavaScriptCore/dfg/DFGNodeFlags.h
Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp
Source/JavaScriptCore/dfg/DFGVariableAccessData.h

index 177d83bee8321fd0d12582392d5ee4b1e9a47885..81dbaeb044603b97a3833284cdeaf596634dee21 100644 (file)
@@ -1,3 +1,38 @@
+2012-03-23  Filip Pizlo  <fpizlo@apple.com>
+
+        DFG double voting may be overzealous in the case of variables that end up
+        being used as integers
+        https://bugs.webkit.org/show_bug.cgi?id=82008
+
+        Reviewed by Oliver Hunt.
+        
+        Cleaned up propagation, making the intent more explicit in most places.
+        Back-propagate NodeUsedAsInt for cases where a node was used in a context
+        that is known to strongly prefer integers.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::handleCall):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dumpCodeOrigin):
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGGraph.h:
+        (Graph):
+        * dfg/DFGNodeFlags.cpp:
+        (JSC::DFG::nodeFlagsAsString):
+        * dfg/DFGNodeFlags.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::run):
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        (PredictionPropagationPhase):
+        (JSC::DFG::PredictionPropagationPhase::mergeDefaultFlags):
+        (JSC::DFG::PredictionPropagationPhase::vote):
+        (JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
+        (JSC::DFG::PredictionPropagationPhase::fixupNode):
+        * dfg/DFGVariableAccessData.h:
+        (JSC::DFG::VariableAccessData::shouldUseDoubleFormatAccordingToVote):
+
 2012-03-24  Filip Pizlo  <fpizlo@apple.com>
 
         DFG::Node::shouldNotSpeculateInteger() should be eliminated
index 20bd08bb6a3b5a48a42ffb0f8257483febb000e6..af3d96df76db5026799d9bb0e795c7cb1a0cc10b 100644 (file)
@@ -84,13 +84,13 @@ static void printWhiteSpace(unsigned amount)
         dataLog(" ");
 }
 
-void Graph::dumpCodeOrigin(NodeIndex nodeIndex)
+void Graph::dumpCodeOrigin(NodeIndex prevNodeIndex, NodeIndex nodeIndex)
 {
-    if (!nodeIndex)
+    if (prevNodeIndex == NoNode)
         return;
     
     Node& currentNode = at(nodeIndex);
-    Node& previousNode = at(nodeIndex - 1);
+    Node& previousNode = at(prevNodeIndex);
     if (previousNode.codeOrigin.inlineCallFrame == currentNode.codeOrigin.inlineCallFrame)
         return;
     
@@ -131,7 +131,6 @@ void Graph::dump(NodeIndex nodeIndex)
         --refCount;
     }
     
-    dumpCodeOrigin(nodeIndex);
     printWhiteSpace((node.codeOrigin.inlineDepth() - 1) * 2);
 
     // Example/explanation of dataflow dump output
@@ -263,6 +262,7 @@ void Graph::dump(NodeIndex nodeIndex)
 
 void Graph::dump()
 {
+    NodeIndex lastNodeIndex = NoNode;
     for (size_t b = 0; b < m_blocks.size(); ++b) {
         BasicBlock* block = m_blocks[b].get();
         dataLog("Block #%u (bc#%u): %s%s\n", (int)b, block->bytecodeBegin, block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "");
@@ -281,8 +281,11 @@ void Graph::dump()
         dataLog("  var links: ");
         dumpOperands(block->variablesAtHead, WTF::dataFile());
         dataLog("\n");
-        for (size_t i = 0; i < block->size(); ++i)
+        for (size_t i = 0; i < block->size(); ++i) {
+            dumpCodeOrigin(lastNodeIndex, block->at(i));
             dump(block->at(i));
+            lastNodeIndex = block->at(i);
+        }
         dataLog("  vars after: ");
         if (block->cfaHasVisited)
             dumpOperands(block->valuesAtTail, WTF::dataFile());
index f4a8f2c8bf4c37546f4e5f09cb282d045d13e8a4..502896921ea2b0cd0a84124191c37b1f6b9444ab 100644 (file)
@@ -143,7 +143,7 @@ public:
 
     // Dump the code origin of the given node as a diff from the code origin of the
     // preceding node.
-    void dumpCodeOrigin(NodeIndex);
+    void dumpCodeOrigin(NodeIndex, NodeIndex);
 
     BlockIndex blockIndexForBytecodeOffset(Vector<BlockIndex>& blocks, unsigned bytecodeBegin);
 
index bdc7210186b0efa09d8083cecf07abfd75e2ae4a..54e6b69b723f7ec9f7694a7349e36a6ca00f95b7 100644 (file)
@@ -123,6 +123,13 @@ const char* nodeFlagsAsString(NodeFlags flags)
         hasPrinted = true;
     }
     
+    if (flags & NodeUsedAsInt) {
+        if (hasPrinted)
+            ptr.strcat("|");
+        ptr.strcat("UsedAsInt");
+        hasPrinted = true;
+    }
+    
     *ptr++ = 0;
     
     return description;
index cdc21499f2d7c56106fa7fb2f64eb98ba9465a9a..16d76655e0c250f4c77baf3489ee167c3f872749 100644 (file)
@@ -36,23 +36,28 @@ namespace JSC { namespace DFG {
 
 // Entries in the NodeType enum (below) are composed of an id, a result type (possibly none)
 // and some additional informative flags (must generate, is constant, etc).
-#define NodeResultMask             0xF
-#define NodeResultJS               0x1
-#define NodeResultNumber           0x2
-#define NodeResultInt32            0x3
-#define NodeResultBoolean          0x4
-#define NodeResultStorage          0x5
-#define NodeMustGenerate          0x10 // set on nodes that have side effects, and may not trivially be removed by DCE.
-#define NodeHasVarArgs            0x20
-#define NodeClobbersWorld         0x40
-#define NodeMightClobber          0x80
-#define NodeBackPropMask         0x300
-#define NodeUseBottom            0x000
-#define NodeUsedAsNumber         0x100
-#define NodeNeedsNegZero         0x200
-#define NodeBehaviorMask         0xC00
-#define NodeMayOverflow          0x400
-#define NodeMayNegZero           0x800
+#define NodeResultMask              0xF
+#define NodeResultJS                0x1
+#define NodeResultNumber            0x2
+#define NodeResultInt32             0x3
+#define NodeResultBoolean           0x4
+#define NodeResultStorage           0x5
+                                
+#define NodeMustGenerate           0x10 // set on nodes that have side effects, and may not trivially be removed by DCE.
+#define NodeHasVarArgs             0x20
+#define NodeClobbersWorld          0x40
+#define NodeMightClobber           0x80
+                                
+#define NodeBehaviorMask          0x300
+#define NodeMayOverflow           0x100
+#define NodeMayNegZero            0x200
+                                
+#define NodeBackPropMask         0x1C00
+#define NodeUseBottom             0x000
+#define NodeUsedAsNumber          0x400 // The result of this computation may be used in a context that observes fractional results.
+#define NodeNeedsNegZero          0x800 // The result of this computation may be used in a context that observes -0.
+#define NodeUsedAsValue           (NodeUsedAsNumber | NodeNeedsNegZero)
+#define NodeUsedAsInt            0x1000 // The result of this computation is known to be used in a context that prefers, but does not require, integer values.
 
 typedef uint16_t NodeFlags;
 
index 0049dbfa768242c5e18faf20224d19158a5ce736..f54ea7588d9717b9a365860a2103cf65976264f6 100644 (file)
@@ -45,8 +45,8 @@ public:
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         m_count = 0;
 #endif
-        // Two stage process: first propagate predictions, then propagate while doing double voting.
-        
+        // 1) propagate predictions
+
         do {
             m_changed = false;
             
@@ -64,6 +64,8 @@ public:
             propagateBackward();
         } while (m_changed);
         
+        // 2) repropagate predictions while doing double voting.
+
         do {
             m_changed = false;
             doRoundOfDoubleVoting();
@@ -119,14 +121,12 @@ private:
             return;
         
         NodeType op = node.op();
-        NodeFlags flags = node.flags();
+        NodeFlags flags = node.flags() & NodeBackPropMask;
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         dataLog("   %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags));
 #endif
         
-        flags &= NodeBackPropMask;
-        
         bool changed = false;
         
         switch (op) {
@@ -156,7 +156,7 @@ private:
         case Flush: {
             // Make sure that the analysis knows that flushed locals escape.
             VariableAccessData* variableAccessData = node.variableAccessData();
-            variableAccessData->mergeFlags(NodeUsedAsNumber | NodeNeedsNegZero);
+            changed |= variableAccessData->mergeFlags(NodeUsedAsValue);
             break;
         }
             
@@ -165,36 +165,47 @@ private:
         case BitXor:
         case BitRShift:
         case BitLShift:
-        case BitURShift:
+        case BitURShift: {
+            changed |= setPrediction(PredictInt32);
+            flags |= NodeUsedAsInt;
+            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
+            changed |= m_graph[node.child1()].mergeFlags(flags);
+            changed |= m_graph[node.child2()].mergeFlags(flags);
+            break;
+        }
+            
         case ValueToInt32: {
             changed |= setPrediction(PredictInt32);
+            flags |= NodeUsedAsInt;
+            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
+            changed |= m_graph[node.child1()].mergeFlags(flags);
             break;
         }
             
         case ArrayPop: {
-            if (node.getHeapPrediction())
-                changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultFlags(node);
             break;
         }
 
         case ArrayPush: {
-            if (node.getHeapPrediction())
-                changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergePrediction(node.getHeapPrediction());
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
             break;
         }
 
         case RegExpExec:
         case RegExpTest: {
-            if (node.getHeapPrediction())
-                changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultFlags(node);
             break;
         }
 
         case StringCharCodeAt: {
             changed |= mergePrediction(PredictInt32);
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
             break;
         }
 
@@ -203,13 +214,16 @@ private:
             PredictedType right = m_graph[node.child2()].prediction();
             
             if (left && right) {
-                if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags()))
+                if (isInt32Prediction(mergePredictions(left, right))
+                    && nodeCanSpeculateInteger(node.arithNodeFlags()))
                     changed |= mergePrediction(PredictInt32);
                 else
                     changed |= mergePrediction(PredictDouble);
             }
             
-            changed |= mergeDefaultArithFlags(node, flags);
+            flags |= NodeUsedAsValue;
+            changed |= m_graph[node.child1()].mergeFlags(flags);
+            changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
         }
             
@@ -303,7 +317,8 @@ private:
             PredictedType right = m_graph[node.child2()].prediction();
             
             if (left && right) {
-                if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags()))
+                if (isInt32Prediction(mergePredictions(left, right))
+                    && nodeCanSpeculateInteger(node.arithNodeFlags()))
                     changed |= mergePrediction(PredictInt32);
                 else
                     changed |= mergePrediction(PredictDouble);
@@ -321,7 +336,8 @@ private:
             PredictedType right = m_graph[node.child2()].prediction();
             
             if (left && right) {
-                if (isInt32Prediction(mergePredictions(left, right)) && nodeCanSpeculateInteger(node.arithNodeFlags()))
+                if (isInt32Prediction(mergePredictions(left, right))
+                    && nodeCanSpeculateInteger(node.arithNodeFlags()))
                     changed |= mergePrediction(PredictInt32);
                 else
                     changed |= mergePrediction(PredictDouble);
@@ -340,18 +356,16 @@ private:
             
         case ArithSqrt: {
             changed |= setPrediction(PredictDouble);
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
             break;
         }
             
         case ArithAbs: {
             PredictedType child = m_graph[node.child1()].prediction();
-            if (child) {
-                if (nodeCanSpeculateInteger(node.arithNodeFlags()))
-                    changed |= mergePrediction(child);
-                else
-                    changed |= setPrediction(PredictDouble);
-            }
+            if (nodeCanSpeculateInteger(node.arithNodeFlags()))
+                changed |= mergePrediction(child);
+            else
+                changed |= setPrediction(PredictDouble);
 
             flags &= ~NodeNeedsNegZero;
             changed |= m_graph[node.child1()].mergeFlags(flags);
@@ -367,71 +381,55 @@ private:
         case CompareStrictEq:
         case InstanceOf: {
             changed |= setPrediction(PredictBoolean);
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergeDefaultFlags(node);
             break;
         }
             
         case GetById: {
-            if (node.getHeapPrediction())
-                changed |= mergePrediction(node.getHeapPrediction());
-            else if (codeBlock()->identifier(node.identifierNumber()) == globalData().propertyNames->length) {
-                // If there is no prediction from value profiles, check if we might be
-                // able to infer the type ourselves.
-                bool isArray = isArrayPrediction(m_graph[node.child1()].prediction());
-                bool isString = isStringPrediction(m_graph[node.child1()].prediction());
-                bool isByteArray = m_graph[node.child1()].shouldSpeculateByteArray();
-                bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array();
-                bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array();
-                bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array();
-                bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array();
-                bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray();
-                bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array();
-                bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array();
-                bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array();
-                bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array();
-                if (isArray || isString || isByteArray || isInt8Array || isInt16Array || isInt32Array || isUint8Array || isUint8ClampedArray || isUint16Array || isUint32Array || isFloat32Array || isFloat64Array)
-                    changed |= mergePrediction(PredictInt32);
-            }
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultFlags(node);
             break;
         }
             
         case GetByIdFlush:
-            if (node.getHeapPrediction())
-                changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultFlags(node);
             break;
             
         case GetByVal: {
-            if (m_graph[node.child1()].shouldSpeculateFloat32Array() || m_graph[node.child1()].shouldSpeculateFloat64Array())
+            if (m_graph[node.child1()].shouldSpeculateFloat32Array()
+                || m_graph[node.child1()].shouldSpeculateFloat64Array())
                 changed |= mergePrediction(PredictDouble);
-            else if (node.getHeapPrediction())
+            else
                 changed |= mergePrediction(node.getHeapPrediction());
 
-            changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
-            changed |= m_graph[node.child2()].mergeFlags(flags | NodeUsedAsNumber);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
             break;
         }
             
         case GetPropertyStorage: 
         case GetIndexedPropertyStorage: {
             changed |= setPrediction(PredictOther);
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergeDefaultFlags(node);
             break;
         }
 
         case GetByOffset: {
-            if (node.getHeapPrediction())
-                changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergePrediction(node.getHeapPrediction());
+            changed |= mergeDefaultFlags(node);
             break;
         }
             
         case Call:
         case Construct: {
-            if (node.getHeapPrediction())
-                changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergePrediction(node.getHeapPrediction());
+            for (unsigned childIdx = node.firstChild();
+                 childIdx < node.firstChild() + node.numChildren();
+                 ++childIdx) {
+                Edge edge = m_graph.m_varArgChildren[childIdx];
+                changed |= m_graph[edge].mergeFlags(NodeUsedAsValue);
+            }
             break;
         }
             
@@ -444,20 +442,20 @@ private:
                 }
                 changed |= mergePrediction(prediction);
             }
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergeDefaultFlags(node);
             break;
         }
             
         case GetGlobalVar: {
             PredictedType prediction = m_graph.getGlobalVarPrediction(node.varNumber());
-            if (prediction)
-                changed |= mergePrediction(prediction);
+            changed |= mergePrediction(prediction);
             break;
         }
             
         case PutGlobalVar: {
-            changed |= m_graph.predictGlobalVar(node.varNumber(), m_graph[node.child1()].prediction());
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= m_graph.predictGlobalVar(
+                node.varNumber(), m_graph[node.child1()].prediction());
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
             break;
         }
             
@@ -467,8 +465,7 @@ private:
         case ResolveBaseStrictPut:
         case ResolveGlobal: {
             PredictedType prediction = node.getHeapPrediction();
-            if (prediction)
-                changed |= mergePrediction(prediction);
+            changed |= mergePrediction(prediction);
             break;
         }
             
@@ -485,14 +482,23 @@ private:
         case CreateThis:
         case NewObject: {
             changed |= setPrediction(PredictFinalObject);
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergeDefaultFlags(node);
+            break;
+        }
+            
+        case NewArray: {
+            changed |= setPrediction(PredictArray);
+            for (unsigned childIdx = node.firstChild();
+                 childIdx < node.firstChild() + node.numChildren();
+                 ++childIdx) {
+                Edge edge = m_graph.m_varArgChildren[childIdx];
+                changed |= m_graph[edge].mergeFlags(NodeUsedAsValue);
+            }
             break;
         }
             
-        case NewArray:
         case NewArrayBuffer: {
             changed |= setPrediction(PredictArray);
-            changed |= mergeDefaultArithFlags(node, flags);
             break;
         }
             
@@ -501,10 +507,19 @@ private:
             break;
         }
         
-        case StringCharAt:
+        case StringCharAt: {
+            changed |= setPrediction(PredictString);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            break;
+        }
+            
         case StrCat: {
             changed |= setPrediction(PredictString);
-            changed |= mergeDefaultArithFlags(node, flags);
+            for (unsigned childIdx = node.firstChild();
+                 childIdx < node.firstChild() + node.numChildren();
+                 ++childIdx)
+                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber);
             break;
         }
             
@@ -521,7 +536,8 @@ private:
                 } else if (child & PredictObjectMask) {
                     // Objects get turned into strings. So if the input has hints of objectness,
                     // the output will have hinsts of stringiness.
-                    changed |= mergePrediction(mergePredictions(child & ~PredictObjectMask, PredictString));
+                    changed |= mergePrediction(
+                        mergePredictions(child & ~PredictObjectMask, PredictString));
                 } else
                     changed |= mergePrediction(child);
             }
@@ -541,6 +557,7 @@ private:
             break;
         }
             
+        case PutByValAlias:
         case GetArrayLength:
         case GetByteArrayLength:
         case GetInt8ArrayLength:
@@ -560,33 +577,45 @@ private:
         }
         
         case PutByVal:
-            changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
-            changed |= m_graph[node.child2()].mergeFlags(flags | NodeUsedAsNumber);
-            changed |= m_graph[node.child3()].mergeFlags(flags | NodeUsedAsNumber | NodeNeedsNegZero);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
+            break;
+
+        case PutScopedVar:
+        case Return:
+        case Throw:
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            break;
+
+        case PutById:
+        case PutByIdDirect:
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
+            break;
+
+        case PutByOffset:
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+            changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
+            break;
+            
+        case Phi:
             break;
 
 #ifndef NDEBUG
         // These get ignored because they don't return anything.
-        case PutScopedVar:
         case DFG::Jump:
         case Branch:
         case Breakpoint:
-        case Return:
         case CheckHasInstance:
-        case Phi:
-        case Throw:
         case ThrowReferenceError:
         case ForceOSRExit:
         case SetArgument:
-        case PutByValAlias:
-        case PutById:
-        case PutByIdDirect:
         case CheckStructure:
         case CheckFunction:
         case PutStructure:
-        case PutByOffset:
         case TearOffActivation:
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergeDefaultFlags(node);
             break;
             
         // These gets ignored because it doesn't do anything.
@@ -600,7 +629,7 @@ private:
             break;
 #else
         default:
-            changed |= mergeDefaultArithFlags(node, flags);
+            changed |= mergeDefaultFlags(node);
             break;
 #endif
         }
@@ -611,24 +640,25 @@ private:
         
         m_changed |= changed;
     }
-    
-    bool mergeDefaultArithFlags(Node& node, NodeFlags flags)
+        
+    bool mergeDefaultFlags(Node& node)
     {
         bool changed = false;
-        flags |= NodeUsedAsNumber | NodeNeedsNegZero;
         if (node.flags() & NodeHasVarArgs) {
-            for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
-                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(flags);
+            for (unsigned childIdx = node.firstChild();
+                 childIdx < node.firstChild() + node.numChildren();
+                 childIdx++)
+                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsValue);
         } else {
             if (!node.child1())
                 return changed;
-            changed |= m_graph[node.child1()].mergeFlags(flags);
+            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
             if (!node.child2())
                 return changed;
-            changed |= m_graph[node.child2()].mergeFlags(flags);
+            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
             if (!node.child3())
                 return changed;
-            changed |= m_graph[node.child3()].mergeFlags(flags);
+            changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
         }
         return changed;
     }
@@ -650,7 +680,7 @@ private:
         for (m_compileIndex = m_graph.size(); m_compileIndex-- > 0;)
             propagate(m_graph[m_compileIndex]);
     }
-
+    
     void vote(Edge nodeUse, VariableAccessData::Ballot ballot)
     {
         switch (m_graph[nodeUse].op()) {
@@ -669,7 +699,9 @@ private:
     void vote(Node& node, VariableAccessData::Ballot ballot)
     {
         if (node.flags() & NodeHasVarArgs) {
-            for (unsigned childIdx = node.firstChild(); childIdx < node.firstChild() + node.numChildren(); childIdx++)
+            for (unsigned childIdx = node.firstChild();
+                 childIdx < node.firstChild() + node.numChildren();
+                 childIdx++)
                 vote(m_graph.m_varArgChildren[childIdx], ballot);
             return;
         }
@@ -724,7 +756,9 @@ private:
                 
                 VariableAccessData::Ballot ballot;
                 
-                if (isNumberPrediction(left) && isNumberPrediction(right) && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()]) && node.canSpeculateInteger()))
+                if (isNumberPrediction(left) && isNumberPrediction(right)
+                    && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()])
+                         && node.canSpeculateInteger()))
                     ballot = VariableAccessData::VoteDouble;
                 else
                     ballot = VariableAccessData::VoteValue;
@@ -736,7 +770,8 @@ private:
                 
             case ArithAbs:
                 VariableAccessData::Ballot ballot;
-                if (!(m_graph[node.child1()].shouldSpeculateInteger() && node.canSpeculateInteger()))
+                if (!(m_graph[node.child1()].shouldSpeculateInteger()
+                      && node.canSpeculateInteger()))
                     ballot = VariableAccessData::VoteDouble;
                 else
                     ballot = VariableAccessData::VoteValue;
index 98f79b9501a19eda9feb39ee9f06e16eb088b7f1..4c69cccfdf9af4e40b3126c3bd9bf12f57703167 100644 (file)
@@ -104,8 +104,32 @@ public:
     
     bool shouldUseDoubleFormatAccordingToVote()
     {
+        // We don't support this facility for arguments, yet.
         // FIXME: make this work for arguments.
-        return !operandIsArgument(operand()) && ((isNumberPrediction(prediction()) && doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat) || isDoublePrediction(prediction()));
+        if (operandIsArgument(operand()))
+            return false;
+        
+        // If the variable is not a number prediction, then this doesn't
+        // make any sense.
+        if (!isNumberPrediction(prediction()))
+            return false;
+        
+        // If the variable is predicted to hold only doubles, then it's a
+        // no-brainer: it should be formatted as a double.
+        if (isDoublePrediction(prediction()))
+            return true;
+        
+        // If the variable is known to be used as an integer, then be safe -
+        // don't force it to be a double.
+        if (flags() & NodeUsedAsInt)
+            return false;
+        
+        // If the variable has been voted to become a double, then make it a
+        // double.
+        if (doubleVoteRatio() >= Options::doubleVoteRatioForDoubleFormat)
+            return true;
+        
+        return false;
     }
     
     bool shouldUseDoubleFormat()