<!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>[180160] 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/180160">180160</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-02-16 11:27:37 -0800 (Mon, 16 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>DFG SSA should use GetLocal for arguments, and the GetArgument node type should be removed
https://bugs.webkit.org/show_bug.cgi?id=141623

Reviewed by Oliver Hunt.
        
During development of https://bugs.webkit.org/show_bug.cgi?id=141332, I realized that I
needed to use GetArgument for loading something that has magically already appeared on the
stack, so currently trunk sort of allows this. But then I realized three things:
        
- A GetArgument with a non-JSValue flush format means speculating that the value on the
  stack obeys that format, rather than just assuming that that it already has that format.
  In bug 141332, I want it to assume rather than speculate. That also happens to be more
  intuitive; I don't think I was wrong to expect that.
        
- The node I really want is GetLocal. I'm just getting the value of the local and I don't
  want to do anything else.
        
- Maybe it would be easier if we just used GetLocal for all of the cases where we currently
  use GetArgument.
        
This changes the FTL to do argument speculations in the prologue just like the DFG does.
This brings some consistency to our system, and allows us to get rid of the GetArgument
node. The speculations that the FTL must do are now made explicit in the m_argumentFormats
vector in DFG::Graph. This has natural DCE behavior: even if all uses of the argument are
dead we will still speculate. We already have safeguards to ensure we only speculate if
there are uses that benefit from speculation (which is a much more conservative criterion
than DCE).
        
