]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGPredictionPropagationPhase.cpp
JavaScriptCore-1218.tar.gz
[apple/javascriptcore.git] / dfg / DFGPredictionPropagationPhase.cpp
index 53174604ac1e6cb3ef43898fb5c71963555c597c..356adb5ec3e33ca270f732561b0cf90f06b165e1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #include "DFGGraph.h"
 #include "DFGPhase.h"
+#include "Operations.h"
 
 namespace JSC { namespace DFG {
 
+SpeculatedType resultOfToPrimitive(SpeculatedType type)
+{
+    if (type & SpecObject) {
+        // Objects get turned into strings. So if the input has hints of objectness,
+        // the output will have hinsts of stringiness.
+        return mergeSpeculations(type & ~SpecObject, SpecString);
+    }
+    
+    return type;
+}
+
 class PredictionPropagationPhase : public Phase {
 public:
     PredictionPropagationPhase(Graph& graph)
@@ -40,8 +52,11 @@ public:
     {
     }
     
-    void run()
+    bool run()
     {
+        ASSERT(m_graph.m_form == ThreadedCPS);
+        ASSERT(m_graph.m_unificationState == GloballyUnified);
+        
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
         m_count = 0;
 #endif
@@ -69,62 +84,56 @@ public:
         do {
             m_changed = false;
             doRoundOfDoubleVoting();
-            propagateForward();
             if (!m_changed)
                 break;
-            
             m_changed = false;
-            doRoundOfDoubleVoting();
-            propagateBackward();
+            propagateForward();
         } while (m_changed);
+        
+        return true;
     }
     
 private:
-    bool setPrediction(PredictedType prediction)
+    bool setPrediction(SpeculatedType prediction)
     {
-        ASSERT(m_graph[m_compileIndex].hasResult());
+        ASSERT(m_currentNode->hasResult());
         
         // setPrediction() is used when we know that there is no way that we can change
         // our minds about what the prediction is going to be. There is no semantic
-        // difference between setPrediction() and mergePrediction() other than the
+        // difference between setPrediction() and mergeSpeculation() other than the
         // increased checking to validate this property.
-        ASSERT(m_graph[m_compileIndex].prediction() == PredictNone || m_graph[m_compileIndex].prediction() == prediction);
+        ASSERT(m_currentNode->prediction() == SpecNone || m_currentNode->prediction() == prediction);
         
-        return m_graph[m_compileIndex].predict(prediction);
+        return m_currentNode->predict(prediction);
     }
     
-    bool mergePrediction(PredictedType prediction)
+    bool mergePrediction(SpeculatedType prediction)
     {
-        ASSERT(m_graph[m_compileIndex].hasResult());
+        ASSERT(m_currentNode->hasResult());
         
-        return m_graph[m_compileIndex].predict(prediction);
+        return m_currentNode->predict(prediction);
     }
     
-    bool isNotNegZero(NodeIndex nodeIndex)
+    SpeculatedType speculatedDoubleTypeForPrediction(SpeculatedType value)
     {
-        if (!m_graph.isNumberConstant(nodeIndex))
-            return false;
-        double value = m_graph.valueOfNumberConstant(nodeIndex);
-        return !value && 1.0 / value < 0.0;
+        if (!isNumberSpeculation(value))
+            return SpecDouble;
+        if (value & SpecDoubleNaN)
+            return SpecDouble;
+        return SpecDoubleReal;
     }
-    
-    bool isNotZero(NodeIndex nodeIndex)
+
+    SpeculatedType speculatedDoubleTypeForPredictions(SpeculatedType left, SpeculatedType right)
     {
-        if (!m_graph.isNumberConstant(nodeIndex))
-            return false;
-        return !!m_graph.valueOfNumberConstant(nodeIndex);
+        return speculatedDoubleTypeForPrediction(mergeSpeculations(left, right));
     }
-    
-    void propagate(Node& node)
+
+    void propagate(Node* node)
     {
-        if (!node.shouldGenerate())
-            return;
-        
-        NodeType op = node.op();
-        NodeFlags flags = node.flags() & NodeBackPropMask;
+        NodeType op = node->op();
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("   %s @%u: %s ", Graph::opName(op), m_compileIndex, nodeFlagsAsString(flags));
+        dataLog("   ", Graph::opName(op), " ", m_currentNode, ": ", NodeFlagsDump(node->flags()), " ");
 #endif
         
         bool changed = false;
@@ -132,31 +141,21 @@ private:
         switch (op) {
         case JSConstant:
         case WeakJSConstant: {
-            changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex)));
+            changed |= setPrediction(speculationFromValue(m_graph.valueOfJSConstant(node)));
             break;
         }
             
         case GetLocal: {
-            VariableAccessData* variableAccessData = node.variableAccessData();
-            PredictedType prediction = variableAccessData->prediction();
+            VariableAccessData* variableAccessData = node->variableAccessData();
+            SpeculatedType prediction = variableAccessData->prediction();
             if (prediction)
                 changed |= mergePrediction(prediction);
-            
-            changed |= variableAccessData->mergeFlags(flags);
             break;
         }
             
         case SetLocal: {
-            VariableAccessData* variableAccessData = node.variableAccessData();
-            changed |= variableAccessData->predict(m_graph[node.child1()].prediction());
-            changed |= m_graph[node.child1()].mergeFlags(variableAccessData->flags());
-            break;
-        }
-            
-        case Flush: {
-            // Make sure that the analysis knows that flushed locals escape.
-            VariableAccessData* variableAccessData = node.variableAccessData();
-            changed |= variableAccessData->mergeFlags(NodeUsedAsValue);
+            VariableAccessData* variableAccessData = node->variableAccessData();
+            changed |= variableAccessData->predict(node->child1()->prediction());
             break;
         }
             
@@ -165,210 +164,172 @@ private:
         case BitXor:
         case BitRShift:
         case BitLShift:
-        case BitURShift: {
-            changed |= setPrediction(PredictInt32);
-            flags |= NodeUsedAsInt;
-            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
-            changed |= m_graph[node.child1()].mergeFlags(flags);
-            changed |= m_graph[node.child2()].mergeFlags(flags);
+        case BitURShift:
+        case ArithIMul: {
+            changed |= setPrediction(SpecInt32);
             break;
         }
             
         case ValueToInt32: {
-            changed |= setPrediction(PredictInt32);
-            flags |= NodeUsedAsInt;
-            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero);
-            changed |= m_graph[node.child1()].mergeFlags(flags);
+            changed |= setPrediction(SpecInt32);
             break;
         }
             
-        case ArrayPop: {
-            changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultFlags(node);
-            break;
-        }
-
-        case ArrayPush: {
-            changed |= mergePrediction(node.getHeapPrediction());
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
-            break;
-        }
-
+        case ArrayPop:
+        case ArrayPush:
         case RegExpExec:
-        case RegExpTest: {
-            changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultFlags(node);
+        case RegExpTest:
+        case GetById:
+        case GetByIdFlush:
+        case GetMyArgumentByValSafe:
+        case GetByOffset:
+        case Call:
+        case Construct:
+        case GetGlobalVar:
+        case GetScopedVar:
+        case Resolve:
+        case ResolveBase:
+        case ResolveBaseStrictPut:
+        case ResolveGlobal: {
+            changed |= setPrediction(node->getHeapPrediction());
             break;
         }
 
         case StringCharCodeAt: {
-            changed |= mergePrediction(PredictInt32);
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            changed |= setPrediction(SpecInt32);
             break;
         }
 
-        case ArithMod: {
-            PredictedType left = m_graph[node.child1()].prediction();
-            PredictedType right = m_graph[node.child2()].prediction();
-            
-            if (left && right) {
-                if (isInt32Prediction(mergePredictions(left, right))
-                    && nodeCanSpeculateInteger(node.arithNodeFlags()))
-                    changed |= mergePrediction(PredictInt32);
-                else
-                    changed |= mergePrediction(PredictDouble);
-            }
-            
-            flags |= NodeUsedAsValue;
-            changed |= m_graph[node.child1()].mergeFlags(flags);
-            changed |= m_graph[node.child2()].mergeFlags(flags);
-            break;
-        }
-            
         case UInt32ToNumber: {
-            if (nodeCanSpeculateInteger(node.arithNodeFlags()))
-                changed |= mergePrediction(PredictInt32);
+            if (nodeCanSpeculateInteger(node->arithNodeFlags()))
+                changed |= mergePrediction(SpecInt32);
             else
-                changed |= mergePrediction(PredictNumber);
-            
-            changed |= m_graph[node.child1()].mergeFlags(flags);
+                changed |= mergePrediction(SpecNumber);
             break;
         }
 
         case ValueAdd: {
-            PredictedType left = m_graph[node.child1()].prediction();
-            PredictedType right = m_graph[node.child2()].prediction();
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
             
             if (left && right) {
-                if (isNumberPrediction(left) && isNumberPrediction(right)) {
-                    if (m_graph.addShouldSpeculateInteger(node))
-                        changed |= mergePrediction(PredictInt32);
+                if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)) {
+                    if (m_graph.addSpeculationMode(node) != DontSpeculateInteger)
+                        changed |= mergePrediction(SpecInt32);
                     else
-                        changed |= mergePrediction(PredictDouble);
-                } else if (!(left & PredictNumber) || !(right & PredictNumber)) {
+                        changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+                } else if (!(left & SpecNumber) || !(right & SpecNumber)) {
                     // left or right is definitely something other than a number.
-                    changed |= mergePrediction(PredictString);
+                    changed |= mergePrediction(SpecString);
                 } else
-                    changed |= mergePrediction(PredictString | PredictInt32 | PredictDouble);
+                    changed |= mergePrediction(SpecString | SpecInt32 | SpecDouble);
             }
-            
-            if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
-                flags &= ~NodeNeedsNegZero;
-            
-            changed |= m_graph[node.child1()].mergeFlags(flags);
-            changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
         }
             
         case ArithAdd: {
-            PredictedType left = m_graph[node.child1()].prediction();
-            PredictedType right = m_graph[node.child2()].prediction();
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
             
             if (left && right) {
-                if (m_graph.addShouldSpeculateInteger(node))
-                    changed |= mergePrediction(PredictInt32);
+                if (m_graph.addSpeculationMode(node) != DontSpeculateInteger)
+                    changed |= mergePrediction(SpecInt32);
                 else
-                    changed |= mergePrediction(PredictDouble);
+                    changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
             }
-            
-            if (isNotNegZero(node.child1().index()) || isNotNegZero(node.child2().index()))
-                flags &= ~NodeNeedsNegZero;
-            
-            changed |= m_graph[node.child1()].mergeFlags(flags);
-            changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
         }
             
         case ArithSub: {
-            PredictedType left = m_graph[node.child1()].prediction();
-            PredictedType right = m_graph[node.child2()].prediction();
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
             
             if (left && right) {
-                if (m_graph.addShouldSpeculateInteger(node))
-                    changed |= mergePrediction(PredictInt32);
+                if (m_graph.addSpeculationMode(node) != DontSpeculateInteger)
+                    changed |= mergePrediction(SpecInt32);
                 else
-                    changed |= mergePrediction(PredictDouble);
+                    changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
             }
-
-            if (isNotZero(node.child1().index()) || isNotZero(node.child2().index()))
-                flags &= ~NodeNeedsNegZero;
-            
-            changed |= m_graph[node.child1()].mergeFlags(flags);
-            changed |= m_graph[node.child2()].mergeFlags(flags);
             break;
         }
             
         case ArithNegate:
-            if (m_graph[node.child1()].prediction()) {
+            if (node->child1()->prediction()) {
                 if (m_graph.negateShouldSpeculateInteger(node))
-                    changed |= mergePrediction(PredictInt32);
+                    changed |= mergePrediction(SpecInt32);
                 else
-                    changed |= mergePrediction(PredictDouble);
+                    changed |= mergePrediction(speculatedDoubleTypeForPrediction(node->child1()->prediction()));
             }
-
-            changed |= m_graph[node.child1()].mergeFlags(flags);
             break;
             
         case ArithMin:
         case ArithMax: {
-            PredictedType left = m_graph[node.child1()].prediction();
-            PredictedType right = m_graph[node.child2()].prediction();
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
             
             if (left && right) {
-                if (isInt32Prediction(mergePredictions(left, right))
-                    && nodeCanSpeculateInteger(node.arithNodeFlags()))
-                    changed |= mergePrediction(PredictInt32);
+                if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+                    && nodeCanSpeculateInteger(node->arithNodeFlags()))
+                    changed |= mergePrediction(SpecInt32);
                 else
-                    changed |= mergePrediction(PredictDouble);
+                    changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
             }
+            break;
+        }
 
-            flags |= NodeUsedAsNumber;
-            changed |= m_graph[node.child1()].mergeFlags(flags);
-            changed |= m_graph[node.child2()].mergeFlags(flags);
+        case ArithMul: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
+            
+            if (left && right) {
+                if (m_graph.mulShouldSpeculateInteger(node))
+                    changed |= mergePrediction(SpecInt32);
+                else
+                    changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+            }
             break;
         }
             
-        case ArithMul:
         case ArithDiv: {
-            PredictedType left = m_graph[node.child1()].prediction();
-            PredictedType right = m_graph[node.child2()].prediction();
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
             
             if (left && right) {
-                if (isInt32Prediction(mergePredictions(left, right))
-                    && nodeCanSpeculateInteger(node.arithNodeFlags()))
-                    changed |= mergePrediction(PredictInt32);
+                if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+                    && nodeCanSpeculateInteger(node->arithNodeFlags()))
+                    changed |= mergePrediction(SpecInt32);
                 else
-                    changed |= mergePrediction(PredictDouble);
+                    changed |= mergePrediction(SpecDouble);
             }
-
-            // As soon as a multiply happens, we can easily end up in the part
-            // of the double domain where the point at which you do truncation
-            // can change the outcome. So, ArithMul always checks for overflow
-            // no matter what, and always forces its inputs to check as well.
+            break;
+        }
             
