⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 185719 in webkit


Ignore:
Timestamp:
Jun 18, 2015, 1:29:37 PM (11 years ago)
Author:
benjamin@webkit.org
Message:

[CSS JIT][ARMv7] The pseudo element early exit trashes r6
https://bugs.webkit.org/show_bug.cgi?id=146078

Patch by Benjamin Poulain <bpoulain@apple.com> on 2015-06-18
Reviewed by Alex Christensen.

The pseudo element early failure runs before we generate the prologue.
The reason is that we can often exit immediately on function entry, before
we even touch any memory.

On ARMv7, we don't have many spare registers so the MacroAssembler
uses r6 as a scratch register and the client code is expected to save
it.

In the early failure case, we were not pushing r6 before using the MacroAssembler
and its value could be trashed.

This patch push the macro assembler registers separately from the prologue.

For restoring the registers, a new function generateFunctionEnding() encapsulate
the pop() and ret().

  • cssjit/SelectorCompiler.cpp:

(WebCore::SelectorCompiler::SelectorCodeGenerator::pushMacroAssemblerRegisters):
(WebCore::SelectorCompiler::SelectorCodeGenerator::popMacroAssemblerRegisters):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generatePrologue):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateEpilogue):
(WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):

  • cssjit/StackAllocator.h:

