Title: [192190] trunk/Source/_javascript_Core
Revision
192190
Author
sbar...@apple.com
Date
2015-11-09 16:39:13 -0800 (Mon, 09 Nov 2015)

Log Message

DFG::PutStackSinkingPhase should not treat the stack variables written by LoadVarargs/ForwardVarargs as being live
https://bugs.webkit.org/show_bug.cgi?id=145295

Reviewed by Filip Pizlo.

This patch fixes PutStackSinkingPhase to no longer escape the stack
locations that LoadVarargs and ForwardVarargs write to. We used
to consider sinking PutStacks right before a LoadVarargs/ForwardVarargs
because we considered them uses of such stack locations. They aren't
uses of those stack locations, they unconditionally write to those
stack locations. Sinking PutStacks to these nodes was not needed before,
but seemed mostly innocent. But I ran into a problem with this while implementing 
FTL try/catch where we would end up having to generate a value for a sunken PutStack 
right before a LoadVarargs. This would cause us to issue a GetStack that loaded garbage that 
was then forwarded into a Phi that was used as the source as the PutStack. This caused the
abstract interpreter to confuse itself on type information for the garbage GetStack
that was fed into the Phi, which would cause the abstract interpreter to then claim 
that the basic block with the PutStack in it would never be reached. This isn't true, the 
block would indeed be reached. The solution here is to be more precise about the 
liveness of locals w.r.t LoadVarargs and ForwardVarargs.

* dfg/DFGPreciseLocalClobberize.h:
(JSC::DFG::PreciseLocalClobberizeAdaptor::PreciseLocalClobberizeAdaptor):
(JSC::DFG::PreciseLocalClobberizeAdaptor::write):
* dfg/DFGPutStackSinkingPhase.cpp:
* dfg/DFGSSACalculator.h:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (192189 => 192190)


--- trunk/Source/_javascript_Core/ChangeLog	2015-11-10 00:36:14 UTC (rev 192189)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-11-10 00:39:13 UTC (rev 192190)
@@ -1,3 +1,32 @@
+2015-11-09  Saam barati  <sbar...@apple.com>
+
+        DFG::PutStackSinkingPhase should not treat the stack variables written by LoadVarargs/ForwardVarargs as being live
+        https://bugs.webkit.org/show_bug.cgi?id=145295
+
+        Reviewed by Filip Pizlo.
+
+        This patch fixes PutStackSinkingPhase to no longer escape the stack
+        locations that LoadVarargs and ForwardVarargs write to. We used
+        to consider sinking PutStacks right before a LoadVarargs/ForwardVarargs
+        because we considered them uses of such stack locations. They aren't
+        uses of those stack locations, they unconditionally write to those
+        stack locations. Sinking PutStacks to these nodes was not needed before,
+        but seemed mostly innocent. But I ran into a problem with this while implementing 
+        FTL try/catch where we would end up having to generate a value for a sunken PutStack 
+        right before a LoadVarargs. This would cause us to issue a GetStack that loaded garbage that 
+        was then forwarded into a Phi that was used as the source as the PutStack. This caused the
+        abstract interpreter to confuse itself on type information for the garbage GetStack
+        that was fed into the Phi, which would cause the abstract interpreter to then claim 
+        that the basic block with the PutStack in it would never be reached. This isn't true, the 
+        block would indeed be reached. The solution here is to be more precise about the 
+        liveness of locals w.r.t LoadVarargs and ForwardVarargs.
+
+        * dfg/DFGPreciseLocalClobberize.h:
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::PreciseLocalClobberizeAdaptor):
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::write):
+        * dfg/DFGPutStackSinkingPhase.cpp:
+        * dfg/DFGSSACalculator.h:
+
 2015-11-09  Filip Pizlo  <fpi...@apple.com>
 
         B3->Air lowering should support CCall

Modified: trunk/Source/_javascript_Core/dfg/DFGPreciseLocalClobberize.h (192189 => 192190)


--- trunk/Source/_javascript_Core/dfg/DFGPreciseLocalClobberize.h	2015-11-10 00:36:14 UTC (rev 192189)
+++ trunk/Source/_javascript_Core/dfg/DFGPreciseLocalClobberize.h	2015-11-10 00:39:13 UTC (rev 192190)
@@ -42,7 +42,7 @@
         : m_graph(graph)
         , m_node(node)
         , m_read(read)
