Title: [183094] trunk/Source/_javascript_Core
Revision
183094
Author
[email protected]
Date
2015-04-21 20:38:17 -0700 (Tue, 21 Apr 2015)

Log Message

DFG should allow Phantoms after terminals
https://bugs.webkit.org/show_bug.cgi?id=126778

Reviewed by Mark Lam.
        
It's important for us to be able to place liveness-marking nodes after nodes that do
things. These liveness-marking nodes are nops. Previously, we disallowed such nodes after
terminals. That made things awkward, especially for Switch and Branch, which may do
things that necessitate liveness markers (for example they might want to use a converted
version of a value rather than the value that was MovHinted). We previously made this
work by disallowing certain optimizations on Switch and Branch, which was probably a bad
thing.
        
This changes our IR to allow for the terminal to not be the last node in a block. Asking
for the terminal involves a search. DFG::validate() checks that the nodes after the
terminal are liveness markers that have no effects or checks.
        
This is perf-neutral but will allow more optimizations in the future. It will also make
it cleaner to fix https://bugs.webkit.org/show_bug.cgi?id=143735.

* dfg/DFGBasicBlock.cpp:
(JSC::DFG::BasicBlock::replaceTerminal):
* dfg/DFGBasicBlock.h:
(JSC::DFG::BasicBlock::findTerminal):
(JSC::DFG::BasicBlock::terminal):
(JSC::DFG::BasicBlock::insertBeforeTerminal):
(JSC::DFG::BasicBlock::numSuccessors):
(JSC::DFG::BasicBlock::successor):
(JSC::DFG::BasicBlock::successorForCondition):
(JSC::DFG::BasicBlock::successors):
(JSC::DFG::BasicBlock::last): Deleted.
(JSC::DFG::BasicBlock::takeLast): Deleted.
(JSC::DFG::BasicBlock::insertBeforeLast): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::SuccessorsIterable): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::iterator::iterator): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator*): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator++): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator==): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator!=): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::begin): Deleted.
(JSC::DFG::BasicBlock::SuccessorsIterable::end): Deleted.
* dfg/DFGBasicBlockInlines.h:
(JSC::DFG::BasicBlock::appendNonTerminal):
(JSC::DFG::BasicBlock::replaceTerminal):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::addToGraph):
(JSC::DFG::ByteCodeParser::inlineCall):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::linkBlock):
(JSC::DFG::ByteCodeParser::parseCodeBlock):
* dfg/DFGCFGSimplificationPhase.cpp:
(JSC::DFG::CFGSimplificationPhase::run):
(JSC::DFG::CFGSimplificationPhase::convertToJump):
(JSC::DFG::CFGSimplificationPhase::mergeBlocks):
* dfg/DFGCPSRethreadingPhase.cpp:
(JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock):
* dfg/DFGCommon.h:
(JSC::DFG::NodeAndIndex::NodeAndIndex):
(JSC::DFG::NodeAndIndex::operator!):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupBlock):
(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::injectTypeConversionsInBlock):
(JSC::DFG::FixupPhase::clearPhantomsAtEnd): Deleted.
* dfg/DFGForAllKills.h:
(JSC::DFG::forAllLiveNodesAtTail):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::terminalsAreValid):
(JSC::DFG::Graph::dumpBlockHeader):
* dfg/DFGGraph.h:
* dfg/DFGInPlaceAbstractState.cpp:
(JSC::DFG::InPlaceAbstractState::mergeToSuccessors):
* dfg/DFGLICMPhase.cpp:
(JSC::DFG::LICMPhase::run):
(JSC::DFG::LICMPhase::attemptHoist):
* dfg/DFGMovHintRemovalPhase.cpp:
* dfg/DFGNode.h:
(JSC::DFG::Node::SuccessorsIterable::SuccessorsIterable):
(JSC::DFG::Node::SuccessorsIterable::iterator::iterator):
(JSC::DFG::Node::SuccessorsIterable::iterator::operator*):
(JSC::DFG::Node::SuccessorsIterable::iterator::operator++):
(JSC::DFG::Node::SuccessorsIterable::iterator::operator==):
(JSC::DFG::Node::SuccessorsIterable::iterator::operator!=):
(JSC::DFG::Node::SuccessorsIterable::begin):
(JSC::DFG::Node::SuccessorsIterable::end):
(JSC::DFG::Node::successors):
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
(JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
(JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields):
* dfg/DFGPhantomRemovalPhase.cpp:
(JSC::DFG::PhantomRemovalPhase::run):
* dfg/DFGPutStackSinkingPhase.cpp:
* dfg/DFGSSAConversionPhase.cpp:
(JSC::DFG::SSAConversionPhase::run):
* dfg/DFGSpeculativeJIT.h:
(JSC::DFG::SpeculativeJIT::detectPeepHoleBranch):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStaticExecutionCountEstimationPhase.cpp:
(JSC::DFG::StaticExecutionCountEstimationPhase::run):
* dfg/DFGTierUpCheckInjectionPhase.cpp:
(JSC::DFG::TierUpCheckInjectionPhase::run):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::compileNode):
* tests/stress/closure-call-exit.js: Added.
(foo):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (183093 => 183094)


