Unreviewed, rolling out r246322.
[WebKit-https.git] / Source / JavaScriptCore / assembler / MacroAssemblerARM64E.h
1 /*
2  * Copyright (C) 2018-2019 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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #pragma once
27
28 #if ENABLE(ASSEMBLER) && CPU(ARM64E)
29
30 // We need to include this before MacroAssemblerARM64.h because MacroAssemblerARM64
31 // will be defined in terms of ARM64EAssembler for ARM64E.
32 #include "ARM64EAssembler.h"
33 #include "JSCPtrTag.h"
34 #include "MacroAssemblerARM64.h"
35
36 namespace JSC {
37
38 using Assembler = TARGET_ASSEMBLER;
39
40 class MacroAssemblerARM64E : public MacroAssemblerARM64 {
41 public:
42     ALWAYS_INLINE void tagReturnAddress()
43     {
44         tagPtr(ARM64Registers::sp, ARM64Registers::lr);
45     }
46
47     ALWAYS_INLINE void untagReturnAddress()
48     {
49         untagPtr(ARM64Registers::sp, ARM64Registers::lr);
50     }
51
52     ALWAYS_INLINE void tagPtr(PtrTag tag, RegisterID target)
53     {
54         auto tagGPR = getCachedDataTempRegisterIDAndInvalidate();
55         move(TrustedImm64(tag), tagGPR);
56         m_assembler.pacib(target, tagGPR);
57     }
58
59     ALWAYS_INLINE void tagPtr(RegisterID tag, RegisterID target)
60     {
61         if (target == ARM64Registers::lr && tag == ARM64Registers::sp) {
62             m_assembler.pacibsp();
63             return;
64         }
65         m_assembler.pacib(target, tag);
66     }
67
68     ALWAYS_INLINE void untagPtr(PtrTag tag, RegisterID target)
69     {
70         auto tagGPR = getCachedDataTempRegisterIDAndInvalidate();
71         move(TrustedImm64(tag), tagGPR);
72         m_assembler.autib(target, tagGPR);
73     }
74
75     ALWAYS_INLINE void untagPtr(RegisterID tag, RegisterID target)
76     {
77         m_assembler.autib(target, tag);
78     }
79
80     ALWAYS_INLINE void removePtrTag(RegisterID target)
81     {
82         m_assembler.xpaci(target);
83     }
84
85     ALWAYS_INLINE void tagArrayPtr(RegisterID length, RegisterID target)
86     {
87         m_assembler.pacdb(target, length);
88     }
89
90     ALWAYS_INLINE void untagArrayPtr(RegisterID length, RegisterID target)
91     {
92         m_assembler.autdb(target, length);
93     }
94
95     ALWAYS_INLINE void untagArrayPtr(Address length, RegisterID target)
96     {
97         auto lengthGPR = getCachedDataTempRegisterIDAndInvalidate();
98         load32(length, lengthGPR);
99         m_assembler.autdb(target, lengthGPR);
100     }
101
102     ALWAYS_INLINE void removeArrayPtrTag(RegisterID target)
103     {
104         m_assembler.xpacd(target);
105     }
106
107     static const RegisterID InvalidGPR  = static_cast<RegisterID>(-1);
108
109     enum class CallSignatureType {
110         CFunctionCall,
111         OtherCall
112     };
113
114     template<CallSignatureType type>
115     ALWAYS_INLINE Call callTrustedPtr(RegisterID tagGPR = InvalidGPR)
116     {
117         ASSERT(tagGPR != dataTempRegister);
118         AssemblerLabel pointerLabel = m_assembler.label();
119         moveWithFixedWidth(TrustedImmPtr(nullptr), getCachedDataTempRegisterIDAndInvalidate());
120         invalidateAllTempRegisters();
121         if (type == CallSignatureType::CFunctionCall)
122             m_assembler.blraaz(dataTempRegister);
123         else
124             m_assembler.blrab(dataTempRegister, tagGPR);
125         AssemblerLabel callLabel = m_assembler.label();
126         ASSERT_UNUSED(pointerLabel, ARM64Assembler::getDifferenceBetweenLabels(callLabel, pointerLabel) == REPATCH_OFFSET_CALL_TO_POINTER);
127         return Call(callLabel, Call::Linkable);
128     }
129
130     ALWAYS_INLINE Call call(PtrTag tag)
131     {
132         if (tag == NoPtrTag)
133             return MacroAssemblerARM64::call(tag);
134         if (tag == CFunctionPtrTag)
135             return callTrustedPtr<CallSignatureType::CFunctionCall>();
136         move(TrustedImm64(tag), ARM64Registers::lr);
137         return callTrustedPtr<CallSignatureType::OtherCall>(ARM64Registers::lr);
138     }
139
140     ALWAYS_INLINE Call call(RegisterID tagGPR)
141     {
142         return callTrustedPtr<CallSignatureType::OtherCall>(tagGPR);
143     }
144
145     template<CallSignatureType type>
146     ALWAYS_INLINE Call callRegister(RegisterID targetGPR, RegisterID tagGPR = InvalidGPR)
147     {
148         ASSERT(tagGPR != targetGPR);
149         invalidateAllTempRegisters();
150         if (type == CallSignatureType::CFunctionCall)
151             m_assembler.blraaz(targetGPR);
152         else
153             m_assembler.blrab(targetGPR, tagGPR);
154         return Call(m_assembler.label(), Call::None);
155     }
156
157     ALWAYS_INLINE Call call(RegisterID targetGPR, PtrTag tag)
158     {
159         if (tag == NoPtrTag)
160             return MacroAssemblerARM64::call(targetGPR, tag);
161         if (tag == CFunctionPtrTag)
162             return callRegister<CallSignatureType::CFunctionCall>(targetGPR);
163         move(TrustedImm64(tag), ARM64Registers::lr);
164         return callRegister<CallSignatureType::OtherCall>(targetGPR, ARM64Registers::lr);
165     }
166
167     ALWAYS_INLINE Call call(RegisterID targetGPR, RegisterID tagGPR)
168     {
169         return callRegister<CallSignatureType::OtherCall>(targetGPR, tagGPR);
170     }
171
172     ALWAYS_INLINE Call call(Address address, PtrTag tag)
173     {
174         if (tag == NoPtrTag)
175             return MacroAssemblerARM64::call(address, tag);
176
177         load64(address, getCachedDataTempRegisterIDAndInvalidate());
178         return call(dataTempRegister, tag);
179     }
180
181     ALWAYS_INLINE Call call(Address address, RegisterID tag)
182     {
183         ASSERT(tag != dataTempRegister);
184         load64(address, getCachedDataTempRegisterIDAndInvalidate());
185         return call(dataTempRegister, tag);
186     }
187
188     ALWAYS_INLINE Jump jump() { return MacroAssemblerARM64::jump(); }
189
190     void jump(RegisterID target, PtrTag tag)
191     {
192         if (tag == NoPtrTag)
193             return MacroAssemblerARM64::jump(target, tag);
194
195         ASSERT(tag != CFunctionPtrTag);
196         RegisterID diversityGPR = getCachedDataTempRegisterIDAndInvalidate();
197         move(TrustedImm64(tag), diversityGPR);
198         jump(target, diversityGPR);
199     }
200
201     void jump(RegisterID target, RegisterID tag)
202     {
203         ASSERT(tag != target);
204         m_assembler.brab(target, tag);
205     }
206
207     void jump(Address address, PtrTag tag)
208     {
209         if (tag == NoPtrTag)
210             return MacroAssemblerARM64::jump(address, tag);
211
212         ASSERT(tag != CFunctionPtrTag);
213         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
214         RegisterID diversityGPR = getCachedMemoryTempRegisterIDAndInvalidate();
215         load64(address, targetGPR);
216         move(TrustedImm64(tag), diversityGPR);
217         m_assembler.brab(targetGPR, diversityGPR);
218     }
219
220     void jump(Address address, RegisterID tag)
221     {
222         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
223         ASSERT(tag != targetGPR);
224         load64(address, targetGPR);
225         m_assembler.brab(targetGPR, tag);
226     }
227
228     void jump(BaseIndex address, PtrTag tag)
229     {
230         if (tag == NoPtrTag)
231             return MacroAssemblerARM64::jump(address, tag);
232
233         ASSERT(tag != CFunctionPtrTag);
234         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
235         RegisterID diversityGPR = getCachedMemoryTempRegisterIDAndInvalidate();
236         load64(address, targetGPR);
237         move(TrustedImm64(tag), diversityGPR);
238         m_assembler.brab(targetGPR, diversityGPR);
239     }
240
241     void jump(BaseIndex address, RegisterID tag)
242     {
243         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
244         ASSERT(tag != targetGPR);
245         load64(address, targetGPR);
246         m_assembler.brab(targetGPR, tag);
247     }
248
249     void jump(AbsoluteAddress address, PtrTag tag)
250     {
251         if (tag == NoPtrTag)
252             return MacroAssemblerARM64::jump(address, tag);
253
254         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
255         RegisterID diversityGPR = getCachedMemoryTempRegisterIDAndInvalidate();
256         move(TrustedImmPtr(address.m_ptr), targetGPR);
257         load64(Address(targetGPR), targetGPR);
258         move(TrustedImm64(tag), diversityGPR);
259         m_assembler.brab(targetGPR, diversityGPR);
260     }
261
262     void jump(AbsoluteAddress address, RegisterID tag)
263     {
264         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
265         ASSERT(tag != targetGPR);
266         move(TrustedImmPtr(address.m_ptr), targetGPR);
267         load64(Address(targetGPR), targetGPR);
268         m_assembler.brab(targetGPR, tag);
269     }
270 };
271
272 } // namespace JSC
273
274 #endif // ENABLE(ASSEMBLER) && CPU(ARM64E)