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
34namespace WebCore {
35
36#if CPU(ARM64)
37static 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};
54static const JSC::MacroAssembler::RegisterID calleeSavedRegisters[] = {
55 JSC::ARM64Registers::x19
56};
57static const JSC::MacroAssembler::RegisterID tempRegister = JSC::ARM64Registers::x15;
58#elif CPU(ARM_THUMB2)
59static 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};
66static 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.
75static const JSC::MacroAssembler::RegisterID tempRegister = JSC::ARMRegisters::r6;
76#elif CPU(X86_64)
77static 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};
88static 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
97static const unsigned calleeSavedRegisterCount = WTF_ARRAY_LENGTH(calleeSavedRegisters);
98static const unsigned maximumRegisterCount = calleeSavedRegisterCount + WTF_ARRAY_LENGTH(callerSavedRegisters);
99
100typedef Vector<JSC::MacroAssembler::RegisterID, maximumRegisterCount> RegisterVector;
101
102class RegisterAllocator {
103public:
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
221private:
222 Deque<JSC::MacroAssembler::RegisterID, maximumRegisterCount> m_registers;
223 RegisterVector m_allocatedRegisters;
224 Vector<JSC::MacroAssembler::RegisterID, calleeSavedRegisterCount> m_reservedCalleeSavedRegisters;
225};
226
227class LocalRegister {
228public:
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
245protected:
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
255class LocalRegisterWithPreference : public LocalRegister {
256public:
257 explicit LocalRegisterWithPreference(RegisterAllocator& allocator, JSC::MacroAssembler::RegisterID preferredRegister)
258 : LocalRegister(allocator, allocator.allocateRegisterWithPreference(preferredRegister))
259 {
260 }
261};
262
263inline RegisterAllocator::~RegisterAllocator()
264{
265 RELEASE_ASSERT(m_reservedCalleeSavedRegisters.isEmpty());
266}
267
268} // namespace WebCore
269
270#endif // ENABLE(CSS_SELECTOR_JIT)
271