Title: [112040] trunk/Source/_javascript_Core
Revision
112040
Author
[email protected]
Date
2012-03-25 16:50:24 -0700 (Sun, 25 Mar 2012)

Log Message

DFG int-to-double conversion should be revealed to CSE
https://bugs.webkit.org/show_bug.cgi?id=82135

Reviewed by Oliver Hunt.
        
This introduces the notion of an Int32ToDouble node, which is injected
into the graph anytime we know that we have a double use of a node that
was predicted integer. The Int32ToDouble simplifies double speculation
on integers by skipping the path that would unbox doubles, if we know
that the value is already proven to be an integer. It allows integer to
double conversions to be subjected to common subexpression elimination
(CSE) by allowing the CSE phase to see where these conversions are
occurring. Finally, it allows us to see when a constant is being used
as both a double and an integer. This is a bit odd, since it means that
sometimes a double use of a constant will not refer directly to the
constant. This should not cause problems, for now, but it may require
some canonizalization in the future if we want to support strength
reductions of double operations based on constants.
        
To allow injection of nodes into the graph, this change introduces the
DFG::InsertionSet, which is a way of lazily inserting elements into a
list. This allows the FixupPhase to remain O(N) despite performing
multiple injections in a single basic block. Without the InsertionSet,
each injection would require performing an insertion into a vector,
which is O(N), leading to O(N^2) performance overall. With the
InsertionSet, each injection simply records what insertion would have
been performed, and all insertions are performed at once (via
InsertionSet::execute) after processing of a basic block is completed.

