1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
18#define ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
19
20#include "asm_support_arm64.h"
21
22// Define special registers.
23
24// Register holding Thread::Current().
25#define xSELF x19
26// Frame Pointer
27#define xFP   x29
28// Link Register
29#define xLR   x30
30// Define the intraprocedural linkage temporary registers.
31#define xIP0 x16
32#define wIP0 w16
33#define xIP1 x17
34#define wIP1 w17
35
36#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
37// Marking Register, holding Thread::Current()->GetIsGcMarking().
38// Only used with the Concurrent Copying (CC) garbage
39// collector, with the Baker read barrier configuration.
40#define wMR w20
41#endif
42
43.macro ENTRY_ALIGNED name, alignment
44    .type \name, #function
45    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
46    .global \name
47    // ART-compiled functions have OatQuickMethodHeader but assembly funtions do not.
48    // Prefix the assembly code with 0xFFs, which means there is no method header.
49    .byte 0xFF, 0xFF, 0xFF, 0xFF
50    // Cache alignment for function entry.
51    // NB: 0xFF because there is a bug in balign where 0x00 creates nop instructions.
52    .balign \alignment, 0xFF
53\name:
54    .cfi_startproc
55.endm
56
57.macro ENTRY name
58    ENTRY_ALIGNED \name, 16
59.endm
60
61.macro END name
62    .cfi_endproc
63    .size \name, .-\name
64.endm
65
66.macro UNIMPLEMENTED name
67    ENTRY \name
68    brk 0
69    END \name
70.endm
71
72// Macro to poison (negate) the reference for heap poisoning.
73.macro POISON_HEAP_REF rRef
74#ifdef USE_HEAP_POISONING
75    neg \rRef, \rRef
76#endif  // USE_HEAP_POISONING
77.endm
78
79// Macro to unpoison (negate) the reference for heap poisoning.
80.macro UNPOISON_HEAP_REF rRef
81#ifdef USE_HEAP_POISONING
82    neg \rRef, \rRef
83#endif  // USE_HEAP_POISONING
84.endm
85
86.macro INCREASE_FRAME frame_adjustment
87    sub sp, sp, #(\frame_adjustment)
88    .cfi_adjust_cfa_offset (\frame_adjustment)
89.endm
90
91.macro DECREASE_FRAME frame_adjustment
92    add sp, sp, #(\frame_adjustment)
93    .cfi_adjust_cfa_offset -(\frame_adjustment)
94.endm
95
96.macro SAVE_REG reg, offset
97    str \reg, [sp, #(\offset)]
98    .cfi_rel_offset \reg, (\offset)
99.endm
100
101.macro RESTORE_REG reg, offset
102    ldr \reg, [sp, #(\offset)]
103    .cfi_restore \reg
104.endm
105
106.macro SAVE_TWO_REGS_BASE base, reg1, reg2, offset
107    stp \reg1, \reg2, [\base, #(\offset)]
108    .cfi_rel_offset \reg1, (\offset)
109    .cfi_rel_offset \reg2, (\offset) + 8
110.endm
111
112.macro SAVE_TWO_REGS reg1, reg2, offset
113    SAVE_TWO_REGS_BASE sp, \reg1, \reg2, \offset
114.endm
115
116.macro RESTORE_TWO_REGS_BASE base, reg1, reg2, offset
117    ldp \reg1, \reg2, [\base, #(\offset)]
118    .cfi_restore \reg1
119    .cfi_restore \reg2
120.endm
121
122.macro RESTORE_TWO_REGS reg1, reg2, offset
123    RESTORE_TWO_REGS_BASE sp, \reg1, \reg2, \offset
124.endm
125
126.macro LOAD_RUNTIME_INSTANCE reg
127#if __has_feature(hwaddress_sanitizer) && __clang_major__ >= 10
128    adrp xIP0, :pg_hi21_nc:_ZN3art7Runtime9instance_E
129#else
130    adrp xIP0, _ZN3art7Runtime9instance_E
131#endif
132    ldr xIP0, [xIP0, #:lo12:_ZN3art7Runtime9instance_E]
133.endm
134
135// Macro to refresh the Marking Register (W20).
136//
137// This macro must be called at the end of functions implementing
138// entrypoints that possibly (directly or indirectly) perform a
139// suspend check (before they return).
140.macro REFRESH_MARKING_REGISTER
141#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
142    ldr wMR, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
143#endif
144.endm
145
146    /*
147     * Macro that sets up the callee save frame to conform with
148     * Runtime::CreateCalleeSaveMethod(kSaveRefsOnly).
149     */
150.macro SETUP_SAVE_REFS_ONLY_FRAME
151    // art::Runtime* xIP0 = art::Runtime::instance_;
152    // Our registers aren't intermixed - just spill in order.
153    LOAD_RUNTIME_INSTANCE xIP0
154
155    // ArtMethod* xIP0 = Runtime::instance_->callee_save_methods_[kSaveRefOnly];
156    ldr xIP0, [xIP0, RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET]
157
158    INCREASE_FRAME 96
159
160    // Ugly compile-time check, but we only have the preprocessor.
161#if (FRAME_SIZE_SAVE_REFS_ONLY != 96)
162#error "FRAME_SIZE_SAVE_REFS_ONLY(ARM64) size not as expected."
163#endif
164
165    // GP callee-saves.
166    // x20 paired with ArtMethod* - see below.
167    SAVE_TWO_REGS x21, x22, 16
168    SAVE_TWO_REGS x23, x24, 32
169    SAVE_TWO_REGS x25, x26, 48
170    SAVE_TWO_REGS x27, x28, 64
171    SAVE_TWO_REGS x29, xLR, 80
172
173    // Store ArtMethod* Runtime::callee_save_methods_[kSaveRefsOnly].
174    // Note: We could avoid saving X20 in the case of Baker read
175    // barriers, as it is overwritten by REFRESH_MARKING_REGISTER
176    // later; but it's not worth handling this special case.
177    stp xIP0, x20, [sp]
178    .cfi_rel_offset x20, 8
179
180    // Place sp in Thread::Current()->top_quick_frame.
181    mov xIP0, sp
182    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
183.endm
184
185// TODO: Probably no need to restore registers preserved by aapcs64.
186.macro RESTORE_SAVE_REFS_ONLY_FRAME
187    // Callee-saves.
188    // Note: Likewise, we could avoid restoring X20 in the case of Baker
189    // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
190    // later; but it's not worth handling this special case.
191    RESTORE_REG x20, 8
192    RESTORE_TWO_REGS x21, x22, 16
193    RESTORE_TWO_REGS x23, x24, 32
194    RESTORE_TWO_REGS x25, x26, 48
195    RESTORE_TWO_REGS x27, x28, 64
196    RESTORE_TWO_REGS x29, xLR, 80
197
198    DECREASE_FRAME 96
199.endm
200
201.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_INTERNAL base
202    // Ugly compile-time check, but we only have the preprocessor.
203#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 224)
204#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(ARM64) size not as expected."
205#endif
206
207    // Stack alignment filler [\base, #8].
208    // FP args.
209    stp d0, d1, [\base, #16]
210    stp d2, d3, [\base, #32]
211    stp d4, d5, [\base, #48]
212    stp d6, d7, [\base, #64]
213
214    // Core args.
215    SAVE_TWO_REGS_BASE \base, x1, x2, 80
216    SAVE_TWO_REGS_BASE \base, x3, x4, 96
217    SAVE_TWO_REGS_BASE \base, x5, x6, 112
218
219    // x7, Callee-saves.
220    // Note: We could avoid saving X20 in the case of Baker read
221    // barriers, as it is overwritten by REFRESH_MARKING_REGISTER
222    // later; but it's not worth handling this special case.
223    SAVE_TWO_REGS_BASE \base, x7, x20, 128
224    SAVE_TWO_REGS_BASE \base, x21, x22, 144
225    SAVE_TWO_REGS_BASE \base, x23, x24, 160
226    SAVE_TWO_REGS_BASE \base, x25, x26, 176
227    SAVE_TWO_REGS_BASE \base, x27, x28, 192
228
229    // x29(callee-save) and LR.
230    SAVE_TWO_REGS_BASE \base, x29, xLR, 208
231.endm
232
233// TODO: Probably no need to restore registers preserved by aapcs64. (That would require
234// auditing all users to make sure they restore aapcs64 callee-save registers they clobber.)
235.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_INTERNAL base
236    // FP args.
237    ldp d0, d1, [\base, #16]
238    ldp d2, d3, [\base, #32]
239    ldp d4, d5, [\base, #48]
240    ldp d6, d7, [\base, #64]
241
242    // Core args.
243    RESTORE_TWO_REGS_BASE \base, x1, x2, 80
244    RESTORE_TWO_REGS_BASE \base, x3, x4, 96
245    RESTORE_TWO_REGS_BASE \base, x5, x6, 112
246
247    // x7, Callee-saves.
248    // Note: Likewise, we could avoid restoring X20 in the case of Baker
249    // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
250    // later; but it's not worth handling this special case.
251    RESTORE_TWO_REGS_BASE \base, x7, x20, 128
252    RESTORE_TWO_REGS_BASE \base, x21, x22, 144
253    RESTORE_TWO_REGS_BASE \base, x23, x24, 160
254    RESTORE_TWO_REGS_BASE \base, x25, x26, 176
255    RESTORE_TWO_REGS_BASE \base, x27, x28, 192
256
257    // x29(callee-save) and LR.
258    RESTORE_TWO_REGS_BASE \base, x29, xLR, 208
259.endm
260
261.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME
262    RESTORE_SAVE_REFS_AND_ARGS_FRAME_INTERNAL sp
263    DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS
264.endm
265
266    /*
267     * Macro that sets up the callee save frame to conform with
268     * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves)
269     */
270.macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
271    // art::Runtime* xIP0 = art::Runtime::instance_;
272    // Our registers aren't intermixed - just spill in order.
273    LOAD_RUNTIME_INSTANCE xIP0
274
275    // ArtMethod* xIP0 = Runtime::instance_->callee_save_methods_[kSaveAllCalleeSaves];
276    ldr xIP0, [xIP0, RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET]
277
278    INCREASE_FRAME 176
279
280    // Ugly compile-time check, but we only have the preprocessor.
281#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 176)
282#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(ARM64) size not as expected."
283#endif
284
285    // Stack alignment filler [sp, #8].
286    // FP callee-saves.
287    stp d8, d9,   [sp, #16]
288    stp d10, d11, [sp, #32]
289    stp d12, d13, [sp, #48]
290    stp d14, d15, [sp, #64]
291
292    // GP callee-saves
293    SAVE_TWO_REGS x19, x20, 80
294    SAVE_TWO_REGS x21, x22, 96
295    SAVE_TWO_REGS x23, x24, 112
296    SAVE_TWO_REGS x25, x26, 128
297    SAVE_TWO_REGS x27, x28, 144
298    SAVE_TWO_REGS x29, xLR, 160
299
300    // Store ArtMethod* Runtime::callee_save_methods_[kSaveAllCalleeSaves].
301    str xIP0, [sp]
302    // Place sp in Thread::Current()->top_quick_frame.
303    mov xIP0, sp
304    str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
305.endm
306
307    /*
308     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
309     * exception is Thread::Current()->exception_ when the runtime method frame is ready.
310     */
311.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
312    mov x0, xSELF
313
314    // Point of no return.
315    bl artDeliverPendingExceptionFromCode  // artDeliverPendingExceptionFromCode(Thread*)
316    brk 0  // Unreached
317.endm
318
319    /*
320     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
321     * exception is Thread::Current()->exception_.
322     */
323.macro DELIVER_PENDING_EXCEPTION
324    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
325    DELIVER_PENDING_EXCEPTION_FRAME_READY
326.endm
327
328.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg
329    ldr \reg, [xSELF, # THREAD_EXCEPTION_OFFSET]   // Get exception field.
330    cbnz \reg, 1f
331    ret
3321:
333    DELIVER_PENDING_EXCEPTION
334.endm
335
336.macro RETURN_OR_DELIVER_PENDING_EXCEPTION
337    RETURN_OR_DELIVER_PENDING_EXCEPTION_REG xIP0
338.endm
339
340#endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_S_
341