-            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
-            changed |= m_graph[node.child1()].mergeFlags(flags);
-            changed |= m_graph[node.child2()].mergeFlags(flags);
+        case ArithMod: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
+            
+            if (left && right) {
+                if (Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node())
+                    && nodeCanSpeculateInteger(node->arithNodeFlags()))
+                    changed |= mergePrediction(SpecInt32);
+                else
+                    changed |= mergePrediction(SpecDouble);
+            }
             break;
         }
             
         case ArithSqrt: {
-            changed |= setPrediction(PredictDouble);
-            changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
+            changed |= setPrediction(SpecDouble);
             break;
         }
             
         case ArithAbs: {
-            PredictedType child = m_graph[node.child1()].prediction();
-            if (nodeCanSpeculateInteger(node.arithNodeFlags()))
-                changed |= mergePrediction(child);
+            SpeculatedType child = node->child1()->prediction();
+            if (isInt32SpeculationForArithmetic(child)
+                && nodeCanSpeculateInteger(node->arithNodeFlags()))
+                changed |= mergePrediction(SpecInt32);
             else
-                changed |= setPrediction(PredictDouble);
-
-            flags &= ~NodeNeedsNegZero;
-            changed |= m_graph[node.child1()].mergeFlags(flags);
+                changed |= mergePrediction(speculatedDoubleTypeForPrediction(child));
             break;
         }
             
