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.thumb
40
41.macro CFI_EXPRESSION_BREG n, b, offset
42    .if (-0x40 <= (\offset)) && ((\offset) < 0x40)
43        CFI_EXPRESSION_BREG_1(\n, \b, \offset)
44    .elseif (-0x2000 <= (\offset)) && ((\offset) < 0x2000)
45        CFI_EXPRESSION_BREG_2(\n, \b, \offset)
46    .else
47        .error "Unsupported offset"
48    .endif
49.endm
50
51// Macro to generate the value of Runtime::Current into rDest. As it uses labels
52// then the labels need to be unique. We bind these to the function name in the ENTRY macros.
53.macro RUNTIME_CURRENT name, num, rDest
54    .if .Lruntime_current\num\()_used
55         .error
56    .endif
57    .set .Lruntime_current\num\()_used, 1
58    ldr \rDest, .Lruntime_instance_\name\()_\num  @ Load GOT_PREL offset of Runtime::instance_.
59.Lload_got_\name\()_\num\():
60    add \rDest, pc                                @ Fixup GOT_PREL address.
61    ldr \rDest, [\rDest]                          @ Load address of Runtime::instance_.
62    ldr \rDest, [\rDest]                          @ Load Runtime::instance_.
63.endm
64
65// Common ENTRY declaration code for ARM and thumb, an ENTRY should always be paired with an END.
66// Declares the RUNTIME_CURRENT[123] macros that can be used within an ENTRY and will have literals
67// generated at END.
68.macro DEF_ENTRY thumb_or_arm, name, alignment
69    \thumb_or_arm
70// Clang ignores .thumb_func and requires an explicit .thumb. Investigate whether we should still
71// carry around the .thumb_func.
72    .ifc \thumb_or_arm, .thumb_func
73        .thumb
74    .endif
75    .type \name, #function
76    .hidden \name  // Hide this as a global symbol, so we do not incur plt calls.
77    .global \name
78    // ART-compiled functions have OatQuickMethodHeader but assembly funtions do not.
79    // Prefix the assembly code with 0xFFs, which means there is no method header.
80    .byte 0xFF, 0xFF, 0xFF, 0xFF
81    // Cache alignment for function entry.
82    // NB: 0xFF because there is a bug in balign where 0x00 creates nop instructions.
83    .balign \alignment, 0xFF
84\name:
85    .cfi_startproc
86    .fnstart
87    // Track whether RUNTIME_CURRENT was used.
88    .set .Lruntime_current1_used, 0
89    .set .Lruntime_current2_used, 0
90    .set .Lruntime_current3_used, 0
91    // The RUNTIME_CURRENT macros that are bound to the \name argument of DEF_ENTRY to ensure
92    // that label names are unique.
93    .macro RUNTIME_CURRENT1 rDest
94        RUNTIME_CURRENT \name, 1, \rDest
95    .endm
96    .macro RUNTIME_CURRENT2 rDest
97        RUNTIME_CURRENT \name, 2, \rDest
98    .endm
99    .macro RUNTIME_CURRENT3 rDest
100        RUNTIME_CURRENT \name, 3, \rDest
101    .endm
102.endm
103
104// A thumb2 style ENTRY.
105.macro ENTRY name
106    DEF_ENTRY .thumb_func, \name, 16
107.endm
108.macro ENTRY_ALIGNED name, alignment
109    DEF_ENTRY .thumb_func, \name, \alignment
110.endm
111
112// A ARM style ENTRY.
113.macro ARM_ENTRY name
114    DEF_ENTRY .arm, \name, 16
115.endm
116
117// Terminate an ENTRY and generate GOT_PREL references.
118.macro END name
119     // Generate offsets of GOT and Runtime::instance_ used in RUNTIME_CURRENT.
120     .if .Lruntime_current1_used
121         .Lruntime_instance_\name\()_1:
122             .word   _ZN3art7Runtime9instance_E(GOT_PREL)-(.Lload_got_\name\()_1+4)
123     .endif
124     .if .Lruntime_current2_used
125         .Lruntime_instance_\name\()_2:
126             .word   _ZN3art7Runtime9instance_E(GOT_PREL)-(.Lload_got_\name\()_2+4)
127    .endif
128     .if .Lruntime_current3_used
129         .Lruntime_instance_\name\()_3:
130             .word   _ZN3art7Runtime9instance_E(GOT_PREL)-(.Lload_got_\name\()_3+4)
131    .endif
132    // Remove the RUNTIME_CURRENTx macros so they get rebound in the next function entry.
133    .purgem RUNTIME_CURRENT1
134    .purgem RUNTIME_CURRENT2
135    .purgem RUNTIME_CURRENT3
136    .fnend
137    .cfi_endproc
138    .size \name, .-\name
139.endm
140
141// Declare an unimplemented ENTRY that will halt a debugger.
142.macro UNIMPLEMENTED name
143    ENTRY \name
144    bkpt
145    bkpt
146    END \name
147.endm
148
149// Macro to poison (negate) the reference for heap poisoning.
150.macro POISON_HEAP_REF rRef
151#ifdef USE_HEAP_POISONING
152    rsb \rRef, \rRef, #0
153#endif  // USE_HEAP_POISONING
154.endm
155
156// Macro to unpoison (negate) the reference for heap poisoning.
157.macro UNPOISON_HEAP_REF rRef
158#ifdef USE_HEAP_POISONING
159    rsb \rRef, \rRef, #0
160#endif  // USE_HEAP_POISONING
161.endm
162
163.macro INCREASE_FRAME frame_adjustment
164    sub sp, sp, #(\frame_adjustment)
165    .cfi_adjust_cfa_offset (\frame_adjustment)
166.endm
167
168.macro DECREASE_FRAME frame_adjustment
169    add sp, sp, #(\frame_adjustment)
170    .cfi_adjust_cfa_offset -(\frame_adjustment)
171.endm
172
173// Macro to refresh the Marking Register (R8).
174//
175// This macro must be called at the end of functions implementing
176// entrypoints that possibly (directly or indirectly) perform a
177// suspend check (before they return).
178.macro REFRESH_MARKING_REGISTER
179#if defined(USE_READ_BARRIER) && defined(USE_BAKER_READ_BARRIER)
180    ldr rMR, [rSELF, #THREAD_IS_GC_MARKING_OFFSET]
181#endif
182.endm
183
184    /*
185     * Macro that sets up the callee save frame to conform with
186     * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs), except for storing the method.
187     */
188.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
189    // Note: We could avoid saving R8 in the case of Baker read
190    // barriers, as it is overwritten by REFRESH_MARKING_REGISTER
191    // later; but it's not worth handling this special case.
192    push {r1-r3, r5-r8, r10-r11, lr}   @ 10 words of callee saves and args.
193    .cfi_adjust_cfa_offset 40
194    .cfi_rel_offset r1, 0
195    .cfi_rel_offset r2, 4
196    .cfi_rel_offset r3, 8
197    .cfi_rel_offset r5, 12
198    .cfi_rel_offset r6, 16
199    .cfi_rel_offset r7, 20
200    .cfi_rel_offset r8, 24
201    .cfi_rel_offset r10, 28
202    .cfi_rel_offset r11, 32
203    .cfi_rel_offset lr, 36
204    vpush {s0-s15}                     @ 16 words of float args.
205    .cfi_adjust_cfa_offset 64
206    sub sp, #8                         @ 2 words of space, alignment padding and Method*
207    .cfi_adjust_cfa_offset 8
208    // Ugly compile-time check, but we only have the preprocessor.
209#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 40 + 64 + 8)
210#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(ARM) size not as expected."
211#endif
212.endm
213
214.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME
215    add  sp, #8                      @ rewind sp
216    .cfi_adjust_cfa_offset -8
217    vpop {s0-s15}
218    .cfi_adjust_cfa_offset -64
219    // Note: Likewise, we could avoid restoring R8 in the case of Baker
220    // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
221    // later; but it's not worth handling this special case.
222    pop {r1-r3, r5-r8, r10-r11, lr}  @ 10 words of callee saves and args.
223    .cfi_restore r1
224    .cfi_restore r2
225    .cfi_restore r3
226    .cfi_restore r5
227    .cfi_restore r6
228    .cfi_restore r7
229    .cfi_restore r8
230    .cfi_restore r10
231    .cfi_restore r11
232    .cfi_restore lr
233    .cfi_adjust_cfa_offset -40
234.endm
235
236    /*
237     * Macro to spill the GPRs.
238     */
239.macro SPILL_ALL_CALLEE_SAVE_GPRS
240    push {r4-r11, lr}                             @ 9 words (36 bytes) of callee saves.
241    .cfi_adjust_cfa_offset 36
242    .cfi_rel_offset r4, 0
243    .cfi_rel_offset r5, 4
244    .cfi_rel_offset r6, 8
245    .cfi_rel_offset r7, 12
246    .cfi_rel_offset r8, 16
247    .cfi_rel_offset r9, 20
248    .cfi_rel_offset r10, 24
249    .cfi_rel_offset r11, 28
250    .cfi_rel_offset lr, 32
251.endm
252
253    /*
254     * Macro that sets up the callee save frame to conform with
255     * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves)
256     */
257.macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME rTemp
258    SPILL_ALL_CALLEE_SAVE_GPRS                    @ 9 words (36 bytes) of callee saves.
259    vpush {s16-s31}                               @ 16 words (64 bytes) of floats.
260    .cfi_adjust_cfa_offset 64
261    sub sp, #12                                   @ 3 words of space, bottom word will hold Method*
262    .cfi_adjust_cfa_offset 12
263    RUNTIME_CURRENT1 \rTemp                       @ Load Runtime::Current into rTemp.
264    @ Load kSaveAllCalleeSaves Method* into rTemp.
265    ldr \rTemp, [\rTemp, #RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET]
266    str \rTemp, [sp, #0]                          @ Place Method* at bottom of stack.
267    str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
268
269     // Ugly compile-time check, but we only have the preprocessor.
270#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 36 + 64 + 12)
271#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(ARM) size not as expected."
272#endif
273.endm
274
275    /*
276     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
277     * exception is Thread::Current()->exception_ when the runtime method frame is ready.
278     */
279.macro DELIVER_PENDING_EXCEPTION_FRAME_READY
280    mov    r0, rSELF                           @ pass Thread::Current
281    bl     artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*)
282.endm
283
284    /*
285     * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending
286     * exception is Thread::Current()->exception_.
287     */
288.macro DELIVER_PENDING_EXCEPTION
289    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0       @ save callee saves for throw
290    DELIVER_PENDING_EXCEPTION_FRAME_READY
291.endm
292
293#endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_
294