[MediaStream] AVVideoCaptureSource reports incorrect size when frames are scaled
[WebKit-https.git] / Source / WebCore / cssjit / StackAllocator.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 "RegisterAllocator.h"
31 #include <JavaScriptCore/MacroAssembler.h>
32 #include <limits>
33
34 namespace WebCore {
35
36 class StackAllocator {
37 public:
38     class StackReference {
39     public:
40         StackReference()
41             : m_offsetFromTop(std::numeric_limits<unsigned>::max())
42         { }
43         explicit StackReference(unsigned offset)
44             : m_offsetFromTop(offset)
45         { }
46         operator unsigned() const { return m_offsetFromTop; }
47         bool isValid() const { return m_offsetFromTop != std::numeric_limits<unsigned>::max(); }
48     private:
49         unsigned m_offsetFromTop;
50     };
51
52     typedef Vector<StackReference, maximumRegisterCount> StackReferenceVector;
53
54     StackAllocator(JSC::MacroAssembler& assembler)
55         : m_assembler(assembler)
56         , m_offsetFromTop(0)
57         , m_hasFunctionCallPadding(false)
58     {
59     }
60
61     StackReference stackTop()
62     {
63         return StackReference(m_offsetFromTop + stackUnitInBytes());
64     }
65
66     ~StackAllocator()
67     {
68         RELEASE_ASSERT(!m_offsetFromTop);
69         RELEASE_ASSERT(!m_hasFunctionCallPadding);
70     }
71
72     StackReference allocateUninitialized()
73     {
74         return allocateUninitialized(1)[0];
75     }
76
77     StackReferenceVector allocateUninitialized(unsigned count)
78     {
79         RELEASE_ASSERT(!m_hasFunctionCallPadding);
80         StackReferenceVector stackReferences;
81         unsigned oldOffsetFromTop = m_offsetFromTop;
82 #if CPU(ARM64)
83         for (unsigned i = 0; i < count - 1; i += 2) {
84             m_offsetFromTop += stackUnitInBytes();
85             stackReferences.append(StackReference(m_offsetFromTop - stackUnitInBytes() / 2));
86             stackReferences.append(StackReference(m_offsetFromTop));
87         }
88         if (count % 2) {
89             m_offsetFromTop += stackUnitInBytes();
90             stackReferences.append(StackReference(m_offsetFromTop));
91         }
92 #else
93         for (unsigned i = 0; i < count; ++i) {
94             m_offsetFromTop += stackUnitInBytes();
95             stackReferences.append(StackReference(m_offsetFromTop));
96         }
97 #endif
98         m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(-(m_offsetFromTop - oldOffsetFromTop)), JSC::MacroAssembler::stackPointerRegister);
99         return stackReferences;
100     }
101
102     template<size_t inlineCapacity, typename OverflowHandler>
103     StackReferenceVector push(const Vector<JSC::MacroAssembler::RegisterID, inlineCapacity, OverflowHandler>& registerIDs)
104     {
105         RELEASE_ASSERT(!m_hasFunctionCallPadding);
106
107         StackReferenceVector stackReferences;
108
109         if (registerIDs.isEmpty())
110             return stackReferences;
111
112 #if CPU(ARM64)
113         unsigned pushRegisterCount = registerIDs.size();
114         for (unsigned i = 0; i < pushRegisterCount - 1; i += 2) {
115             m_assembler.pushPair(registerIDs[i + 1], registerIDs[i]);
116             m_offsetFromTop += stackUnitInBytes();
117             stackReferences.append(StackReference(m_offsetFromTop - stackUnitInBytes() / 2));
118             stackReferences.append(StackReference(m_offsetFromTop));
119         }
120         if (pushRegisterCount % 2)
121             stackReferences.append(push(registerIDs[pushRegisterCount - 1]));
122 #else
123         for (auto registerID : registerIDs)
124             stackReferences.append(push(registerID));
125 #endif
126         return stackReferences;
127     }
128
129     StackReference push(JSC::MacroAssembler::RegisterID registerID)
130     {
131         RELEASE_ASSERT(!m_hasFunctionCallPadding);
132         m_assembler.pushToSave(registerID);
133         m_offsetFromTop += stackUnitInBytes();
134         return StackReference(m_offsetFromTop);
135     }
136
137     template<size_t inlineCapacity, typename OverflowHandler>
138     void pop(const StackReferenceVector& stackReferences, const Vector<JSC::MacroAssembler::RegisterID, inlineCapacity, OverflowHandler>& registerIDs)
139     {
140         RELEASE_ASSERT(!m_hasFunctionCallPadding);
141
142         unsigned popRegisterCount = registerIDs.size();
143         RELEASE_ASSERT(stackReferences.size() == popRegisterCount);
144 #if CPU(ARM64)
145         ASSERT(m_offsetFromTop >= stackUnitInBytes() * ((popRegisterCount + 1) / 2));
146         unsigned popRegisterCountOdd = popRegisterCount % 2;
147         if (popRegisterCountOdd)
148             pop(stackReferences[popRegisterCount - 1], registerIDs[popRegisterCount - 1]);
149         for (unsigned i = popRegisterCount - popRegisterCountOdd; i > 0; i -= 2) {
150             RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop);
151             RELEASE_ASSERT(stackReferences[i - 2] == m_offsetFromTop - stackUnitInBytes() / 2);
152             RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes());
153             m_offsetFromTop -= stackUnitInBytes();
154             m_assembler.popPair(registerIDs[i - 1], registerIDs[i - 2]);
155         }
156 #else
157         ASSERT(m_offsetFromTop >= stackUnitInBytes() * popRegisterCount);
158         for (unsigned i = popRegisterCount; i > 0; --i)
159             pop(stackReferences[i - 1], registerIDs[i - 1]);
160 #endif
161     }
162
163     void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID)
164     {
165         RELEASE_ASSERT(stackReference == m_offsetFromTop);
166         RELEASE_ASSERT(!m_hasFunctionCallPadding);
167         RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes());
168         m_offsetFromTop -= stackUnitInBytes();
169         m_assembler.popToRestore(registerID);
170     }
171
172     void popAndDiscardUpTo(StackReference stackReference)
173     {
174         unsigned positionBeforeStackReference = stackReference - stackUnitInBytes();
175         RELEASE_ASSERT(positionBeforeStackReference < m_offsetFromTop);
176
177         unsigned stackDelta = m_offsetFromTop - positionBeforeStackReference;
178         m_assembler.addPtr(JSC::MacroAssembler::TrustedImm32(stackDelta), JSC::MacroAssembler::stackPointerRegister);
179         m_offsetFromTop -= stackDelta;
180     }
181
182     void alignStackPreFunctionCall()
183     {
184 #if CPU(X86_64)
185         RELEASE_ASSERT(!m_hasFunctionCallPadding);
186         unsigned topAlignment = stackUnitInBytes();
187         if ((topAlignment + m_offsetFromTop) % 16) {
188             m_hasFunctionCallPadding = true;
189             m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(-stackUnitInBytes()), JSC::MacroAssembler::stackPointerRegister);
190         }
191 #endif
192     }
193
194     void unalignStackPostFunctionCall()
195     {
196 #if CPU(X86_64)
197         if (m_hasFunctionCallPadding) {
198             m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(stackUnitInBytes()), JSC::MacroAssembler::stackPointerRegister);
199             m_hasFunctionCallPadding = false;
200         }
201 #endif
202     }
203
204     void merge(StackAllocator&& stackA, StackAllocator&& stackB)
205     {
206         RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop);
207         RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding);
208         ASSERT(&stackA.m_assembler == &stackB.m_assembler);
209         ASSERT(&m_assembler == &stackB.m_assembler);
210
211         m_offsetFromTop = stackA.m_offsetFromTop;
212         m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding;
213
214         stackA.reset();
215         stackB.reset();
216     }
217
218     void merge(StackAllocator&& stackA, StackAllocator&& stackB, StackAllocator&& stackC)
219     {
220         RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop);
221         RELEASE_ASSERT(stackA.m_offsetFromTop == stackC.m_offsetFromTop);
222         RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding);
223         RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackC.m_hasFunctionCallPadding);
224         ASSERT(&stackA.m_assembler == &stackB.m_assembler);
225         ASSERT(&stackA.m_assembler == &stackC.m_assembler);
226         ASSERT(&m_assembler == &stackB.m_assembler);
227
228         m_offsetFromTop = stackA.m_offsetFromTop;
229         m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding;
230
231         stackA.reset();
232         stackB.reset();
233         stackC.reset();
234     }
235
236     JSC::MacroAssembler::Address addressOf(StackReference stackReference)
237     {
238         return JSC::MacroAssembler::Address(JSC::MacroAssembler::stackPointerRegister, offsetToStackReference(stackReference));
239     }
240
241     StackAllocator& operator=(const StackAllocator& other)
242     {
243         RELEASE_ASSERT(&m_assembler == &other.m_assembler);
244         m_offsetFromTop = other.m_offsetFromTop;
245         m_hasFunctionCallPadding = other.m_hasFunctionCallPadding;
246         return *this;
247     }
248
249
250 private:
251     static unsigned stackUnitInBytes()
252     {
253         return JSC::MacroAssembler::pushToSaveByteOffset();
254     }
255
256     unsigned offsetToStackReference(StackReference stackReference)
257     {
258         RELEASE_ASSERT(m_offsetFromTop >= stackReference);
259         return m_offsetFromTop - stackReference;
260     }
261
262     void reset()
263     {
264         m_offsetFromTop = 0;
265         m_hasFunctionCallPadding = false;
266     }
267
268     JSC::MacroAssembler& m_assembler;
269     unsigned m_offsetFromTop;
270     bool m_hasFunctionCallPadding;
271 };
272
273 } // namespace WebCore
274
275 #endif // ENABLE(CSS_SELECTOR_JIT)