* _javascript_Core.xcodeproj/project.pbxproj:
* bytecode/PredictedType.h:
(JSC::isActionableIntMutableArrayPrediction):
(JSC):
(JSC::isActionableFloatMutableArrayPrediction):
(JSC::isActionableTypedMutableArrayPrediction):
(JSC::isActionableMutableArrayPrediction):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGCSEPhase.cpp:
(JSC::DFG::CSEPhase::performNodeCSE):
* dfg/DFGCommon.h:
(JSC::DFG::useKindToString):
(DFG):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::run):
(JSC::DFG::FixupPhase::fixupBlock):
(FixupPhase):
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixDoubleEdge):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGInsertionSet.h: Added.
(DFG):
(Insertion):
(JSC::DFG::Insertion::Insertion):
(JSC::DFG::Insertion::index):
(JSC::DFG::Insertion::element):
(InsertionSet):
(JSC::DFG::InsertionSet::InsertionSet):
(JSC::DFG::InsertionSet::append):
(JSC::DFG::InsertionSet::execute):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::computeValueRecoveryFor):
(JSC::DFG::SpeculativeJIT::compileValueToInt32):
(JSC::DFG::SpeculativeJIT::compileInt32ToDouble):
(DFG):
* dfg/DFGSpeculativeJIT.h:
(SpeculativeJIT):
(JSC::DFG::IntegerOperand::IntegerOperand):
(JSC::DFG::DoubleOperand::DoubleOperand):
(JSC::DFG::JSValueOperand::JSValueOperand):
(JSC::DFG::StorageOperand::StorageOperand):
(JSC::DFG::SpeculateIntegerOperand::SpeculateIntegerOperand):
(JSC::DFG::SpeculateStrictInt32Operand::SpeculateStrictInt32Operand):
(JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand):
(JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
(JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (112039 => 112040)


--- trunk/Source/_javascript_Core/ChangeLog	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-03-25 23:50:24 UTC (rev 112040)
@@ -1,5 +1,93 @@
 2012-03-25  Filip Pizlo  <[email protected]>
 
+        DFG int-to-double conversion should be revealed to CSE
+        https://bugs.webkit.org/show_bug.cgi?id=82135
+
+        Reviewed by Oliver Hunt.
+        
+        This introduces the notion of an Int32ToDouble node, which is injected
+        into the graph anytime we know that we have a double use of a node that
+        was predicted integer. The Int32ToDouble simplifies double speculation
+        on integers by skipping the path that would unbox doubles, if we know
+        that the value is already proven to be an integer. It allows integer to
+        double conversions to be subjected to common subexpression elimination
+        (CSE) by allowing the CSE phase to see where these conversions are
+        occurring. Finally, it allows us to see when a constant is being used
+        as both a double and an integer. This is a bit odd, since it means that
+        sometimes a double use of a constant will not refer directly to the
+        constant. This should not cause problems, for now, but it may require
+        some canonizalization in the future if we want to support strength
+        reductions of double operations based on constants.
+        
+        To allow injection of nodes into the graph, this change introduces the
+        DFG::InsertionSet, which is a way of lazily inserting elements into a
+        list. This allows the FixupPhase to remain O(N) despite performing
+        multiple injections in a single basic block. Without the InsertionSet,
+        each injection would require performing an insertion into a vector,
+        which is O(N), leading to O(N^2) performance overall. With the
+        InsertionSet, each injection simply records what insertion would have
+        been performed, and all insertions are performed at once (via
+        InsertionSet::execute) after processing of a basic block is completed.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * bytecode/PredictedType.h:
+        (JSC::isActionableIntMutableArrayPrediction):
+        (JSC):
+        (JSC::isActionableFloatMutableArrayPrediction):
+        (JSC::isActionableTypedMutableArrayPrediction):
+        (JSC::isActionableMutableArrayPrediction):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGCSEPhase.cpp:
+        (JSC::DFG::CSEPhase::performNodeCSE):
+        * dfg/DFGCommon.h:
+        (JSC::DFG::useKindToString):
+        (DFG):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::run):
+        (JSC::DFG::FixupPhase::fixupBlock):
+        (FixupPhase):
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::fixDoubleEdge):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGInsertionSet.h: Added.
+        (DFG):
+        (Insertion):
+        (JSC::DFG::Insertion::Insertion):
+        (JSC::DFG::Insertion::index):
+        (JSC::DFG::Insertion::element):
+        (InsertionSet):
+        (JSC::DFG::InsertionSet::InsertionSet):
+        (JSC::DFG::InsertionSet::append):
+        (JSC::DFG::InsertionSet::execute):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor):
+        (JSC::DFG::SpeculativeJIT::compileValueToInt32):
+        (JSC::DFG::SpeculativeJIT::compileInt32ToDouble):
+        (DFG):
+        * dfg/DFGSpeculativeJIT.h:
+        (SpeculativeJIT):
+        (JSC::DFG::IntegerOperand::IntegerOperand):
+        (JSC::DFG::DoubleOperand::DoubleOperand):
+        (JSC::DFG::JSValueOperand::JSValueOperand):
+        (JSC::DFG::StorageOperand::StorageOperand):
+        (JSC::DFG::SpeculateIntegerOperand::SpeculateIntegerOperand):
+        (JSC::DFG::SpeculateStrictInt32Operand::SpeculateStrictInt32Operand):
+        (JSC::DFG::SpeculateDoubleOperand::SpeculateDoubleOperand):
+        (JSC::DFG::SpeculateCellOperand::SpeculateCellOperand):
+        (JSC::DFG::SpeculateBooleanOperand::SpeculateBooleanOperand):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+
+2012-03-25  Filip Pizlo  <[email protected]>
+
         DFGOperands should be moved out of the DFG and into bytecode
         https://bugs.webkit.org/show_bug.cgi?id=82151
 

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (112039 => 112040)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2012-03-25 23:50:24 UTC (rev 112040)
@@ -74,6 +74,7 @@
 		0F242DA713F3B1E8007ADD4C /* WeakReferenceHarvester.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F2BDC15151C5D4D00CD8910 /* DFGFixupPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2BDC12151C5D4A00CD8910 /* DFGFixupPhase.cpp */; };
 		0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2BDC2B151FDE8B00CD8910 /* Operands.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F2C556F14738F3100121E4F /* DFGCodeBlocks.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		0F2C557014738F3500121E4F /* DFGCodeBlocks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */; };
