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

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

<h3>Log Message</h3>
<pre>DFG PhantomArguments shouldn't rely on a dead Phi graph
https://bugs.webkit.org/show_bug.cgi?id=126218

Source/JavaScriptCore: 

Reviewed by Oliver Hunt.
        
This change dramatically rationalizes our handling of PhantomArguments (i.e.
speculative elision of arguments object allocation).
        
It's now the case that if we decide that we can elide arguments allocation, we just
turn the arguments-creating node into a PhantomArguments and mark all locals that
it's stored to as being arguments aliases. Being an arguments alias and being a
PhantomArguments means basically the same thing: in DFG execution you have the empty
value, on OSR exit an arguments object is allocated in your place, and all operations
that use the value now just refer directly to the actual arguments in the call frame
header (or the arguments we know that we passed to the call, in case of inlining).
        
This means that we no longer have arguments simplification creating a dead Phi graph
that then has to be interpreted by the OSR exit logic. That sort of never made any
sense.
        
This means that PhantomArguments now has a clear story in SSA: basically SSA just
gets rid of the &quot;locals&quot; but everything else is the same.
        
Finally, this means that we can more easily get rid of forward exiting. As I was
working on the code to get rid of forward exiting, I realized that I'd have to
carefully preserve the special meanings of MovHint and SetLocal in the case of
PhantomArguments. It was really bizarre: even the semantics of MovHint were tied to
our specific treatment of PhantomArguments. After this change this is no longer the
case.
        
One of the really cool things about this change is that arguments reification now
just becomes a special kind of FlushFormat. This further unifies things: it means
that a MovHint(PhantomArguments) and a SetLocal(PhantomArguments) both have the same
meaning, since both of them dictate that the way we recover the local on exit is by
reifying arguments. Previously, the SetLocal(PhantomArguments) case needed some
special handling to accomplish this.
        
A downside of this approach is that we will now emit code to store the empty value
into aliased arguments variables, and we will even emit code to load that empty value
as well. As far as I can tell this doesn't cost anything, since PhantomArguments are
most profitable in cases where it allows us to simplify control flow and kill the
arguments locals entirely. Of course, this isn't an issue in SSA form since SSA form
also eliminates the locals.

* dfg/DFGArgumentsSimplificationPhase.cpp:
(JSC::DFG::ArgumentsSimplificationPhase::run):
(JSC::DFG::ArgumentsSimplificationPhase::detypeArgumentsReferencingPhantomChild):
* dfg/DFGFlushFormat.cpp:
(WTF::printInternal):
* dfg/DFGFlushFormat.h:
(JSC::DFG::resultFor):
(JSC::DFG::useKindFor):
(JSC::DFG::dataFormatFor):
* dfg/DFGSpeculativeJIT.cpp:
(JSC::DFG::SpeculativeJIT::compileCurrentBlock):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGValueSource.h:
(JSC::DFG::ValueSource::ValueSource):
(JSC::DFG::ValueSource::forFlushFormat):
* dfg/DFGVariableAccessData.h:
(JSC::DFG::VariableAccessData::flushFormat):
* ftl/FTLLowerDFGToLLVM.cpp:
(JSC::FTL::LowerDFGToLLVM::buildExitArguments):

LayoutTests: 

Reviewed by Oliver Hunt.
        
Added a test for an obvious case that I don't think we had coverage for in
microbenchmarks. Of course, this case was already covered by more complex tests.

