<!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>[209846] 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/209846">209846</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2016-12-14 17:25:16 -0800 (Wed, 14 Dec 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>DirectTailCall implementation needs to tell the shuffler what to put into the ArgumentCount explicitly
https://bugs.webkit.org/show_bug.cgi?id=165882

Reviewed by Mark Lam.
JSTests:


* stress/direct-tail-call-arity-mismatch-count-args.js: Added.
(foo):
(bar):

Source/JavaScriptCore:

        
The CallFrameShuffler was assuming that the ArgumentCount that it should store into the
callee frame is simply the size of the args vector.
        
That's not true for DirectTailCall, which will pad the args vector with undefined if we
are optimizing an arity mismatch. We need to pass the ArgumentCount explicitly in this
case.

* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* ftl/FTLLowerDFGToB3.cpp:
(JSC::FTL::DFG::LowerDFGToB3::compileDirectCallOrConstruct):
(JSC::FTL::DFG::LowerDFGToB3::compileTailCall):
* jit/CallFrameShuffleData.h:
* jit/CallFrameShuffler.cpp:
(JSC::CallFrameShuffler::CallFrameShuffler):
(JSC::CallFrameShuffler::prepareAny):
* jit/CallFrameShuffler.h:
(JSC::CallFrameShuffler::snapshot):
* jit/JITCall.cpp:
(JSC::JIT::compileOpCall):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</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="#trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp">trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShuffleDatah">trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShufflercpp">trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitCallFrameShufflerh">trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCallcpp">trunk/Source/JavaScriptCore/jit/JITCall.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestsstressdirecttailcallaritymismatchcountargsjs">trunk/JSTests/stress/direct-tail-call-arity-mismatch-count-args.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/JSTests/ChangeLog        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-12-14  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DirectTailCall implementation needs to tell the shuffler what to put into the ArgumentCount explicitly
+        https://bugs.webkit.org/show_bug.cgi?id=165882
+
+        Reviewed by Mark Lam.
+
+        * stress/direct-tail-call-arity-mismatch-count-args.js: Added.
+        (foo):
+        (bar):
+
</ins><span class="cx"> 2016-12-14  Keith Miller  &lt;keith_miller@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WebAssembly JS API: implement Global
</span></span></pre></div>
<a id="trunkJSTestsstressdirecttailcallaritymismatchcountargsjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/stress/direct-tail-call-arity-mismatch-count-args.js (0 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/stress/direct-tail-call-arity-mismatch-count-args.js                                (rev 0)
+++ trunk/JSTests/stress/direct-tail-call-arity-mismatch-count-args.js        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+&quot;use strict&quot;;
+
+function foo(a, b, c, d, e, f) {
+    return arguments.length;
+}
+
+noInline(foo);
+
+function bar() {
+    return foo(1, 2, 3);
+}
+
+noInline(bar);
+
+for (var i = 0; i &lt; 10000; ++i) {
+    var result = bar();
+    if (result != 3)
+        throw &quot;Error: bad result: &quot; + result;
+}
+
</ins></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/ChangeLog        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -1,3 +1,33 @@
</span><ins>+2016-12-14  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        DirectTailCall implementation needs to tell the shuffler what to put into the ArgumentCount explicitly
+        https://bugs.webkit.org/show_bug.cgi?id=165882
+
+        Reviewed by Mark Lam.
+        
+        The CallFrameShuffler was assuming that the ArgumentCount that it should store into the
+        callee frame is simply the size of the args vector.
+        
+        That's not true for DirectTailCall, which will pad the args vector with undefined if we
+        are optimizing an arity mismatch. We need to pass the ArgumentCount explicitly in this
+        case.
+
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::emitCall):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::emitCall):
+        * ftl/FTLLowerDFGToB3.cpp:
+        (JSC::FTL::DFG::LowerDFGToB3::compileDirectCallOrConstruct):
+        (JSC::FTL::DFG::LowerDFGToB3::compileTailCall):
+        * jit/CallFrameShuffleData.h:
+        * jit/CallFrameShuffler.cpp:
+        (JSC::CallFrameShuffler::CallFrameShuffler):
+        (JSC::CallFrameShuffler::prepareAny):
+        * jit/CallFrameShuffler.h:
+        (JSC::CallFrameShuffler::snapshot):
+        * jit/JITCall.cpp:
+        (JSC::JIT::compileOpCall):
+
</ins><span class="cx"> 2016-12-14  Keith Miller  &lt;keith_miller@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         WebAssembly JS API: implement Global
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -879,6 +879,7 @@
</span><span class="cx">             shuffleData.numLocals = m_jit.graph().frameRegisterCount();
</span><span class="cx">             shuffleData.callee = ValueRecovery::inPair(calleeTagGPR, calleePayloadGPR);
</span><span class="cx">             shuffleData.args.resize(numAllocatedArgs);
</span><ins>+            shuffleData.numPassedArgs = numPassedArgs;
</ins><span class="cx"> 
</span><span class="cx">             for (unsigned i = 0; i &lt; numPassedArgs; ++i) {
</span><span class="cx">                 Edge argEdge = m_jit.graph().varArgChild(node, i + 1);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoredfgDFGSpeculativeJIT64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -851,7 +851,8 @@
</span><span class="cx">             shuffleData.numLocals = m_jit.graph().frameRegisterCount();
</span><span class="cx">             shuffleData.callee = ValueRecovery::inGPR(calleeGPR, DataFormatJS);
</span><span class="cx">             shuffleData.args.resize(numAllocatedArgs);
</span><del>-
</del><ins>+            shuffleData.numPassedArgs = numPassedArgs;
+            
</ins><span class="cx">             for (unsigned i = 0; i &lt; numPassedArgs; ++i) {
</span><span class="cx">                 Edge argEdge = m_jit.graph().varArgChild(node, i + 1);
</span><span class="cx">                 GenerationInfo&amp; info = generationInfo(argEdge.node());
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreftlFTLLowerDFGToB3cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -5992,6 +5992,7 @@
</span><span class="cx">                     }
</span><span class="cx">                     for (unsigned i = numPassedArgs; i &lt; numAllocatedArgs; ++i)
</span><span class="cx">                         shuffleData.args.append(ValueRecovery::constant(jsUndefined()));
</span><ins>+                    shuffleData.numPassedArgs = numPassedArgs;
</ins><span class="cx">                     shuffleData.setupCalleeSaveRegisters(jit.codeBlock());
</span><span class="cx">                     
</span><span class="cx">                     CallLinkInfo* callLinkInfo = jit.codeBlock()-&gt;addCallLinkInfo();
</span><span class="lines">@@ -6158,6 +6159,8 @@
</span><span class="cx">                 for (unsigned i = 0; i &lt; numArgs; ++i)
</span><span class="cx">                     shuffleData.args.append(params[1 + i].recoveryForJSValue());
</span><span class="cx"> 
</span><ins>+                shuffleData.numPassedArgs = numArgs;
+                
</ins><span class="cx">                 shuffleData.setupCalleeSaveRegisters(jit.codeBlock());
</span><span class="cx"> 
</span><span class="cx">                 CallLinkInfo* callLinkInfo = jit.codeBlock()-&gt;addCallLinkInfo();
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShuffleDatah"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffleData.h        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -35,9 +35,10 @@
</span><span class="cx"> struct CallFrameShuffleData {
</span><span class="cx">     WTF_MAKE_FAST_ALLOCATED;
</span><span class="cx"> public:
</span><del>-    unsigned numLocals;
</del><ins>+    unsigned numLocals { UINT_MAX };
</ins><span class="cx">     ValueRecovery callee;
</span><span class="cx">     Vector&lt;ValueRecovery&gt; args;
</span><ins>+    unsigned numPassedArgs { UINT_MAX };
</ins><span class="cx"> #if USE(JSVALUE64)
</span><span class="cx">     RegisterMap&lt;ValueRecovery&gt; registers;
</span><span class="cx">     GPRReg tagTypeNumber { InvalidGPRReg };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShufflercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler.cpp        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2015 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -44,6 +44,7 @@
</span><span class="cx">         + roundArgumentCountToAlignFrame(data.args.size()))
</span><span class="cx">     , m_frameDelta(m_alignedNewFrameSize - m_alignedOldFrameSize)
</span><span class="cx">     , m_lockedRegisters(RegisterSet::allRegisters())
</span><ins>+    , m_numPassedArgs(data.numPassedArgs)
</ins><span class="cx"> {
</span><span class="cx">     // We are allowed all the usual registers...
</span><span class="cx">     for (unsigned i = GPRInfo::numberOfRegisters; i--; )
</span><span class="lines">@@ -746,7 +747,8 @@
</span><span class="cx">         dataLog(&quot;   * Storing the argument count into &quot;, VirtualRegister { CallFrameSlot::argumentCount }, &quot;\n&quot;);
</span><span class="cx">     m_jit.store32(MacroAssembler::TrustedImm32(0),
</span><span class="cx">         addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(TagOffset));
</span><del>-    m_jit.store32(MacroAssembler::TrustedImm32(argCount()),
</del><ins>+    RELEASE_ASSERT(m_numPassedArgs != UINT_MAX);
+    m_jit.store32(MacroAssembler::TrustedImm32(m_numPassedArgs),
</ins><span class="cx">         addressForNew(VirtualRegister { CallFrameSlot::argumentCount }).withOffset(PayloadOffset));
</span><span class="cx"> 
</span><span class="cx">     if (!isSlowPath()) {
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitCallFrameShufflerh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/jit/CallFrameShuffler.h        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -102,6 +102,7 @@
</span><span class="cx"> 
</span><span class="cx">         CallFrameShuffleData data;
</span><span class="cx">         data.numLocals = numLocals();
</span><ins>+        data.numPassedArgs = m_numPassedArgs;
</ins><span class="cx">         data.callee = getNew(VirtualRegister { CallFrameSlot::callee })-&gt;recovery();
</span><span class="cx">         data.args.resize(argCount());
</span><span class="cx">         for (size_t i = 0; i &lt; argCount(); ++i)
</span><span class="lines">@@ -794,6 +795,8 @@
</span><span class="cx">     // It returns false if it was unable to perform some safe writes
</span><span class="cx">     // due to high register pressure.
</span><span class="cx">     bool performSafeWrites();
</span><ins>+    
+    unsigned m_numPassedArgs { UINT_MAX };
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCallcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCall.cpp (209845 => 209846)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCall.cpp        2016-12-15 01:06:21 UTC (rev 209845)
+++ trunk/Source/JavaScriptCore/jit/JITCall.cpp        2016-12-15 01:25:16 UTC (rev 209846)
</span><span class="lines">@@ -198,6 +198,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (opcodeID == op_tail_call) {
</span><span class="cx">         CallFrameShuffleData shuffleData;
</span><ins>+        shuffleData.numPassedArgs = instruction[3].u.operand;
</ins><span class="cx">         shuffleData.tagTypeNumber = GPRInfo::tagTypeNumberRegister;
</span><span class="cx">         shuffleData.numLocals =
</span><span class="cx">             instruction[4].u.operand - sizeof(CallerFrameAndPC) / sizeof(Register);
</span></span></pre>
</div>
</div>

</body>
</html>