@@ -724,6 +725,7 @@
 		0F242DA513F3B1BB007ADD4C /* WeakReferenceHarvester.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakReferenceHarvester.h; sourceTree = "<group>"; };
 		0F2BDC12151C5D4A00CD8910 /* DFGFixupPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGFixupPhase.cpp; path = dfg/DFGFixupPhase.cpp; sourceTree = "<group>"; };
 		0F2BDC13151C5D4A00CD8910 /* DFGFixupPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGFixupPhase.h; path = dfg/DFGFixupPhase.h; sourceTree = "<group>"; };
+		0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGInsertionSet.h; path = dfg/DFGInsertionSet.h; sourceTree = "<group>"; };
 		0F2BDC2B151FDE8B00CD8910 /* Operands.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Operands.h; sourceTree = "<group>"; };
 		0F2C556D14738F2E00121E4F /* DFGCodeBlocks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGCodeBlocks.cpp; sourceTree = "<group>"; };
 		0F2C556E14738F2E00121E4F /* DFGCodeBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGCodeBlocks.h; sourceTree = "<group>"; };
@@ -1994,6 +1996,7 @@
 				86AE6C4C136A11E400963012 /* DFGGPRInfo.h */,
 				86EC9DB71328DF82002B2AD7 /* DFGGraph.cpp */,
 				86EC9DB81328DF82002B2AD7 /* DFGGraph.h */,
+				0F2BDC1F151E803800CD8910 /* DFGInsertionSet.h */,
 				86EC9DBB1328DF82002B2AD7 /* DFGJITCompiler.cpp */,
 				86EC9DBC1328DF82002B2AD7 /* DFGJITCompiler.h */,
 				86ECA3E9132DEF1C002B2AD7 /* DFGNode.h */,
@@ -2500,6 +2503,7 @@
 				0FA581BB150E953000B9A2D9 /* DFGNodeFlags.h in Headers */,
 				0FA581BC150E953000B9A2D9 /* DFGNodeType.h in Headers */,
 				0F2BDC16151C5D4F00CD8910 /* DFGFixupPhase.h in Headers */,