@@ -378,7 +339,9 @@ private:
         case CompareGreater:
         case CompareGreaterEq:
         case CompareEq:
+        case CompareEqConstant:
         case CompareStrictEq:
+        case CompareStrictEqConstant:
         case InstanceOf:
         case IsUndefined:
         case IsBoolean:
@@ -386,228 +349,172 @@ private:
         case IsString:
         case IsObject:
         case IsFunction: {
-            changed |= setPrediction(PredictBoolean);
-            changed |= mergeDefaultFlags(node);
+            changed |= setPrediction(SpecBoolean);
             break;
         }
-            
-        case GetById: {
-            changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultFlags(node);
+
+        case TypeOf: {
+            changed |= setPrediction(SpecString);
             break;
         }
-            
-        case GetByIdFlush:
-            changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultFlags(node);
-            break;
-            
+
         case GetByVal: {
-            if (m_graph[node.child1()].shouldSpeculateFloat32Array()
-                || m_graph[node.child1()].shouldSpeculateFloat64Array())
-                changed |= mergePrediction(PredictDouble);
+            if (node->child1()->shouldSpeculateFloat32Array()
+                || node->child1()->shouldSpeculateFloat64Array())
+                changed |= mergePrediction(SpecDouble);
             else
-                changed |= mergePrediction(node.getHeapPrediction());
-
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+                changed |= mergePrediction(node->getHeapPrediction());
             break;
         }
             
-        case GetPropertyStorage: 
-        case GetIndexedPropertyStorage: {
-            changed |= setPrediction(PredictOther);
-            changed |= mergeDefaultFlags(node);
+        case GetMyArgumentsLengthSafe: {
+            changed |= setPrediction(SpecInt32);
             break;
         }
 
-        case GetByOffset: {
-            changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultFlags(node);
-            break;
-        }
-            
-        case Call:
-        case Construct: {
-            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);
-            }
+        case GetScopeRegisters:            
+        case GetButterfly: 
+        case GetIndexedPropertyStorage:
+        case AllocatePropertyStorage:
+        case ReallocatePropertyStorage: {
+            changed |= setPrediction(SpecOther);
             break;
         }
-            
+
         case ConvertThis: {
-            PredictedType prediction = m_graph[node.child1()].prediction();
+            SpeculatedType prediction = node->child1()->prediction();
             if (prediction) {
-                if (prediction & ~PredictObjectMask) {
-                    prediction &= PredictObjectMask;
-                    prediction = mergePredictions(prediction, PredictObjectOther);
+                if (prediction & ~SpecObject) {
+                    prediction &= SpecObject;
+                    prediction = mergeSpeculations(prediction, SpecObjectOther);
                 }
                 changed |= mergePrediction(prediction);
             }
-            changed |= mergeDefaultFlags(node);
-            break;
-        }
-            
-        case GetGlobalVar: {
-            changed |= mergePrediction(node.getHeapPrediction());
-            break;
-        }
-            
-        case PutGlobalVar: {
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            break;
-        }
-            
-        case GetScopedVar:
-        case Resolve:
-        case ResolveBase:
-        case ResolveBaseStrictPut:
-        case ResolveGlobal: {
-            PredictedType prediction = node.getHeapPrediction();
-            changed |= mergePrediction(prediction);
             break;
         }
             
-        case GetScopeChain: {
-            changed |= setPrediction(PredictCellOther);
+        case GetMyScope:
+        case SkipTopScope:
+        case SkipScope: {
+            changed |= setPrediction(SpecObjectOther);
             break;
         }
             
         case GetCallee: {
-            changed |= setPrediction(PredictFunction);
+            changed |= setPrediction(SpecFunction);
             break;
         }
             
         case CreateThis:
         case NewObject: {
-            changed |= setPrediction(PredictFinalObject);
-            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);
-            }
+            changed |= setPrediction(SpecFinalObject);
             break;
         }
             
+        case NewArray:
+        case NewArrayWithSize:
         case NewArrayBuffer: {
-            changed |= setPrediction(PredictArray);
+            changed |= setPrediction(SpecArray);
             break;
         }
             
-        case NewRegexp: {
-            changed |= setPrediction(PredictObjectOther);
+        case NewRegexp:
+        case CreateActivation: {
+            changed |= setPrediction(SpecObjectOther);
             break;
         }
         
-        case StringCharAt: {
-            changed |= setPrediction(PredictString);
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+        case StringFromCharCode: {
+            changed |= setPrediction(SpecString);
+            changed |= node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);            
             break;
         }
-            
-        case StrCat: {
-            changed |= setPrediction(PredictString);
-            for (unsigned childIdx = node.firstChild();
-                 childIdx < node.firstChild() + node.numChildren();
-                 ++childIdx)
-                changed |= m_graph[m_graph.m_varArgChildren[childIdx]].mergeFlags(NodeUsedAsNumber);
+        case StringCharAt:
+        case ToString:
+        case MakeRope: {
+            changed |= setPrediction(SpecString);
             break;
         }
             
         case ToPrimitive: {
-            PredictedType child = m_graph[node.child1()].prediction();
-            if (child) {
-                if (isObjectPrediction(child)) {
-                    // I'd love to fold this case into the case below, but I can't, because
-                    // removing PredictObjectMask from something that only has an object
-                    // prediction and nothing else means we have an ill-formed PredictedType
-                    // (strong predict-none). This should be killed once we remove all traces
-                    // of static (aka weak) predictions.
-                    changed |= mergePrediction(PredictString);
-                } 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));
-                } else
-                    changed |= mergePrediction(child);
-            }
-            changed |= m_graph[node.child1()].mergeFlags(flags);
+            SpeculatedType child = node->child1()->prediction();
+            if (child)
+                changed |= mergePrediction(resultOfToPrimitive(child));
             break;
         }
             
