<!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>[169297] trunk/Source/WebCore</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/169297">169297</a></dd>
<dt>Author</dt> <dd>achristensen@apple.com</dd>
<dt>Date</dt> <dd>2014-05-23 18:06:16 -0700 (Fri, 23 May 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make CSS JIT run on ARM64.
https://bugs.webkit.org/show_bug.cgi?id=133156

Reviewed by Benjamin Poulain.

* cssjit/FunctionCall.h:
(WebCore::FunctionCall::saveAllocatedRegisters):
(WebCore::FunctionCall::restoreAllocatedRegisters):
Use StackAllocator's new push and pop functions to push and pop a vector instead of iterating it.
* cssjit/RegisterAllocator.h:
(WebCore::RegisterAllocator::reserveCalleeSavedRegisters):
(WebCore::RegisterAllocator::restoreCalleeSavedRegisters):
Return a vector of registers to allocate instead of doing the allocation to make the RegisterAllocator
not need to know about the StackAllocator and to use the new vector push and pop functions.
(WebCore::RegisterAllocator::~RegisterAllocator):
Store RegisterIDs instead of StackReferences to avoid needing to know about the stack.
* cssjit/SelectorCompiler.cpp:
(WebCore::SelectorCompiler::SelectorCodeGenerator::compile):
Removed the requirement for assert to be disabled to print disassembly when debugging css jit.
(WebCore::SelectorCompiler::SelectorCodeGenerator::generatePrologue):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateEpilogue):
Added to correctly push the link register and frame pointer.
This is required if the jit code calls a function on arm64 and helpful for debugging tools on x86_64.
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
Generate the prologue and epilogue which respectively push and pop
the link register, frame pointer, and callee saved registers if needed.
* cssjit/StackAllocator.h:
(WebCore::StackAllocator::push):
(WebCore::StackAllocator::pop):
Added new vector push and pop functions to use stp and ldb instructions on arm64.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorecssjitFunctionCallh">trunk/Source/WebCore/cssjit/FunctionCall.h</a></li>
<li><a href="#trunkSourceWebCorecssjitRegisterAllocatorh">trunk/Source/WebCore/cssjit/RegisterAllocator.h</a></li>
<li><a href="#trunkSourceWebCorecssjitSelectorCompilercpp">trunk/Source/WebCore/cssjit/SelectorCompiler.cpp</a></li>
<li><a href="#trunkSourceWebCorecssjitStackAllocatorh">trunk/Source/WebCore/cssjit/StackAllocator.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (169296 => 169297)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-05-24 00:29:44 UTC (rev 169296)
+++ trunk/Source/WebCore/ChangeLog        2014-05-24 01:06:16 UTC (rev 169297)
</span><span class="lines">@@ -1,3 +1,36 @@
</span><ins>+2014-05-23  Alex Christensen  &lt;achristensen@webkit.org&gt;
+
+        Make CSS JIT run on ARM64.
+        https://bugs.webkit.org/show_bug.cgi?id=133156
+
+        Reviewed by Benjamin Poulain.
+
+        * cssjit/FunctionCall.h:
+        (WebCore::FunctionCall::saveAllocatedRegisters):
+        (WebCore::FunctionCall::restoreAllocatedRegisters):
+        Use StackAllocator's new push and pop functions to push and pop a vector instead of iterating it.
+        * cssjit/RegisterAllocator.h:
+        (WebCore::RegisterAllocator::reserveCalleeSavedRegisters):
+        (WebCore::RegisterAllocator::restoreCalleeSavedRegisters):
+        Return a vector of registers to allocate instead of doing the allocation to make the RegisterAllocator
+        not need to know about the StackAllocator and to use the new vector push and pop functions.
+        (WebCore::RegisterAllocator::~RegisterAllocator):
+        Store RegisterIDs instead of StackReferences to avoid needing to know about the stack.
+        * cssjit/SelectorCompiler.cpp:
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::compile):
+        Removed the requirement for assert to be disabled to print disassembly when debugging css jit.
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generatePrologue):
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateEpilogue):
+        Added to correctly push the link register and frame pointer.
+        This is required if the jit code calls a function on arm64 and helpful for debugging tools on x86_64.
+        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
+        Generate the prologue and epilogue which respectively push and pop
+        the link register, frame pointer, and callee saved registers if needed.
+        * cssjit/StackAllocator.h:
+        (WebCore::StackAllocator::push):
+        (WebCore::StackAllocator::pop):
+        Added new vector push and pop functions to use stp and ldb instructions on arm64.
+
</ins><span class="cx"> 2014-05-23  Jeremy Jones  &lt;jeremyj@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Hide fullscreen immediately when switching tabs.
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitFunctionCallh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/FunctionCall.h (169296 => 169297)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/FunctionCall.h        2014-05-24 00:29:44 UTC (rev 169296)
+++ trunk/Source/WebCore/cssjit/FunctionCall.h        2014-05-24 01:06:16 UTC (rev 169297)
</span><span class="lines">@@ -165,20 +165,14 @@
</span><span class="cx">     void saveAllocatedRegisters()
</span><span class="cx">     {
</span><span class="cx">         ASSERT(m_savedRegisterStackReferences.isEmpty());
</span><del>-
-        unsigned allocatedRegistersCount = m_registerAllocator.allocatedRegisters().size();
-        m_savedRegisterStackReferences.reserveCapacity(allocatedRegistersCount);
-
-        for (unsigned i = 0; i &lt; allocatedRegistersCount; ++i) {
-            JSC::MacroAssembler::RegisterID registerID = m_registerAllocator.allocatedRegisters()[i];
-            m_savedRegisterStackReferences.append(m_stackAllocator.push(registerID));
-        }
</del><ins>+        const Vector&lt;JSC::MacroAssembler::RegisterID, registerCount&gt;&amp; allocatedRegisters = m_registerAllocator.allocatedRegisters();
+        Vector&lt;StackAllocator::StackReference&gt; stackReferences = m_stackAllocator.push(allocatedRegisters);
+        m_savedRegisterStackReferences.appendVector(stackReferences);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     void restoreAllocatedRegisters()
</span><span class="cx">     {
</span><del>-        for (unsigned i = m_registerAllocator.allocatedRegisters().size(); i &gt; 0; --i)
-            m_stackAllocator.pop(m_savedRegisterStackReferences[i - 1], m_registerAllocator.allocatedRegisters()[i - 1]);
</del><ins>+        m_stackAllocator.pop(m_savedRegisterStackReferences, m_registerAllocator.allocatedRegisters());
</ins><span class="cx">         m_savedRegisterStackReferences.clear();
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitRegisterAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/RegisterAllocator.h (169296 => 169297)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/RegisterAllocator.h        2014-05-24 00:29:44 UTC (rev 169296)
+++ trunk/Source/WebCore/cssjit/RegisterAllocator.h        2014-05-24 01:06:16 UTC (rev 169297)
</span><span class="lines">@@ -29,7 +29,6 @@
</span><span class="cx"> #if ENABLE(CSS_SELECTOR_JIT)
</span><span class="cx"> 
</span><span class="cx"> #include &lt;JavaScriptCore/MacroAssembler.h&gt;
</span><del>-#include &lt;StackAllocator.h&gt;
</del><span class="cx"> #include &lt;wtf/HashSet.h&gt;
</span><span class="cx"> #include &lt;wtf/Vector.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -78,7 +77,8 @@
</span><span class="cx"> #else
</span><span class="cx"> #error RegisterAllocator has no defined registers for the architecture.
</span><span class="cx"> #endif
</span><del>-static const unsigned registerCount = WTF_ARRAY_LENGTH(callerSavedRegisters) + WTF_ARRAY_LENGTH(calleeSavedRegisters);
</del><ins>+static const unsigned calleeSavedRegisterCount = WTF_ARRAY_LENGTH(calleeSavedRegisters);
+static const unsigned registerCount = calleeSavedRegisterCount + WTF_ARRAY_LENGTH(callerSavedRegisters);
</ins><span class="cx"> 
</span><span class="cx"> class RegisterAllocator {
</span><span class="cx"> public:
</span><span class="lines">@@ -113,25 +113,23 @@
</span><span class="cx">         RELEASE_ASSERT(m_registers.add(registerID).isNewEntry);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void reserveCalleeSavedRegisters(StackAllocator&amp; stack, unsigned count)
</del><ins>+    const Vector&lt;JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount&gt;&amp; reserveCalleeSavedRegisters(unsigned count)
</ins><span class="cx">     {
</span><del>-        unsigned finalSize = m_calleeSavedRegisters.size() + count;
-        RELEASE_ASSERT(finalSize &lt;= WTF_ARRAY_LENGTH(calleeSavedRegisters));
-        for (unsigned i = m_calleeSavedRegisters.size(); i &lt; finalSize; ++i) {
</del><ins>+        RELEASE_ASSERT(count &lt;= WTF_ARRAY_LENGTH(calleeSavedRegisters));
+        RELEASE_ASSERT(!m_reservedCalleeSavedRegisters.size());
+        for (unsigned i = 0; i &lt; count; ++i) {
</ins><span class="cx">             JSC::MacroAssembler::RegisterID registerId = calleeSavedRegisters[i];
</span><del>-            m_calleeSavedRegisters.append(stack.push(registerId));
</del><ins>+            m_reservedCalleeSavedRegisters.append(registerId);
</ins><span class="cx">             m_registers.add(registerId);
</span><span class="cx">         }
</span><ins>+        return m_reservedCalleeSavedRegisters;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void restoreCalleeSavedRegisters(StackAllocator&amp; stack)
</del><ins>+    Vector&lt;JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount&gt; restoreCalleeSavedRegisters()
</ins><span class="cx">     {
</span><del>-        for (unsigned i = m_calleeSavedRegisters.size(); i &gt; 0 ; --i) {
-            JSC::MacroAssembler::RegisterID registerId = calleeSavedRegisters[i - 1];
-            stack.pop(m_calleeSavedRegisters[i - 1], registerId);
-            RELEASE_ASSERT(m_registers.remove(registerId));
-        }
-        m_calleeSavedRegisters.clear();
</del><ins>+        Vector&lt;JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount&gt; registers(m_reservedCalleeSavedRegisters);
+        m_reservedCalleeSavedRegisters.clear();
+        return registers;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     const Vector&lt;JSC::MacroAssembler::RegisterID, registerCount&gt;&amp; allocatedRegisters() const { return m_allocatedRegisters; }
</span><span class="lines">@@ -150,7 +148,7 @@
</span><span class="cx"> private:
</span><span class="cx">     HashSet&lt;unsigned, DefaultHash&lt;unsigned&gt;::Hash, WTF::UnsignedWithZeroKeyHashTraits&lt;unsigned&gt;&gt; m_registers;
</span><span class="cx">     Vector&lt;JSC::MacroAssembler::RegisterID, registerCount&gt; m_allocatedRegisters;
</span><del>-    Vector&lt;StackAllocator::StackReference, WTF_ARRAY_LENGTH(calleeSavedRegisters)&gt; m_calleeSavedRegisters;
</del><ins>+    Vector&lt;JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount&gt; m_reservedCalleeSavedRegisters;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> class LocalRegister {
</span><span class="lines">@@ -184,7 +182,7 @@
</span><span class="cx"> 
</span><span class="cx"> inline RegisterAllocator::~RegisterAllocator()
</span><span class="cx"> {
</span><del>-    RELEASE_ASSERT(m_calleeSavedRegisters.isEmpty());
</del><ins>+    RELEASE_ASSERT(m_reservedCalleeSavedRegisters.isEmpty());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> } // namespace WebCore
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitSelectorCompilercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/SelectorCompiler.cpp (169296 => 169297)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-05-24 00:29:44 UTC (rev 169296)
+++ trunk/Source/WebCore/cssjit/SelectorCompiler.cpp        2014-05-24 01:06:16 UTC (rev 169297)
</span><span class="lines">@@ -221,6 +221,10 @@
</span><span class="cx">     Assembler::Jump modulo(JSC::MacroAssembler::ResultCondition, Assembler::RegisterID inputDividend, int divisor);
</span><span class="cx">     void moduloIsZero(Assembler::JumpList&amp; failureCases, Assembler::RegisterID inputDividend, int divisor);
</span><span class="cx"> 
</span><ins>+    bool generatePrologue();
+    void generateEpilogue();
+    Vector&lt;StackAllocator::StackReference&gt; m_prologueStackReferences;
+    
</ins><span class="cx">     Assembler m_assembler;
</span><span class="cx">     RegisterAllocator m_registerAllocator;
</span><span class="cx">     StackAllocator m_stackAllocator;
</span><span class="lines">@@ -542,7 +546,7 @@
</span><span class="cx">     for (unsigned i = 0; i &lt; m_functionCalls.size(); i++)
</span><span class="cx">         linkBuffer.link(m_functionCalls[i].first, m_functionCalls[i].second);
</span><span class="cx"> 
</span><del>-#if CSS_SELECTOR_JIT_DEBUGGING &amp;&amp; ASSERT_DISABLED
</del><ins>+#if CSS_SELECTOR_JIT_DEBUGGING
</ins><span class="cx">     codeRef = linkBuffer.finalizeCodeWithDisassembly(&quot;CSS Selector JIT for \&quot;%s\&quot;&quot;, m_originalSelector-&gt;selectorText().utf8().data());
</span><span class="cx"> #else
</span><span class="cx">     codeRef = FINALIZE_CODE(linkBuffer, (&quot;CSS Selector JIT&quot;));
</span><span class="lines">@@ -858,14 +862,48 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+inline bool SelectorCodeGenerator::generatePrologue()
+{
+#if CPU(ARM64)
+    Vector&lt;JSC::MacroAssembler::RegisterID, 2&gt; prologueRegisters;
+    prologueRegisters.append(JSC::ARM64Registers::lr);
+    prologueRegisters.append(JSC::ARM64Registers::fp);
+    m_prologueStackReferences = m_stackAllocator.push(prologueRegisters);
+    return true;
+#elif CPU(X86_64) &amp;&amp; CSS_SELECTOR_JIT_DEBUGGING
+    Vector&lt;JSC::MacroAssembler::RegisterID, 1&gt; prologueRegister;
+    prologueRegister.append(GPRInfo::callFrameRegister);
+    m_prologueStackReferences = m_stackAllocator.push(prologueRegister);
+    return true;
+#endif
+    return false;
+}
+    
+inline void SelectorCodeGenerator::generateEpilogue()
+{
+#if CPU(ARM64)
+    Vector&lt;JSC::MacroAssembler::RegisterID, 2&gt; prologueRegisters;
+    prologueRegisters.append(JSC::ARM64Registers::lr);
+    prologueRegisters.append(JSC::ARM64Registers::fp);
+    m_stackAllocator.pop(m_prologueStackReferences, prologueRegisters);
+#elif CPU(X86_64) &amp;&amp; CSS_SELECTOR_JIT_DEBUGGING
+    Vector&lt;JSC::MacroAssembler::RegisterID, 1&gt; prologueRegister;
+    prologueRegister.append(GPRInfo::callFrameRegister);
+    m_stackAllocator.pop(m_prologueStackReferences, prologueRegister);
+#endif
+}
+    
</ins><span class="cx"> void SelectorCodeGenerator::generateSelectorChecker()
</span><span class="cx"> {
</span><ins>+    bool needsEpilogue = generatePrologue();
+    
+    Vector&lt;StackAllocator::StackReference&gt; calleeSavedRegisterStackReferences;
</ins><span class="cx">     bool reservedCalleeSavedRegisters = false;
</span><span class="cx">     unsigned availableRegisterCount = m_registerAllocator.availableRegisterCount();
</span><span class="cx">     unsigned minimumRegisterCountForAttributes = minimumRegisterRequirements(m_selectorFragments);
</span><span class="cx">     if (availableRegisterCount &lt; minimumRegisterCountForAttributes) {
</span><span class="cx">         reservedCalleeSavedRegisters = true;
</span><del>-        m_registerAllocator.reserveCalleeSavedRegisters(m_stackAllocator, minimumRegisterCountForAttributes - availableRegisterCount);
</del><ins>+        calleeSavedRegisterStackReferences = m_stackAllocator.push(m_registerAllocator.reserveCalleeSavedRegisters(minimumRegisterCountForAttributes - availableRegisterCount));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     m_registerAllocator.allocateRegister(elementAddressRegister);
</span><span class="lines">@@ -903,7 +941,7 @@
</span><span class="cx">     m_registerAllocator.deallocateRegister(elementAddressRegister);
</span><span class="cx"> 
</span><span class="cx">     if (m_functionType == FunctionType::SimpleSelectorChecker) {
</span><del>-        if (!m_needsAdjacentBacktrackingStart &amp;&amp; !reservedCalleeSavedRegisters) {
</del><ins>+        if (!m_needsAdjacentBacktrackingStart &amp;&amp; !reservedCalleeSavedRegisters &amp;&amp; !needsEpilogue) {
</ins><span class="cx">             // Success.
</span><span class="cx">             m_assembler.move(Assembler::TrustedImm32(1), returnRegister);
</span><span class="cx">             m_assembler.ret();
</span><span class="lines">@@ -928,7 +966,10 @@
</span><span class="cx"> 
</span><span class="cx">             if (m_needsAdjacentBacktrackingStart)
</span><span class="cx">                 m_stackAllocator.popAndDiscardUpTo(m_adjacentBacktrackingStart);
</span><del>-            m_registerAllocator.restoreCalleeSavedRegisters(m_stackAllocator);
</del><ins>+            if (reservedCalleeSavedRegisters)
+                m_stackAllocator.pop(calleeSavedRegisterStackReferences, m_registerAllocator.restoreCalleeSavedRegisters());
+            if (needsEpilogue)
+                generateEpilogue();
</ins><span class="cx">             m_assembler.ret();
</span><span class="cx">         }
</span><span class="cx">     } else {
</span><span class="lines">@@ -946,7 +987,10 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         m_stackAllocator.popAndDiscardUpTo(m_checkingContextStackReference);
</span><del>-        m_registerAllocator.restoreCalleeSavedRegisters(m_stackAllocator);
</del><ins>+        if (reservedCalleeSavedRegisters)
+            m_stackAllocator.pop(calleeSavedRegisterStackReferences, m_registerAllocator.restoreCalleeSavedRegisters());
+        if (needsEpilogue)
+            generateEpilogue();
</ins><span class="cx">         m_assembler.ret();
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceWebCorecssjitStackAllocatorh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/cssjit/StackAllocator.h (169296 => 169297)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/cssjit/StackAllocator.h        2014-05-24 00:29:44 UTC (rev 169296)
+++ trunk/Source/WebCore/cssjit/StackAllocator.h        2014-05-24 01:06:16 UTC (rev 169297)
</span><span class="lines">@@ -68,31 +68,83 @@
</span><span class="cx">         return StackReference(m_offsetFromTop);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // FIXME: ARM64 needs an API take a list of register to push and pop to use strp and ldrp when possible.
-    StackReference push(JSC::MacroAssembler::RegisterID registerID)
</del><ins>+    Vector&lt;StackReference&gt; push(const Vector&lt;JSC::MacroAssembler::RegisterID&gt;&amp; registerIDs)
</ins><span class="cx">     {
</span><span class="cx">         RELEASE_ASSERT(!m_hasFunctionCallPadding);
</span><ins>+        unsigned registerCount = registerIDs.size();
+        Vector&lt;StackReference&gt; stackReferences;
+        stackReferences.reserveInitialCapacity(registerCount);
</ins><span class="cx"> #if CPU(ARM64)
</span><del>-        m_assembler.m_assembler.str&lt;64&gt;(registerID, JSC::ARM64Registers::sp, JSC::PreIndex(-16));
</del><ins>+        for (unsigned i = 0; i &lt; registerCount - 1; i += 2) {
+            m_assembler.pushPair(registerIDs[i + 1], registerIDs[i]);
+            m_offsetFromTop += stackUnitInBytes;
+            stackReferences.append(StackReference(m_offsetFromTop - stackUnitInBytes / 2));
+            stackReferences.append(StackReference(m_offsetFromTop));
+        }
+        if (registerCount % 2) {
+            m_assembler.pushToSave(registerIDs[registerCount - 1]);
+            m_offsetFromTop += stackUnitInBytes;
+            stackReferences.append(StackReference(m_offsetFromTop));
+        }
</ins><span class="cx"> #else
</span><del>-        m_assembler.push(registerID);
</del><ins>+        for (auto registerID : registerIDs) {
+            m_assembler.pushToSave(registerID);
+            m_offsetFromTop += stackUnitInBytes;
+            stackReferences.append(StackReference(m_offsetFromTop));
+        }
</ins><span class="cx"> #endif
</span><ins>+        return stackReferences;
+    }
+
+    StackReference push(JSC::MacroAssembler::RegisterID registerID)
+    {
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        m_assembler.pushToSave(registerID);
</ins><span class="cx">         m_offsetFromTop += stackUnitInBytes;
</span><span class="cx">         return StackReference(m_offsetFromTop);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID)
</del><ins>+    void pop(const Vector&lt;StackReference&gt;&amp; stackReferences, const Vector&lt;JSC::MacroAssembler::RegisterID&gt;&amp; registerIDs)
</ins><span class="cx">     {
</span><del>-        RELEASE_ASSERT(stackReference == m_offsetFromTop);
</del><span class="cx">         RELEASE_ASSERT(!m_hasFunctionCallPadding);
</span><del>-        ASSERT(m_offsetFromTop &gt; 0);
-        m_offsetFromTop -= stackUnitInBytes;
</del><ins>+        
+        unsigned registerCount = registerIDs.size();
+        RELEASE_ASSERT(stackReferences.size() == registerCount);
</ins><span class="cx"> #if CPU(ARM64)
</span><del>-        m_assembler.m_assembler.ldr&lt;64&gt;(registerID, JSC::ARM64Registers::sp, JSC::PostIndex(16));
</del><ins>+        ASSERT(m_offsetFromTop &gt;= stackUnitInBytes * registerCount);
+        unsigned registerCountOdd = registerCount % 2;
+        if (registerCountOdd) {
+            RELEASE_ASSERT(stackReferences[registerCount - 1] == m_offsetFromTop);
+            RELEASE_ASSERT(m_offsetFromTop &gt;= stackUnitInBytes);
+            m_offsetFromTop -= stackUnitInBytes;
+            m_assembler.popToRestore(registerIDs[registerCount - 1]);
+        }
+        for (unsigned i = registerCount - registerCountOdd; i &gt; 0; i -= 2) {
+            RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop);
+            RELEASE_ASSERT(stackReferences[i - 2] == m_offsetFromTop - stackUnitInBytes / 2);
+            RELEASE_ASSERT(m_offsetFromTop &gt;= stackUnitInBytes);
+            m_offsetFromTop -= stackUnitInBytes;
+            m_assembler.popPair(registerIDs[i - 1], registerIDs[i - 2]);
+        }
</ins><span class="cx"> #else
</span><del>-        m_assembler.pop(registerID);
</del><ins>+        ASSERT(m_offsetFromTop &gt;= stackUnitInBytes * registerCount);
+        for (unsigned i = registerCount; i &gt; 0; --i) {
+            RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop);
+            RELEASE_ASSERT(m_offsetFromTop &gt;= stackUnitInBytes);
+            m_offsetFromTop -= stackUnitInBytes;
+            m_assembler.popToRestore(registerIDs[i - 1]);
+        }
</ins><span class="cx"> #endif
</span><span class="cx">     }
</span><ins>+    
+    void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID)
+    {
+        RELEASE_ASSERT(stackReference == m_offsetFromTop);
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        RELEASE_ASSERT(m_offsetFromTop &gt;= stackUnitInBytes);
+        m_offsetFromTop -= stackUnitInBytes;
+        m_assembler.popToRestore(registerID);
+    }
</ins><span class="cx"> 
</span><span class="cx">     void popAndDiscard(StackReference stackReference)
</span><span class="cx">     {
</span></span></pre>
</div>
</div>

</body>
</html>