+				0F2BDC21151E803B00CD8910 /* DFGInsertionSet.h in Headers */,
 				0F2BDC2C151FDE9100CD8910 /* Operands.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

Modified: trunk/Source/_javascript_Core/bytecode/PredictedType.h (112039 => 112040)


--- trunk/Source/_javascript_Core/bytecode/PredictedType.h	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/bytecode/PredictedType.h	2012-03-25 23:50:24 UTC (rev 112040)
@@ -159,10 +159,9 @@
     return value == PredictFloat64Array;
 }
 
-inline bool isActionableMutableArrayPrediction(PredictedType value)
+inline bool isActionableIntMutableArrayPrediction(PredictedType value)
 {
-    return isArrayPrediction(value)
-        || isByteArrayPrediction(value)
+    return isByteArrayPrediction(value)
 #if CPU(X86) || CPU(X86_64)
         || isInt8ArrayPrediction(value)
         || isInt16ArrayPrediction(value)
@@ -171,13 +170,30 @@
         || isUint8ArrayPrediction(value)
         || isUint8ClampedArrayPrediction(value)
         || isUint16ArrayPrediction(value)
-        || isUint32ArrayPrediction(value)
+        || isUint32ArrayPrediction(value);
+}
+
+inline bool isActionableFloatMutableArrayPrediction(PredictedType value)
+{
+    return false
 #if CPU(X86) || CPU(X86_64)
         || isFloat32ArrayPrediction(value)
 #endif
         || isFloat64ArrayPrediction(value);
 }
 
+inline bool isActionableTypedMutableArrayPrediction(PredictedType value)
+{
+    return isActionableIntMutableArrayPrediction(value)
+        || isActionableFloatMutableArrayPrediction(value);
+}
+
+inline bool isActionableMutableArrayPrediction(PredictedType value)
+{
+    return isArrayPrediction(value)
+        || isActionableTypedMutableArrayPrediction(value);
+}
+
 inline bool isActionableArrayPrediction(PredictedType value)
 {
     return isStringPrediction(value)

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -300,6 +300,11 @@
         
         forNode(nodeIndex).set(PredictInt32);
         break;
+        
+    case Int32ToDouble:
+        forNode(node.child1()).filter(PredictNumber);
+        forNode(nodeIndex).set(PredictDouble);
+        break;
             
     case ValueAdd:
     case ArithAdd: {

Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -587,6 +587,7 @@
         case GetStringLength:
         case StringCharAt:
         case StringCharCodeAt:
+        case Int32ToDouble:
             setReplacement(pureCSE(node));
             break;
             

Modified: trunk/Source/_javascript_Core/dfg/DFGCommon.h (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGCommon.h	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGCommon.h	2012-03-25 23:50:24 UTC (rev 112040)
@@ -97,9 +97,23 @@
 
 enum UseKind {
     UntypedUse,
+    DoubleUse,
     LastUseKind // Must always be the last entry in the enum, as it is used to denote the number of enum elements.
 };
 
+inline const char* useKindToString(UseKind useKind)
+{
+    switch (useKind) {
+    case UntypedUse:
+        return "";
+    case DoubleUse:
+        return "d";
+    default:
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -29,6 +29,7 @@
 #if ENABLE(DFG_JIT)
 
 #include "DFGGraph.h"
+#include "DFGInsertionSet.h"
 #include "DFGPhase.h"
 
 namespace JSC { namespace DFG {
@@ -42,11 +43,20 @@
     
     void run()
     {
-        for (m_compileIndex = 0; m_compileIndex < m_graph.size(); ++m_compileIndex)
-            fixupNode(m_graph[m_compileIndex]);
+        for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
+            fixupBlock(m_graph.m_blocks[blockIndex].get());
     }
 
 private:
+    void fixupBlock(BasicBlock* block)
+    {
+        for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
+            m_compileIndex = block->at(m_indexInBlock);
+            fixupNode(m_graph[m_compileIndex]);
+        }
+        m_insertionSet.execute(*block);
+    }
+    
     void fixupNode(Node& node)
     {
         if (!node.shouldGenerate())
@@ -152,11 +162,130 @@
             break;
         }
             
+        case CompareEq:
+        case CompareLess:
+        case CompareLessEq:
+        case CompareGreater:
+        case CompareGreaterEq:
+        case CompareStrictEq: {
+            if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()]))
+                break;
+            if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()]))
+                break;
+            fixDoubleEdge(0);
+            fixDoubleEdge(1);
+            break;
+        }
+            
+        case LogicalNot: {
+            if (m_graph[node.child1()].shouldSpeculateInteger())
+                break;
+            if (!m_graph[node.child1()].shouldSpeculateNumber())
+                break;
+            fixDoubleEdge(0);
+            break;
+        }
+            
+        case Branch: {
+            if (m_graph[node.child1()].shouldSpeculateInteger())
+                break;
+            if (!m_graph[node.child1()].shouldSpeculateNumber())
+                break;
+            fixDoubleEdge(0);
+            break;
+        }
+            
+        case SetLocal: {
+            if (m_graph.isCaptured(node.local()))
+                break;
+            if (!node.variableAccessData()->shouldUseDoubleFormat())
+                break;
+            fixDoubleEdge(0);
+            break;
+        }
+            
+        case ArithAdd:
+        case ValueAdd: {
+            if (m_graph.addShouldSpeculateInteger(node))
+                break;
+            if (!Node::shouldSpeculateNumber(m_graph[node.child1()], m_graph[node.child2()]))
+                break;
+            fixDoubleEdge(0);
+            fixDoubleEdge(1);
+            break;
+        }
+            
+        case ArithSub: {
+            if (m_graph.addShouldSpeculateInteger(node)
+                && node.canSpeculateInteger())
+                break;
+            fixDoubleEdge(0);
+            fixDoubleEdge(1);
+            break;
+        }
+            
+        case ArithNegate: {
+            if (m_graph.negateShouldSpeculateInteger(node))
+                break;
+            fixDoubleEdge(0);
+            break;
+        }
+            
+        case ArithMin:
+        case ArithMax:
+        case ArithMul:
+        case ArithDiv:
+        case ArithMod: {
+            if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])
+                && node.canSpeculateInteger())
+                break;
+            fixDoubleEdge(0);
+            fixDoubleEdge(1);
+            break;
+        }
+            
+        case ArithAbs: {
+            if (m_graph[node.child1()].shouldSpeculateInteger()
+                && node.canSpeculateInteger())
+                break;
+            fixDoubleEdge(0);
+            break;
+        }
+            
+        case ArithSqrt: {
+            fixDoubleEdge(0);
+            break;
+        }
+            
+        case PutByVal: {
+            if (!m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction())
+                break;
+            if (!m_graph[node.child2()].shouldSpeculateInteger())
+                break;
+            if (isActionableIntMutableArrayPrediction(m_graph[node.child1()].prediction())) {
+                if (m_graph[node.child3()].isConstant())
+                    break;
+                if (m_graph[node.child3()].shouldSpeculateInteger())
+                    break;
+                fixDoubleEdge(2);
+                break;
+            }
+            if (isActionableFloatMutableArrayPrediction(m_graph[node.child1()].prediction())) {
+                fixDoubleEdge(2);
+                break;
+            }
+            break;
+        }
+            
         default:
             break;
         }
 
 #if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        if (!(node.flags() & NodeHasVarArgs)) {
+            dataLog("new children: ");
+            node.dumpChildren(WTF::dataFile());
+        }
         dataLog("\n");
 #endif
     }
@@ -179,7 +308,39 @@
         edge = newEdge;
     }
     
+    void fixDoubleEdge(unsigned childIndex)
+    {
+        Node& source = m_graph[m_compileIndex];
+        Edge& edge = source.children.child(childIndex);
+        
+        if (!m_graph[edge].shouldSpeculateInteger()) {
+            edge.setUseKind(DoubleUse);
+            return;
+        }
+        
+        NodeIndex resultIndex = (NodeIndex)m_graph.size();
+        
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+        dataLog("(replacing @%u->@%u with @%u->@%u) ",
+                m_compileIndex, edge.index(), m_compileIndex, resultIndex);
+#endif
+        
+        // Fix the edge up here because it's a reference that will be clobbered by
+        // the append() below.
+        NodeIndex oldIndex = edge.index();
+        edge = Edge(resultIndex, DoubleUse);
+
+        m_graph.append(Node(Int32ToDouble, source.codeOrigin, oldIndex));
+        m_insertionSet.append(m_indexInBlock, resultIndex);
+        
+        Node& int32ToDouble = m_graph[resultIndex];
+        int32ToDouble.predict(PredictDouble);
+        int32ToDouble.ref();
+    }
+    
+    unsigned m_indexInBlock;
     NodeIndex m_compileIndex;
+    InsertionSet<NodeIndex> m_insertionSet;
 };
     
 void performFixup(Graph& graph)

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -163,15 +163,30 @@
                 dataLog(", ");
             else
                 hasPrinted = true;
-            dataLog("@%u%s", m_varArgChildren[childIdx].index(), predictionToAbbreviatedString(at(childIdx).prediction()));
+            dataLog("%s@%u%s",
+                    useKindToString(m_varArgChildren[childIdx].useKind()),
+                    m_varArgChildren[childIdx].index(),
+                    predictionToAbbreviatedString(at(childIdx).prediction()));
         }
     } else {
-        if (!!node.child1())
-            dataLog("@%u%s", node.child1().index(), predictionToAbbreviatedString(at(node.child1()).prediction()));
-        if (!!node.child2())
-            dataLog(", @%u%s", node.child2().index(), predictionToAbbreviatedString(at(node.child2()).prediction()));
-        if (!!node.child3())
-            dataLog(", @%u%s", node.child3().index(), predictionToAbbreviatedString(at(node.child3()).prediction()));
+        if (!!node.child1()) {
+            dataLog("%s@%u%s",
+                    useKindToString(node.child1().useKind()),
+                    node.child1().index(),
+                    predictionToAbbreviatedString(at(node.child1()).prediction()));
+        }
+        if (!!node.child2()) {
+            dataLog(", %s@%u%s",
+                    useKindToString(node.child2().useKind()),
+                    node.child2().index(),
+                    predictionToAbbreviatedString(at(node.child2()).prediction()));
+        }
+        if (!!node.child3()) {
+            dataLog(", %s@%u%s",
+                    useKindToString(node.child3().useKind()),
+                    node.child3().index(),
+                    predictionToAbbreviatedString(at(node.child3()).prediction()));
+        }
         hasPrinted = !!node.child1();
     }
 

Added: trunk/Source/_javascript_Core/dfg/DFGInsertionSet.h (0 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGInsertionSet.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/dfg/DFGInsertionSet.h	2012-03-25 23:50:24 UTC (rev 112040)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGInsertionSet_h
+#define DFGInsectionSet_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(DFG_JIT)
+
+#include <wtf/Vector.h>
+
+namespace JSC { namespace DFG {
+
+template<typename ElementType>
+class Insertion {
+public:
+    Insertion() { }
+    
+    Insertion(size_t index, const ElementType& element)
+        : m_index(index)
+        , m_element(element)
+    {
+    }
+    
+    size_t index() const { return m_index; }
+    const ElementType& element() const { return m_element; }
+private:
+    size_t m_index;
+    ElementType m_element;
+};
+
+template<typename ElementType>
+class InsertionSet {
+public:
+    InsertionSet() { }
+    
+    void append(const Insertion<ElementType>& insertion)
+    {
+        ASSERT(!m_insertions.size() || m_insertions.last().index() <= insertion.index());
+        m_insertions.append(insertion);
+    }
+    
+    void append(size_t index, const ElementType& element)
+    {
+        append(Insertion<ElementType>(index, element));
+    }
+    
+    template<typename CollectionType>
+    void execute(CollectionType& collection)
+    {
+        if (!m_insertions.size())
+            return;
+        collection.grow(collection.size() + m_insertions.size());
+        size_t lastIndex = collection.size();
+        for (size_t indexInInsertions = m_insertions.size(); indexInInsertions--;) {
+            Insertion<ElementType>& insertion = m_insertions[indexInInsertions];
+            size_t firstIndex = insertion.index() + indexInInsertions;
+            size_t indexOffset = indexInInsertions + 1;
+            for (size_t i = lastIndex; i-- > firstIndex;)
+                collection[i] = collection[i - indexOffset];
+            collection[firstIndex] = insertion.element();
+            lastIndex = firstIndex;
+        }
+        m_insertions.resize(0);
+    }
+private:
+    Vector<Insertion<ElementType>, 8> m_insertions;
+};
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGInsertionSet_h
+

Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h	2012-03-25 23:50:24 UTC (rev 112040)
@@ -75,6 +75,9 @@
     macro(ValueToInt32, NodeResultInt32 | NodeMustGenerate) \
     /* Used to box the result of URShift nodes (result has range 0..2^32-1). */\
     macro(UInt32ToNumber, NodeResultNumber) \
