]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGPredictionPropagationPhase.cpp
JavaScriptCore-7600.1.4.9.tar.gz
[apple/javascriptcore.git] / dfg / DFGPredictionPropagationPhase.cpp
index 53174604ac1e6cb3ef43898fb5c71963555c597c..6a35b9cbd7edab74dc4cbf3c388e8ab33ecc0a8a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2012, 2013, 2014 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 "JSCInlines.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,123 +52,117 @@ public:
     {
     }
     
-    void run()
+    bool run()
     {
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        m_count = 0;
-#endif
-        // 1) propagate predictions
+        ASSERT(m_graph.m_form == ThreadedCPS);
+        ASSERT(m_graph.m_unificationState == GloballyUnified);
 
+        m_pass = PrimaryPass;
+        propagateToFixpoint();
+        
+        m_pass = RareCasePass;
+        propagateToFixpoint();
+        
+        m_pass = DoubleVotingPass;
         do {
             m_changed = false;
-            
-            // Forward propagation is near-optimal for both topologically-sorted and
-            // DFS-sorted code.
-            propagateForward();
+            doRoundOfDoubleVoting();
             if (!m_changed)
                 break;
-            
-            // Backward propagation reduces the likelihood that pathological code will
-            // cause slowness. Loops (especially nested ones) resemble backward flow.
-            // This pass captures two cases: (1) it detects if the forward fixpoint
-            // found a sound solution and (2) short-circuits backward flow.
             m_changed = false;
-            propagateBackward();
+            propagateForward();
         } while (m_changed);
         
-        // 2) repropagate predictions while doing double voting.
-
+        return true;
+    }
+    
+private:
+    void propagateToFixpoint()
+    {
         do {
             m_changed = false;
-            doRoundOfDoubleVoting();
+            
+            // Forward propagation is near-optimal for both topologically-sorted and
+            // DFS-sorted code.
             propagateForward();
             if (!m_changed)
                 break;
             
+            // Backward propagation reduces the likelihood that pathological code will
+            // cause slowness. Loops (especially nested ones) resemble backward flow.
+            // This pass captures two cases: (1) it detects if the forward fixpoint
+            // found a sound solution and (2) short-circuits backward flow.
             m_changed = false;
-            doRoundOfDoubleVoting();
             propagateBackward();
         } while (m_changed);
     }
     
-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;
+        SpeculatedType result = SpecDoubleReal;
+        if (value & SpecDoubleImpureNaN)
+            result |= SpecDoubleImpureNaN;
+        if (value & SpecDoublePureNaN)
+            result |= SpecDoublePureNaN;
+        if (!isFullNumberOrBooleanSpeculation(value))
+            result |= SpecDoublePureNaN;
+        return result;
     }
