[MediaStream] AVVideoCaptureSource reports incorrect size when frames are scaled
[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 #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)