Make CSS JIT run on ARM64.
authorachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 24 May 2014 01:06:16 +0000 (01:06 +0000)
committerachristensen@apple.com <achristensen@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 24 May 2014 01:06:16 +0000 (01:06 +0000)
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.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@169297 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/cssjit/FunctionCall.h
Source/WebCore/cssjit/RegisterAllocator.h
Source/WebCore/cssjit/SelectorCompiler.cpp
Source/WebCore/cssjit/StackAllocator.h

index 85e076e..a2d04b6 100644 (file)
@@ -1,3 +1,36 @@
+2014-05-23  Alex Christensen  <achristensen@webkit.org>
+
+        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.
+
 2014-05-23  Jeremy Jones  <jeremyj@apple.com>
 
         Hide fullscreen immediately when switching tabs.
index b7cf424..976a300 100644 (file)
@@ -165,20 +165,14 @@ private:
     void saveAllocatedRegisters()
     {
         ASSERT(m_savedRegisterStackReferences.isEmpty());
-
-        unsigned allocatedRegistersCount = m_registerAllocator.allocatedRegisters().size();
-        m_savedRegisterStackReferences.reserveCapacity(allocatedRegistersCount);
-
-        for (unsigned i = 0; i < allocatedRegistersCount; ++i) {
-            JSC::MacroAssembler::RegisterID registerID = m_registerAllocator.allocatedRegisters()[i];
-            m_savedRegisterStackReferences.append(m_stackAllocator.push(registerID));
-        }
+        const Vector<JSC::MacroAssembler::RegisterID, registerCount>& allocatedRegisters = m_registerAllocator.allocatedRegisters();
+        Vector<StackAllocator::StackReference> stackReferences = m_stackAllocator.push(allocatedRegisters);
+        m_savedRegisterStackReferences.appendVector(stackReferences);
     }
 
     void restoreAllocatedRegisters()
     {
-        for (unsigned i = m_registerAllocator.allocatedRegisters().size(); i > 0; --i)
-            m_stackAllocator.pop(m_savedRegisterStackReferences[i - 1], m_registerAllocator.allocatedRegisters()[i - 1]);
+        m_stackAllocator.pop(m_savedRegisterStackReferences, m_registerAllocator.allocatedRegisters());
         m_savedRegisterStackReferences.clear();
     }
 
index 0ecfb91..40d255b 100644 (file)
@@ -29,7 +29,6 @@
 #if ENABLE(CSS_SELECTOR_JIT)
 
 #include <JavaScriptCore/MacroAssembler.h>
-#include <StackAllocator.h>
 #include <wtf/HashSet.h>
 #include <wtf/Vector.h>
 
@@ -78,7 +77,8 @@ static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
 #else
 #error RegisterAllocator has no defined registers for the architecture.
 #endif
-static const unsigned registerCount = WTF_ARRAY_LENGTH(callerSavedRegisters) + WTF_ARRAY_LENGTH(calleeSavedRegisters);
+static const unsigned calleeSavedRegisterCount = WTF_ARRAY_LENGTH(calleeSavedRegisters);
+static const unsigned registerCount = calleeSavedRegisterCount + WTF_ARRAY_LENGTH(callerSavedRegisters);
 
 class RegisterAllocator {
 public:
@@ -113,25 +113,23 @@ public:
         RELEASE_ASSERT(m_registers.add(registerID).isNewEntry);
     }
 