--- trunk/Source/_javascript_Core/ChangeLog	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,3 +1,118 @@
+2015-04-21  Filip Pizlo  <[email protected]>
+
+        DFG should allow Phantoms after terminals
+        https://bugs.webkit.org/show_bug.cgi?id=126778
+
+        Reviewed by Mark Lam.
+        
+        It's important for us to be able to place liveness-marking nodes after nodes that do
+        things. These liveness-marking nodes are nops. Previously, we disallowed such nodes after
+        terminals. That made things awkward, especially for Switch and Branch, which may do
+        things that necessitate liveness markers (for example they might want to use a converted
+        version of a value rather than the value that was MovHinted). We previously made this
+        work by disallowing certain optimizations on Switch and Branch, which was probably a bad
+        thing.
+        
+        This changes our IR to allow for the terminal to not be the last node in a block. Asking
+        for the terminal involves a search. DFG::validate() checks that the nodes after the
+        terminal are liveness markers that have no effects or checks.
+        
+        This is perf-neutral but will allow more optimizations in the future. It will also make
+        it cleaner to fix https://bugs.webkit.org/show_bug.cgi?id=143735.
+
+        * dfg/DFGBasicBlock.cpp:
+        (JSC::DFG::BasicBlock::replaceTerminal):
+        * dfg/DFGBasicBlock.h:
+        (JSC::DFG::BasicBlock::findTerminal):
+        (JSC::DFG::BasicBlock::terminal):
+        (JSC::DFG::BasicBlock::insertBeforeTerminal):
+        (JSC::DFG::BasicBlock::numSuccessors):
+        (JSC::DFG::BasicBlock::successor):
+        (JSC::DFG::BasicBlock::successorForCondition):
+        (JSC::DFG::BasicBlock::successors):
+        (JSC::DFG::BasicBlock::last): Deleted.
+        (JSC::DFG::BasicBlock::takeLast): Deleted.
+        (JSC::DFG::BasicBlock::insertBeforeLast): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::SuccessorsIterable): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::iterator): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator*): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator++): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator==): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::iterator::operator!=): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::begin): Deleted.
+        (JSC::DFG::BasicBlock::SuccessorsIterable::end): Deleted.
+        * dfg/DFGBasicBlockInlines.h:
+        (JSC::DFG::BasicBlock::appendNonTerminal):
+        (JSC::DFG::BasicBlock::replaceTerminal):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::addToGraph):
+        (JSC::DFG::ByteCodeParser::inlineCall):
+        (JSC::DFG::ByteCodeParser::handleInlining):
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        (JSC::DFG::ByteCodeParser::linkBlock):
+        (JSC::DFG::ByteCodeParser::parseCodeBlock):
+        * dfg/DFGCFGSimplificationPhase.cpp:
+        (JSC::DFG::CFGSimplificationPhase::run):
+        (JSC::DFG::CFGSimplificationPhase::convertToJump):
+        (JSC::DFG::CFGSimplificationPhase::mergeBlocks):
+        * dfg/DFGCPSRethreadingPhase.cpp:
+        (JSC::DFG::CPSRethreadingPhase::canonicalizeLocalsInBlock):
+        * dfg/DFGCommon.h:
+        (JSC::DFG::NodeAndIndex::NodeAndIndex):
+        (JSC::DFG::NodeAndIndex::operator!):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupBlock):
+        (JSC::DFG::FixupPhase::fixupNode):
+        (JSC::DFG::FixupPhase::injectTypeConversionsInBlock):
+        (JSC::DFG::FixupPhase::clearPhantomsAtEnd): Deleted.
+        * dfg/DFGForAllKills.h:
+        (JSC::DFG::forAllLiveNodesAtTail):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::terminalsAreValid):
+        (JSC::DFG::Graph::dumpBlockHeader):
+        * dfg/DFGGraph.h:
+        * dfg/DFGInPlaceAbstractState.cpp:
+        (JSC::DFG::InPlaceAbstractState::mergeToSuccessors):
+        * dfg/DFGLICMPhase.cpp:
+        (JSC::DFG::LICMPhase::run):
+        (JSC::DFG::LICMPhase::attemptHoist):
+        * dfg/DFGMovHintRemovalPhase.cpp:
+        * dfg/DFGNode.h:
+        (JSC::DFG::Node::SuccessorsIterable::SuccessorsIterable):
+        (JSC::DFG::Node::SuccessorsIterable::iterator::iterator):
+        (JSC::DFG::Node::SuccessorsIterable::iterator::operator*):
+        (JSC::DFG::Node::SuccessorsIterable::iterator::operator++):
+        (JSC::DFG::Node::SuccessorsIterable::iterator::operator==):
+        (JSC::DFG::Node::SuccessorsIterable::iterator::operator!=):
+        (JSC::DFG::Node::SuccessorsIterable::begin):
+        (JSC::DFG::Node::SuccessorsIterable::end):
+        (JSC::DFG::Node::successors):
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
+        (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
+        (JSC::DFG::ObjectAllocationSinkingPhase::promoteSunkenFields):
+        * dfg/DFGPhantomRemovalPhase.cpp:
+        (JSC::DFG::PhantomRemovalPhase::run):
+        * dfg/DFGPutStackSinkingPhase.cpp:
+        * dfg/DFGSSAConversionPhase.cpp:
+        (JSC::DFG::SSAConversionPhase::run):
+        * dfg/DFGSpeculativeJIT.h:
+        (JSC::DFG::SpeculativeJIT::detectPeepHoleBranch):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStaticExecutionCountEstimationPhase.cpp:
+        (JSC::DFG::StaticExecutionCountEstimationPhase::run):
+        * dfg/DFGTierUpCheckInjectionPhase.cpp:
+        (JSC::DFG::TierUpCheckInjectionPhase::run):
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validate):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        * tests/stress/closure-call-exit.js: Added.
+        (foo):
+
 2015-04-21  Basile Clement  <[email protected]>
 
         PhantomNewObject should be marked NodeMustGenerate

Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlock.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGBasicBlock.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlock.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -71,6 +71,19 @@
     intersectionOfPastValuesAtHead.ensureLocals(newNumLocals, AbstractValue::fullTop());
 }
 
