9803bd5c1403d047d5965f0f4cca0ae1037f4db0
[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     static const RegisterID InvalidGPR  = static_cast<RegisterID>(-1);
86
87     enum class CallSignatureType {
88         CFunctionCall,
89         OtherCall
90     };
91
92     template<CallSignatureType type>
93     ALWAYS_INLINE Call callTrustedPtr(RegisterID tagGPR = InvalidGPR)
94     {
95         ASSERT(tagGPR != dataTempRegister);
96         AssemblerLabel pointerLabel = m_assembler.label();
97         moveWithFixedWidth(TrustedImmPtr(nullptr), getCachedDataTempRegisterIDAndInvalidate());
98         invalidateAllTempRegisters();
99         if (type == CallSignatureType::CFunctionCall)
100             m_assembler.blraaz(dataTempRegister);
101         else
102             m_assembler.blrab(dataTempRegister, tagGPR);
103         AssemblerLabel callLabel = m_assembler.label();
104         ASSERT_UNUSED(pointerLabel, ARM64Assembler::getDifferenceBetweenLabels(callLabel, pointerLabel) == REPATCH_OFFSET_CALL_TO_POINTER);
105         return Call(callLabel, Call::Linkable);
106     }
107
108     ALWAYS_INLINE Call call(PtrTag tag)
109     {
110         if (tag == NoPtrTag)
111             return MacroAssemblerARM64::call(tag);
112         if (tag == CFunctionPtrTag)
113             return callTrustedPtr<CallSignatureType::CFunctionCall>();
114         move(TrustedImm64(tag), ARM64Registers::lr);
115         return callTrustedPtr<CallSignatureType::OtherCall>(ARM64Registers::lr);
116     }
117
118     ALWAYS_INLINE Call call(RegisterID tagGPR)
119     {
120         return callTrustedPtr<CallSignatureType::OtherCall>(tagGPR);
121     }
122
123     template<CallSignatureType type>
124     ALWAYS_INLINE Call callRegister(RegisterID targetGPR, RegisterID tagGPR = InvalidGPR)
125     {
126         ASSERT(tagGPR != targetGPR);
127         invalidateAllTempRegisters();
128         if (type == CallSignatureType::CFunctionCall)
129             m_assembler.blraaz(targetGPR);
130         else
131             m_assembler.blrab(targetGPR, tagGPR);
132         return Call(m_assembler.label(), Call::None);
133     }
134
135     ALWAYS_INLINE Call call(RegisterID targetGPR, PtrTag tag)
136     {
137         if (tag == NoPtrTag)
138             return MacroAssemblerARM64::call(targetGPR, tag);
139         if (tag == CFunctionPtrTag)
140             return callRegister<CallSignatureType::CFunctionCall>(targetGPR);
141         move(TrustedImm64(tag), ARM64Registers::lr);
142         return callRegister<CallSignatureType::OtherCall>(targetGPR, ARM64Registers::lr);
143     }
144
145     ALWAYS_INLINE Call call(RegisterID targetGPR, RegisterID tagGPR)
146     {
147         return callRegister<CallSignatureType::OtherCall>(targetGPR, tagGPR);
148     }
149
150     ALWAYS_INLINE Call call(Address address, PtrTag tag)
151     {
152         if (tag == NoPtrTag)
153             return MacroAssemblerARM64::call(address, tag);
154
155         load64(address, getCachedDataTempRegisterIDAndInvalidate());
156         return call(dataTempRegister, tag);
157     }
158
159     ALWAYS_INLINE Call call(Address address, RegisterID tag)
160     {
161         ASSERT(tag != dataTempRegister);
162         load64(address, getCachedDataTempRegisterIDAndInvalidate());
163         return call(dataTempRegister, tag);
164     }
165
166     ALWAYS_INLINE Jump jump() { return MacroAssemblerARM64::jump(); }
167
168     void jump(RegisterID target, PtrTag tag)
169     {
170         if (tag == NoPtrTag)
171             return MacroAssemblerARM64::jump(target, tag);
172
173         ASSERT(tag != CFunctionPtrTag);
174         RegisterID diversityGPR = getCachedDataTempRegisterIDAndInvalidate();
175         move(TrustedImm64(tag), diversityGPR);
176         jump(target, diversityGPR);
177     }
178
179     void jump(RegisterID target, RegisterID tag)
180     {
181         ASSERT(tag != target);
182         m_assembler.brab(target, tag);
183     }
184
185     void jump(Address address, PtrTag tag)
186     {
187         if (tag == NoPtrTag)
188             return MacroAssemblerARM64::jump(address, tag);
189
190         ASSERT(tag != CFunctionPtrTag);
191         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
192         RegisterID diversityGPR = getCachedMemoryTempRegisterIDAndInvalidate();
193         load64(address, targetGPR);
194         move(TrustedImm64(tag), diversityGPR);
195         m_assembler.brab(targetGPR, diversityGPR);
196     }
197
198     void jump(Address address, RegisterID tag)
199     {
200         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
201         ASSERT(tag != targetGPR);
202         load64(address, targetGPR);
203         m_assembler.brab(targetGPR, tag);
204     }
205
206     void jump(BaseIndex address, PtrTag tag)
207     {
208         if (tag == NoPtrTag)
209             return MacroAssemblerARM64::jump(address, tag);
210
211         ASSERT(tag != CFunctionPtrTag);
212         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
213         RegisterID diversityGPR = getCachedMemoryTempRegisterIDAndInvalidate();
214         load64(address, targetGPR);
215         move(TrustedImm64(tag), diversityGPR);
216         m_assembler.brab(targetGPR, diversityGPR);
217     }
218
219     void jump(BaseIndex address, RegisterID tag)
220     {
221         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
222         ASSERT(tag != targetGPR);
223         load64(address, targetGPR);
224         m_assembler.brab(targetGPR, tag);
225     }
226
227     void jump(AbsoluteAddress address, PtrTag tag)
228     {
229         if (tag == NoPtrTag)
230             return MacroAssemblerARM64::jump(address, tag);
231
232         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
233         RegisterID diversityGPR = getCachedMemoryTempRegisterIDAndInvalidate();
234         move(TrustedImmPtr(address.m_ptr), targetGPR);
235         load64(Address(targetGPR), targetGPR);
236         move(TrustedImm64(tag), diversityGPR);
237         m_assembler.brab(targetGPR, diversityGPR);
238     }
239
240     void jump(AbsoluteAddress address, RegisterID tag)
241     {
242         RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
243         ASSERT(tag != targetGPR);
244         move(TrustedImmPtr(address.m_ptr), targetGPR);
245         load64(Address(targetGPR), targetGPR);
246         m_assembler.brab(targetGPR, tag);
247     }
248 };
249
250 } // namespace JSC
251
252 #endif // ENABLE(ASSEMBLER) && CPU(ARM64E)