* js/regress/inline-arguments-aliased-access-expected.txt: Added.
* js/regress/inline-arguments-aliased-access.html: Added.
* js/regress/script-tests/inline-arguments-aliased-access.js: Added.
(foo):
(bar):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGArgumentsSimplificationPhasecpp">trunk/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFlushFormatcpp">trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGFlushFormath">trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp">trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp</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="#trunkSourceJavaScriptCoredfgDFGValueSourceh">trunk/Source/JavaScriptCore/dfg/DFGValueSource.h</a></li>
<li><a href="#trunkSourceJavaScriptCoredfgDFGVariableAccessDatah">trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h</a></li>
<li><a href="#trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsjsregressinlineargumentsaliasedaccessexpectedtxt">trunk/LayoutTests/js/regress/inline-arguments-aliased-access-expected.txt</a></li>
<li><a href="#trunkLayoutTestsjsregressinlineargumentsaliasedaccesshtml">trunk/LayoutTests/js/regress/inline-arguments-aliased-access.html</a></li>
<li><a href="#trunkLayoutTestsjsregressscripttestsinlineargumentsaliasedaccessjs">trunk/LayoutTests/js/regress/script-tests/inline-arguments-aliased-access.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/LayoutTests/ChangeLog        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -1,3 +1,19 @@
</span><ins>+2013-12-25  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG PhantomArguments shouldn't rely on a dead Phi graph
+        https://bugs.webkit.org/show_bug.cgi?id=126218
+
+        Reviewed by Oliver Hunt.
+        
+        Added a test for an obvious case that I don't think we had coverage for in
+        microbenchmarks. Of course, this case was already covered by more complex tests.
+
+        * js/regress/inline-arguments-aliased-access-expected.txt: Added.
+        * js/regress/inline-arguments-aliased-access.html: Added.
+        * js/regress/script-tests/inline-arguments-aliased-access.js: Added.
+        (foo):
+        (bar):
+
</ins><span class="cx"> 2013-12-25  Dirk Schulze  &lt;krit@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Support &lt;box&gt; values parsing on 'clip-path' property
</span></span></pre></div>
<a id="trunkLayoutTestsjsregressinlineargumentsaliasedaccessexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/inline-arguments-aliased-access-expected.txt (0 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/inline-arguments-aliased-access-expected.txt                                (rev 0)
+++ trunk/LayoutTests/js/regress/inline-arguments-aliased-access-expected.txt        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+JSRegress/inline-arguments-aliased-access
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS no exception thrown
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressinlineargumentsaliasedaccesshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/inline-arguments-aliased-access.html (0 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/inline-arguments-aliased-access.html                                (rev 0)
+++ trunk/LayoutTests/js/regress/inline-arguments-aliased-access.html        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+&lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
+&lt;html&gt;
+&lt;head&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;/head&gt;
+&lt;body&gt;
+&lt;script src=&quot;resources/regress-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;script-tests/inline-arguments-aliased-access.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;resources/regress-post.js&quot;&gt;&lt;/script&gt;
+&lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestsjsregressscripttestsinlineargumentsaliasedaccessjs"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/js/regress/script-tests/inline-arguments-aliased-access.js (0 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/js/regress/script-tests/inline-arguments-aliased-access.js                                (rev 0)
+++ trunk/LayoutTests/js/regress/script-tests/inline-arguments-aliased-access.js        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+function foo() {
+    var a = arguments;
+    return a[0] + a[1] + a[2];
+}
+
+function bar(a, b, c) {
+    return foo(b, c, 42);
+}
+
+for (var i = 0; i &lt; 200000; ++i) {
+    var result = bar(1, 2, 3);
+    if (result != 47)
+        throw &quot;Bad result: &quot; + result;
+}
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/ChangeLog        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -1,3 +1,72 @@
</span><ins>+2013-12-25  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DFG PhantomArguments shouldn't rely on a dead Phi graph
+        https://bugs.webkit.org/show_bug.cgi?id=126218
+
+        Reviewed by Oliver Hunt.
+        
+        This change dramatically rationalizes our handling of PhantomArguments (i.e.
+        speculative elision of arguments object allocation).
+        
+        It's now the case that if we decide that we can elide arguments allocation, we just
+        turn the arguments-creating node into a PhantomArguments and mark all locals that
+        it's stored to as being arguments aliases. Being an arguments alias and being a
+        PhantomArguments means basically the same thing: in DFG execution you have the empty
+        value, on OSR exit an arguments object is allocated in your place, and all operations
+        that use the value now just refer directly to the actual arguments in the call frame
+        header (or the arguments we know that we passed to the call, in case of inlining).
+        
+        This means that we no longer have arguments simplification creating a dead Phi graph
+        that then has to be interpreted by the OSR exit logic. That sort of never made any
+        sense.
+        
+        This means that PhantomArguments now has a clear story in SSA: basically SSA just
+        gets rid of the &quot;locals&quot; but everything else is the same.
+        
+        Finally, this means that we can more easily get rid of forward exiting. As I was
+        working on the code to get rid of forward exiting, I realized that I'd have to
+        carefully preserve the special meanings of MovHint and SetLocal in the case of
+        PhantomArguments. It was really bizarre: even the semantics of MovHint were tied to
+        our specific treatment of PhantomArguments. After this change this is no longer the
+        case.
+        
+        One of the really cool things about this change is that arguments reification now
+        just becomes a special kind of FlushFormat. This further unifies things: it means
+        that a MovHint(PhantomArguments) and a SetLocal(PhantomArguments) both have the same
+        meaning, since both of them dictate that the way we recover the local on exit is by
+        reifying arguments. Previously, the SetLocal(PhantomArguments) case needed some
+        special handling to accomplish this.
+        
+        A downside of this approach is that we will now emit code to store the empty value
+        into aliased arguments variables, and we will even emit code to load that empty value
+        as well. As far as I can tell this doesn't cost anything, since PhantomArguments are
+        most profitable in cases where it allows us to simplify control flow and kill the
+        arguments locals entirely. Of course, this isn't an issue in SSA form since SSA form
+        also eliminates the locals.
+
+        * dfg/DFGArgumentsSimplificationPhase.cpp:
+        (JSC::DFG::ArgumentsSimplificationPhase::run):
+        (JSC::DFG::ArgumentsSimplificationPhase::detypeArgumentsReferencingPhantomChild):
+        * dfg/DFGFlushFormat.cpp:
+        (WTF::printInternal):
+        * dfg/DFGFlushFormat.h:
+        (JSC::DFG::resultFor):
+        (JSC::DFG::useKindFor):
+        (JSC::DFG::dataFormatFor):
+        * dfg/DFGSpeculativeJIT.cpp:
+        (JSC::DFG::SpeculativeJIT::compileCurrentBlock):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGValueSource.h:
+        (JSC::DFG::ValueSource::ValueSource):
+        (JSC::DFG::ValueSource::forFlushFormat):
+        * dfg/DFGVariableAccessData.h:
+        (JSC::DFG::VariableAccessData::flushFormat):
+        * ftl/FTLLowerDFGToLLVM.cpp:
+        (JSC::FTL::LowerDFGToLLVM::buildExitArguments):
+
</ins><span class="cx"> 2013-12-23  Oliver Hunt  &lt;oliver@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Refactor PutPropertySlot to be aware of custom properties
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGArgumentsSimplificationPhasecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -395,16 +395,6 @@
</span><span class="cx">                         || unmodifiedArgumentsRegister(m_graph.argumentsRegisterFor(node-&gt;codeOrigin)) == variableAccessData-&gt;local())
</span><span class="cx">                         break;
</span><span class="cx"> 
</span><del>-                    ASSERT(!variableAccessData-&gt;isCaptured());
-                    
-                    // If this is a store into a VariableAccessData* that is marked as
-                    // arguments aliasing for an InlineCallFrame* that does not create
-                    // arguments, then flag the VariableAccessData as being an
-                    // arguments-aliased. This'll let the OSR exit machinery do the right
-                    // things. Note also that the SetLocal should become dead as soon as
-                    // we replace all uses of this variable with GetMyArgumentsLength and
-                    // GetMyArgumentByVal.
-                    ASSERT(m_argumentsAliasing.find(variableAccessData)-&gt;value.isValid());
</del><span class="cx">                     if (variableAccessData-&gt;mergeIsArgumentsAlias(true)) {
</span><span class="cx">                         changed = true;
</span><span class="cx">                         
</span><span class="lines">@@ -420,22 +410,6 @@
</span><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><del>-                case PhantomLocal: {
-                    VariableAccessData* variableAccessData = node-&gt;variableAccessData();
-                    
-                    if (variableAccessData-&gt;isCaptured()
-                        || !m_argumentsAliasing.find(variableAccessData)-&gt;value.isValid()
-                        || m_createsArguments.contains(node-&gt;codeOrigin.inlineCallFrame))
-                        break;
-                    
-                    // Turn PhantomLocals into just GetLocals. This will preserve the threading
-                    // of the local through to this point, but will allow it to die, causing
-                    // only OSR to know about it.
-
-                    node-&gt;setOpAndDefaultFlags(GetLocal);
-                    break;
-                }
-
</del><span class="cx">                 case Flush: {
</span><span class="cx">                     VariableAccessData* variableAccessData = node-&gt;variableAccessData();
</span><span class="cx">                     
</span><span class="lines">@@ -459,7 +433,7 @@
</span><span class="cx">                     // 2) The Phantom may keep the CreateArguments node alive, which is
</span><span class="cx">                     //    precisely what we don't want.
</span><span class="cx">                     for (unsigned i = 0; i &lt; AdjacencyList::Size; ++i)
</span><del>-                        removeArgumentsReferencingPhantomChild(node, i);
</del><ins>+                        detypeArgumentsReferencingPhantomChild(node, i);
</ins><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><span class="lines">@@ -470,7 +444,6 @@
</span><span class="cx">                     if (!isOKToOptimize(node-&gt;child1().node()))
</span><span class="cx">                         break;
</span><span class="cx">                     node-&gt;convertToPhantom();
</span><del>-                    node-&gt;children.setChild1(Edge());
</del><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><span class="lines">@@ -488,8 +461,11 @@
</span><span class="cx">                     if (!isOKToOptimize(node-&gt;child1().node()))
</span><span class="cx">                         break;
</span><span class="cx">                     
</span><del>-                    node-&gt;children.child1() = node-&gt;children.child2();
-                    node-&gt;children.child2() = Edge();
</del><ins>+                    insertionSet.insertNode(
+                        indexInBlock, SpecNone, Phantom, node-&gt;codeOrigin, node-&gt;child1());
+                    
+                    node-&gt;child1() = node-&gt;child2();
+                    node-&gt;child2() = Edge();
</ins><span class="cx">                     node-&gt;setOpAndDefaultFlags(GetMyArgumentByVal);
</span><span class="cx">                     changed = true;
</span><span class="cx">                     --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal.
</span><span class="lines">@@ -503,7 +479,10 @@
</span><span class="cx">                     if (!isOKToOptimize(node-&gt;child1().node()))
</span><span class="cx">                         break;
</span><span class="cx">                     
</span><del>-                    node-&gt;children.child1() = Edge();
</del><ins>+                    insertionSet.insertNode(
+                        indexInBlock, SpecNone, Phantom, node-&gt;codeOrigin, node-&gt;child1());
+                    
+                    node-&gt;child1() = Edge();
</ins><span class="cx">                     node-&gt;setOpAndDefaultFlags(GetMyArgumentsLength);
</span><span class="cx">                     changed = true;
</span><span class="cx">                     --indexInBlock; // Force reconsideration of this op noew that it's a GetMyArgumentsLength.
</span><span class="lines">@@ -580,8 +559,7 @@
</span><span class="cx">                         indexInBlock, SpecNone, CheckArgumentsNotCreated,
</span><span class="cx">                         codeOrigin);
</span><span class="cx">                     insertionSet.insertNode(
</span><del>-                        indexInBlock, SpecNone, Phantom, codeOrigin,
-                        children);
</del><ins>+                        indexInBlock, SpecNone, Phantom, codeOrigin, children);
</ins><span class="cx">                     
</span><span class="cx">                     changed = true;
</span><span class="cx">                     break;
</span><span class="lines">@@ -591,8 +569,7 @@
</span><span class="cx">                     if (m_createsArguments.contains(node-&gt;codeOrigin.inlineCallFrame))
</span><span class="cx">                         continue;
</span><span class="cx">                     
</span><del>-                    node-&gt;setOpAndDefaultFlags(Phantom);
-                    node-&gt;children.reset();
</del><ins>+                    node-&gt;convertToPhantom();
</ins><span class="cx">                     break;
</span><span class="cx">                 }
</span><span class="cx">                     
</span><span class="lines">@@ -627,6 +604,19 @@
</span><span class="cx">             insertionSet.execute(block);
</span><span class="cx">         }
</span><span class="cx">         
</span><ins>+        for (BlockIndex blockIndex = 0; blockIndex &lt; m_graph.numBlocks(); ++blockIndex) {
+            BasicBlock* block = m_graph.block(blockIndex);
+            if (!block)
+                continue;
+            for (unsigned indexInBlock = 0; indexInBlock &lt; block-&gt;size(); ++indexInBlock) {
+                Node* node = block-&gt;at(indexInBlock);
+                if (node-&gt;op() != Phantom)
+                    continue;
+                for (unsigned i = 0; i &lt; AdjacencyList::Size; ++i)
+                    detypeArgumentsReferencingPhantomChild(node, i);
+            }
+        }
+        
</ins><span class="cx">         if (changed) {
</span><span class="cx">             m_graph.dethread();
</span><span class="cx">             m_graph.m_form = LoadStore;
</span><span class="lines">@@ -764,35 +754,23 @@
</span><span class="cx">         return false;
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    void removeArgumentsReferencingPhantomChild(Node* node, unsigned edgeIndex)
</del><ins>+    void detypeArgumentsReferencingPhantomChild(Node* node, unsigned edgeIndex)
</ins><span class="cx">     {
</span><span class="cx">         Edge edge = node-&gt;children.child(edgeIndex);
</span><span class="cx">         if (!edge)
</span><span class="cx">             return;
</span><span class="cx">         
</span><span class="cx">         switch (edge-&gt;op()) {
</span><del>-        case Phi: // Arises if we had CSE on a GetLocal of the arguments register.
-        case GetLocal: // Arises if we had CSE on an arguments access to a variable aliased to the arguments.
-        case SetLocal: { // Arises if we had CSE on a GetLocal of the arguments register.
</del><ins>+        case GetLocal: {
</ins><span class="cx">             VariableAccessData* variableAccessData = edge-&gt;variableAccessData();
</span><del>-            bool isDeadArgumentsRegister =
-                variableAccessData-&gt;local() ==
-                    m_graph.uncheckedArgumentsRegisterFor(edge-&gt;codeOrigin)
-                &amp;&amp; !m_createsArguments.contains(edge-&gt;codeOrigin.inlineCallFrame);
-            bool isAliasedArgumentsRegister =
-                !variableAccessData-&gt;isCaptured()
-                &amp;&amp; m_argumentsAliasing.find(variableAccessData)-&gt;value.isValid()
-                &amp;&amp; !m_createsArguments.contains(edge-&gt;codeOrigin.inlineCallFrame);
-            if (!isDeadArgumentsRegister &amp;&amp; !isAliasedArgumentsRegister)
</del><ins>+            if (!variableAccessData-&gt;isArgumentsAlias())
</ins><span class="cx">                 break;
</span><del>-            node-&gt;children.removeEdge(edgeIndex);
</del><ins>+            node-&gt;children.child(edgeIndex).setUseKind(UntypedUse);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case CreateArguments: { // Arises if we CSE two GetLocals to the arguments register and then CSE the second use of the GetLocal to the first.
-            if (m_createsArguments.contains(edge-&gt;codeOrigin.inlineCallFrame))
-                break;
-            node-&gt;children.removeEdge(edgeIndex);
</del><ins>+        case PhantomArguments: {
+            node-&gt;children.child(edgeIndex).setUseKind(UntypedUse);
</ins><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFlushFormatcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.cpp        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -56,6 +56,9 @@
</span><span class="cx">     case FlushedJSValue:
</span><span class="cx">         out.print(&quot;FlushedJSValue&quot;);
</span><span class="cx">         return;
</span><ins>+    case FlushedArguments:
+        out.print(&quot;FlushedArguments&quot;);
+        return;
</ins><span class="cx">     case ConflictingFlush:
</span><span class="cx">         out.print(&quot;ConflictingFlush&quot;);
</span><span class="cx">         return;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGFlushFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGFlushFormat.h        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -46,6 +46,7 @@
</span><span class="cx">     FlushedCell,
</span><span class="cx">     FlushedBoolean,
</span><span class="cx">     FlushedJSValue,
</span><ins>+    FlushedArguments,
</ins><span class="cx">     ConflictingFlush
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -56,6 +57,7 @@
</span><span class="cx">     case FlushedJSValue:
</span><span class="cx">     case FlushedCell:
</span><span class="cx">     case ConflictingFlush:
</span><ins>+    case FlushedArguments:
</ins><span class="cx">         return NodeResultJS;
</span><span class="cx">     case FlushedInt32:
</span><span class="cx">         return NodeResultInt32;
</span><span class="lines">@@ -76,6 +78,7 @@
</span><span class="cx">     case DeadFlush:
</span><span class="cx">     case FlushedJSValue:
</span><span class="cx">     case ConflictingFlush:
</span><ins>+    case FlushedArguments:
</ins><span class="cx">         return UntypedUse;
</span><span class="cx">     case FlushedCell:
</span><span class="cx">         return CellUse;
</span><span class="lines">@@ -110,6 +113,8 @@
</span><span class="cx">         return DataFormatCell;
</span><span class="cx">     case FlushedBoolean:
</span><span class="cx">         return DataFormatBoolean;
</span><ins>+    case FlushedArguments:
+        return DataFormatArguments;
</ins><span class="cx">     }
</span><span class="cx">     RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">     return DataFormatDead;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJITcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -1436,9 +1436,7 @@
</span><span class="cx">         
</span><span class="cx">         VariableAccessData* variable = node-&gt;variableAccessData();
</span><span class="cx">         DataFormat format;
</span><del>-        if (variable-&gt;isArgumentsAlias())
-            format = DataFormatArguments;
-        else if (!node-&gt;refCount())
</del><ins>+        if (!node-&gt;refCount())
</ins><span class="cx">             continue; // No need to record dead SetLocal's.
</span><span class="cx">         else
</span><span class="cx">             format = dataFormatFor(variable-&gt;flushFormat());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -1889,7 +1889,8 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case FlushedJSValue: {
</del><ins>+        case FlushedJSValue:
+        case FlushedArguments: {
</ins><span class="cx">             GPRTemporary result(this);
</span><span class="cx">             GPRTemporary tag(this);
</span><span class="cx">             m_jit.load32(JITCompiler::payloadFor(node-&gt;machineLocal()), result.gpr());
</span><span class="lines">@@ -1975,7 +1976,8 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case FlushedJSValue: {
</del><ins>+        case FlushedJSValue:
+        case FlushedArguments: {
</ins><span class="cx">             if (generationInfoFromVirtualRegister(node-&gt;child1()-&gt;virtualRegister()).registerFormat() == DataFormatDouble) {
</span><span class="cx">                 SpeculateDoubleOperand value(this, node-&gt;child1(), ManualOperandSpeculation);
</span><span class="cx">                 m_jit.storeDouble(value.fpr(), JITCompiler::addressFor(node-&gt;machineLocal()));
</span><span class="lines">@@ -1989,14 +1991,6 @@
</span><span class="cx">             m_jit.store32(value.tagGPR(), JITCompiler::tagFor(node-&gt;machineLocal()));
</span><span class="cx">             noResult(node);
</span><span class="cx">             recordSetLocal(DataFormatJS);
</span><del>-            
-            // If we're storing an arguments object that has been optimized away,
-            // our variable event stream for OSR exit now reflects the optimized
-            // value (JSValue()). On the slow path, we want an arguments object
-            // instead. We add an additional move hint to show OSR exit that it
-            // needs to reconstruct the arguments object.
-            if (node-&gt;child1()-&gt;op() == PhantomArguments)
-                compileMovHint(node);
</del><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -2299,20 +2299,13 @@
</span><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span><del>-        case FlushedJSValue: {
</del><ins>+        case FlushedJSValue:
+        case FlushedArguments: {
</ins><span class="cx">             JSValueOperand value(this, node-&gt;child1());
</span><span class="cx">             m_jit.store64(value.gpr(), JITCompiler::addressFor(node-&gt;machineLocal()));
</span><span class="cx">             noResult(node);
</span><span class="cx">             
</span><span class="cx">             recordSetLocal(DataFormatJS);
</span><del>-            
-            // If we're storing an arguments object that has been optimized away,
-            // our variable event stream for OSR exit now reflects the optimized
-            // value (JSValue()). On the slow path, we want an arguments object
-            // instead. We add an additional move hint to show OSR exit that it
-            // needs to reconstruct the arguments object.
-            if (node-&gt;child1()-&gt;op() == PhantomArguments)
-                compileMovHint(node);
</del><span class="cx">             break;
</span><span class="cx">         }
</span><span class="cx">             
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGValueSourceh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGValueSource.h (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGValueSource.h        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGValueSource.h        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -122,7 +122,7 @@
</span><span class="cx">     explicit ValueSource(ValueSourceKind valueSourceKind)
</span><span class="cx">         : m_kind(valueSourceKind)
</span><span class="cx">     {
</span><del>-        ASSERT(kind() == ArgumentsSource || kind() == SourceIsDead);
</del><ins>+        ASSERT(kind() == ArgumentsSource || kind() == SourceIsDead || kind() == ArgumentsSource);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     explicit ValueSource(MinifiedID id)
</span><span class="lines">@@ -159,6 +159,8 @@
</span><span class="cx">             return ValueSource(CellInJSStack, where);
</span><span class="cx">         case FlushedBoolean:
</span><span class="cx">             return ValueSource(BooleanInJSStack, where);
</span><ins>+        case FlushedArguments:
+            return ValueSource(ArgumentsSource);
</ins><span class="cx">         }
</span><span class="cx">         RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx">         return ValueSource();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGVariableAccessDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/dfg/DFGVariableAccessData.h        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -328,6 +328,9 @@
</span><span class="cx">     {
</span><span class="cx">         ASSERT(find() == this);
</span><span class="cx">         
</span><ins>+        if (isArgumentsAlias())
+            return FlushedArguments;
+        
</ins><span class="cx">         if (!shouldUnboxIfPossible())
</span><span class="cx">             return FlushedJSValue;
</span><span class="cx">         
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToLLVMcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp (161071 => 161072)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2013-12-25 20:39:32 UTC (rev 161071)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp        2013-12-25 23:44:57 UTC (rev 161072)
</span><span class="lines">@@ -4209,6 +4209,12 @@
</span><span class="cx">             case FlushedDouble:
</span><span class="cx">                 exit.m_values[i] = ExitValue::inJSStackAsDouble(flush.virtualRegister());
</span><span class="cx">                 break;
</span><ins>+                
+            case FlushedArguments:
+                // FIXME: implement PhantomArguments.
+                // https://bugs.webkit.org/show_bug.cgi?id=113986
+                RELEASE_ASSERT_NOT_REACHED();
+                break;
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         
</span></span></pre>
</div>
</div>

</body>
</html>