-    void reserveCalleeSavedRegisters(StackAllocator& stack, unsigned count)
+    const Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount>& reserveCalleeSavedRegisters(unsigned count)
     {
-        unsigned finalSize = m_calleeSavedRegisters.size() + count;
-        RELEASE_ASSERT(finalSize <= WTF_ARRAY_LENGTH(calleeSavedRegisters));
-        for (unsigned i = m_calleeSavedRegisters.size(); i < finalSize; ++i) {
+        RELEASE_ASSERT(count <= WTF_ARRAY_LENGTH(calleeSavedRegisters));
+        RELEASE_ASSERT(!m_reservedCalleeSavedRegisters.size());
+        for (unsigned i = 0; i < count; ++i) {
             JSC::MacroAssembler::RegisterID registerId = calleeSavedRegisters[i];
-            m_calleeSavedRegisters.append(stack.push(registerId));
+            m_reservedCalleeSavedRegisters.append(registerId);
             m_registers.add(registerId);
         }
+        return m_reservedCalleeSavedRegisters;
     }
 
-    void restoreCalleeSavedRegisters(StackAllocator& stack)
+    Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> restoreCalleeSavedRegisters()
     {
-        for (unsigned i = m_calleeSavedRegisters.size(); i > 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();
+        Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> registers(m_reservedCalleeSavedRegisters);
+        m_reservedCalleeSavedRegisters.clear();
+        return registers;
     }
 
     const Vector<JSC::MacroAssembler::RegisterID, registerCount>& allocatedRegisters() const { return m_allocatedRegisters; }
@@ -150,7 +148,7 @@ public:
 private:
     HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> m_registers;
     Vector<JSC::MacroAssembler::RegisterID, registerCount> m_allocatedRegisters;
-    Vector<StackAllocator::StackReference, WTF_ARRAY_LENGTH(calleeSavedRegisters)> m_calleeSavedRegisters;
+    Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> m_reservedCalleeSavedRegisters;
 };
 
 class LocalRegister {
@@ -184,7 +182,7 @@ inline RegisterAllocator::RegisterAllocator()
 
 inline RegisterAllocator::~RegisterAllocator()
 {
-    RELEASE_ASSERT(m_calleeSavedRegisters.isEmpty());
+    RELEASE_ASSERT(m_reservedCalleeSavedRegisters.isEmpty());
 }
 
 } // namespace WebCore
index c0c1bd6..e3b5b85 100644 (file)
@@ -221,6 +221,10 @@ private:
     Assembler::Jump modulo(JSC::MacroAssembler::ResultCondition, Assembler::RegisterID inputDividend, int divisor);
     void moduloIsZero(Assembler::JumpList& failureCases, Assembler::RegisterID inputDividend, int divisor);
 
+    bool generatePrologue();
+    void generateEpilogue();
+    Vector<StackAllocator::StackReference> m_prologueStackReferences;
+    
     Assembler m_assembler;
     RegisterAllocator m_registerAllocator;
     StackAllocator m_stackAllocator;
@@ -542,7 +546,7 @@ inline SelectorCompilationStatus SelectorCodeGenerator::compile(JSC::VM* vm, JSC
     for (unsigned i = 0; i < m_functionCalls.size(); i++)
         linkBuffer.link(m_functionCalls[i].first, m_functionCalls[i].second);
 
-#if CSS_SELECTOR_JIT_DEBUGGING && ASSERT_DISABLED
+#if CSS_SELECTOR_JIT_DEBUGGING
     codeRef = linkBuffer.finalizeCodeWithDisassembly("CSS Selector JIT for \"%s\"", m_originalSelector->selectorText().utf8().data());
 #else
     codeRef = FINALIZE_CODE(linkBuffer, ("CSS Selector JIT"));
@@ -858,14 +862,48 @@ void SelectorCodeGenerator::computeBacktrackingInformation()
     }
 }
 
+inline bool SelectorCodeGenerator::generatePrologue()
+{
+#if CPU(ARM64)
+    Vector<JSC::MacroAssembler::RegisterID, 2> prologueRegisters;
+    prologueRegisters.append(JSC::ARM64Registers::lr);
+    prologueRegisters.append(JSC::ARM64Registers::fp);
+    m_prologueStackReferences = m_stackAllocator.push(prologueRegisters);
+    return true;
+#elif CPU(X86_64) && CSS_SELECTOR_JIT_DEBUGGING
+    Vector<JSC::MacroAssembler::RegisterID, 1> prologueRegister;
+    prologueRegister.append(GPRInfo::callFrameRegister);
+    m_prologueStackReferences = m_stackAllocator.push(prologueRegister);
+    return true;
+#endif
+    return false;
+}
+    
+inline void SelectorCodeGenerator::generateEpilogue()
+{
+#if CPU(ARM64)
+    Vector<JSC::MacroAssembler::RegisterID, 2> prologueRegisters;
+    prologueRegisters.append(JSC::ARM64Registers::lr);
+    prologueRegisters.append(JSC::ARM64Registers::fp);
+    m_stackAllocator.pop(m_prologueStackReferences, prologueRegisters);
+#elif CPU(X86_64) && CSS_SELECTOR_JIT_DEBUGGING
+    Vector<JSC::MacroAssembler::RegisterID, 1> prologueRegister;
+    prologueRegister.append(GPRInfo::callFrameRegister);
+    m_stackAllocator.pop(m_prologueStackReferences, prologueRegister);
+#endif
+}
+    
 void SelectorCodeGenerator::generateSelectorChecker()
 {
+    bool needsEpilogue = generatePrologue();
+    
+    Vector<StackAllocator::StackReference> calleeSavedRegisterStackReferences;
     bool reservedCalleeSavedRegisters = false;
     unsigned availableRegisterCount = m_registerAllocator.availableRegisterCount();
     unsigned minimumRegisterCountForAttributes = minimumRegisterRequirements(m_selectorFragments);
     if (availableRegisterCount < minimumRegisterCountForAttributes) {
         reservedCalleeSavedRegisters = true;
-        m_registerAllocator.reserveCalleeSavedRegisters(m_stackAllocator, minimumRegisterCountForAttributes - availableRegisterCount);
+        calleeSavedRegisterStackReferences = m_stackAllocator.push(m_registerAllocator.reserveCalleeSavedRegisters(minimumRegisterCountForAttributes - availableRegisterCount));
     }
 
     m_registerAllocator.allocateRegister(elementAddressRegister);
@@ -903,7 +941,7 @@ void SelectorCodeGenerator::generateSelectorChecker()
     m_registerAllocator.deallocateRegister(elementAddressRegister);
 
     if (m_functionType == FunctionType::SimpleSelectorChecker) {
-        if (!m_needsAdjacentBacktrackingStart && !reservedCalleeSavedRegisters) {
+        if (!m_needsAdjacentBacktrackingStart && !reservedCalleeSavedRegisters && !needsEpilogue) {
             // Success.
             m_assembler.move(Assembler::TrustedImm32(1), returnRegister);
             m_assembler.ret();
@@ -928,7 +966,10 @@ void SelectorCodeGenerator::generateSelectorChecker()
 
             if (m_needsAdjacentBacktrackingStart)
                 m_stackAllocator.popAndDiscardUpTo(m_adjacentBacktrackingStart);
-            m_registerAllocator.restoreCalleeSavedRegisters(m_stackAllocator);
+            if (reservedCalleeSavedRegisters)
+                m_stackAllocator.pop(calleeSavedRegisterStackReferences, m_registerAllocator.restoreCalleeSavedRegisters());
+            if (needsEpilogue)
+                generateEpilogue();
             m_assembler.ret();
         }
     } else {
@@ -946,7 +987,10 @@ void SelectorCodeGenerator::generateSelectorChecker()
         }
 
         m_stackAllocator.popAndDiscardUpTo(m_checkingContextStackReference);
-        m_registerAllocator.restoreCalleeSavedRegisters(m_stackAllocator);
+        if (reservedCalleeSavedRegisters)
+            m_stackAllocator.pop(calleeSavedRegisterStackReferences, m_registerAllocator.restoreCalleeSavedRegisters());
+        if (needsEpilogue)
+            generateEpilogue();
         m_assembler.ret();
     }
 }
