2 * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #if ENABLE(ASSEMBLER) && CPU(ARM64E)
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"
38 using Assembler = TARGET_ASSEMBLER;
40 class MacroAssemblerARM64E : public MacroAssemblerARM64 {
42 ALWAYS_INLINE void tagReturnAddress()
44 tagPtr(ARM64Registers::sp, ARM64Registers::lr);
47 ALWAYS_INLINE void untagReturnAddress()
49 untagPtr(ARM64Registers::sp, ARM64Registers::lr);
52 ALWAYS_INLINE void tagPtr(PtrTag tag, RegisterID target)
54 auto tagGPR = getCachedDataTempRegisterIDAndInvalidate();
55 move(TrustedImm64(tag), tagGPR);
56 m_assembler.pacib(target, tagGPR);
59 ALWAYS_INLINE void tagPtr(RegisterID tag, RegisterID target)
61 if (target == ARM64Registers::lr && tag == ARM64Registers::sp) {
62 m_assembler.pacibsp();
65 m_assembler.pacib(target, tag);
68 ALWAYS_INLINE void untagPtr(PtrTag tag, RegisterID target)
70 auto tagGPR = getCachedDataTempRegisterIDAndInvalidate();
71 move(TrustedImm64(tag), tagGPR);
72 m_assembler.autib(target, tagGPR);
75 ALWAYS_INLINE void untagPtr(RegisterID tag, RegisterID target)
77 m_assembler.autib(target, tag);
80 ALWAYS_INLINE void removePtrTag(RegisterID target)
82 m_assembler.xpaci(target);
85 ALWAYS_INLINE void tagArrayPtr(RegisterID length, RegisterID target)
87 m_assembler.pacdb(target, length);
90 ALWAYS_INLINE void untagArrayPtr(RegisterID length, RegisterID target)
92 m_assembler.autdb(target, length);
95 ALWAYS_INLINE void untagArrayPtr(Address length, RegisterID target)
97 auto lengthGPR = getCachedDataTempRegisterIDAndInvalidate();
98 load32(length, lengthGPR);
99 m_assembler.autdb(target, lengthGPR);
102 ALWAYS_INLINE void removeArrayPtrTag(RegisterID target)
104 m_assembler.xpacd(target);
107 static const RegisterID InvalidGPR = static_cast<RegisterID>(-1);
109 enum class CallSignatureType {
114 template<CallSignatureType type>
115 ALWAYS_INLINE Call callTrustedPtr(RegisterID tagGPR = InvalidGPR)
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);
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);
130 ALWAYS_INLINE Call call(PtrTag tag)
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);
140 ALWAYS_INLINE Call call(RegisterID tagGPR)
142 return callTrustedPtr<CallSignatureType::OtherCall>(tagGPR);
145 template<CallSignatureType type>
146 ALWAYS_INLINE Call callRegister(RegisterID targetGPR, RegisterID tagGPR = InvalidGPR)
148 ASSERT(tagGPR != targetGPR);
149 invalidateAllTempRegisters();
150 if (type == CallSignatureType::CFunctionCall)
151 m_assembler.blraaz(targetGPR);
153 m_assembler.blrab(targetGPR, tagGPR);
154 return Call(m_assembler.label(), Call::None);
157 ALWAYS_INLINE Call call(RegisterID targetGPR, PtrTag tag)
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);
167 ALWAYS_INLINE Call call(RegisterID targetGPR, RegisterID tagGPR)
169 return callRegister<CallSignatureType::OtherCall>(targetGPR, tagGPR);
172 ALWAYS_INLINE Call call(Address address, PtrTag tag)
175 return MacroAssemblerARM64::call(address, tag);
177 load64(address, getCachedDataTempRegisterIDAndInvalidate());
178 return call(dataTempRegister, tag);
181 ALWAYS_INLINE Call call(Address address, RegisterID tag)
183 ASSERT(tag != dataTempRegister);
184 load64(address, getCachedDataTempRegisterIDAndInvalidate());
185 return call(dataTempRegister, tag);
188 ALWAYS_INLINE Jump jump() { return MacroAssemblerARM64::jump(); }
190 void jump(RegisterID target, PtrTag tag)
193 return MacroAssemblerARM64::jump(target, tag);
195 ASSERT(tag != CFunctionPtrTag);
196 RegisterID diversityGPR = getCachedDataTempRegisterIDAndInvalidate();
197 move(TrustedImm64(tag), diversityGPR);
198 jump(target, diversityGPR);
201 void jump(RegisterID target, RegisterID tag)
203 ASSERT(tag != target);
204 m_assembler.brab(target, tag);
207 void jump(Address address, PtrTag tag)
210 return MacroAssemblerARM64::jump(address, tag);
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);
220 void jump(Address address, RegisterID tag)
222 RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
223 ASSERT(tag != targetGPR);
224 load64(address, targetGPR);
225 m_assembler.brab(targetGPR, tag);
228 void jump(BaseIndex address, PtrTag tag)
231 return MacroAssemblerARM64::jump(address, tag);
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);
241 void jump(BaseIndex address, RegisterID tag)
243 RegisterID targetGPR = getCachedDataTempRegisterIDAndInvalidate();
244 ASSERT(tag != targetGPR);
245 load64(address, targetGPR);
246 m_assembler.brab(targetGPR, tag);
249 void jump(AbsoluteAddress address, PtrTag tag)
252 return MacroAssemblerARM64::jump(address, tag);
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);
262 void jump(AbsoluteAddress address, RegisterID tag)
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);
274 #endif // ENABLE(ASSEMBLER) && CPU(ARM64E)