-        case CreateActivation: {
-            changed |= setPrediction(PredictObjectOther);
+        case NewStringObject: {
+            changed |= setPrediction(SpecStringObject);
+            break;
+        }
+            
+        case CreateArguments: {
+            changed |= setPrediction(SpecArguments);
+            break;
+        }
+            
+        case NewFunction: {
+            SpeculatedType child = node->child1()->prediction();
+            if (child & SpecEmpty)
+                changed |= mergePrediction((child & ~SpecEmpty) | SpecFunction);
+            else
+                changed |= mergePrediction(child);
             break;
         }
             
-        case NewFunction:
         case NewFunctionNoCheck:
         case NewFunctionExpression: {
-            changed |= setPrediction(PredictFunction);
+            changed |= setPrediction(SpecFunction);
             break;
         }
             
         case PutByValAlias:
         case GetArrayLength:
-        case GetInt8ArrayLength:
-        case GetInt16ArrayLength:
-        case GetInt32ArrayLength:
-        case GetUint8ArrayLength:
-        case GetUint8ClampedArrayLength:
-        case GetUint16ArrayLength:
-        case GetUint32ArrayLength:
-        case GetFloat32ArrayLength:
-        case GetFloat64ArrayLength:
-        case GetStringLength:
         case Int32ToDouble:
-        case DoubleAsInt32: {
+        case ForwardInt32ToDouble:
+        case DoubleAsInt32:
+        case GetLocalUnlinked:
+        case GetMyArgumentsLength:
+        case GetMyArgumentByVal:
+        case PhantomPutStructure:
+        case PhantomArguments:
+        case CheckArray:
+        case Arrayify:
+        case ArrayifyToStructure:
+        case MovHint:
+        case MovHintAndCheck:
+        case ZombieHint: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
-            ASSERT_NOT_REACHED();
+            CRASH();
             break;
         }
         
-        case PutByVal:
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
-            changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
+        case Phi:
+            // Phis should not be visible here since we're iterating the all-but-Phi's
+            // part of basic blocks.
+            CRASH();
             break;
 
-        case PutScopedVar:
-        case Return:
-        case Throw:
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+        case GetScope:
+            changed |= setPrediction(SpecObjectOther);
             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:
+        case Identity:
+            changed |= mergePrediction(node->child1()->prediction());
             break;
 
 #ifndef NDEBUG
         // These get ignored because they don't return anything.
+        case PutByVal:
+        case PutScopedVar:
+        case Return:
+        case Throw:
+        case PutById:
+        case PutByIdDirect:
+        case PutByOffset:
+        case SetCallee:
+        case SetMyScope:
         case DFG::Jump:
         case Branch:
         case Breakpoint:
@@ -616,215 +523,222 @@ private:
         case ForceOSRExit:
         case SetArgument:
         case CheckStructure:
+        case CheckExecutable:
+        case ForwardCheckStructure:
+        case StructureTransitionWatchpoint:
+        case ForwardStructureTransitionWatchpoint:
         case CheckFunction:
         case PutStructure:
         case TearOffActivation:
-        case CheckNumber:
-            changed |= mergeDefaultFlags(node);
+        case TearOffArguments:
+        case CheckArgumentsNotCreated:
+        case GlobalVarWatchpoint:
+        case GarbageValue:
+        case AllocationProfileWatchpoint:
+        case Phantom:
+        case PutGlobalVar:
+        case PutGlobalVarCheck:
+        case CheckWatchdogTimer:
             break;
             
         // These gets ignored because it doesn't do anything.
-        case Phantom:
         case InlineStart:
         case Nop:
+        case CountExecution:
+        case PhantomLocal:
+        case Flush:
             break;
             
         case LastNodeType:
-            ASSERT_NOT_REACHED();
+            CRASH();
             break;
 #else
         default:
-            changed |= mergeDefaultFlags(node);
             break;
 #endif
         }
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction()));
+        dataLog(SpeculationDump(node->prediction()), "\n");
 #endif
         
         m_changed |= changed;
     }
         
