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)