+    /* Used to cast known integers to doubles, so as to separate the double form */\
+    /* of the value from the integer form. */\
+    macro(Int32ToDouble, NodeResultNumber) \
     \
     /* Nodes for arithmetic operations. */\
     macro(ArithAdd, NodeResultNumber) \

Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -569,7 +569,8 @@
         case GetUint32ArrayLength:
         case GetFloat32ArrayLength:
         case GetFloat64ArrayLength:
-        case GetStringLength: {
+        case GetStringLength:
+        case Int32ToDouble: {
             // This node should never be visible at this stage of compilation. It is
             // inserted by fixup(), which follows this phase.
             ASSERT_NOT_REACHED();

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -1284,6 +1284,10 @@
             // Try to see if there is an alternate node that would contain the value we want.
             // There are four possibilities:
             //
+            // Int32ToDouble: We can use this in place of the original node, but
+            //    we'd rather not; so we use it only if it is the only remaining
+            //    live version.
+            //
             // ValueToInt32: If the only remaining live version of the value is
             //    ValueToInt32, then we can use it.
             //
@@ -1306,6 +1310,7 @@
             }
         
             if (!found) {
+                NodeIndex int32ToDoubleIndex = NoNode;
                 NodeIndex valueToInt32Index = NoNode;
                 NodeIndex uint32ToNumberIndex = NoNode;
             
@@ -1319,6 +1324,9 @@
                     if (node.child1Unchecked() != valueSource.nodeIndex())
                         continue;
                     switch (node.op()) {
+                    case Int32ToDouble:
+                        int32ToDoubleIndex = info.nodeIndex();
+                        break;
                     case ValueToInt32:
                         valueToInt32Index = info.nodeIndex();
                         break;
@@ -1331,7 +1339,9 @@
                 }
             
                 NodeIndex nodeIndexToUse;
-                if (valueToInt32Index != NoNode)
+                if (int32ToDoubleIndex != NoNode)
+                    nodeIndexToUse = int32ToDoubleIndex;
+                else if (valueToInt32Index != NoNode)
                     nodeIndexToUse = valueToInt32Index;
                 else if (uint32ToNumberIndex != NoNode)
                     nodeIndexToUse = uint32ToNumberIndex;
@@ -1537,7 +1547,7 @@
         }
         case GeneratedOperandDouble: {
             GPRTemporary result(this);
-            SpeculateDoubleOperand op1(this, node.child1());
+            DoubleOperand op1(this, node.child1());
             FPRReg fpr = op1.fpr();
             GPRReg gpr = result.gpr();
             JITCompiler::Jump truncatedToInteger = m_jit.branchTruncateDoubleToInt32(fpr, gpr, JITCompiler::BranchIfTruncateSuccessful);
@@ -1674,6 +1684,82 @@
     integerResult(result.gpr(), m_compileIndex, op1.format());
 }
 
+void SpeculativeJIT::compileInt32ToDouble(Node& node)
+{
+#if USE(JSVALUE64)
+    // On JSVALUE64 we have a way of loading double constants in a more direct manner
+    // than a int->double conversion. On 32_64, unfortunately, we currently don't have
+    // any such mechanism - though we could have it, if we just provisioned some memory
+    // in CodeBlock for the double form of integer constants.
+    if (at(node.child1()).hasConstant()) {
+        ASSERT(isInt32Constant(node.child1().index()));
+        FPRTemporary result(this);
+        GPRTemporary temp(this);
+        m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfNumberConstant(node.child1().index())))), temp.gpr());
+        m_jit.movePtrToDouble(temp.gpr(), result.fpr());
+        doubleResult(result.fpr(), m_compileIndex);
+        return;
+    }
+#endif
+    
+    if (isInt32Prediction(m_state.forNode(node.child1()).m_type)) {
+        SpeculateIntegerOperand op1(this, node.child1());
+        FPRTemporary result(this);
+        m_jit.convertInt32ToDouble(op1.gpr(), result.fpr());
+        doubleResult(result.fpr(), m_compileIndex);
+        return;
+    }
+    
+    JSValueOperand op1(this, node.child1());
+    FPRTemporary result(this);
+    
+#if USE(JSVALUE64)
+    GPRTemporary temp(this);
+
+    GPRReg op1GPR = op1.gpr();
+    GPRReg tempGPR = temp.gpr();
+    FPRReg resultFPR = result.fpr();
+    
+    JITCompiler::Jump isInteger = m_jit.branchPtr(
+        MacroAssembler::AboveOrEqual, op1GPR, GPRInfo::tagTypeNumberRegister);
+    
+    speculationCheck(
+        BadType, JSValueRegs(op1GPR), node.child1(),
+        m_jit.branchTestPtr(MacroAssembler::Zero, op1GPR, GPRInfo::tagTypeNumberRegister));
+    
+    m_jit.move(op1GPR, tempGPR);
+    unboxDouble(tempGPR, resultFPR);
+    JITCompiler::Jump done = m_jit.jump();
+    
+    isInteger.link(&m_jit);
+    m_jit.convertInt32ToDouble(op1GPR, resultFPR);
+    done.link(&m_jit);
+#else
+    FPRTemporary temp(this);
+    
+    GPRReg op1TagGPR = op1.tagGPR();
+    GPRReg op1PayloadGPR = op1.payloadGPR();
+    FPRReg tempFPR = temp.fpr();
+    FPRReg resultFPR = result.fpr();
+    
+    JITCompiler::Jump isInteger = m_jit.branch32(
+        MacroAssembler::Equal, op1TagGPR, TrustedImm32(JSValue::Int32Tag));
+    
+    speculationCheck(
+        BadType, JSValueRegs(op1TagGPR, op1PayloadGPR), node.child1(),
+        m_jit.branch32(MacroAssembler::AboveOrEqual, op1TagGPR, TrustedImm32(JSValue::LowestTag)));
+    
+    unboxDouble(op1TagGPR, op1PayloadGPR, resultFPR, tempFPR);
+    JITCompiler::Jump done = m_jit.jump();
+    
+    isInteger.link(&m_jit);
+    m_jit.convertInt32ToDouble(op1PayloadGPR, resultFPR);
+    done.link(&m_jit);
+#endif
+    
+    doubleResult(resultFPR, m_compileIndex);
+}
+
 static double clampDoubleToByte(double d)
 {
     d += 0.5;

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2012-03-25 23:50:24 UTC (rev 112040)
@@ -1732,6 +1732,7 @@
     void compileGetByValOnString(Node&);
     void compileValueToInt32(Node&);
     void compileUInt32ToNumber(Node&);
+    void compileInt32ToDouble(Node&);
     void compileGetByValOnByteArray(Node&);
     void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
     void compileAdd(Node&);
@@ -1984,6 +1985,7 @@
 #endif
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() != DoubleUse);
         if (jit->isFilled(m_index))
             gpr();
     }
