<!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>[174275] trunk</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/174275">174275</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2014-10-03 12:38:06 -0700 (Fri, 03 Oct 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>FTL should sink PutLocals
https://bugs.webkit.org/show_bug.cgi?id=137168

Reviewed by Oliver Hunt.
Source/JavaScriptCore:

        
We've known for a while that our PutLocal situation was sub-optimal. We emit them anytime we
&quot;pass&quot; arguments to an inlined function call, because we need to enable the runtime to grab
those arguments when doing foo.arguments where foo is inlined: our engine doesn't deoptimize
in that case but rather just relies on the arguments being flushed (i.e. a copy of their
values is spilled) at a well-known place in a well-known format.
        
The PutLocals incur two costs: (1) they are store instructions and stores ain't free, and (2)
they look like escaping sites and so they inhibit object allocation sinking.
        
But in most cases, the PutLocals are unnecessary because the inlined code never performs any
side effect that could transitively lead to function.arguments. Even if the inlined code
could do such a side effect, it may be on a rare path so there is no need to penalize the
entire function.
        
This patch implements one solution to the PutLocal problem: it aggressively sinks PutLocals
to the latest possible point. This is even more aggressive than the object allocation
sinking. That sinking algorithm avoids creating situations where an object could be
materialized more than one along any path. PutLocal sinking, on the other hand, doesn't avoid
this at all - both to make the phase cheaper and simpler and to make it more aggressive.
Every PutLocal is sunk no matter what.
        
The upside of this patch is that it eliminates many PutLocals: many of them are sunk &quot;past
their death&quot;, thus eliminating them completely. Others are sunk to rare paths. This enables a
lot of object allocation sinking and it removes a lot of pointless store instructions.
        
It also has downsites. Sinking PutLocals increases register pressure because it increases the
live ranges of things like inlined arguments.
        
