The DFG backend's and OSR's decision to unbox a variable should be based on whether it's used in a typed context
https://bugs.webkit.org/show_bug.cgi?id=110433

Reviewed by Oliver Hunt and Mark Hahnenberg.
        
This introduces the equivalent of a liveness analysis, except for type checking.
A variable is said to be "profitable for unboxing" (i.e. live at a type check)
if there exists a type check on a GetLocal of that variable, and the type check
is consistent with the variable's prediction. Variables that are not profitable
for unboxing aren't unboxed. Previously they would have been.
        
This is a slight speed-up on some things but mostly neutral.

* dfg/DFGArgumentPosition.h:
(JSC::DFG::ArgumentPosition::ArgumentPosition):
(JSC::DFG::ArgumentPosition::mergeShouldNeverUnbox):
(JSC::DFG::ArgumentPosition::mergeArgumentPredictionAwareness):
(JSC::DFG::ArgumentPosition::mergeArgumentUnboxingAwareness):
(ArgumentPosition):
(JSC::DFG::ArgumentPosition::isProfitableToUnbox):
(JSC::DFG::ArgumentPosition::shouldUseDoubleFormat):
* dfg/DFGCommon.h:
(JSC::DFG::checkAndSet):
(DFG):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::run):
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupSetLocalsInBlock):
(FixupPhase):
(JSC::DFG::FixupPhase::alwaysUnboxSimplePrimitives):
(JSC::DFG::FixupPhase::setUseKindAndUnboxIfProfitable):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::doRoundOfDoubleVoting):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::checkArgumentTypes):
* dfg/DFGVariableAccessData.h:
(JSC::DFG::VariableAccessData::VariableAccessData):
(JSC::DFG::VariableAccessData::mergeIsCaptured):
(JSC::DFG::VariableAccessData::mergeIsProfitableToUnbox):
(VariableAccessData):
(JSC::DFG::VariableAccessData::isProfitableToUnbox):
(JSC::DFG::VariableAccessData::shouldUnboxIfPossible):
(JSC::DFG::VariableAccessData::mergeStructureCheckHoistingFailed):
(JSC::DFG::VariableAccessData::mergeIsArgumentsAlias):
(JSC::DFG::VariableAccessData::shouldUseDoubleFormat):
(JSC::DFG::VariableAccessData::mergeFlags):



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@144131 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
index 0de2219..4a9a482 100644
--- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp
@@ -31,6 +31,7 @@
 #include "DFGGraph.h"
 #include "DFGInsertionSet.h"
 #include "DFGPhase.h"
+#include "DFGVariableAccessDataDump.h"
 #include "Operations.h"
 
 namespace JSC { namespace DFG {
@@ -48,8 +49,20 @@
         ASSERT(m_graph.m_fixpointState == BeforeFixpoint);
         ASSERT(m_graph.m_form == ThreadedCPS);
         
+        m_profitabilityChanged = false;
         for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
             fixupBlock(m_graph.m_blocks[blockIndex].get());
+        
+        while (m_profitabilityChanged) {
+            m_profitabilityChanged = false;
+            
+            for (unsigned i = m_graph.m_argumentPositions.size(); i--;)
+                m_graph.m_argumentPositions[i].mergeArgumentUnboxingAwareness();
+            
+            for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex)
+                fixupSetLocalsInBlock(m_graph.m_blocks[blockIndex].get());
+        }
+        
         return true;
     }
 
@@ -80,23 +93,7 @@
         
         switch (op) {
         case SetLocal: {
-            VariableAccessData* variable = node->variableAccessData();
-            
-            if (!variable->shouldUnboxIfPossible())
-                break;
-            
-            if (variable->shouldUseDoubleFormat()) {
-                fixDoubleEdge<NumberUse>(node->child1(), ForwardSpeculation);
-                break;
-            }
-            
-            SpeculatedType predictedType = variable->argumentAwarePrediction();
-            if (isInt32Speculation(predictedType))
-                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
-            else if (isCellSpeculation(predictedType))
-                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
-            else if (isBooleanSpeculation(predictedType))
-                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
+            // This gets handled by fixupSetLocalsInBlock().
             break;
         }
             
@@ -807,6 +804,40 @@
 #endif
     }
     
