<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[183094] trunk/Source/JavaScriptCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/183094">183094</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-04-21 20:38:17 -0700 (Tue, 21 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>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):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGBasicBlockcpp">trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGBasicBlockh">trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGBasicBlockInlinesh">trunk/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCFGSimplificationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCPSRethreadingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGCommonh">trunk/Source/JavaScriptCore/dfg/DFGCommon.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGForAllKillsh">trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphcpp">trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGGraphh">trunk/Source/JavaScriptCore/dfg/DFGGraph.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp">trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGLICMPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGMovHintRemovalPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPhantomRemovalPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITh">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGStaticExecutionCountEstimationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGStaticExecutionCountEstimationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGTierUpCheckInjectionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGValidatecpp">trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressclosurecallexitjs">trunk/Source/JavaScriptCore/tests/stress/closure-call-exit.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,3 +1,118 @@
</span><ins>+2015-04-21  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        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):
+
</ins><span class="cx"> 2015-04-21  Basile Clement  &lt;basile_clement@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         PhantomNewObject should be marked NodeMustGenerate
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGBasicBlockcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -71,6 +71,19 @@
</span><span class="cx">     intersectionOfPastValuesAtHead.ensureLocals(newNumLocals, AbstractValue::fullTop());
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void BasicBlock::replaceTerminal(Node* node)
+{
+    NodeAndIndex result = findTerminal();
+    if (!result)
+        append(node);
+    else {
+        m_nodes.insert(result.index + 1, node);
+        result.node-&gt;convertToPhantom();
+    }
+    
+    ASSERT(terminal());
+}
+
</ins><span class="cx"> bool BasicBlock::isInPhis(Node* node) const
</span><span class="cx"> {
</span><span class="cx">     for (size_t i = 0; i &lt; phis.size(); ++i) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGBasicBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.h (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.h        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGBasicBlock.h        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2011, 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -63,18 +63,63 @@
</span><span class="cx">     Node* at(size_t i) const { return m_nodes[i]; }
</span><span class="cx">     Node*&amp; operator[](size_t i) { return at(i); }
</span><span class="cx">     Node* operator[](size_t i) const { return at(i); }
</span><del>-    Node* last() const { return at(size() - 1); }
-    Node* takeLast() { return m_nodes.takeLast(); }
</del><ins>+    
+    // 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 &quot;at(size() - 1)&quot; 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-&gt;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;
+    }
+    
</ins><span class="cx">     void resize(size_t size) { m_nodes.resize(size); }
</span><span class="cx">     void grow(size_t size) { m_nodes.grow(size); }
</span><span class="cx">     
</span><span class="cx">     void append(Node* node) { m_nodes.append(node); }
</span><del>-    void insertBeforeLast(Node* node)
</del><ins>+    void insertBeforeTerminal(Node* node)
</ins><span class="cx">     {
</span><del>-        append(last());
-        at(size() - 2) = node;
</del><ins>+        NodeAndIndex result = findTerminal();
+        if (!result)
+            append(node);
+        else
+            m_nodes.insert(result.index, node);
</ins><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void replaceTerminal(Node*);
+    
</ins><span class="cx">     size_t numNodes() const { return phis.size() + size(); }
</span><span class="cx">     Node* node(size_t i) const
</span><span class="cx">     {
</span><span class="lines">@@ -93,85 +138,20 @@
</span><span class="cx">     Node* firstOriginNode();
</span><span class="cx">     NodeOrigin firstOrigin();
</span><span class="cx">     
</span><del>-    unsigned numSuccessors() { return last()-&gt;numSuccessors(); }
</del><ins>+    unsigned numSuccessors() { return terminal()-&gt;numSuccessors(); }
</ins><span class="cx">     
</span><span class="cx">     BasicBlock*&amp; successor(unsigned index)
</span><span class="cx">     {
</span><del>-        return last()-&gt;successor(index);
</del><ins>+        return terminal()-&gt;successor(index);
</ins><span class="cx">     }
</span><span class="cx">     BasicBlock*&amp; successorForCondition(bool condition)
</span><span class="cx">     {
</span><del>-        return last()-&gt;successorForCondition(condition);
</del><ins>+        return terminal()-&gt;successorForCondition(condition);
</ins><span class="cx">     }
</span><del>-    
-    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-&gt;successor(m_index);
-            }
-            
-            iterator&amp; operator++()
-            {
-                m_index++;
-                return *this;
-            }
-            
-            bool operator==(const iterator&amp; other) const
-            {
-                return m_index == other.m_index;
-            }
-            
-            bool operator!=(const iterator&amp; 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-&gt;numSuccessors());
-        }
-        
-    private:
-        BasicBlock* m_block;
-    };
-    
-    SuccessorsIterable successors()
</del><ins>+
+    Node::SuccessorsIterable successors()
</ins><span class="cx">     {
</span><del>-        return SuccessorsIterable(this);
</del><ins>+        return terminal()-&gt;successors();
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void removePredecessor(BasicBlock* block);
</span><span class="lines">@@ -183,6 +163,9 @@
</span><span class="cx">     template&lt;typename... Params&gt;
</span><span class="cx">     Node* appendNonTerminal(Graph&amp;, SpeculatedType, Params...);
</span><span class="cx">     
</span><ins>+    template&lt;typename... Params&gt;
+    Node* replaceTerminal(Graph&amp;, SpeculatedType, Params...);
+    
</ins><span class="cx">     void dump(PrintStream&amp; out) const;
</span><span class="cx">     
</span><span class="cx">     void didLink()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGBasicBlockInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGBasicBlockInlines.h        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -45,10 +45,18 @@
</span><span class="cx"> Node* BasicBlock::appendNonTerminal(Graph&amp; graph, SpeculatedType type, Params... params)
</span><span class="cx"> {
</span><span class="cx">     Node* result = graph.addNode(type, params...);
</span><del>-    insertBeforeLast(result);
</del><ins>+    insertBeforeTerminal(result);
</ins><span class="cx">     return result;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename... Params&gt;
+Node* BasicBlock::replaceTerminal(Graph&amp; graph, SpeculatedType type, Params... params)
+{
+    Node* result = graph.addNode(type, params...);
+    replaceTerminal(result);
+    return result;
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DFG_JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>- /*
</del><ins>+/*
</ins><span class="cx">  * Copyright (C) 2011-2015 Apple Inc. All rights reserved.
</span><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="lines">@@ -622,40 +622,40 @@
</span><span class="cx">         return data;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    Node* addToGraph(Node* node)
+    {
+        if (Options::verboseDFGByteCodeParsing())
+            dataLog(&quot;        appended &quot;, node, &quot; &quot;, Graph::opName(node-&gt;op()), &quot;\n&quot;);
+        m_currentBlock-&gt;append(node);
+        return node;
+    }
+    
</ins><span class="cx">     Node* addToGraph(NodeType op, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
</span><span class="cx">     {
</span><span class="cx">         Node* result = m_graph.addNode(
</span><span class="cx">             SpecNone, op, currentNodeOrigin(), Edge(child1), Edge(child2),
</span><span class="cx">             Edge(child3));
</span><del>-        ASSERT(op != Phi);
-        m_currentBlock-&gt;append(result);
-        return result;
</del><ins>+        return addToGraph(result);
</ins><span class="cx">     }
</span><span class="cx">     Node* addToGraph(NodeType op, Edge child1, Edge child2 = Edge(), Edge child3 = Edge())
</span><span class="cx">     {
</span><span class="cx">         Node* result = m_graph.addNode(
</span><span class="cx">             SpecNone, op, currentNodeOrigin(), child1, child2, child3);
</span><del>-        ASSERT(op != Phi);
-        m_currentBlock-&gt;append(result);
-        return result;
</del><ins>+        return addToGraph(result);
</ins><span class="cx">     }
</span><span class="cx">     Node* addToGraph(NodeType op, OpInfo info, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
</span><span class="cx">     {
</span><span class="cx">         Node* result = m_graph.addNode(
</span><span class="cx">             SpecNone, op, currentNodeOrigin(), info, Edge(child1), Edge(child2),
</span><span class="cx">             Edge(child3));
</span><del>-        ASSERT(op != Phi);
-        m_currentBlock-&gt;append(result);
-        return result;
</del><ins>+        return addToGraph(result);
</ins><span class="cx">     }
</span><span class="cx">     Node* addToGraph(NodeType op, OpInfo info1, OpInfo info2, Node* child1 = 0, Node* child2 = 0, Node* child3 = 0)
</span><span class="cx">     {
</span><span class="cx">         Node* result = m_graph.addNode(
</span><span class="cx">             SpecNone, op, currentNodeOrigin(), info1, info2,
</span><span class="cx">             Edge(child1), Edge(child2), Edge(child3));
</span><del>-        ASSERT(op != Phi);
-        m_currentBlock-&gt;append(result);
-        return result;
</del><ins>+        return addToGraph(result);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     Node* addToGraph(Node::VarArgTag, NodeType op, OpInfo info1, OpInfo info2)
</span><span class="lines">@@ -663,8 +663,7 @@
</span><span class="cx">         Node* result = m_graph.addNode(
</span><span class="cx">             SpecNone, Node::VarArg, op, currentNodeOrigin(), info1, info2,
</span><span class="cx">             m_graph.m_varArgChildren.size() - m_numPassedVarArgs, m_numPassedVarArgs);
</span><del>-        ASSERT(op != Phi);
-        m_currentBlock-&gt;append(result);
</del><ins>+        addToGraph(result);
</ins><span class="cx">         
</span><span class="cx">         m_numPassedVarArgs = 0;
</span><span class="cx">         
</span><span class="lines">@@ -1360,14 +1359,19 @@
</span><span class="cx">     // If there was a return, but no early returns, then we're done. We allow parsing of
</span><span class="cx">     // the caller to continue in whatever basic block we're in right now.
</span><span class="cx">     if (!inlineStackEntry.m_didEarlyReturn &amp;&amp; inlineStackEntry.m_didReturn) {
</span><del>-        ASSERT(lastBlock-&gt;isEmpty() || !lastBlock-&gt;last()-&gt;isTerminal());
</del><ins>+        if (Options::verboseDFGByteCodeParsing())
+            dataLog(&quot;    Allowing parsing to continue in last inlined block.\n&quot;);
</ins><span class="cx">         
</span><ins>+        ASSERT(lastBlock-&gt;isEmpty() || !lastBlock-&gt;terminal());
+        
</ins><span class="cx">         // If we created new blocks then the last block needs linking, but in the
</span><span class="cx">         // caller. It doesn't need to be linked to, but it needs outgoing links.
</span><span class="cx">         if (!inlineStackEntry.m_unlinkedBlocks.isEmpty()) {
</span><span class="cx">             // For debugging purposes, set the bytecodeBegin. Note that this doesn't matter
</span><span class="cx">             // for release builds because this block will never serve as a potential target
</span><span class="cx">             // in the linker's binary search.
</span><ins>+            if (Options::verboseDFGByteCodeParsing())
+                dataLog(&quot;        Repurposing last block from &quot;, lastBlock-&gt;bytecodeBegin, &quot; to &quot;, m_currentIndex, &quot;\n&quot;);
</ins><span class="cx">             lastBlock-&gt;bytecodeBegin = m_currentIndex;
</span><span class="cx">             if (callerLinkability == CallerDoesNormalLinking) {
</span><span class="cx">                 if (verbose)
</span><span class="lines">@@ -1380,8 +1384,11 @@
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    if (Options::verboseDFGByteCodeParsing())
+        dataLog(&quot;    Creating new block after inlining.\n&quot;);
+
</ins><span class="cx">     // If we get to this point then all blocks must end in some sort of terminals.
</span><del>-    ASSERT(lastBlock-&gt;last()-&gt;isTerminal());
</del><ins>+    ASSERT(lastBlock-&gt;terminal());
</ins><span class="cx"> 
</span><span class="cx">     // Need to create a new basic block for the continuation at the caller.
</span><span class="cx">     RefPtr&lt;BasicBlock&gt; block = adoptRef(new BasicBlock(nextOffset, m_numArguments, m_numLocals, PNaN));
</span><span class="lines">@@ -1392,7 +1399,7 @@
</span><span class="cx">             continue;
</span><span class="cx">         BasicBlock* blockToLink = inlineStackEntry.m_unlinkedBlocks[i].m_block;
</span><span class="cx">         ASSERT(!blockToLink-&gt;isLinked);
</span><del>-        Node* node = blockToLink-&gt;last();
</del><ins>+        Node* node = blockToLink-&gt;terminal();
</ins><span class="cx">         ASSERT(node-&gt;op() == Jump);
</span><span class="cx">         ASSERT(!node-&gt;targetBlock());
</span><span class="cx">         node-&gt;targetBlock() = block.get();
</span><span class="lines">@@ -1803,7 +1810,7 @@
</span><span class="cx">     m_currentBlock = continuationBlock.get();
</span><span class="cx">     
</span><span class="cx">     for (unsigned i = landingBlocks.size(); i--;)
</span><del>-        landingBlocks[i]-&gt;last()-&gt;targetBlock() = continuationBlock.get();
</del><ins>+        landingBlocks[i]-&gt;terminal()-&gt;targetBlock() = continuationBlock.get();
</ins><span class="cx">     
</span><span class="cx">     m_currentIndex = oldOffset;
</span><span class="cx">     
</span><span class="lines">@@ -3129,9 +3136,9 @@
</span><span class="cx"> 
</span><span class="cx">         case op_jmp: {
</span><span class="cx">             int relativeOffset = currentInstruction[1].u.operand;
</span><ins>+            addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
</ins><span class="cx">             if (relativeOffset &lt;= 0)
</span><span class="cx">                 flushForTerminal();
</span><del>-            addToGraph(Jump, OpInfo(m_currentIndex + relativeOffset));
</del><span class="cx">             LAST_OPCODE(op_jmp);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3251,8 +3258,8 @@
</span><span class="cx">                     continue;
</span><span class="cx">                 data.cases.append(SwitchCase::withBytecodeIndex(m_graph.freeze(jsNumber(static_cast&lt;int32_t&gt;(table.min + i))), target));
</span><span class="cx">             }
</span><ins>+            addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</ins><span class="cx">             flushIfTerminal(data);
</span><del>-            addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</del><span class="cx">             LAST_OPCODE(op_switch_imm);
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="lines">@@ -3271,8 +3278,8 @@
</span><span class="cx">                 data.cases.append(
</span><span class="cx">                     SwitchCase::withBytecodeIndex(LazyJSValue::singleCharacterString(table.min + i), target));
</span><span class="cx">             }
</span><ins>+            addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</ins><span class="cx">             flushIfTerminal(data);
</span><del>-            addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</del><span class="cx">             LAST_OPCODE(op_switch_char);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -3291,14 +3298,14 @@
</span><span class="cx">                 data.cases.append(
</span><span class="cx">                     SwitchCase::withBytecodeIndex(LazyJSValue::knownStringImpl(iter-&gt;key.get()), target));
</span><span class="cx">             }
</span><ins>+            addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</ins><span class="cx">             flushIfTerminal(data);
</span><del>-            addToGraph(Switch, OpInfo(&amp;data), get(VirtualRegister(currentInstruction[3].u.operand)));
</del><span class="cx">             LAST_OPCODE(op_switch_string);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         case op_ret:
</span><del>-            flushForReturn();
</del><span class="cx">             if (inlineCallFrame()) {
</span><ins>+                flushForReturn();
</ins><span class="cx">                 if (m_inlineStackTop-&gt;m_returnValue.isValid())
</span><span class="cx">                     setDirect(m_inlineStackTop-&gt;m_returnValue, get(VirtualRegister(currentInstruction[1].u.operand)), ImmediateSetWithFlush);
</span><span class="cx">                 m_inlineStackTop-&gt;m_didReturn = true;
</span><span class="lines">@@ -3322,12 +3329,13 @@
</span><span class="cx">                 LAST_OPCODE(op_ret);
</span><span class="cx">             }
</span><span class="cx">             addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
</span><ins>+            flushForReturn();
</ins><span class="cx">             LAST_OPCODE(op_ret);
</span><span class="cx">             
</span><span class="cx">         case op_end:
</span><del>-            flushForReturn();
</del><span class="cx">             ASSERT(!inlineCallFrame());
</span><span class="cx">             addToGraph(Return, get(VirtualRegister(currentInstruction[1].u.operand)));
</span><ins>+            flushForReturn();
</ins><span class="cx">             LAST_OPCODE(op_end);
</span><span class="cx"> 
</span><span class="cx">         case op_throw:
</span><span class="lines">@@ -3854,7 +3862,7 @@
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!block-&gt;isLinked);
</span><span class="cx">     ASSERT(!block-&gt;isEmpty());
</span><del>-    Node* node = block-&gt;last();
</del><ins>+    Node* node = block-&gt;terminal();
</ins><span class="cx">     ASSERT(node-&gt;isTerminal());
</span><span class="cx">     
</span><span class="cx">     switch (node-&gt;op()) {
</span><span class="lines">@@ -4134,10 +4142,13 @@
</span><span class="cx">             // are at the end of an inline function, or we realized that we
</span><span class="cx">             // should stop parsing because there was a return in the first
</span><span class="cx">             // basic block.
</span><del>-            ASSERT(m_currentBlock-&gt;isEmpty() || m_currentBlock-&gt;last()-&gt;isTerminal() || (m_currentIndex == codeBlock-&gt;instructions().size() &amp;&amp; inlineCallFrame()) || !shouldContinueParsing);
</del><ins>+            ASSERT(m_currentBlock-&gt;isEmpty() || m_currentBlock-&gt;terminal() || (m_currentIndex == codeBlock-&gt;instructions().size() &amp;&amp; inlineCallFrame()) || !shouldContinueParsing);
</ins><span class="cx"> 
</span><del>-            if (!shouldContinueParsing)
</del><ins>+            if (!shouldContinueParsing) {
+                if (Options::verboseDFGByteCodeParsing())
+                    dataLog(&quot;Done parsing &quot;, *codeBlock, &quot;\n&quot;);
</ins><span class="cx">                 return;
</span><ins>+            }
</ins><span class="cx">             
</span><span class="cx">             m_currentBlock = 0;
</span><span class="cx">         } while (m_currentIndex &lt; limit);
</span><span class="lines">@@ -4145,6 +4156,9 @@
</span><span class="cx"> 
</span><span class="cx">     // Should have reached the end of the instructions.
</span><span class="cx">     ASSERT(m_currentIndex == codeBlock-&gt;instructions().size());
</span><ins>+    
+    if (Options::verboseDFGByteCodeParsing())
+        dataLog(&quot;Done parsing &quot;, *codeBlock, &quot; (fell off end)\n&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool ByteCodeParser::parse()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCFGSimplificationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGCFGSimplificationPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2012, 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">                     continue;
</span><span class="cx">                 ASSERT(block-&gt;isReachable);
</span><span class="cx">             
</span><del>-                switch (block-&gt;last()-&gt;op()) {
</del><ins>+                switch (block-&gt;terminal()-&gt;op()) {
</ins><span class="cx">                 case Jump: {
</span><span class="cx">                     // Successor with one predecessor -&gt; merge.
</span><span class="cx">                     if (block-&gt;successor(0)-&gt;predecessors.size() == 1) {
</span><span class="lines">@@ -99,17 +99,19 @@
</span><span class="cx">                             if (extremeLogging)
</span><span class="cx">                                 m_graph.dump();
</span><span class="cx">                             m_graph.dethread();
</span><del>-                        
-                            ASSERT(block-&gt;last()-&gt;isTerminal());
-                            NodeOrigin boundaryNodeOrigin = block-&gt;last()-&gt;origin;
-                            block-&gt;last()-&gt;convertToPhantom();
-                            ASSERT(block-&gt;last()-&gt;refCount() == 1);
-                        
</del><ins>+                            
+                            Node* terminal = block-&gt;terminal();
+                            ASSERT(terminal-&gt;isTerminal());
+                            NodeOrigin boundaryNodeOrigin = terminal-&gt;origin;
+
</ins><span class="cx">                             jettisonBlock(block, jettisonedBlock, boundaryNodeOrigin);
</span><del>-                        
-                            block-&gt;appendNode(
</del><ins>+
+                            block-&gt;replaceTerminal(
</ins><span class="cx">                                 m_graph, SpecNone, Jump, boundaryNodeOrigin,
</span><span class="cx">                                 OpInfo(targetBlock));
</span><ins>+                            
+                            ASSERT(block-&gt;terminal());
+                        
</ins><span class="cx">                         }
</span><span class="cx">                         innerChanged = outerChanged = true;
</span><span class="cx">                         break;
</span><span class="lines">@@ -129,7 +131,7 @@
</span><span class="cx">                 }
</span><span class="cx">                     
</span><span class="cx">                 case Switch: {
</span><del>-                    SwitchData* data = block-&gt;last()-&gt;switchData();
</del><ins>+                    SwitchData* data = block-&gt;terminal()-&gt;switchData();
</ins><span class="cx">                     
</span><span class="cx">                     // Prune out cases that end up jumping to default.
</span><span class="cx">                     for (unsigned i = 0; i &lt; data-&gt;cases.size(); ++i) {
</span><span class="lines">@@ -149,8 +151,9 @@
</span><span class="cx">                     }
</span><span class="cx">                     
</span><span class="cx">                     // Switch on constant -&gt; jettison all other targets and merge.
</span><del>-                    if (block-&gt;last()-&gt;child1()-&gt;hasConstant()) {
-                        FrozenValue* value = block-&gt;last()-&gt;child1()-&gt;constant();
</del><ins>+                    Node* terminal = block-&gt;terminal();
+                    if (terminal-&gt;child1()-&gt;hasConstant()) {
+                        FrozenValue* value = terminal-&gt;child1()-&gt;constant();
</ins><span class="cx">                         TriState found = FalseTriState;
</span><span class="cx">                         BasicBlock* targetBlock = 0;
</span><span class="cx">                         for (unsigned i = data-&gt;cases.size(); found == FalseTriState &amp;&amp; i--;) {
</span><span class="lines">@@ -166,10 +169,9 @@
</span><span class="cx">                         ASSERT(targetBlock);
</span><span class="cx">                         
</span><span class="cx">                         Vector&lt;BasicBlock*, 1&gt; jettisonedBlocks;
</span><del>-                        for (unsigned i = block-&gt;numSuccessors(); i--;) {
-                            BasicBlock* jettisonedBlock = block-&gt;successor(i);
-                            if (jettisonedBlock != targetBlock)
-                                jettisonedBlocks.append(jettisonedBlock);
</del><ins>+                        for (BasicBlock* successor : terminal-&gt;successors()) {
+                            if (successor != targetBlock)
+                                jettisonedBlocks.append(successor);
</ins><span class="cx">                         }
</span><span class="cx">                         
</span><span class="cx">                         if (targetBlock-&gt;predecessors.size() == 1) {
</span><span class="lines">@@ -183,11 +185,12 @@
</span><span class="cx">                                 m_graph.dump();
</span><span class="cx">                             m_graph.dethread();
</span><span class="cx">                             
</span><del>-                            NodeOrigin boundaryNodeOrigin = block-&gt;last()-&gt;origin;
-                            block-&gt;last()-&gt;convertToPhantom();
</del><ins>+                            NodeOrigin boundaryNodeOrigin = terminal-&gt;origin;
+
</ins><span class="cx">                             for (unsigned i = jettisonedBlocks.size(); i--;)
</span><span class="cx">                                 jettisonBlock(block, jettisonedBlocks[i], boundaryNodeOrigin);
</span><del>-                            block-&gt;appendNode(
</del><ins>+                            
+                            block-&gt;replaceTerminal(
</ins><span class="cx">                                 m_graph, SpecNone, Jump, boundaryNodeOrigin, OpInfo(targetBlock));
</span><span class="cx">                         }
</span><span class="cx">                         innerChanged = outerChanged = true;
</span><span class="lines">@@ -253,13 +256,10 @@
</span><span class="cx">             m_graph.dethread();
</span><span class="cx">             mergeBlocks(block, targetBlock, noBlocks());
</span><span class="cx">         } else {
</span><del>-            Node* branch = block-&gt;last();
-            ASSERT(branch-&gt;isTerminal());
</del><ins>+            Node* branch = block-&gt;terminal();
</ins><span class="cx">             ASSERT(branch-&gt;op() == Branch || branch-&gt;op() == Switch);
</span><del>-            branch-&gt;convertToPhantom();
-            ASSERT(branch-&gt;refCount() == 1);
-            
-            block-&gt;appendNode(
</del><ins>+
+            block-&gt;replaceTerminal(
</ins><span class="cx">                 m_graph, SpecNone, Jump, branch-&gt;origin, OpInfo(targetBlock));
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -318,10 +318,11 @@
</span><span class="cx">         
</span><span class="cx">         // Remove the terminal of firstBlock since we don't need it anymore. Well, we don't
</span><span class="cx">         // really remove it; we actually turn it into a Phantom.
</span><del>-        ASSERT(firstBlock-&gt;last()-&gt;isTerminal());
-        NodeOrigin boundaryNodeOrigin = firstBlock-&gt;last()-&gt;origin;
-        firstBlock-&gt;last()-&gt;convertToPhantom();
-        ASSERT(firstBlock-&gt;last()-&gt;refCount() == 1);
</del><ins>+        Node* terminal = firstBlock-&gt;terminal();
+        ASSERT(terminal-&gt;isTerminal());
+        NodeOrigin boundaryNodeOrigin = terminal-&gt;origin;
+        terminal-&gt;convertToPhantom();
+        ASSERT(terminal-&gt;refCount() == 1);
</ins><span class="cx">         
</span><span class="cx">         for (unsigned i = jettisonedBlocks.size(); i--;) {
</span><span class="cx">             BasicBlock* jettisonedBlock = jettisonedBlocks[i];
</span><span class="lines">@@ -342,7 +343,7 @@
</span><span class="cx">         for (size_t i = 0; i &lt; secondBlock-&gt;size(); ++i)
</span><span class="cx">             firstBlock-&gt;append(secondBlock-&gt;at(i));
</span><span class="cx">         
</span><del>-        ASSERT(firstBlock-&gt;last()-&gt;isTerminal());
</del><ins>+        ASSERT(firstBlock-&gt;terminal()-&gt;isTerminal());
</ins><span class="cx">         
</span><span class="cx">         // Fix the predecessors of my new successors. This is tricky, since we are going to reset
</span><span class="cx">         // all predecessors anyway due to reachability analysis. But we need to fix the
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCPSRethreadingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGCPSRethreadingPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -363,6 +363,10 @@
</span><span class="cx">                 m_availableForOSR.operand(node-&gt;unlinkedLocal()) = node-&gt;child1();
</span><span class="cx">                 break;
</span><span class="cx">                 
</span><ins>+            case ZombieHint:
+                m_availableForOSR.operand(node-&gt;unlinkedLocal()) = Edge();
+                break;
+                
</ins><span class="cx">             default:
</span><span class="cx">                 break;
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGCommonh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGCommon.h (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGCommon.h        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGCommon.h        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -274,6 +274,29 @@
</span><span class="cx"> 
</span><span class="cx"> JS_EXPORT_PRIVATE bool isCrashing();
</span><span class="cx"> 
</span><ins>+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;
+};
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -85,7 +85,7 @@
</span><span class="cx">             addPhantomsIfNecessary();
</span><span class="cx">             fixupNode(m_currentNode);
</span><span class="cx">         }
</span><del>-        clearPhantomsAtEnd();
</del><ins>+        addPhantomsIfNecessary();
</ins><span class="cx">         m_insertionSet.execute(block);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -725,9 +725,8 @@
</span><span class="cx">             else if (node-&gt;child1()-&gt;shouldSpeculateObjectOrOther())
</span><span class="cx">                 fixEdge&lt;ObjectOrOtherUse&gt;(node-&gt;child1());
</span><span class="cx">             // FIXME: We should just be able to do shouldSpeculateInt32OrBoolean() and
</span><del>-            // 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
</del><ins>+            // shouldSpeculateNumberOrBoolean() here now that
+            // https://bugs.webkit.org/show_bug.cgi?id=126778 is fixed.
</ins><span class="cx">             else if (node-&gt;child1()-&gt;shouldSpeculateInt32())
</span><span class="cx">                 fixEdge&lt;Int32Use&gt;(node-&gt;child1());
</span><span class="cx">             else if (node-&gt;child1()-&gt;shouldSpeculateNumber())
</span><span class="lines">@@ -1996,7 +1995,7 @@
</span><span class="cx">             tryToRelaxRepresentation(m_currentNode);
</span><span class="cx">             DFG_NODE_DO_TO_CHILDREN(m_graph, m_currentNode, injectTypeConversionsForEdge);
</span><span class="cx">         }
</span><del>-        clearPhantomsAtEnd();
</del><ins>+        addPhantomsIfNecessary();
</ins><span class="cx">         m_insertionSet.execute(block);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="lines">@@ -2161,21 +2160,6 @@
</span><span class="cx">         m_requiredPhantoms.resize(0);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    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);
-    }
-    
</del><span class="cx">     BasicBlock* m_block;
</span><span class="cx">     unsigned m_indexInBlock;
</span><span class="cx">     Node* m_currentNode;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGForAllKillsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGForAllKills.h        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -48,13 +48,13 @@
</span><span class="cx">             functor(node);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    DFG_ASSERT(graph, block-&gt;last(), block-&gt;last()-&gt;origin.forExit.isSet());
</del><ins>+    DFG_ASSERT(graph, block-&gt;terminal(), block-&gt;terminal()-&gt;origin.forExit.isSet());
</ins><span class="cx">     
</span><span class="cx">     AvailabilityMap&amp; availabilityMap = block-&gt;ssa-&gt;availabilityAtTail;
</span><span class="cx">     for (unsigned i = availabilityMap.m_locals.size(); i--;) {
</span><span class="cx">         VirtualRegister reg = availabilityMap.m_locals.virtualRegisterForIndex(i);
</span><span class="cx">         
</span><del>-        if (!graph.isLiveInBytecode(reg, block-&gt;last()-&gt;origin.forExit))
</del><ins>+        if (!graph.isLiveInBytecode(reg, block-&gt;terminal()-&gt;origin.forExit))
</ins><span class="cx">             continue;
</span><span class="cx">         
</span><span class="cx">         availabilityMap.closeStartingWithLocal(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -365,6 +365,15 @@
</span><span class="cx">     out.print(&quot;\n&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool Graph::terminalsAreValid()
+{
+    for (BasicBlock* block : blocksInNaturalOrder()) {
+        if (!block-&gt;terminal())
+            return false;
+    }
+    return true;
+}
+
</ins><span class="cx"> void Graph::dumpBlockHeader(PrintStream&amp; out, const char* prefix, BasicBlock* block, PhiNodeDumpMode phiNodeDumpMode, DumpContext* context)
</span><span class="cx"> {
</span><span class="cx">     out.print(prefix, &quot;Block &quot;, *block, &quot; (&quot;, inContext(block-&gt;at(0)-&gt;origin.semantic, context), &quot;):&quot;, block-&gt;isReachable ? &quot;&quot; : &quot; (skipped)&quot;, block-&gt;isOSRTarget ? &quot; (OSR target)&quot; : &quot;&quot;, &quot;\n&quot;);
</span><span class="lines">@@ -375,13 +384,16 @@
</span><span class="cx">         out.print(&quot; &quot;, *block-&gt;predecessors[i]);
</span><span class="cx">     out.print(&quot;\n&quot;);
</span><span class="cx">     out.print(prefix, &quot;  Successors:&quot;);
</span><del>-    for (BasicBlock* successor : block-&gt;successors()) {
-        out.print(&quot; &quot;, *successor);
-        if (m_prePostNumbering.isValid())
-            out.print(&quot; (&quot;, m_prePostNumbering.edgeKind(block, successor), &quot;)&quot;);
-    }
</del><ins>+    if (block-&gt;terminal()) {
+        for (BasicBlock* successor : block-&gt;successors()) {
+            out.print(&quot; &quot;, *successor);
+            if (m_prePostNumbering.isValid())
+                out.print(&quot; (&quot;, m_prePostNumbering.edgeKind(block, successor), &quot;)&quot;);
+        }
+    } else
+        out.print(&quot; &lt;invalid&gt;&quot;);
</ins><span class="cx">     out.print(&quot;\n&quot;);
</span><del>-    if (m_dominators.isValid()) {
</del><ins>+    if (m_dominators.isValid() &amp;&amp; terminalsAreValid()) {
</ins><span class="cx">         out.print(prefix, &quot;  Dominated by: &quot;, m_dominators.dominatorsOf(block), &quot;\n&quot;);
</span><span class="cx">         out.print(prefix, &quot;  Dominates: &quot;, m_dominators.blocksDominatedBy(block), &quot;\n&quot;);
</span><span class="cx">         out.print(prefix, &quot;  Dominance Frontier: &quot;, m_dominators.dominanceFrontierOf(block), &quot;\n&quot;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -196,6 +196,9 @@
</span><span class="cx">     
</span><span class="cx">     // CodeBlock is optional, but may allow additional information to be dumped (e.g. Identifier names).
</span><span class="cx">     void dump(PrintStream&amp; = WTF::dataFile(), DumpContext* = 0);
</span><ins>+    
+    bool terminalsAreValid();
+    
</ins><span class="cx">     enum PhiNodeDumpMode { DumpLivePhisOnly, DumpAllPhis };
</span><span class="cx">     void dumpBlockHeader(PrintStream&amp;, const char* prefix, BasicBlock*, PhiNodeDumpMode, DumpContext*);
</span><span class="cx">     void dump(PrintStream&amp;, Edge);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -361,7 +361,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline bool InPlaceAbstractState::mergeToSuccessors(BasicBlock* basicBlock)
</span><span class="cx"> {
</span><del>-    Node* terminal = basicBlock-&gt;last();
</del><ins>+    Node* terminal = basicBlock-&gt;terminal();
</ins><span class="cx">     
</span><span class="cx">     ASSERT(terminal-&gt;isTerminal());
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGLICMPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGLICMPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -128,7 +128,7 @@
</span><span class="cx">                 preHeader = predecessor;
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            DFG_ASSERT(m_graph, preHeader-&gt;last(), preHeader-&gt;last()-&gt;op() == Jump);
</del><ins>+            DFG_ASSERT(m_graph, preHeader-&gt;terminal(), preHeader-&gt;terminal()-&gt;op() == Jump);
</ins><span class="cx">             
</span><span class="cx">             data.preHeader = preHeader;
</span><span class="cx">         }
</span><span class="lines">@@ -237,10 +237,10 @@
</span><span class="cx">                 &quot;\n&quot;);
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        data.preHeader-&gt;insertBeforeLast(node);
</del><ins>+        data.preHeader-&gt;insertBeforeTerminal(node);
</ins><span class="cx">         node-&gt;owner = data.preHeader;
</span><span class="cx">         NodeOrigin originalOrigin = node-&gt;origin;
</span><del>-        node-&gt;origin.forExit = data.preHeader-&gt;last()-&gt;origin.forExit;
</del><ins>+        node-&gt;origin.forExit = data.preHeader-&gt;terminal()-&gt;origin.forExit;
</ins><span class="cx">         
</span><span class="cx">         // Modify the states at the end of the preHeader of the loop we hoisted to,
</span><span class="cx">         // and all pre-headers inside the loop.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMovHintRemovalPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGMovHintRemovalPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -82,7 +82,7 @@
</span><span class="cx">         
</span><span class="cx">         for (unsigned i = m_state.size(); i--;) {
</span><span class="cx">             VirtualRegister reg = m_state.virtualRegisterForIndex(i);
</span><del>-            if (m_graph.isLiveInBytecode(reg, block-&gt;last()-&gt;origin.forExit))
</del><ins>+            if (m_graph.isLiveInBytecode(reg, block-&gt;terminal()-&gt;origin.forExit))
</ins><span class="cx">                 m_state[i] = currentEpoch;
</span><span class="cx">             else
</span><span class="cx">                 m_state[i] = Epoch();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1142,6 +1142,76 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    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-&gt;successor(m_index);
+            }
+            
+            iterator&amp; operator++()
+            {
+                m_index++;
+                return *this;
+            }
+            
+            bool operator==(const iterator&amp; other) const
+            {
+                return m_index == other.m_index;
+            }
+            
+            bool operator!=(const iterator&amp; 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-&gt;numSuccessors());
+        }
+        
+    private:
+        Node* m_terminal;
+    };
+    
+    SuccessorsIterable successors()
+    {
+        return SuccessorsIterable(this);
+    }
+    
</ins><span class="cx">     BasicBlock*&amp; successorForCondition(bool condition)
</span><span class="cx">     {
</span><span class="cx">         return branchData()-&gt;forCondition(condition);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -352,7 +352,7 @@
</span><span class="cx">                     // already handled the case where the predecessor has multiple successors.
</span><span class="cx">                     DFG_ASSERT(m_graph, block, block-&gt;numSuccessors() == 1);
</span><span class="cx">                     
</span><del>-                    createMaterialize(allocation, block-&gt;last());
</del><ins>+                    createMaterialize(allocation, block-&gt;terminal());
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -461,8 +461,9 @@
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            size_t upsilonInsertionPoint = block-&gt;size() - 1;
-            Node* upsilonWhere = block-&gt;last();
</del><ins>+            NodeAndIndex terminal = block-&gt;findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            Node* upsilonWhere = terminal.node;
</ins><span class="cx">             NodeOrigin upsilonOrigin = upsilonWhere-&gt;origin;
</span><span class="cx">             for (BasicBlock* successorBlock : block-&gt;successors()) {
</span><span class="cx">                 for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) {
</span><span class="lines">@@ -708,8 +709,9 @@
</span><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             // Gotta drop some Upsilons.
</span><del>-            size_t upsilonInsertionPoint = block-&gt;size() - 1;
-            NodeOrigin upsilonOrigin = block-&gt;last()-&gt;origin;
</del><ins>+            NodeAndIndex terminal = block-&gt;findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            NodeOrigin upsilonOrigin = terminal.node-&gt;origin;
</ins><span class="cx">             for (BasicBlock* successorBlock : block-&gt;successors()) {
</span><span class="cx">                 for (SSACalculator::Def* phiDef : m_ssaCalculator.phisForBlock(successorBlock)) {
</span><span class="cx">                     Node* phiNode = phiDef-&gt;value();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPhantomRemovalPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGPhantomRemovalPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -90,6 +90,9 @@
</span><span class="cx">                     Node* lastNode = nullptr;
</span><span class="cx">                     if (sourceIndex &gt; 1) {
</span><span class="cx">                         lastNode = block-&gt;at(sourceIndex - 2);
</span><ins>+                        
+                        // 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.
</ins><span class="cx">                         if (lastNode-&gt;op() != Phantom
</span><span class="cx">                             || lastNode-&gt;origin.forExit != node-&gt;origin.forExit)
</span><span class="cx">                             lastNode = nullptr;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -441,8 +441,9 @@
</span><span class="cx">                 } }
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            size_t upsilonInsertionPoint = block-&gt;size() - 1;
-            NodeOrigin upsilonOrigin = block-&gt;last()-&gt;origin;
</del><ins>+            NodeAndIndex terminal = block-&gt;findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            NodeOrigin upsilonOrigin = terminal.node-&gt;origin;
</ins><span class="cx">             for (BasicBlock* successorBlock : block-&gt;successors()) {
</span><span class="cx">                 for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(successorBlock)) {
</span><span class="cx">                     Node* phiNode = phiDef-&gt;value();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -335,8 +335,9 @@
</span><span class="cx">             // seems dangerous because the Upsilon will have a checking UseKind. But, we will not
</span><span class="cx">             // actually be performing the check at the point of the Upsilon; the check will
</span><span class="cx">             // already have been performed at the point where the original SetLocal was.
</span><del>-            size_t upsilonInsertionPoint = block-&gt;size() - 1;
-            NodeOrigin upsilonOrigin = block-&gt;last()-&gt;origin;
</del><ins>+            NodeAndIndex terminal = block-&gt;findTerminal();
+            size_t upsilonInsertionPoint = terminal.index;
+            NodeOrigin upsilonOrigin = terminal.node-&gt;origin;
</ins><span class="cx">             for (unsigned successorIndex = block-&gt;numSuccessors(); successorIndex--;) {
</span><span class="cx">                 BasicBlock* successorBlock = block-&gt;successor(successorIndex);
</span><span class="cx">                 for (SSACalculator::Def* phiDef : m_calculator.phisForBlock(successorBlock)) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -681,7 +681,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // Check if the lastNode is a branch on this node.
</span><del>-        Node* lastNode = m_block-&gt;last();
</del><ins>+        Node* lastNode = m_block-&gt;terminal();
</ins><span class="cx">         return lastNode-&gt;op() == Branch &amp;&amp; lastNode-&gt;child1() == m_currentNode ? m_block-&gt;size() - 1 : UINT_MAX;
</span><span class="cx">     }
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1832,11 +1832,14 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    case MovHint:
-    case ZombieHint: {
</del><ins>+    case MovHint: {
</ins><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">         break;
</span><span class="cx">     }
</span><ins>+        
+    case ZombieHint:
+        recordSetLocal(m_currentNode-&gt;unlinkedLocal(), VirtualRegister(), DataFormatDead);
+        break;
</ins><span class="cx"> 
</span><span class="cx">     case SetLocal: {
</span><span class="cx">         switch (node-&gt;variableAccessData()-&gt;flushFormat()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1932,7 +1932,7 @@
</span><span class="cx">         noResult(node);
</span><span class="cx">         break;
</span><span class="cx">     }
</span><del>-
</del><ins>+        
</ins><span class="cx">     case SetLocal: {
</span><span class="cx">         switch (node-&gt;variableAccessData()-&gt;flushFormat()) {
</span><span class="cx">         case FlushedDouble: {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGStaticExecutionCountEstimationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGStaticExecutionCountEstimationPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGStaticExecutionCountEstimationPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGStaticExecutionCountEstimationPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -63,16 +63,17 @@
</span><span class="cx">             if (!block)
</span><span class="cx">                 continue;
</span><span class="cx">             
</span><del>-            switch (block-&gt;last()-&gt;op()) {
</del><ins>+            Node* terminal = block-&gt;terminal();
+            switch (terminal-&gt;op()) {
</ins><span class="cx">             case Branch: {
</span><del>-                BranchData* data = block-&gt;last()-&gt;branchData();
</del><ins>+                BranchData* data = terminal-&gt;branchData();
</ins><span class="cx">                 applyCounts(data-&gt;taken);
</span><span class="cx">                 applyCounts(data-&gt;notTaken);
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">                 
</span><span class="cx">             case Switch: {
</span><del>-                SwitchData* data = block-&gt;last()-&gt;switchData();
</del><ins>+                SwitchData* data = terminal-&gt;switchData();
</ins><span class="cx">                 for (unsigned i = data-&gt;cases.size(); i--;)
</span><span class="cx">                     applyCounts(data-&gt;cases[i].target);
</span><span class="cx">                 applyCounts(data-&gt;fallThrough);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGTierUpCheckInjectionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGTierUpCheckInjectionPhase.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -103,9 +103,10 @@
</span><span class="cx">                 break;
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            if (block-&gt;last()-&gt;op() == Return) {
</del><ins>+            NodeAndIndex terminal = block-&gt;findTerminal();
+            if (terminal.node-&gt;op() == Return) {
</ins><span class="cx">                 insertionSet.insertNode(
</span><del>-                    block-&gt;size() - 1, SpecNone, CheckTierUpAtReturn, block-&gt;last()-&gt;origin);
</del><ins>+                    terminal.index, SpecNone, CheckTierUpAtReturn, terminal.node-&gt;origin);
</ins><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             insertionSet.execute(block);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -189,10 +189,24 @@
</span><span class="cx">                     V_EQUAL((node), m_myRefCounts.get(node), node-&gt;adjustedRefCount());
</span><span class="cx">             }
</span><span class="cx">             
</span><del>-            for (size_t i = 0 ; i &lt; block-&gt;size() - 1; ++i) {
</del><ins>+            bool foundTerminal = false;
+            for (size_t i = 0 ; i &lt; block-&gt;size(); ++i) {
</ins><span class="cx">                 Node* node = block-&gt;at(i);
</span><del>-                VALIDATE((node), !node-&gt;isTerminal());
</del><ins>+                if (node-&gt;isTerminal()) {
+                    foundTerminal = true;
+                    for (size_t j = i + 1; j &lt; block-&gt;size(); ++j) {
+                        node = block-&gt;at(j);
+                        VALIDATE((node), node-&gt;op() == Phantom || node-&gt;op() == PhantomLocal || node-&gt;op() == Flush);
+                        m_graph.doToChildren(
+                            node,
+                            [&amp;] (Edge edge) {
+                                VALIDATE((node, edge), shouldNotHaveTypeCheck(edge.useKind()));
+                            });
+                    }
+                    break;
+                }
</ins><span class="cx">             }
</span><ins>+            VALIDATE((block), foundTerminal);
</ins><span class="cx">             
</span><span class="cx">             for (size_t i = 0; i &lt; block-&gt;size(); ++i) {
</span><span class="cx">                 Node* node = block-&gt;at(i);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (183093 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-04-22 02:46:45 UTC (rev 183093)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -859,8 +859,11 @@
</span><span class="cx">             DFG_CRASH(m_graph, m_node, &quot;Unrecognized node in FTL backend&quot;);
</span><span class="cx">             break;
</span><span class="cx">         }
</span><del>-
-        if (!m_state.isValid() &amp;&amp; !m_node-&gt;isTerminal()) {
</del><ins>+        
+        if (m_node-&gt;isTerminal())
+            return false;
+        
+        if (!m_state.isValid()) {
</ins><span class="cx">             safelyInvalidateAfterTermination();
</span><span class="cx">             return false;
</span><span class="cx">         }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressclosurecallexitjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/closure-call-exit.js (0 => 183094)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/closure-call-exit.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/closure-call-exit.js        2015-04-22 03:38:17 UTC (rev 183094)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+function foo(o, i) {
+    return o[i]();
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var result = foo([function() { return 42; }], 0);
+    if (result != 42)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
+var result = foo([function() { return 43; }], 0);
+if (result != 43)
+    throw &quot;Error: bad result at end: &quot; + result;
</ins></span></pre>
</div>
</div>

</body>
</html>