-        , m_write(write)
+        , m_unconditionalWrite(write)
         , m_def(def)
     {
     }
@@ -70,7 +70,7 @@
         // We expect stack writes to already be precisely characterized by DFG::clobberize().
         if (heap.kind() == Stack) {
             RELEASE_ASSERT(!heap.payload().isTop());
-            callIfAppropriate(m_write, VirtualRegister(heap.payload().value32()));
+            callIfAppropriate(m_unconditionalWrite, VirtualRegister(heap.payload().value32()));
             return;
         }
         
@@ -155,7 +155,7 @@
     Graph& m_graph;
     Node* m_node;
     const ReadFunctor& m_read;
-    const WriteFunctor& m_write;
+    const WriteFunctor& m_unconditionalWrite;
     const DefFunctor& m_def;
 };
 

Modified: trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp (192189 => 192190)


--- trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp	2015-11-10 00:36:14 UTC (rev 192189)
+++ trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp	2015-11-10 00:39:13 UTC (rev 192190)
@@ -108,31 +108,29 @@
                     if (verbose)
                         dataLog("Live at ", node, ": ", live, "\n");
                     
+                    Vector<VirtualRegister, 4> reads;
+                    Vector<VirtualRegister, 4> writes;
                     auto escapeHandler = [&] (VirtualRegister operand) {
                         if (operand.isHeader())
                             return;
                         if (verbose)
                             dataLog("    ", operand, " is live at ", node, "\n");
-                        live.operand(operand) = true;
+                        reads.append(operand);
                     };
-                    
-                    // FIXME: This might mishandle LoadVarargs and ForwardVarargs. It might make us
-                    // think that the locals being written are stack-live here. They aren't. This
-                    // should be harmless since we overwrite them anyway, but still, it's sloppy.
-                    // https://bugs.webkit.org/show_bug.cgi?id=145295
+
+                    auto writeHandler = [&] (VirtualRegister operand) {
+                        RELEASE_ASSERT(node->op() == PutStack || node->op() == LoadVarargs || node->op() == ForwardVarargs);
+                        writes.append(operand);
+                    };
+
                     preciseLocalClobberize(
-                        m_graph, node, escapeHandler, escapeHandler,
-                        [&] (VirtualRegister operand, LazyNode source) {
-                            RELEASE_ASSERT(source.isNode());
+                        m_graph, node, escapeHandler, writeHandler,
+                        [&] (VirtualRegister, LazyNode) { });
 
-                            if (source.asNode() == node) {
-                                // This is a load. Ignore it.
-                                return;
-                            }
-                            
-                            RELEASE_ASSERT(node->op() == PutStack);
-                            live.operand(operand) = false;
-                        });
+                    for (VirtualRegister operand : writes)
+                        live.operand(operand) = false;
+                    for (VirtualRegister operand : reads)
+                        live.operand(operand) = true;
                 }
                 
                 if (live == liveAtHead[block])
@@ -205,10 +203,13 @@
         //     Represents the fact that the original code would have done a PutStack but we haven't
         //     identified an operation that would have observed that PutStack.
         //
-        // This code has some interesting quirks because of the fact that neither liveness nor
-        // deferrals are very precise. They are only precise enough to be able to correctly tell us
-        // when we may [sic] need to execute PutStacks. This means that they may report the need to
-        // execute a PutStack in cases where we actually don't really need it, and that's totally OK.
+        // We need to be precise about liveness in this phase because not doing so
+        // could cause us to insert a PutStack before a node we thought may escape a 
+        // value that it doesn't really escape. Sinking this PutStack above such a node may
+        // cause us to insert a GetStack that we forward to the Phi we're feeding into the
+        // sunken PutStack. Inserting such a GetStack could cause us to load garbage and
+        // can confuse the AI to claim untrue things (like that the program will exit when
+        // it really won't).
         BlockMap<Operands<FlushFormat>> deferredAtHead(m_graph);
         BlockMap<Operands<FlushFormat>> deferredAtTail(m_graph);
         
@@ -269,6 +270,10 @@
                         // A GetStack doesn't affect anything, since we know which local we are reading
                         // from.
                         continue;
