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#ifdef RESERVE_MARKING_REGISTER 31// Marking Register, holding Thread::Current()->GetIsGcMarking(). 32#define rMR r8 33#endif 34 35.syntax unified 36.arch armv7-a 37.arch_extension idiv 38.thumb 39 40.macro CFI_EXPRESSION_BREG n, b, offset 41 .if (-0x40 <= (\offset)) && ((\offset) < 0x40) 42 CFI_EXPRESSION_BREG_1(\n, \b, \offset) 43 .elseif (-0x2000 <= (\offset)) && ((\offset) < 0x2000) 44 CFI_EXPRESSION_BREG_2(\n, \b, \offset) 45 .else 46 .error "Unsupported offset" 47 .endif 48.endm 49 50.macro CFI_DEF_CFA_BREG_PLUS_UCONST reg, offset, size 51 .if ((\size) < 0) 52 .error "Size should be positive" 53 .endif 54 .if (((\offset) < -0x40) || ((\offset) >= 0x40)) 55 .error "Unsupported offset" 56 .endif 57 .if ((\size) < 0x80) 58 CFI_DEF_CFA_BREG_PLUS_UCONST_1_1(\reg, \offset, \size) 59 .elseif ((\size) < 0x4000) 60 CFI_DEF_CFA_BREG_PLUS_UCONST_1_2(\reg, \offset, \size) 61 .else 62 .error "Unsupported size" 63 .endif 64.endm 65 66.macro CFI_REMEMBER_STATE 67 .cfi_remember_state 68.endm 69 70// The spec is not clear whether the CFA is part of the saved state and tools 71// differ in the behaviour, so explicitly set the CFA to avoid any ambiguity. 72// The restored CFA state should match the CFA state during CFI_REMEMBER_STATE. 73.macro CFI_RESTORE_STATE_AND_DEF_CFA reg, offset 74 .cfi_restore_state 75 .cfi_def_cfa \reg, \offset 76.endm 77 78// Common ENTRY declaration code for ARM and thumb, an ENTRY should always be paired with an END. 79.macro DEF_ENTRY thumb_or_arm, name, alignment 80 \thumb_or_arm 81// Clang ignores .thumb_func and requires an explicit .thumb. Investigate whether we should still 82// carry around the .thumb_func. 83 .ifc \thumb_or_arm, .thumb_func 84 .thumb 85 .endif 86 .type \name, #function 87 .hidden \name // Hide this as a global symbol, so we do not incur plt calls. 88 .global \name 89 .balign \alignment 90\name: 91 .cfi_startproc 92 .fnstart 93.endm 94 95// A thumb2 style ENTRY. 96.macro ENTRY name 97 DEF_ENTRY .thumb_func, \name, 16 98.endm 99.macro ENTRY_ALIGNED name, alignment 100 DEF_ENTRY .thumb_func, \name, \alignment 101.endm 102 103// A ARM style ENTRY. 104.macro ARM_ENTRY name 105 DEF_ENTRY .arm, \name, 16 106.endm 107 108// Terminate an ENTRY. 109.macro END name 110 .fnend 111 .cfi_endproc 112 .size \name, .-\name 113.endm 114 115// Declare an unimplemented ENTRY that will halt a debugger. 116.macro UNIMPLEMENTED name 117 ENTRY \name 118 bkpt 119 bkpt 120 END \name 121.endm 122 123// Macro to poison (negate) the reference for heap poisoning. 124.macro POISON_HEAP_REF rRef 125#ifdef USE_HEAP_POISONING 126 rsb \rRef, \rRef, #0 127#endif // USE_HEAP_POISONING 128.endm 129 130// Macro to unpoison (negate) the reference for heap poisoning. 131.macro UNPOISON_HEAP_REF rRef 132#ifdef USE_HEAP_POISONING 133 rsb \rRef, \rRef, #0 134#endif // USE_HEAP_POISONING 135.endm 136 137.macro INCREASE_FRAME frame_adjustment 138 sub sp, sp, #(\frame_adjustment) 139 .cfi_adjust_cfa_offset (\frame_adjustment) 140.endm 141 142.macro DECREASE_FRAME frame_adjustment 143 add sp, sp, #(\frame_adjustment) 144 .cfi_adjust_cfa_offset -(\frame_adjustment) 145.endm 146 147.macro LOAD_RUNTIME_INSTANCE rDest 148 movw \rDest, #:lower16:(_ZN3art7Runtime9instance_E - (. + 12)) 149 movt \rDest, #:upper16:(_ZN3art7Runtime9instance_E - (. + 8)) 150 add \rDest, pc 151 ldr \rDest, [\rDest] 152.endm 153 154// Macro to refresh the Marking Register (R8). 155// 156// This macro must be called at the end of functions implementing 157// entrypoints that possibly (directly or indirectly) perform a 158// suspend check (before they return). 159.macro REFRESH_MARKING_REGISTER 160#ifdef RESERVE_MARKING_REGISTER 161 ldr rMR, [rSELF, #THREAD_IS_GC_MARKING_OFFSET] 162#endif 163.endm 164 165.macro CONDITIONAL_CBZ reg, reg_if, dest 166.ifc \reg, \reg_if 167 cbz \reg, \dest 168.endif 169.endm 170 171.macro CONDITIONAL_CMPBZ reg, reg_if, dest 172.ifc \reg, \reg_if 173 cmp \reg, #0 174 beq \dest 175.endif 176.endm 177 178// Use CBZ if the register is in {r0, r7} otherwise compare and branch. 179.macro SMART_CBZ reg, dest 180 CONDITIONAL_CBZ \reg, r0, \dest 181 CONDITIONAL_CBZ \reg, r1, \dest 182 CONDITIONAL_CBZ \reg, r2, \dest 183 CONDITIONAL_CBZ \reg, r3, \dest 184 CONDITIONAL_CBZ \reg, r4, \dest 185 CONDITIONAL_CBZ \reg, r5, \dest 186 CONDITIONAL_CBZ \reg, r6, \dest 187 CONDITIONAL_CBZ \reg, r7, \dest 188 CONDITIONAL_CMPBZ \reg, r8, \dest 189 CONDITIONAL_CMPBZ \reg, r9, \dest 190 CONDITIONAL_CMPBZ \reg, r10, \dest 191 CONDITIONAL_CMPBZ \reg, r11, \dest 192 CONDITIONAL_CMPBZ \reg, r12, \dest 193 CONDITIONAL_CMPBZ \reg, r13, \dest 194 CONDITIONAL_CMPBZ \reg, r14, \dest 195 CONDITIONAL_CMPBZ \reg, r15, \dest 196.endm 197 198 /* 199 * Macro that sets up the callee save frame to conform with 200 * Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs), except for storing the method. 201 */ 202.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY 203 // Note: We could avoid saving R8 in the case of Baker read 204 // barriers, as it is overwritten by REFRESH_MARKING_REGISTER 205 // later; but it's not worth handling this special case. 206 push {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves and args. 207 .cfi_adjust_cfa_offset 40 208 .cfi_rel_offset r5, 12 209 .cfi_rel_offset r6, 16 210 .cfi_rel_offset r7, 20 211 .cfi_rel_offset r8, 24 212 .cfi_rel_offset r10, 28 213 .cfi_rel_offset r11, 32 214 .cfi_rel_offset lr, 36 215 vpush {s0-s15} @ 16 words of float args. 216 .cfi_adjust_cfa_offset 64 217 sub sp, #8 @ 2 words of space, alignment padding and Method* 218 .cfi_adjust_cfa_offset 8 219 // Ugly compile-time check, but we only have the preprocessor. 220#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 40 + 64 + 8) 221#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(ARM) size not as expected." 222#endif 223.endm 224 225.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME 226 add sp, #8 @ rewind sp 227 .cfi_adjust_cfa_offset -8 228 vpop {s0-s15} 229 .cfi_adjust_cfa_offset -64 230 // Note: Likewise, we could avoid restoring R8 in the case of Baker 231 // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER 232 // later; but it's not worth handling this special case. 233 pop {r1-r3, r5-r8, r10-r11, lr} @ 10 words of callee saves and args. 234 .cfi_restore r5 235 .cfi_restore r6 236 .cfi_restore r7 237 .cfi_restore r8 238 .cfi_restore r10 239 .cfi_restore r11 240 .cfi_restore lr 241 .cfi_adjust_cfa_offset -40 242.endm 243 244 /* 245 * Macro to spill the GPRs. 246 */ 247.macro SPILL_ALL_CALLEE_SAVE_GPRS 248 push {r4-r11, lr} @ 9 words (36 bytes) of callee saves. 249 .cfi_adjust_cfa_offset 36 250 .cfi_rel_offset r4, 0 251 .cfi_rel_offset r5, 4 252 .cfi_rel_offset r6, 8 253 .cfi_rel_offset r7, 12 254 .cfi_rel_offset r8, 16 255 .cfi_rel_offset r9, 20 256 .cfi_rel_offset r10, 24 257 .cfi_rel_offset r11, 28 258 .cfi_rel_offset lr, 32 259.endm 260 261 /* 262 * Macro that sets up the callee save frame to conform with 263 * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves) 264 */ 265.macro SETUP_SAVE_ALL_CALLEE_SAVES_FRAME rTemp 266 SPILL_ALL_CALLEE_SAVE_GPRS @ 9 words (36 bytes) of callee saves. 267 vpush {s16-s31} @ 16 words (64 bytes) of floats. 268 .cfi_adjust_cfa_offset 64 269 sub sp, #12 @ 3 words of space, bottom word will hold Method* 270 .cfi_adjust_cfa_offset 12 271 LOAD_RUNTIME_INSTANCE \rTemp @ Load Runtime::Current into rTemp. 272 @ Load kSaveAllCalleeSaves Method* into rTemp. 273 ldr \rTemp, [\rTemp, #RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET] 274 str \rTemp, [sp, #0] @ Place Method* at bottom of stack. 275 str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. 276 277 // Ugly compile-time check, but we only have the preprocessor. 278#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 36 + 64 + 12) 279#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(ARM) size not as expected." 280#endif 281.endm 282 283 /* 284 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending 285 * exception is Thread::Current()->exception_ when the runtime method frame is ready. 286 */ 287.macro DELIVER_PENDING_EXCEPTION_FRAME_READY 288 mov r0, rSELF @ pass Thread::Current 289 bl artDeliverPendingExceptionFromCode @ artDeliverPendingExceptionFromCode(Thread*) 290.endm 291 292 /* 293 * Macro that calls through to artDeliverPendingExceptionFromCode, where the pending 294 * exception is Thread::Current()->exception_. 295 */ 296.macro DELIVER_PENDING_EXCEPTION 297 SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0 @ save callee saves for throw 298 DELIVER_PENDING_EXCEPTION_FRAME_READY 299.endm 300 301.macro RETURN_OR_DELIVER_PENDING_EXCEPTION_REG reg 302 ldr \reg, [rSELF, #THREAD_EXCEPTION_OFFSET] @ Get exception field. 303 cbnz \reg, 1f 304 bx lr 3051: 306 DELIVER_PENDING_EXCEPTION 307.endm 308 309.macro RETURN_OR_DELIVER_PENDING_EXCEPTION 310 ldr ip, [rSELF, #THREAD_EXCEPTION_OFFSET] @ Get exception field. 311 cmp ip, #0 312 bne 1f 313 bx lr 3141: 315 DELIVER_PENDING_EXCEPTION 316.endm 317 318 /* 319 * Macro that sets up the callee save frame to conform with 320 * Runtime::CreateCalleeSaveMethod(kSaveRefsOnly). 321 */ 322.macro SETUP_SAVE_REFS_ONLY_FRAME rTemp 323 // Note: We could avoid saving R8 in the case of Baker read 324 // barriers, as it is overwritten by REFRESH_MARKING_REGISTER 325 // later; but it's not worth handling this special case. 326 push {r5-r8, r10-r11, lr} @ 7 words of callee saves 327 .cfi_adjust_cfa_offset 28 328 .cfi_rel_offset r5, 0 329 .cfi_rel_offset r6, 4 330 .cfi_rel_offset r7, 8 331 .cfi_rel_offset r8, 12 332 .cfi_rel_offset r10, 16 333 .cfi_rel_offset r11, 20 334 .cfi_rel_offset lr, 24 335 sub sp, #4 @ bottom word will hold Method* 336 .cfi_adjust_cfa_offset 4 337 LOAD_RUNTIME_INSTANCE \rTemp @ Load Runtime::Current into rTemp. 338 @ Load kSaveRefsOnly Method* into rTemp. 339 ldr \rTemp, [\rTemp, #RUNTIME_SAVE_REFS_ONLY_METHOD_OFFSET] 340 str \rTemp, [sp, #0] @ Place Method* at bottom of stack. 341 str sp, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET] @ Place sp in Thread::Current()->top_quick_frame. 342 343 // Ugly compile-time check, but we only have the preprocessor. 344#if (FRAME_SIZE_SAVE_REFS_ONLY != 28 + 4) 345#error "FRAME_SIZE_SAVE_REFS_ONLY(ARM) size not as expected." 346#endif 347.endm 348 349.macro RESTORE_SAVE_REFS_ONLY_FRAME 350 add sp, #4 @ bottom word holds Method* 351 .cfi_adjust_cfa_offset -4 352 // Note: Likewise, we could avoid restoring R8 in the case of Baker 353 // read barriers, as it is overwritten by REFRESH_MARKING_REGISTER 354 // later; but it's not worth handling this special case. 355 pop {r5-r8, r10-r11, lr} @ 7 words of callee saves 356 .cfi_restore r5 357 .cfi_restore r6 358 .cfi_restore r7 359 .cfi_restore r8 360 .cfi_restore r10 361 .cfi_restore r11 362 .cfi_restore lr 363 .cfi_adjust_cfa_offset -28 364.endm 365 366// Locking is needed for both managed code and JNI stubs. 367.macro LOCK_OBJECT_FAST_PATH obj, tmp1, tmp2, tmp3, slow_lock, can_be_null 368 ldr \tmp1, [rSELF, #THREAD_ID_OFFSET] 369 .if \can_be_null 370 cbz \obj, \slow_lock 371 .endif 3721: 373 ldrex \tmp2, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 374 eor \tmp3, \tmp2, \tmp1 @ Prepare the value to store if unlocked 375 @ (thread id, count of 0 and preserved read barrier bits), 376 @ or prepare to compare thread id for recursive lock check 377 @ (lock_word.ThreadId() ^ self->ThreadId()). 378 ands ip, \tmp2, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ Test the non-gc bits. 379 bne 2f @ Check if unlocked. 380 @ unlocked case - store tmp3: original lock word plus thread id, preserved read barrier bits. 381 strex \tmp2, \tmp3, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 382 cbnz \tmp2, 3f @ If store failed, retry. 383 dmb ish @ Full (LoadLoad|LoadStore) memory barrier. 384 bx lr 3852: @ tmp2: original lock word, tmp1: thread_id, tmp3: tmp2 ^ tmp1 386#if LOCK_WORD_THIN_LOCK_COUNT_SHIFT + LOCK_WORD_THIN_LOCK_COUNT_SIZE != LOCK_WORD_GC_STATE_SHIFT 387#error "Expecting thin lock count and gc state in consecutive bits." 388#endif 389 @ Check lock word state and thread id together. 390 bfc \tmp3, \ 391 #LOCK_WORD_THIN_LOCK_COUNT_SHIFT, \ 392 #(LOCK_WORD_THIN_LOCK_COUNT_SIZE + LOCK_WORD_GC_STATE_SIZE) 393 cbnz \tmp3, \slow_lock @ if either of the top two bits are set, or the lock word's 394 @ thread id did not match, go slow path. 395 add \tmp3, \tmp2, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ Increment the recursive lock count. 396 @ Extract the new thin lock count for overflow check. 397 ubfx \tmp2, \tmp3, #LOCK_WORD_THIN_LOCK_COUNT_SHIFT, #LOCK_WORD_THIN_LOCK_COUNT_SIZE 398 cbz \tmp2, \slow_lock @ Zero as the new count indicates overflow, go slow path. 399 @ strex necessary for read barrier bits. 400 strex \tmp2, \tmp3, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 401 cbnz \tmp2, 3f @ If strex failed, retry. 402 bx lr 4033: 404 b 1b @ retry 405.endm 406 407// Unlocking is needed for both managed code and JNI stubs. 408.macro UNLOCK_OBJECT_FAST_PATH obj, tmp1, tmp2, tmp3, slow_unlock, can_be_null 409 ldr \tmp1, [rSELF, #THREAD_ID_OFFSET] 410 .if \can_be_null 411 cbz \obj, \slow_unlock 412 .endif 4131: 414#ifndef USE_READ_BARRIER 415 ldr \tmp2, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 416#else 417 @ Need to use atomic instructions for read barrier. 418 ldrex \tmp2, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 419#endif 420 eor \tmp3, \tmp2, \tmp1 @ Prepare the value to store if simply locked 421 @ (mostly 0s, and preserved read barrier bits), 422 @ or prepare to compare thread id for recursive lock check 423 @ (lock_word.ThreadId() ^ self->ThreadId()). 424 ands ip, \tmp3, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED @ Test the non-gc bits. 425 bne 2f @ Locked recursively or by other thread? 426 @ Transition to unlocked. 427 dmb ish @ Full (LoadStore|StoreStore) memory barrier. 428#ifndef USE_READ_BARRIER 429 str \tmp3, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 430#else 431 @ strex necessary for read barrier bits 432 strex \tmp2, \tmp3, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 433 cbnz \tmp2, 3f @ If the store failed, retry. 434#endif 435 bx lr 4362: @ tmp2: original lock word, tmp1: thread_id, tmp3: tmp2 ^ tmp1 437#if LOCK_WORD_THIN_LOCK_COUNT_SHIFT + LOCK_WORD_THIN_LOCK_COUNT_SIZE != LOCK_WORD_GC_STATE_SHIFT 438#error "Expecting thin lock count and gc state in consecutive bits." 439#endif 440 @ Check lock word state and thread id together, 441 bfc \tmp3, \ 442 #LOCK_WORD_THIN_LOCK_COUNT_SHIFT, \ 443 #(LOCK_WORD_THIN_LOCK_COUNT_SIZE + LOCK_WORD_GC_STATE_SIZE) 444 cbnz \tmp3, \slow_unlock @ if either of the top two bits are set, or the lock word's 445 @ thread id did not match, go slow path. 446 sub \tmp3, \tmp2, #LOCK_WORD_THIN_LOCK_COUNT_ONE @ Decrement recursive lock count. 447#ifndef USE_READ_BARRIER 448 str \tmp3, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 449#else 450 @ strex necessary for read barrier bits. 451 strex \tmp2, \tmp3, [\obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET] 452 cbnz \tmp2, 3f @ If the store failed, retry. 453#endif 454 bx lr 4553: 456 b 1b @ retry 457.endm 458 459#endif // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_S_ 460