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