Title: [94449] trunk/Source/_javascript_Core
Revision
94449
Author
fpi...@apple.com
Date
2011-09-02 14:16:25 -0700 (Fri, 02 Sep 2011)

Log Message

DFG graph has no way of distinguishing or reconciling between static
and dynamic predictions
https://bugs.webkit.org/show_bug.cgi?id=67343

Reviewed by Gavin Barraclough.

PredictedType now stores the source of the prediction.  Merging predictions,
which was previously done with a bitwise or, is now done via the
mergePredictions (equivalent to |) and mergePrediction (equivalent to |=)
functions, which correctly handle combinations of static and dynamic.

This is performance-neutral, since all predictions are currently static and
so the code has no visible effects.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::set):
(JSC::DFG::ByteCodeParser::staticallyPredictArray):
(JSC::DFG::ByteCodeParser::staticallyPredictInt32):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::predict):
(JSC::DFG::Graph::predictGlobalVar):
* dfg/DFGNode.h:
(JSC::DFG::isArrayPrediction):
(JSC::DFG::isInt32Prediction):
(JSC::DFG::isDoublePrediction):
(JSC::DFG::isDynamicPrediction):
(JSC::DFG::mergePredictions):
(JSC::DFG::mergePrediction):
(JSC::DFG::makePrediction):
(JSC::DFG::Node::predict):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (94448 => 94449)


--- trunk/Source/_javascript_Core/ChangeLog	2011-09-02 21:08:27 UTC (rev 94448)
+++ trunk/Source/_javascript_Core/ChangeLog	2011-09-02 21:16:25 UTC (rev 94449)
@@ -1,3 +1,37 @@
+2011-09-02  Filip Pizlo  <fpi...@apple.com>
+
+        DFG graph has no way of distinguishing or reconciling between static
+        and dynamic predictions
+        https://bugs.webkit.org/show_bug.cgi?id=67343
+
+        Reviewed by Gavin Barraclough.
+        
+        PredictedType now stores the source of the prediction.  Merging predictions,
+        which was previously done with a bitwise or, is now done via the
+        mergePredictions (equivalent to |) and mergePrediction (equivalent to |=)
+        functions, which correctly handle combinations of static and dynamic.
+        
+        This is performance-neutral, since all predictions are currently static and
+        so the code has no visible effects.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::set):
+        (JSC::DFG::ByteCodeParser::staticallyPredictArray):
+        (JSC::DFG::ByteCodeParser::staticallyPredictInt32):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::predict):
+        (JSC::DFG::Graph::predictGlobalVar):
+        * dfg/DFGNode.h:
+        (JSC::DFG::isArrayPrediction):
+        (JSC::DFG::isInt32Prediction):
+        (JSC::DFG::isDoublePrediction):
+        (JSC::DFG::isDynamicPrediction):
+        (JSC::DFG::mergePredictions):
+        (JSC::DFG::mergePrediction):
+        (JSC::DFG::makePrediction):
+        (JSC::DFG::Node::predict):
+
 2011-09-02  Oliver Hunt  <oli...@apple.com>
 
         Fix 32bit build.

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (94448 => 94449)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2011-09-02 21:08:27 UTC (rev 94448)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2011-09-02 21:16:25 UTC (rev 94449)
@@ -102,9 +102,9 @@
         // Must be a local.
         return getLocal((unsigned)operand);
     }
-    void set(int operand, NodeIndex value, PredictedType prediction = PredictNone)
+    void set(int operand, NodeIndex value, PredictedType staticPrediction = PredictNone)
     {
-        m_graph.predict(operand, prediction);
+        m_graph.predict(operand, staticPrediction, StaticPrediction);
 
         // Is this an argument?
         if (operandIsArgument(operand)) {
@@ -428,12 +428,12 @@
         return call;
     }
 
-    void predictArray(NodeIndex nodeIndex)
+    void staticallyPredictArray(NodeIndex nodeIndex)
     {
-        m_graph.predict(m_graph[nodeIndex], PredictArray);
+        m_graph.predict(m_graph[nodeIndex], PredictArray, StaticPrediction);
     }
 
-    void predictInt32(NodeIndex nodeIndex)
+    void staticallyPredictInt32(NodeIndex nodeIndex)
     {
         ASSERT(m_reusableNodeStack.isEmpty());
         m_reusableNodeStack.append(&m_graph[nodeIndex]);
@@ -457,7 +457,7 @@
                 m_reusableNodeStack.append(&m_graph[nodePtr->child2()]);
                 break;
             default:
-                m_graph.predict(*nodePtr, PredictInt32);
+                m_graph.predict(*nodePtr, PredictInt32, StaticPrediction);
                 break;
             }
         } while (!m_reusableNodeStack.isEmpty());