-    bool mergeDefaultFlags(Node& node)
-    {
-        bool changed = false;
-        if (node.flags() & NodeHasVarArgs) {
-            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(NodeUsedAsValue);
-            if (!node.child2())
-                return changed;
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
-            if (!node.child3())
-                return changed;
-            changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
-        }
-        return changed;
-    }
-    
     void propagateForward()
     {
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("Propagating predictions forward [%u]\n", ++m_count);
+        dataLogF("Propagating predictions forward [%u]\n", ++m_count);
 #endif
-        for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
-            propagate(m_graph[m_compileIndex]);
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            if (!block)
+                continue;
+            ASSERT(block->isReachable);
+            for (unsigned i = 0; i < block->size(); ++i) {
+                m_currentNode = block->at(i);
+                propagate(m_currentNode);
+            }
+        }
     }
     
     void propagateBackward()
     {
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("Propagating predictions backward [%u]\n", ++m_count);
+        dataLogF("Propagating predictions backward [%u]\n", ++m_count);
 #endif
-        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()) {
-        case ValueToInt32:
-        case UInt32ToNumber:
-            nodeUse = m_graph[nodeUse].child1();
-            break;
-        default:
-            break;
+        for (BlockIndex blockIndex = m_graph.m_blocks.size(); blockIndex--;) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            if (!block)
+                continue;
+            ASSERT(block->isReachable);
+            for (unsigned i = block->size(); i--;) {
+                m_currentNode = block->at(i);
+                propagate(m_currentNode);
+            }
         }