-    
-    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));
-#endif
-        
         bool changed = false;
         
         switch (op) {
         case JSConstant:
         case WeakJSConstant: {
-            changed |= setPrediction(predictionFromValue(m_graph.valueOfJSConstant(m_compileIndex)));
+            SpeculatedType type = speculationFromValue(m_graph.valueOfJSConstant(node));
+            if (type == SpecInt52AsDouble && enableInt52())
+                type = SpecInt52;
+            changed |= setPrediction(type);
             break;
         }
             
         case GetLocal: {
-            VariableAccessData* variableAccessData = node.variableAccessData();
-            PredictedType prediction = variableAccessData->prediction();
+            VariableAccessData* variable = node->variableAccessData();
+            SpeculatedType prediction = variable->prediction();
+            if (!variable->couldRepresentInt52() && (prediction & SpecInt52))
+                prediction = (prediction | SpecInt52AsDouble) & ~SpecInt52;
             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 +171,182 @@ 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);
-            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 MultiGetByOffset:
+        case Call:
+        case Construct:
+        case GetGlobalVar:
+        case GetClosureVar: {
+            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);
+            // FIXME: Support Int52.
+            // https://bugs.webkit.org/show_bug.cgi?id=125704
+            if (node->canSpeculateInt32(m_pass))
+                changed |= mergePrediction(SpecInt32);
             else
-                changed |= mergePrediction(PredictNumber);
-            
-            changed |= m_graph[node.child1()].mergeFlags(flags);
+                changed |= mergePrediction(SpecBytecodeNumber);
             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 (isFullNumberOrBooleanSpeculationExpectingDefined(left)
+                    && isFullNumberOrBooleanSpeculationExpectingDefined(right)) {
+                    if (m_graph.addSpeculationMode(node, m_pass) != DontSpeculateInt32)
+                        changed |= mergePrediction(SpecInt32);
+                    else if (m_graph.addShouldSpeculateMachineInt(node))
+                        changed |= mergePrediction(SpecInt52);
                     else
-                        changed |= mergePrediction(PredictDouble);
-                } else if (!(left & PredictNumber) || !(right & PredictNumber)) {
+                        changed |= mergePrediction(speculatedDoubleTypeForPredictions(left, right));
+                } else if (
+                    !(left & (SpecFullNumber | SpecBoolean))
+                    || !(right & (SpecFullNumber | SpecBoolean))) {
                     // 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 | SpecBytecodeDouble);
             }
-            
-            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, m_pass) != DontSpeculateInt32)
+                    changed |= mergePrediction(SpecInt32);
+                else if (m_graph.addShouldSpeculateMachineInt(node))
+                    changed |= mergePrediction(SpecInt52);
                 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, m_pass) != DontSpeculateInt32)
+                    changed |= mergePrediction(SpecInt32);
+                else if (m_graph.addShouldSpeculateMachineInt(node))
+                    changed |= mergePrediction(SpecInt52);
                 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 (m_graph.negateShouldSpeculateInteger(node))
-                    changed |= mergePrediction(PredictInt32);
+            if (node->child1()->prediction()) {
+                if (m_graph.negateShouldSpeculateInt32(node, m_pass))
+                    changed |= mergePrediction(SpecInt32);
+                else if (m_graph.negateShouldSpeculateMachineInt(node, m_pass))
+                    changed |= mergePrediction(SpecInt52);
                 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::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+                    && node->canSpeculateInt32(m_pass))
+                    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.mulShouldSpeculateInt32(node, m_pass))
+                    changed |= mergePrediction(SpecInt32);
+                else if (m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+                    changed |= mergePrediction(SpecInt52);
+                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::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+                    && node->canSpeculateInt32(m_pass))
+                    changed |= mergePrediction(SpecInt32);
                 else
-                    changed |= mergePrediction(PredictDouble);
+                    changed |= mergePrediction(SpecBytecodeDouble);
             }
-
-            // 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::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node())
+                    && node->canSpeculateInt32(m_pass))
+                    changed |= mergePrediction(SpecInt32);
+                else
+                    changed |= mergePrediction(SpecBytecodeDouble);
+            }
             break;
         }
             
