Diff
Modified: trunk/LayoutTests/ChangeLog (122540 => 122541)
--- trunk/LayoutTests/ChangeLog 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/LayoutTests/ChangeLog 2012-07-13 05:31:05 UTC (rev 122541)
@@ -1,3 +1,15 @@
+2012-07-12 Filip Pizlo <[email protected]>
+
+ DFG CFA may get overzealous in loops that have code that must exit
+ https://bugs.webkit.org/show_bug.cgi?id=91188
+
+ Reviewed by Gavin Baraclough.
+
+ * fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop-expected.txt: Added.
+ * fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.html: Added.
+ * fast/js/script-tests/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.js: Added.
+ (foo):
+
2012-07-12 Eric Seidel <[email protected]>
Incorrect behaviour calling Range setStart or setEnd with boundary in different document
Added: trunk/LayoutTests/fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop-expected.txt (0 => 122541)
--- trunk/LayoutTests/fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop-expected.txt 2012-07-13 05:31:05 UTC (rev 122541)
@@ -0,0 +1,209 @@
+Checks that increased aggressiveness in sparse conditional constant propagation resultin from a node being proven to be force exit does not lead to a cascade of unsound decisions.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS foo(array) is 8746
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.html (0 => 122541)
--- trunk/LayoutTests/fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.html (rev 0)
+++ trunk/LayoutTests/fast/js/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.html 2012-07-13 05:31:05 UTC (rev 122541)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<script src=""
+</head>
+<body>
+<script src=""
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/fast/js/script-tests/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.js (0 => 122541)
--- trunk/LayoutTests/fast/js/script-tests/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.js (rev 0)
+++ trunk/LayoutTests/fast/js/script-tests/dfg-force-exit-then-sparse-conditional-constant-prop-in-loop.js 2012-07-13 05:31:05 UTC (rev 122541)
@@ -0,0 +1,22 @@
+description(
+"Checks that increased aggressiveness in sparse conditional constant propagation resultin from a node being proven to be force exit does not lead to a cascade of unsound decisions."
+);
+
+function foo(a) {
+ var i;
+ if (a.push)
+ i = 0;
+ else
+ i = a;
+ var result = 0;
+ while (i < 10) {
+ result += a[i];
+ i++;
+ }
+ return result;
+}
+
+var array = [54, 5432, 1234, 54, 1235, 64, 75, 532, 64, 2];
+
+for (var i = 0; i < 200; ++i)
+ shouldBe("foo(array)", "8746");
Modified: trunk/Source/_javascript_Core/ChangeLog (122540 => 122541)
--- trunk/Source/_javascript_Core/ChangeLog 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/Source/_javascript_Core/ChangeLog 2012-07-13 05:31:05 UTC (rev 122541)
@@ -1,3 +1,37 @@
+2012-07-12 Filip Pizlo <[email protected]>
+
+ DFG CFA may get overzealous in loops that have code that must exit
+ https://bugs.webkit.org/show_bug.cgi?id=91188
+
+ Reviewed by Gavin Barraclough.
+
+ Ensure that if the CFA assumes that an operation must exit, then it will always exit
+ no matter what happens after. That's necessary to preserve soundness.
+
+ Remove a broken fixup done by the DFG simplifier, where it was trying to say that the
+ variable-at-head was the first access in the second block in the merge, if the first
+ block did not read the variable. That's totally wrong, if the first block was in fact
+ doing a phantom read. I removed that fixup and instead hardened the rest of the
+ compiler.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::endBasicBlock):
+ * dfg/DFGBasicBlock.h:
+ (JSC::DFG::BasicBlock::BasicBlock):
+ (BasicBlock):
+ * dfg/DFGCFAPhase.cpp:
+ (JSC::DFG::CFAPhase::performBlockCFA):
+ * dfg/DFGCFGSimplificationPhase.cpp:
+ (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::ConstantFoldingPhase):
+ (JSC::DFG::ConstantFoldingPhase::run):
+ (ConstantFoldingPhase):
+ (JSC::DFG::ConstantFoldingPhase::foldConstants):
+ (JSC::DFG::ConstantFoldingPhase::paintUnreachableCode):
+ * dfg/DFGVariableEventStream.cpp:
+ (JSC::DFG::VariableEventStream::reconstruct):
+
2012-07-12 Allan Sandfeld Jensen <[email protected]>
[Qt] Implement MemoryUsageSupport
Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (122540 => 122541)
--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp 2012-07-13 05:31:05 UTC (rev 122541)
@@ -52,6 +52,10 @@
ASSERT(basicBlock->variablesAtTail.numberOfLocals() == basicBlock->valuesAtTail.numberOfLocals());
ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->variablesAtTail.numberOfLocals());
+ // This is usually a no-op, but it is possible that the graph has grown since the
+ // abstract state was last used.
+ m_nodes.resize(m_graph.size());
+
for (size_t i = 0; i < basicBlock->size(); i++)
m_nodes[basicBlock->at(i)].clear();
@@ -164,6 +168,7 @@
BasicBlock* block = m_block; // Save the block for successor merging.
block->cfaFoundConstants = m_foundConstants;
+ block->cfaDidFinish = m_isValid;
if (!m_isValid) {
reset();
Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h (122540 => 122541)
--- trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h 2012-07-13 05:31:05 UTC (rev 122541)
@@ -45,6 +45,7 @@
, cfaHasVisited(false)
, cfaShouldRevisit(false)
, cfaFoundConstants(false)
+ , cfaDidFinish(true)
#if !ASSERT_DISABLED
, isLinked(false)
#endif
@@ -103,6 +104,7 @@
bool cfaHasVisited;
bool cfaShouldRevisit;
bool cfaFoundConstants;
+ bool cfaDidFinish;
#if !ASSERT_DISABLED
bool isLinked;
#endif
Modified: trunk/Source/_javascript_Core/dfg/DFGCFAPhase.cpp (122540 => 122541)
--- trunk/Source/_javascript_Core/dfg/DFGCFAPhase.cpp 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/Source/_javascript_Core/dfg/DFGCFAPhase.cpp 2012-07-13 05:31:05 UTC (rev 122541)
@@ -95,8 +95,12 @@
m_state.dump(WTF::dataFile());
dataLog("\n");
#endif
- if (!m_state.execute(i))
+ if (!m_state.execute(i)) {
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" Expect OSR exit.\n");
+#endif
break;
+ }
}
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" tail regs: ");
Modified: trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp (122540 => 122541)
--- trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp 2012-07-13 05:31:05 UTC (rev 122541)
@@ -643,18 +643,6 @@
NodeIndex atFirstIndex = firstBlock->variablesAtTail.operand(node.local());
m_graph.changeEdge(node.children.child1(), Edge(skipGetLocal(atFirstIndex)), node.shouldGenerate());
childrenAlreadyFixed = true;
-
- if (node.op() != GetLocal)
- break;
-
- NodeIndex atFirstHeadIndex = firstBlock->variablesAtHead.operand(node.local());
- if (atFirstHeadIndex == NoNode)
- break;
-
- if (m_graph[atFirstHeadIndex].op() != Phi)
- break;
-
- firstBlock->variablesAtHead.operand(node.local()) = nodeIndex;
break;
}
Modified: trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp (122540 => 122541)
--- trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/Source/_javascript_Core/dfg/DFGConstantFoldingPhase.cpp 2012-07-13 05:31:05 UTC (rev 122541)
@@ -40,6 +40,7 @@
public:
ConstantFoldingPhase(Graph& graph)
: Phase(graph, "constant folding")
+ , m_state(graph)
{
}
@@ -47,114 +48,192 @@
{
bool changed = false;
- AbstractState state(m_graph);
- InsertionSet<NodeIndex> insertionSet;
-
for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) {
BasicBlock* block = m_graph.m_blocks[blockIndex].get();
if (!block)
continue;
- if (!block->cfaFoundConstants)
- continue;
+ if (!block->cfaDidFinish)
+ changed |= paintUnreachableCode(blockIndex);
+ if (block->cfaFoundConstants)
+ changed |= foldConstants(blockIndex);
+ }
+
+ return changed;
+ }
+
+private:
+ bool foldConstants(BlockIndex blockIndex)
+ {
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog("Constant folding considering Block #%u.\n", blockIndex);
+ dataLog("Constant folding considering Block #%u.\n", blockIndex);
#endif
- state.beginBasicBlock(block);
- for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
- if (!state.isValid())
- break;
- NodeIndex nodeIndex = block->at(indexInBlock);
- Node& node = m_graph[nodeIndex];
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ bool changed = false;
+ m_state.beginBasicBlock(block);
+ for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+ NodeIndex nodeIndex = block->at(indexInBlock);
+ Node& node = m_graph[nodeIndex];
- bool eliminated = false;
+ if (!m_state.isValid())
+ break;
+
+ bool eliminated = false;
- switch (node.op()) {
- case CheckArgumentsNotCreated: {
- if (!isEmptySpeculation(
- state.variables().operand(
- m_graph.argumentsRegisterFor(node.codeOrigin)).m_type))
- break;
- ASSERT(node.refCount() == 1);
- node.setOpAndDefaultFlags(Phantom);
- eliminated = true;
+ switch (node.op()) {
+ case CheckArgumentsNotCreated: {
+ if (!isEmptySpeculation(
+ m_state.variables().operand(
+ m_graph.argumentsRegisterFor(node.codeOrigin)).m_type))
break;
- }
+ ASSERT(node.refCount() == 1);
+ node.setOpAndDefaultFlags(Phantom);
+ eliminated = true;
+ break;
+ }
// FIXME: This would be a great place to remove CheckStructure's.
- default:
- break;
- }
+ default:
+ break;
+ }
- if (eliminated) {
- changed = true;
- continue;
- }
+ if (eliminated) {
+ changed = true;
+ continue;
+ }
- state.execute(indexInBlock);
- if (!node.shouldGenerate()
- || state.didClobber()
- || node.hasConstant())
- continue;
- JSValue value = state.forNode(nodeIndex).value();
- if (!value)
- continue;
+ m_state.execute(indexInBlock);
+ if (!node.shouldGenerate()
+ || m_state.didClobber()
+ || node.hasConstant())
+ continue;
+ JSValue value = m_state.forNode(nodeIndex).value();
+ if (!value)
+ continue;
- Node phantom(Phantom, node.codeOrigin);
+ Node phantom(Phantom, node.codeOrigin);
- if (node.op() == GetLocal) {
- NodeIndex previousLocalAccess = NoNode;
- if (block->variablesAtHead.operand(node.local()) == nodeIndex
- && m_graph[node.child1()].op() == Phi) {
- // We expect this to be the common case.
- ASSERT(block->isInPhis(node.child1().index()));
- previousLocalAccess = node.child1().index();
- block->variablesAtHead.operand(node.local()) = previousLocalAccess;
- } else {
- ASSERT(indexInBlock > 0);
- // Must search for the previous access to this local.
- for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) {
- NodeIndex subNodeIndex = block->at(subIndexInBlock);
- Node& subNode = m_graph[subNodeIndex];
- if (!subNode.shouldGenerate())
+ if (node.op() == GetLocal) {
+ NodeIndex previousLocalAccess = NoNode;
+ if (block->variablesAtHead.operand(node.local()) == nodeIndex
+ && m_graph[node.child1()].op() == Phi) {
+ // We expect this to be the common case.
+ ASSERT(block->isInPhis(node.child1().index()));
+ previousLocalAccess = node.child1().index();
+ block->variablesAtHead.operand(node.local()) = previousLocalAccess;
+ } else {
+ ASSERT(indexInBlock > 0);
+ // Must search for the previous access to this local.
+ for (BlockIndex subIndexInBlock = indexInBlock; subIndexInBlock--;) {
+ NodeIndex subNodeIndex = block->at(subIndexInBlock);
+ Node& subNode = m_graph[subNodeIndex];
+ if (!subNode.shouldGenerate())
+ continue;
+ if (!subNode.hasVariableAccessData())
+ continue;
+ if (subNode.local() != node.local())
+ continue;
+ // The two must have been unified.
+ ASSERT(subNode.variableAccessData() == node.variableAccessData());
+ previousLocalAccess = subNodeIndex;
+ break;
+ }
+ if (previousLocalAccess == NoNode) {
+ // The previous access must have been a Phi.
+ for (BlockIndex phiIndexInBlock = block->phis.size(); phiIndexInBlock--;) {
+ NodeIndex phiNodeIndex = block->phis[phiIndexInBlock];
+ Node& phiNode = m_graph[phiNodeIndex];
+ if (!phiNode.shouldGenerate())
continue;
- if (!subNode.hasVariableAccessData())
+ if (phiNode.local() != node.local())
continue;
- if (subNode.local() != node.local())
- continue;
// The two must have been unified.
- ASSERT(subNode.variableAccessData() == node.variableAccessData());
- previousLocalAccess = subNodeIndex;
+ ASSERT(phiNode.variableAccessData() == node.variableAccessData());
+ previousLocalAccess = phiNodeIndex;
break;
}
ASSERT(previousLocalAccess != NoNode);
}
+ }
- NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local());
- if (tailNodeIndex == nodeIndex)
- block->variablesAtTail.operand(node.local()) = previousLocalAccess;
- else {
- ASSERT(m_graph[tailNodeIndex].op() == Flush
- || m_graph[tailNodeIndex].op() == SetLocal);
- }
+ ASSERT(previousLocalAccess != NoNode);
+
+ NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local());
+ if (tailNodeIndex == nodeIndex)
+ block->variablesAtTail.operand(node.local()) = previousLocalAccess;
+ else {
+ ASSERT(m_graph[tailNodeIndex].op() == Flush
+ || m_graph[tailNodeIndex].op() == SetLocal);
}
+ }
- phantom.children = node.children;
- phantom.ref();
+ phantom.children = node.children;
+ phantom.ref();
+
+ m_graph.convertToConstant(nodeIndex, value);
+ NodeIndex phantomNodeIndex = m_graph.size();
+ m_graph.append(phantom);
+ m_insertionSet.append(indexInBlock, phantomNodeIndex);
- m_graph.convertToConstant(nodeIndex, value);
- NodeIndex phantomNodeIndex = m_graph.size();
- m_graph.append(phantom);
- insertionSet.append(indexInBlock, phantomNodeIndex);
+ changed = true;
+ }
+ m_state.reset();
+ m_insertionSet.execute(*block);
+
+ return changed;
+ }
+
+ // This is necessary because the CFA may reach conclusions about constants based on its
+ // assumption that certain code must exit, but then those constants may lead future
+ // reexecutions of the CFA to believe that the same code will now no longer exit. Thus
+ // to ensure soundness, we must paint unreachable code as such, by inserting an
+ // unconditional ForceOSRExit wherever we find that a node would have always exited.
+ // This will only happen in cases where we are making static speculations, or we're
+ // making totally wrong speculations due to imprecision on the prediction propagator.
+ bool paintUnreachableCode(BlockIndex blockIndex)
+ {
+ bool changed = false;
+
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog("Painting unreachable code in Block #%u.\n", blockIndex);
+#endif
+ BasicBlock* block = m_graph.m_blocks[blockIndex].get();
+ m_state.beginBasicBlock(block);
+
+ for (unsigned indexInBlock = 0; indexInBlock < block->size(); ++indexInBlock) {
+ m_state.execute(indexInBlock);
+ if (m_state.isValid())
+ continue;
+
+ NodeIndex nodeIndex = block->at(indexInBlock);
+ Node& node = m_graph[nodeIndex];
+ switch (node.op()) {
+ case Return:
+ case Throw:
+ case ThrowReferenceError:
+ case ForceOSRExit:
+ // Do nothing. These nodes will already do the right thing.
+ break;
+ default:
+ Node forceOSRExit(ForceOSRExit, node.codeOrigin);
+ forceOSRExit.ref();
+ NodeIndex forceOSRExitIndex = m_graph.size();
+ m_graph.append(forceOSRExit);
+ m_insertionSet.append(indexInBlock, forceOSRExitIndex);
changed = true;
+ break;
}
- insertionSet.execute(*block);
- state.reset();
+ break;
}
+ m_state.reset();
+ m_insertionSet.execute(*block);
return changed;
}
+
+ AbstractState m_state;
+ InsertionSet<NodeIndex> m_insertionSet;
};
bool performConstantFolding(Graph& graph)
Modified: trunk/Source/_javascript_Core/dfg/DFGVariableEventStream.cpp (122540 => 122541)
--- trunk/Source/_javascript_Core/dfg/DFGVariableEventStream.cpp 2012-07-13 05:08:23 UTC (rev 122540)
+++ trunk/Source/_javascript_Core/dfg/DFGVariableEventStream.cpp 2012-07-13 05:31:05 UTC (rev 122541)
@@ -102,6 +102,10 @@
while (at(startIndex).kind() != Reset)
startIndex--;
+#if DFG_ENABLE(DEBUG_VERBOSE)
+ dataLog("Computing OSR exit recoveries starting at seq#%u.\n", startIndex);
+#endif
+
// Step 2: Create a mock-up of the DFG's state and execute the events.
Operands<ValueSource> operandSources(codeBlock->numParameters(), numVariables);
Vector<MinifiedGenerationInfo, 32> generationInfos(graph.originalGraphSize());