-        
-        if (m_graph[nodeUse].op() == GetLocal)
-            m_graph[nodeUse].variableAccessData()->vote(ballot);
     }
     
-    void vote(Node& node, VariableAccessData::Ballot ballot)
+    void doDoubleVoting(Node* node)
     {
-        if (node.flags() & NodeHasVarArgs) {
-            for (unsigned childIdx = node.firstChild();
-                 childIdx < node.firstChild() + node.numChildren();
-                 childIdx++)
-                vote(m_graph.m_varArgChildren[childIdx], ballot);
-            return;
+        switch (node->op()) {
+        case ValueAdd:
+        case ArithAdd:
+        case ArithSub: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
+                
+            DoubleBallot ballot;
+                
+            if (isNumberSpeculationExpectingDefined(left) && isNumberSpeculationExpectingDefined(right)
+                && !m_graph.addShouldSpeculateInteger(node))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
+                
+            m_graph.voteNode(node->child1(), ballot);
+            m_graph.voteNode(node->child2(), ballot);
+            break;
         }
-        
-        if (!node.child1())
-            return;
-        vote(node.child1(), ballot);
-        if (!node.child2())
-            return;
-        vote(node.child2(), ballot);
-        if (!node.child3())
-            return;
-        vote(node.child3(), ballot);
-    }
-    
-    void doRoundOfDoubleVoting()
-    {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("Voting on double uses of locals [%u]\n", m_count);
-#endif
-        for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
-            m_graph.m_variableAccessData[i].find()->clearVotes();
-        for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex) {
-            Node& node = m_graph[m_compileIndex];
-            switch (node.op()) {
-            case ValueAdd:
-            case ArithAdd:
-            case ArithSub: {
-                PredictedType left = m_graph[node.child1()].prediction();
-                PredictedType right = m_graph[node.child2()].prediction();
                 
-                VariableAccessData::Ballot ballot;
+        case ArithMul: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
                 
-                if (isNumberPrediction(left) && isNumberPrediction(right)
-                    && !m_graph.addShouldSpeculateInteger(node))
-                    ballot = VariableAccessData::VoteDouble;
-                else
-                    ballot = VariableAccessData::VoteValue;
+            DoubleBallot ballot;
                 
-                vote(node.child1(), ballot);
-                vote(node.child2(), ballot);
-                break;
-            }
+            if (isNumberSpeculation(left) && isNumberSpeculation(right)
+                && !m_graph.mulShouldSpeculateInteger(node))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
                 
-            case ArithMul:
-            case ArithMin:
-            case ArithMax:
-            case ArithMod:
-            case ArithDiv: {
-                PredictedType left = m_graph[node.child1()].prediction();
-                PredictedType right = m_graph[node.child2()].prediction();
+            m_graph.voteNode(node->child1(), ballot);
+            m_graph.voteNode(node->child2(), ballot);
+            break;
+        }
+
+        case ArithMin:
+        case ArithMax:
+        case ArithMod:
+        case ArithDiv: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
                 
-                VariableAccessData::Ballot ballot;
+            DoubleBallot ballot;
                 
-                if (isNumberPrediction(left) && isNumberPrediction(right)
-                    && !(Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child1()])
-                         && node.canSpeculateInteger()))
-                    ballot = VariableAccessData::VoteDouble;
-                else
-                    ballot = VariableAccessData::VoteValue;
+            if (isNumberSpeculation(left) && isNumberSpeculation(right)
+                && !(Node::shouldSpeculateIntegerForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInteger()))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
                 
-                vote(node.child1(), ballot);
-                vote(node.child2(), ballot);
-                break;
-            }
+            m_graph.voteNode(node->child1(), ballot);
+            m_graph.voteNode(node->child2(), ballot);
+            break;
+        }
                 
