<!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>[180691] trunk/Source/JavaScriptCore</title>
</head>
<body>

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

<h3>Log Message</h3>
<pre>DFG SSA stack accesses shouldn't speak of VariableAccessDatas
https://bugs.webkit.org/show_bug.cgi?id=142036

Reviewed by Michael Saboff.
        
VariableAccessData is a useful thing in LoadStore and ThreadedCPS, but it's purely harmful in
SSA because you can't cook up new VariableAccessDatas. So, if you know that you want to load
or store to the stack, and you know what format to use as well as the location, then prior to
this patch you couldn't do it unless you found some existing VariableAccessData that matched
your requirements. That can be a hard task.
        
It's better if SSA doesn't speak of VariableAccessDatas but instead just has stack accesses
that speak of the things that a stack access needs: local, machineLocal, and format. This
patch changes the SSA way of accessing the stack to do just that.
        
Also add more IR validation.

* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGConstantFoldingPhase.cpp:
(JSC::DFG::ConstantFoldingPhase::foldConstants):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGFlushFormat.h:
(JSC::DFG::isConcrete):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
* dfg/DFGMayExit.cpp:
(JSC::DFG::mayExit):
* dfg/DFGNode.cpp:
(JSC::DFG::Node::hasVariableAccessData):
* dfg/DFGNode.h:
(JSC::DFG::StackAccessData::StackAccessData):
(JSC::DFG::StackAccessData::flushedAt):
(JSC::DFG::Node::convertToPutStack):
(JSC::DFG::Node::convertToGetStack):
(JSC::DFG::Node::hasUnlinkedLocal):
(JSC::DFG::Node::hasStackAccessData):
(JSC::DFG::Node::stackAccessData):
(JSC::DFG::Node::willHaveCodeGenOrOSR):
* dfg/DFGNodeType.h:
* dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
(JSC::DFG::LocalOSRAvailabilityCalculator::executeNode):
* dfg/DFGPlan.cpp:
(JSC::DFG::Plan::compileInThreadImpl):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGPutLocalSinkingPhase.cpp: Removed.
* dfg/DFGPutLocalSinkingPhase.h: Removed.
* dfg/DFGPutStackSinkingPhase.cpp: Copied from Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp.
(JSC::DFG::performPutStackSinking):
(JSC::DFG::performPutLocalSinking): Deleted.
* dfg/DFGPutStackSinkingPhase.h: Copied from Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h.
* dfg/DFGSSAConversionPhase.cpp:
(JSC::DFG::SSAConversionPhase::run):
* dfg/DFGSafeToExecute.h:
(JSC::DFG::safeToExecute):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGStackLayoutPhase.cpp:
(JSC::DFG::StackLayoutPhase::run):
* dfg/DFGValidate.cpp:
(JSC::DFG::Validate::validate):
(JSC::DFG::Validate::validateCPS):
(JSC::DFG::Validate::validateSSA):
* dfg/DFGVirtualRegisterAllocationPhase.cpp:
(JSC::DFG::VirtualRegisterAllocationPhase::run):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::lower):
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetStack):
(JSC::FTL::LowerDFGToLLVM::compilePutStack):
(JSC::FTL::LowerDFGToLLVM::compileGetLocal): Deleted.
(JSC::FTL::LowerDFGToLLVM::compilePutLocal): Deleted.
* ftl/FTLOSRExit.h:
* tests/stress/many-sunken-locals.js: Added. This failure mode was caught by some miscellaneous test, so I figured I should write an explicit test for it.
(foo):
(bar):
(baz):
(fuzz):
(buzz):</pre>

