]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGBackwardsPropagationPhase.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGBackwardsPropagationPhase.cpp
index 2f06646aa72fce701ddbbba0e8ca594cdd2dc15e..2768f611fca8e5f74a2b6364d6591831cdc63886 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
 #include "DFGBasicBlockInlines.h"
 #include "DFGGraph.h"
 #include "DFGPhase.h"
-#include "Operations.h"
+#include "JSCInlines.h"
 
 namespace JSC { namespace DFG {
 
@@ -44,17 +44,21 @@ public:
     
     bool run()
     {
-        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
-            BasicBlock* block = m_graph.m_blocks[blockIndex].get();
-            if (!block)
-                continue;
-            
-            // Prevent a tower of overflowing additions from creating a value that is out of the
-            // safe 2^48 range.
-            m_allowNestedOverflowingAdditions = block->size() < (1 << 16);
-            
-            for (unsigned indexInBlock = block->size(); indexInBlock--;)
-                propagate(block->at(indexInBlock));
+        m_changed = true;
+        while (m_changed) {
+            m_changed = false;
+            for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+                BasicBlock* block = m_graph.block(blockIndex);
+                if (!block)
+                    continue;
+            
+                // Prevent a tower of overflowing additions from creating a value that is out of the
+                // safe 2^48 range.
+                m_allowNestedOverflowingAdditions = block->size() < (1 << 16);
+            
+                for (unsigned indexInBlock = block->size(); indexInBlock--;)
+                    propagate(block->at(indexInBlock));
+            }
         }
         
         return true;
@@ -63,17 +67,17 @@ public:
 private:
     bool isNotNegZero(Node* node)
     {
-        if (!m_graph.isNumberConstant(node))
+        if (!node->isNumberConstant())
             return false;
-        double value = m_graph.valueOfNumberConstant(node);
+        double value = node->asNumber();
         return (value || 1.0 / value > 0.0);
     }
     
     bool isNotPosZero(Node* node)
     {
-        if (!m_graph.isNumberConstant(node))
+        if (!node->isNumberConstant())
             return false;
-        double value = m_graph.valueOfNumberConstant(node);
+        double value = node->asNumber();
         return (value || 1.0 / value < 0.0);
     }
 
@@ -81,7 +85,7 @@ private:
     template<int power>
     bool isWithinPowerOfTwoForConstant(Node* node)
     {
-        JSValue immediateValue = node->valueOfJSConstant(codeBlock());
+        JSValue immediateValue = node->asJSValue();
         if (!immediateValue.isNumber())
             return false;
         double immediate = immediateValue.asNumber();
@@ -91,7 +95,7 @@ private:
     template<int power>
     bool isWithinPowerOfTwoNonRecursive(Node* node)
     {
-        if (node->op() != JSConstant)
+        if (!node->isNumberConstant())
             return false;
         return isWithinPowerOfTwoForConstant<power>(node);
     }
@@ -100,7 +104,9 @@ private:
     bool isWithinPowerOfTwo(Node* node)
     {
         switch (node->op()) {
-        case JSConstant: {
+        case DoubleConstant:
+        case JSConstant:
+        case Int52Constant: {
             return isWithinPowerOfTwoForConstant<power>(node);
         }
             
@@ -114,8 +120,7 @@ private:
             
         case BitOr:
         case BitXor:
-        case BitLShift:
-        case ValueToInt32: {
+        case BitLShift: {
             return power > 31;
         }
             
@@ -125,9 +130,9 @@ private:
                 return true;
             
             Node* shiftAmount = node->child2().node();
-            if (shiftAmount->op() != JSConstant)
+            if (!node->isNumberConstant())
                 return false;
-            JSValue immediateValue = shiftAmount->valueOfJSConstant(codeBlock());
+            JSValue immediateValue = shiftAmount->asJSValue();
             if (!immediateValue.isInt32())
                 return false;
             return immediateValue.asInt32() > 32 - power;
@@ -152,30 +157,31 @@ private:
                 childIdx < node->firstChild() + node->numChildren();
                 childIdx++) {
                 if (!!m_graph.m_varArgChildren[childIdx])
-                    changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeUsedAsValue);
+                    changed |= m_graph.m_varArgChildren[childIdx]->mergeFlags(NodeBytecodeUsesAsValue);
             }
         } else {
             if (!node->child1())
                 return changed;
-            changed |= node->child1()->mergeFlags(NodeUsedAsValue);
+            changed |= node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
             if (!node->child2())
                 return changed;
-            changed |= node->child2()->mergeFlags(NodeUsedAsValue);
+            changed |= node->child2()->mergeFlags(NodeBytecodeUsesAsValue);
             if (!node->child3())
                 return changed;
-            changed |= node->child3()->mergeFlags(NodeUsedAsValue);
+            changed |= node->child3()->mergeFlags(NodeBytecodeUsesAsValue);
         }
         return changed;
     }
     
     void propagate(Node* node)
     {
-        NodeFlags flags = node->flags() & NodeBackPropMask;
+        NodeFlags flags = node->flags() & NodeBytecodeBackPropMask;
         
         switch (node->op()) {
         case GetLocal: {
             VariableAccessData* variableAccessData = node->variableAccessData();
-            variableAccessData->mergeFlags(flags);
+            flags &= ~NodeBytecodeUsesAsInt; // We don't care about cross-block uses-as-int.
+            m_changed |= variableAccessData->mergeFlags(flags);
             break;
         }
             
@@ -183,10 +189,23 @@ private:
             VariableAccessData* variableAccessData = node->variableAccessData();
             if (!variableAccessData->isLoadedFrom())
                 break;
-            node->child1()->mergeFlags(NodeUsedAsValue);
+            flags = variableAccessData->flags();
+            RELEASE_ASSERT(!(flags & ~NodeBytecodeBackPropMask));
+            flags |= NodeBytecodeUsesAsNumber; // Account for the fact that control flow may cause overflows that our modeling can't handle.
+            node->child1()->mergeFlags(flags);
             break;
         }
             
+        case Flush: {
+            VariableAccessData* variableAccessData = node->variableAccessData();
+            m_changed |= variableAccessData->mergeFlags(NodeBytecodeUsesAsValue);
+            break;
+        }
+            
+        case MovHint:
+        case Check:
+            break;
+            
         case BitAnd:
         case BitOr:
         case BitXor:
@@ -194,27 +213,20 @@ private:
         case BitLShift:
         case BitURShift:
         case ArithIMul: {
-            flags |= NodeUsedAsInt;
-            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
+            flags |= NodeBytecodeUsesAsInt;
+            flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther);
+            flags &= ~NodeBytecodeUsesAsArrayIndex;
             node->child1()->mergeFlags(flags);
             node->child2()->mergeFlags(flags);
             break;
         }
             
-        case ValueToInt32: {
-            flags |= NodeUsedAsInt;
-            flags &= ~(NodeUsedAsNumber | NodeNeedsNegZero | NodeUsedAsOther);
-            node->child1()->mergeFlags(flags);
-            break;
-        }
-            
         case StringCharCodeAt: {
-            node->child1()->mergeFlags(NodeUsedAsValue);
-            node->child2()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt);
+            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
+            node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
             break;
         }
             
-        case Identity: 
         case UInt32ToNumber: {
             node->child1()->mergeFlags(flags);
             break;
@@ -222,13 +234,13 @@ private:
 
         case ValueAdd: {
             if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node()))
-                flags &= ~NodeNeedsNegZero;
+                flags &= ~NodeBytecodeNeedsNegZero;
             if (node->child1()->hasNumberResult() || node->child2()->hasNumberResult())
-                flags &= ~NodeUsedAsOther;
+                flags &= ~NodeBytecodeUsesAsOther;
             if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2()))