-            case ArithAbs:
-                VariableAccessData::Ballot ballot;
-                if (!(m_graph[node.child1()].shouldSpeculateInteger()
-                      && node.canSpeculateInteger()))
-                    ballot = VariableAccessData::VoteDouble;
-                else
-                    ballot = VariableAccessData::VoteValue;
+        case ArithAbs:
+            DoubleBallot ballot;
+            if (!(node->child1()->shouldSpeculateIntegerForArithmetic() && node->canSpeculateInteger()))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
                 
-                vote(node.child1(), ballot);
-                break;
+            m_graph.voteNode(node->child1(), ballot);
+            break;
                 
-            case ArithSqrt:
-                vote(node.child1(), VariableAccessData::VoteDouble);
-                break;
+        case ArithSqrt:
+            m_graph.voteNode(node->child1(), VoteDouble);
+            break;
                 
-            case SetLocal: {
-                PredictedType prediction = m_graph[node.child1()].prediction();
-                if (isDoublePrediction(prediction))
-                    node.variableAccessData()->vote(VariableAccessData::VoteDouble);
-                else if (!isNumberPrediction(prediction) || isInt32Prediction(prediction))
-                    node.variableAccessData()->vote(VariableAccessData::VoteValue);
-                break;
-            }
+        case SetLocal: {
+            SpeculatedType prediction = node->child1()->prediction();
+            if (isDoubleSpeculation(prediction))
+                node->variableAccessData()->vote(VoteDouble);
+            else if (!isNumberSpeculation(prediction) || isInt32Speculation(prediction))
+                node->variableAccessData()->vote(VoteValue);
+            break;
+        }
                 
