Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (115092 => 115093)
--- trunk/Source/_javascript_Core/ChangeLog 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-04-24 19:19:35 UTC (rev 115093)
@@ -1,3 +1,44 @@
+2012-04-23 Filip Pizlo <[email protected]>
+
+ DFG on ARMv7 should not OSR exit on every integer division
+ https://bugs.webkit.org/show_bug.cgi?id=84661
+
+ Reviewed by Oliver Hunt.
+
+ On ARMv7, ArithDiv no longer has to know whether or not to speculate integer (since
+ that was broken with the introduction of Int32ToDouble) nor does it have to know
+ whether or not to convert its result to integer. This is now taken care of for free
+ with the addition of the DoubleAsInt32 node, which represents a double-is-really-int
+ speculation.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGFixupPhase.cpp:
+ (JSC::DFG::FixupPhase::fixupNode):
+ * dfg/DFGNodeType.h:
+ (DFG):
+ * dfg/DFGOSRExit.cpp:
+ (JSC::DFG::OSRExit::OSRExit):
+ (JSC::DFG::OSRExit::considerAddingAsFrequentExitSiteSlow):
+ * dfg/DFGOSRExit.h:
+ (OSRExit):
+ * dfg/DFGPredictionPropagationPhase.cpp:
+ (JSC::DFG::PredictionPropagationPhase::propagate):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::computeValueRecoveryFor):
+ (JSC::DFG::SpeculativeJIT::compileDoubleAsInt32):
+ (DFG):
+ * dfg/DFGSpeculativeJIT.h:
+ (SpeculativeJIT):
+ (JSC::DFG::SpeculativeJIT::speculationCheck):
+ (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
2012-04-24 Geoffrey Garen <[email protected]>
"GlobalHandle" HandleHeap (now WeakSet) allocations grow but do not shrink
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -290,6 +290,11 @@
forNode(nodeIndex).set(PredictInt32);
break;
+ case DoubleAsInt32:
+ forNode(node.child1()).filter(PredictNumber);
+ forNode(nodeIndex).set(PredictInt32);
+ break;
+
case ValueToInt32:
if (m_graph[node.child1()].shouldSpeculateInteger())
forNode(node.child1()).filter(PredictInt32);
Modified: trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGCSEPhase.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -594,6 +594,7 @@
case IsString:
case IsObject:
case IsFunction:
+ case DoubleAsInt32:
setReplacement(pureCSE(node));
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -260,10 +260,28 @@
}
case ArithDiv: {
- if (isX86()
- && Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])
- && node.canSpeculateInteger())
+ if (Node::shouldSpeculateInteger(m_graph[node.child1()], m_graph[node.child2()])
+ && node.canSpeculateInteger()) {
+ if (isX86())
+ break;
+ fixDoubleEdge(0);
+ fixDoubleEdge(1);
+
+ Node& oldDivision = m_graph[m_compileIndex];
+
+ Node newDivision = oldDivision;
+ newDivision.setRefCount(2);
+ newDivision.predict(PredictDouble);
+ NodeIndex newDivisionIndex = m_graph.size();
+
+ oldDivision.setOp(DoubleAsInt32);
+ oldDivision.children.initialize(Edge(newDivisionIndex, DoubleUse), Edge(), Edge());
+
+ m_graph.append(newDivision);
+ m_insertionSet.append(m_indexInBlock, newDivisionIndex);
+
break;
+ }
fixDoubleEdge(0);
fixDoubleEdge(1);
break;
Modified: trunk/Source/_javascript_Core/dfg/DFGNodeType.h (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGNodeType.h 2012-04-24 19:19:35 UTC (rev 115093)
@@ -78,6 +78,8 @@
/* Used to cast known integers to doubles, so as to separate the double form */\
/* of the value from the integer form. */\
macro(Int32ToDouble, NodeResultNumber) \
+ /* Used to speculate that a double value is actually an integer. */\
+ macro(DoubleAsInt32, NodeResultInt32) \
\
/* Nodes for arithmetic operations. */\
macro(ArithAdd, NodeResultNumber | NodeMustGenerate) \
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExit.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -49,6 +49,7 @@
, m_check(check)
, m_nodeIndex(jit->m_compileIndex)
, m_codeOrigin(jit->m_codeOriginForOSR)
+ , m_codeOriginForExitProfile(m_codeOrigin)
, m_recoveryIndex(recoveryIndex)
, m_kind(kind)
, m_count(0)
@@ -77,7 +78,7 @@
if (static_cast<double>(m_count) / dfgCodeBlock->speculativeFailCounter() <= Options::osrExitProminenceForFrequentExitSite)
return false;
- return baselineCodeBlockForOriginAndBaselineCodeBlock(m_codeOrigin, profiledCodeBlock)->addFrequentExitSite(FrequentExitSite(m_codeOrigin.bytecodeIndex, m_kind));
+ return baselineCodeBlockForOriginAndBaselineCodeBlock(m_codeOriginForExitProfile, profiledCodeBlock)->addFrequentExitSite(FrequentExitSite(m_codeOriginForExitProfile.bytecodeIndex, m_kind));
}
} } // namespace JSC::DFG
Modified: trunk/Source/_javascript_Core/dfg/DFGOSRExit.h (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGOSRExit.h 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGOSRExit.h 2012-04-24 19:19:35 UTC (rev 115093)
@@ -93,6 +93,7 @@
CorrectableJumpPoint m_check;
NodeIndex m_nodeIndex;
CodeOrigin m_codeOrigin;
+ CodeOrigin m_codeOriginForExitProfile;
unsigned m_recoveryIndex;
Modified: trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGPredictionPropagationPhase.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -573,7 +573,8 @@
case GetFloat32ArrayLength:
case GetFloat64ArrayLength:
case GetStringLength:
- case Int32ToDouble: {
+ case Int32ToDouble:
+ case DoubleAsInt32: {
// 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 (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -1343,10 +1343,13 @@
// The reverse of the above: This node could be a UInt32ToNumber, but its
// alternative is still alive. This means that the only remaining uses of
// the number would be fine with a UInt32 intermediate.
+ //
+ // DoubleAsInt32: Same as UInt32ToNumber.
+ //
bool found = false;
- if (nodePtr->op() == UInt32ToNumber) {
+ if (nodePtr->op() == UInt32ToNumber || nodePtr->op() == DoubleAsInt32) {
NodeIndex nodeIndex = nodePtr->child1().index();
nodePtr = &at(nodeIndex);
infoPtr = &m_generationInfo[nodePtr->virtualRegister()];
@@ -1358,6 +1361,7 @@
NodeIndex int32ToDoubleIndex = NoNode;
NodeIndex valueToInt32Index = NoNode;
NodeIndex uint32ToNumberIndex = NoNode;
+ NodeIndex doubleAsInt32Index = NoNode;
for (unsigned virtualRegister = 0; virtualRegister < m_generationInfo.size(); ++virtualRegister) {
GenerationInfo& info = m_generationInfo[virtualRegister];
@@ -1378,13 +1382,17 @@
case UInt32ToNumber:
uint32ToNumberIndex = info.nodeIndex();
break;
+ case DoubleAsInt32:
+ doubleAsInt32Index = info.nodeIndex();
default:
break;
}
}
NodeIndex nodeIndexToUse;
- if (int32ToDoubleIndex != NoNode)
+ if (doubleAsInt32Index != NoNode)
+ nodeIndexToUse = doubleAsInt32Index;
+ else if (int32ToDoubleIndex != NoNode)
nodeIndexToUse = int32ToDoubleIndex;
else if (valueToInt32Index != NoNode)
nodeIndexToUse = valueToInt32Index;
@@ -1729,6 +1737,23 @@
integerResult(result.gpr(), m_compileIndex, op1.format());
}
+void SpeculativeJIT::compileDoubleAsInt32(Node& node)
+{
+ SpeculateDoubleOperand op1(this, node.child1());
+ FPRTemporary scratch(this);
+ GPRTemporary result(this);
+
+ FPRReg valueFPR = op1.fpr();
+ FPRReg scratchFPR = scratch.fpr();
+ GPRReg resultGPR = result.gpr();
+
+ JITCompiler::JumpList failureCases;
+ m_jit.branchConvertDoubleToInt32(valueFPR, resultGPR, failureCases, scratchFPR);
+ forwardSpeculationCheck(Overflow, JSValueRegs(), NoNode, failureCases, ValueRecovery::inFPR(valueFPR));
+
+ integerResult(resultGPR, m_compileIndex);
+}
+
void SpeculativeJIT::compileInt32ToDouble(Node& node)
{
#if USE(JSVALUE64)
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h 2012-04-24 19:19:35 UTC (rev 115093)
@@ -1751,6 +1751,7 @@
void compileGetByValOnString(Node&);
void compileValueToInt32(Node&);
void compileUInt32ToNumber(Node&);
+ void compileDoubleAsInt32(Node&);
void compileInt32ToDouble(Node&);
void compileGetByValOnByteArray(Node&);
void compilePutByValForByteArray(GPRReg base, GPRReg property, Node&);
@@ -1848,9 +1849,9 @@
// Add a set of speculation checks without additional recovery.
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail)
{
- Vector<MacroAssembler::Jump, 16> JumpVector = jumpsToFail.jumps();
- for (unsigned i = 0; i < JumpVector.size(); ++i)
- speculationCheck(kind, jsValueSource, nodeIndex, JumpVector[i]);
+ Vector<MacroAssembler::Jump, 16> jumpVector = jumpsToFail.jumps();
+ for (unsigned i = 0; i < jumpVector.size(); ++i)
+ speculationCheck(kind, jsValueSource, nodeIndex, jumpVector[i]);
}
void speculationCheck(ExitKind kind, JSValueSource jsValueSource, Edge nodeUse, MacroAssembler::JumpList& jumpsToFail)
{
@@ -1872,18 +1873,33 @@
{
speculationCheck(kind, jsValueSource, nodeIndex, jumpToFail);
- Node& setLocal = at(m_jit.graph().m_blocks[m_block]->at(m_indexInBlock + 1));
- Node& nextNode = at(m_jit.graph().m_blocks[m_block]->at(m_indexInBlock + 2));
- ASSERT(setLocal.op() == SetLocal);
- ASSERT(setLocal.codeOrigin == at(m_compileIndex).codeOrigin);
+ unsigned setLocalIndexInBlock = m_indexInBlock + 1;
+
+ Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock));
+
+ if (setLocal->op() == Int32ToDouble) {
+ setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
+ ASSERT(at(setLocal->child1()).child1() == m_compileIndex);
+ } else
+ ASSERT(setLocal->child1() == m_compileIndex);
+
+ Node& nextNode = at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1));
+ ASSERT(setLocal->op() == SetLocal);
+ ASSERT(setLocal->codeOrigin == at(m_compileIndex).codeOrigin);
ASSERT(nextNode.codeOrigin != at(m_compileIndex).codeOrigin);
OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
exit.m_codeOrigin = nextNode.codeOrigin;
- exit.m_lastSetOperand = setLocal.local();
+ exit.m_lastSetOperand = setLocal->local();
- exit.valueRecoveryForOperand(setLocal.local()) = valueRecovery;
+ exit.valueRecoveryForOperand(setLocal->local()) = valueRecovery;
}
+ void forwardSpeculationCheck(ExitKind kind, JSValueSource jsValueSource, NodeIndex nodeIndex, MacroAssembler::JumpList& jumpsToFail, const ValueRecovery& valueRecovery)
+ {
+ Vector<MacroAssembler::Jump, 16> jumpVector = jumpsToFail.jumps();
+ for (unsigned i = 0; i < jumpVector.size(); ++i)
+ forwardSpeculationCheck(kind, jsValueSource, nodeIndex, jumpVector[i], valueRecovery);
+ }
// Called when we statically determine that a speculation will fail.
void terminateSpeculativeExecution(ExitKind kind, JSValueRegs jsValueRegs, NodeIndex nodeIndex)
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -2038,6 +2038,11 @@
compileUInt32ToNumber(node);
break;
}
+
+ case DoubleAsInt32: {
+ compileDoubleAsInt32(node);
+ break;
+ }
case ValueToInt32: {
compileValueToInt32(node);
@@ -2071,25 +2076,7 @@
#if CPU(X86)
compileIntegerArithDivForX86(node);
#else // CPU(X86) -> so non-X86 code follows
- SpeculateDoubleOperand op1(this, node.child1());
- SpeculateDoubleOperand op2(this, node.child2());
- FPRTemporary result(this);
- FPRTemporary scratch(this);
- GPRTemporary intResult(this);
-
- FPRReg op1FPR = op1.fpr();
- FPRReg op2FPR = op2.fpr();
- FPRReg resultFPR = result.fpr();
- FPRReg scratchFPR = scratch.fpr();
- GPRReg resultGPR = intResult.gpr();
-
- m_jit.divDouble(op1FPR, op2FPR, resultFPR);
-
- JITCompiler::JumpList failureCases;
- m_jit.branchConvertDoubleToInt32(resultFPR, resultGPR, failureCases, scratchFPR);
- speculationCheck(Overflow, JSValueRegs(), NoNode, failureCases);
-
- integerResult(resultGPR, m_compileIndex);
+ ASSERT_NOT_REACHED(); // should have been coverted into a double divide.
#endif // CPU(X86)
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (115092 => 115093)
--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-04-24 19:11:12 UTC (rev 115092)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp 2012-04-24 19:19:35 UTC (rev 115093)
@@ -2114,6 +2114,11 @@
break;
}
+ case DoubleAsInt32: {
+ compileDoubleAsInt32(node);
+ break;
+ }
+
case ValueToInt32: {
compileValueToInt32(node);
break;