This patch is a net performance win in its current form: 1% SunSpider regression, 2% OctaneV2
progression, 0.6% Kraken regression, 1% AsmBench progression, and 0.5% CompressionBench
regression. The biggest win is on Octane/raytrace, which improves by 27%.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.h:
* bytecode/Operands.h:
(JSC::Operands::dump): Deleted.
* bytecode/OperandsInlines.h:
(JSC::Traits&gt;::dump):
* bytecode/VirtualRegister.h:
(JSC::VirtualRegister::isHeader):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
* dfg/DFGClobberSet.h:
(JSC::DFG::ClobberSetAdd::operator()):
(JSC::DFG::ClobberSetOverlaps::operator()):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
(JSC::DFG::NoOpClobberize::operator()):
(JSC::DFG::CheckClobberize::operator()):
(JSC::DFG::AbstractHeapOverlaps::operator()):
(JSC::DFG::ReadMethodClobberize::operator()):
(JSC::DFG::WriteMethodClobberize::operator()):
(JSC::DFG::DefMethodClobberize::operator()):
* dfg/DFGFlushFormat.h:
(JSC::DFG::merge):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::Graph):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::capturedVarsFor):
* dfg/DFGObjectAllocationSinkingPhase.cpp:
(JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
(JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPreciseLocalClobberize.h: Added.
(JSC::DFG::PreciseLocalClobberizeAdaptor::PreciseLocalClobberizeAdaptor):
(JSC::DFG::PreciseLocalClobberizeAdaptor::read):
(JSC::DFG::PreciseLocalClobberizeAdaptor::write):
(JSC::DFG::PreciseLocalClobberizeAdaptor::def):
(JSC::DFG::PreciseLocalClobberizeAdaptor::callIfAppropriate):
(JSC::DFG::PreciseLocalClobberizeAdaptor::readTop):
(JSC::DFG::PreciseLocalClobberizeAdaptor::writeTop):
(JSC::DFG::forEachLocalReadByUnwind):
(JSC::DFG::preciseLocalClobberize):
* dfg/DFGPutLocalSinkingPhase.cpp: Added.
(JSC::DFG::performPutLocalSinking):
* dfg/DFGPutLocalSinkingPhase.h: Added.
* dfg/DFGSSACalculator.h:
(JSC::DFG::SSACalculator::computePhis):
* dfg/DFGValidate.cpp:

Source/WTF:

        
Make the set bits of a BitVector iterable.

* wtf/BitVector.h:
(WTF::BitVector::SetBitsIterable::SetBitsIterable):
(WTF::BitVector::SetBitsIterable::iterator::iterator):
(WTF::BitVector::SetBitsIterable::iterator::operator*):
(WTF::BitVector::SetBitsIterable::iterator::operator++):
(WTF::BitVector::SetBitsIterable::iterator::operator==):
(WTF::BitVector::SetBitsIterable::iterator::operator!=):
(WTF::BitVector::SetBitsIterable::begin):
(WTF::BitVector::SetBitsIterable::end):
(WTF::BitVector::setBits):

LayoutTests:


* js/regress/elidable-new-object-then-call-expected.txt: Added.
* js/regress/elidable-new-object-then-call.html: Added.
* js/regress/script-tests/elidable-new-object-then-call.js: Added.
(sumOfArithSeries):
(bar):
(foo):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreCMakeListstxt">trunk/Source/JavaScriptCore/CMakeLists.txt</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj">trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj</a></li>
<li><a href="#trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj">trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeCodeBlockh">trunk/Source/JavaScriptCore/bytecode/CodeBlock.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeOperandsh">trunk/Source/JavaScriptCore/bytecode/Operands.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeOperandsInlinesh">trunk/Source/JavaScriptCore/bytecode/OperandsInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCorebytecodeVirtualRegisterh">trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp">trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberSeth">trunk/Source/JavaScriptCore/dfg/DFGClobberSet.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFlushFormath">trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.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="#trunkSourceJavaScriptCoredfgDFGMayExitcpp">trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlancpp">trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSSACalculatorh">trunk/Source/JavaScriptCore/dfg/DFGSSACalculator.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGValidatecpp">trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp</a></li>
<li><a href="#trunkSourceWTFChangeLog">trunk/Source/WTF/ChangeLog</a></li>
<li><a href="#trunkSourceWTFwtfBitVectorh">trunk/Source/WTF/wtf/BitVector.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregresselidablenewobjectthencallexpectedtxt">trunk/LayoutTests/js/regress/elidable-new-object-then-call-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregresselidablenewobjectthencallhtml">trunk/LayoutTests/js/regress/elidable-new-object-then-call.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestselidablenewobjectthencalljs">trunk/LayoutTests/js/regress/script-tests/elidable-new-object-then-call.js</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPreciseLocalClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhaseh">trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/LayoutTests/ChangeLog        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2014-10-02  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        FTL should sink PutLocals
+        https://bugs.webkit.org/show_bug.cgi?id=137168
+
+        Reviewed by Oliver Hunt.
+
+        * js/regress/elidable-new-object-then-call-expected.txt: Added.
+        * js/regress/elidable-new-object-then-call.html: Added.
+        * js/regress/script-tests/elidable-new-object-then-call.js: Added.
+        (sumOfArithSeries):
+        (bar):
+        (foo):
+
</ins><span class="cx"> 2014-10-03 Bear Travis &lt;betravis@adobe.com&gt;
</span><span class="cx"> 
</span><span class="cx">         REGRESSION (r173531): Use after free in WebCore::RenderStyle::fontMetrics /
</span></span></pre></div>
<a id="trunkLayoutTestsjsregresselidablenewobjectthencallexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/elidable-new-object-then-call-expected.txt (0 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/elidable-new-object-then-call-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/elidable-new-object-then-call-expected.txt        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/elidable-new-object-then-call
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregresselidablenewobjectthencallhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/elidable-new-object-then-call.html (0 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/elidable-new-object-then-call.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/elidable-new-object-then-call.html        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/elidable-new-object-then-call.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestselidablenewobjectthencalljs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/elidable-new-object-then-call.js (0 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/elidable-new-object-then-call.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/elidable-new-object-then-call.js        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+function sumOfArithSeries(limit) {
+    return limit * (limit + 1) / 2;
+}
+
+var n = 10000000;
+
+function bar(p, o) {
+    if (p)
+        return 5;
+    else
+        return 6;
+}
+
+function foo() {
+    var result = 0;
+    for (var i = 0; i &lt; n; ++i) {
+        var o = {f: i};
+        var p = {f: i + 1};
+        bar(i, o);
+        bar(i, p);
+        result += o.f + p.f;
+    }
+    return result;
+}
+
+var result = foo();
+if (result != sumOfArithSeries(n - 1) + sumOfArithSeries(n))
+    throw &quot;Error: bad result: &quot; + result;
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -207,6 +207,7 @@
</span><span class="cx">     dfg/DFGPredictionPropagationPhase.cpp
</span><span class="cx">     dfg/DFGPromotedHeapLocation.cpp
</span><span class="cx">     dfg/DFGPureValue.cpp
</span><ins>+    dfg/DFGPutLocalSinkingPhase.cpp
</ins><span class="cx">     dfg/DFGResurrectionForValidationPhase.cpp
</span><span class="cx">     dfg/DFGSSACalculator.cpp
</span><span class="cx">     dfg/DFGSSAConversionPhase.cpp
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -1,3 +1,93 @@
</span><ins>+2014-10-02  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        FTL should sink PutLocals
+        https://bugs.webkit.org/show_bug.cgi?id=137168
+
+        Reviewed by Oliver Hunt.
+        
+        We've known for a while that our PutLocal situation was sub-optimal. We emit them anytime we
+        &quot;pass&quot; arguments to an inlined function call, because we need to enable the runtime to grab
+        those arguments when doing foo.arguments where foo is inlined: our engine doesn't deoptimize
+        in that case but rather just relies on the arguments being flushed (i.e. a copy of their
+        values is spilled) at a well-known place in a well-known format.
+        
+        The PutLocals incur two costs: (1) they are store instructions and stores ain't free, and (2)
+        they look like escaping sites and so they inhibit object allocation sinking.
+        
+        But in most cases, the PutLocals are unnecessary because the inlined code never performs any
+        side effect that could transitively lead to function.arguments. Even if the inlined code
+        could do such a side effect, it may be on a rare path so there is no need to penalize the
+        entire function.
+        
+        This patch implements one solution to the PutLocal problem: it aggressively sinks PutLocals
+        to the latest possible point. This is even more aggressive than the object allocation
+        sinking. That sinking algorithm avoids creating situations where an object could be
+        materialized more than one along any path. PutLocal sinking, on the other hand, doesn't avoid
+        this at all - both to make the phase cheaper and simpler and to make it more aggressive.
+        Every PutLocal is sunk no matter what.
+        
+        The upside of this patch is that it eliminates many PutLocals: many of them are sunk &quot;past
+        their death&quot;, thus eliminating them completely. Others are sunk to rare paths. This enables a
+        lot of object allocation sinking and it removes a lot of pointless store instructions.
+        
+        It also has downsites. Sinking PutLocals increases register pressure because it increases the
+        live ranges of things like inlined arguments.
+        
+        This patch is a net performance win in its current form: 1% SunSpider regression, 2% OctaneV2
+        progression, 0.6% Kraken regression, 1% AsmBench progression, and 0.5% CompressionBench
+        regression. The biggest win is on Octane/raytrace, which improves by 27%.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.h:
+        * bytecode/Operands.h:
+        (JSC::Operands::dump): Deleted.
+        * bytecode/OperandsInlines.h:
+        (JSC::Traits&gt;::dump):
+        * bytecode/VirtualRegister.h:
+        (JSC::VirtualRegister::isHeader):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+        * dfg/DFGClobberSet.h:
+        (JSC::DFG::ClobberSetAdd::operator()):
+        (JSC::DFG::ClobberSetOverlaps::operator()):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        (JSC::DFG::NoOpClobberize::operator()):
+        (JSC::DFG::CheckClobberize::operator()):
+        (JSC::DFG::AbstractHeapOverlaps::operator()):
+        (JSC::DFG::ReadMethodClobberize::operator()):
+        (JSC::DFG::WriteMethodClobberize::operator()):
+        (JSC::DFG::DefMethodClobberize::operator()):
+        * dfg/DFGFlushFormat.h:
+        (JSC::DFG::merge):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::Graph):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::capturedVarsFor):
+        * dfg/DFGObjectAllocationSinkingPhase.cpp:
+        (JSC::DFG::ObjectAllocationSinkingPhase::determineMaterializationPoints):
+        (JSC::DFG::ObjectAllocationSinkingPhase::placeMaterializationPoints):
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        * dfg/DFGPreciseLocalClobberize.h: Added.
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::PreciseLocalClobberizeAdaptor):
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::read):
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::write):
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::def):
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::callIfAppropriate):
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::readTop):
+        (JSC::DFG::PreciseLocalClobberizeAdaptor::writeTop):
+        (JSC::DFG::forEachLocalReadByUnwind):
+        (JSC::DFG::preciseLocalClobberize):
+        * dfg/DFGPutLocalSinkingPhase.cpp: Added.
+        (JSC::DFG::performPutLocalSinking):
+        * dfg/DFGPutLocalSinkingPhase.h: Added.
+        * dfg/DFGSSACalculator.h:
+        (JSC::DFG::SSACalculator::computePhis):
+        * dfg/DFGValidate.cpp:
+
</ins><span class="cx"> 2014-10-03  Saam Barati  &lt;saambarati1@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Change how 32-bit JSValues check if they are a Boolean
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -453,6 +453,7 @@
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPredictionPropagationPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPromotedHeapLocation.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGPureValue.cpp&quot; /&gt;
</span><ins>+    &lt;ClCompile Include=&quot;..\dfg\DFGPutLocalSinkingPhase.cpp&quot; /&gt;
</ins><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGResurrectionForValidationPhase.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGSafepoint.cpp&quot; /&gt;
</span><span class="cx">     &lt;ClCompile Include=&quot;..\dfg\DFGSpeculativeJIT.cpp&quot; /&gt;
</span><span class="lines">@@ -1104,11 +1105,13 @@
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPhiChildren.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPlan.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPrePostNumbering.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\dfg\DFGPreciseLocalClobberize.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPredictionInjectionPhase.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPredictionPropagationPhase.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPromoteHeapAccess.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPromotedHeapLocation.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGPureValue.h&quot; /&gt;
</span><ins>+    &lt;ClInclude Include=&quot;..\dfg\DFGPutLocalSinkingPhase.h&quot; /&gt;
</ins><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGRegisterBank.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGRegisterSet.h&quot; /&gt;
</span><span class="cx">     &lt;ClInclude Include=&quot;..\dfg\DFGResurrectionForValidationPhase.h&quot; /&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -1562,6 +1562,9 @@
</span><span class="cx">                 C49FE4AA19AAC83E00F40CE9 /* generate_protocol_types_implementation.py in Resources */ = {isa = PBXBuildFile; fileRef = C49FE4A819AAC83E00F40CE9 /* generate_protocol_types_implementation.py */; };
</span><span class="cx">                 C49FE4AB19AAC86100F40CE9 /* generate_protocol_types_header.py in Headers */ = {isa = PBXBuildFile; fileRef = C49FE4A719AAC83E00F40CE9 /* generate_protocol_types_header.py */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 C49FE4AC19AAC86100F40CE9 /* generate_protocol_types_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C49FE4A819AAC83E00F40CE9 /* generate_protocol_types_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */; settings = {ATTRIBUTES = (Private, ); }; };
+                DC00039819DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DC00039619DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp */; };
+                DC00039919DBA70600023EB0 /* DFGPutLocalSinkingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039719DBA70600023EB0 /* DFGPutLocalSinkingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E124A8F60E555775003091F1 /* OpaqueJSString.cpp */; };
</span><span class="cx">                 E18E3A590DF9278C00D90B34 /* VM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E3A570DF9278C00D90B34 /* VM.cpp */; };
</span><span class="lines">@@ -3222,6 +3225,9 @@
</span><span class="cx">                 C49FE4A819AAC83E00F40CE9 /* generate_protocol_types_implementation.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = generate_protocol_types_implementation.py; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPreciseLocalClobberize.h; path = dfg/DFGPreciseLocalClobberize.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                DC00039619DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPutLocalSinkingPhase.cpp; path = dfg/DFGPutLocalSinkingPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                DC00039719DBA70600023EB0 /* DFGPutLocalSinkingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPutLocalSinkingPhase.h; path = dfg/DFGPutLocalSinkingPhase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 E124A8F50E555775003091F1 /* OpaqueJSString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpaqueJSString.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E124A8F60E555775003091F1 /* OpaqueJSString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OpaqueJSString.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 E178633F0D9BEC0000D74E75 /* InitializeThreading.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeThreading.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -4755,6 +4761,7 @@
</span><span class="cx">                                 0F2B9CDF19D0BA7D00B1D1B5 /* DFGPhiChildren.h */,
</span><span class="cx">                                 A78A9772179738B8009DF744 /* DFGPlan.cpp */,
</span><span class="cx">                                 A78A9773179738B8009DF744 /* DFGPlan.h */,
</span><ins>+                                DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */,
</ins><span class="cx">                                 0FBE0F6D16C1DB010082C5E8 /* DFGPredictionInjectionPhase.cpp */,
</span><span class="cx">                                 0FBE0F6E16C1DB010082C5E8 /* DFGPredictionInjectionPhase.h */,
</span><span class="cx">                                 0FFFC95114EF909500C72532 /* DFGPredictionPropagationPhase.cpp */,
</span><span class="lines">@@ -4766,6 +4773,8 @@
</span><span class="cx">                                 0FAA3E0819D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.h */,
</span><span class="cx">                                 0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */,
</span><span class="cx">                                 0FB1765F196B8F9E0091052A /* DFGPureValue.h */,
</span><ins>+                                DC00039619DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp */,
+                                DC00039719DBA70600023EB0 /* DFGPutLocalSinkingPhase.h */,
</ins><span class="cx">                                 86EC9DC11328DF82002B2AD7 /* DFGRegisterBank.h */,
</span><span class="cx">                                 0F666ECA1836B37E00D017F1 /* DFGResurrectionForValidationPhase.cpp */,
</span><span class="cx">                                 0F666ECB1836B37E00D017F1 /* DFGResurrectionForValidationPhase.h */,
</span><span class="lines">@@ -5586,6 +5595,7 @@
</span><span class="cx">                                 0FEA0A08170513DB00BB722C /* FTLAbbreviations.h in Headers */,
</span><span class="cx">                                 A53CE08A18BC21C300BEDF76 /* ConsoleClient.h in Headers */,
</span><span class="cx">                                 0FEA0A1D1708B00700BB722C /* FTLAbstractHeap.h in Headers */,
</span><ins>+                                DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */,
</ins><span class="cx">                                 0FEA0A1F1708B00700BB722C /* FTLAbstractHeapRepository.h in Headers */,
</span><span class="cx">                                 0F485328187DFDEC0083B687 /* FTLAvailableRecovery.h in Headers */,
</span><span class="cx">                                 0FEA0A0A170513DB00BB722C /* FTLCapabilities.h in Headers */,
</span><span class="lines">@@ -5844,6 +5854,7 @@
</span><span class="cx">                                 BC18C4280E16F5CD00B34460 /* JSStringRef.h in Headers */,
</span><span class="cx">                                 BC18C4290E16F5CD00B34460 /* JSStringRefCF.h in Headers */,
</span><span class="cx">                                 1A28D4A8177B71C80007FA3C /* JSStringRefPrivate.h in Headers */,
</span><ins>+                                DC00039919DBA70600023EB0 /* DFGPutLocalSinkingPhase.h in Headers */,
</ins><span class="cx">                                 0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */,
</span><span class="cx">                                 BC18C42A0E16F5CD00B34460 /* JSType.h in Headers */,
</span><span class="cx">                                 0F2B66FB17B6B5AB00A7AE3F /* JSTypedArrayConstructors.h in Headers */,
</span><span class="lines">@@ -6719,6 +6730,7 @@
</span><span class="cx">                                 A7D89CF517A0B8CC00773AD8 /* DFGCriticalEdgeBreakingPhase.cpp in Sources */,
</span><span class="cx">                                 0FFFC95914EF90A600C72532 /* DFGCSEPhase.cpp in Sources */,
</span><span class="cx">                                 0F2FC77216E12F710038D976 /* DFGDCEPhase.cpp in Sources */,
</span><ins>+                                DC00039819DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp in Sources */,
</ins><span class="cx">                                 0F8F2B99172F04FF007DBDA5 /* DFGDesiredIdentifiers.cpp in Sources */,
</span><span class="cx">                                 C2C0F7CD17BBFC5B00464FE4 /* DFGDesiredTransitions.cpp in Sources */,
</span><span class="cx">                                 0FE8534B1723CDA500B618F5 /* DFGDesiredWatchpoints.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeCodeBlockh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/CodeBlock.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/bytecode/CodeBlock.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -384,7 +384,7 @@
</span><span class="cx">             return 0;
</span><span class="cx">         return symbolTable()-&gt;captureEnd();
</span><span class="cx">     }
</span><del>-
</del><ins>+    
</ins><span class="cx">     bool isCaptured(VirtualRegister operand, InlineCallFrame* = 0) const;
</span><span class="cx">     
</span><span class="cx">     int framePointerOffsetToGetActivationRegisters(int machineCaptureStart);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeOperandsh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/Operands.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/Operands.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/bytecode/Operands.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -252,12 +252,8 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     void dumpInContext(PrintStream&amp; out, DumpContext* context) const;
</span><ins>+    void dump(PrintStream&amp; out) const;
</ins><span class="cx">     
</span><del>-    void dump(PrintStream&amp; out) const
-    {
-        dumpInContext(out, 0);
-    }
-    
</del><span class="cx"> private:
</span><span class="cx">     Vector&lt;T, 8&gt; m_arguments;
</span><span class="cx">     Vector&lt;T, 16&gt; m_locals;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeOperandsInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/OperandsInlines.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/OperandsInlines.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/bytecode/OperandsInlines.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -47,6 +47,22 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+template&lt;typename T, typename Traits&gt;
+void Operands&lt;T, Traits&gt;::dump(PrintStream&amp; out) const
+{
+    CommaPrinter comma(&quot; &quot;);
+    for (size_t argumentIndex = numberOfArguments(); argumentIndex--;) {
+        if (Traits::isEmptyForDump(argument(argumentIndex)))
+            continue;
+        out.print(comma, &quot;arg&quot;, argumentIndex, &quot;:&quot;, argument(argumentIndex));
+    }
+    for (size_t localIndex = 0; localIndex &lt; numberOfLocals(); ++localIndex) {
+        if (Traits::isEmptyForDump(local(localIndex)))
+            continue;
+        out.print(comma, &quot;loc&quot;, localIndex, &quot;:&quot;, local(localIndex));
+    }
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // OperandsInlines_h
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorebytecodeVirtualRegisterh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/bytecode/VirtualRegister.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -59,6 +59,7 @@
</span><span class="cx">     bool isValid() const { return (m_virtualRegister != s_invalidVirtualRegister); }
</span><span class="cx">     bool isLocal() const { return operandIsLocal(m_virtualRegister); }
</span><span class="cx">     bool isArgument() const { return operandIsArgument(m_virtualRegister); }
</span><ins>+    bool isHeader() const { return m_virtualRegister &gt;= 0 &amp;&amp; m_virtualRegister &lt; JSStack::ThisArgument; }
</ins><span class="cx">     bool isConstant() const { return m_virtualRegister &gt;= s_firstConstantRegisterIndex; }
</span><span class="cx">     int toLocal() const { ASSERT(isLocal()); return operandToLocal(m_virtualRegister); }
</span><span class="cx">     int toArgument() const { ASSERT(isArgument()); return operandToArgument(m_virtualRegister); }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -109,7 +109,7 @@
</span><span class="cx">     if (!(forNode(edge).m_type &amp; ~typeFilterFor(edge.useKind())))
</span><span class="cx">         return;
</span><span class="cx">     
</span><del>-    DFG_CRASH(m_graph, node, toCString(&quot;Edge verification error: &quot;, node, &quot;-&gt;&quot;, edge, &quot; was expected to have type &quot;, SpeculationDump(typeFilterFor(edge.useKind())), &quot; but has type &quot;, SpeculationDump(forNode(edge).m_type)).data());
</del><ins>+    DFG_CRASH(m_graph, node, toCString(&quot;Edge verification error: &quot;, node, &quot;-&gt;&quot;, edge, &quot; was expected to have type &quot;, SpeculationDump(typeFilterFor(edge.useKind())), &quot; but has type &quot;, SpeculationDump(forNode(edge).m_type), &quot; (&quot;, forNode(edge).m_type, &quot;)&quot;).data());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename AbstractStateType&gt;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGByteCodeParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -3692,12 +3692,8 @@
</span><span class="cx">         
</span><span class="cx">         if (m_inlineCallFrame-&gt;caller.inlineCallFrame)
</span><span class="cx">             m_inlineCallFrame-&gt;capturedVars = m_inlineCallFrame-&gt;caller.inlineCallFrame-&gt;capturedVars;
</span><del>-        else {
-            for (int i = byteCodeParser-&gt;m_codeBlock-&gt;m_numVars; i--;) {
-                if (byteCodeParser-&gt;m_codeBlock-&gt;isCaptured(virtualRegisterForLocal(i)))
-                    m_inlineCallFrame-&gt;capturedVars.set(i);
-            }
-        }
</del><ins>+        else
+            m_inlineCallFrame-&gt;capturedVars = byteCodeParser-&gt;m_graph.m_outermostCapturedVars;
</ins><span class="cx"> 
</span><span class="cx">         for (int i = argumentCountIncludingThis; i--;) {
</span><span class="cx">             VirtualRegister argument = virtualRegisterForArgument(i);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberSeth"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberSet.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberSet.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberSet.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(AbstractHeap heap)
</del><ins>+    void operator()(AbstractHeap heap) const
</ins><span class="cx">     {
</span><span class="cx">         m_set.add(heap);
</span><span class="cx">     }
</span><span class="lines">@@ -96,7 +96,7 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(AbstractHeap heap)
</del><ins>+    void operator()(AbstractHeap heap) const
</ins><span class="cx">     {
</span><span class="cx">         m_result |= m_set.overlaps(heap);
</span><span class="cx">     }
</span><span class="lines">@@ -105,7 +105,7 @@
</span><span class="cx">     
</span><span class="cx"> private:
</span><span class="cx">     const ClobberSet&amp; m_set;
</span><del>-    bool m_result;
</del><ins>+    mutable bool m_result;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> void addReads(Graph&amp;, Node*, ClobberSet&amp;);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>- /*
</del><ins>+/*
</ins><span class="cx">  * Copyright (C) 2013, 2014 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">@@ -37,7 +37,7 @@
</span><span class="cx"> namespace JSC { namespace DFG {
</span><span class="cx"> 
</span><span class="cx"> template&lt;typename ReadFunctor, typename WriteFunctor, typename DefFunctor&gt;
</span><del>-void clobberize(Graph&amp; graph, Node* node, ReadFunctor&amp; read, WriteFunctor&amp; write, DefFunctor&amp; def)
</del><ins>+void clobberize(Graph&amp; graph, Node* node, const ReadFunctor&amp; read, const WriteFunctor&amp; write, const DefFunctor&amp; def)
</ins><span class="cx"> {
</span><span class="cx">     // Some notes:
</span><span class="cx">     //
</span><span class="lines">@@ -897,7 +897,7 @@
</span><span class="cx"> public:
</span><span class="cx">     NoOpClobberize() { }
</span><span class="cx">     template&lt;typename... T&gt;
</span><del>-    void operator()(T...) { }
</del><ins>+    void operator()(T...) const { }
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class CheckClobberize {
</span><span class="lines">@@ -908,12 +908,12 @@
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     template&lt;typename... T&gt;
</span><del>-    void operator()(T...) { m_result = true; }
</del><ins>+    void operator()(T...) const { m_result = true; }
</ins><span class="cx">     
</span><span class="cx">     bool result() const { return m_result; }
</span><span class="cx">     
</span><span class="cx"> private:
</span><del>-    bool m_result;
</del><ins>+    mutable bool m_result;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> bool doesWrites(Graph&amp;, Node*);
</span><span class="lines">@@ -926,7 +926,7 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(AbstractHeap otherHeap)
</del><ins>+    void operator()(AbstractHeap otherHeap) const
</ins><span class="cx">     {
</span><span class="cx">         if (m_result)
</span><span class="cx">             return;
</span><span class="lines">@@ -937,7 +937,7 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     AbstractHeap m_heap;
</span><del>-    bool m_result;
</del><ins>+    mutable bool m_result;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> bool accessesOverlap(Graph&amp;, Node*, AbstractHeap);
</span><span class="lines">@@ -954,7 +954,7 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(AbstractHeap heap)
</del><ins>+    void operator()(AbstractHeap heap) const
</ins><span class="cx">     {
</span><span class="cx">         m_value.read(heap);
</span><span class="cx">     }
</span><span class="lines">@@ -970,7 +970,7 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(AbstractHeap heap)
</del><ins>+    void operator()(AbstractHeap heap) const
</ins><span class="cx">     {
</span><span class="cx">         m_value.write(heap);
</span><span class="cx">     }
</span><span class="lines">@@ -986,12 +986,12 @@
</span><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(PureValue value)
</del><ins>+    void operator()(PureValue value) const
</ins><span class="cx">     {
</span><span class="cx">         m_value.def(value);
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void operator()(HeapLocation location, Node* node)
</del><ins>+    void operator()(HeapLocation location, Node* node) const
</ins><span class="cx">     {
</span><span class="cx">         m_value.def(location, node);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFlushFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -118,6 +118,17 @@
</span><span class="cx">     return DataFormatDead;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline FlushFormat merge(FlushFormat a, FlushFormat b)
+{
+    if (a == DeadFlush)
+        return b;
+    if (b == DeadFlush)
+        return a;
+    if (a == b)
+        return a;
+    return ConflictingFlush;
+}
+
</ins><span class="cx"> } } // namespace JSC::DFG
</span><span class="cx"> 
</span><span class="cx"> namespace WTF {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -75,6 +75,11 @@
</span><span class="cx">     
</span><span class="cx">     for (unsigned i = m_mustHandleValues.size(); i--;)
</span><span class="cx">         m_mustHandleValues[i] = freezeFragile(plan.mustHandleValues[i]);
</span><ins>+    
+    for (unsigned i = m_codeBlock-&gt;m_numVars; i--;) {
+        if (m_codeBlock-&gt;isCaptured(virtualRegisterForLocal(i)))
+            m_outermostCapturedVars.set(i);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> Graph::~Graph()
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -367,6 +367,13 @@
</span><span class="cx">         return baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, m_profiledBlock);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    const BitVector&amp; capturedVarsFor(InlineCallFrame* inlineCallFrame)
+    {
+        if (!inlineCallFrame)
+            return m_outermostCapturedVars;
+        return inlineCallFrame-&gt;capturedVars;
+    }
+    
</ins><span class="cx">     bool isStrictModeFor(CodeOrigin codeOrigin)
</span><span class="cx">     {
</span><span class="cx">         if (!codeOrigin.inlineCallFrame)
</span><span class="lines">@@ -894,6 +901,7 @@
</span><span class="cx">     unsigned m_parameterSlots;
</span><span class="cx">     int m_machineCaptureStart;
</span><span class="cx">     std::unique_ptr&lt;SlowArgument[]&gt; m_slowArguments;
</span><ins>+    BitVector m_outermostCapturedVars;
</ins><span class="cx"> 
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx">     std::unordered_map&lt;int64_t, double*&gt; m_doubleConstantsMap;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMayExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -79,6 +79,8 @@
</span><span class="cx">     case PutStructureHint:
</span><span class="cx">     case PutByOffsetHint:
</span><span class="cx">     case PhantomNewObject:
</span><ins>+    case PutLocal:
+    case KillLocal:
</ins><span class="cx">         break;
</span><span class="cx">         
</span><span class="cx">     default:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGObjectAllocationSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -158,6 +158,8 @@
</span><span class="cx">             changed = false;
</span><span class="cx">             for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
</span><span class="cx">                 HashMap&lt;Node*, bool&gt; materialized = materializedAtHead[block];
</span><ins>+                if (verbose)
+                    dataLog(&quot;    Looking at block &quot;, pointerDump(block), &quot;\n&quot;);
</ins><span class="cx">                 for (Node* node : *block) {
</span><span class="cx">                     handleNode(
</span><span class="cx">                         node,
</span><span class="lines">@@ -166,8 +168,11 @@
</span><span class="cx">                         },
</span><span class="cx">                         [&amp;] (Node* escapee) {
</span><span class="cx">                             auto iter = materialized.find(escapee);
</span><del>-                            if (iter != materialized.end())
</del><ins>+                            if (iter != materialized.end()) {
+                                if (verbose)
+                                    dataLog(&quot;    &quot;, escapee, &quot; escapes at &quot;, node, &quot;\n&quot;);
</ins><span class="cx">                                 iter-&gt;value = true;
</span><ins>+                            }
</ins><span class="cx">                         });
</span><span class="cx">                 }
</span><span class="cx">                 
</span><span class="lines">@@ -271,6 +276,9 @@
</span><span class="cx">                     materialized.add(pair.key);
</span><span class="cx">             }
</span><span class="cx">             
</span><ins>+            if (verbose)
+                dataLog(&quot;Placing materialization points in &quot;, pointerDump(block), &quot; with materialization set &quot;, listDump(materialized), &quot;\n&quot;);
+            
</ins><span class="cx">             for (unsigned nodeIndex = 0; nodeIndex &lt; block-&gt;size(); ++nodeIndex) {
</span><span class="cx">                 Node* node = block-&gt;at(nodeIndex);
</span><span class="cx">                 
</span><span class="lines">@@ -278,11 +286,20 @@
</span><span class="cx">                     node,
</span><span class="cx">                     [&amp;] () { },
</span><span class="cx">                     [&amp;] (Node* escapee) {
</span><del>-                        if (!m_sinkCandidates.contains(escapee))
</del><ins>+                        if (verbose)
+                            dataLog(&quot;Seeing &quot;, escapee, &quot; escape at &quot;, node, &quot;\n&quot;);
+                        
+                        if (!m_sinkCandidates.contains(escapee)) {
+                            if (verbose)
+                                dataLog(&quot;    It's not a sink candidate.\n&quot;);
</ins><span class="cx">                             return;
</span><ins>+                        }
</ins><span class="cx">                         
</span><del>-                        if (!materialized.add(escapee).isNewEntry)
</del><ins>+                        if (!materialized.add(escapee).isNewEntry) {
+                            if (verbose)
+                                dataLog(&quot;   It's already materialized.\n&quot;);
</ins><span class="cx">                             return;
</span><ins>+                        }
</ins><span class="cx">                         
</span><span class="cx">                         createMaterialize(escapee, node);
</span><span class="cx">                     });
</span><span class="lines">@@ -432,6 +449,16 @@
</span><span class="cx">                         if (Node* materialize = mapping.get(edge.node()))
</span><span class="cx">                             edge.setNode(materialize);
</span><span class="cx">                     });
</span><ins>+                
+                // If you cause an escape, you shouldn't see the original escapee.
+                if (validationEnabled()) {
+                    handleNode(
+                        node,
+                        [&amp;] () { },
+                        [&amp;] (Node* escapee) {
+                            DFG_ASSERT(m_graph, node, !m_sinkCandidates.contains(escapee));
+                        });
+                }
</ins><span class="cx">             }
</span><span class="cx">             
</span><span class="cx">             size_t upsilonInsertionPoint = block-&gt;size() - 1;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -54,6 +54,7 @@
</span><span class="cx"> #include &quot;DFGPhantomRemovalPhase.h&quot;
</span><span class="cx"> #include &quot;DFGPredictionInjectionPhase.h&quot;
</span><span class="cx"> #include &quot;DFGPredictionPropagationPhase.h&quot;
</span><ins>+#include &quot;DFGPutLocalSinkingPhase.h&quot;
</ins><span class="cx"> #include &quot;DFGResurrectionForValidationPhase.h&quot;
</span><span class="cx"> #include &quot;DFGSSAConversionPhase.h&quot;
</span><span class="cx"> #include &quot;DFGSSALoweringPhase.h&quot;
</span><span class="lines">@@ -322,6 +323,7 @@
</span><span class="cx">         performCPSRethreading(dfg);
</span><span class="cx">         performSSAConversion(dfg);
</span><span class="cx">         performSSALowering(dfg);
</span><ins>+        performPutLocalSinking(dfg);
</ins><span class="cx">         performGlobalCSE(dfg);
</span><span class="cx">         performLivenessAnalysis(dfg);
</span><span class="cx">         performCFA(dfg);
</span><span class="lines">@@ -355,7 +357,7 @@
</span><span class="cx">         performCFA(dfg);
</span><span class="cx">         if (Options::validateFTLOSRExitLiveness())
</span><span class="cx">             performResurrectionForValidation(dfg);
</span><del>-        performDCE(dfg); // We rely on this to convert dead SetLocals into the appropriate hint, and to kill dead code that won't be recognized as dead by LLVM.
</del><ins>+        performDCE(dfg); // We rely on this to kill dead code that won't be recognized as dead by LLVM.
</ins><span class="cx">         performStackLayout(dfg);
</span><span class="cx">         performLivenessAnalysis(dfg);
</span><span class="cx">         performOSRAvailabilityAnalysis(dfg);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPreciseLocalClobberizeh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h (0 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPreciseLocalClobberize.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -0,0 +1,192 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGPreciseLocalClobberize_h
+#define DFGPreciseLocalClobberize_h
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;DFGClobberize.h&quot;
+#include &quot;DFGMayExit.h&quot;
+
+namespace JSC { namespace DFG {
+
+template&lt;typename ReadFunctor, typename WriteFunctor, typename DefFunctor&gt;
+class PreciseLocalClobberizeAdaptor {
+public:
+    PreciseLocalClobberizeAdaptor(
+        Graph&amp; graph, Node* node,
+        const ReadFunctor&amp; read, const WriteFunctor&amp; write, const DefFunctor&amp; def)
+        : m_graph(graph)
+        , m_node(node)
+        , m_read(read)
+        , m_write(write)
+        , m_def(def)
+    {
+    }
+    
+    void read(AbstractHeap heap)
+    {
+        if (heap.kind() == Variables) {
+            if (heap.payload().isTop()) {
+                readTop();
+                return;
+            }
+            
+            callIfAppropriate(m_read, VirtualRegister(heap.payload().value()));
+            return;
+        }
+        
+        if (heap.overlaps(Variables)) {
+            readTop();
+            return;
+        }
+    }
+    
+    void write(AbstractHeap heap)
+    {
+        if (heap.kind() == Variables) {
+            if (heap.payload().isTop()) {
+                writeTop();
+                return;
+            }
+            
+            callIfAppropriate(m_write, VirtualRegister(heap.payload().value()));
+            return;
+        }
+        
+        if (heap.overlaps(Variables)) {
+            writeTop();
+            return;
+        }
+    }
+    
+    void def(PureValue)
+    {
+        // PureValue defs never have anything to do with locals, so ignore this.
+    }
+    
+    void def(HeapLocation location, Node* node)
+    {
+        if (location.kind() != VariableLoc)
+            return;
+        
+        RELEASE_ASSERT(location.heap().kind() == Variables);
+        
+        m_def(VirtualRegister(location.heap().payload().value()), node);
+    }
+    
+private:
+    template&lt;typename Functor&gt;
+    void callIfAppropriate(const Functor&amp; functor, VirtualRegister operand)
+    {
+        if (operand.isLocal() &amp;&amp; static_cast&lt;unsigned&gt;(operand.toLocal()) &gt;= m_graph.block(0)-&gt;variablesAtHead.numberOfLocals())
+            return;
+        
+        if (operand.isArgument() &amp;&amp; !operand.isHeader() &amp;&amp; static_cast&lt;unsigned&gt;(operand.toArgument()) &gt;= m_graph.block(0)-&gt;variablesAtHead.numberOfArguments())
+            return;
+        
+        functor(operand);
+    }
+    
+    void readTop()
+    {
+        // All of the outermost arguments, except this, are definitely read.
+        for (unsigned i = m_graph.m_codeBlock-&gt;numParameters(); i-- &gt; 1;)
+            m_read(virtualRegisterForArgument(i));
+        
+        // The stack header is read.
+        for (unsigned i = 0; i &lt; JSStack::ThisArgument; ++i)
+            m_read(VirtualRegister(i));
+        
+        // Read all of the captured variables.
+        const BitVector&amp; capturedVars =
+            m_graph.capturedVarsFor(m_node-&gt;origin.semantic.inlineCallFrame);
+        for (unsigned i : capturedVars.setBits())
+            m_read(virtualRegisterForLocal(i));
+        
+        // Read all of the inline arguments and call frame headers that we didn't already capture.
+        for (InlineCallFrame* inlineCallFrame = m_node-&gt;origin.semantic.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame-&gt;caller.inlineCallFrame) {
+            for (unsigned i = inlineCallFrame-&gt;arguments.size(); i-- &gt; 1;)
+                m_read(VirtualRegister(inlineCallFrame-&gt;stackOffset + virtualRegisterForArgument(i).offset()));
+            if (inlineCallFrame-&gt;isClosureCall) {
+                m_read(VirtualRegister(inlineCallFrame-&gt;stackOffset + JSStack::ScopeChain));
+                m_read(VirtualRegister(inlineCallFrame-&gt;stackOffset + JSStack::Callee));
+            }
+        }
+    }
+    
+    void writeTop()
+    {
+        if (m_graph.m_codeBlock-&gt;usesArguments()) {
+            for (unsigned i = m_graph.m_codeBlock-&gt;numParameters(); i-- &gt; 1;)
+                m_write(virtualRegisterForArgument(i));
+        }
+
+        const BitVector&amp; capturedVars =
+            m_graph.capturedVarsFor(m_node-&gt;origin.semantic.inlineCallFrame);
+        for (unsigned i : capturedVars.setBits())
+            m_write(virtualRegisterForLocal(i));
+    }
+    
+    Graph&amp; m_graph;
+    Node* m_node;
+    const ReadFunctor&amp; m_read;
+    const WriteFunctor&amp; m_write;
+    const DefFunctor&amp; m_def;
+};
+
+template&lt;typename ReadFunctor&gt;
+void forEachLocalReadByUnwind(Graph&amp; graph, CodeOrigin codeOrigin, const ReadFunctor&amp; read)
+{
+    if (graph.uncheckedActivationRegister().isValid())
+        read(graph.activationRegister());
+    if (graph.m_codeBlock-&gt;usesArguments())
+        read(unmodifiedArgumentsRegister(graph.argumentsRegisterFor(nullptr)));
+    
+    for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame-&gt;caller.inlineCallFrame) {
+        if (inlineCallFrame-&gt;executable-&gt;usesArguments())
+            read(unmodifiedArgumentsRegister(graph.argumentsRegisterFor(inlineCallFrame)));
+    }
+}
+
+template&lt;typename ReadFunctor, typename WriteFunctor, typename DefFunctor&gt;
+void preciseLocalClobberize(
+    Graph&amp; graph, Node* node,
+    const ReadFunctor&amp; read, const WriteFunctor&amp; write, const DefFunctor&amp; def)
+{
+    PreciseLocalClobberizeAdaptor&lt;ReadFunctor, WriteFunctor, DefFunctor&gt;
+        adaptor(graph, node, read, write, def);
+    clobberize(graph, node, adaptor);
+    if (mayExit(graph, node))
+        forEachLocalReadByUnwind(graph, node-&gt;origin.forExit, read);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGPreciseLocalClobberize_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhasecpp"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp (0 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -0,0 +1,517 @@
</span><ins>+/*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;DFGPutLocalSinkingPhase.h&quot;
+
+#if ENABLE(DFG_JIT)
+
+#include &quot;DFGBlockMapInlines.h&quot;
+#include &quot;DFGGraph.h&quot;
+#include &quot;DFGInsertionSet.h&quot;
+#include &quot;DFGPhase.h&quot;
+#include &quot;DFGPreciseLocalClobberize.h&quot;
+#include &quot;DFGSSACalculator.h&quot;
+#include &quot;DFGValidate.h&quot;
+#include &quot;JSCInlines.h&quot;
+#include &quot;OperandsInlines.h&quot;
+
+namespace JSC { namespace DFG {
+
+namespace {
+
+bool verbose = false;
+
+class VariableDeferral {
+public:
+    VariableDeferral(VariableAccessData* variable = nullptr)
+        : m_variable(variable)
+    {
+    }
+    
+    static VariableDeferral conflict()
+    {
+        return VariableDeferral(conflictMarker());
+    }
+    
+    bool operator!() const { return !m_variable; }
+    
+    bool hasVariable() const { return !!*this &amp;&amp; !isConflict(); }
+    
+    VariableAccessData* variable() const
+    {
+        ASSERT(hasVariable());
+        return m_variable;
+    }
+    
+    bool isConflict() const
+    {
+        return m_variable == conflictMarker();
+    }
+    
+    VariableDeferral merge(VariableDeferral other) const
+    {
+        if (*this == other || !other)
+            return *this;
+        if (!*this)
+            return other;
+        return conflict();
+    }
+    
+    bool operator==(VariableDeferral other) const
+    {
+        return m_variable == other.m_variable;
+    }
+    
+    void dump(PrintStream&amp; out) const
+    {
+        if (!*this)
+            out.print(&quot;-&quot;);
+        else if (isConflict())
+            out.print(&quot;Conflict&quot;);
+        else
+            out.print(RawPointer(m_variable));
+    }
+    
+    void dumpInContext(PrintStream&amp; out, DumpContext*) const
+    {
+        dump(out);
+    }
+    
+private:
+    static VariableAccessData* conflictMarker()
+    {
+        return bitwise_cast&lt;VariableAccessData*&gt;(static_cast&lt;intptr_t&gt;(1));
+    }
+    
+    VariableAccessData* m_variable;
+};
+
+class PutLocalSinkingPhase : public Phase {
+public:
+    PutLocalSinkingPhase(Graph&amp; graph)
+        : Phase(graph, &quot;PutLocal sinking&quot;)
+    {
+    }
+    
+    bool run()
+    {
+        // FIXME: One of the problems of this approach is that it will create a duplicate Phi graph
+        // for sunken PutLocals in the presence of interesting control flow merges, and where the
+        // value being PutLocal'd is also otherwise live in the DFG code. We could work around this
+        // by doing the sinking over CPS, or maybe just by doing really smart hoisting. It's also
+        // possible that the duplicate Phi graph can be deduplicated by LLVM. It would be best if we
+        // could observe that there is already a Phi graph in place that does what we want. In
+        // principle if we have a request to place a Phi at a particular place, we could just check
+        // if there is already a Phi that does what we want. Because PutLocalSinkingPhase runs just
+        // after SSA conversion, we have almost a guarantee that the Phi graph we produce here would
+        // be trivially redundant to the one we already have.
+        
+        if (verbose) {
+            dataLog(&quot;Graph before PutLocal sinking:\n&quot;);
+            m_graph.dump();
+        }
+        
+        SSACalculator ssaCalculator(m_graph);
+        InsertionSet insertionSet(m_graph);
+        
+        // First figure out where various locals are live.
+        BlockMap&lt;Operands&lt;bool&gt;&gt; liveAtHead(m_graph);
+        BlockMap&lt;Operands&lt;bool&gt;&gt; liveAtTail(m_graph);
+        
+        for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+            liveAtHead[block] = Operands&lt;bool&gt;(OperandsLike, block-&gt;variablesAtHead);
+            liveAtTail[block] = Operands&lt;bool&gt;(OperandsLike, block-&gt;variablesAtHead);
+            
+            liveAtHead[block].fill(false);
+            liveAtTail[block].fill(false);
+        }
+        
+        bool changed;
+        do {
+            changed = false;
+            
+            for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
+                BasicBlock* block = m_graph.block(blockIndex);
+                if (!block)
+                    continue;
+                
+                Operands&lt;bool&gt; live = liveAtTail[block];
+                for (unsigned nodeIndex = block-&gt;size(); nodeIndex--;) {
+                    Node* node = block-&gt;at(nodeIndex);
+                    if (verbose)
+                        dataLog(&quot;Live at &quot;, node, &quot;: &quot;, live, &quot;\n&quot;);
+                    
+                    auto escapeHandler = [&amp;] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
+                        if (verbose)
+                            dataLog(&quot;    r&quot;, operand, &quot; is live at &quot;, node, &quot;\n&quot;);
+                        live.operand(operand) = true;
+                    };
+                    
+                    preciseLocalClobberize(
+                        m_graph, node, escapeHandler, escapeHandler,
+                        [&amp;] (VirtualRegister operand, Node* source) {
+                            if (source == node) {
+                                // This is a load. Ignore it.
+                                return;
+                            }
+                            
+                            RELEASE_ASSERT(node-&gt;op() == PutLocal);
+                            live.operand(operand) = false;
+                        });
+                }
+                
+                if (live == liveAtHead[block])
+                    continue;
+                
+                liveAtHead[block] = live;
+                changed = true;
+                
+                for (BasicBlock* predecessor : block-&gt;predecessors) {
+                    for (size_t i = live.size(); i--;)
+                        liveAtTail[predecessor][i] |= live[i];
+                }
+            }
+            
+        } while (changed);
+        
+        // All of the arguments should be live at head of root. Note that we may find that some
+        // locals are live at head of root. This seems wrong but isn't. This will happen for example
+        // if the function accesses closure variable #42 for some other function and we either don't
+        // have variable #42 at all or we haven't set it at root, for whatever reason. Basically this
+        // arises since our aliasing for closure variables is conservatively based on variable number
+        // and ignores the owning symbol table. We should probably fix this eventually and make our
+        // aliasing more precise.
+        //
+        // For our purposes here, the imprecision in the aliasing is harmless. It just means that we
+        // may not do as much Phi pruning as we wanted.
+        for (size_t i = liveAtHead.atIndex(0).numberOfArguments(); i--;)
+            DFG_ASSERT(m_graph, nullptr, liveAtHead.atIndex(0).argument(i));
+        
+        // Next identify where we would want to sink PutLocals to. We say that there is a deferred
+        // flush if we had a PutLocal with a given VariableAccessData* but it hasn't been
+        // materialized yet.
+        BlockMap&lt;Operands&lt;VariableDeferral&gt;&gt; deferredAtHead(m_graph);
+        BlockMap&lt;Operands&lt;VariableDeferral&gt;&gt; deferredAtTail(m_graph);
+        
+        for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+            deferredAtHead[block] =
+                Operands&lt;VariableDeferral&gt;(OperandsLike, block-&gt;variablesAtHead);
+            deferredAtTail[block] =
+                Operands&lt;VariableDeferral&gt;(OperandsLike, block-&gt;variablesAtHead);
+        }
+        
+        deferredAtHead.atIndex(0).fill(VariableDeferral::conflict());
+        
+        do {
+            changed = false;
+            
+            for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+                Operands&lt;VariableDeferral&gt; deferred = deferredAtHead[block];
+                
+                for (Node* node : *block) {
+                    if (verbose)
+                        dataLog(&quot;Deferred at &quot;, node, &quot;:&quot;, deferred, &quot;\n&quot;);
+                    
+                    if (node-&gt;op() == KillLocal) {
+                        deferred.operand(node-&gt;unlinkedLocal()) = VariableDeferral::conflict();
+                        continue;
+                    }
+                    
+                    auto escapeHandler = [&amp;] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
+                        // We will materialize just before any reads.
+                        deferred.operand(operand) = VariableDeferral();
+                    };
+                    
+                    preciseLocalClobberize(
+                        m_graph, node, escapeHandler, escapeHandler,
+                        [&amp;] (VirtualRegister operand, Node* source) {
+                            if (source == node) {
+                                // This is a load. Ignore it.
+                                return;
+                            }
+                            
+                            deferred.operand(operand) = VariableDeferral(node-&gt;variableAccessData());
+                        });
+                }
+                
+                if (deferred == deferredAtTail[block])
+                    continue;
+                
+                deferredAtTail[block] = deferred;
+                changed = true;
+                
+                for (BasicBlock* successor : block-&gt;successors()) {
+                    for (size_t i = deferred.size(); i--;) {
+                        if (verbose)
+                            dataLog(&quot;Considering r&quot;, deferred.operandForIndex(i), &quot; at &quot;, pointerDump(block), &quot;-&gt;&quot;, pointerDump(successor), &quot;: &quot;, deferred[i], &quot; and &quot;, deferredAtHead[successor][i], &quot; merges to &quot;);
+
+                        deferredAtHead[successor][i] =
+                            deferredAtHead[successor][i].merge(deferred[i]);
+                        
+                        if (verbose)
+                            dataLog(deferredAtHead[successor][i], &quot;\n&quot;);
+                    }
+                }
+            }
+            
+        } while (changed);
+        
+        // We wish to insert PutLocals at all of the materialization points, which are defined
+        // implicitly as the places where we set deferred to Dead while it was previously not Dead.
+        // To do this, we may need to build some Phi functions to handle stuff like this:
+        //
+        // Before:
+        //
+        //     if (p)
+        //         PutLocal(r42, @x)
+        //     else
+        //         PutLocal(r42, @y)
+        //
+        // After:
+        //
+        //     if (p)
+        //         Upsilon(@x, ^z)
+        //     else
+        //         Upsilon(@y, ^z)
+        //     z: Phi()
+        //     PutLocal(r42, @z)
+        //
+        // This means that we have an SSACalculator::Variable for each local, and a Def is any
+        // PutLocal in the original program. The original PutLocals will simply vanish.
+        
+        Operands&lt;SSACalculator::Variable*&gt; operandToVariable(
+            OperandsLike, m_graph.block(0)-&gt;variablesAtHead);
+        Vector&lt;VirtualRegister&gt; indexToOperand;
+        for (size_t i = m_graph.block(0)-&gt;variablesAtHead.size(); i--;) {
+            VirtualRegister operand(m_graph.block(0)-&gt;variablesAtHead.operandForIndex(i));
+            
+            SSACalculator::Variable* variable = ssaCalculator.newVariable();
+            operandToVariable.operand(operand) = variable;
+            ASSERT(indexToOperand.size() == variable-&gt;index());
+            indexToOperand.append(operand);
+        }
+        
+        HashSet&lt;Node*&gt; putLocalsToSink;
+        
+        for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+            for (Node* node : *block) {
+                switch (node-&gt;op()) {
+                case PutLocal:
+                    putLocalsToSink.add(node);
+                    ssaCalculator.newDef(
+                        operandToVariable.operand(node-&gt;local()), block, node-&gt;child1().node());
+                    break;
+                case GetArgument:
+                    ssaCalculator.newDef(
+                        operandToVariable.operand(node-&gt;local()), block, node);
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+        
+        ssaCalculator.computePhis(
+            [&amp;] (SSACalculator::Variable* variable, BasicBlock* block) -&gt; Node* {
+                VirtualRegister operand = indexToOperand[variable-&gt;index()];
+                
+                if (!liveAtHead[block].operand(operand))
+                    return nullptr;
+                
+                VariableDeferral variableDeferral = deferredAtHead[block].operand(operand);
+
+                // We could have an invalid deferral because liveness is imprecise.
+                if (!variableDeferral.hasVariable())
+                    return nullptr;
+
+                if (verbose)
+                    dataLog(&quot;Adding Phi for r&quot;, operand, &quot; at &quot;, pointerDump(block), &quot;\n&quot;);
+                
+                Node* phiNode = m_graph.addNode(SpecHeapTop, Phi, NodeOrigin());
+                DFG_ASSERT(m_graph, nullptr, variableDeferral.hasVariable());
+                FlushFormat format = variableDeferral.variable()-&gt;flushFormat();
+                phiNode-&gt;mergeFlags(resultFor(format));
+                return phiNode;
+            });
+        
+        Operands&lt;Node*&gt; mapping(OperandsLike, m_graph.block(0)-&gt;variablesAtHead);
+        Operands&lt;VariableDeferral&gt; deferred;
+        for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+            mapping.fill(nullptr);
+            
+            for (size_t i = mapping.size(); i--;) {
+                VirtualRegister operand(mapping.operandForIndex(i));
+                
+                SSACalculator::Variable* variable = operandToVariable.operand(operand);
+                SSACalculator::Def* def = ssaCalculator.reachingDefAtHead(block, variable);
+                if (!def)
+                    continue;
+                
+                mapping.operand(operand) = def-&gt;value();
+            }
+            
+            if (verbose)
+                dataLog(&quot;Mapping at top of &quot;, pointerDump(block), &quot;: &quot;, mapping, &quot;\n&quot;);
+            
+            for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(block)) {
+                VirtualRegister operand = indexToOperand[phiDef-&gt;variable()-&gt;index()];
+                
+                insertionSet.insert(0, phiDef-&gt;value());
+                
+                if (verbose)
+                    dataLog(&quot;   Mapping r&quot;, operand, &quot; to &quot;, phiDef-&gt;value(), &quot;\n&quot;);
+                mapping.operand(operand) = phiDef-&gt;value();
+            }
+            
+            deferred = deferredAtHead[block];
+            for (unsigned nodeIndex = 0; nodeIndex &lt; block-&gt;size(); ++nodeIndex) {
+                Node* node = block-&gt;at(nodeIndex);
+                if (verbose)
+                    dataLog(&quot;Deferred at &quot;, node, &quot;:&quot;, deferred, &quot;\n&quot;);
+                
+                switch (node-&gt;op()) {
+                case PutLocal: {
+                    VariableAccessData* variable = node-&gt;variableAccessData();
+                    VirtualRegister operand = variable-&gt;local();
+                    deferred.operand(operand) = VariableDeferral(variable);
+                    if (verbose)
+                        dataLog(&quot;   Mapping r&quot;, operand, &quot; to &quot;, node-&gt;child1().node(), &quot; at &quot;, node, &quot;\n&quot;);
+                    mapping.operand(operand) = node-&gt;child1().node();
+                    break;
+                }
+                    
+                case GetArgument: {
+                    VariableAccessData* variable = node-&gt;variableAccessData();
+                    VirtualRegister operand = variable-&gt;local();
+                    mapping.operand(operand) = node;
+                    break;
+                }
+                    
+                case KillLocal: {
+                    deferred.operand(node-&gt;unlinkedLocal()) = VariableDeferral();
+                    break;
+                }
+                
+                default: {
+                    auto escapeHandler = [&amp;] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
+                    
+                        VariableDeferral variableDeferral = deferred.operand(operand);
+                        if (!variableDeferral.hasVariable())
+                            return;
+                    
+                        // Gotta insert a PutLocal.
+                        if (verbose)
+                            dataLog(&quot;Inserting a PutLocal for r&quot;, operand, &quot; at &quot;, node, &quot;\n&quot;);
+
+                        Node* incoming = mapping.operand(operand);
+                        DFG_ASSERT(m_graph, node, incoming);
+                    
+                        insertionSet.insertNode(
+                            nodeIndex, SpecNone, PutLocal, node-&gt;origin,
+                            OpInfo(variableDeferral.variable()),
+                            Edge(incoming, useKindFor(variableDeferral.variable()-&gt;flushFormat())));
+                    
+                        deferred.operand(operand) = nullptr;
+                    };
+                
+                    preciseLocalClobberize(
+                        m_graph, node, escapeHandler, escapeHandler,
+                        [&amp;] (VirtualRegister, Node*) { });
+                    break;
+                } }
+            }
+            
+            size_t upsilonInsertionPoint = block-&gt;size() - 1;
+            NodeOrigin upsilonOrigin = block-&gt;last()-&gt;origin;
+            for (BasicBlock* successorBlock : block-&gt;successors()) {
+                for (SSACalculator::Def* phiDef : ssaCalculator.phisForBlock(successorBlock)) {
+                    Node* phiNode = phiDef-&gt;value();
+                    SSACalculator::Variable* variable = phiDef-&gt;variable();
+                    VirtualRegister operand = indexToOperand[variable-&gt;index()];
+                    if (verbose)
+                        dataLog(&quot;Creating Upsilon for r&quot;, operand, &quot; at &quot;, pointerDump(block), &quot;-&gt;&quot;, pointerDump(successorBlock), &quot;\n&quot;);
+                    VariableDeferral variableDeferral =
+                        deferredAtHead[successorBlock].operand(operand);
+                    DFG_ASSERT(m_graph, nullptr, variableDeferral.hasVariable());
+                    FlushFormat format = variableDeferral.variable()-&gt;flushFormat();
+                    UseKind useKind = useKindFor(format);
+                    Node* incoming = mapping.operand(operand);
+                    DFG_ASSERT(m_graph, nullptr, incoming);
+                    
+                    insertionSet.insertNode(
+                        upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin,
+                        OpInfo(phiNode), Edge(incoming, useKind));
+                }
+            }
+            
+            insertionSet.execute(block);
+        }
+        
+        // Finally eliminate the sunken PutLocals by turning them into Phantoms. This keeps whatever
+        // type check they were doing. Also prepend KillLocals to them to ensure that we know that
+        // the relevant value was *not* stored to the stack.
+        for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+            for (unsigned nodeIndex = 0; nodeIndex &lt; block-&gt;size(); ++nodeIndex) {
+                Node* node = block-&gt;at(nodeIndex);
+                
+                if (!putLocalsToSink.contains(node))
+                    continue;
+                
+                insertionSet.insertNode(
+                    nodeIndex, SpecNone, KillLocal, node-&gt;origin, OpInfo(node-&gt;local().offset()));
+                node-&gt;convertToPhantom();
+            }
+            
+            insertionSet.execute(block);
+        }
+        
+        if (verbose) {
+            dataLog(&quot;Graph after PutLocal sinking:\n&quot;);
+            m_graph.dump();
+        }
+        
+        return true;
+    }
+};
+
+} // anonymous namespace
+    
+bool performPutLocalSinking(Graph&amp; graph)
+{
+    SamplingRegion samplingRegion(&quot;DFG PutLocal Sinking Phase&quot;);
+    return runPhase&lt;PutLocalSinkingPhase&gt;(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhaseh"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h (0 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+ /*
+ * Copyright (C) 2014 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef DFGPutLocalSinkingPhase_h
+#define DFGPutLocalSinkingPhase_h
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Sinks PutLocals to the absolute latest point where they can possibly happen, which is usually
+// side-effects that may observe them. This eliminates PutLocals if it sinks them past the point of
+// their deaths.
+
+bool performPutLocalSinking(Graph&amp;);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGPutLocalSinkingPhase_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSSACalculatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSSACalculator.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSSACalculator.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGSSACalculator.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -174,7 +174,7 @@
</span><span class="cx">     // nonLocalReachingDef() will find it later. Note that it is generally always sound to not
</span><span class="cx">     // prune any Phis (that is, to always have the functor insert a Phi and never return nullptr).
</span><span class="cx">     template&lt;typename PhiInsertionFunctor&gt;
</span><del>-    void computePhis(PhiInsertionFunctor functor)
</del><ins>+    void computePhis(const PhiInsertionFunctor&amp; functor)
</ins><span class="cx">     {
</span><span class="cx">         DFG_ASSERT(m_graph, nullptr, m_graph.m_dominators.isValid());
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx">     } while (0)
</span><span class="cx"> 
</span><span class="cx">     #define notSet (static_cast&lt;size_t&gt;(-1))
</span><del>-
</del><ins>+        
</ins><span class="cx">     void validate()
</span><span class="cx">     {
</span><span class="cx">         // NB. This code is not written for performance, since it is not intended to run
</span></span></pre></div>
<a id="trunkSourceWTFChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/ChangeLog (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/ChangeLog        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/WTF/ChangeLog        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2014-09-28  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        FTL should sink PutLocals
+        https://bugs.webkit.org/show_bug.cgi?id=137168
+
+        Reviewed by Oliver Hunt.
+        
+        Make the set bits of a BitVector iterable.
+
+        * wtf/BitVector.h:
+        (WTF::BitVector::SetBitsIterable::SetBitsIterable):
+        (WTF::BitVector::SetBitsIterable::iterator::iterator):
+        (WTF::BitVector::SetBitsIterable::iterator::operator*):
+        (WTF::BitVector::SetBitsIterable::iterator::operator++):
+        (WTF::BitVector::SetBitsIterable::iterator::operator==):
+        (WTF::BitVector::SetBitsIterable::iterator::operator!=):
+        (WTF::BitVector::SetBitsIterable::begin):
+        (WTF::BitVector::SetBitsIterable::end):
+        (WTF::BitVector::setBits):
+
</ins><span class="cx"> 2014-10-03  Myles C. Maxfield  &lt;mmaxfield@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Support modern for loops over StringViews
</span></span></pre></div>
<a id="trunkSourceWTFwtfBitVectorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WTF/wtf/BitVector.h (174274 => 174275)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WTF/wtf/BitVector.h        2014-10-03 18:38:40 UTC (rev 174274)
+++ trunk/Source/WTF/wtf/BitVector.h        2014-10-03 19:38:06 UTC (rev 174275)
</span><span class="lines">@@ -269,6 +269,58 @@
</span><span class="cx">         return IntHash&lt;uintptr_t&gt;::hash(value);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    class SetBitsIterable {
+    public:
+        SetBitsIterable(const BitVector&amp; bitVector)
+            : m_bitVector(bitVector)
+        {
+        }
+        
+        class iterator {
+        public:
+            iterator()
+                : m_bitVector(nullptr)
+                , m_index(0)
+            {
+            }
+            
+            iterator(const BitVector&amp; bitVector, size_t index)
+                : m_bitVector(&amp;bitVector)
+                , m_index(index)
+            {
+            }
+            
+            size_t operator*() const { return m_index; }
+            
+            iterator&amp; operator++()
+            {
+                m_index = m_bitVector-&gt;findBit(m_index + 1, true);
+                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:
+            const BitVector* m_bitVector;
+            size_t m_index;
+        };
+        
+        iterator begin() const { return iterator(m_bitVector, m_bitVector.findBit(0, true)); }
+        iterator end() const { return iterator(m_bitVector, m_bitVector.size()); }
+        
+    private:
+        const BitVector&amp; m_bitVector;
+    };
+    
+    SetBitsIterable setBits() const { return SetBitsIterable(*this); }
+    
</ins><span class="cx"> private:
</span><span class="cx">     static unsigned bitsInPointer()
</span><span class="cx">     {
</span></span></pre>
</div>
</div>

</body>
</html>