+        case PutByVal:
+        case PutByValAlias: {
+            Edge child1 = m_graph.varArgChild(node, 0);
+            Edge child2 = m_graph.varArgChild(node, 1);
+            Edge child3 = m_graph.varArgChild(node, 2);
+            m_graph.voteNode(child1, VoteValue);
+            m_graph.voteNode(child2, VoteValue);
+            switch (node->arrayMode().type()) {
+            case Array::Double:
+                m_graph.voteNode(child3, VoteDouble);
+                break;
             default:
-                vote(node, VariableAccessData::VoteValue);
+                m_graph.voteNode(child3, VoteValue);
                 break;
             }
+            break;
+        }
+            
+        default:
+            m_graph.voteChildren(node, VoteValue);
+            break;
+        }
+    }
+    
+    void doRoundOfDoubleVoting()
+    {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLogF("Voting on double uses of locals [%u]\n", m_count);
+#endif
+        for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i)
+            m_graph.m_variableAccessData[i].find()->clearVotes();
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
+            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+            if (!block)
+                continue;
+            ASSERT(block->isReachable);
+            for (unsigned i = 0; i < block->size(); ++i) {
+                m_currentNode = block->at(i);
+                doDoubleVoting(m_currentNode);
+            }
         }
         for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
             VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
             if (!variableAccessData->isRoot())
                 continue;
-            if (operandIsArgument(variableAccessData->local())
-                || m_graph.isCaptured(variableAccessData->local()))
-                continue;
             m_changed |= variableAccessData->tallyVotesForShouldUseDoubleFormat();
         }
         for (unsigned i = 0; i < m_graph.m_argumentPositions.size(); ++i)
-            m_changed |= m_graph.m_argumentPositions[i].mergeArgumentAwareness();
+            m_changed |= m_graph.m_argumentPositions[i].mergeArgumentPredictionAwareness();
         for (unsigned i = 0; i < m_graph.m_variableAccessData.size(); ++i) {
             VariableAccessData* variableAccessData = &m_graph.m_variableAccessData[i];
             if (!variableAccessData->isRoot())
                 continue;
-            if (operandIsArgument(variableAccessData->local())
-                || m_graph.isCaptured(variableAccessData->local()))
-                continue;
             m_changed |= variableAccessData->makePredictionForDoubleFormat();
         }
     }
     
-    NodeIndex m_compileIndex;
+    Node* m_currentNode;
     bool m_changed;
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
@@ -832,9 +746,10 @@ private:
 #endif
 };
     
-void performPredictionPropagation(Graph& graph)
+bool performPredictionPropagation(Graph& graph)
 {
-    runPhase<PredictionPropagationPhase>(graph);
+    SamplingRegion samplingRegion("DFG Prediction Propagation Phase");
+    return runPhase<PredictionPropagationPhase>(graph);
 }
 
 } } // namespace JSC::DFG