@@ -2033,6 +2035,15 @@
         , m_fprOrInvalid(InvalidFPRReg)
     {
         ASSERT(m_jit);
+        
+        // This is counter-intuitive but correct. DoubleOperand is intended to
+        // be used only when you're a node that is happy to accept an untyped
+        // value, but will special-case for doubles (using DoubleOperand) if the
+        // value happened to already be represented as a double. The implication
+        // is that you will not try to force the value to become a double if it
+        // is not one already.
+        ASSERT(use.useKind() != DoubleUse);
+        
         if (jit->isFilledDouble(m_index))
             fpr();
     }
@@ -2078,6 +2089,7 @@
 #endif
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() != DoubleUse);
 #if USE(JSVALUE64)
         if (jit->isFilled(m_index))
             gpr();
@@ -2188,6 +2200,7 @@
         , m_gprOrInvalid(InvalidGPRReg)
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() != DoubleUse);
         if (jit->isFilled(m_index))
             gpr();
     }
@@ -2360,6 +2373,7 @@
 #endif
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() != DoubleUse);
         if (jit->isFilled(m_index))
             gpr();
     }
@@ -2404,6 +2418,7 @@
         , m_gprOrInvalid(InvalidGPRReg)
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() != DoubleUse);
         if (jit->isFilled(m_index))
             gpr();
     }
