CSS Selectors: fix attribute case-insensitive matching of Contain and List
[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/Deque.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 };
55 static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
56     JSC::ARM64Registers::x19
57 };
58 static const JSC::MacroAssembler::RegisterID tempRegister = JSC::ARM64Registers::x15;
59 #elif CPU(ARM_THUMB2)
60 static const JSC::MacroAssembler::RegisterID callerSavedRegisters[] {
61     JSC::ARMRegisters::r0,
62     JSC::ARMRegisters::r1,
63     JSC::ARMRegisters::r2,
64     JSC::ARMRegisters::r3,
65     JSC::ARMRegisters::r9,
66 };
67 static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
68     JSC::ARMRegisters::r4,
69     JSC::ARMRegisters::r5,
70     JSC::ARMRegisters::r7,
71     JSC::ARMRegisters::r8,
72     JSC::ARMRegisters::r10,
73     JSC::ARMRegisters::r11,
74 };
75 // r6 is also used as addressTempRegister in the macro assembler. It is saved in the prologue and restored in the epilogue.
76 static const JSC::MacroAssembler::RegisterID tempRegister = JSC::ARMRegisters::r6;
77 #elif CPU(X86_64)
78 static const JSC::MacroAssembler::RegisterID callerSavedRegisters[] = {
79     JSC::X86Registers::eax,
80     JSC::X86Registers::ecx,
81     JSC::X86Registers::edx,
82     JSC::X86Registers::esi,
83     JSC::X86Registers::edi,
84     JSC::X86Registers::r8,
85     JSC::X86Registers::r9,
86     JSC::X86Registers::r10,
87     JSC::X86Registers::r11
88 };
89 static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
90     JSC::X86Registers::r12,
91     JSC::X86Registers::r13,
92     JSC::X86Registers::r14,
93     JSC::X86Registers::r15
94 };
95 #else
96 #error RegisterAllocator has no defined registers for the architecture.
97 #endif
98 static const unsigned calleeSavedRegisterCount = WTF_ARRAY_LENGTH(calleeSavedRegisters);
99 static const unsigned maximumRegisterCount = calleeSavedRegisterCount + WTF_ARRAY_LENGTH(callerSavedRegisters);
100
101 typedef Vector<JSC::MacroAssembler::RegisterID, maximumRegisterCount> RegisterVector;
102
103 class RegisterAllocator {
104 public:
105     RegisterAllocator() { }
106     ~RegisterAllocator();
107
108     unsigned availableRegisterCount() const { return m_registers.size(); }
109
110     JSC::MacroAssembler::RegisterID allocateRegister()
111     {
112         RELEASE_ASSERT(m_registers.size());
113         JSC::MacroAssembler::RegisterID registerID = m_registers.first();
114         m_registers.removeFirst();
115         ASSERT(!m_allocatedRegisters.contains(registerID));
116         m_allocatedRegisters.append(registerID);
117         return registerID;
118     }
119
120     void allocateRegister(JSC::MacroAssembler::RegisterID registerID)
121     {
122         for (auto it = m_registers.begin(); it != m_registers.end(); ++it) {
123             if (*it == registerID) {
124                 m_registers.remove(it);
125                 ASSERT(!m_allocatedRegisters.contains(registerID));
126                 m_allocatedRegisters.append(registerID);
127                 return;
128             }
129         }
130         RELEASE_ASSERT_NOT_REACHED();
131     }
132     
133     JSC::MacroAssembler::RegisterID allocateRegisterWithPreference(JSC::MacroAssembler::RegisterID preferredRegister)
134     {
135         for (auto it = m_registers.begin(); it != m_registers.end(); ++it) {
136             if (*it == preferredRegister) {
137                 m_registers.remove(it);
138                 ASSERT(!m_allocatedRegisters.contains(preferredRegister));
139                 m_allocatedRegisters.append(preferredRegister);
140                 return preferredRegister;
141             }
142         }
143         return allocateRegister();
144     }
145
146     void deallocateRegister(JSC::MacroAssembler::RegisterID registerID)
147     {
148         ASSERT(m_allocatedRegisters.contains(registerID));
149         // Most allocation/deallocation happen in stack-like order. In the common case, this
150         // just removes the last item.
151         m_allocatedRegisters.remove(m_allocatedRegisters.reverseFind(registerID));
152         for (auto unallocatedRegister : m_registers)
153             RELEASE_ASSERT(unallocatedRegister != registerID);
154         m_registers.append(registerID);
155     }
156
157     unsigned reserveCallerSavedRegisters(unsigned count)
158     {
159 #ifdef NDEBUG
160         UNUSED_PARAM(count);
161         unsigned numberToAllocate = WTF_ARRAY_LENGTH(callerSavedRegisters);
162 #else
163         unsigned numberToAllocate = std::min<unsigned>(WTF_ARRAY_LENGTH(callerSavedRegisters), count);
164 #endif
165         for (unsigned i = 0; i < numberToAllocate; ++i)
166             m_registers.append(callerSavedRegisters[i]);
167         return numberToAllocate;
168     }
169
170     const Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount>& reserveCalleeSavedRegisters(unsigned count)
171     {
172         RELEASE_ASSERT(count <= WTF_ARRAY_LENGTH(calleeSavedRegisters));
173         RELEASE_ASSERT(!m_reservedCalleeSavedRegisters.size());
174         for (unsigned i = 0; i < count; ++i) {
175             JSC::MacroAssembler::RegisterID registerId = calleeSavedRegisters[i];
176             m_reservedCalleeSavedRegisters.append(registerId);
177             m_registers.append(registerId);
178         }
179         return m_reservedCalleeSavedRegisters;
180     }
181
182     Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> restoreCalleeSavedRegisters()
183     {
184         Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> registers(m_reservedCalleeSavedRegisters);
185         m_reservedCalleeSavedRegisters.clear();
186         return registers;
187     }
188
189     const RegisterVector& allocatedRegisters() const { return m_allocatedRegisters; }
190
191     static bool isValidRegister(JSC::MacroAssembler::RegisterID registerID)
192     {
193 #if CPU(ARM64)
194         return (registerID >= JSC::ARM64Registers::x0 && registerID <= JSC::ARM64Registers::x14)
195             || registerID == JSC::ARM64Registers::x19;
196 #elif CPU(ARM_THUMB2)
197         return registerID >= JSC::ARMRegisters::r0 && registerID <= JSC::ARMRegisters::r11 && registerID != JSC::ARMRegisters::r6;
198 #elif CPU(X86_64)
199         return (registerID >= JSC::X86Registers::eax && registerID <= JSC::X86Registers::edx)
200             || (registerID >= JSC::X86Registers::esi && registerID <= JSC::X86Registers::r15);
201 #else
202 #error RegisterAllocator does not define the valid register range for the current architecture.
203 #endif
204     }
205     
206     static bool isCallerSavedRegister(JSC::MacroAssembler::RegisterID registerID)
207     {
208         ASSERT(isValidRegister(registerID));
209 #if CPU(ARM64)
210         return registerID >= JSC::ARM64Registers::x0 && registerID <= JSC::ARM64Registers::x14;
211 #elif CPU(ARM_THUMB2)
212         return (registerID >= JSC::ARMRegisters::r0 && registerID <= JSC::ARMRegisters::r3)
213             || registerID == JSC::ARMRegisters::r9;
214 #elif CPU(X86_64)
215         return (registerID >= JSC::X86Registers::eax && registerID <= JSC::X86Registers::edx)
216             || (registerID >= JSC::X86Registers::esi && registerID <= JSC::X86Registers::r11);
217 #else
218 #error RegisterAllocator does not define the valid caller saved register range for the current architecture.
219 #endif
220     }
221
222 private:
223     Deque<JSC::MacroAssembler::RegisterID, maximumRegisterCount> m_registers;
224     RegisterVector m_allocatedRegisters;
225     Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> m_reservedCalleeSavedRegisters;
226 };
227
228 class LocalRegister {
229 public:
230     explicit LocalRegister(RegisterAllocator& allocator)
231         : m_allocator(allocator)
232         , m_register(allocator.allocateRegister())
233     {
234     }
235
236     ~LocalRegister()
237     {
238         m_allocator.deallocateRegister(m_register);
239     }
240
241     operator JSC::MacroAssembler::RegisterID() const
242     {
243         return m_register;
244     }
245
246 protected:
247     explicit LocalRegister(RegisterAllocator& allocator, JSC::MacroAssembler::RegisterID registerID)
248         : m_allocator(allocator)
249         , m_register(registerID)
250     {
251     }
252     RegisterAllocator& m_allocator;
253     JSC::MacroAssembler::RegisterID m_register;
254 };
255
256 class LocalRegisterWithPreference : public LocalRegister {
257 public:
258     explicit LocalRegisterWithPreference(RegisterAllocator& allocator, JSC::MacroAssembler::RegisterID preferredRegister)
259         : LocalRegister(allocator, allocator.allocateRegisterWithPreference(preferredRegister))
260     {
261     }
262 };
263
264 inline RegisterAllocator::~RegisterAllocator()
265 {
266     RELEASE_ASSERT(m_reservedCalleeSavedRegisters.isEmpty());
267 }
268
269 } // namespace WebCore
270
271 #endif // ENABLE(CSS_SELECTOR_JIT)
272
273 #endif // RegisterAllocator_h
274