<h3>Modified Paths</h3>
<ul>
<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="#trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh">trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGClobberizeh">trunk/Source/JavaScriptCore/dfg/DFGClobberize.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGDoesGCcpp">trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFixupPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp</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="#trunkSourceJavaScriptCoredfgDFGNodecpp">trunk/Source/JavaScriptCore/dfg/DFGNode.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeh">trunk/Source/JavaScriptCore/dfg/DFGNode.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodeTypeh">trunk/Source/JavaScriptCore/dfg/DFGNodeType.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGOSRAvailabilityAnalysisPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPlancpp">trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSafeToExecuteh">trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGStackLayoutPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGValidatecpp">trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGVirtualRegisterAllocationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLOSRExith">trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhaseh">trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.h</a></li>
<li><a href="#trunkSourceJavaScriptCoretestsstressmanysunkenlocalsjs">trunk/Source/JavaScriptCore/tests/stress/many-sunken-locals.js</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<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="trunkSourceJavaScriptCoreCMakeListstxt"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/CMakeLists.txt (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/CMakeLists.txt        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/CMakeLists.txt        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -206,7 +206,7 @@
</span><span class="cx">     dfg/DFGPredictionPropagationPhase.cpp
</span><span class="cx">     dfg/DFGPromotedHeapLocation.cpp
</span><span class="cx">     dfg/DFGPureValue.cpp
</span><del>-    dfg/DFGPutLocalSinkingPhase.cpp
</del><ins>+    dfg/DFGPutStackSinkingPhase.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 (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -1,3 +1,99 @@
</span><ins>+2015-02-25  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG SSA stack accesses shouldn't speak of VariableAccessDatas
+        https://bugs.webkit.org/show_bug.cgi?id=142036
+
+        Reviewed by Michael Saboff.
+        
+        VariableAccessData is a useful thing in LoadStore and ThreadedCPS, but it's purely harmful in
+        SSA because you can't cook up new VariableAccessDatas. So, if you know that you want to load
+        or store to the stack, and you know what format to use as well as the location, then prior to
+        this patch you couldn't do it unless you found some existing VariableAccessData that matched
+        your requirements. That can be a hard task.
+        
+        It's better if SSA doesn't speak of VariableAccessDatas but instead just has stack accesses
+        that speak of the things that a stack access needs: local, machineLocal, and format. This
+        patch changes the SSA way of accessing the stack to do just that.
+        
+        Also add more IR validation.
+
+        * CMakeLists.txt:
+        * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGConstantFoldingPhase.cpp:
+        (JSC::DFG::ConstantFoldingPhase::foldConstants):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGFlushFormat.h:
+        (JSC::DFG::isConcrete):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGGraph.h:
+        * dfg/DFGMayExit.cpp:
+        (JSC::DFG::mayExit):
+        * dfg/DFGNode.cpp:
+        (JSC::DFG::Node::hasVariableAccessData):
+        * dfg/DFGNode.h:
+        (JSC::DFG::StackAccessData::StackAccessData):
+        (JSC::DFG::StackAccessData::flushedAt):
+        (JSC::DFG::Node::convertToPutStack):
+        (JSC::DFG::Node::convertToGetStack):
+        (JSC::DFG::Node::hasUnlinkedLocal):
+        (JSC::DFG::Node::hasStackAccessData):
+        (JSC::DFG::Node::stackAccessData):
+        (JSC::DFG::Node::willHaveCodeGenOrOSR):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
+        (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode):
+        * dfg/DFGPlan.cpp:
+        (JSC::DFG::Plan::compileInThreadImpl):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGPutLocalSinkingPhase.cpp: Removed.
+        * dfg/DFGPutLocalSinkingPhase.h: Removed.
+        * dfg/DFGPutStackSinkingPhase.cpp: Copied from Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp.
+        (JSC::DFG::performPutStackSinking):
+        (JSC::DFG::performPutLocalSinking): Deleted.
+        * dfg/DFGPutStackSinkingPhase.h: Copied from Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h.
+        * dfg/DFGSSAConversionPhase.cpp:
+        (JSC::DFG::SSAConversionPhase::run):
+        * dfg/DFGSafeToExecute.h:
+        (JSC::DFG::safeToExecute):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGStackLayoutPhase.cpp:
+        (JSC::DFG::StackLayoutPhase::run):
+        * dfg/DFGValidate.cpp:
+        (JSC::DFG::Validate::validate):
+        (JSC::DFG::Validate::validateCPS):
+        (JSC::DFG::Validate::validateSSA):
+        * dfg/DFGVirtualRegisterAllocationPhase.cpp:
+        (JSC::DFG::VirtualRegisterAllocationPhase::run):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::lower):
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileGetStack):
+        (JSC::FTL::LowerDFGToLLVM::compilePutStack):
+        (JSC::FTL::LowerDFGToLLVM::compileGetLocal): Deleted.
+        (JSC::FTL::LowerDFGToLLVM::compilePutLocal): Deleted.
+        * ftl/FTLOSRExit.h:
+        * tests/stress/many-sunken-locals.js: Added. This failure mode was caught by some miscellaneous test, so I figured I should write an explicit test for it.
+        (foo):
+        (bar):
+        (baz):
+        (fuzz):
+        (buzz):
+
</ins><span class="cx"> 2015-02-26  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rolling out r180602, r180608, r180613, r180617, r180671.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreJavaScriptCorevcxprojJavaScriptCorevcxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -451,7 +451,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><del>-    &lt;ClCompile Include=&quot;..\dfg\DFGPutLocalSinkingPhase.cpp&quot; /&gt;
</del><ins>+    &lt;ClCompile Include=&quot;..\dfg\DFGPutStackSinkingPhase.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">@@ -1123,7 +1123,7 @@
</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><del>-    &lt;ClInclude Include=&quot;..\dfg\DFGPutLocalSinkingPhase.h&quot; /&gt;
</del><ins>+    &lt;ClInclude Include=&quot;..\dfg\DFGPutStackSinkingPhase.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 (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -274,6 +274,8 @@
</span><span class="cx">                 0F38B01817CFE75500B144D3 /* DFGCompilationKey.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F38B01417CFE75500B144D3 /* DFGCompilationKey.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F38B01917CFE75500B144D3 /* DFGCompilationMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F38B01517CFE75500B144D3 /* DFGCompilationMode.cpp */; };
</span><span class="cx">                 0F38B01A17CFE75500B144D3 /* DFGCompilationMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F38B01617CFE75500B144D3 /* DFGCompilationMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                0F3A1BF91A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3A1BF71A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp */; };
+                0F3A1BFA1A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3A1BF81A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 0F3AC752183EA1040032029F /* StackAlignment.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3AC751183EA1040032029F /* StackAlignment.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F3AC754188E5EC80032029F /* ExitingJITType.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F3AC753188E5EC80032029F /* ExitingJITType.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 0F3B3A1A153E68F2003ED0FF /* DFGConstantFoldingPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */; };
</span><span class="lines">@@ -1598,8 +1600,6 @@
</span><span class="cx">                 C4F4B6F51A05C984005CAB76 /* generate_objc_protocol_types_implementation.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D71A05C76F005CAB76 /* generate_objc_protocol_types_implementation.py */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 C4F4B6F61A05C984005CAB76 /* objc_generator_templates.py in Headers */ = {isa = PBXBuildFile; fileRef = C4F4B6D81A05C76F005CAB76 /* objc_generator_templates.py */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 DC00039319D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h in Headers */ = {isa = PBXBuildFile; fileRef = DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                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, ); }; };
</del><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">@@ -1956,6 +1956,8 @@
</span><span class="cx">                 0F38B01417CFE75500B144D3 /* DFGCompilationKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCompilationKey.h; path = dfg/DFGCompilationKey.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F38B01517CFE75500B144D3 /* DFGCompilationMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCompilationMode.cpp; path = dfg/DFGCompilationMode.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F38B01617CFE75500B144D3 /* DFGCompilationMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCompilationMode.h; path = dfg/DFGCompilationMode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                0F3A1BF71A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGPutStackSinkingPhase.cpp; path = dfg/DFGPutStackSinkingPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                0F3A1BF81A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPutStackSinkingPhase.h; path = dfg/DFGPutStackSinkingPhase.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 0F3AC751183EA1040032029F /* StackAlignment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackAlignment.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F3AC753188E5EC80032029F /* ExitingJITType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExitingJITType.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 0F3B3A17153E68EF003ED0FF /* DFGConstantFoldingPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGConstantFoldingPhase.cpp; path = dfg/DFGConstantFoldingPhase.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -3303,8 +3305,6 @@
</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><span class="cx">                 DC00039019D8BE6F00023EB0 /* DFGPreciseLocalClobberize.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGPreciseLocalClobberize.h; path = dfg/DFGPreciseLocalClobberize.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                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;; };
</del><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">@@ -4882,8 +4882,8 @@
</span><span class="cx">                                 0FAA3E0819D0C2CB00FAC9E2 /* DFGPromoteHeapAccess.h */,
</span><span class="cx">                                 0FB1765E196B8F9E0091052A /* DFGPureValue.cpp */,
</span><span class="cx">                                 0FB1765F196B8F9E0091052A /* DFGPureValue.h */,
</span><del>-                                DC00039619DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp */,
-                                DC00039719DBA70600023EB0 /* DFGPutLocalSinkingPhase.h */,
</del><ins>+                                0F3A1BF71A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp */,
+                                0F3A1BF81A9ECB7D000DE01A /* DFGPutStackSinkingPhase.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">@@ -6008,7 +6008,6 @@
</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><del>-                                DC00039919DBA70600023EB0 /* DFGPutLocalSinkingPhase.h in Headers */,
</del><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">@@ -6319,6 +6318,7 @@
</span><span class="cx">                                 0FC8150A14043BF500CFA603 /* WriteBarrierSupport.h in Headers */,
</span><span class="cx">                                 9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */,
</span><span class="cx">                                 A5840E2A187CA75900843B10 /* xxd.pl in Headers */,
</span><ins>+                                0F3A1BFA1A9ECB7D000DE01A /* DFGPutStackSinkingPhase.h in Headers */,
</ins><span class="cx">                                 451539B912DC994500EF7AC4 /* Yarr.h in Headers */,
</span><span class="cx">                                 86704B8512DBA33700A9FE7B /* YarrInterpreter.h in Headers */,
</span><span class="cx">                                 86704B8712DBA33700A9FE7B /* YarrJIT.h in Headers */,
</span><span class="lines">@@ -6885,7 +6885,6 @@
</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><del>-                                DC00039819DBA70600023EB0 /* DFGPutLocalSinkingPhase.cpp in Sources */,
</del><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 class="lines">@@ -6906,6 +6905,7 @@
</span><span class="cx">                                 0FD120331A8C85BD000F5280 /* FTLJSCallVarargs.cpp in Sources */,
</span><span class="cx">                                 0F9D339617FFC4E60073C2BC /* DFGFlushedAt.cpp in Sources */,
</span><span class="cx">                                 A7D89CF717A0B8CC00773AD8 /* DFGFlushFormat.cpp in Sources */,
</span><ins>+                                0F3A1BF91A9ECB7D000DE01A /* DFGPutStackSinkingPhase.cpp in Sources */,
</ins><span class="cx">                                 86EC9DC71328DF82002B2AD7 /* DFGGraph.cpp in Sources */,
</span><span class="cx">                                 0F2FCCF918A60070001A27F8 /* DFGGraphSafepoint.cpp in Sources */,
</span><span class="cx">                                 A704D90517A0BAA8006BA554 /* DFGInPlaceAbstractState.cpp in Sources */,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -167,6 +167,17 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><ins>+    case GetStack: {
+        StackAccessData* data = node-&gt;stackAccessData();
+        AbstractValue value = m_state.variables().operand(data-&gt;local);
+        // The value in the local should already be checked.
+        DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(data-&gt;format)));
+        if (value.value())
+            m_state.setFoundConstants(true);
+        forNode(node) = value;
+        break;
+    }
+        
</ins><span class="cx">     case GetLocalUnlinked: {
</span><span class="cx">         AbstractValue value = m_state.variables().operand(node-&gt;unlinkedLocal().offset());
</span><span class="cx">         if (value.value())
</span><span class="lines">@@ -175,12 +186,16 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    case SetLocal:
-    case PutLocal: {
-        m_state.variables().operand(node-&gt;local().offset()) = forNode(node-&gt;child1());
</del><ins>+    case SetLocal: {
+        m_state.variables().operand(node-&gt;local()) = forNode(node-&gt;child1());
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><ins>+    case PutStack: {
+        m_state.variables().operand(node-&gt;stackAccessData()-&gt;local) = forNode(node-&gt;child1());
+        break;
+    }
+        
</ins><span class="cx">     case MovHint: {
</span><span class="cx">         // Don't need to do anything. A MovHint only informs us about what would have happened
</span><span class="cx">         // in bytecode, but this code is just concerned with what is actually happening during
</span><span class="lines">@@ -188,7 +203,7 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    case KillLocal: {
</del><ins>+    case KillStack: {
</ins><span class="cx">         // This is just a hint telling us that the OSR state of the local is no longer inside the
</span><span class="cx">         // flushed data.
</span><span class="cx">         break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -260,7 +260,7 @@
</span><span class="cx">          
</span><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><del>-    case KillLocal:
</del><ins>+    case KillStack:
</ins><span class="cx">     case Upsilon:
</span><span class="cx">     case Phi:
</span><span class="cx">     case PhantomLocal:
</span><span class="lines">@@ -406,11 +406,24 @@
</span><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case SetLocal:
</span><del>-    case PutLocal:
</del><span class="cx">         write(AbstractHeap(Variables, node-&gt;local()));
</span><span class="cx">         def(HeapLocation(VariableLoc, AbstractHeap(Variables, node-&gt;local())), node-&gt;child1().node());
</span><span class="cx">         return;
</span><span class="cx">         
</span><ins>+    case GetStack: {
+        AbstractHeap heap(Variables, node-&gt;stackAccessData()-&gt;local);
+        read(heap);
+        def(HeapLocation(VariableLoc, heap), node);
+        return;
+    }
+        
+    case PutStack: {
+        AbstractHeap heap(Variables, node-&gt;stackAccessData()-&gt;local);
+        write(heap);
+        def(HeapLocation(VariableLoc, heap), node-&gt;child1().node());
+        return;
+    }
+        
</ins><span class="cx">     case LoadVarargs:
</span><span class="cx">         // This actually writes to local variables as well. But when it reads the array, it does
</span><span class="cx">         // so in a way that may trigger getters or various traps.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGConstantFoldingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -397,7 +397,10 @@
</span><span class="cx">                         m_insertionSet.insertNode(
</span><span class="cx">                             indexInBlock, SpecNone, Phantom, node-&gt;origin, node-&gt;children);
</span><span class="cx">                         
</span><del>-                        node-&gt;convertToGetLocalUnlinked(VirtualRegister(operand));
</del><ins>+                        if (m_graph.m_form == SSA)
+                            node-&gt;convertToGetStack(m_graph.m_stackAccessData.add(VirtualRegister(operand), FlushedJSValue));
+                        else
+                            node-&gt;convertToGetLocalUnlinked(VirtualRegister(operand));
</ins><span class="cx">                         break;
</span><span class="cx">                     }
</span><span class="cx">                 }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDoesGCcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -207,8 +207,9 @@
</span><span class="cx">     case PutByOffsetHint:
</span><span class="cx">     case CheckStructureImmediate:
</span><span class="cx">     case PutStructureHint:
</span><del>-    case PutLocal:
-    case KillLocal:
</del><ins>+    case PutStack:
+    case KillStack:
+    case GetStack:
</ins><span class="cx">         return false;
</span><span class="cx"> 
</span><span class="cx">     case CreateActivation:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -1058,8 +1058,9 @@
</span><span class="cx">         case CheckStructureImmediate:
</span><span class="cx">         case PutStructureHint:
</span><span class="cx">         case MaterializeNewObject:
</span><del>-        case PutLocal:
-        case KillLocal:
</del><ins>+        case PutStack:
+        case KillStack:
+        case GetStack:
</ins><span class="cx">             // These are just nodes that we don't currently expect to see during fixup.
</span><span class="cx">             // If we ever wanted to insert them prior to fixup, then we just have to create
</span><span class="cx">             // fixup rules for them.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFlushFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -134,6 +134,11 @@
</span><span class="cx">     return ConflictingFlush;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool isConcrete(FlushFormat format)
+{
+    return format != DeadFlush &amp;&amp; format != 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 (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -282,6 +282,13 @@
</span><span class="cx">                 out.print(comma, &quot;machine:&quot;, operand);
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+    if (node-&gt;hasStackAccessData()) {
+        StackAccessData* data = node-&gt;stackAccessData();
+        out.print(comma, data-&gt;local);
+        if (data-&gt;machineLocal.isValid())
+            out.print(comma, &quot;machine:&quot;, data-&gt;machineLocal);
+        out.print(comma, data-&gt;format);
+    }
</ins><span class="cx">     if (node-&gt;hasUnlinkedLocal()) 
</span><span class="cx">         out.print(comma, node-&gt;unlinkedLocal());
</span><span class="cx">     if (node-&gt;hasUnlinkedMachineLocal()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -783,7 +783,7 @@
</span><span class="cx">     // that survived DCE. All of them except maybe &quot;this&quot; will survive DCE, because of the Flush
</span><span class="cx">     // nodes.
</span><span class="cx">     //
</span><del>-    // In SSA, this is all of the GetLocal nodes for the arguments in the machine code block that
</del><ins>+    // In SSA, this is all of the GetStack nodes for the arguments in the machine code block that
</ins><span class="cx">     // may have some speculation in the prologue and survived DCE. Note that to get the speculation
</span><span class="cx">     // for an argument in SSA, you must use m_argumentFormats, since we still have to speculate
</span><span class="cx">     // even if the argument got killed. For example:
</span><span class="lines">@@ -794,7 +794,7 @@
</span><span class="cx">     //
</span><span class="cx">     // Assume that x is always int during profiling. The ArithAdd for &quot;x + 1&quot; will be dead and will
</span><span class="cx">     // have a proven check for the edge to &quot;x&quot;. So, we will not insert a Check node and we will
</span><del>-    // kill the GetLocal for &quot;x&quot;. But, we must do the int check in the progolue, because that's the
</del><ins>+    // kill the GetStack for &quot;x&quot;. But, we must do the int check in the progolue, because that's the
</ins><span class="cx">     // thing we used to allow DCE of ArithAdd. Otherwise the add could be impure:
</span><span class="cx">     //
</span><span class="cx">     //     var o = {
</span><span class="lines">@@ -821,6 +821,7 @@
</span><span class="cx">     Bag&lt;ObjectMaterializationData&gt; m_objectMaterializationData;
</span><span class="cx">     Bag&lt;CallVarargsData&gt; m_callVarargsData;
</span><span class="cx">     Bag&lt;LoadVarargsData&gt; m_loadVarargsData;
</span><ins>+    Bag&lt;StackAccessData&gt; m_stackAccessData;
</ins><span class="cx">     Vector&lt;InlineVariableData, 4&gt; m_inlineVariableData;
</span><span class="cx">     HashMap&lt;CodeBlock*, std::unique_ptr&lt;FullBytecodeLiveness&gt;&gt; m_bytecodeLiveness;
</span><span class="cx">     bool m_hasArguments;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGMayExitcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGMayExit.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -79,8 +79,9 @@
</span><span class="cx">     case PutStructureHint:
</span><span class="cx">     case PutByOffsetHint:
</span><span class="cx">     case PhantomNewObject:
</span><del>-    case PutLocal:
-    case KillLocal:
</del><ins>+    case PutStack:
+    case KillStack:
+    case GetStack:
</ins><span class="cx">     case GetCallee:
</span><span class="cx">     case GetScope:
</span><span class="cx">     case PhantomLocal:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -78,7 +78,6 @@
</span><span class="cx">     case SetArgument:
</span><span class="cx">     case Flush:
</span><span class="cx">     case PhantomLocal:
</span><del>-    case PutLocal:
</del><span class="cx">         return true;
</span><span class="cx">     default:
</span><span class="cx">         return false;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -197,6 +197,25 @@
</span><span class="cx">     unsigned limit; // Maximum number of elements to load. Includes &quot;this&quot;.
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+struct StackAccessData {
+    StackAccessData()
+        : format(DeadFlush)
+    {
+    }
+    
+    StackAccessData(VirtualRegister local, FlushFormat format)
+        : local(local)
+        , format(format)
+    {
+    }
+    
+    VirtualRegister local;
+    VirtualRegister machineLocal;
+    FlushFormat format;
+    
+    FlushedAt flushedAt() { return FlushedAt(format, machineLocal); }
+};
+
</ins><span class="cx"> // This type used in passing an immediate argument to Node constructor;
</span><span class="cx"> // distinguishes an immediate value (typically an index into a CodeBlock data structure - 
</span><span class="cx"> // a constant index, argument, or identifier) from a Node*.
</span><span class="lines">@@ -484,6 +503,23 @@
</span><span class="cx">         children.reset();
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    void convertToPutStack(StackAccessData* data)
+    {
+        m_op = PutStack;
+        m_flags |= NodeMustGenerate;
+        m_opInfo = bitwise_cast&lt;uintptr_t&gt;(data);
+        m_opInfo2 = 0;
+    }
+    
+    void convertToGetStack(StackAccessData* data)
+    {
+        m_op = GetStack;
+        m_flags &amp;= ~NodeMustGenerate;
+        m_opInfo = bitwise_cast&lt;uintptr_t&gt;(data);
+        m_opInfo2 = 0;
+        children.reset();
+    }
+    
</ins><span class="cx">     void convertToGetByOffset(StorageAccessData&amp; data, Edge storage)
</span><span class="cx">     {
</span><span class="cx">         ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset);
</span><span class="lines">@@ -717,7 +753,7 @@
</span><span class="cx">         case ExtractOSREntryLocal:
</span><span class="cx">         case MovHint:
</span><span class="cx">         case ZombieHint:
</span><del>-        case KillLocal:
</del><ins>+        case KillStack:
</ins><span class="cx">             return true;
</span><span class="cx">         default:
</span><span class="cx">             return false;
</span><span class="lines">@@ -747,6 +783,23 @@
</span><span class="cx">         return VirtualRegister(m_opInfo2);
</span><span class="cx">     }
</span><span class="cx">     
</span><ins>+    bool hasStackAccessData()
+    {
+        switch (op()) {
+        case PutStack:
+        case GetStack:
+            return true;
+        default:
+            return false;
+        }
+    }
+    
+    StackAccessData* stackAccessData()
+    {
+        ASSERT(hasStackAccessData());
+        return bitwise_cast&lt;StackAccessData*&gt;(m_opInfo);
+    }
+    
</ins><span class="cx">     bool hasPhi()
</span><span class="cx">     {
</span><span class="cx">         return op() == Upsilon;
</span><span class="lines">@@ -1428,8 +1481,6 @@
</span><span class="cx">     {
</span><span class="cx">         switch (op()) {
</span><span class="cx">         case SetLocal:
</span><del>-        case PutLocal:
-        case KillLocal:
</del><span class="cx">         case MovHint:
</span><span class="cx">         case ZombieHint:
</span><span class="cx">         case PhantomArguments:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -57,8 +57,11 @@
</span><span class="cx">     /* better names for a lot of these. https://bugs.webkit.org/show_bug.cgi?id=137307 */\
</span><span class="cx">     macro(GetLocal, NodeResultJS) \
</span><span class="cx">     macro(SetLocal, 0) \
</span><del>-    macro(PutLocal, NodeMustGenerate) \
-    macro(KillLocal, NodeMustGenerate) \
</del><ins>+    \
+    macro(PutStack, NodeMustGenerate) \
+    macro(KillStack, NodeMustGenerate) \
+    macro(GetStack, NodeResultJS) \
+    \
</ins><span class="cx">     macro(MovHint, 0) \
</span><span class="cx">     macro(ZombieHint, 0) \
</span><span class="cx">     macro(Phantom, NodeMustGenerate) \
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRAvailabilityAnalysisPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -128,21 +128,20 @@
</span><span class="cx"> void LocalOSRAvailabilityCalculator::executeNode(Node* node)
</span><span class="cx"> {
</span><span class="cx">     switch (node-&gt;op()) {
</span><del>-    case PutLocal: {
-        VariableAccessData* variable = node-&gt;variableAccessData();
-        m_availability.m_locals.operand(variable-&gt;local()).setFlush(variable-&gt;flushedAt());
</del><ins>+    case PutStack: {
+        StackAccessData* data = node-&gt;stackAccessData();
+        m_availability.m_locals.operand(data-&gt;local).setFlush(data-&gt;flushedAt());
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    case KillLocal: {
</del><ins>+    case KillStack: {
</ins><span class="cx">         m_availability.m_locals.operand(node-&gt;unlinkedLocal()).setFlush(FlushedAt(ConflictingFlush));
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    case GetLocal: {
-        VariableAccessData* variable = node-&gt;variableAccessData();
-        m_availability.m_locals.operand(variable-&gt;local()) =
-            Availability(node, variable-&gt;flushedAt());
</del><ins>+    case GetStack: {
+        StackAccessData* data = node-&gt;stackAccessData();
+        m_availability.m_locals.operand(data-&gt;local) = Availability(node, data-&gt;flushedAt());
</ins><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPlancpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGPlan.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -54,7 +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><del>-#include &quot;DFGPutLocalSinkingPhase.h&quot;
</del><ins>+#include &quot;DFGPutStackSinkingPhase.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">@@ -324,7 +324,7 @@
</span><span class="cx">         performCPSRethreading(dfg);
</span><span class="cx">         performSSAConversion(dfg);
</span><span class="cx">         performSSALowering(dfg);
</span><del>-        performPutLocalSinking(dfg);
</del><ins>+        performPutStackSinking(dfg);
</ins><span class="cx">         performGlobalCSE(dfg);
</span><span class="cx">         performLivenessAnalysis(dfg);
</span><span class="cx">         performCFA(dfg);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -541,8 +541,9 @@
</span><span class="cx">         case CheckStructureImmediate:
</span><span class="cx">         case PutStructureHint:
</span><span class="cx">         case MaterializeNewObject:
</span><del>-        case PutLocal:
-        case KillLocal: {
</del><ins>+        case PutStack:
+        case KillStack:
+        case GetStack: {
</ins><span class="cx">             // This node should never be visible at this stage of compilation. It is
</span><span class="cx">             // inserted by fixup(), which follows this phase.
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhasecpp"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -1,590 +0,0 @@
</span><del>-/*
- * 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;    &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. Deferrals have the following lattice; but it's worth noting that the
-        // TOP part of the lattice serves an entirely different purpose than the rest of the lattice:
-        // it just means that we're in a region of code where nobody should have been relying on the
-        // value. The rest of the lattice means that we either have a PutLocal that is deferred (i.e.
-        // still needs to be executed) or there isn't one (because we've alraedy executed it).
-        //
-        // Bottom:
-        //     Instantiated as VariableDeferral(). 
-        //     Means that all previous PutLocals have been executed so there is nothing deferred.
-        //     During merging this is subordinate to the other kinds of deferrals, because it
-        //     represents the fact that we've already executed all necessary PutLocals. This implies
-        //     that there *had* been some PutLocals that we should have executed.
-        //
-        // Top:
-        //     Instantiated as VariableDeferral::conflict().
-        //     Represents the fact that we know, via forward flow, that there isn't any value in the
-        //     given local that anyone should have been relying on. This comes into play at the
-        //     prologue (because in SSA form at the prologue no local has any value) or when we merge
-        //     deferrals for different VariableAccessData*'s. A VAD encompasses a lexical scope in
-        //     which the local has some semantic meaning; if we had stores from different lexical
-        //     scopes that got merged together then we know that we're not in either scope anymore.
-        //     Note that this is all approximate and only precise enough to later answer questions
-        //     pertinent to sinking. For example, this doesn't always detect when a local is no
-        //     longer semantically relevant - we may well have a deferral from inside some inlined
-        //     call survive outside of that inlined code, and this is generally OK. In the worst case
-        //     it means that we might think that a deferral that is actually dead must still be
-        //     executed. But we usually catch that with liveness. Liveness doesn't always catch it
-        //     because liveness is conservative.
-        //
-        //     What Top does give us is detects situations where we both don't need to care about a
-        //     deferral and there is no way that we could reason about it anyway. If we merged
-        //     deferrals for different variables then we wouldn't know the format to use. So, we
-        //     use Top in that case because that's also a case where we know that we can ignore the
-        //     deferral.
-        //
-        // Deferral with a concrete VariableAccessData*:
-        //     Instantiated as VariableDeferral(someVariableAccessData)
-        //     Represents the fact that the original code would have done a PutLocal but we haven't
-        //     identified an operation that would have observed that PutLocal.
-        //
-        // This code has some interesting quirks because of the fact that neither liveness nor
-        // deferrals are very precise. They are only precise enough to be able to correctly tell us
-        // when we may [sic] need to execute PutLocals. This means that they may report the need to
-        // execute a PutLocal in cases where we actually don't really need it, and that's totally OK.
-        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 &quot;, VirtualRegister(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 GetLocal:
-                    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 &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 &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 &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 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 &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*) { });
-                    
-                    // If we're a GetLocal, then we also create a mapping.
-                    // FIXME: We should be able to just eliminate such GetLocals, when we know
-                    // what their incoming value will be.
-                    // https://bugs.webkit.org/show_bug.cgi?id=141624
-                    if (node-&gt;op() == GetLocal) {
-                        VariableAccessData* variable = node-&gt;variableAccessData();
-                        VirtualRegister operand = variable-&gt;local();
-                        mapping.operand(operand) = 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 &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);
-                    if (!incoming) {
-                        // This can totally happen, see tests/stress/put-local-conservative.js.
-                        // This arises because deferral and liveness are both conservative.
-                        // Conservative liveness means that a load from a *different* closure
-                        // variable may lead us to believe that our local is live. Conservative
-                        // deferral may lead us to believe that the local doesn't have a top deferral
-                        // because someone has done something that would have forced it to be
-                        // materialized. The basic pattern is:
-                        //
-                        // GetClosureVar(loc42) // loc42's deferral is now bottom
-                        // if (predicate1)
-                        //     PutClosureVar(loc42) // prevent GCSE of our GetClosureVar's
-                        // if (predicate2)
-                        //     PutLocal(loc42) // we now have a concrete deferral
-                        // // we still have the concrete deferral because we merged with bottom
-                        // GetClosureVar(loc42) // force materialization
-                        //
-                        // We will have a Phi with no incoming value form the basic block that
-                        // bypassed the PutLocal.
-                        
-                        // Note: we sort of could have used the equivalent of LLVM's undef here. The
-                        // point is that it's OK to just leave random bits in the local if we're
-                        // coming down this path. But, we don't have a way of saying that in our IR
-                        // right now and anyway it probably doesn't matter that much.
-                        
-                        incoming = insertionSet.insertBottomConstantForUse(
-                            upsilonInsertionPoint, upsilonOrigin, useKind).node();
-                    }
-                    
-                    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)
-
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhaseh"></a>
<div class="delfile"><h4>Deleted: trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -1,46 +0,0 @@
</span><del>- /*
- * 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
-
</del></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasecppfromrev180580trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhasecpp"></a>
<div class="copfile"><h4>Copied: trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp (from rev 180580, trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp) (0 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -0,0 +1,524 @@
</span><ins>+/*
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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;DFGPutStackSinkingPhase.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 PutStackSinkingPhase : public Phase {
+public:
+    PutStackSinkingPhase(Graph&amp; graph)
+        : Phase(graph, &quot;PutStack sinking&quot;)
+    {
+    }
+    
+    bool run()
+    {
+        // FIXME: One of the problems of this approach is that it will create a duplicate Phi graph
+        // for sunken PutStacks in the presence of interesting control flow merges, and where the
+        // value being PutStack'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 PutStackSinkingPhase 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 PutStack 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;    &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() == PutStack);
+                            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 PutStacks to. We say that there is a deferred
+        // flush if we had a PutStack with a given FlushFormat but it hasn't been materialized yet.
+        // Deferrals have the following lattice; but it's worth noting that the TOP part of the
+        // lattice serves an entirely different purpose than the rest of the lattice: it just means
+        // that we're in a region of code where nobody should have been relying on the value. The
+        // rest of the lattice means that we either have a PutStack that is deferred (i.e. still
+        // needs to be executed) or there isn't one (because we've alraedy executed it).
+        //
+        // Bottom:
+        //     Represented as DeadFlush. 
+        //     Means that all previous PutStacks have been executed so there is nothing deferred.
+        //     During merging this is subordinate to the other kinds of deferrals, because it
+        //     represents the fact that we've already executed all necessary PutStacks. This implies
+        //     that there *had* been some PutStacks that we should have executed.
+        //
+        // Top:
+        //     Represented as ConflictingFlush.
+        //     Represents the fact that we know, via forward flow, that there isn't any value in the
+        //     given local that anyone should have been relying on. This comes into play at the
+        //     prologue (because in SSA form at the prologue no local has any value) or when we merge
+        //     deferrals for different formats's. A lexical scope in which a local had some semantic
+        //     meaning will by this point share the same format; if we had stores from different
+        //     lexical scopes that got merged together then we may have a conflicting format. Hence
+        //     a conflicting format proves that we're no longer in an area in which the variable was
+        //     in scope. Note that this is all approximate and only precise enough to later answer
+        //     questions pertinent to sinking. For example, this doesn't always detect when a local
+        //     is no longer semantically relevant - we may well have a deferral from inside some
+        //     inlined call survive outside of that inlined code, and this is generally OK. In the
+        //     worst case it means that we might think that a deferral that is actually dead must
+        //     still be executed. But we usually catch that with liveness. Liveness usually catches
+        //     such cases, but that's not guaranteed since liveness is conservative.
+        //
+        //     What Top does give us is detects situations where we both don't need to care about a
+        //     deferral and there is no way that we could reason about it anyway. If we merged
+        //     deferrals for different formats then we wouldn't know the format to use. So, we use
+        //     Top in that case because that's also a case where we know that we can ignore the
+        //     deferral.
+        //
+        // Deferral with a concrete format:
+        //     Represented by format values other than DeadFlush or ConflictingFlush.
+        //     Represents the fact that the original code would have done a PutStack but we haven't
+        //     identified an operation that would have observed that PutStack.
+        //
+        // This code has some interesting quirks because of the fact that neither liveness nor
+        // deferrals are very precise. They are only precise enough to be able to correctly tell us
+        // when we may [sic] need to execute PutStacks. This means that they may report the need to
+        // execute a PutStack in cases where we actually don't really need it, and that's totally OK.
+        BlockMap&lt;Operands&lt;FlushFormat&gt;&gt; deferredAtHead(m_graph);
+        BlockMap&lt;Operands&lt;FlushFormat&gt;&gt; deferredAtTail(m_graph);
+        
+        for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+            deferredAtHead[block] =
+                Operands&lt;FlushFormat&gt;(OperandsLike, block-&gt;variablesAtHead);
+            deferredAtTail[block] =
+                Operands&lt;FlushFormat&gt;(OperandsLike, block-&gt;variablesAtHead);
+        }
+        
+        deferredAtHead.atIndex(0).fill(ConflictingFlush);
+        
+        do {
+            changed = false;
+            
+            for (BasicBlock* block : m_graph.blocksInNaturalOrder()) {
+                Operands&lt;FlushFormat&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() == KillStack) {
+                        deferred.operand(node-&gt;unlinkedLocal()) = ConflictingFlush;
+                        continue;
+                    }
+                    
+                    auto escapeHandler = [&amp;] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
+                        // We will materialize just before any reads.
+                        deferred.operand(operand) = DeadFlush;
+                    };
+                    
+                    preciseLocalClobberize(
+                        m_graph, node, escapeHandler, escapeHandler,
+                        [&amp;] (VirtualRegister operand, Node* source) {
+                            if (source == node) {
+                                // This is a load. Ignore it.
+                                return;
+                            }
+                            
+                            deferred.operand(operand) = node-&gt;stackAccessData()-&gt;format;
+                        });
+                }
+                
+                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 &quot;, VirtualRegister(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] =
+                            merge(deferredAtHead[successor][i], deferred[i]);
+                        
+                        if (verbose)
+                            dataLog(deferredAtHead[successor][i], &quot;\n&quot;);
+                    }
+                }
+            }
+            
+        } while (changed);
+        
+        // We wish to insert PutStacks 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)
+        //         PutStack(r42, @x)
+        //     else
+        //         PutStack(r42, @y)
+        //
+        // After:
+        //
+        //     if (p)
+        //         Upsilon(@x, ^z)
+        //     else
+        //         Upsilon(@y, ^z)
+        //     z: Phi()
+        //     PutStack(r42, @z)
+        //
+        // This means that we have an SSACalculator::Variable for each local, and a Def is any
+        // PutStack in the original program. The original PutStacks 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 PutStack:
+                    putLocalsToSink.add(node);
+                    ssaCalculator.newDef(
+                        operandToVariable.operand(node-&gt;stackAccessData()-&gt;local),
+                        block, node-&gt;child1().node());
+                    break;
+                case GetStack:
+                    ssaCalculator.newDef(
+                        operandToVariable.operand(node-&gt;stackAccessData()-&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;
+                
+                FlushFormat format = deferredAtHead[block].operand(operand);
+
+                // We could have an invalid deferral because liveness is imprecise.
+                if (!isConcrete(format))
+                    return nullptr;
+
+                if (verbose)
+                    dataLog(&quot;Adding Phi for &quot;, operand, &quot; at &quot;, pointerDump(block), &quot;\n&quot;);
+                
+                Node* phiNode = m_graph.addNode(SpecHeapTop, Phi, NodeOrigin());
+                phiNode-&gt;mergeFlags(resultFor(format));
+                return phiNode;
+            });
+        
+        Operands&lt;Node*&gt; mapping(OperandsLike, m_graph.block(0)-&gt;variablesAtHead);
+        Operands&lt;FlushFormat&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 &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 PutStack: {
+                    StackAccessData* data = node-&gt;stackAccessData();
+                    VirtualRegister operand = data-&gt;local;
+                    deferred.operand(operand) = data-&gt;format;
+                    if (verbose)
+                        dataLog(&quot;   Mapping &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 KillStack: {
+                    deferred.operand(node-&gt;unlinkedLocal()) = ConflictingFlush;
+                    break;
+                }
+                
+                default: {
+                    auto escapeHandler = [&amp;] (VirtualRegister operand) {
+                        if (operand.isHeader())
+                            return;
+                    
+                        FlushFormat format = deferred.operand(operand);
+                        if (!isConcrete(format))
+                            return;
+                    
+                        // Gotta insert a PutStack.
+                        if (verbose)
+                            dataLog(&quot;Inserting a PutStack for &quot;, operand, &quot; at &quot;, node, &quot;\n&quot;);
+
+                        Node* incoming = mapping.operand(operand);
+                        DFG_ASSERT(m_graph, node, incoming);
+                    
+                        insertionSet.insertNode(
+                            nodeIndex, SpecNone, PutStack, node-&gt;origin,
+                            OpInfo(m_graph.m_stackAccessData.add(operand, format)),
+                            Edge(incoming, useKindFor(format)));
+                    
+                        deferred.operand(operand) = DeadFlush;
+                    };
+                
+                    preciseLocalClobberize(
+                        m_graph, node, escapeHandler, escapeHandler,
+                        [&amp;] (VirtualRegister, Node*) { });
+                    
+                    // If we're a GetStack, then we also create a mapping.
+                    // FIXME: We should be able to just eliminate such GetLocals, when we know
+                    // what their incoming value will be.
+                    // https://bugs.webkit.org/show_bug.cgi?id=141624
+                    if (node-&gt;op() == GetStack) {
+                        StackAccessData* data = node-&gt;stackAccessData();
+                        VirtualRegister operand = data-&gt;local;
+                        mapping.operand(operand) = 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 &quot;, operand, &quot; at &quot;, pointerDump(block), &quot;-&gt;&quot;, pointerDump(successorBlock), &quot;\n&quot;);
+                    FlushFormat format = deferredAtHead[successorBlock].operand(operand);
+                    DFG_ASSERT(m_graph, nullptr, isConcrete(format));
+                    UseKind useKind = useKindFor(format);
+                    Node* incoming = mapping.operand(operand);
+                    if (!incoming) {
+                        // This can totally happen, see tests/stress/put-local-conservative.js.
+                        // This arises because deferral and liveness are both conservative.
+                        // Conservative liveness means that a load from a *different* closure
+                        // variable may lead us to believe that our local is live. Conservative
+                        // deferral may lead us to believe that the local doesn't have a top deferral
+                        // because someone has done something that would have forced it to be
+                        // materialized. The basic pattern is:
+                        //
+                        // GetClosureVar(loc42) // loc42's deferral is now bottom
+                        // if (predicate1)
+                        //     PutClosureVar(loc42) // prevent GCSE of our GetClosureVar's
+                        // if (predicate2)
+                        //     PutStack(loc42) // we now have a concrete deferral
+                        // // we still have the concrete deferral because we merged with bottom
+                        // GetClosureVar(loc42) // force materialization
+                        //
+                        // We will have a Phi with no incoming value form the basic block that
+                        // bypassed the PutStack.
+                        
+                        // Note: we sort of could have used the equivalent of LLVM's undef here. The
+                        // point is that it's OK to just leave random bits in the local if we're
+                        // coming down this path. But, we don't have a way of saying that in our IR
+                        // right now and anyway it probably doesn't matter that much.
+                        
+                        incoming = insertionSet.insertBottomConstantForUse(
+                            upsilonInsertionPoint, upsilonOrigin, useKind).node();
+                    }
+                    
+                    insertionSet.insertNode(
+                        upsilonInsertionPoint, SpecNone, Upsilon, upsilonOrigin,
+                        OpInfo(phiNode), Edge(incoming, useKind));
+                }
+            }
+            
+            insertionSet.execute(block);
+        }
+        
+        // Finally eliminate the sunken PutStacks 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, KillStack, node-&gt;origin, OpInfo(node-&gt;stackAccessData()-&gt;local.offset()));
+                node-&gt;convertToPhantom();
+            }
+            
+            insertionSet.execute(block);
+        }
+        
+        if (verbose) {
+            dataLog(&quot;Graph after PutStack sinking:\n&quot;);
+            m_graph.dump();
+        }
+        
+        return true;
+    }
+};
+
+} // anonymous namespace
+    
+bool performPutStackSinking(Graph&amp; graph)
+{
+    SamplingRegion samplingRegion(&quot;DFG PutStack Sinking Phase&quot;);
+    return runPhase&lt;PutStackSinkingPhase&gt;(graph);
+}
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutStackSinkingPhasehfromrev180580trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhaseh"></a>
<div class="copfile"><h4>Copied: trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.h (from rev 180580, trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.h) (0 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.h                                (rev 0)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutStackSinkingPhase.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+ /*
+ * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * 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 DFGPutStackSinkingPhase_h
+#define DFGPutStackSinkingPhase_h
+
+#if ENABLE(DFG_JIT)
+
+namespace JSC { namespace DFG {
+
+class Graph;
+
+// Sinks PutStacks to the absolute latest point where they can possibly happen, which is usually
+// side-effects that may observe them. This eliminates PutStacks if it sinks them past the point of
+// their deaths.
+
+bool performPutStackSinking(Graph&amp;);
+
+} } // namespace JSC::DFG
+
+#endif // ENABLE(DFG_JIT)
+
+#endif // DFGPutStackSinkingPhase_h
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -97,8 +97,10 @@
</span><span class="cx">                     ASSERT(node-&gt;op() == SetArgument);
</span><span class="cx">                     childNode = m_insertionSet.insertNode(
</span><span class="cx">                         nodeIndex, node-&gt;variableAccessData()-&gt;prediction(),
</span><del>-                        GetLocal, node-&gt;origin, OpInfo(node-&gt;variableAccessData()));
-                    m_argumentGetters.add(childNode);
</del><ins>+                        GetStack, node-&gt;origin,
+                        OpInfo(m_graph.m_stackAccessData.add(variable-&gt;local(), variable-&gt;flushFormat())));
+                    if (!ASSERT_DISABLED)
+                        m_argumentGetters.add(childNode);
</ins><span class="cx">                     m_argumentMapping.add(node, childNode);
</span><span class="cx">                 }
</span><span class="cx">                 
</span><span class="lines">@@ -188,26 +190,26 @@
</span><span class="cx">         //
</span><span class="cx">         //   - MovHint has KillLocal prepended to it.
</span><span class="cx">         //
</span><del>-        //   - GetLocal over captured variables lose their phis.
</del><ins>+        //   - GetLocal over captured variables lose their phis and become GetStack.
</ins><span class="cx">         //
</span><span class="cx">         //   - GetLocal over uncaptured variables die and get replaced with references to the node
</span><span class="cx">         //     specified by valueForOperand.
</span><span class="cx">         //
</span><del>-        //   - SetLocal turns into PutLocal if it's flushed, or turns into a Check otherwise.
</del><ins>+        //   - SetLocal turns into PutStack if it's flushed, or turns into a Check otherwise.
</ins><span class="cx">         //
</span><span class="cx">         //   - Flush loses its children and turns into a Phantom.
</span><span class="cx">         //
</span><span class="cx">         //   - PhantomLocal becomes Phantom, and its child is whatever is specified by
</span><span class="cx">         //     valueForOperand.
</span><span class="cx">         //
</span><del>-        //   - SetArgument is removed. Note that GetLocal nodes have already been inserted.
</del><ins>+        //   - SetArgument is removed. Note that GetStack nodes have already been inserted.
</ins><span class="cx">         Operands&lt;Node*&gt; valueForOperand(OperandsLike, m_graph.block(0)-&gt;variablesAtHead);
</span><span class="cx">         for (BasicBlock* block : m_graph.blocksInPreOrder()) {
</span><span class="cx">             valueForOperand.clear();
</span><span class="cx">             
</span><span class="cx">             // CPS will claim that the root block has all arguments live. But we have already done
</span><span class="cx">             // the first step of SSA conversion: argument locals are no longer live at head;
</span><del>-            // instead we have GetLocal nodes for extracting the values of arguments. So, we
</del><ins>+            // instead we have GetStack nodes for extracting the values of arguments. So, we
</ins><span class="cx">             // skip the at-head available value calculation for the root block.
</span><span class="cx">             if (block != m_graph.block(0)) {
</span><span class="cx">                 for (size_t i = valueForOperand.size(); i--;) {
</span><span class="lines">@@ -273,7 +275,7 @@
</span><span class="cx">                 switch (node-&gt;op()) {
</span><span class="cx">                 case MovHint: {
</span><span class="cx">                     m_insertionSet.insertNode(
</span><del>-                        nodeIndex, SpecNone, KillLocal, node-&gt;origin,
</del><ins>+                        nodeIndex, SpecNone, KillStack, node-&gt;origin,
</ins><span class="cx">                         OpInfo(node-&gt;unlinkedLocal().offset()));
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="lines">@@ -281,9 +283,11 @@
</span><span class="cx">                 case SetLocal: {
</span><span class="cx">                     VariableAccessData* variable = node-&gt;variableAccessData();
</span><span class="cx">                     
</span><del>-                    if (variable-&gt;isCaptured() || !!(node-&gt;flags() &amp; NodeIsFlushed))
-                        node-&gt;setOpAndDefaultFlags(PutLocal);
-                    else
</del><ins>+                    if (variable-&gt;isCaptured() || !!(node-&gt;flags() &amp; NodeIsFlushed)) {
+                        node-&gt;convertToPutStack(
+                            m_graph.m_stackAccessData.add(
+                                variable-&gt;local(), variable-&gt;flushFormat()));
+                    } else
</ins><span class="cx">                         node-&gt;setOpAndDefaultFlags(Check);
</span><span class="cx">                     
</span><span class="cx">                     if (!variable-&gt;isCaptured()) {
</span><span class="lines">@@ -294,18 +298,20 @@
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><ins>+                case GetStack: {
+                    ASSERT(m_argumentGetters.contains(node));
+                    valueForOperand.operand(node-&gt;stackAccessData()-&gt;local) = node;
+                    break;
+                }
+                    
</ins><span class="cx">                 case GetLocal: {
</span><span class="cx">                     VariableAccessData* variable = node-&gt;variableAccessData();
</span><del>-                    if (m_argumentGetters.contains(node)) {
-                        if (verbose)
-                            dataLog(&quot;Mapping: &quot;, variable-&gt;local(), &quot; -&gt; &quot;, node, &quot;\n&quot;);
-                        valueForOperand.operand(variable-&gt;local()) = node;
-                        break;
-                    }
</del><span class="cx">                     node-&gt;children.reset();
</span><span class="cx">                     
</span><del>-                    if (variable-&gt;isCaptured())
</del><ins>+                    if (variable-&gt;isCaptured()) {
+                        node-&gt;convertToGetStack(m_graph.m_stackAccessData.add(variable-&gt;local(), variable-&gt;flushFormat()));
</ins><span class="cx">                         break;
</span><ins>+                    }
</ins><span class="cx">                     
</span><span class="cx">                     node-&gt;convertToPhantom();
</span><span class="cx">                     if (verbose)
</span><span class="lines">@@ -401,7 +407,7 @@
</span><span class="cx">             // track the argument loads of those arguments for which we speculate type. We don't
</span><span class="cx">             // speculate type for captured arguments.
</span><span class="cx">             if (node)
</span><del>-                format = node-&gt;variableAccessData()-&gt;flushFormat();
</del><ins>+                format = node-&gt;stackAccessData()-&gt;format;
</ins><span class="cx">             
</span><span class="cx">             m_graph.m_argumentFormats[i] = format;
</span><span class="cx">             m_graph.m_arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -118,8 +118,9 @@
</span><span class="cx">     case GetCallee:
</span><span class="cx">     case GetLocal:
</span><span class="cx">     case SetLocal:
</span><del>-    case PutLocal:
-    case KillLocal:
</del><ins>+    case PutStack:
+    case KillStack:
+    case GetStack:
</ins><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><span class="cx">     case Phantom:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -5088,8 +5088,9 @@
</span><span class="cx">     case CheckStructureImmediate:
</span><span class="cx">     case PutStructureHint:
</span><span class="cx">     case MaterializeNewObject:
</span><del>-    case PutLocal:
-    case KillLocal:
</del><ins>+    case PutStack:
+    case KillStack:
+    case GetStack:
</ins><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">         break;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -5159,8 +5159,9 @@
</span><span class="cx">     case CheckStructureImmediate:
</span><span class="cx">     case PutStructureHint:
</span><span class="cx">     case MaterializeNewObject:
</span><del>-    case PutLocal:
-    case KillLocal:
</del><ins>+    case PutStack:
+    case KillStack:
+    case GetStack:
</ins><span class="cx">         DFG_CRASH(m_jit.graph(), node, &quot;Unexpected node&quot;);
</span><span class="cx">         break;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGStackLayoutPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGStackLayoutPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -66,7 +66,6 @@
</span><span class="cx">                 switch (node-&gt;op()) {
</span><span class="cx">                 case GetLocal:
</span><span class="cx">                 case SetLocal:
</span><del>-                case PutLocal:
</del><span class="cx">                 case Flush:
</span><span class="cx">                 case PhantomLocal: {
</span><span class="cx">                     VariableAccessData* variable = node-&gt;variableAccessData();
</span><span class="lines">@@ -100,6 +99,15 @@
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><ins>+                case PutStack:
+                case GetStack: {
+                    StackAccessData* stack = node-&gt;stackAccessData();
+                    if (stack-&gt;local.isArgument())
+                        break;
+                    usedLocals.set(stack-&gt;local.toLocal());
+                    break;
+                }
+                    
</ins><span class="cx">                 default:
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="lines">@@ -171,6 +179,20 @@
</span><span class="cx">             variable-&gt;machineLocal() = assign(allocation, variable-&gt;local());
</span><span class="cx">         }
</span><span class="cx">         
</span><ins>+        for (StackAccessData* data : m_graph.m_stackAccessData) {
+            if (!data-&gt;local.isLocal()) {
+                data-&gt;machineLocal = data-&gt;local;
+                continue;
+            }
+            
+            if (static_cast&lt;size_t&gt;(data-&gt;local.toLocal()) &gt;= allocation.size())
+                continue;
+            if (allocation[data-&gt;local.toLocal()] == UINT_MAX)
+                continue;
+            
+            data-&gt;machineLocal = assign(allocation, data-&gt;local);
+        }
+        
</ins><span class="cx">         if (codeBlock()-&gt;usesArguments()) {
</span><span class="cx">             VirtualRegister argumentsRegister =
</span><span class="cx">                 assign(allocation, codeBlock()-&gt;argumentsRegister());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValidatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGValidate.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -214,7 +214,7 @@
</span><span class="cx">                     VALIDATE((node), canonicalResultRepresentation(node-&gt;result()) == canonicalResultRepresentation(node-&gt;child1()-&gt;result()));
</span><span class="cx">                     break;
</span><span class="cx">                 case SetLocal:
</span><del>-                case PutLocal:
</del><ins>+                case PutStack:
</ins><span class="cx">                 case Upsilon:
</span><span class="cx">                     VALIDATE((node), !!node-&gt;child1());
</span><span class="cx">                     switch (node-&gt;child1().useKind()) {
</span><span class="lines">@@ -433,6 +433,24 @@
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="cx">                 
</span><ins>+                switch (node-&gt;op()) {
+                case Phi:
+                case Upsilon:
+                case CheckInBounds:
+                case PhantomNewObject:
+                case PutByOffsetHint:
+                case CheckStructureImmediate:
+                case PutStructureHint:
+                case MaterializeNewObject:
+                case PutStack:
+                case KillStack:
+                case GetStack:
+                    VALIDATE((node), !&quot;unexpected node type in CPS&quot;);
+                    break;
+                default:
+                    break;
+                }
+                
</ins><span class="cx">                 if (!node-&gt;shouldGenerate())
</span><span class="cx">                     continue;
</span><span class="cx">                 switch (node-&gt;op()) {
</span><span class="lines">@@ -493,6 +511,8 @@
</span><span class="cx">             if (!block)
</span><span class="cx">                 continue;
</span><span class="cx">             
</span><ins>+            VALIDATE((block), block-&gt;phis.isEmpty());
+            
</ins><span class="cx">             unsigned nodeIndex = 0;
</span><span class="cx">             for (; nodeIndex &lt; block-&gt;size() &amp;&amp; !block-&gt;at(nodeIndex)-&gt;origin.forExit.isSet(); nodeIndex++) { }
</span><span class="cx">             
</span><span class="lines">@@ -508,6 +528,13 @@
</span><span class="cx">                     VALIDATE((node), !node-&gt;origin.forExit.isSet());
</span><span class="cx">                     break;
</span><span class="cx">                     
</span><ins>+                case GetLocal:
+                case SetLocal:
+                case GetLocalUnlinked:
+                case SetArgument:
+                    VALIDATE((node), !&quot;bad node type for SSA&quot;);
+                    break;
+                    
</ins><span class="cx">                 default:
</span><span class="cx">                     // FIXME: Add more things here.
</span><span class="cx">                     // https://bugs.webkit.org/show_bug.cgi?id=123471
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGVirtualRegisterAllocationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/dfg/DFGVirtualRegisterAllocationPhase.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -45,6 +45,8 @@
</span><span class="cx">     
</span><span class="cx">     bool run()
</span><span class="cx">     {
</span><ins>+        DFG_ASSERT(m_graph, nullptr, m_graph.m_form == ThreadedCPS);
+        
</ins><span class="cx">         ScoreBoard scoreBoard(m_graph.m_nextMachineLocal);
</span><span class="cx">         scoreBoard.assertClear();
</span><span class="cx">         for (size_t blockIndex = 0; blockIndex &lt; m_graph.numBlocks(); ++blockIndex) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -47,8 +47,9 @@
</span><span class="cx">     case GetMyArgumentsLength:
</span><span class="cx">     case GetLocal:
</span><span class="cx">     case SetLocal:
</span><del>-    case PutLocal:
-    case KillLocal:
</del><ins>+    case PutStack:
+    case KillStack:
+    case GetStack:
</ins><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><span class="cx">     case Phantom:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -253,7 +253,7 @@
</span><span class="cx">             LValue jsValue = m_out.load64(addressFor(operand));
</span><span class="cx">             
</span><span class="cx">             if (node) {
</span><del>-                DFG_ASSERT(m_graph, node, operand == node-&gt;variableAccessData()-&gt;machineLocal());
</del><ins>+                DFG_ASSERT(m_graph, node, operand == node-&gt;stackAccessData()-&gt;machineLocal);
</ins><span class="cx">                 
</span><span class="cx">                 // This is a hack, but it's an effective one. It allows us to do CSE on the
</span><span class="cx">                 // primordial load of arguments. This assumes that the GetLocal that got put in
</span><span class="lines">@@ -455,11 +455,11 @@
</span><span class="cx">         case ExtractOSREntryLocal:
</span><span class="cx">             compileExtractOSREntryLocal();
</span><span class="cx">             break;
</span><del>-        case GetLocal:
-            compileGetLocal();
</del><ins>+        case GetStack:
+            compileGetStack();
</ins><span class="cx">             break;
</span><del>-        case PutLocal:
-            compilePutLocal();
</del><ins>+        case PutStack:
+            compilePutStack();
</ins><span class="cx">             break;
</span><span class="cx">         case GetMyArgumentsLength:
</span><span class="cx">             compileGetMyArgumentsLength();
</span><span class="lines">@@ -828,7 +828,7 @@
</span><span class="cx">         case PutByOffsetHint:
</span><span class="cx">         case PutStructureHint:
</span><span class="cx">         case BottomValue:
</span><del>-        case KillLocal:
</del><ins>+        case KillStack:
</ins><span class="cx">             break;
</span><span class="cx">         default:
</span><span class="cx">             DFG_CRASH(m_graph, m_node, &quot;Unrecognized node in FTL backend&quot;);
</span><span class="lines">@@ -1067,7 +1067,7 @@
</span><span class="cx">         setJSValue(m_out.load64(m_out.absolute(buffer + m_node-&gt;unlinkedLocal().toLocal())));
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void compileGetLocal()
</del><ins>+    void compileGetStack()
</ins><span class="cx">     {
</span><span class="cx">         // GetLocals arise only for captured variables and arguments. For arguments, we might have
</span><span class="cx">         // already loaded it.
</span><span class="lines">@@ -1076,47 +1076,50 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        VariableAccessData* variable = m_node-&gt;variableAccessData();
-        AbstractValue&amp; value = m_state.variables().operand(variable-&gt;local());
</del><ins>+        StackAccessData* data = m_node-&gt;stackAccessData();
+        AbstractValue&amp; value = m_state.variables().operand(data-&gt;local);
</ins><span class="cx">         
</span><ins>+        DFG_ASSERT(m_graph, m_node, isConcrete(data-&gt;format));
+        DFG_ASSERT(m_graph, m_node, data-&gt;format != FlushedDouble); // This just happens to not arise for GetStacks, right now. It would be trivial to support.
+        
</ins><span class="cx">         if (isInt32Speculation(value.m_type))
</span><del>-            setInt32(m_out.load32(payloadFor(variable-&gt;machineLocal())));
</del><ins>+            setInt32(m_out.load32(payloadFor(data-&gt;machineLocal)));
</ins><span class="cx">         else
</span><del>-            setJSValue(m_out.load64(addressFor(variable-&gt;machineLocal())));
</del><ins>+            setJSValue(m_out.load64(addressFor(data-&gt;machineLocal)));
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    void compilePutLocal()
</del><ins>+    void compilePutStack()
</ins><span class="cx">     {
</span><del>-        VariableAccessData* variable = m_node-&gt;variableAccessData();
-        switch (variable-&gt;flushFormat()) {
</del><ins>+        StackAccessData* data = m_node-&gt;stackAccessData();
+        switch (data-&gt;format) {
</ins><span class="cx">         case FlushedJSValue:
</span><span class="cx">         case FlushedArguments: {
</span><span class="cx">             LValue value = lowJSValue(m_node-&gt;child1());
</span><del>-            m_out.store64(value, addressFor(variable-&gt;machineLocal()));
</del><ins>+            m_out.store64(value, addressFor(data-&gt;machineLocal));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case FlushedDouble: {
</span><span class="cx">             LValue value = lowDouble(m_node-&gt;child1());
</span><del>-            m_out.storeDouble(value, addressFor(variable-&gt;machineLocal()));
</del><ins>+            m_out.storeDouble(value, addressFor(data-&gt;machineLocal));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case FlushedInt32: {
</span><span class="cx">             LValue value = lowInt32(m_node-&gt;child1());
</span><del>-            m_out.store32(value, payloadFor(variable-&gt;machineLocal()));
</del><ins>+            m_out.store32(value, payloadFor(data-&gt;machineLocal));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case FlushedInt52: {
</span><span class="cx">             LValue value = lowInt52(m_node-&gt;child1());
</span><del>-            m_out.store64(value, addressFor(variable-&gt;machineLocal()));
</del><ins>+            m_out.store64(value, addressFor(data-&gt;machineLocal));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="cx">         case FlushedCell: {
</span><span class="cx">             LValue value = lowCell(m_node-&gt;child1());
</span><del>-            m_out.store64(value, addressFor(variable-&gt;machineLocal()));
</del><ins>+            m_out.store64(value, addressFor(data-&gt;machineLocal));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><span class="lines">@@ -1124,7 +1127,7 @@
</span><span class="cx">             speculateBoolean(m_node-&gt;child1());
</span><span class="cx">             m_out.store64(
</span><span class="cx">                 lowJSValue(m_node-&gt;child1(), ManualOperandSpeculation),
</span><del>-                addressFor(variable-&gt;machineLocal()));
</del><ins>+                addressFor(data-&gt;machineLocal));
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLOSRExith"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h (180690 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h        2015-02-26 19:44:08 UTC (rev 180690)
+++ trunk/Source/JavaScriptCore/ftl/FTLOSRExit.h        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -45,14 +45,12 @@
</span><span class="cx"> 
</span><span class="cx"> // Tracks one OSR exit site within the FTL JIT. OSR exit in FTL works by deconstructing
</span><span class="cx"> // the crazy that is OSR down to simple SSA CFG primitives that any compiler backend
</span><del>-// (including of course LLVM) can grok and do meaningful things to. Except for
-// watchpoint-based exits, which haven't yet been implemented (see webkit.org/b/113647),
-// an exit is just a conditional branch in the emitted code where one destination is the
-// continuation and the other is a basic block that performs a no-return tail-call to an
-// exit thunk. This thunk takes as its arguments the live non-constant
-// not-already-accounted-for bytecode state. To appreciate how this works consider the
-// following JavaScript program, and its lowering down to LLVM IR including the relevant
-// exits:
</del><ins>+// (including of course LLVM) can grok and do meaningful things to. An exit is just a
+// conditional branch in the emitted code where one destination is the continuation and
+// the other is a basic block that performs a no-return tail-call to an  exit thunk.
+// This thunk takes as its arguments the live non-constant not-already-accounted-for
+// bytecode state. To appreciate how this works consider the following JavaScript
+// program, and its lowering down to LLVM IR including the relevant exits:
</ins><span class="cx"> //
</span><span class="cx"> // function foo(o) {
</span><span class="cx"> //     var a = o.a; // predicted int
</span><span class="lines">@@ -66,10 +64,10 @@
</span><span class="cx"> //
</span><span class="cx"> // BitOr(Check:Int32:@a, Int32:5)
</span><span class="cx"> //
</span><del>-// Where @a is the node for the GetLocal node that gets the value of the 'a' variable.
-// Conceptually, this node can be further broken down to the following (note that this
-// particular lowering never actually happens - we skip this step and go straight to
-// LLVM IR - but it's still useful to see this):
</del><ins>+// Where @a is the node for the value of the 'a' variable. Conceptually, this node can
+// be further broken down to the following (note that this particular lowering never
+// actually happens - we skip this step and go straight to LLVM IR - but it's still
+// useful to see this):
</ins><span class="cx"> //
</span><span class="cx"> // exitIf(@a is not int32);
</span><span class="cx"> // continuation;
</span><span class="lines">@@ -124,22 +122,12 @@
</span><span class="cx"> //   arguments into argument position), the backend could choose to simply inform us
</span><span class="cx"> //   where it had placed the arguments and expect the callee (i.e. the exit thunk) to
</span><span class="cx"> //   figure it out from there. It could also tell us what we need to do to pop stack,
</span><del>-//   although again, it doesn't have to; it could just emit that code normally. Though
-//   we don't support this yet, we could; the only thing that would change on our end
-//   is that we'd need feedback from the backend about the location of the arguments
-//   and a description of the things that need to be done to pop stack. This would
-//   involve switching the m_values array to use something more akin to ValueRecovery
-//   rather than the current ExitValue, albeit possibly with some hacks to better
-//   understand the kinds of places where the LLVM backend would put values.
</del><ins>+//   although again, it doesn't have to; it could just emit that code normally. We do
+//   all of these things through the patchpoint/stackmap LLVM intrinsics.
</ins><span class="cx"> //
</span><span class="cx"> // - It could be extended to allow the backend to do its own exit hoisting, by using
</span><span class="cx"> //   intrinsics (or meta-data, or something) to inform the backend that it's safe to
</span><span class="cx"> //   make the predicate passed to 'exitIf()' more truthy.
</span><del>-//
-// - It could be extended to support watchpoints (see webkit.org/b/113647) by making
-//   the predicate passed to 'exitIf()' be an intrinsic that the backend knows to be
-//   true at compile-time. The backend could then turn the conditional branch into a
-//   replaceable jump, much like the DFG does.
</del><span class="cx"> 
</span><span class="cx"> struct OSRExit : public DFG::OSRExitBase {
</span><span class="cx">     OSRExit(
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressmanysunkenlocalsjs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/many-sunken-locals.js (0 => 180691)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/many-sunken-locals.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/many-sunken-locals.js        2015-02-26 19:51:52 UTC (rev 180691)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+function foo(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) {
+    if (a)
+        return 42;
+    else
+        return 63;
+}
+
+function bar(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) {
+    return foo(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z);
+}
+
+function baz(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) {
+    return bar(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z);
+}
+
+function fuzz(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) {
+    return baz(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z);
+}
+
+function buzz(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z) {
+    return fuzz(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z);
+}
+
+noInline(buzz);
+
+for (var i = 0; i &lt; 10000; ++i)
+    buzz(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26);
</ins></span></pre>
</div>
</div>

</body>
</html>