* dfg/DFGAbstractInterpreterInlines.h:
(JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
* dfg/DFGClobberize.h:
(JSC::DFG::clobberize):
* dfg/DFGDCEPhase.cpp:
(JSC::DFG::DCEPhase::run):
* dfg/DFGDoesGC.cpp:
(JSC::DFG::doesGC):
* dfg/DFGFixupPhase.cpp:
(JSC::DFG::FixupPhase::fixupNode):
* dfg/DFGFlushFormat.h:
(JSC::DFG::typeFilterFor):
* dfg/DFGGraph.cpp:
(JSC::DFG::Graph::dump):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::valueProfileFor):
(JSC::DFG::Graph::methodOfGettingAValueProfileFor):
* dfg/DFGInPlaceAbstractState.cpp:
(JSC::DFG::InPlaceAbstractState::initialize):
* dfg/DFGNode.cpp:
(JSC::DFG::Node::hasVariableAccessData):
* dfg/DFGNodeType.h:
* dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
(JSC::DFG::OSRAvailabilityAnalysisPhase::run):
(JSC::DFG::LocalOSRAvailabilityCalculator::executeNode):
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGPutLocalSinkingPhase.cpp:
* 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):
* ftl/FTLCapabilities.cpp:
(JSC::FTL::canCompile):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::lower):
(JSC::FTL::LowerDFGToLLVM::compileNode):
(JSC::FTL::LowerDFGToLLVM::compileGetLocal):
(JSC::FTL::LowerDFGToLLVM::compileGetArgument): Deleted.
* tests/stress/dead-speculating-argument-use.js: Added.
(foo):
(o.valueOf):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</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="#trunkSourceJavaScriptCoredfgDFGDCEPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.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="#trunkSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp">trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGNodecpp">trunk/Source/JavaScriptCore/dfg/DFGNode.cpp</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="#trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.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="#trunkSourceJavaScriptCoreftlFTLCapabilitiescpp">trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoretestsstressdeadspeculatingargumentusejs">trunk/Source/JavaScriptCore/tests/stress/dead-speculating-argument-use.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -1,3 +1,80 @@
</span><ins>+2015-02-16  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG SSA should use GetLocal for arguments, and the GetArgument node type should be removed
+        https://bugs.webkit.org/show_bug.cgi?id=141623
+
+        Reviewed by Oliver Hunt.
+        
+        During development of https://bugs.webkit.org/show_bug.cgi?id=141332, I realized that I
+        needed to use GetArgument for loading something that has magically already appeared on the
+        stack, so currently trunk sort of allows this. But then I realized three things:
+        
+        - A GetArgument with a non-JSValue flush format means speculating that the value on the
+          stack obeys that format, rather than just assuming that that it already has that format.
+          In bug 141332, I want it to assume rather than speculate. That also happens to be more
+          intuitive; I don't think I was wrong to expect that.
+        
+        - The node I really want is GetLocal. I'm just getting the value of the local and I don't
+          want to do anything else.
+        
+        - Maybe it would be easier if we just used GetLocal for all of the cases where we currently
+          use GetArgument.
+        
+        This changes the FTL to do argument speculations in the prologue just like the DFG does.
+        This brings some consistency to our system, and allows us to get rid of the GetArgument
+        node. The speculations that the FTL must do are now made explicit in the m_argumentFormats
+        vector in DFG::Graph. This has natural DCE behavior: even if all uses of the argument are
+        dead we will still speculate. We already have safeguards to ensure we only speculate if
+        there are uses that benefit from speculation (which is a much more conservative criterion
+        than DCE).
+        
+        * dfg/DFGAbstractInterpreterInlines.h:
+        (JSC::DFG::AbstractInterpreter&lt;AbstractStateType&gt;::executeEffects):
+        * dfg/DFGClobberize.h:
+        (JSC::DFG::clobberize):
+        * dfg/DFGDCEPhase.cpp:
+        (JSC::DFG::DCEPhase::run):
+        * dfg/DFGDoesGC.cpp:
+        (JSC::DFG::doesGC):
+        * dfg/DFGFixupPhase.cpp:
+        (JSC::DFG::FixupPhase::fixupNode):
+        * dfg/DFGFlushFormat.h:
+        (JSC::DFG::typeFilterFor):
+        * dfg/DFGGraph.cpp:
+        (JSC::DFG::Graph::dump):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::valueProfileFor):
+        (JSC::DFG::Graph::methodOfGettingAValueProfileFor):
+        * dfg/DFGInPlaceAbstractState.cpp:
+        (JSC::DFG::InPlaceAbstractState::initialize):
+        * dfg/DFGNode.cpp:
+        (JSC::DFG::Node::hasVariableAccessData):
+        * dfg/DFGNodeType.h:
+        * dfg/DFGOSRAvailabilityAnalysisPhase.cpp:
+        (JSC::DFG::OSRAvailabilityAnalysisPhase::run):
+        (JSC::DFG::LocalOSRAvailabilityCalculator::executeNode):
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGPutLocalSinkingPhase.cpp:
+        * 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):
+        * ftl/FTLCapabilities.cpp:
+        (JSC::FTL::canCompile):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::lower):
+        (JSC::FTL::LowerDFGToLLVM::compileNode):
+        (JSC::FTL::LowerDFGToLLVM::compileGetLocal):
+        (JSC::FTL::LowerDFGToLLVM::compileGetArgument): Deleted.
+        * tests/stress/dead-speculating-argument-use.js: Added.
+        (foo):
+        (o.valueOf):
+
</ins><span class="cx"> 2015-02-15  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rare case profiling should actually work
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGAbstractInterpreterInlinesh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -141,18 +141,6 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx">         
</span><del>-    case GetArgument: {
-        ASSERT(m_graph.m_form == SSA);
-        VariableAccessData* variable = node-&gt;variableAccessData();
-        AbstractValue&amp; value = m_state.variables().operand(variable-&gt;local().offset());
-        ASSERT(value.isHeapTop());
-        FiltrationResult result =
-            value.filter(typeFilterFor(useKindFor(variable-&gt;flushFormat())));
-        ASSERT_UNUSED(result, result == FiltrationOK);
-        forNode(node) = value;
-        break;
-    }
-        
</del><span class="cx">     case ExtractOSREntryLocal: {
</span><span class="cx">         if (!(node-&gt;unlinkedLocal().isArgument())
</span><span class="cx">             &amp;&amp; m_graph.m_lazyVars.get(node-&gt;unlinkedLocal().toLocal())) {
</span><span class="lines">@@ -170,6 +158,8 @@
</span><span class="cx">     case GetLocal: {
</span><span class="cx">         VariableAccessData* variableAccessData = node-&gt;variableAccessData();
</span><span class="cx">         AbstractValue value = m_state.variables().operand(variableAccessData-&gt;local().offset());
</span><ins>+        // The value in the local should already be checked.
+        DFG_ASSERT(m_graph, node, value.isType(typeFilterFor(variableAccessData-&gt;flushFormat())));
</ins><span class="cx">         if (value.value())
</span><span class="cx">             m_state.setFoundConstants(true);
</span><span class="cx">         forNode(node) = value;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGClobberizeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGClobberize.h (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGClobberize.h        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -391,7 +391,6 @@
</span><span class="cx">         return;
</span><span class="cx">         
</span><span class="cx">     case GetLocal:
</span><del>-    case GetArgument:
</del><span class="cx">         read(AbstractHeap(Variables, node-&gt;local()));
</span><span class="cx">         def(HeapLocation(VariableLoc, AbstractHeap(Variables, node-&gt;local())), node);
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGDCEPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGDCEPhase.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -53,12 +53,21 @@
</span><span class="cx">         if (m_graph.m_form == SSA) {
</span><span class="cx">             for (BasicBlock* block : m_graph.blocksInPreOrder())
</span><span class="cx">                 fixupBlock(block);
</span><ins>+            
+            // This is like cleanVariables, but has a much simpler approach to GetLocal.
+            for (unsigned i = m_graph.m_arguments.size(); i--;) {
+                Node* node = m_graph.m_arguments[i];
+                if (!node)
+                    continue;
+                if (node-&gt;op() != Phantom &amp;&amp; node-&gt;op() != Check &amp;&amp; node-&gt;shouldGenerate())
+                    continue;
+                m_graph.m_arguments[i] = nullptr;
+            }
</ins><span class="cx">         } else {
</span><span class="cx">             RELEASE_ASSERT(m_graph.m_form == ThreadedCPS);
</span><span class="cx">             
</span><span class="cx">             for (BlockIndex blockIndex = 0; blockIndex &lt; m_graph.numBlocks(); ++blockIndex)
</span><span class="cx">                 fixupBlock(m_graph.block(blockIndex));
</span><del>-            
</del><span class="cx">             cleanVariables(m_graph.m_arguments);
</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 (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -53,7 +53,6 @@
</span><span class="cx">     case SetLocal:
</span><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><del>-    case GetArgument:
</del><span class="cx">     case Phantom:
</span><span class="cx">     case HardPhantom:
</span><span class="cx">     case Upsilon:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFixupPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -1033,7 +1033,6 @@
</span><span class="cx">         case GetArrayLength:
</span><span class="cx">         case Phi:
</span><span class="cx">         case Upsilon:
</span><del>-        case GetArgument:
</del><span class="cx">         case GetIndexedPropertyStorage:
</span><span class="cx">         case GetTypedArrayByteOffset:
</span><span class="cx">         case LastNodeType:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFlushFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -93,6 +93,11 @@
</span><span class="cx">     return UntypedUse;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline SpeculatedType typeFilterFor(FlushFormat format)
+{
+    return typeFilterFor(useKindFor(format));
+}
+
</ins><span class="cx"> inline DataFormat dataFormatFor(FlushFormat format)
</span><span class="cx"> {
</span><span class="cx">     switch (format) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -425,6 +425,10 @@
</span><span class="cx">     out.print(&quot;\n&quot;);
</span><span class="cx">     out.print(&quot;DFG for &quot;, CodeBlockWithJITType(m_codeBlock, JITCode::DFGJIT), &quot;:\n&quot;);
</span><span class="cx">     out.print(&quot;  Fixpoint state: &quot;, m_fixpointState, &quot;; Form: &quot;, m_form, &quot;; Unification state: &quot;, m_unificationState, &quot;; Ref count state: &quot;, m_refCountState, &quot;\n&quot;);
</span><ins>+    if (m_form == SSA)
+        out.print(&quot;  Argument formats: &quot;, listDump(m_argumentFormats), &quot;\n&quot;);
+    else
+        out.print(&quot;  Arguments: &quot;, listDump(m_arguments), &quot;\n&quot;);
</ins><span class="cx">     out.print(&quot;\n&quot;);
</span><span class="cx">     
</span><span class="cx">     Node* lastNode = 0;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGGraphh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGGraph.h (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGGraph.h        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -475,21 +475,19 @@
</span><span class="cx">     ValueProfile* valueProfileFor(Node* node)
</span><span class="cx">     {
</span><span class="cx">         if (!node)
</span><del>-            return 0;
</del><ins>+            return nullptr;
</ins><span class="cx">         
</span><span class="cx">         CodeBlock* profiledBlock = baselineCodeBlockFor(node-&gt;origin.semantic);
</span><span class="cx">         
</span><del>-        if (node-&gt;op() == GetArgument)
-            return profiledBlock-&gt;valueProfileForArgument(node-&gt;local().toArgument());
-        
</del><span class="cx">         if (node-&gt;hasLocal(*this)) {
</span><del>-            if (m_form == SSA)
-                return 0;
</del><span class="cx">             if (!node-&gt;local().isArgument())
</span><span class="cx">                 return 0;
</span><span class="cx">             int argument = node-&gt;local().toArgument();
</span><del>-            if (node-&gt;variableAccessData() != m_arguments[argument]-&gt;variableAccessData())
-                return 0;
</del><ins>+            Node* argumentNode = m_arguments[argument];
+            if (!argumentNode)
+                return nullptr;
+            if (node-&gt;variableAccessData() != argumentNode-&gt;variableAccessData())
+                return nullptr;
</ins><span class="cx">             return profiledBlock-&gt;valueProfileForArgument(argument);
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="lines">@@ -504,16 +502,19 @@
</span><span class="cx">         if (!node)
</span><span class="cx">             return MethodOfGettingAValueProfile();
</span><span class="cx">         
</span><del>-        CodeBlock* profiledBlock = baselineCodeBlockFor(node-&gt;origin.semantic);
</del><ins>+        if (ValueProfile* valueProfile = valueProfileFor(node))
+            return MethodOfGettingAValueProfile(valueProfile);
</ins><span class="cx">         
</span><span class="cx">         if (node-&gt;op() == GetLocal) {
</span><ins>+            CodeBlock* profiledBlock = baselineCodeBlockFor(node-&gt;origin.semantic);
+        
</ins><span class="cx">             return MethodOfGettingAValueProfile::fromLazyOperand(
</span><span class="cx">                 profiledBlock,
</span><span class="cx">                 LazyOperandValueProfileKey(
</span><span class="cx">                     node-&gt;origin.semantic.bytecodeIndex, node-&gt;local()));
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        return MethodOfGettingAValueProfile(valueProfileFor(node));
</del><ins>+        return MethodOfGettingAValueProfile();
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     bool usesArguments() const
</span><span class="lines">@@ -811,7 +812,37 @@
</span><span class="cx">     Bag&lt;FrozenValue&gt; m_frozenValues;
</span><span class="cx">     
</span><span class="cx">     Bag&lt;StorageAccessData&gt; m_storageAccessData;
</span><ins>+    
+    // In CPS, this is all of the SetArgument nodes for the arguments in the machine code block
+    // that survived DCE. All of them except maybe &quot;this&quot; will survive DCE, because of the Flush
+    // nodes.
+    //
+    // In SSA, this is all of the GetLocal nodes for the arguments in the machine code block that
+    // may have some speculation in the prologue and survived DCE. Note that to get the speculation
+    // for an argument in SSA, you must use m_argumentFormats, since we still have to speculate
+    // even if the argument got killed. For example:
+    //
+    //     function foo(x) {
+    //        var tmp = x + 1;
+    //     }
+    //
+    // Assume that x is always int during profiling. The ArithAdd for &quot;x + 1&quot; will be dead and will
+    // have a proven check for the edge to &quot;x&quot;. So, we will not insert a Check node and we will
+    // kill the GetLocal for &quot;x&quot;. But, we must do the int check in the progolue, because that's the
+    // thing we used to allow DCE of ArithAdd. Otherwise the add could be impure:
+    //
+    //     var o = {
+    //         valueOf: function() { do side effects; }
+    //     };
+    //     foo(o);
+    //
+    // If we DCE the ArithAdd and we remove the int check on x, then this won't do the side
+    // effects.
</ins><span class="cx">     Vector&lt;Node*, 8&gt; m_arguments;
</span><ins>+    
+    // In CPS, this is meaningless. In SSA, this is the argument speculation that we've locked in.
+    Vector&lt;FlushFormat&gt; m_argumentFormats;
+    
</ins><span class="cx">     SegmentedVector&lt;VariableAccessData, 16&gt; m_variableAccessData;
</span><span class="cx">     SegmentedVector&lt;ArgumentPosition, 8&gt; m_argumentPositions;
</span><span class="cx">     SegmentedVector&lt;StructureSet, 16&gt; m_structureSet;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGInPlaceAbstractStatecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGInPlaceAbstractState.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -96,28 +96,37 @@
</span><span class="cx">     root-&gt;cfaStructureClobberStateAtTail = StructuresAreWatched;
</span><span class="cx">     for (size_t i = 0; i &lt; root-&gt;valuesAtHead.numberOfArguments(); ++i) {
</span><span class="cx">         root-&gt;valuesAtTail.argument(i).clear();
</span><del>-        if (m_graph.m_form == SSA) {
-            root-&gt;valuesAtHead.argument(i).makeHeapTop();
-            continue;
</del><ins>+
+        FlushFormat format;
+        if (m_graph.m_form == SSA)
+            format = m_graph.m_argumentFormats[i];
+        else {
+            Node* node = m_graph.m_arguments[i];
+            if (!node)
+                format = FlushedJSValue;
+            else {
+                ASSERT(node-&gt;op() == SetArgument);
+                format = node-&gt;variableAccessData()-&gt;flushFormat();
+            }
</ins><span class="cx">         }
</span><span class="cx">         
</span><del>-        Node* node = root-&gt;variablesAtHead.argument(i);
-        ASSERT(node-&gt;op() == SetArgument);
-        if (!node-&gt;variableAccessData()-&gt;shouldUnboxIfPossible()) {
-            root-&gt;valuesAtHead.argument(i).makeHeapTop();
-            continue;
-        }
-        
-        SpeculatedType prediction =
-            node-&gt;variableAccessData()-&gt;argumentAwarePrediction();
-        if (isInt32Speculation(prediction))
</del><ins>+        switch (format) {
+        case FlushedInt32:
</ins><span class="cx">             root-&gt;valuesAtHead.argument(i).setType(SpecInt32);
</span><del>-        else if (isBooleanSpeculation(prediction))
</del><ins>+            break;
+        case FlushedBoolean:
</ins><span class="cx">             root-&gt;valuesAtHead.argument(i).setType(SpecBoolean);
</span><del>-        else if (isCellSpeculation(prediction))
</del><ins>+            break;
+        case FlushedCell:
</ins><span class="cx">             root-&gt;valuesAtHead.argument(i).setType(SpecCell);
</span><del>-        else
</del><ins>+            break;
+        case FlushedJSValue:
</ins><span class="cx">             root-&gt;valuesAtHead.argument(i).makeHeapTop();
</span><ins>+            break;
+        default:
+            DFG_CRASH(m_graph, nullptr, &quot;Bad flush format for argument&quot;);
+            break;
+        }
</ins><span class="cx">     }
</span><span class="cx">     for (size_t i = 0; i &lt; root-&gt;valuesAtHead.numberOfLocals(); ++i) {
</span><span class="cx">         Node* node = root-&gt;variablesAtHead.local(i);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNode.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGNode.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -74,7 +74,6 @@
</span><span class="cx">     case Phi:
</span><span class="cx">         return graph.m_form != SSA;
</span><span class="cx">     case GetLocal:
</span><del>-    case GetArgument:
</del><span class="cx">     case SetLocal:
</span><span class="cx">     case SetArgument:
</span><span class="cx">     case Flush:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGNodeTypeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGNodeType.h (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGNodeType.h        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -61,7 +61,6 @@
</span><span class="cx">     macro(KillLocal, NodeMustGenerate) \
</span><span class="cx">     macro(MovHint, 0) \
</span><span class="cx">     macro(ZombieHint, 0) \
</span><del>-    macro(GetArgument, NodeResultJS | NodeMustGenerate) \
</del><span class="cx">     macro(Phantom, NodeMustGenerate) \
</span><span class="cx">     macro(HardPhantom, NodeMustGenerate) /* Like Phantom, but we never remove any of its children. */ \
</span><span class="cx">     macro(Check, NodeMustGenerate) /* Used if we want just a type check but not liveness. Non-checking uses will be removed. */\
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGOSRAvailabilityAnalysisPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGOSRAvailabilityAnalysisPhase.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -58,10 +58,11 @@
</span><span class="cx">         
</span><span class="cx">         BasicBlock* root = m_graph.block(0);
</span><span class="cx">         root-&gt;ssa-&gt;availabilityAtHead.m_locals.fill(Availability::unavailable());
</span><del>-        for (unsigned argument = root-&gt;ssa-&gt;availabilityAtHead.m_locals.numberOfArguments(); argument--;) {
-            root-&gt;ssa-&gt;availabilityAtHead.m_locals.argument(argument) =
-                Availability::unavailable().withFlush(
-                    FlushedAt(FlushedJSValue, virtualRegisterForArgument(argument)));
</del><ins>+        for (unsigned argument = m_graph.m_argumentFormats.size(); argument--;) {
+            FlushedAt flushedAt = FlushedAt(
+                m_graph.m_argumentFormats[argument],
+                virtualRegisterForArgument(argument));
+            root-&gt;ssa-&gt;availabilityAtHead.m_locals.argument(argument) = Availability(flushedAt);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         // This could be made more efficient by processing blocks in reverse postorder.
</span><span class="lines">@@ -138,7 +139,7 @@
</span><span class="cx">         break;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    case GetArgument: {
</del><ins>+    case GetLocal: {
</ins><span class="cx">         VariableAccessData* variable = node-&gt;variableAccessData();
</span><span class="cx">         m_availability.m_locals.operand(variable-&gt;local()) =
</span><span class="cx">             Availability(node, variable-&gt;flushedAt());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPredictionPropagationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -552,7 +552,6 @@
</span><span class="cx">             break;
</span><span class="cx">             
</span><span class="cx">         case Upsilon:
</span><del>-        case GetArgument:
</del><span class="cx">             // These don't get inserted until we go into SSA.
</span><span class="cx">             RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">             break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGPutLocalSinkingPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGPutLocalSinkingPhase.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -371,7 +371,7 @@
</span><span class="cx">                     ssaCalculator.newDef(
</span><span class="cx">                         operandToVariable.operand(node-&gt;local()), block, node-&gt;child1().node());
</span><span class="cx">                     break;
</span><del>-                case GetArgument:
</del><ins>+                case GetLocal:
</ins><span class="cx">                     ssaCalculator.newDef(
</span><span class="cx">                         operandToVariable.operand(node-&gt;local()), block, node);
</span><span class="cx">                     break;
</span><span class="lines">@@ -450,13 +450,6 @@
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><del>-                case GetArgument: {
-                    VariableAccessData* variable = node-&gt;variableAccessData();
-                    VirtualRegister operand = variable-&gt;local();
-                    mapping.operand(operand) = node;
-                    break;
-                }
-                    
</del><span class="cx">                 case KillLocal: {
</span><span class="cx">                     deferred.operand(node-&gt;unlinkedLocal()) = VariableDeferral();
</span><span class="cx">                     break;
</span><span class="lines">@@ -489,6 +482,16 @@
</span><span class="cx">                     preciseLocalClobberize(
</span><span class="cx">                         m_graph, node, escapeHandler, escapeHandler,
</span><span class="cx">                         [&amp;] (VirtualRegister, Node*) { });
</span><ins>+                    
+                    // 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;
+                    }
</ins><span class="cx">                     break;
</span><span class="cx">                 } }
</span><span class="cx">             }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSSAConversionPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGSSAConversionPhase.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -73,7 +73,7 @@
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         // Find all SetLocals and create Defs for them. We handle SetArgument by creating a
</span><del>-        // GetArgument.
</del><ins>+        // GetLocal, and recording the flush format.
</ins><span class="cx">         for (BlockIndex blockIndex = m_graph.numBlocks(); blockIndex--;) {
</span><span class="cx">             BasicBlock* block = m_graph.block(blockIndex);
</span><span class="cx">             if (!block)
</span><span class="lines">@@ -97,7 +97,9 @@
</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>-                        GetArgument, node-&gt;origin, OpInfo(node-&gt;variableAccessData()));
</del><ins>+                        GetLocal, node-&gt;origin, OpInfo(node-&gt;variableAccessData()));
+                    m_argumentGetters.add(childNode);
+                    m_argumentMapping.add(node, childNode);
</ins><span class="cx">                 }
</span><span class="cx">                 
</span><span class="cx">                 m_calculator.newDef(
</span><span class="lines">@@ -198,14 +200,14 @@
</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 GetArgument nodes have already been inserted.
</del><ins>+        //   - SetArgument is removed. Note that GetLocal 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 GetArgument nodes for extracting the values of arguments. So, we
</del><ins>+            // instead we have GetLocal 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">@@ -293,9 +295,15 @@
</span><span class="cx">                 }
</span><span class="cx">                     
</span><span class="cx">                 case GetLocal: {
</span><ins>+                    VariableAccessData* variable = node-&gt;variableAccessData();
+                    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;
+                    }
</ins><span class="cx">                     node-&gt;children.reset();
</span><span class="cx">                     
</span><del>-                    VariableAccessData* variable = node-&gt;variableAccessData();
</del><span class="cx">                     if (variable-&gt;isCaptured())
</span><span class="cx">                         break;
</span><span class="cx">                     
</span><span class="lines">@@ -337,15 +345,6 @@
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><del>-                case GetArgument: {
-                    VariableAccessData* variable = node-&gt;variableAccessData();
-                    ASSERT(!variable-&gt;isCaptured());
-                    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">                 default:
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="lines">@@ -392,7 +391,21 @@
</span><span class="cx">             block-&gt;ssa = std::make_unique&lt;BasicBlock::SSAData&gt;(block);
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        m_graph.m_arguments.clear();
</del><ins>+        m_graph.m_argumentFormats.resize(m_graph.m_arguments.size());
+        for (unsigned i = m_graph.m_arguments.size(); i--;) {
+            FlushFormat format = FlushedJSValue;
+
+            Node* node = m_argumentMapping.get(m_graph.m_arguments[i]);
+
+            // m_argumentMapping.get could return null for a captured local. That's fine. We only
+            // track the argument loads of those arguments for which we speculate type. We don't
+            // speculate type for captured arguments.
+            if (node)
+                format = node-&gt;variableAccessData()-&gt;flushFormat();
+            
+            m_graph.m_argumentFormats[i] = format;
+            m_graph.m_arguments[i] = node; // Record the load that loads the arguments for the benefit of exit profiling.
+        }
</ins><span class="cx">         
</span><span class="cx">         m_graph.m_form = SSA;
</span><span class="cx"> 
</span><span class="lines">@@ -408,6 +421,8 @@
</span><span class="cx">     SSACalculator m_calculator;
</span><span class="cx">     InsertionSet m_insertionSet;
</span><span class="cx">     HashMap&lt;VariableAccessData*, SSACalculator::Variable*&gt; m_ssaVariableForVariable;
</span><ins>+    HashMap&lt;Node*, Node*&gt; m_argumentMapping;
+    HashSet&lt;Node*&gt; m_argumentGetters;
</ins><span class="cx">     Vector&lt;VariableAccessData*&gt; m_variableForSSAIndex;
</span><span class="cx"> };
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSafeToExecuteh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -122,7 +122,6 @@
</span><span class="cx">     case KillLocal:
</span><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><del>-    case GetArgument:
</del><span class="cx">     case Phantom:
</span><span class="cx">     case HardPhantom:
</span><span class="cx">     case Upsilon:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -4898,7 +4898,6 @@
</span><span class="cx">     case LastNodeType:
</span><span class="cx">     case Phi:
</span><span class="cx">     case Upsilon:
</span><del>-    case GetArgument:
</del><span class="cx">     case ExtractOSREntryLocal:
</span><span class="cx">     case CheckTierUpInLoop:
</span><span class="cx">     case CheckTierUpAtReturn:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -4993,7 +4993,6 @@
</span><span class="cx">     case LastNodeType:
</span><span class="cx">     case Phi:
</span><span class="cx">     case Upsilon:
</span><del>-    case GetArgument:
</del><span class="cx">     case ExtractOSREntryLocal:
</span><span class="cx">     case CheckInBounds:
</span><span class="cx">     case ArithIMul:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLCapabilitiescpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -51,7 +51,6 @@
</span><span class="cx">     case KillLocal:
</span><span class="cx">     case MovHint:
</span><span class="cx">     case ZombieHint:
</span><del>-    case GetArgument:
</del><span class="cx">     case Phantom:
</span><span class="cx">     case HardPhantom:
</span><span class="cx">     case Flush:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (180159 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-02-16 19:05:06 UTC (rev 180159)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -135,6 +135,8 @@
</span><span class="cx">         m_prologue = FTL_NEW_BLOCK(m_out, (&quot;Prologue&quot;));
</span><span class="cx">         LBasicBlock stackOverflow = FTL_NEW_BLOCK(m_out, (&quot;Stack overflow&quot;));
</span><span class="cx">         m_handleExceptions = FTL_NEW_BLOCK(m_out, (&quot;Handle Exceptions&quot;));
</span><ins>+        
+        LBasicBlock checkArguments = FTL_NEW_BLOCK(m_out, (&quot;Check arguments&quot;));
</ins><span class="cx"> 
</span><span class="cx">         for (BlockIndex blockIndex = 0; blockIndex &lt; m_graph.numBlocks(); ++blockIndex) {
</span><span class="cx">             m_highBlock = m_graph.block(blockIndex);
</span><span class="lines">@@ -193,7 +195,7 @@
</span><span class="cx">         m_out.storePtr(m_out.constIntPtr(codeBlock()), addressFor(JSStack::CodeBlock));
</span><span class="cx">         
</span><span class="cx">         m_out.branch(
</span><del>-            didOverflowStack(), rarely(stackOverflow), usually(lowBlock(m_graph.block(0))));
</del><ins>+            didOverflowStack(), rarely(stackOverflow), usually(checkArguments));
</ins><span class="cx">         
</span><span class="cx">         m_out.appendTo(stackOverflow, m_handleExceptions);
</span><span class="cx">         m_out.call(m_out.operation(operationThrowStackOverflowError), m_callFrame, m_out.constIntPtr(codeBlock()));
</span><span class="lines">@@ -203,13 +205,58 @@
</span><span class="cx">             m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
</span><span class="cx">         m_out.unreachable();
</span><span class="cx">         
</span><del>-        m_out.appendTo(m_handleExceptions, lowBlock(m_graph.block(0)));
</del><ins>+        m_out.appendTo(m_handleExceptions, checkArguments);
</ins><span class="cx">         m_ftlState.handleExceptionStackmapID = m_stackmapIDs++;
</span><span class="cx">         m_out.call(
</span><span class="cx">             m_out.stackmapIntrinsic(), m_out.constInt64(m_ftlState.handleExceptionStackmapID),
</span><span class="cx">             m_out.constInt32(MacroAssembler::maxJumpReplacementSize()));
</span><span class="cx">         m_out.unreachable();
</span><del>-
</del><ins>+        
+        m_out.appendTo(checkArguments, lowBlock(m_graph.block(0)));
+        availabilityMap().clear();
+        availabilityMap().m_locals = Operands&lt;Availability&gt;(codeBlock()-&gt;numParameters(), 0);
+        for (unsigned i = codeBlock()-&gt;numParameters(); i--;) {
+            availabilityMap().m_locals.argument(i) =
+                Availability(FlushedAt(FlushedJSValue, virtualRegisterForArgument(i)));
+        }
+        m_codeOriginForExitTarget = CodeOrigin(0);
+        m_codeOriginForExitProfile = CodeOrigin(0);
+        m_node = nullptr;
+        for (unsigned i = codeBlock()-&gt;numParameters(); i--;) {
+            Node* node = m_graph.m_arguments[i];
+            VirtualRegister operand = virtualRegisterForArgument(i);
+            
+            LValue jsValue = m_out.load64(addressFor(operand));
+            
+            if (node) {
+                DFG_ASSERT(m_graph, node, operand == node-&gt;variableAccessData()-&gt;machineLocal());
+                
+                // This is a hack, but it's an effective one. It allows us to do CSE on the
+                // primordial load of arguments. This assumes that the GetLocal that got put in
+                // place of the original SetArgument doesn't have any effects before it. This
+                // should hold true.
+                m_loadedArgumentValues.add(node, jsValue);
+            }
+            
+            switch (m_graph.m_argumentFormats[i]) {
+            case FlushedInt32:
+                speculate(BadType, jsValueValue(jsValue), node, isNotInt32(jsValue));
+                break;
+            case FlushedBoolean:
+                speculate(BadType, jsValueValue(jsValue), node, isNotBoolean(jsValue));
+                break;
+            case FlushedCell:
+                speculate(BadType, jsValueValue(jsValue), node, isNotCell(jsValue));
+                break;
+            case FlushedJSValue:
+                break;
+            default:
+                DFG_CRASH(m_graph, node, &quot;Bad flush format for argument&quot;);
+                break;
+            }
+        }
+        m_out.jump(lowBlock(m_graph.block(0)));
+        
</ins><span class="cx">         for (BasicBlock* block : preOrder)
</span><span class="cx">             compileBlock(block);
</span><span class="cx">         
</span><span class="lines">@@ -381,9 +428,6 @@
</span><span class="cx">         case BooleanToNumber:
</span><span class="cx">             compileBooleanToNumber();
</span><span class="cx">             break;
</span><del>-        case GetArgument:
-            compileGetArgument();
-            break;
</del><span class="cx">         case ExtractOSREntryLocal:
</span><span class="cx">             compileExtractOSREntryLocal();
</span><span class="cx">             break;
</span><span class="lines">@@ -981,36 +1025,6 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void compileGetArgument()
-    {
-        VariableAccessData* variable = m_node-&gt;variableAccessData();
-        VirtualRegister operand = variable-&gt;machineLocal();
-        DFG_ASSERT(m_graph, m_node, operand.isArgument());
-
-        LValue jsValue = m_out.load64(addressFor(operand));
-
-        switch (useKindFor(variable-&gt;flushFormat())) {
-        case Int32Use:
-            speculate(BadType, jsValueValue(jsValue), m_node, isNotInt32(jsValue));
-            setInt32(unboxInt32(jsValue));
-            break;
-        case CellUse:
-            speculate(BadType, jsValueValue(jsValue), m_node, isNotCell(jsValue));
-            setJSValue(jsValue);
-            break;
-        case BooleanUse:
-            speculate(BadType, jsValueValue(jsValue), m_node, isNotBoolean(jsValue));
-            setBoolean(unboxBoolean(jsValue));
-            break;
-        case UntypedUse:
-            setJSValue(jsValue);
-            break;
-        default:
-            DFG_CRASH(m_graph, m_node, &quot;Bad use kind&quot;);
-            break;
-        }
-    }
-    
</del><span class="cx">     void compileExtractOSREntryLocal()
</span><span class="cx">     {
</span><span class="cx">         EncodedJSValue* buffer = static_cast&lt;EncodedJSValue*&gt;(
</span><span class="lines">@@ -1020,13 +1034,16 @@
</span><span class="cx">     
</span><span class="cx">     void compileGetLocal()
</span><span class="cx">     {
</span><del>-        // GetLocals arise only for captured variables.
</del><ins>+        // GetLocals arise only for captured variables and arguments. For arguments, we might have
+        // already loaded it.
+        if (LValue value = m_loadedArgumentValues.get(m_node)) {
+            setJSValue(value);
+            return;
+        }
</ins><span class="cx">         
</span><span class="cx">         VariableAccessData* variable = m_node-&gt;variableAccessData();
</span><span class="cx">         AbstractValue&amp; value = m_state.variables().operand(variable-&gt;local());
</span><span class="cx">         
</span><del>-        DFG_ASSERT(m_graph, m_node, variable-&gt;isCaptured());
-        
</del><span class="cx">         if (isInt32Speculation(value.m_type))
</span><span class="cx">             setInt32(m_out.load32(payloadFor(variable-&gt;machineLocal())));
</span><span class="cx">         else
</span><span class="lines">@@ -7014,6 +7031,11 @@
</span><span class="cx">     HashMap&lt;Node*, LoweredNodeValue&gt; m_storageValues;
</span><span class="cx">     HashMap&lt;Node*, LoweredNodeValue&gt; m_doubleValues;
</span><span class="cx">     
</span><ins>+    // This is a bit of a hack. It prevents LLVM from having to do CSE on loading of arguments.
+    // It's nice to have these optimizations on our end because we can guarantee them a bit better.
+    // Probably also saves LLVM compile time.
+    HashMap&lt;Node*, LValue&gt; m_loadedArgumentValues;
+    
</ins><span class="cx">     HashMap&lt;Node*, LValue&gt; m_phis;
</span><span class="cx">     
</span><span class="cx">     LocalOSRAvailabilityCalculator m_availabilityCalculator;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoretestsstressdeadspeculatingargumentusejs"></a>
<div class="addfile"><h4>Added: trunk/Source/JavaScriptCore/tests/stress/dead-speculating-argument-use.js (0 => 180160)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/tests/stress/dead-speculating-argument-use.js                                (rev 0)
+++ trunk/Source/JavaScriptCore/tests/stress/dead-speculating-argument-use.js        2015-02-16 19:27:37 UTC (rev 180160)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+function foo(x) {
+    var tmp = x + 1;
+}
+
+noInline(foo);
+
+for (var i = 0; i &lt; 10000; ++i)
+    foo(i);
+
+var didCall = false;
+var o = {
+    valueOf: function() { didCall = true; }
+};
+
+foo(o);
+if (!didCall)
+    throw &quot;Error: didn't call valueOf&quot;;
</ins></span></pre>
</div>
</div>

</body>
</html>