+                    } else if (node->op() == PutStack) {
+                        VirtualRegister operand = node->stackAccessData()->local;
+                        deferred.operand(operand) = node->stackAccessData()->format;
+                        continue;
                     }
                     
                     auto escapeHandler = [&] (VirtualRegister operand) {
@@ -279,19 +284,15 @@
                         // We will materialize just before any reads.
                         deferred.operand(operand) = DeadFlush;
                     };
+
+                    auto writeHandler = [&] (VirtualRegister operand) {
+                        RELEASE_ASSERT(node->op() == LoadVarargs || node->op() == ForwardVarargs);
+                        deferred.operand(operand) = DeadFlush;
+                    };
                     
                     preciseLocalClobberize(
-                        m_graph, node, escapeHandler, escapeHandler,
-                        [&] (VirtualRegister operand, LazyNode source) {
-                            RELEASE_ASSERT(source.isNode());
-
-                            if (source.asNode() == node) {
-                                // This is a load. Ignore it.
-                                return;
-                            }
-                            
-                            deferred.operand(operand) = node->stackAccessData()->format;
-                        });
+                        m_graph, node, escapeHandler, writeHandler,
+                        [&] (VirtualRegister, LazyNode) { });
                 }
                 
                 if (deferred == deferredAtTail[block])
@@ -351,13 +352,13 @@
             indexToOperand.append(operand);
         }
         
-        HashSet<Node*> putLocalsToSink;
+        HashSet<Node*> putStacksToSink;
         
         for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
             for (Node* node : *block) {
                 switch (node->op()) {
                 case PutStack:
-                    putLocalsToSink.add(node);
+                    putStacksToSink.add(node);
                     ssaCalculator.newDef(
                         operandToVariable.operand(node->stackAccessData()->local),
                         block, node->child1().node());
@@ -496,9 +497,19 @@
                     
                         deferred.operand(operand) = DeadFlush;
                     };
-                
+
+                    auto writeHandler = [&] (VirtualRegister operand) {
+                        // LoadVarargs and ForwardVarargs are unconditional writes to the stack
+                        // locations they claim to write to. They do not read from the stack 
+                        // locations they write to. This makes those stack locations dead right 
+                        // before a LoadVarargs/ForwardVarargs. This means we should never sink
+                        // PutStacks right to this point.
+                        RELEASE_ASSERT(node->op() == LoadVarargs || node->op() == ForwardVarargs);
+                        deferred.operand(operand) = DeadFlush;
+                    };
+
                     preciseLocalClobberize(
-                        m_graph, node, escapeHandler, escapeHandler,
+                        m_graph, node, escapeHandler, writeHandler,
                         [&] (VirtualRegister, LazyNode) { });
                     break;
                 } }
@@ -552,13 +563,11 @@
             for (unsigned nodeIndex = 0; nodeIndex < block->size(); ++nodeIndex) {
                 Node* node = block->at(nodeIndex);
                 
-                if (!putLocalsToSink.contains(node))
+                if (!putStacksToSink.contains(node))
                     continue;
                 
                 node->remove();
             }
-            
-            insertionSet.execute(block);
         }
         
         if (verbose) {

Modified: trunk/Source/_javascript_Core/dfg/DFGSSACalculator.h (192189 => 192190)


--- trunk/Source/_javascript_Core/dfg/DFGSSACalculator.h	2015-11-10 00:36:14 UTC (rev 192189)
+++ trunk/Source/_javascript_Core/dfg/DFGSSACalculator.h	2015-11-10 00:39:13 UTC (rev 192190)
@@ -91,10 +91,10 @@
 //         FIXME: Make it easier to do this, that doesn't involve rerunning GCSE.
 //         https://bugs.webkit.org/show_bug.cgi?id=136639
 //
-//    4.3) Insert Upsilons for each Phi in each successor block. Use the available values table to
-//         decide the source value for each Phi's variable. Note that you could also use
-//         SSACalculator::reachingDefAtTail() instead of the available values table, though your
-//         local available values table is likely to be more efficient.
+//    4.3) Insert Upsilons at the end of the current block for the corresponding Phis in each successor block. 
+//         Use the available values table to decide the source value for each Phi's variable. Note that 
+//         you could also use SSACalculator::reachingDefAtTail() instead of the available values table, 
+//         though your local available values table is likely to be more efficient.
 //
 // The most obvious use of SSACalculator is for the CPS->SSA conversion itself, but it's meant to
 // also be used for SSA update and for things like the promotion of heap fields to local SSA
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to