+void BasicBlock::replaceTerminal(Node* node)
+{
+    NodeAndIndex result = findTerminal();
+    if (!result)
+        append(node);
+    else {
+        m_nodes.insert(result.index + 1, node);
+        result.node->convertToPhantom();
+    }
+    
+    ASSERT(terminal());
+}
+
 bool BasicBlock::isInPhis(Node* node) const
 {
     for (size_t i = 0; i < phis.size(); ++i) {

Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlock.h	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -63,18 +63,63 @@
     Node* at(size_t i) const { return m_nodes[i]; }
     Node*& operator[](size_t i) { return at(i); }
     Node* operator[](size_t i) const { return at(i); }
-    Node* last() const { return at(size() - 1); }
-    Node* takeLast() { return m_nodes.takeLast(); }
+    
+    // Use this to find both the index of the terminal and the terminal itself in one go. May
+    // return a clear NodeAndIndex if the basic block currently lacks a terminal. That may happen
+    // in the middle of IR transformations within a phase but should never be the case in between
+    // phases.
+    //
+    // The reason why this is more than just "at(size() - 1)" is that we may place non-terminal
+    // liveness marking instructions after the terminal. This is supposed to happen infrequently
+    // but some basic blocks - most notably return blocks - will have liveness markers for all of
+    // the flushed variables right after the return.
+    //
+    // It turns out that doing this linear search is basically perf-neutral, so long as we force
+    // the method to be inlined. Hence the ALWAYS_INLINE.
+    ALWAYS_INLINE NodeAndIndex findTerminal() const
+    {
+        size_t i = size();
+        while (i--) {
+            Node* node = at(i);
+            switch (node->op()) {
+            case Jump:
+            case Branch:
+            case Switch:
+            case Return:
+            case Unreachable:
+                return NodeAndIndex(node, i);
+            // The bitter end can contain Phantoms and the like. There will probably only be one or two nodes after the terminal.
+            case Phantom:
+            case PhantomLocal:
+            case Flush:
+                break;
+            default:
+                return NodeAndIndex();
+            }
+        }
+        return NodeAndIndex();
+    }
+    
+    ALWAYS_INLINE Node* terminal() const
+    {
+        return findTerminal().node;
+    }
+    
     void resize(size_t size) { m_nodes.resize(size); }
     void grow(size_t size) { m_nodes.grow(size); }
     
     void append(Node* node) { m_nodes.append(node); }
-    void insertBeforeLast(Node* node)
+    void insertBeforeTerminal(Node* node)
     {
-        append(last());
-        at(size() - 2) = node;
+        NodeAndIndex result = findTerminal();
+        if (!result)
+            append(node);
+        else
+            m_nodes.insert(result.index, node);
     }
     
+    void replaceTerminal(Node*);
+    
     size_t numNodes() const { return phis.size() + size(); }
     Node* node(size_t i) const
     {
@@ -93,85 +138,20 @@
     Node* firstOriginNode();
     NodeOrigin firstOrigin();
     
-    unsigned numSuccessors() { return last()->numSuccessors(); }
+    unsigned numSuccessors() { return terminal()->numSuccessors(); }
     
     BasicBlock*& successor(unsigned index)
     {
-        return last()->successor(index);
+        return terminal()->successor(index);
     }
     BasicBlock*& successorForCondition(bool condition)
     {
-        return last()->successorForCondition(condition);
+        return terminal()->successorForCondition(condition);
     }
-    
-    class SuccessorsIterable {
-    public:
-        SuccessorsIterable()
-            : m_block(nullptr)
-        {
-        }
-        
-        SuccessorsIterable(BasicBlock* block)
-            : m_block(block)
-        {
-        }
-        
-        class iterator {
-        public:
-            iterator()
-                : m_block(nullptr)
-                , m_index(UINT_MAX)
-            {
-            }
-            
-            iterator(BasicBlock* block, unsigned index)
-                : m_block(block)
-                , m_index(index)
-            {
-            }
-            
-            BasicBlock* operator*()
-            {
-                return m_block->successor(m_index);
-            }
-            
-            iterator& operator++()
-            {
-                m_index++;
-                return *this;
-            }
-            
-            bool operator==(const iterator& other) const
-            {
-                return m_index == other.m_index;
-            }
-            
-            bool operator!=(const iterator& other) const
-            {
-                return !(*this == other);
-            }
-        private:
-            BasicBlock* m_block;
-            unsigned m_index;
-        };
-        
-        iterator begin()
-        {
-            return iterator(m_block, 0);
-        }
-        
-        iterator end()
-        {
-            return iterator(m_block, m_block->numSuccessors());
-        }
-        
-    private:
-        BasicBlock* m_block;
-    };
-    
-    SuccessorsIterable successors()
+
+    Node::SuccessorsIterable successors()
     {
-        return SuccessorsIterable(this);
+        return terminal()->successors();
     }
     
     void removePredecessor(BasicBlock* block);
@@ -183,6 +163,9 @@
     template<typename... Params>
     Node* appendNonTerminal(Graph&, SpeculatedType, Params...);
     
+    template<typename... Params>
+    Node* replaceTerminal(Graph&, SpeculatedType, Params...);
+    
     void dump(PrintStream& out) const;
     
     void didLink()

Modified: trunk/Source/_javascript_Core/dfg/DFGBasicBlockInlines.h (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGBasicBlockInlines.h	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGBasicBlockInlines.h	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -45,10 +45,18 @@
 Node* BasicBlock::appendNonTerminal(Graph& graph, SpeculatedType type, Params... params)
 {
     Node* result = graph.addNode(type, params...);
-    insertBeforeLast(result);
+    insertBeforeTerminal(result);
     return result;
 }
 
+template<typename... Params>
+Node* BasicBlock::replaceTerminal(Graph& graph, SpeculatedType type, Params... params)
+{
+    Node* result = graph.addNode(type, params...);
+    replaceTerminal(result);
+    return result;
+}
+
 } } // namespace JSC::DFG
 
 #endif // ENABLE(DFG_JIT)

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,4 +1,4 @@
- /*
+/*
  * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -622,40 +622,40 @@
         return data;
     }
     
+    Node* addToGraph(Node* node)
+    {
+        if (Options::verboseDFGByteCodeParsing())
+            dataLog("        appended ", node, " ", Graph::opName(node->op()), "\n");
+        m_currentBlock->append(node);
+        return node;
+    }
+    
     Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
     {
         Node* result = m_graph.addNode(
             SpecNone, op, currentNodeOrigin(), Edge(child1), Edge(child2),
             Edge(child3));
-        ASSERT(op != Phi);
-        m_currentBlock->append(result);
-        return result;
+        return addToGraph(result);
     }
     Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
     {
         Node* result = m_graph.addNode(
             SpecNone, op, currentNodeOrigin(), child1, child2, child3);
-        ASSERT(op != Phi);
-        m_currentBlock->append(result);
-        return result;
+        return addToGraph(result);
     }
     Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
     {
         Node* result = m_graph.addNode(
             SpecNone, op, currentNodeOrigin(), info, Edge(child1), Edge(child2),
             Edge(child3));
-        ASSERT(op != Phi);
-        m_currentBlock->append(result);
-        return result;
+        return addToGraph(result);
     }
     Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
     {
         Node* result = m_graph.addNode(
             SpecNone, op, currentNodeOrigin(), info1, info2,
             Edge(child1), Edge(child2), Edge(child3));
-        ASSERT(op != Phi);
-        m_currentBlock->append(result);
-        return result;
+        return addToGraph(result);
     }
     
     Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
@@ -663,8 +663,7 @@
         Node* result = m_graph.addNode(
             SpecNone, Node::VarArg, op, currentNodeOrigin(), info1, info2,
             m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs);
-        ASSERT(op != Phi);
-        m_currentBlock->append(result);
+        addToGraph(result);
         
         m_numPassedVarArgs = 0;
         
@@ -1360,14 +1359,19 @@
     // If there was a return, but no early returns, then we're done. We allow parsing of
     // the caller to continue in whatever basic block we're in right now.
     if (!inlineStackEntry.m_didEarlyReturn && inlineStackEntry.m_didReturn) {
-        ASSERT(lastBlock->isEmpty() || !lastBlock->last()->isTerminal());
+        if (Options::verboseDFGByteCodeParsing())
+            dataLog("    Allowing parsing to continue in last inlined block.\n");
         
+        ASSERT(lastBlock->isEmpty() || !lastBlock->terminal());
+        
         // If we created new blocks then the last block needs linking, but in the
         // caller. It doesn't need to be linked to, but it needs outgoing links.
         if (!inlineStackEntry.m_unlinkedBlocks.isEmpty()) {
             // For debugging purposes, set the bytecodeBegin. Note that this doesn't matter
             // for release builds because this block will never serve as a potential target
             // in the linker's binary search.
+            if (Options::verboseDFGByteCodeParsing())
+                dataLog("        Repurposing last block from ", lastBlock->bytecodeBegin, " to ", m_currentIndex, "\n");
             lastBlock->bytecodeBegin = m_currentIndex;
             if (callerLinkability == CallerDoesNormalLinking) {
                 if (verbose)
@@ -1380,8 +1384,11 @@
         return;
     }
     
+    if (Options::verboseDFGByteCodeParsing())
+        dataLog("    Creating new block after inlining.\n");
+
     // If we get to this point then all blocks must end in some sort of terminals.
-    ASSERT(lastBlock->last()->isTerminal());
+    ASSERT(lastBlock->terminal());
 
     // Need to create a new basic block for the continuation at the caller.
     RefPtr<BasicBlock> block = adoptRef(new BasicBlock(nextOffset, m_numArguments, m_numLocals, PNaN));
@@ -1392,7 +1399,7 @@
             continue;
         BasicBlock* blockToLink = inlineStackEntry.m_unlinkedBlocks[i].m_block;
         ASSERT(!blockToLink->isLinked);
-        Node* node = blockToLink->last();
+        Node* node = blockToLink->terminal();
         ASSERT(node->op() == Jump);
         ASSERT(!node->targetBlock());
         node->targetBlock() = block.get();
@@ -1803,7 +1810,7 @@
     m_currentBlock = continuationBlock.get();
     
     for (unsigned i = landingBlocks.size(); i--;)
-        landingBlocks[i]->last()->targetBlock() = continuationBlock.get();
+        landingBlocks[i]->terminal()->targetBlock() = continuationBlock.get();
     
     m_currentIndex = oldOffset;
     
@@ -3129,9 +3136,9 @@
 
         case op_jmp: {
             int relativeOffset = currentInstruction[1].u.operand;
+            addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
             if (relativeOffset <= 0)
                 flushForTerminal();
-            addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
             LAST_OPCODE(op_jmp);
         }
 
@@ -3251,8 +3258,8 @@
                     continue;
                 data.cases.append(SwitchCase::withBytecodeIndex(m_graph.freeze(jsNumber(static_cast<int32_t>(table.min + i))), target));
             }
+            addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
             flushIfTerminal(data);
-            addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
             LAST_OPCODE(op_switch_imm);
         }
             
@@ -3271,8 +3278,8 @@
                 data.cases.append(
                     SwitchCase::withBytecodeIndex(LazyJSValue::singleCharacterString(table.min + i), target));
             }
+            addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
             flushIfTerminal(data);
-            addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
             LAST_OPCODE(op_switch_char);
         }
 
@@ -3291,14 +3298,14 @@
                 data.cases.append(
                     SwitchCase::withBytecodeIndex(LazyJSValue::knownStringImpl(iter->key.get()), target));
             }
+            addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
             flushIfTerminal(data);
-            addToGraph(Switch, OpInfo(&data), get(VirtualRegister(currentInstruction[3].u.operand)));
             LAST_OPCODE(op_switch_string);
         }
 
         case op_ret:
-            flushForReturn();
             if (inlineCallFrame()) {
+                flushForReturn();
                 if (m_inlineStackTop->m_returnValue.isValid())
                     setDirect(m_inlineStackTop->m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush);
                 m_inlineStackTop->m_didReturn = true;
@@ -3322,12 +3329,13 @@
                 LAST_OPCODE(op_ret);
             }
             addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
+            flushForReturn();
             LAST_OPCODE(op_ret);
             
         case op_end:
-            flushForReturn();
             ASSERT(!inlineCallFrame());
             addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
+            flushForReturn();
             LAST_OPCODE(op_end);
 
         case op_throw:
@@ -3854,7 +3862,7 @@
 {
     ASSERT(!block->isLinked);
     ASSERT(!block->isEmpty());
-    Node* node = block->last();
+    Node* node = block->terminal();
     ASSERT(node->isTerminal());
     
     switch (node->op()) {
@@ -4134,10 +4142,13 @@
             // are at the end of an inline function, or we realized that we
             // should stop parsing because there was a return in the first
             // basic block.
-            ASSERT(m_currentBlock->isEmpty() || m_currentBlock->last()->isTerminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing);
+            ASSERT(m_currentBlock->isEmpty() || m_currentBlock->terminal() || (m_currentIndex == codeBlock->instructions().size() && inlineCallFrame()) || !shouldContinueParsing);
 
-            if (!shouldContinueParsing)
+            if (!shouldContinueParsing) {
+                if (Options::verboseDFGByteCodeParsing())
+                    dataLog("Done parsing ", *codeBlock, "\n");
                 return;
+            }
             
             m_currentBlock = 0;
         } while (m_currentIndex < limit);
@@ -4145,6 +4156,9 @@
 
     // Should have reached the end of the instructions.
     ASSERT(m_currentIndex == codeBlock->instructions().size());
+    
+    if (Options::verboseDFGByteCodeParsing())
+        dataLog("Done parsing ", *codeBlock, " (fell off end)\n");
 }
 
 bool ByteCodeParser::parse()

Modified: trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGCFGSimplificationPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -59,7 +59,7 @@
                     continue;
                 ASSERT(block->isReachable);
             
-                switch (block->last()->op()) {
+                switch (block->terminal()->op()) {
                 case Jump: {
                     // Successor with one predecessor -> merge.
                     if (block->successor(0)->predecessors.size() == 1) {
@@ -99,17 +99,19 @@
                             if (extremeLogging)
                                 m_graph.dump();
                             m_graph.dethread();
-                        
-                            ASSERT(block->last()->isTerminal());
-                            NodeOrigin boundaryNodeOrigin = block->last()->origin;
-                            block->last()->convertToPhantom();
-                            ASSERT(block->last()->refCount() == 1);
-                        
+                            
+                            Node* terminal = block->terminal();
+                            ASSERT(terminal->isTerminal());
+                            NodeOrigin boundaryNodeOrigin = terminal->origin;
+
                             jettisonBlock(block, jettisonedBlock, boundaryNodeOrigin);
-                        
-                            block->appendNode(
+
+                            block->replaceTerminal(
                                 m_graph, SpecNone, Jump, boundaryNodeOrigin,
                                 OpInfo(targetBlock));
+                            
+                            ASSERT(block->terminal());
+                        
                         }
                         innerChanged = outerChanged = true;
                         break;
@@ -129,7 +131,7 @@
                 }
                     
                 case Switch: {
-                    SwitchData* data = ""
+                    SwitchData* data = ""
                     
                     // Prune out cases that end up jumping to default.
                     for (unsigned i = 0; i < data->cases.size(); ++i) {
@@ -149,8 +151,9 @@
                     }
                     
                     // Switch on constant -> jettison all other targets and merge.
-                    if (block->last()->child1()->hasConstant()) {
-                        FrozenValue* value = block->last()->child1()->constant();
+                    Node* terminal = block->terminal();
+                    if (terminal->child1()->hasConstant()) {
+                        FrozenValue* value = terminal->child1()->constant();
                         TriState found = FalseTriState;
                         BasicBlock* targetBlock = 0;
                         for (unsigned i = data->cases.size(); found == FalseTriState && i--;) {
@@ -166,10 +169,9 @@
                         ASSERT(targetBlock);
                         
                         Vector<BasicBlock*, 1> jettisonedBlocks;
-                        for (unsigned i = block->numSuccessors(); i--;) {
-                            BasicBlock* jettisonedBlock = block->successor(i);
-                            if (jettisonedBlock != targetBlock)
-                                jettisonedBlocks.append(jettisonedBlock);
+                        for (BasicBlock* successor : terminal->successors()) {
+                            if (successor != targetBlock)
+                                jettisonedBlocks.append(successor);
                         }
                         
                         if (targetBlock->predecessors.size() == 1) {
@@ -183,11 +185,12 @@
                                 m_graph.dump();
                             m_graph.dethread();
                             
-                            NodeOrigin boundaryNodeOrigin = block->last()->origin;
-                            block->last()->convertToPhantom();
+                            NodeOrigin boundaryNodeOrigin = terminal->origin;
+
                             for (unsigned i = jettisonedBlocks.size(); i--;)
                                 jettisonBlock(block, jettisonedBlocks[i], boundaryNodeOrigin);
-                            block->appendNode(
+                            
+                            block->replaceTerminal(
                                 m_graph, SpecNone, Jump, boundaryNodeOrigin, OpInfo(targetBlock));
                         }
                         innerChanged = outerChanged = true;
@@ -253,13 +256,10 @@
             m_graph.dethread();
             mergeBlocks(block, targetBlock, noBlocks());
         } else {
-            Node* branch = block->last();
-            ASSERT(branch->isTerminal());
+            Node* branch = block->terminal();
             ASSERT(branch->op() == Branch || branch->op() == Switch);
-            branch->convertToPhantom();
-            ASSERT(branch->refCount() == 1);
-            
-            block->appendNode(
+
+            block->replaceTerminal(
                 m_graph, SpecNone, Jump, branch->origin, OpInfo(targetBlock));
         }
     }
@@ -318,10 +318,11 @@
         
         // Remove the terminal of firstBlock since we don't need it anymore. Well, we don't
         // really remove it; we actually turn it into a Phantom.
-        ASSERT(firstBlock->last()->isTerminal());
-        NodeOrigin boundaryNodeOrigin = firstBlock->last()->origin;
-        firstBlock->last()->convertToPhantom();
-        ASSERT(firstBlock->last()->refCount() == 1);
+        Node* terminal = firstBlock->terminal();
+        ASSERT(terminal->isTerminal());
+        NodeOrigin boundaryNodeOrigin = terminal->origin;
+        terminal->convertToPhantom();
+        ASSERT(terminal->refCount() == 1);
         
         for (unsigned i = jettisonedBlocks.size(); i--;) {
             BasicBlock* jettisonedBlock = jettisonedBlocks[i];
@@ -342,7 +343,7 @@
         for (size_t i = 0; i < secondBlock->size(); ++i)
             firstBlock->append(secondBlock->at(i));
         
-        ASSERT(firstBlock->last()->isTerminal());
+        ASSERT(firstBlock->terminal()->isTerminal());
         
         // Fix the predecessors of my new successors. This is tricky, since we are going to reset
         // all predecessors anyway due to reachability analysis. But we need to fix the

Modified: trunk/Source/_javascript_Core/dfg/DFGCPSRethreadingPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGCPSRethreadingPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGCPSRethreadingPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -363,6 +363,10 @@
                 m_availableForOSR.operand(node->unlinkedLocal()) = node->child1();
                 break;
                 
+            case ZombieHint:
+                m_availableForOSR.operand(node->unlinkedLocal()) = Edge();
+                break;
+                
             default:
                 break;
             }

Modified: trunk/Source/_javascript_Core/dfg/DFGCommon.h (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGCommon.h	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGCommon.h	2015-04-22 03:38:17 UTC (rev 183094)
@@ -274,6 +274,29 @@
 
 JS_EXPORT_PRIVATE bool isCrashing();
 
+struct NodeAndIndex {
+    NodeAndIndex()
+        : node(nullptr)
+        , index(UINT_MAX)
+    {
+    }
+    
+    NodeAndIndex(Node* node, unsigned index)
+        : node(node)
+        , index(index)
+    {
+        ASSERT(!node == (index == UINT_MAX));
+    }
+    
+    bool operator!() const
+    {
+        return !node;
+    }
+    
+    Node* node;
+    unsigned index;
+};
+
 } } // namespace JSC::DFG
 
 namespace WTF {

Modified: trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGFixupPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -85,7 +85,7 @@
             addPhantomsIfNecessary();
             fixupNode(m_currentNode);
         }
-        clearPhantomsAtEnd();
+        addPhantomsIfNecessary();
         m_insertionSet.execute(block);
     }
     
@@ -725,9 +725,8 @@
             else if (node->child1()->shouldSpeculateObjectOrOther())
                 fixEdge<ObjectOrOtherUse>(node->child1());
             // FIXME: We should just be able to do shouldSpeculateInt32OrBoolean() and
-            // shouldSpeculateNumberOrBoolean() here, but we can't because then the Branch
-            // could speculate on the result of a non-speculative conversion node.
-            // https://bugs.webkit.org/show_bug.cgi?id=126778
+            // shouldSpeculateNumberOrBoolean() here now that
+            // https://bugs.webkit.org/show_bug.cgi?id=126778 is fixed.
             else if (node->child1()->shouldSpeculateInt32())
                 fixEdge<Int32Use>(node->child1());
             else if (node->child1()->shouldSpeculateNumber())
@@ -1996,7 +1995,7 @@
             tryToRelaxRepresentation(m_currentNode);
             DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, injectTypeConversionsForEdge);
         }
-        clearPhantomsAtEnd();
+        addPhantomsIfNecessary();
         m_insertionSet.execute(block);
     }
     
@@ -2161,21 +2160,6 @@
         m_requiredPhantoms.resize(0);
     }
     
-    void clearPhantomsAtEnd()
-    {
-        // Terminal nodes don't need post-phantoms, and inserting them would violate
-        // the current requirement that a terminal is the last thing in a block. We
-        // should eventually change that requirement. Currently we get around this by
-        // ensuring that all terminals accept just one input, and if that input is a
-        // conversion node then no further speculations will be performed. See
-        // references to the bug, below, for places where we have to have hacks to
-        // work around this.
-        // FIXME: Get rid of this by allowing Phantoms after terminals.
-        // https://bugs.webkit.org/show_bug.cgi?id=126778
-        
-        m_requiredPhantoms.resize(0);
-    }
-    
     BasicBlock* m_block;
     unsigned m_indexInBlock;
     Node* m_currentNode;

Modified: trunk/Source/_javascript_Core/dfg/DFGForAllKills.h (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGForAllKills.h	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGForAllKills.h	2015-04-22 03:38:17 UTC (rev 183094)
@@ -48,13 +48,13 @@
             functor(node);
     }
     
-    DFG_ASSERT(graph, block->last(), block->last()->origin.forExit.isSet());
+    DFG_ASSERT(graph, block->terminal(), block->terminal()->origin.forExit.isSet());
     
     AvailabilityMap& availabilityMap = block->ssa->availabilityAtTail;
     for (unsigned i = availabilityMap.m_locals.size(); i--;) {
         VirtualRegister reg = availabilityMap.m_locals.virtualRegisterForIndex(i);
         
-        if (!graph.isLiveInBytecode(reg, block->last()->origin.forExit))
+        if (!graph.isLiveInBytecode(reg, block->terminal()->origin.forExit))
             continue;
         
         availabilityMap.closeStartingWithLocal(

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -365,6 +365,15 @@
     out.print("\n");
 }
 
+bool Graph::terminalsAreValid()
+{
+    for (BasicBlock* block : blocksInNaturalOrder()) {
+        if (!block->terminal())
+            return false;
+    }
+    return true;
+}
+
 void Graph::dumpBlockHeader(PrintStream& out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context)
 {
     out.print(prefix, "Block ", *block, " (", inContext(block->at(0)->origin.semantic, context), "):", block->isReachable ? "" : " (skipped)", block->isOSRTarget ? " (OSR target)" : "", "\n");
@@ -375,13 +384,16 @@
         out.print(" ", *block->predecessors[i]);
     out.print("\n");
     out.print(prefix, "  Successors:");
-    for (BasicBlock* successor : block->successors()) {
-        out.print(" ", *successor);
-        if (m_prePostNumbering.isValid())
-            out.print(" (", m_prePostNumbering.edgeKind(block, successor), ")");
-    }
+    if (block->terminal()) {
+        for (BasicBlock* successor : block->successors()) {
+            out.print(" ", *successor);
+            if (m_prePostNumbering.isValid())
+                out.print(" (", m_prePostNumbering.edgeKind(block, successor), ")");
+        }
+    } else
+        out.print(" <invalid>");
     out.print("\n");
-    if (m_dominators.isValid()) {
+    if (m_dominators.isValid() && terminalsAreValid()) {
         out.print(prefix, "  Dominated by: ", m_dominators.dominatorsOf(block), "\n");
         out.print(prefix, "  Dominates: ", m_dominators.blocksDominatedBy(block), "\n");
         out.print(prefix, "  Dominance Frontier: ", m_dominators.dominanceFrontierOf(block), "\n");

Modified: trunk/Source/_javascript_Core/dfg/DFGGraph.h (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGGraph.h	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGGraph.h	2015-04-22 03:38:17 UTC (rev 183094)
@@ -196,6 +196,9 @@
     
     // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
     void dump(PrintStream& = WTF::dataFile(), DumpContext* = 0);
+    
+    bool terminalsAreValid();
+    
     enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis };
     void dumpBlockHeader(PrintStream&, const char* prefix, BasicBlock*, PhiNodeDumpMode, DumpContext*);
     void dump(PrintStream&, Edge);

Modified: trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGInPlaceAbstractState.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -361,7 +361,7 @@
 
 inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock)
 {
-    Node* terminal = basicBlock->last();
+    Node* terminal = basicBlock->terminal();
     
     ASSERT(terminal->isTerminal());
     

Modified: trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGLICMPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -128,7 +128,7 @@
                 preHeader = predecessor;
             }
             
-            DFG_ASSERT(m_graph, preHeader->last(), preHeader->last()->op() == Jump);
+            DFG_ASSERT(m_graph, preHeader->terminal(), preHeader->terminal()->op() == Jump);
             
             data.preHeader = preHeader;
         }
@@ -237,10 +237,10 @@
                 "\n");
         }
         
-        data.preHeader->insertBeforeLast(node);
+        data.preHeader->insertBeforeTerminal(node);
         node->owner = data.preHeader;
         NodeOrigin originalOrigin = node->origin;
-        node->origin.forExit = data.preHeader->last()->origin.forExit;
+        node->origin.forExit = data.preHeader->terminal()->origin.forExit;
         
         // Modify the states at the end of the preHeader of the loop we hoisted to,
         // and all pre-headers inside the loop.

Modified: trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGMovHintRemovalPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -82,7 +82,7 @@
         
         for (unsigned i = m_state.size(); i--;) {
             VirtualRegister reg = m_state.virtualRegisterForIndex(i);
-            if (m_graph.isLiveInBytecode(reg, block->last()->origin.forExit))
+            if (m_graph.isLiveInBytecode(reg, block->terminal()->origin.forExit))
                 m_state[i] = currentEpoch;
             else
                 m_state[i] = Epoch();

Modified: trunk/Source/_javascript_Core/dfg/DFGNode.h (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGNode.h	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1142,6 +1142,76 @@
         }
     }
     
+    class SuccessorsIterable {
+    public:
+        SuccessorsIterable()
+            : m_terminal(nullptr)
+        {
+        }
+        
+        SuccessorsIterable(Node* terminal)
+            : m_terminal(terminal)
+        {
+        }
+        
+        class iterator {
+        public:
+            iterator()
+                : m_terminal(nullptr)
+                , m_index(UINT_MAX)
+            {
+            }
+            
+            iterator(Node* terminal, unsigned index)
+                : m_terminal(terminal)
+                , m_index(index)
+            {
+            }
+            
+            BasicBlock* operator*()
+            {
+                return m_terminal->successor(m_index);
+            }
+            
+            iterator& operator++()
+            {
+                m_index++;
+                return *this;
+            }
+            
+            bool operator==(const iterator& other) const
+            {
+                return m_index == other.m_index;
+            }
+            
+            bool operator!=(const iterator& other) const
+            {
+                return !(*this == other);
+            }
+        private:
+            Node* m_terminal;
+            unsigned m_index;
+        };
+        
+        iterator begin()
+        {
+            return iterator(m_terminal, 0);
+        }
+        
+        iterator end()
+        {
+            return iterator(m_terminal, m_terminal->numSuccessors());
+        }
+        
+    private:
+        Node* m_terminal;
+    };
+    
+    SuccessorsIterable successors()
+    {
+        return SuccessorsIterable(this);
+    }
+    
     BasicBlock*& successorForCondition(bool condition)
     {
         return branchData()->forCondition(condition);

Modified: trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGObjectAllocationSinkingPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -352,7 +352,7 @@
                     // already handled the case where the predecessor has multiple successors.
                     DFG_ASSERT(m_graph, block, block->numSuccessors() == 1);
                     
-                    createMaterialize(allocation, block->last());
+                    createMaterialize(allocation, block->terminal());
                 }
             }
         }
@@ -461,8 +461,9 @@
                 }
             }
             
-            size_t upsilonInsertionPoint = block->size() - 1;
-            Node* upsilonWhere = block->last();
+            NodeAndIndex terminal = block->findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            Node* upsilonWhere = terminal.node;
             NodeOrigin upsilonOrigin = upsilonWhere->origin;
             for (BasicBlock* successorBlock : block->successors()) {
                 for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) {
@@ -708,8 +709,9 @@
             }
             
             // Gotta drop some Upsilons.
-            size_t upsilonInsertionPoint = block->size() - 1;
-            NodeOrigin upsilonOrigin = block->last()->origin;
+            NodeAndIndex terminal = block->findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            NodeOrigin upsilonOrigin = terminal.node->origin;
             for (BasicBlock* successorBlock : block->successors()) {
                 for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) {
                     Node* phiNode = phiDef->value();

Modified: trunk/Source/_javascript_Core/dfg/DFGPhantomRemovalPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGPhantomRemovalPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGPhantomRemovalPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -90,6 +90,9 @@
                     Node* lastNode = nullptr;
                     if (sourceIndex > 1) {
                         lastNode = block->at(sourceIndex - 2);
+                        
+                        // This doesn't need to specialize for Phantom. lastNode could be any node
+                        // that isn't subject to DCE. But we keep it simple for now.
                         if (lastNode->op() != Phantom
                             || lastNode->origin.forExit != node->origin.forExit)
                             lastNode = nullptr;

Modified: trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGPutStackSinkingPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -441,8 +441,9 @@
                 } }
             }
             
-            size_t upsilonInsertionPoint = block->size() - 1;
-            NodeOrigin upsilonOrigin = block->last()->origin;
+            NodeAndIndex terminal = block->findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            NodeOrigin upsilonOrigin = terminal.node->origin;
             for (BasicBlock* successorBlock : block->successors()) {
                 for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(successorBlock)) {
                     Node* phiNode = phiDef->value();

Modified: trunk/Source/_javascript_Core/dfg/DFGSSAConversionPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGSSAConversionPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSSAConversionPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -335,8 +335,9 @@
             // seems dangerous because the Upsilon will have a checking UseKind. But, we will not
             // actually be performing the check at the point of the Upsilon; the check will
             // already have been performed at the point where the original SetLocal was.
-            size_t upsilonInsertionPoint = block->size() - 1;
-            NodeOrigin upsilonOrigin = block->last()->origin;
+            NodeAndIndex terminal = block->findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            NodeOrigin upsilonOrigin = terminal.node->origin;
             for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
                 BasicBlock* successorBlock = block->successor(successorIndex);
                 for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT.h	2015-04-22 03:38:17 UTC (rev 183094)
@@ -681,7 +681,7 @@
         }
 
         // Check if the lastNode is a branch on this node.
-        Node* lastNode = m_block->last();
+        Node* lastNode = m_block->terminal();
         return lastNode->op() == Branch && lastNode->child1() == m_currentNode ? m_block->size() - 1 : UINT_MAX;
     }
     

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1832,11 +1832,14 @@
         break;
     }
 
-    case MovHint:
-    case ZombieHint: {
+    case MovHint: {
         RELEASE_ASSERT_NOT_REACHED();
         break;
     }
+        
+    case ZombieHint:
+        recordSetLocal(m_currentNode->unlinkedLocal(), VirtualRegister(), DataFormatDead);
+        break;
 
     case SetLocal: {
         switch (node->variableAccessData()->flushFormat()) {

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1932,7 +1932,7 @@
         noResult(node);
         break;
     }
-
+        
     case SetLocal: {
         switch (node->variableAccessData()->flushFormat()) {
         case FlushedDouble: {

Modified: trunk/Source/_javascript_Core/dfg/DFGStaticExecutionCountEstimationPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGStaticExecutionCountEstimationPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGStaticExecutionCountEstimationPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -63,16 +63,17 @@
             if (!block)
                 continue;
             
-            switch (block->last()->op()) {
+            Node* terminal = block->terminal();
+            switch (terminal->op()) {
             case Branch: {
-                BranchData* data = ""
+                BranchData* data = ""
                 applyCounts(data->taken);
                 applyCounts(data->notTaken);
                 break;
             }
                 
             case Switch: {
-                SwitchData* data = ""
+                SwitchData* data = ""
                 for (unsigned i = data->cases.size(); i--;)
                     applyCounts(data->cases[i].target);
                 applyCounts(data->fallThrough);

Modified: trunk/Source/_javascript_Core/dfg/DFGTierUpCheckInjectionPhase.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGTierUpCheckInjectionPhase.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGTierUpCheckInjectionPhase.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -103,9 +103,10 @@
                 break;
             }
             
-            if (block->last()->op() == Return) {
+            NodeAndIndex terminal = block->findTerminal();
+            if (terminal.node->op() == Return) {
                 insertionSet.insertNode(
-                    block->size() - 1, SpecNone, CheckTierUpAtReturn, block->last()->origin);
+                    terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node->origin);
             }
             
             insertionSet.execute(block);

Modified: trunk/Source/_javascript_Core/dfg/DFGValidate.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/dfg/DFGValidate.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -189,10 +189,24 @@
                     V_EQUAL((node), m_myRefCounts.get(node), node->adjustedRefCount());
             }
             
-            for (size_t i = 0 ; i < block->size() - 1; ++i) {
+            bool foundTerminal = false;
+            for (size_t i = 0 ; i < block->size(); ++i) {
                 Node* node = block->at(i);
-                VALIDATE((node), !node->isTerminal());
+                if (node->isTerminal()) {
+                    foundTerminal = true;
+                    for (size_t j = i + 1; j < block->size(); ++j) {
+                        node = block->at(j);
+                        VALIDATE((node), node->op() == Phantom || node->op() == PhantomLocal || node->op() == Flush);
+                        m_graph.doToChildren(
+                            node,
+                            [&] (Edge edge) {
+                                VALIDATE((node, edge), shouldNotHaveTypeCheck(edge.useKind()));
+                            });
+                    }
+                    break;
+                }
             }
+            VALIDATE((block), foundTerminal);
             
             for (size_t i = 0; i < block->size(); ++i) {
                 Node* node = block->at(i);

Modified: trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp (183093 => 183094)


--- trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/_javascript_Core/ftl/FTLLowerDFGToLLVM.cpp	2015-04-22 03:38:17 UTC (rev 183094)
@@ -859,8 +859,11 @@
             DFG_CRASH(m_graph, m_node, "Unrecognized node in FTL backend");
             break;
         }
-
-        if (!m_state.isValid() && !m_node->isTerminal()) {
+        
+        if (m_node->isTerminal())
+            return false;
+        
+        if (!m_state.isValid()) {
             safelyInvalidateAfterTermination();
             return false;
         }

Added: trunk/Source/_javascript_Core/tests/stress/closure-call-exit.js (0 => 183094)


--- trunk/Source/_javascript_Core/tests/stress/closure-call-exit.js	                        (rev 0)
+++ trunk/Source/_javascript_Core/tests/stress/closure-call-exit.js	2015-04-22 03:38:17 UTC (rev 183094)
@@ -0,0 +1,15 @@
+function foo(o, i) {
+    return o[i]();
+}
+
+noInline(foo);
+
+for (var i = 0; i < 10000; ++i) {
+    var result = foo([function() { return 42; }], 0);
+    if (result != 42)
+        throw "Error: bad result: " + result;
+}
+
+var result = foo([function() { return 43; }], 0);
+if (result != 43)
+    throw "Error: bad result at end: " + result;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to