+    void fixupSetLocalsInBlock(BasicBlock* block)
+    {
+        if (!block)
+            return;
+        ASSERT(block->isReachable);
+        m_block = block;
+        for (m_indexInBlock = 0; m_indexInBlock < block->size(); ++m_indexInBlock) {
+            Node* node = m_currentNode = block->at(m_indexInBlock);
+            if (node->op() != SetLocal)
+                continue;
+            if (!node->shouldGenerate())
+                continue;
+            
+            VariableAccessData* variable = node->variableAccessData();
+            
+            if (!variable->shouldUnboxIfPossible())
+                continue;
+            
+            if (variable->shouldUseDoubleFormat()) {
+                fixDoubleEdge<NumberUse>(node->child1(), ForwardSpeculation);
+                continue;
+            }
+            
+            SpeculatedType predictedType = variable->argumentAwarePrediction();
+            if (isInt32Speculation(predictedType))
+                setUseKindAndUnboxIfProfitable<Int32Use>(node->child1());
+            else if (isCellSpeculation(predictedType))
+                setUseKindAndUnboxIfProfitable<CellUse>(node->child1());
+            else if (isBooleanSpeculation(predictedType))
+                setUseKindAndUnboxIfProfitable<BooleanUse>(node->child1());
+        }
+        m_insertionSet.execute(block);
+    }
+    
     Node* checkArray(ArrayMode arrayMode, CodeOrigin codeOrigin, Node* array, Node* index, bool (*storageCheck)(const ArrayMode&) = canCSEStorage, bool shouldGenerate = true)
     {
         ASSERT(arrayMode.isSpecific());
@@ -895,11 +926,52 @@
         } }
     }
     
+    bool alwaysUnboxSimplePrimitives()
+    {
+#if USE(JSVALUE64)
+        return false;
+#else
+        // Any boolean, int, or cell value is profitable to unbox on 32-bit because it
+        // reduces traffic.
+        return true;
+#endif
+    }
+    
     // Set the use kind of the edge. In the future (https://bugs.webkit.org/show_bug.cgi?id=110433),
     // this can be used to notify the GetLocal that the variable is profitable to unbox.
     template<UseKind useKind>
     void setUseKindAndUnboxIfProfitable(Edge& edge)
     {
+        if (edge->op() == GetLocal) {
+            VariableAccessData* variable = edge->variableAccessData();
+            switch (useKind) {
+            case Int32Use:
+                if (alwaysUnboxSimplePrimitives()
+                    || isInt32Speculation(variable->prediction()))
+                    m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
+                break;
+            case NumberUse:
+            case RealNumberUse:
+                if (variable->doubleFormatState() == UsingDoubleFormat)
+                    m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
+                break;
+            case BooleanUse:
+                if (alwaysUnboxSimplePrimitives()
+                    || isBooleanSpeculation(variable->prediction()))
+                    m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
+                break;
+            case CellUse:
+            case ObjectUse:
+            case StringUse:
+                if (alwaysUnboxSimplePrimitives()
+                    || isCellSpeculation(variable->prediction()))
+                    m_profitabilityChanged |= variable->mergeIsProfitableToUnbox(true);
+                break;
+            default:
+                break;
+            }
+        }
+        
         edge.setUseKind(useKind);
     }
     
@@ -1001,6 +1073,7 @@
     unsigned m_indexInBlock;
     Node* m_currentNode;
     InsertionSet m_insertionSet;
+    bool m_profitabilityChanged;
 };
     
 bool performFixup(Graph& graph)