-        case ArithSqrt: {
-            changed |= setPrediction(PredictDouble);
-            changed |= m_graph[node.child1()].mergeFlags(flags | NodeUsedAsValue);
+        case ArithSqrt:
+        case ArithFRound:
+        case ArithSin:
+        case ArithCos: {
+            changed |= setPrediction(SpecBytecodeDouble);
             break;
         }
             
         case ArithAbs: {
-            PredictedType child = m_graph[node.child1()].prediction();
-            if (nodeCanSpeculateInteger(node.arithNodeFlags()))
-                changed |= mergePrediction(child);
+            SpeculatedType child = node->child1()->prediction();
+            if (isInt32OrBooleanSpeculationForArithmetic(child)
+                && node->canSpeculateInt32(m_pass))
+                changed |= mergePrediction(SpecInt32);
             else
-                changed |= setPrediction(PredictDouble);
-
-            flags &= ~NodeNeedsNegZero;
-            changed |= m_graph[node.child1()].mergeFlags(flags);
+                changed |= mergePrediction(speculatedDoubleTypeForPrediction(child));
             break;
         }
             
@@ -378,6 +356,7 @@ private:
         case CompareGreater:
         case CompareGreaterEq:
         case CompareEq:
+        case CompareEqConstant:
         case CompareStrictEq:
         case InstanceOf:
         case IsUndefined:
@@ -386,455 +365,483 @@ 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 GetByVal: {
+            if (!node->child1()->prediction())
+                break;
             
-        case GetByIdFlush:
-            changed |= mergePrediction(node.getHeapPrediction());
-            changed |= mergeDefaultFlags(node);
-            break;
+            ArrayMode arrayMode = node->arrayMode().refine(
+                m_graph, node,
+                node->child1()->prediction(),
+                node->child2()->prediction(),
+                SpecNone, node->flags());
             
-        case GetByVal: {
-            if (m_graph[node.child1()].shouldSpeculateFloat32Array()
-                || m_graph[node.child1()].shouldSpeculateFloat64Array())
-                changed |= mergePrediction(PredictDouble);
-            else
-                changed |= mergePrediction(node.getHeapPrediction());
-
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+            switch (arrayMode.type()) {
+            case Array::Double:
+                if (arrayMode.isOutOfBounds())
+                    changed |= mergePrediction(node->getHeapPrediction() | SpecDoubleReal);
+                else
+                    changed |= mergePrediction(SpecDoubleReal);
+                break;
+            case Array::Float32Array:
+            case Array::Float64Array:
+                changed |= mergePrediction(SpecFullDouble);
+                break;
+            case Array::Uint32Array:
+                if (isInt32Speculation(node->getHeapPrediction()))
+                    changed |= mergePrediction(SpecInt32);
+                else if (enableInt52())
+                    changed |= mergePrediction(SpecMachineInt);
+                else
+                    changed |= mergePrediction(SpecInt32 | SpecInt52AsDouble);
+                break;
+            default:
+                changed |= mergePrediction(node->getHeapPrediction());
+                break;
+            }
             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);
+        case GetClosureRegisters:            
+        case GetButterfly: 
+        case GetIndexedPropertyStorage:
+        case AllocatePropertyStorage:
+        case ReallocatePropertyStorage: {
+            changed |= setPrediction(SpecOther);
             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);
-            }
-            break;
-        }
-            
-        case ConvertThis: {
-            PredictedType prediction = m_graph[node.child1()].prediction();
+
+        case ToThis: {
+            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());
+        case GetMyScope:
+        case SkipTopScope:
+        case SkipScope: {
+            changed |= setPrediction(SpecObjectOther);
             break;
         }
             
-        case PutGlobalVar: {
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+        case GetCallee: {
+            changed |= setPrediction(SpecFunction);
             break;
         }
             
-        case GetScopedVar:
-        case Resolve:
-        case ResolveBase:
-        case ResolveBaseStrictPut:
-        case ResolveGlobal: {
-            PredictedType prediction = node.getHeapPrediction();
-            changed |= mergePrediction(prediction);
+        case CreateThis:
+        case NewObject: {
+            changed |= setPrediction(SpecFinalObject);
             break;
         }
             
-        case GetScopeChain: {
-            changed |= setPrediction(PredictCellOther);
+        case NewArray:
+        case NewArrayWithSize:
+        case NewArrayBuffer: {
+            changed |= setPrediction(SpecArray);
             break;
         }
             
-        case GetCallee: {
-            changed |= setPrediction(PredictFunction);
+        case NewTypedArray: {
+            changed |= setPrediction(speculationFromTypedArrayType(node->typedArrayType()));
             break;
         }
             
-        case CreateThis:
-        case NewObject: {
-            changed |= setPrediction(PredictFinalObject);
-            changed |= mergeDefaultFlags(node);
+        case NewRegexp:
+        case CreateActivation: {
+            changed |= setPrediction(SpecObjectOther);
             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);
-            }
+        
+        case StringFromCharCode: {
+            changed |= setPrediction(SpecString);
+            changed |= node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt);            
             break;
         }
-            
-        case NewArrayBuffer: {
-            changed |= setPrediction(PredictArray);
+        case StringCharAt:
+        case ToString:
+        case MakeRope: {
+            changed |= setPrediction(SpecString);
             break;
         }
             
-        case NewRegexp: {
-            changed |= setPrediction(PredictObjectOther);
-            break;
-        }
-        
-        case StringCharAt: {
-            changed |= setPrediction(PredictString);
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt);
+        case ToPrimitive: {
+            SpeculatedType child = node->child1()->prediction();
+            if (child)
+                changed |= mergePrediction(resultOfToPrimitive(child));
             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 NewStringObject: {
+            changed |= setPrediction(SpecStringObject);
             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);
+        case CreateArguments: {
+            changed |= setPrediction(SpecArguments);
             break;
         }
             
-        case CreateActivation: {
-            changed |= setPrediction(PredictObjectOther);
+        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 FiatInt52: {
+            RELEASE_ASSERT(enableInt52());
+            changed |= setPrediction(SpecMachineInt);
+            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 GetTypedArrayByteOffset:
+        case DoubleAsInt32:
+        case GetLocalUnlinked:
+        case GetMyArgumentsLength:
+        case GetMyArgumentByVal:
+        case PhantomPutStructure:
+        case PhantomArguments:
+        case CheckArray:
+        case Arrayify:
+        case ArrayifyToStructure:
+        case CheckTierUpInLoop:
+        case CheckTierUpAtReturn:
+        case CheckTierUpAndOSREnter:
+        case InvalidationPoint:
+        case CheckInBounds:
+        case ValueToInt32:
+        case HardPhantom:
+        case DoubleRep:
+        case ValueRep:
+        case Int52Rep:
+        case DoubleConstant:
+        case Int52Constant:
+        case Identity:
+        case BooleanToNumber: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
-            ASSERT_NOT_REACHED();
+            RELEASE_ASSERT_NOT_REACHED();
             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);
-            break;
-
-        case PutScopedVar:
-        case Return:
-        case Throw:
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
+        case Phi:
+            // Phis should not be visible here since we're iterating the all-but-Phi's
+            // part of basic blocks.
+            RELEASE_ASSERT_NOT_REACHED();
             break;
-
-        case PutById:
-        case PutByIdDirect:
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child2()].mergeFlags(NodeUsedAsValue);
+            
+        case Upsilon:
+        case GetArgument:
+            // These don't get inserted until we go into SSA.
+            RELEASE_ASSERT_NOT_REACHED();
             break;
 
-        case PutByOffset:
-            changed |= m_graph[node.child1()].mergeFlags(NodeUsedAsValue);
-            changed |= m_graph[node.child3()].mergeFlags(NodeUsedAsValue);
+        case GetScope:
+            changed |= setPrediction(SpecObjectOther);
             break;
             
-        case Phi:
+        case In:
+            changed |= setPrediction(SpecBoolean);
             break;
 
 #ifndef NDEBUG
         // These get ignored because they don't return anything.
+        case StoreBarrier:
+        case StoreBarrierWithNullCheck:
+        case PutByValDirect:
+        case PutByVal:
+        case PutClosureVar:
+        case Return:
+        case Throw:
+        case PutById:
+        case PutByIdFlush:
+        case PutByIdDirect:
+        case PutByOffset:
+        case MultiPutByOffset:
         case DFG::Jump:
         case Branch:
+        case Switch:
         case Breakpoint:
+        case ProfileWillCall:
+        case ProfileDidCall:
         case CheckHasInstance:
         case ThrowReferenceError:
         case ForceOSRExit:
         case SetArgument:
         case CheckStructure:
+        case CheckExecutable:
+        case StructureTransitionWatchpoint:
         case CheckFunction:
         case PutStructure:
         case TearOffActivation:
-        case CheckNumber:
-            changed |= mergeDefaultFlags(node);
+        case TearOffArguments:
+        case CheckArgumentsNotCreated:
+        case VariableWatchpoint:
+        case VarInjectionWatchpoint:
+        case AllocationProfileWatchpoint:
+        case Phantom:
+        case Check:
+        case PutGlobalVar:
+        case CheckWatchdogTimer:
+        case Unreachable:
+        case LoopHint:
+        case NotifyWrite:
+        case FunctionReentryWatchpoint:
+        case TypedArrayWatchpoint:
+        case ConstantStoragePointer:
+        case MovHint:
+        case ZombieHint:
+            break;
+            
+        // This gets ignored because it already has a prediction.
+        case ExtractOSREntryLocal:
             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();
+            RELEASE_ASSERT_NOT_REACHED();
             break;
 #else
         default:
-            changed |= mergeDefaultFlags(node);
             break;
 #endif
         }
 
-#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
-        dataLog("%s\n", predictionToString(m_graph[m_compileIndex].prediction()));
-#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);
-#endif
-        for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
-            propagate(m_graph[m_compileIndex]);
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            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);
-#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.numBlocks(); blockIndex--;) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            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, float weight)
     {
-        if (node.flags() & NodeHasVarArgs) {
-            for (unsigned childIdx = node.firstChild();
-                 childIdx < node.firstChild() + node.numChildren();
-                 childIdx++)
-                vote(m_graph.m_varArgChildren[childIdx], ballot);
-            return;
-        }
+        // Loop pre-headers created by OSR entrypoint creation may have NaN weight to indicate
+        // that we actually don't know they weight. Assume that they execute once. This turns
+        // out to be an OK assumption since the pre-header doesn't have any meaningful code.
+        if (weight != weight)
+            weight = 1;
         
-        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();
+        switch (node->op()) {
+        case ValueAdd:
+        case ArithAdd:
+        case ArithSub: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
                 
-                VariableAccessData::Ballot ballot;
+            DoubleBallot ballot;
                 
-                if (isNumberPrediction(left) && isNumberPrediction(right)
-                    && !m_graph.addShouldSpeculateInteger(node))
-                    ballot = VariableAccessData::VoteDouble;
-                else
-                    ballot = VariableAccessData::VoteValue;
+            if (isFullNumberSpeculation(left)
+                && isFullNumberSpeculation(right)
+                && !m_graph.addShouldSpeculateInt32(node, m_pass)
+                && !m_graph.addShouldSpeculateMachineInt(node))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
                 
-                vote(node.child1(), ballot);
-                vote(node.child2(), ballot);
-                break;
-            }
+            m_graph.voteNode(node->child1(), ballot, weight);
+            m_graph.voteNode(node->child2(), ballot, weight);
+            break;
+        }
                 
-            case ArithMul:
-            case ArithMin:
-            case ArithMax:
-            case ArithMod:
-            case ArithDiv: {
-                PredictedType left = m_graph[node.child1()].prediction();
-                PredictedType right = m_graph[node.child2()].prediction();
+        case ArithMul: {
+            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 (isFullNumberSpeculation(left)
+                && isFullNumberSpeculation(right)
+                && !m_graph.mulShouldSpeculateInt32(node, m_pass)
+                && !m_graph.mulShouldSpeculateMachineInt(node, m_pass))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
                 
-                vote(node.child1(), ballot);
-                vote(node.child2(), ballot);
-                break;
-            }
+            m_graph.voteNode(node->child1(), ballot, weight);
+            m_graph.voteNode(node->child2(), ballot, weight);
+            break;
+        }
+
+        case ArithMin:
+        case ArithMax:
+        case ArithMod:
+        case ArithDiv: {
+            SpeculatedType left = node->child1()->prediction();
+            SpeculatedType right = node->child2()->prediction();
                 
-            case ArithAbs:
-                VariableAccessData::Ballot ballot;
-                if (!(m_graph[node.child1()].shouldSpeculateInteger()
-                      && node.canSpeculateInteger()))
-                    ballot = VariableAccessData::VoteDouble;
-                else
-                    ballot = VariableAccessData::VoteValue;
+            DoubleBallot ballot;
                 
-                vote(node.child1(), ballot);
-                break;
+            if (isFullNumberSpeculation(left)
+                && isFullNumberSpeculation(right)
+                && !(Node::shouldSpeculateInt32OrBooleanForArithmetic(node->child1().node(), node->child2().node()) && node->canSpeculateInt32(m_pass)))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
                 
-            case ArithSqrt:
-                vote(node.child1(), VariableAccessData::VoteDouble);
-                break;
+            m_graph.voteNode(node->child1(), ballot, weight);
+            m_graph.voteNode(node->child2(), ballot, weight);
+            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 ArithAbs:
+            DoubleBallot ballot;
+            if (node->child1()->shouldSpeculateNumber()
+                && !(node->child1()->shouldSpeculateInt32OrBooleanForArithmetic() && node->canSpeculateInt32(m_pass)))
+                ballot = VoteDouble;
+            else
+                ballot = VoteValue;
                 
+            m_graph.voteNode(node->child1(), ballot, weight);
+            break;
+                
+        case ArithSqrt:
+        case ArithCos:
+        case ArithSin:
+            if (node->child1()->shouldSpeculateNumber())
+                m_graph.voteNode(node->child1(), VoteDouble, weight);
+            else
+                m_graph.voteNode(node->child1(), VoteValue, weight);
+            break;
+                
+        case SetLocal: {
+            SpeculatedType prediction = node->child1()->prediction();
+            if (isDoubleSpeculation(prediction))
+                node->variableAccessData()->vote(VoteDouble, weight);
+            else if (
+                !isFullNumberSpeculation(prediction)
+                || isInt32Speculation(prediction) || isMachineIntSpeculation(prediction))
+                node->variableAccessData()->vote(VoteValue, weight);
+            break;
+        }
+
+        case PutByValDirect:
+        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, weight);
+            m_graph.voteNode(child2, VoteValue, weight);
+            switch (node->arrayMode().type()) {
+            case Array::Double:
+                m_graph.voteNode(child3, VoteDouble, weight);
+                break;
             default:
-                vote(node, VariableAccessData::VoteValue);
+                m_graph.voteNode(child3, VoteValue, weight);
                 break;
             }
+            break;
+        }
+            
+        case MovHint:
+            // Ignore these since they have no effect on in-DFG execution.
+            break;
+            
+        default:
+            m_graph.voteChildren(node, VoteValue, weight);
+            break;
+        }
+    }
+    
+    void doRoundOfDoubleVoting()
+    {
+        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.numBlocks(); ++blockIndex) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
+                continue;
+            ASSERT(block->isReachable);
+            for (unsigned i = 0; i < block->size(); ++i) {
+                m_currentNode = block->at(i);
+                doDoubleVoting(m_currentNode, block->executionCount);
+            }
         }
         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)
-    unsigned m_count;
-#endif
+    PredictionPass m_pass; // We use different logic for considering predictions depending on how far along we are in propagation.
 };
     
-void performPredictionPropagation(Graph& graph)
+bool performPredictionPropagation(Graph& graph)
 {
-    runPhase<PredictionPropagationPhase>(graph);
+    SamplingRegion samplingRegion("DFG Prediction Propagation Phase");
+    return runPhase<PredictionPropagationPhase>(graph);
 }
 
 } } // namespace JSC::DFG