Make CSS JIT run on ARM64.
[WebKit-https.git] / Source / WebCore / cssjit / StackAllocator.h
1 /*
2  * Copyright (C) 2013 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 StackAllocator_h
27 #define StackAllocator_h
28
29 #if ENABLE(CSS_SELECTOR_JIT)
30
31 #include <JavaScriptCore/MacroAssembler.h>
32
33 namespace WebCore {
34
35 class StackAllocator {
36 public:
37     class StackReference {
38     public:
39         StackReference()
40             : m_offsetFromTop(-1)
41         { }
42         explicit StackReference(unsigned offset)
43             : m_offsetFromTop(offset)
44         { }
45         operator unsigned() const { return m_offsetFromTop; }
46     private:
47         unsigned m_offsetFromTop;
48     };
49
50     StackAllocator(JSC::MacroAssembler& assembler)
51         : m_assembler(assembler)
52         , m_offsetFromTop(0)
53         , m_hasFunctionCallPadding(false)
54     {
55     }
56
57     ~StackAllocator()
58     {
59         RELEASE_ASSERT(!m_offsetFromTop);
60         RELEASE_ASSERT(!m_hasFunctionCallPadding);
61     }
62
63     StackReference allocateUninitialized()
64     {
65         RELEASE_ASSERT(!m_hasFunctionCallPadding);
66         m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(-stackUnitInBytes), JSC::MacroAssembler::stackPointerRegister);
67         m_offsetFromTop += stackUnitInBytes;
68         return StackReference(m_offsetFromTop);
69     }
70
71     Vector<StackReference> push(const Vector<JSC::MacroAssembler::RegisterID>& registerIDs)
72     {
73         RELEASE_ASSERT(!m_hasFunctionCallPadding);
74         unsigned registerCount = registerIDs.size();
75         Vector<StackReference> stackReferences;
76         stackReferences.reserveInitialCapacity(registerCount);
77 #if CPU(ARM64)
78         for (unsigned i = 0; i < registerCount - 1; i += 2) {
79             m_assembler.pushPair(registerIDs[i + 1], registerIDs[i]);
80             m_offsetFromTop += stackUnitInBytes;
81             stackReferences.append(StackReference(m_offsetFromTop - stackUnitInBytes / 2));
82             stackReferences.append(StackReference(m_offsetFromTop));
83         }
84         if (registerCount % 2) {
85             m_assembler.pushToSave(registerIDs[registerCount - 1]);
86             m_offsetFromTop += stackUnitInBytes;
87             stackReferences.append(StackReference(m_offsetFromTop));
88         }
89 #else
90         for (auto registerID : registerIDs) {
91             m_assembler.pushToSave(registerID);
92             m_offsetFromTop += stackUnitInBytes;
93             stackReferences.append(StackReference(m_offsetFromTop));
94         }
95 #endif
96         return stackReferences;
97     }
98
99     StackReference push(JSC::MacroAssembler::RegisterID registerID)
100     {
101         RELEASE_ASSERT(!m_hasFunctionCallPadding);
102         m_assembler.pushToSave(registerID);
103         m_offsetFromTop += stackUnitInBytes;
104         return StackReference(m_offsetFromTop);
105     }
106
107     void pop(const Vector<StackReference>& stackReferences, const Vector<JSC::MacroAssembler::RegisterID>& registerIDs)
108     {
109         RELEASE_ASSERT(!m_hasFunctionCallPadding);
110         
111         unsigned registerCount = registerIDs.size();
112         RELEASE_ASSERT(stackReferences.size() == registerCount);
113 #if CPU(ARM64)
114         ASSERT(m_offsetFromTop >= stackUnitInBytes * registerCount);
115         unsigned registerCountOdd = registerCount % 2;
116         if (registerCountOdd) {
117             RELEASE_ASSERT(stackReferences[registerCount - 1] == m_offsetFromTop);
118             RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
119             m_offsetFromTop -= stackUnitInBytes;
120             m_assembler.popToRestore(registerIDs[registerCount - 1]);
121         }
122         for (unsigned i = registerCount - registerCountOdd; i > 0; i -= 2) {
123             RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop);
124             RELEASE_ASSERT(stackReferences[i - 2] == m_offsetFromTop - stackUnitInBytes / 2);
125             RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
126             m_offsetFromTop -= stackUnitInBytes;
127             m_assembler.popPair(registerIDs[i - 1], registerIDs[i - 2]);
128         }
129 #else
130         ASSERT(m_offsetFromTop >= stackUnitInBytes * registerCount);
131         for (unsigned i = registerCount; i > 0; --i) {
132             RELEASE_ASSERT(stackReferences[i - 1] == m_offsetFromTop);
133             RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
134             m_offsetFromTop -= stackUnitInBytes;
135             m_assembler.popToRestore(registerIDs[i - 1]);
136         }
137 #endif
138     }
139     
140     void pop(StackReference stackReference, JSC::MacroAssembler::RegisterID registerID)
141     {
142         RELEASE_ASSERT(stackReference == m_offsetFromTop);
143         RELEASE_ASSERT(!m_hasFunctionCallPadding);
144         RELEASE_ASSERT(m_offsetFromTop >= stackUnitInBytes);
145         m_offsetFromTop -= stackUnitInBytes;
146         m_assembler.popToRestore(registerID);
147     }
148
149     void popAndDiscard(StackReference stackReference)
150     {
151         RELEASE_ASSERT(stackReference == m_offsetFromTop);
152         m_assembler.addPtr(JSC::MacroAssembler::TrustedImm32(stackUnitInBytes), JSC::MacroAssembler::stackPointerRegister);
153         m_offsetFromTop -= stackUnitInBytes;
154     }
155
156     void popAndDiscardUpTo(StackReference stackReference)
157     {
158         unsigned positionBeforeStackReference = stackReference - stackUnitInBytes;
159         RELEASE_ASSERT(positionBeforeStackReference < m_offsetFromTop);
160
161         unsigned stackDelta = m_offsetFromTop - positionBeforeStackReference;
162         m_assembler.addPtr(JSC::MacroAssembler::TrustedImm32(stackDelta), JSC::MacroAssembler::stackPointerRegister);
163         m_offsetFromTop -= stackDelta;
164     }
165
166     void alignStackPreFunctionCall()
167     {
168 #if CPU(X86_64)
169         RELEASE_ASSERT(!m_hasFunctionCallPadding);
170         unsigned topAlignment = stackUnitInBytes;
171         if ((topAlignment + m_offsetFromTop) % 16) {
172             m_hasFunctionCallPadding = true;
173             m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(-stackUnitInBytes), JSC::MacroAssembler::stackPointerRegister);
174         }
175 #endif
176     }
177
178     void unalignStackPostFunctionCall()
179     {
180 #if CPU(X86_64)
181         if (m_hasFunctionCallPadding) {
182             m_assembler.addPtrNoFlags(JSC::MacroAssembler::TrustedImm32(stackUnitInBytes), JSC::MacroAssembler::stackPointerRegister);
183             m_hasFunctionCallPadding = false;
184         }
185 #endif
186     }
187
188     void merge(StackAllocator&& stackA, StackAllocator&& stackB)
189     {
190         RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop);
191         RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding);
192         ASSERT(&stackA.m_assembler == &stackB.m_assembler);
193         ASSERT(&m_assembler == &stackB.m_assembler);
194
195         m_offsetFromTop = stackA.m_offsetFromTop;
196         m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding;
197
198         stackA.reset();
199         stackB.reset();
200     }
201
202     void merge(StackAllocator&& stackA, StackAllocator&& stackB, StackAllocator&& stackC)
203     {
204         RELEASE_ASSERT(stackA.m_offsetFromTop == stackB.m_offsetFromTop);
205         RELEASE_ASSERT(stackA.m_offsetFromTop == stackC.m_offsetFromTop);
206         RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackB.m_hasFunctionCallPadding);
207         RELEASE_ASSERT(stackA.m_hasFunctionCallPadding == stackC.m_hasFunctionCallPadding);
208         ASSERT(&stackA.m_assembler == &stackB.m_assembler);
209         ASSERT(&stackA.m_assembler == &stackC.m_assembler);
210         ASSERT(&m_assembler == &stackB.m_assembler);
211
212         m_offsetFromTop = stackA.m_offsetFromTop;
213         m_hasFunctionCallPadding = stackA.m_hasFunctionCallPadding;
214
215         stackA.reset();
216         stackB.reset();
217         stackC.reset();
218     }
219
220     unsigned offsetToStackReference(StackReference stackReference)
221     {
222         RELEASE_ASSERT(m_offsetFromTop >= stackReference);
223         return m_offsetFromTop - stackReference;
224     }
225
226 private:
227 #if CPU(ARM64)
228     static const unsigned stackUnitInBytes = 16;
229 #elif CPU(X86_64)
230     static const unsigned stackUnitInBytes = 8;
231 #else
232 #error Stack Unit Size is undefined.
233 #endif
234
235     void reset()
236     {
237         m_offsetFromTop = 0;
238         m_hasFunctionCallPadding = false;
239     }
240
241     JSC::MacroAssembler& m_assembler;
242     unsigned m_offsetFromTop;
243     bool m_hasFunctionCallPadding;
244 };
245
246 } // namespace WebCore
247
248 #endif // ENABLE(CSS_SELECTOR_JIT)
249
250 #endif // StackAllocator_h