<!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>[161450] 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/161450">161450</a></dd>
<dt>Author</dt> <dd>mhahnenberg@apple.com</dd>
<dt>Date</dt> <dd>2014-01-07 13:05:30 -0800 (Tue, 07 Jan 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Repatch write barrier slow path call doesn't align the stack in the presence of saved registers
https://bugs.webkit.org/show_bug.cgi?id=126093

Reviewed by Geoffrey Garen.

* jit/Repatch.cpp: Reworked the stack alignment code for calling out to C code on the write barrier slow path.
We need to properly account for the number of reused registers that were saved to the stack, so we have to 
pass the ScratchRegisterAllocator around.
(JSC::storeToWriteBarrierBuffer):
(JSC::writeBarrier):
(JSC::emitPutReplaceStub):
(JSC::emitPutTransitionStub):
* jit/ScratchRegisterAllocator.h: Previously the ScratchRegisterAllocator only knew whether or not it had
reused registers, but not how many. In order to correctly align the stack for calls to C slow paths for 
the write barriers in inline caches we need to know how the stack is aligned. So now ScratchRegisterAllocator
tracks how many registers it has reused.
(JSC::ScratchRegisterAllocator::ScratchRegisterAllocator):
(JSC::ScratchRegisterAllocator::allocateScratch):
(JSC::ScratchRegisterAllocator::didReuseRegisters):
(JSC::ScratchRegisterAllocator::numberOfReusedRegisters):
(JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing):
(JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping):
* llint/LowLevelInterpreter64.asm: Random typo fix.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorejitRepatchcpp">trunk/Source/JavaScriptCore/jit/Repatch.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorejitScratchRegisterAllocatorh">trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h</a></li>
<li><a href="#trunkSourceJavaScriptCorellintLowLevelInterpreter64asm">trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (161449 => 161450)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog        2014-01-07 20:59:43 UTC (rev 161449)
+++ trunk/Source/JavaScriptCore/ChangeLog        2014-01-07 21:05:30 UTC (rev 161450)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2014-01-07  Mark Hahnenberg  &lt;mhahnenberg@apple.com&gt;
+
+        Repatch write barrier slow path call doesn't align the stack in the presence of saved registers
+        https://bugs.webkit.org/show_bug.cgi?id=126093
+
+        Reviewed by Geoffrey Garen.
+
+        * jit/Repatch.cpp: Reworked the stack alignment code for calling out to C code on the write barrier slow path.
+        We need to properly account for the number of reused registers that were saved to the stack, so we have to 
+        pass the ScratchRegisterAllocator around.
+        (JSC::storeToWriteBarrierBuffer):
+        (JSC::writeBarrier):
+        (JSC::emitPutReplaceStub):
+        (JSC::emitPutTransitionStub):
+        * jit/ScratchRegisterAllocator.h: Previously the ScratchRegisterAllocator only knew whether or not it had
+        reused registers, but not how many. In order to correctly align the stack for calls to C slow paths for 
+        the write barriers in inline caches we need to know how the stack is aligned. So now ScratchRegisterAllocator
+        tracks how many registers it has reused.
+        (JSC::ScratchRegisterAllocator::ScratchRegisterAllocator):
+        (JSC::ScratchRegisterAllocator::allocateScratch):
+        (JSC::ScratchRegisterAllocator::didReuseRegisters):
+        (JSC::ScratchRegisterAllocator::numberOfReusedRegisters):
+        (JSC::ScratchRegisterAllocator::preserveReusedRegistersByPushing):
+        (JSC::ScratchRegisterAllocator::restoreReusedRegistersByPopping):
+        * llint/LowLevelInterpreter64.asm: Random typo fix.
+
</ins><span class="cx"> 2014-01-07  Mark Lam  &lt;mark.lam@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         r161364 caused JSC tests regression on non-DFG builds (e.g. C Loop and Windows).
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitRepatchcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/Repatch.cpp (161449 => 161450)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/Repatch.cpp        2014-01-07 20:59:43 UTC (rev 161449)
+++ trunk/Source/JavaScriptCore/jit/Repatch.cpp        2014-01-07 21:05:30 UTC (rev 161450)
</span><span class="lines">@@ -774,7 +774,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(GGC)
</span><del>-static MacroAssembler::Call storeToWriteBarrierBuffer(CCallHelpers&amp; jit, GPRReg cell, GPRReg scratch1, GPRReg scratch2, ScratchRegisterAllocator&amp; allocator)
</del><ins>+static MacroAssembler::Call storeToWriteBarrierBuffer(CCallHelpers&amp; jit, GPRReg cell, GPRReg scratch1, GPRReg scratch2, GPRReg callFrameRegister, ScratchRegisterAllocator&amp; allocator)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(scratch1 != scratch2);
</span><span class="cx">     WriteBarrierBuffer* writeBarrierBuffer = &amp;jit.vm()-&gt;heap.writeBarrierBuffer();
</span><span class="lines">@@ -795,17 +795,23 @@
</span><span class="cx">     ScratchBuffer* scratchBuffer = jit.vm()-&gt;scratchBufferForSize(allocator.desiredScratchBufferSize());
</span><span class="cx">     allocator.preserveUsedRegistersToScratchBuffer(jit, scratchBuffer, scratch1);
</span><span class="cx"> 
</span><del>-    // We need these extra slots because setupArgumentsWithExecState will use poke on x86.
</del><ins>+    unsigned bytesFromBase = allocator.numberOfReusedRegisters() * sizeof(void*);
+    unsigned bytesToSubtract = 0;
</ins><span class="cx"> #if CPU(X86)
</span><del>-    jit.subPtr(MacroAssembler::TrustedImm32(sizeof(void*) * 3), MacroAssembler::stackPointerRegister);
</del><ins>+    bytesToSubtract += 2 * sizeof(void*);
+    bytesFromBase += bytesToSubtract;
</ins><span class="cx"> #endif
</span><ins>+    unsigned currentAlignment = bytesFromBase % stackAlignmentBytes();
+    bytesToSubtract += currentAlignment;
</ins><span class="cx"> 
</span><del>-    jit.setupArgumentsWithExecState(cell);
</del><ins>+    if (bytesToSubtract)
+        jit.subPtr(MacroAssembler::TrustedImm32(bytesToSubtract), MacroAssembler::stackPointerRegister); 
+
+    jit.setupArguments(callFrameRegister, cell);
</ins><span class="cx">     MacroAssembler::Call call = jit.call();
</span><span class="cx"> 
</span><del>-#if CPU(X86)
-    jit.addPtr(MacroAssembler::TrustedImm32(sizeof(void*) * 3), MacroAssembler::stackPointerRegister);
-#endif
</del><ins>+    if (bytesToSubtract)
+        jit.addPtr(MacroAssembler::TrustedImm32(bytesToSubtract), MacroAssembler::stackPointerRegister);
</ins><span class="cx">     allocator.restoreUsedRegistersFromScratchBuffer(jit, scratchBuffer, scratch1);
</span><span class="cx"> 
</span><span class="cx">     done.link(&amp;jit);
</span><span class="lines">@@ -813,13 +819,13 @@
</span><span class="cx">     return call;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static MacroAssembler::Call writeBarrier(CCallHelpers&amp; jit, GPRReg owner, GPRReg scratch1, GPRReg scratch2, ScratchRegisterAllocator&amp; allocator)
</del><ins>+static MacroAssembler::Call writeBarrier(CCallHelpers&amp; jit, GPRReg owner, GPRReg scratch1, GPRReg scratch2, GPRReg callFrameRegister, ScratchRegisterAllocator&amp; allocator)
</ins><span class="cx"> {
</span><span class="cx">     ASSERT(owner != scratch1);
</span><span class="cx">     ASSERT(owner != scratch2);
</span><span class="cx"> 
</span><span class="cx">     MacroAssembler::Jump definitelyNotMarked = DFG::SpeculativeJIT::genericWriteBarrier(jit, owner, scratch1, scratch2);
</span><del>-    MacroAssembler::Call call = storeToWriteBarrierBuffer(jit, owner, scratch1, scratch2, allocator);
</del><ins>+    MacroAssembler::Call call = storeToWriteBarrierBuffer(jit, owner, scratch1, scratch2, callFrameRegister, allocator);
</ins><span class="cx">     definitelyNotMarked.link(&amp;jit);
</span><span class="cx">     return call;
</span><span class="cx"> }
</span><span class="lines">@@ -837,6 +843,9 @@
</span><span class="cx">     RefPtr&lt;JITStubRoutine&gt;&amp; stubRoutine)
</span><span class="cx"> {
</span><span class="cx">     VM* vm = &amp;exec-&gt;vm();
</span><ins>+#if ENABLE(GGC)
+    GPRReg callFrameRegister = static_cast&lt;GPRReg&gt;(stubInfo.patch.callFrameRegister);
+#endif
</ins><span class="cx">     GPRReg baseGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.baseGPR);
</span><span class="cx"> #if USE(JSVALUE32_64)
</span><span class="cx">     GPRReg valueTagGPR = static_cast&lt;GPRReg&gt;(stubInfo.patch.valueTagGPR);
</span><span class="lines">@@ -883,7 +892,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     
</span><span class="cx"> #if ENABLE(GGC)
</span><del>-    MacroAssembler::Call writeBarrierOperation = writeBarrier(stubJit, baseGPR, scratchGPR1, scratchGPR2, allocator);
</del><ins>+    MacroAssembler::Call writeBarrierOperation = writeBarrier(stubJit, baseGPR, scratchGPR1, scratchGPR2, callFrameRegister, allocator);
</ins><span class="cx"> #endif
</span><span class="cx">     
</span><span class="cx">     MacroAssembler::Jump success;
</span><span class="lines">@@ -1050,7 +1059,7 @@
</span><span class="cx"> #endif
</span><span class="cx">     
</span><span class="cx"> #if ENABLE(GGC)
</span><del>-    MacroAssembler::Call writeBarrierOperation = writeBarrier(stubJit, baseGPR, scratchGPR1, scratchGPR2, allocator);
</del><ins>+    MacroAssembler::Call writeBarrierOperation = writeBarrier(stubJit, baseGPR, scratchGPR1, scratchGPR2, callFrameRegister, allocator);
</ins><span class="cx"> #endif
</span><span class="cx">     
</span><span class="cx">     MacroAssembler::Jump success;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorejitScratchRegisterAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h (161449 => 161450)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h        2014-01-07 20:59:43 UTC (rev 161449)
+++ trunk/Source/JavaScriptCore/jit/ScratchRegisterAllocator.h        2014-01-07 21:05:30 UTC (rev 161450)
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx"> public:
</span><span class="cx">     ScratchRegisterAllocator(const TempRegisterSet&amp; usedRegisters)
</span><span class="cx">         : m_usedRegisters(usedRegisters)
</span><del>-        , m_didReuseRegisters(false)
</del><ins>+        , m_numberOfReusedRegisters(0)
</ins><span class="cx">     {
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -80,7 +80,7 @@
</span><span class="cx">             typename BankInfo::RegisterType reg = BankInfo::toRegister(i);
</span><span class="cx">             if (!m_lockedRegisters.get(reg) &amp;&amp; !m_scratchRegisters.get(reg)) {
</span><span class="cx">                 m_scratchRegisters.set(reg);
</span><del>-                m_didReuseRegisters = true;
</del><ins>+                m_numberOfReusedRegisters++;
</ins><span class="cx">                 return reg;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -96,12 +96,17 @@
</span><span class="cx">     
</span><span class="cx">     bool didReuseRegisters() const
</span><span class="cx">     {
</span><del>-        return m_didReuseRegisters;
</del><ins>+        return !!m_numberOfReusedRegisters;
</ins><span class="cx">     }
</span><span class="cx">     
</span><ins>+    unsigned numberOfReusedRegisters() const
+    {
+        return m_numberOfReusedRegisters;
+    }
+    
</ins><span class="cx">     void preserveReusedRegistersByPushing(MacroAssembler&amp; jit)
</span><span class="cx">     {
</span><del>-        if (!m_didReuseRegisters)
</del><ins>+        if (!didReuseRegisters())
</ins><span class="cx">             return;
</span><span class="cx">         
</span><span class="cx">         for (unsigned i = 0; i &lt; FPRInfo::numberOfRegisters; ++i) {
</span><span class="lines">@@ -116,7 +121,7 @@
</span><span class="cx">     
</span><span class="cx">     void restoreReusedRegistersByPopping(MacroAssembler&amp; jit)
</span><span class="cx">     {
</span><del>-        if (!m_didReuseRegisters)
</del><ins>+        if (!didReuseRegisters())
</ins><span class="cx">             return;
</span><span class="cx">         
</span><span class="cx">         for (unsigned i = GPRInfo::numberOfRegisters; i--;) {
</span><span class="lines">@@ -199,7 +204,7 @@
</span><span class="cx">     TempRegisterSet m_usedRegisters;
</span><span class="cx">     TempRegisterSet m_lockedRegisters;
</span><span class="cx">     TempRegisterSet m_scratchRegisters;
</span><del>-    bool m_didReuseRegisters;
</del><ins>+    unsigned m_numberOfReusedRegisters;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> } // namespace JSC
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorellintLowLevelInterpreter64asm"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm (161449 => 161450)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2014-01-07 20:59:43 UTC (rev 161449)
+++ trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm        2014-01-07 21:05:30 UTC (rev 161450)
</span><span class="lines">@@ -340,7 +340,7 @@
</span><span class="cx">                 btbz marked, .writeBarrierDone
</span><span class="cx">                 push PB, PC
</span><span class="cx">                 cCall2(_llint_write_barrier_slow, cfr, t0)
</span><del>-                push PC, PB
</del><ins>+                pop PC, PB
</ins><span class="cx">             end
</span><span class="cx">         )
</span><span class="cx">     .writeBarrierDone:
</span></span></pre>
</div>
</div>

</body>
</html>