<!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>[179957] 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/179957">179957</a></dd>
<dt>Author</dt> <dd>fpizlo@apple.com</dd>
<dt>Date</dt> <dd>2015-02-11 13:48:38 -0800 (Wed, 11 Feb 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>SetupVarargsFrame should not assume that an inline stack frame would have identical layout to a normal stack frame
https://bugs.webkit.org/show_bug.cgi?id=141485

Reviewed by Oliver Hunt.
        
The inlineStackOffset argument was meant to make it easy for the DFG to use this helper for
vararg calls from inlined code, but that doesn't work since the DFG inline call frame
doesn't actually put the argument count at the JSStack::ArgumentCount offset. In fact there
is really no such thing as an inlineStackOffset except when we OSR exit; while the code is
running the stack layout is compacted so that the stackOffset is not meaningful.

* jit/JITCall.cpp:
(JSC::JIT::compileSetupVarargsFrame):
* jit/JITCall32_64.cpp:
(JSC::JIT::compileSetupVarargsFrame):
* jit/SetupVarargsFrame.cpp:
(JSC::emitSetupVarargsFrameFastCase):
* jit/SetupVarargsFrame.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCallcpp">trunk/Source/JavaScriptCore/jit/JITCall.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitJITCall32_64cpp">trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitSetupVarargsFramecpp">trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitSetupVarargsFrameh">trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (179956 => 179957)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2015-02-11 21:45:02 UTC (rev 179956)
+++ trunk/Source/JavaScriptCore/ChangeLog        2015-02-11 21:48:38 UTC (rev 179957)
</span><span class="lines">@@ -1,3 +1,24 @@
</span><ins>+2015-02-11  Filip Pizlo  &lt;fpizlo@apple.com&gt;
+
+        SetupVarargsFrame should not assume that an inline stack frame would have identical layout to a normal stack frame
+        https://bugs.webkit.org/show_bug.cgi?id=141485
+
+        Reviewed by Oliver Hunt.
+        
+        The inlineStackOffset argument was meant to make it easy for the DFG to use this helper for
+        vararg calls from inlined code, but that doesn't work since the DFG inline call frame
+        doesn't actually put the argument count at the JSStack::ArgumentCount offset. In fact there
+        is really no such thing as an inlineStackOffset except when we OSR exit; while the code is
+        running the stack layout is compacted so that the stackOffset is not meaningful.
+
+        * jit/JITCall.cpp:
+        (JSC::JIT::compileSetupVarargsFrame):
+        * jit/JITCall32_64.cpp:
+        (JSC::JIT::compileSetupVarargsFrame):
+        * jit/SetupVarargsFrame.cpp:
+        (JSC::emitSetupVarargsFrameFastCase):
+        * jit/SetupVarargsFrame.h:
+
</ins><span class="cx"> 2015-02-10  Filip Pizlo  &lt;fpizlo@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Split FTL::JSCall into the part that knows about call inline caching and the part that interacts with LLVM patchpoints
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCallcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCall.cpp (179956 => 179957)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCall.cpp        2015-02-11 21:45:02 UTC (rev 179956)
+++ trunk/Source/JavaScriptCore/jit/JITCall.cpp        2015-02-11 21:48:38 UTC (rev 179957)
</span><span class="lines">@@ -73,7 +73,7 @@
</span><span class="cx">         slowCase.append(branch64(NotEqual, regT0, TrustedImm64(JSValue::encode(JSValue()))));
</span><span class="cx">         
</span><span class="cx">         move(TrustedImm32(-firstFreeRegister), regT1);
</span><del>-        emitSetupVarargsFrameFastCase(*this, regT1, regT0, regT1, regT2, 0, firstVarArgOffset, slowCase);
</del><ins>+        emitSetupVarargsFrameFastCase(*this, regT1, regT0, regT1, regT2, firstVarArgOffset, slowCase);
</ins><span class="cx">         end.append(jump());
</span><span class="cx">         slowCase.link(this);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitJITCall32_64cpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp (179956 => 179957)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp        2015-02-11 21:45:02 UTC (rev 179956)
+++ trunk/Source/JavaScriptCore/jit/JITCall32_64.cpp        2015-02-11 21:48:38 UTC (rev 179957)
</span><span class="lines">@@ -133,7 +133,7 @@
</span><span class="cx">         slowCase.append(branch32(NotEqual, regT1, TrustedImm32(JSValue::EmptyValueTag)));
</span><span class="cx">         
</span><span class="cx">         move(TrustedImm32(-firstFreeRegister), regT1);
</span><del>-        emitSetupVarargsFrameFastCase(*this, regT1, regT0, regT1, regT2, 0, firstVarArgOffset, slowCase);
</del><ins>+        emitSetupVarargsFrameFastCase(*this, regT1, regT0, regT1, regT2, firstVarArgOffset, slowCase);
</ins><span class="cx">         end.append(jump());
</span><span class="cx">         slowCase.link(this);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitSetupVarargsFramecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.cpp (179956 => 179957)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.cpp        2015-02-11 21:45:02 UTC (rev 179956)
+++ trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.cpp        2015-02-11 21:48:38 UTC (rev 179957)
</span><span class="lines">@@ -51,11 +51,16 @@
</span><span class="cx">     jit.addPtr(GPRInfo::callFrameRegister, resultGPR);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void emitSetupVarargsFrameFastCase(CCallHelpers&amp; jit, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, int inlineStackOffset, unsigned firstVarArgOffset, CCallHelpers::JumpList&amp; slowCase)
</del><ins>+void emitSetupVarargsFrameFastCase(CCallHelpers&amp; jit, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, ValueRecovery argCountRecovery, VirtualRegister firstArgumentReg, unsigned firstVarArgOffset, CCallHelpers::JumpList&amp; slowCase)
</ins><span class="cx"> {
</span><span class="cx">     CCallHelpers::JumpList end;
</span><span class="cx">     
</span><del>-    jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, (inlineStackOffset + JSStack::ArgumentCount) * sizeof(Register) + PayloadOffset), scratchGPR1);
</del><ins>+    if (argCountRecovery.isConstant()) {
+        // FIXME: We could constant-fold a lot of the computation below in this case.
+        // https://bugs.webkit.org/show_bug.cgi?id=141486
+        jit.move(CCallHelpers::TrustedImm32(argCountRecovery.constant().asInt32()), scratchGPR1);
+    } else
+        jit.load32(CCallHelpers::payloadFor(argCountRecovery.virtualRegister()), scratchGPR1);
</ins><span class="cx">     if (firstVarArgOffset) {
</span><span class="cx">         CCallHelpers::Jump sufficientArguments = jit.branch32(CCallHelpers::GreaterThan, scratchGPR1, CCallHelpers::TrustedImm32(firstVarArgOffset + 1));
</span><span class="cx">         jit.move(CCallHelpers::TrustedImm32(1), scratchGPR1);
</span><span class="lines">@@ -79,13 +84,14 @@
</span><span class="cx">     // scratchGPR1: argumentCount
</span><span class="cx"> 
</span><span class="cx">     CCallHelpers::Label copyLoop = jit.label();
</span><ins>+    int argOffset = (firstArgumentReg.offset() - 1 + firstVarArgOffset) * static_cast&lt;int&gt;(sizeof(Register));
</ins><span class="cx"> #if USE(JSVALUE64)
</span><del>-    jit.load64(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister, scratchGPR1, CCallHelpers::TimesEight, (CallFrame::thisArgumentOffset() + inlineStackOffset + firstVarArgOffset) * static_cast&lt;int&gt;(sizeof(Register))), scratchGPR3);
</del><ins>+    jit.load64(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister, scratchGPR1, CCallHelpers::TimesEight, argOffset), scratchGPR3);
</ins><span class="cx">     jit.store64(scratchGPR3, CCallHelpers::BaseIndex(scratchGPR2, scratchGPR1, CCallHelpers::TimesEight, CallFrame::thisArgumentOffset() * static_cast&lt;int&gt;(sizeof(Register))));
</span><span class="cx"> #else // USE(JSVALUE64), so this begins the 32-bit case
</span><del>-    jit.load32(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister, scratchGPR1, CCallHelpers::TimesEight, (CallFrame::thisArgumentOffset() + inlineStackOffset + firstVarArgOffset) * static_cast&lt;int&gt;(sizeof(Register)) + TagOffset), scratchGPR3);
</del><ins>+    jit.load32(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister, scratchGPR1, CCallHelpers::TimesEight, argOffset + TagOffset), scratchGPR3);
</ins><span class="cx">     jit.store32(scratchGPR3, CCallHelpers::BaseIndex(scratchGPR2, scratchGPR1, CCallHelpers::TimesEight, CallFrame::thisArgumentOffset() * static_cast&lt;int&gt;(sizeof(Register)) + TagOffset));
</span><del>-    jit.load32(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister, scratchGPR1, CCallHelpers::TimesEight, (CallFrame::thisArgumentOffset() + inlineStackOffset + firstVarArgOffset) * static_cast&lt;int&gt;(sizeof(Register)) + PayloadOffset), scratchGPR3);
</del><ins>+    jit.load32(CCallHelpers::BaseIndex(GPRInfo::callFrameRegister, scratchGPR1, CCallHelpers::TimesEight, argOffset + PayloadOffset), scratchGPR3);
</ins><span class="cx">     jit.store32(scratchGPR3, CCallHelpers::BaseIndex(scratchGPR2, scratchGPR1, CCallHelpers::TimesEight, CallFrame::thisArgumentOffset() * static_cast&lt;int&gt;(sizeof(Register)) + PayloadOffset));
</span><span class="cx"> #endif // USE(JSVALUE64), end of 32-bit case
</span><span class="cx">     jit.branchSubPtr(CCallHelpers::NonZero, CCallHelpers::TrustedImm32(1), scratchGPR1).linkTo(copyLoop, &amp;jit);
</span><span class="lines">@@ -93,6 +99,15 @@
</span><span class="cx">     done.link(&amp;jit);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void emitSetupVarargsFrameFastCase(CCallHelpers&amp; jit, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, unsigned firstVarArgOffset, CCallHelpers::JumpList&amp; slowCase)
+{
+    emitSetupVarargsFrameFastCase(
+        jit, numUsedSlotsGPR, scratchGPR1, scratchGPR2, scratchGPR3,
+        ValueRecovery::displacedInJSStack(VirtualRegister(JSStack::ArgumentCount), DataFormatInt32),
+        VirtualRegister(CallFrame::argumentOffset(0)),
+        firstVarArgOffset, slowCase);
+}
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(JIT)
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitSetupVarargsFrameh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.h (179956 => 179957)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.h        2015-02-11 21:45:02 UTC (rev 179956)
+++ trunk/Source/JavaScriptCore/jit/SetupVarargsFrame.h        2015-02-11 21:48:38 UTC (rev 179957)
</span><span class="lines">@@ -37,8 +37,11 @@
</span><span class="cx"> 
</span><span class="cx"> // Assumes that SP refers to the last in-use stack location, and after this returns SP will point to
</span><span class="cx"> // the newly created frame plus the native header. scratchGPR2 may be the same as numUsedSlotsGPR.
</span><del>-void emitSetupVarargsFrameFastCase(CCallHelpers&amp;, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, int inlineStackOffset, unsigned firstVarArgOffset, CCallHelpers::JumpList&amp; slowCase);
</del><ins>+void emitSetupVarargsFrameFastCase(CCallHelpers&amp;, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, ValueRecovery argCountRecovery, VirtualRegister firstArgumentReg, unsigned firstVarArgOffset, CCallHelpers::JumpList&amp; slowCase);
</ins><span class="cx"> 
</span><ins>+// Variant that assumes normal stack frame.
+void emitSetupVarargsFrameFastCase(CCallHelpers&amp;, GPRReg numUsedSlotsGPR, GPRReg scratchGPR1, GPRReg scratchGPR2, GPRReg scratchGPR3, unsigned firstVarArgOffset, CCallHelpers::JumpList&amp; slowCase);
+
</ins><span class="cx"> } // namespace JSC
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(JIT)
</span></span></pre>
</div>
</div>

</body>
</html>