1/*
2 * Copyright (C) 2013 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_ARM_ASM_SUPPORT_ARM_S_
18#define ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_S_
19
20#include "asm_support_arm.h"
21#include "interpreter/cfi_asm_support.h"
22
23// Define special registers.
24
25// Register holding suspend check count down.
26#define rSUSPEND r4
27// Register holding Thread::Current().
28#define rSELF r9
29
30#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
31// Marking Register, holding Thread::Current()->GetIsGcMarking().
32// Only used with the Concurrent Copying (CC) garbage
33// collector, with the Baker read barrier configuration.
34#define rMR r8
35#endif
36
37.syntax unified
38.arch armv7-a
39.arch_extension idiv
40.thumb
41
42.macro CFI_EXPRESSION_BREG n, b, offset
43    .if (-0x40 <= (\offset)) && ((\offset) < 0x40)
44        CFI_EXPRESSION_BREG_1(\n, \b, \offset)
45    .elseif (-0x2000 <= (\offset)) && ((\offset) < 0x2000)
46        CFI_EXPRESSION_BREG_2(\n, \b, \offset)
47    .else
48        .error "Unsupported offset"
49    .endif
50.endm
51
52.macro CFI_DEF_CFA_BREG_PLUS_UCONST reg, offset, size
53    .if ((\size) < 0)
54        .error "Size should be positive"
55    .endif
56    .if (((\offset) < -0x40) || ((\offset) >= 0x40))
57        .error "Unsupported offset"
58    .endif
59    .if ((\size) < 0x80)
60        CFI_DEF_CFA_BREG_PLUS_UCONST_1_1(\reg, \offset, \size)
61    .elseif ((\size) < 0x4000)
62        CFI_DEF_CFA_BREG_PLUS_UCONST_1_2(\reg, \offset, \size)
63    .else
64        .error "Unsupported size"
65    .endif
66.endm
67
68// Macro to generate the value of Runtime::Current into rDest. As it uses labels
69// then the labels need to be unique. We bind these to the function name in the ENTRY macros.
70.macro RUNTIME_CURRENT name, num, rDest
71    .if .Lruntime_current\num\()_used
72         .error
73    .endif
74    .set .Lruntime_current\num\()_used, 1
75    ldr \rDest, .Lruntime_instance_\name\()_\num  @ Load GOT_PREL offset of Runtime::instance_.
76.Lload_got_\name\()_\num\():
77    add \rDest, pc                                @ Fixup GOT_PREL address.
78    ldr \rDest, [\rDest]                          @ Load address of Runtime::instance_.
79    ldr \rDest, [\rDest]                          @ Load Runtime::instance_.
80.endm
81
82// Common ENTRY declaration code for ARM and thumb, an ENTRY should always be paired with an END.
83// Declares the RUNTIME_CURRENT[123] macros that can be used within an ENTRY and will have literals
84// generated at END.
85.macro DEF_ENTRY thumb_or_arm, name, alignment
86    \thumb_or_arm
87// Clang ignores .thumb_func and requires an explicit .thumb. Investigate whether we should still
88// carry around the .thumb_func.
89    .ifc \thumb_or_arm, .thumb_func
90        .thumb
91    .endif
92    .type \name, #function
93    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
94    .global \name
95    // ART-compiled functions have OatQuickMethodHeader but assembly funtions do not.
96    // Prefix the assembly code with 0xFFs, which means there is no method header.
97    .byte 0xFF, 0xFF, 0xFF, 0xFF
98    // Cache alignment for function entry.
99    // NB: 0xFF because there is a bug in balign where 0x00 creates nop instructions.
100    .balign \alignment, 0xFF
101\name:
102    .cfi_startproc
103    .fnstart
104    // Track whether RUNTIME_CURRENT was used.
105    .set .Lruntime_current1_used, 0
106    .set .Lruntime_current2_used, 0
107    .set .Lruntime_current3_used, 0
108    // The RUNTIME_CURRENT macros that are bound to the \name argument of DEF_ENTRY to ensure
109    // that label names are unique.
110    .macro RUNTIME_CURRENT1 rDest
111        RUNTIME_CURRENT \name, 1, \rDest
112    .endm
113    .macro RUNTIME_CURRENT2 rDest
114        RUNTIME_CURRENT \name, 2, \rDest
115    .endm
116    .macro RUNTIME_CURRENT3 rDest
117        RUNTIME_CURRENT \name, 3, \rDest
118    .endm
119.endm
120
121// A thumb2 style ENTRY.
122.macro ENTRY name
123    DEF_ENTRY .thumb_func, \name, 16
124.endm
125.macro ENTRY_ALIGNED name, alignment
126    DEF_ENTRY .thumb_func, \name, \alignment
127.endm
128
129// A ARM style ENTRY.
130.macro ARM_ENTRY name
131    DEF_ENTRY .arm, \name, 16
132.endm
133
134// Terminate an ENTRY and generate GOT_PREL references.
135.macro END name
136     // Generate offsets of GOT and Runtime::instance_ used in RUNTIME_CURRENT.
137     .if .Lruntime_current1_used
138         .Lruntime_instance_\name\()_1:
139             .word   _ZN3art7Runtime9instance_E(GOT_PREL)-(.Lload_got_\name\()_1+4)
140     .endif
141     .if .Lruntime_current2_used
142         .Lruntime_instance_\name\()_2:
143             .word   _ZN3art7Runtime9instance_E(GOT_PREL)-(.Lload_got_\name\()_2+4)
144    .endif
145     .if .Lruntime_current3_used
146         .Lruntime_instance_\name\()_3:
147             .word   _ZN3art7Runtime9instance_E(GOT_PREL)-(.Lload_got_\name\()_3+4)
148    .endif
149    // Remove the RUNTIME_CURRENTx macros so they get rebound in the next function entry.
150    .purgem RUNTIME_CURRENT1
151    .purgem RUNTIME_CURRENT2
152    .purgem RUNTIME_CURRENT3
153    .fnend
154    .cfi_endproc
155    .size \name, .-\name
156.endm
157
158// Declare an unimplemented ENTRY that will halt a debugger.
159.macro UNIMPLEMENTED name
160    ENTRY \name
161    bkpt
162    bkpt
163    END \name
164.endm
165
166// Macro to poison (negate) the reference for heap poisoning.
167.macro POISON_HEAP_REF rRef
168#ifdef USE_HEAP_POISONING
169    rsb \rRef, \rRef, #0
170#endif  // USE_HEAP_POISONING
171.endm
172
173// Macro to unpoison (negate) the reference for heap poisoning.
174.macro UNPOISON_HEAP_REF rRef
175#ifdef USE_HEAP_POISONING
176    rsb \rRef, \rRef, #0
177#endif  // USE_HEAP_POISONING
178.endm
179
180.macro INCREASE_FRAME frame_adjustment
181    sub sp, sp, #(\frame_adjustment)
182    .cfi_adjust_cfa_offset (\frame_adjustment)
183.endm
184
185.macro DECREASE_FRAME frame_adjustment
186    add sp, sp, #(\frame_adjustment)
187    .cfi_adjust_cfa_offset -(\frame_adjustment)
188.endm
189
190// Macro to refresh the Marking Register (R8).
191//
192// This macro must be called at the end of functions implementing
193// entrypoints that possibly (directly or indirectly) perform a
194// suspend check (before they return).
195.macro REFRESH_MARKING_REGISTER
196#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
197    ldr rMR, [rSELF, #THREAD_IS_GC_MARKING_OFFSET]
198#endif
199.endm
200
201.macro CONDITIONAL_CBZ reg, reg_if, dest
202.ifc \reg, \reg_if
203    cbz \reg, \dest
204.endif
205.endm
206
207.macro CONDITIONAL_CMPBZ reg, reg_if, dest
208.ifc \reg, \reg_if
209    cmp \reg, #0
210    beq \dest
211.endif
212.endm
213
214// Use CBZ if the register is in {r0, r7} otherwise compare and branch.
215.macro SMART_CBZ reg, dest
216    CONDITIONAL_CBZ \reg, r0, \dest
217    CONDITIONAL_CBZ \reg, r1, \dest
218    CONDITIONAL_CBZ \reg, r2, \dest
219    CONDITIONAL_CBZ \reg, r3, \dest
220    CONDITIONAL_CBZ \reg, r4, \dest
221    CONDITIONAL_CBZ \reg, r5, \dest
222    CONDITIONAL_CBZ \reg, r6, \dest
223    CONDITIONAL_CBZ \reg, r7, \dest
224    CONDITIONAL_CMPBZ \reg, r8, \dest
225    CONDITIONAL_CMPBZ \reg, r9, \dest
226    CONDITIONAL_CMPBZ \reg, r10, \dest
227    CONDITIONAL_CMPBZ \reg, r11, \dest
228    CONDITIONAL_CMPBZ \reg, r12, \dest
229    CONDITIONAL_CMPBZ \reg, r13, \dest
230    CONDITIONAL_CMPBZ \reg, r14, \dest
231    CONDITIONAL_CMPBZ \reg, r15, \dest
232.endm
233
234    /*
235     * Macro that sets up the callee save frame to conform with
236     * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs), except for storing the method.
237     */
238.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
239    // Note: We could avoid saving R8 in the case of Baker read
240    // barriers, as it is overwritten by REFRESH_MARKING_REGISTER
241    // later; but it's not worth handling this special case.
242    push {r1-r3, r5-r8, r10-r11, lr}   @ 10 words of callee saves and args.
243    .cfi_adjust_cfa_offset 40
244    .cfi_rel_offset r1, 0
245    .cfi_rel_offset r2, 4
246    .cfi_rel_offset r3, 8
247    .cfi_rel_offset r5, 12
248    .cfi_rel_offset r6, 16
249    .cfi_rel_offset r7, 20
250    .cfi_rel_offset r8, 24
251    .cfi_rel_offset r10, 28
252    .cfi_rel_offset r11, 32
253    .cfi_rel_offset lr, 36
254    vpush {s0-s15}                     @ 16 words of float args.
255    .cfi_adjust_cfa_offset 64
256    sub sp, #8                         @ 2 words of space, alignment padding and Method*
257    .cfi_adjust_cfa_offset 8
258    // Ugly compile-time check, but we only have the preprocessor.
259#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 40 + 64 + 8)
260#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(ARM) size not as expected."
261#endif
262.endm
263
264.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME
265    add  sp, #8                      @ rewind sp
266    .cfi_adjust_cfa_offset -8
267    vpop {s0-s15}
268    .cfi_adjust_cfa_offset -64
269    // Note: Likewise, we could avoid restoring R8 in the case of Baker
270    // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
271    // later; but it's not worth handling this special case.
272    pop {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves and args.
273    .cfi_restore r1
274    .cfi_restore r2
275    .cfi_restore r3
276    .cfi_restore r5
277    .cfi_restore r6
278    .cfi_restore r7
279    .cfi_restore r8
280    .cfi_restore r10
281    .cfi_restore r11
282    .cfi_restore lr
283    .cfi_adjust_cfa_offset -40
284.endm
285
286    /*
287     * Macro to spill the GPRs.
288     */
289.macro SPILL_ALL_CALLEE_SAVE_GPRS
290    push {r4-r11, lr}                             @ 9 words (36 bytes) of callee saves.
291    .cfi_adjust_cfa_offset 36
292    .cfi_rel_offset r4, 0
293    .cfi_rel_offset r5, 4
294    .cfi_rel_offset r6, 8
295    .cfi_rel_offset r7, 12
296    .cfi_rel_offset r8, 16
297    .cfi_rel_offset r9, 20
298    .cfi_rel_offset r10, 24
299    .cfi_rel_offset r11, 28
300    .cfi_rel_offset lr, 32
301.endm
302
303    /*
304     * Macro that sets up the callee save frame to conform with
305     * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves)
306     */
307.macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME rTemp
308    SPILL_ALL_CALLEE_SAVE_GPRS                    @ 9 words (36 bytes) of callee saves.
309    vpush {s16-s31}                               @ 16 words (64 bytes) of floats.
310    .cfi_adjust_cfa_offset 64
311    sub sp, #12                                   @ 3 words of space, bottom word will hold Method*
312    .cfi_adjust_cfa_offset 12
313    RUNTIME_CURRENT1 \rTemp                       @ Load Runtime::Current into rTemp.
314    @ Load kSaveAllCalleeSaves Method* into rTemp.
315    ldr \rTemp, [\rTemp, #RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET]
316    str \rTemp, [sp, #0]                          @ Place Method* at bottom of stack.
317    str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
318
319     // Ugly compile-time check, but we only have the preprocessor.
320#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 36 + 64 + 12)
321#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(ARM) size not as expected."
322#endif
323.endm
324
325    /*
326     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
327     * exception is Thread::Current()->exception_ when the runtime method frame is ready.
328     */
329.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
330    mov    r0, rSELF                           @ pass Thread::Current
331    bl     artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*)
332.endm
333
334    /*
335     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
336     * exception is Thread::Current()->exception_.
337     */
338.macro DELIVER_PENDING_EXCEPTION
339    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0       @ save callee saves for throw
340    DELIVER_PENDING_EXCEPTION_FRAME_READY
341.endm
342
343.macro  RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg
344    ldr \reg, [rSELF, #THREAD_EXCEPTION_OFFSET]  @ Get exception field.
345    cbnz \reg, 1f
346    bx lr
3471:
348    DELIVER_PENDING_EXCEPTION
349.endm
350
351.macro  RETURN_OR_DELIVER_PENDING_EXCEPTION_R1
352    RETURN_OR_DELIVER_PENDING_EXCEPTION_REG r1
353.endm
354
355.macro  RETURN_OR_DELIVER_PENDING_EXCEPTION
356    ldr ip, [rSELF, #THREAD_EXCEPTION_OFFSET]  @ Get exception field.
357    cmp ip, #0
358    bne 1f
359    bx lr
3601:
361    DELIVER_PENDING_EXCEPTION
362.endm
363
364    /*
365     * Macro that sets up the callee save frame to conform with
366     * Runtime::CreateCalleeSaveMethod(kSaveRefsOnly).
367     */
368.macro SETUP_SAVE_REFS_ONLY_FRAME rTemp
369    // Note: We could avoid saving R8 in the case of Baker read
370    // barriers, as it is overwritten by REFRESH_MARKING_REGISTER
371    // later; but it's not worth handling this special case.
372    push {r5-r8, r10-r11, lr}                     @ 7 words of callee saves
373    .cfi_adjust_cfa_offset 28
374    .cfi_rel_offset r5, 0
375    .cfi_rel_offset r6, 4
376    .cfi_rel_offset r7, 8
377    .cfi_rel_offset r8, 12
378    .cfi_rel_offset r10, 16
379    .cfi_rel_offset r11, 20
380    .cfi_rel_offset lr, 24
381    sub sp, #4                                    @ bottom word will hold Method*
382    .cfi_adjust_cfa_offset 4
383    RUNTIME_CURRENT2 \rTemp                       @ Load Runtime::Current into rTemp.
384    @ Load kSaveRefsOnly Method* into rTemp.
385    ldr \rTemp, [\rTemp, #RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET]
386    str \rTemp, [sp, #0]                          @ Place Method* at bottom of stack.
387    str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
388
389    // Ugly compile-time check, but we only have the preprocessor.
390#if (FRAME_SIZE_SAVE_REFS_ONLY != 28 + 4)
391#error "FRAME_SIZE_SAVE_REFS_ONLY(ARM) size not as expected."
392#endif
393.endm
394
395.macro RESTORE_SAVE_REFS_ONLY_FRAME
396    add sp, #4               @ bottom word holds Method*
397    .cfi_adjust_cfa_offset -4
398    // Note: Likewise, we could avoid restoring R8 in the case of Baker
399    // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
400    // later; but it's not worth handling this special case.
401    pop {r5-r8, r10-r11, lr} @ 7 words of callee saves
402    .cfi_restore r5
403    .cfi_restore r6
404    .cfi_restore r7
405    .cfi_restore r8
406    .cfi_restore r10
407    .cfi_restore r11
408    .cfi_restore lr
409    .cfi_adjust_cfa_offset -28
410.endm
411
412#endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_
413