-                flags |= NodeUsedAsNumber;
+                flags |= NodeBytecodeUsesAsNumber;
             if (!m_allowNestedOverflowingAdditions)
-                flags |= NodeUsedAsNumber;
+                flags |= NodeBytecodeUsesAsNumber;
             
             node->child1()->mergeFlags(flags);
             node->child2()->mergeFlags(flags);
@@ -237,24 +249,31 @@ private:
             
         case ArithAdd: {
             if (isNotNegZero(node->child1().node()) || isNotNegZero(node->child2().node()))
-                flags &= ~NodeNeedsNegZero;
+                flags &= ~NodeBytecodeNeedsNegZero;
             if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2()))
-                flags |= NodeUsedAsNumber;
+                flags |= NodeBytecodeUsesAsNumber;
             if (!m_allowNestedOverflowingAdditions)
-                flags |= NodeUsedAsNumber;
+                flags |= NodeBytecodeUsesAsNumber;
             
             node->child1()->mergeFlags(flags);
             node->child2()->mergeFlags(flags);
             break;
         }
-            
+
+        case ArithClz32: {
+            flags &= ~(NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero | NodeBytecodeUsesAsOther | ~NodeBytecodeUsesAsArrayIndex);
+            flags |= NodeBytecodeUsesAsInt;
+            node->child1()->mergeFlags(flags);
+            break;
+        }
+
         case ArithSub: {
             if (isNotNegZero(node->child1().node()) || isNotPosZero(node->child2().node()))
-                flags &= ~NodeNeedsNegZero;
+                flags &= ~NodeBytecodeNeedsNegZero;
             if (!isWithinPowerOfTwo<32>(node->child1()) && !isWithinPowerOfTwo<32>(node->child2()))
-                flags |= NodeUsedAsNumber;
+                flags |= NodeBytecodeUsesAsNumber;
             if (!m_allowNestedOverflowingAdditions)
-                flags |= NodeUsedAsNumber;
+                flags |= NodeBytecodeUsesAsNumber;
             
             node->child1()->mergeFlags(flags);
             node->child2()->mergeFlags(flags);
@@ -262,7 +281,7 @@ private:
         }
             
         case ArithNegate: {
-            flags &= ~NodeUsedAsOther;
+            flags &= ~NodeBytecodeUsesAsOther;
 
             node->child1()->mergeFlags(flags);
             break;
@@ -278,12 +297,12 @@ private:
             
             if (!isWithinPowerOfTwo<22>(node->child1().node())
                 && !isWithinPowerOfTwo<22>(node->child2().node()))
-                flags |= NodeUsedAsNumber;
+                flags |= NodeBytecodeUsesAsNumber;
             
             node->mergeFlags(flags);
             
-            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
-            flags &= ~NodeUsedAsOther;
+            flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero;
+            flags &= ~NodeBytecodeUsesAsOther;
 
             node->child1()->mergeFlags(flags);
             node->child2()->mergeFlags(flags);
@@ -291,8 +310,8 @@ private:
         }
             
         case ArithDiv: {
-            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
-            flags &= ~NodeUsedAsOther;
+            flags |= NodeBytecodeUsesAsNumber | NodeBytecodeNeedsNegZero;
+            flags &= ~NodeBytecodeUsesAsOther;
 
             node->child1()->mergeFlags(flags);
             node->child2()->mergeFlags(flags);
@@ -300,38 +319,42 @@ private:
         }
             
         case ArithMod: {
-            flags |= NodeUsedAsNumber | NodeNeedsNegZero;
-            flags &= ~NodeUsedAsOther;
+            flags |= NodeBytecodeUsesAsNumber;
+            flags &= ~NodeBytecodeUsesAsOther;
 
             node->child1()->mergeFlags(flags);
-            node->child2()->mergeFlags(flags);
+            node->child2()->mergeFlags(flags & ~NodeBytecodeNeedsNegZero);
             break;
         }
             
         case GetByVal: {
-            node->child1()->mergeFlags(NodeUsedAsValue);
-            node->child2()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
+            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
+            node->child2()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
             break;
         }
             
