Title: [122541] trunk
Revision
122541
Author
[email protected]
Date
2012-07-12 22:31:05 -0700 (Thu, 12 Jul 2012)

Log Message

DFG CFA may get overzealous in loops that have code that must exit
https://bugs.webkit.org/show_bug.cgi?id=91188

Source/_javascript_Core: 

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):

LayoutTests: 

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):

Modified Paths

Added Paths

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());
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to