@@ -2445,6 +2460,7 @@
         , m_fprOrInvalid(InvalidFPRReg)
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() == DoubleUse);
         if (jit->isFilled(m_index))
             fpr();
     }
@@ -2481,6 +2497,7 @@
         , m_gprOrInvalid(InvalidGPRReg)
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() != DoubleUse);
         if (jit->isFilled(m_index))
             gpr();
     }
@@ -2522,6 +2539,7 @@
         , m_gprOrInvalid(InvalidGPRReg)
     {
         ASSERT(m_jit);
+        ASSERT(use.useKind() != DoubleUse);
         if (jit->isFilled(m_index))
             gpr();
     }

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -1878,6 +1878,11 @@
         compileValueToInt32(node);
         break;
     }
+        
+    case Int32ToDouble: {
+        compileInt32ToDouble(node);
+        break;
+    }
 
     case ValueAdd:
     case ArithAdd:

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (112039 => 112040)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-03-25 23:35:07 UTC (rev 112039)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-03-25 23:50:24 UTC (rev 112040)
@@ -1965,6 +1965,11 @@
         compileValueToInt32(node);
         break;
     }
+        
+    case Int32ToDouble: {
+        compileInt32ToDouble(node);
+        break;
+    }
 
     case ValueAdd:
     case ArithAdd:
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to