index baff9f0..54d47e5 100644 (file)
@@ -68,31 +68,83 @@ public:
         return StackReference(m_offsetFromTop);
     }
 
-    // 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)
+    Vector<StackReference> push(const Vector<JSC::MacroAssembler::RegisterID>& registerIDs)
     {
         RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        unsigned registerCount = registerIDs.size();
+        Vector<StackReference> stackReferences;
+        stackReferences.reserveInitialCapacity(registerCount);
 #if CPU(ARM64)
-        m_assembler.m_assembler.str<64>(registerID, JSC::ARM64Registers::sp, JSC::PreIndex(-16));
+        for (unsigned i = 0; i < 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));
+        }
 #else
-        m_assembler.push(registerID);
+        for (auto registerID : registerIDs) {
+            m_assembler.pushToSave(registerID);
+            m_offsetFromTop += stackUnitInBytes;
+            stackReferences.append(StackReference(m_offsetFromTop));
+        }
 #endif
+        return stackReferences;
+    }
+
+    StackReference push(JSC::MacroAssembler::RegisterID registerID)
+    {
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        m_assembler.pushToSave(registerID);
         m_offsetFromTop += stackUnitInBytes;
         return StackReference(m_offsetFromTop);
     }
 
-    void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID)
+    void pop(const Vector<StackReference>& stackReferences, const Vector<JSC::MacroAssembler::RegisterID>& registerIDs)
     {
-        RELEASE_ASSERT(stackReference == m_offsetFromTop);
         RELEASE_ASSERT(!m_hasFunctionCallPadding);
-        ASSERT(m_offsetFromTop > 0);
-        m_offsetFromTop -= stackUnitInBytes;
+        
+        unsigned registerCount = registerIDs.size();
+        RELEASE_ASSERT(stackReferences.size() == registerCount);
 #if CPU(ARM64)
-        m_assembler.m_assembler.ldr<64>(registerID, JSC::ARM64Registers::sp, JSC::PostIndex(16));
+        ASSERT(m_offsetFromTop >= stackUnitInBytes * registerCount);
+        unsigned registerCountOdd = registerCount % 2;
+        if (registerCountOdd) {
+            RELEASE_ASSERT(stackReferences[registerCount - 1] == m_offsetFromTop);
+            RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
+            m_offsetFromTop -= stackUnitInBytes;
+            m_assembler.popToRestore(registerIDs[registerCount - 1]);
+        }
+        for (unsigned i = registerCount - registerCountOdd; i > 0; i -= 2) {
+            RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop);
+            RELEASE_ASSERT(stackReferences[i - 2] == m_offsetFromTop - stackUnitInBytes / 2);
+            RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
+            m_offsetFromTop -= stackUnitInBytes;
+            m_assembler.popPair(registerIDs[i - 1], registerIDs[i - 2]);
+        }
 #else
-        m_assembler.pop(registerID);
+        ASSERT(m_offsetFromTop >= stackUnitInBytes * registerCount);
+        for (unsigned i = registerCount; i > 0; --i) {
+            RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop);
+            RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
+            m_offsetFromTop -= stackUnitInBytes;
+            m_assembler.popToRestore(registerIDs[i - 1]);
+        }
 #endif
     }
+    
+    void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID)
+    {
+        RELEASE_ASSERT(stackReference == m_offsetFromTop);
+        RELEASE_ASSERT(!m_hasFunctionCallPadding);
+        RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
+        m_offsetFromTop -= stackUnitInBytes;
+        m_assembler.popToRestore(registerID);
+    }
 
     void popAndDiscard(StackReference stackReference)
     {