(WebCore::StackAllocator::operator=):
We have a new case for the stack allocator: some stack changes are conditional
at compile time instead of runtime. This is easy to deal with by overriding
the stack if a path is not taken at compile time.

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r185717 r185719  
     12015-06-18  Benjamin Poulain  <bpoulain@apple.com>
     2
     3        [CSS JIT][ARMv7] The pseudo element early exit trashes r6
     4        https://bugs.webkit.org/show_bug.cgi?id=146078
     5
     6        Reviewed by Alex Christensen.
     7
     8        The pseudo element early failure runs before we generate the prologue.
     9        The reason is that we can often exit immediately on function entry, before
     10        we even touch any memory.
     11
     12        On ARMv7, we don't have many spare registers so the MacroAssembler
     13        uses r6 as a scratch register and the client code is expected to save
     14        it.
     15
     16        In the early failure case, we were not pushing r6 before using the MacroAssembler
     17        and its value could be trashed.
     18
     19        This patch push the macro assembler registers separately from the prologue.
     20
     21        For restoring the registers, a new function generateFunctionEnding() encapsulate
     22        the pop() and ret().
     23
     24        * cssjit/SelectorCompiler.cpp:
     25        (WebCore::SelectorCompiler::SelectorCodeGenerator::pushMacroAssemblerRegisters):
     26        (WebCore::SelectorCompiler::SelectorCodeGenerator::popMacroAssemblerRegisters):
     27        (WebCore::SelectorCompiler::SelectorCodeGenerator::generatePrologue):
     28        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateEpilogue):
     29        (WebCore::SelectorCompiler::SelectorCodeGenerator::generateSelectorChecker):
     30
     31        * cssjit/StackAllocator.h:
     32        (WebCore::StackAllocator::operator=):
     33        We have a new case for the stack allocator: some stack changes are conditional
     34        at compile time instead of runtime. This is easy to deal with by overriding
     35        the stack if a path is not taken at compile time.
     36
    1372015-06-17  Conrad Shultz  <conrad_shultz@apple.com>
    238
  • trunk/Source/WebCore/cssjit/SelectorCompiler.cpp

    r185071 r185719  
    341341    void moduloIsZero(Assembler::JumpList& failureCases, Assembler::RegisterID inputDividend, int divisor);
    342342
     343    void pushMacroAssemblerRegisters();
     344    void popMacroAssemblerRegisters(StackAllocator&);
    343345    bool generatePrologue();
    344     void generateEpilogue();
     346    void generateEpilogue(StackAllocator&);
     347    StackAllocator::StackReferenceVector m_macroAssemblerRegistersStackReferences;
    345348    StackAllocator::StackReferenceVector m_prologueStackReferences;
    346349
     
    16801683}
    16811684
     1685inline void SelectorCodeGenerator::pushMacroAssemblerRegisters()
     1686{
     1687#if CPU(ARM_THUMB2)
     1688    // r6 is tempRegister in RegisterAllocator.h and addressTempRegister in MacroAssemblerARMv7.h and must be preserved by the callee.
     1689    Vector<JSC::MacroAssembler::RegisterID, 1> macroAssemblerRegisters({ JSC::ARMRegisters::r6 });
     1690    m_macroAssemblerRegistersStackReferences = m_stackAllocator.push(macroAssemblerRegisters);
     1691#endif
     1692}
     1693
     1694inline void SelectorCodeGenerator::popMacroAssemblerRegisters(StackAllocator& stackAllocator)
     1695{
     1696#if CPU(ARM_THUMB2)
     1697    Vector<JSC::MacroAssembler::RegisterID, 1> macroAssemblerRegisters({ JSC::ARMRegisters::r6 });
     1698    stackAllocator.pop(m_macroAssemblerRegistersStackReferences, macroAssemblerRegisters);
     1699#else
     1700    UNUSED_PARAM(stackAllocator);
     1701#endif
     1702}
     1703
    16821704inline bool SelectorCodeGenerator::generatePrologue()
    16831705{
     
    16891711    return true;
    16901712#elif CPU(ARM_THUMB2)
    1691     Vector<JSC::MacroAssembler::RegisterID, 2> prologueRegisters;
     1713    Vector<JSC::MacroAssembler::RegisterID, 1> prologueRegisters;
    16921714    prologueRegisters.append(JSC::ARMRegisters::lr);
    1693     // r6 is tempRegister in RegisterAllocator.h and addressTempRegister in MacroAssemblerARMv7.h and must be preserved by the callee.
    1694     prologueRegisters.append(JSC::ARMRegisters::r6);
    16951715    m_prologueStackReferences = m_stackAllocator.push(prologueRegisters);
    16961716    return true;
     
    17041724}
    17051725
    1706 inline void SelectorCodeGenerator::generateEpilogue()
     1726inline void SelectorCodeGenerator::generateEpilogue(StackAllocator& stackAllocator)
    17071727{
    17081728#if CPU(ARM64)
    1709     Vector<JSC::MacroAssembler::RegisterID, 2> prologueRegisters;
    1710     prologueRegisters.append(JSC::ARM64Registers::lr);
    1711     prologueRegisters.append(JSC::ARM64Registers::fp);
    1712     m_stackAllocator.pop(m_prologueStackReferences, prologueRegisters);
     1729    Vector<JSC::MacroAssembler::RegisterID, 2> prologueRegisters({ JSC::ARM64Registers::lr, JSC::ARM64Registers::fp });
     1730    stackAllocator.pop(m_prologueStackReferences, prologueRegisters);
    17131731#elif CPU(ARM_THUMB2)
    1714     Vector<JSC::MacroAssembler::RegisterID, 2> prologueRegisters;
    1715     prologueRegisters.append(JSC::ARMRegisters::lr);
    1716     prologueRegisters.append(JSC::ARMRegisters::r6);
    1717     m_stackAllocator.pop(m_prologueStackReferences, prologueRegisters);
     1732    Vector<JSC::MacroAssembler::RegisterID, 1> prologueRegister({ JSC::ARMRegisters::lr });
     1733    stackAllocator.pop(m_prologueStackReferences, prologueRegister);
    17181734#elif CPU(X86_64) && CSS_SELECTOR_JIT_DEBUGGING
    1719     Vector<JSC::MacroAssembler::RegisterID, 1> prologueRegister;
    1720     prologueRegister.append(callFrameRegister);
    1721     m_stackAllocator.pop(m_prologueStackReferences, prologueRegister);
     1735    Vector<JSC::MacroAssembler::RegisterID, 1> prologueRegister({ callFrameRegister });
     1736    stackAllocator.pop(m_prologueStackReferences, prologueRegister);
     1737#else
     1738    UNUSED_PARAM(stackAllocator);
    17221739#endif
    17231740}
     
    17351752void SelectorCodeGenerator::generateSelectorChecker()
    17361753{
     1754    pushMacroAssemblerRegisters();
     1755    StackAllocator earlyFailureStack = m_stackAllocator;
     1756
    17371757    Assembler::JumpList failureOnFunctionEntry;
    17381758    // Test selector's pseudo element equals to requested PseudoId.
     
    17611781    if (m_selectorFragments.stackRequirements > maximumBacktrackingAllocations) {
    17621782        m_assembler.move(Assembler::TrustedImm32(0), returnRegister);
     1783        popMacroAssemblerRegisters(m_stackAllocator);
    17631784        m_assembler.ret();
    17641785        return;
     
    18191840    if (m_functionType == FunctionType::SimpleSelectorChecker) {
    18201841        if (temporaryStackBase == m_stackAllocator.stackTop() && !reservedCalleeSavedRegisters && !needsEpilogue) {
     1842            StackAllocator successStack = m_stackAllocator;
     1843            StackAllocator failureStack = m_stackAllocator;
     1844
    18211845            ASSERT(!m_selectorFragments.stackRequirements);
    18221846            // Success.
    18231847            m_assembler.move(Assembler::TrustedImm32(1), returnRegister);
     1848            popMacroAssemblerRegisters(successStack);
    18241849            m_assembler.ret();
    18251850
     
    18291854                failureCases.link(&m_assembler);
    18301855                m_assembler.move(Assembler::TrustedImm32(0), returnRegister);
     1856                popMacroAssemblerRegisters(failureStack);
    18311857                m_assembler.ret();
    1832             }
     1858            } else
     1859                failureStack = successStack;
     1860
     1861            m_stackAllocator.merge(WTF::move(successStack), WTF::move(failureStack));
    18331862            return;
    18341863        }
     
    18501879    if (reservedCalleeSavedRegisters)
    18511880        m_stackAllocator.pop(calleeSavedRegisterStackReferences, m_registerAllocator.restoreCalleeSavedRegisters());
     1881
     1882    StackAllocator successStack = m_stackAllocator;
    18521883    if (needsEpilogue)
    1853         generateEpilogue();
     1884        generateEpilogue(successStack);
     1885    popMacroAssemblerRegisters(successStack);
    18541886    m_assembler.ret();
    18551887
     
    18581890        failureOnFunctionEntry.link(&m_assembler);
    18591891        m_assembler.move(Assembler::TrustedImm32(0), returnRegister);
     1892        popMacroAssemblerRegisters(earlyFailureStack);
    18601893        m_assembler.ret();
    1861     }
     1894    } else
     1895        earlyFailureStack = successStack;
     1896    m_stackAllocator.merge(WTF::move(successStack), WTF::move(earlyFailureStack));
    18621897}
    18631898
  • trunk/Source/WebCore/cssjit/StackAllocator.h

    r183065 r185719  
    240240    }
    241241
     242    StackAllocator& operator=(const StackAllocator& other)
     243    {
     244        RELEASE_ASSERT(&m_assembler == &other.m_assembler);
     245        m_offsetFromTop = other.m_offsetFromTop;
     246        m_hasFunctionCallPadding = other.m_hasFunctionCallPadding;
     247        return *this;
     248    }
     249
     250
    242251private:
    243252    static unsigned stackUnitInBytes()
Note: See TracChangeset for help on using the changeset viewer.