@@ -587,8 +587,8 @@
         case op_bitand: {
             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
-            predictInt32(op1);
-            predictInt32(op2);
+            staticallyPredictInt32(op1);
+            staticallyPredictInt32(op2);
             set(currentInstruction[1].u.operand, addToGraph(BitAnd, op1, op2), PredictInt32);
             NEXT_OPCODE(op_bitand);
         }
@@ -596,8 +596,8 @@
         case op_bitor: {
             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
-            predictInt32(op1);
-            predictInt32(op2);
+            staticallyPredictInt32(op1);
+            staticallyPredictInt32(op2);
             set(currentInstruction[1].u.operand, addToGraph(BitOr, op1, op2), PredictInt32);
             NEXT_OPCODE(op_bitor);
         }
@@ -605,8 +605,8 @@
         case op_bitxor: {
             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
-            predictInt32(op1);
-            predictInt32(op2);
+            staticallyPredictInt32(op1);
+            staticallyPredictInt32(op2);
             set(currentInstruction[1].u.operand, addToGraph(BitXor, op1, op2), PredictInt32);
             NEXT_OPCODE(op_bitxor);
         }
@@ -614,8 +614,8 @@
         case op_rshift: {
             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
-            predictInt32(op1);
-            predictInt32(op2);
+            staticallyPredictInt32(op1);
+            staticallyPredictInt32(op2);
             NodeIndex result;
             // Optimize out shifts by zero.
             if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
@@ -629,8 +629,8 @@
         case op_lshift: {
             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
-            predictInt32(op1);
-            predictInt32(op2);
+            staticallyPredictInt32(op1);
+            staticallyPredictInt32(op2);
             NodeIndex result;
             // Optimize out shifts by zero.
             if (isInt32Constant(op2) && !(valueOfInt32Constant(op2) & 0x1f))
@@ -644,8 +644,8 @@
         case op_urshift: {
             NodeIndex op1 = getToInt32(currentInstruction[2].u.operand);
             NodeIndex op2 = getToInt32(currentInstruction[3].u.operand);
-            predictInt32(op1);
-            predictInt32(op2);
+            staticallyPredictInt32(op1);
+            staticallyPredictInt32(op2);
             NodeIndex result;
             // The result of a zero-extending right shift is treated as an unsigned value.
             // This means that if the top bit is set, the result is not in the int32 range,
@@ -675,7 +675,7 @@
         case op_pre_inc: {
             unsigned srcDst = currentInstruction[1].u.operand;
             NodeIndex op = getToNumber(srcDst);
-            predictInt32(op);
+            staticallyPredictInt32(op);
             set(srcDst, addToGraph(ArithAdd, op, one()));
             NEXT_OPCODE(op_pre_inc);
         }
@@ -684,7 +684,7 @@
             unsigned result = currentInstruction[1].u.operand;
             unsigned srcDst = currentInstruction[2].u.operand;
             NodeIndex op = getToNumber(srcDst);
-            predictInt32(op);
+            staticallyPredictInt32(op);
             set(result, op);
             set(srcDst, addToGraph(ArithAdd, op, one()));
             NEXT_OPCODE(op_post_inc);
@@ -693,7 +693,7 @@
         case op_pre_dec: {
             unsigned srcDst = currentInstruction[1].u.operand;
             NodeIndex op = getToNumber(srcDst);
-            predictInt32(op);
+            staticallyPredictInt32(op);
             set(srcDst, addToGraph(ArithSub, op, one()));
             NEXT_OPCODE(op_pre_dec);
         }
@@ -702,7 +702,7 @@
             unsigned result = currentInstruction[1].u.operand;
             unsigned srcDst = currentInstruction[2].u.operand;
             NodeIndex op = getToNumber(srcDst);
-            predictInt32(op);
+            staticallyPredictInt32(op);
             set(result, op);
             set(srcDst, addToGraph(ArithSub, op, one()));
             NEXT_OPCODE(op_post_dec);
@@ -717,8 +717,8 @@
             // If both operands can statically be determined to the numbers, then this is an arithmetic add.
             // Otherwise, we must assume this may be performing a concatenation to a string.
             if (isSmallInt32Constant(op1) || isSmallInt32Constant(op2)) {
-                predictInt32(op1);
-                predictInt32(op2);
+                staticallyPredictInt32(op1);
+                staticallyPredictInt32(op2);
             }
             if (m_graph[op1].hasNumericResult() && m_graph[op2].hasNumericResult())
                 set(currentInstruction[1].u.operand, addToGraph(ArithAdd, toNumber(op1), toNumber(op2)));
@@ -732,8 +732,8 @@
             NodeIndex op1 = getToNumber(currentInstruction[2].u.operand);
             NodeIndex op2 = getToNumber(currentInstruction[3].u.operand);
             if (isSmallInt32Constant(op1) || isSmallInt32Constant(op2)) {
-                predictInt32(op1);
-                predictInt32(op2);
+                staticallyPredictInt32(op1);
+                staticallyPredictInt32(op2);
             }
             set(currentInstruction[1].u.operand, addToGraph(ArithSub, op1, op2));
             NEXT_OPCODE(op_sub);
@@ -878,8 +878,8 @@
         case op_get_by_val: {
             NodeIndex base = get(currentInstruction[2].u.operand);
             NodeIndex property = get(currentInstruction[3].u.operand);
-            predictArray(base);
-            predictInt32(property);
+            staticallyPredictArray(base);
+            staticallyPredictInt32(property);
 
             NodeIndex getByVal = addToGraph(GetByVal, OpInfo(0), OpInfo(PredictNone), base, property, aliases.lookupGetByVal(base, property));
             set(currentInstruction[1].u.operand, getByVal);
@@ -892,8 +892,8 @@
             NodeIndex base = get(currentInstruction[1].u.operand);
             NodeIndex property = get(currentInstruction[2].u.operand);
             NodeIndex value = get(currentInstruction[3].u.operand);
-            predictArray(base);
-            predictInt32(property);
+            staticallyPredictArray(base);
+            staticallyPredictInt32(property);
 
             NodeIndex aliasedGet = aliases.lookupGetByVal(base, property);
             NodeIndex putByVal = addToGraph(aliasedGet != NoNode ? PutByValAlias : PutByVal, base, property, value);

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (94448 => 94449)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2011-09-02 21:08:27 UTC (rev 94448)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2011-09-02 21:16:25 UTC (rev 94449)
@@ -135,35 +135,41 @@
         return *m_blocks[blockIndexForBytecodeOffset(bytecodeBegin)];
     }
 
-    void predict(int operand, PredictedType prediction)
+    void predict(int operand, PredictedType prediction, PredictionSource source)
     {
         if (operandIsArgument(operand)) {
             unsigned argument = operand + m_argumentPredictions.size() + RegisterFile::CallFrameHeaderSize;
-            m_argumentPredictions[argument].m_value |= prediction;
+            mergePrediction(m_argumentPredictions[argument].m_value, makePrediction(prediction, source));
         } else if ((unsigned)operand < m_variablePredictions.size())
-            m_variablePredictions[operand].m_value |= prediction;
+            mergePrediction(m_variablePredictions[operand].m_value, makePrediction(prediction, source));
     }
     
-    void predictGlobalVar(unsigned varNumber, PredictedType prediction)
+    void predictGlobalVar(unsigned varNumber, PredictedType prediction, PredictionSource source)
     {
         HashMap<unsigned, PredictionSlot>::iterator iter = m_globalVarPredictions.find(varNumber + 1);
         if (iter == m_globalVarPredictions.end()) {
             PredictionSlot predictionSlot;
-            predictionSlot.m_value |= prediction;
+            mergePrediction(predictionSlot.m_value, makePrediction(prediction, source));
             m_globalVarPredictions.add(varNumber + 1, predictionSlot);
         } else
-            iter->second.m_value |= prediction;
+            mergePrediction(iter->second.m_value, makePrediction(prediction, source));
     }
     
-    void predict(Node& node, PredictedType prediction)
+    void predict(Node& node, PredictedType prediction, PredictionSource source)
     {
         switch (node.op) {
         case GetLocal:
-            predict(node.local(), prediction);
+            predict(node.local(), prediction, source);
             break;
         case GetGlobalVar:
-            predictGlobalVar(node.varNumber(), prediction);
+            predictGlobalVar(node.varNumber(), prediction, source);
             break;
+        case GetById:
+        case GetMethod:
+        case GetByVal:
+        case Call:
+        case Construct:
+            node.predict(prediction, source);
         default:
             break;
         }

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (94448 => 94449)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-09-02 21:08:27 UTC (rev 94448)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2011-09-02 21:16:25 UTC (rev 94449)
@@ -195,7 +195,11 @@
 static const PredictedType PredictInt32  = 0x04;
 static const PredictedType PredictDouble = 0x08;
 static const PredictedType PredictNumber = 0x0c;
+static const PredictedType DynamicPredictionTag = 0x80;
+static const PredictedType PredictionTagMask    = 0x80;
 
+enum PredictionSource { StaticPrediction, DynamicPrediction };
+
 inline bool isCellPrediction(PredictedType value)
 {
     return (value & PredictCell) == PredictCell && !(value & ~PredictArray);
@@ -203,17 +207,17 @@
 
 inline bool isArrayPrediction(PredictedType value)
 {
-    return value == PredictArray;
+    return (value & ~PredictionTagMask) == PredictArray;
 }
 
 inline bool isInt32Prediction(PredictedType value)
 {
-    return value == PredictInt32;
+    return (value & ~PredictionTagMask) == PredictInt32;
 }
 
 inline bool isDoublePrediction(PredictedType value)
 {
-    return value == PredictDouble;
+    return (value & ~PredictionTagMask) == PredictDouble;
 }
 
 inline bool isNumberPrediction(PredictedType value)
@@ -221,6 +225,40 @@
     return !!(value & PredictNumber) && !(value & ~PredictNumber);
 }
 
+inline bool isDynamicPrediction(PredictedType value)
+{
+    ASSERT(value != (PredictNone | DynamicPredictionTag));
+    return !!(value & DynamicPredictionTag);
+}
+
+inline PredictedType mergePredictions(PredictedType left, PredictedType right)
+{
+    if (isDynamicPrediction(left) == isDynamicPrediction(right))
+        return left | right;
+    if (isDynamicPrediction(left)) {
+        ASSERT(!isDynamicPrediction(right));
+        return left;
+    }
+    ASSERT(!isDynamicPrediction(left));
+    ASSERT(isDynamicPrediction(right));
+    return right;
+}
+
+template<typename T>
+inline void mergePrediction(T& left, PredictedType right)
+{
+    left = static_cast<T>(mergePredictions(static_cast<PredictedType>(left), right));
+}
+
+inline PredictedType makePrediction(PredictedType type, PredictionSource source)
+{
+    ASSERT(!(type & DynamicPredictionTag));
+    ASSERT(source == DynamicPrediction || source == StaticPrediction);
+    if (type == PredictNone)
+        return PredictNone;
+    return type | (source == DynamicPrediction ? DynamicPredictionTag : 0);
+}
+
 #ifndef NDEBUG
 inline const char* predictionToString(PredictedType value)
 {
@@ -432,10 +470,22 @@
         return static_cast<PredictedType>(m_opInfo2);
     }
     
-    void predict(PredictedType prediction)
+    void predict(PredictedType prediction, PredictionSource source)
     {
         ASSERT(hasPrediction());
-        m_opInfo2 |= prediction;
+        
+        // We have previously found empirically that ascribing static predictions
+        // to heap loads as well as calls is not profitable, as these predictions
+        // are wrong too often. Hence, this completely ignores static predictions.
+        if (source == StaticPrediction)
+            return;
+        
+        if (prediction == PredictNone)
+            return;
+        
+        ASSERT(source == DynamicPrediction);
+        
+        m_opInfo2 |= DynamicPredictionTag | prediction;
     }
 
     VirtualRegister virtualRegister()
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to