-        case GetMyArgumentByValSafe: {
-            node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
+        case NewArrayWithSize: {
+            node->child1()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
             break;
         }
             
-        case NewArrayWithSize: {
-            node->child1()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt);
+        case NewTypedArray: {
+            // Negative zero is not observable. NaN versus undefined are only observable
+            // in that you would get a different exception message. So, like, whatever: we
+            // claim here that NaN v. undefined is observable.
+            node->child1()->mergeFlags(NodeBytecodeUsesAsInt | NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsArrayIndex);
             break;
         }
             
         case StringCharAt: {
-            node->child1()->mergeFlags(NodeUsedAsValue);
-            node->child2()->mergeFlags(NodeUsedAsValue | NodeUsedAsInt);
+            node->child1()->mergeFlags(NodeBytecodeUsesAsValue);
+            node->child2()->mergeFlags(NodeBytecodeUsesAsValue | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
             break;
         }
             
-        case ToString: {
-            node->child1()->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther);
+        case ToString:
+        case CallStringConstructor: {
+            node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
             break;
         }
             
@@ -339,13 +362,57 @@ private:
             node->child1()->mergeFlags(flags);
             break;
         }
-            
+
+        case PutByValDirect:
         case PutByVal: {
-            m_graph.varArgChild(node, 0)->mergeFlags(NodeUsedAsValue);
-            m_graph.varArgChild(node, 1)->mergeFlags(NodeUsedAsNumber | NodeUsedAsOther | NodeUsedAsInt);
-            m_graph.varArgChild(node, 2)->mergeFlags(NodeUsedAsValue);
+            m_graph.varArgChild(node, 0)->mergeFlags(NodeBytecodeUsesAsValue);
+            m_graph.varArgChild(node, 1)->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther | NodeBytecodeUsesAsInt | NodeBytecodeUsesAsArrayIndex);
+            m_graph.varArgChild(node, 2)->mergeFlags(NodeBytecodeUsesAsValue);
+            break;
+        }
+            
+        case Switch: {
+            SwitchData* data = node->switchData();
+            switch (data->kind) {
+            case SwitchImm:
+                // We don't need NodeBytecodeNeedsNegZero because if the cases are all integers
+                // then -0 and 0 are treated the same.  We don't need NodeBytecodeUsesAsOther
+                // because if all of the cases are integers then NaN and undefined are
+                // treated the same (i.e. they will take default).
+                node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsInt);
+                break;
+            case SwitchChar: {
+                // We don't need NodeBytecodeNeedsNegZero because if the cases are all strings
+                // then -0 and 0 are treated the same.  We don't need NodeBytecodeUsesAsOther
+                // because if all of the cases are single-character strings then NaN
+                // and undefined are treated the same (i.e. they will take default).
+                node->child1()->mergeFlags(NodeBytecodeUsesAsNumber);
+                break;
+            }
+            case SwitchString:
+                // We don't need NodeBytecodeNeedsNegZero because if the cases are all strings
+                // then -0 and 0 are treated the same.
+                node->child1()->mergeFlags(NodeBytecodeUsesAsNumber | NodeBytecodeUsesAsOther);
+                break;
+            case SwitchCell:
+                // There is currently no point to being clever here since this is used for switching
+                // on objects.
+                mergeDefaultFlags(node);
+                break;
+            }
             break;
         }
+
+        case Identity: 
+            // This would be trivial to handle but we just assert that we cannot see these yet.
+            RELEASE_ASSERT_NOT_REACHED();
+            break;
+            
+        // Note: ArithSqrt, ArithSin, and ArithCos and other math intrinsics don't have special
+        // rules in here because they are always followed by Phantoms to signify that if the
+        // method call speculation fails, the bytecode may use the arguments in arbitrary ways.
+        // This corresponds to that possibility of someone doing something like:
+        // Math.sin = function(x) { doArbitraryThingsTo(x); }
             
         default:
             mergeDefaultFlags(node);
@@ -354,6 +421,7 @@ private:
     }
     
     bool m_allowNestedOverflowingAdditions;
+    bool m_changed;
 };
 
 bool performBackwardsPropagation(Graph& graph)