Make CSS JIT run on ARM64.
[WebKit-https.git] / Source / WebCore / cssjit / RegisterAllocator.h
1 /*
2  * Copyright (C) 2013, 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef RegisterAllocator_h
27 #define RegisterAllocator_h
28
29 #if ENABLE(CSS_SELECTOR_JIT)
30
31 #include <JavaScriptCore/MacroAssembler.h>
32 #include <wtf/HashSet.h>
33 #include <wtf/Vector.h>
34
35 namespace WebCore {
36
37 #if CPU(ARM64)
38 static const JSC::MacroAssembler::RegisterID callerSavedRegisters[] = {
39     JSC::ARM64Registers::x0,
40     JSC::ARM64Registers::x1,
41     JSC::ARM64Registers::x2,
42     JSC::ARM64Registers::x3,
43     JSC::ARM64Registers::x4,
44     JSC::ARM64Registers::x5,
45     JSC::ARM64Registers::x6,
46     JSC::ARM64Registers::x7,
47     JSC::ARM64Registers::x8,
48     JSC::ARM64Registers::x9,
49     JSC::ARM64Registers::x10,
50     JSC::ARM64Registers::x11,
51     JSC::ARM64Registers::x12,
52     JSC::ARM64Registers::x13,
53     JSC::ARM64Registers::x14,
54     JSC::ARM64Registers::x15,
55 };
56 static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
57     JSC::ARM64Registers::x19
58 };
59 #elif CPU(X86_64)
60 static const JSC::MacroAssembler::RegisterID callerSavedRegisters[] = {
61     JSC::X86Registers::eax,
62     JSC::X86Registers::ecx,
63     JSC::X86Registers::edx,
64     JSC::X86Registers::esi,
65     JSC::X86Registers::edi,
66     JSC::X86Registers::r8,
67     JSC::X86Registers::r9,
68     JSC::X86Registers::r10,
69     JSC::X86Registers::r11
70 };
71 static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
72     JSC::X86Registers::r12,
73     JSC::X86Registers::r13,
74     JSC::X86Registers::r14,
75     JSC::X86Registers::r15
76 };
77 #else
78 #error RegisterAllocator has no defined registers for the architecture.
79 #endif
80 static const unsigned calleeSavedRegisterCount = WTF_ARRAY_LENGTH(calleeSavedRegisters);
81 static const unsigned registerCount = calleeSavedRegisterCount + WTF_ARRAY_LENGTH(callerSavedRegisters);
82
83 class RegisterAllocator {
84 public:
85     RegisterAllocator();
86     ~RegisterAllocator();
87
88     unsigned availableRegisterCount() const { return m_registers.size(); }
89
90     JSC::MacroAssembler::RegisterID allocateRegister()
91     {
92         auto first = m_registers.begin();
93         JSC::MacroAssembler::RegisterID registerID = static_cast<JSC::MacroAssembler::RegisterID>(*first);
94         RELEASE_ASSERT(m_registers.remove(first));
95         ASSERT(!m_allocatedRegisters.contains(registerID));
96         m_allocatedRegisters.append(registerID);
97         return registerID;
98     }
99
100     void allocateRegister(JSC::MacroAssembler::RegisterID registerID)
101     {
102         RELEASE_ASSERT(m_registers.remove(registerID));
103         ASSERT(!m_allocatedRegisters.contains(registerID));
104         m_allocatedRegisters.append(registerID);
105     }
106
107     void deallocateRegister(JSC::MacroAssembler::RegisterID registerID)
108     {
109         ASSERT(m_allocatedRegisters.contains(registerID));
110         // Most allocation/deallocation happen in stack-like order. In the common case, this
111         // just removes the last item.
112         m_allocatedRegisters.remove(m_allocatedRegisters.reverseFind(registerID));
113         RELEASE_ASSERT(m_registers.add(registerID).isNewEntry);
114     }
115
116     const Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount>& reserveCalleeSavedRegisters(unsigned count)
117     {
118         RELEASE_ASSERT(count <= WTF_ARRAY_LENGTH(calleeSavedRegisters));
119         RELEASE_ASSERT(!m_reservedCalleeSavedRegisters.size());
120         for (unsigned i = 0; i < count; ++i) {
121             JSC::MacroAssembler::RegisterID registerId = calleeSavedRegisters[i];
122             m_reservedCalleeSavedRegisters.append(registerId);
123             m_registers.add(registerId);
124         }
125         return m_reservedCalleeSavedRegisters;
126     }
127
128     Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> restoreCalleeSavedRegisters()
129     {
130         Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> registers(m_reservedCalleeSavedRegisters);
131         m_reservedCalleeSavedRegisters.clear();
132         return registers;
133     }
134
135     const Vector<JSC::MacroAssembler::RegisterID, registerCount>& allocatedRegisters() const { return m_allocatedRegisters; }
136
137     static bool isValidRegister(JSC::MacroAssembler::RegisterID registerID)
138     {
139 #if CPU(ARM64)
140         return registerID >= JSC::ARM64Registers::x0 && registerID <= JSC::ARM64Registers::x15;
141 #elif CPU(X86_64)
142         return registerID >= JSC::X86Registers::eax && registerID <= JSC::X86Registers::r15;
143 #else
144 #error RegisterAllocator does not define the valid register range for the current architecture.
145 #endif
146     }
147
148 private:
149     HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> m_registers;
150     Vector<JSC::MacroAssembler::RegisterID, registerCount> m_allocatedRegisters;
151     Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> m_reservedCalleeSavedRegisters;
152 };
153
154 class LocalRegister {
155 public:
156     explicit LocalRegister(RegisterAllocator& allocator)
157         : m_allocator(allocator)
158         , m_register(allocator.allocateRegister())
159     {
160     }
161
162     ~LocalRegister()
163     {
164         m_allocator.deallocateRegister(m_register);
165     }
166
167     operator JSC::MacroAssembler::RegisterID() const
168     {
169         return m_register;
170     }
171
172 private:
173     RegisterAllocator& m_allocator;
174     JSC::MacroAssembler::RegisterID m_register;
175 };
176
177 inline RegisterAllocator::RegisterAllocator()
178 {
179     for (unsigned i = 0; i < WTF_ARRAY_LENGTH(callerSavedRegisters); ++i)
180         m_registers.add(callerSavedRegisters[i]);
181 }
182
183 inline RegisterAllocator::~RegisterAllocator()
184 {
185     RELEASE_ASSERT(m_reservedCalleeSavedRegisters.isEmpty());
186 }
187
188 } // namespace WebCore
189
190 #endif // ENABLE(CSS_SELECTOR_JIT)
191
192 #endif // RegisterAllocator_h
193