#ifdef ART_USE_RESTRICTED_MODE
// Load the absolute address of a symbol using the R_X86_64_PC64 (PC relative)
// relocation type into the register "reg".
//
// Clobbers xIP1.
//
.macro LOAD_PC_REL_ADDRESS reg, symbol
// Load address of reloc_addr following R_X86_64_PC64 relocation type.
adr \reg, reloc_addr\@
ldr xIP1, reloc_addr\@
add \reg, \reg, xIP1
// Jump over the literal.
b .Lload_pc_rel_address_done\@
.global \symbol
#ifdef ART_USE_SIMULATOR
// R_AARCH64_NONE will be replaced by R_X86_64_PC64 in simulator mode.
.reloc reloc_addr\@, R_AARCH64_NONE, \symbol
#else
.reloc reloc_addr\@, R_AARCH64_PREL64, \symbol
#endif // ART_USE_SIMULATOR
reloc_addr\@:
.dword 0x0000000000000000
.Lload_pc_rel_address_done\@:
.endm
// Note: xIP0 and xIP1 will be clobbered and shouldn't ever be expected to retain values pre/post
// branch to symbol as the Arm AAPCS prohibts it.
// Call a symbol (e.g: "bl symbol").
.macro CALL_SYMBOL symbol
LOAD_PC_REL_ADDRESS xIP0, \symbol
blr xIP0
.endm
// Branch to a symbol without link (e.g: "b symbol")
.macro BRANCH_SYMBOL symbol
LOAD_PC_REL_ADDRESS xIP0, \symbol
br xIP0
.endm
// Branch to a symbol if register is not equal to zero (e.g: "cbz reg, symbol").
.macro BRANCH_SYMBOL_CBZ reg, symbol
cbnz \reg, .Lbranch_not_zero\@
BRANCH_SYMBOL \symbol
.Lbranch_not_zero\@:
nop
.endm
// Branch to a symbol if not equal (e.g: "b.ne symbol").
.macro BRANCH_SYMBOL_NE symbol
b.eq .Lbranch_equal\@
BRANCH_SYMBOL \symbol
.Lbranch_equal\@:
nop
.endm
// Branch to a symbol if not equal (e.g: "b.eq symbol").
.macro BRANCH_SYMBOL_EQ symbol
b.ne .Lbranch_not_equal\@
BRANCH_SYMBOL \symbol
// The spec is not clear whether the CFA is part of the saved state and tools
// differ in the behaviour, so explicitly set the CFA to avoid any ambiguity.
// The restored CFA state should match the CFA state during CFI_REMEMBER_STATE.
.macro CFI_RESTORE_STATE_AND_DEF_CFA reg, offset
.cfi_restore_state
.cfi_def_cfa \reg, \offset
.endm
.macro ENTRY_ALIGNED name, alignment
.type \name, #function
.hidden \name // Hide this as a global symbol, so we do not incur plt calls.
.global \name
.balign \alignment
\name:
.cfi_startproc
.endm
.macro ENTRY name
ENTRY_ALIGNED \name, 16
.endm
.macro END name
.cfi_endproc
.size \name, .-\name
.endm
.macro UNIMPLEMENTED name
ENTRY \name
brk 0
END \name
.endm
// Macro to poison (negate) the reference for heap poisoning.
.macro POISON_HEAP_REF rRef
#ifdef USE_HEAP_POISONING
neg \rRef, \rRef
#endif // USE_HEAP_POISONING
.endm
// Macro to unpoison (negate) the reference for heap poisoning.
.macro UNPOISON_HEAP_REF rRef
#ifdef USE_HEAP_POISONING
neg \rRef, \rRef
#endif // USE_HEAP_POISONING
.endm
.macro INCREASE_FRAME frame_adjustment sub sp, sp, #(\frame_adjustment)
.cfi_adjust_cfa_offset (\frame_adjustment)
.endm
// _ZN3art7Runtime9instance_E is a pointer to the runtime instance so
// dereference it.
ldr \reg, [\reg, #0]
.endm
#else
.macro LOAD_RUNTIME_INSTANCE reg
#if __has_feature(hwaddress_sanitizer)
adrp \reg, :pg_hi21_nc:_ZN3art7Runtime9instance_E
#else
adrp \reg, _ZN3art7Runtime9instance_E
#endif // __has_feature(hwaddress_sanitizer)
ldr \reg, [\reg, #:lo12:_ZN3art7Runtime9instance_E]
.endm
#endif // ART_USE_RESTRICTED_MODE
// Macro to refresh the Marking Register (W20).
//
// This macro must be called at the end of functions implementing
// entrypoints that possibly (directly or indirectly) perform a
// suspend check (before they return).
.macro REFRESH_MARKING_REGISTER
#ifdef RESERVE_MARKING_REGISTER
ldr wMR, [xSELF, #THREAD_IS_GC_MARKING_OFFSET]
#endif
.endm
// Macro to refresh the suspend check register.
//
// We do not refresh `xSUSPEND` after every transition to Runnable, so there is
// a chance that an implicit suspend check loads null to xSUSPEND but before
// causing a SIGSEGV at the next implicit suspend check we make a runtime call
// that performs the suspend check explicitly. This can cause a spurious fault
// without a pending suspend check request but it should be rare and the fault
// overhead was already expected when we triggered the suspend check, we just
// pay the price later than expected.
.macro REFRESH_SUSPEND_CHECK_REGISTER
ldr xSUSPEND, [xSELF, #THREAD_SUSPEND_TRIGGER_OFFSET]
.endm
// Ugly compile-time check, but we only have the preprocessor.
#if (FRAME_SIZE_SAVE_REFS_ONLY != 96)
#error "FRAME_SIZE_SAVE_REFS_ONLY(ARM64) size not as expected."
#endif
// Store ArtMethod* Runtime::callee_save_methods_[kSaveRefsOnly].
// Note: We could avoid saving X20 in the case of Baker read
// barriers, as it is overwritten by REFRESH_MARKING_REGISTER
// later; but it's not worth handling this special case.
stp xIP0, x20, [sp]
.cfi_rel_offset x20, 8
// Place sp in Thread::Current()->top_quick_frame.
mov xIP0, sp
str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
.endm
// TODO: Probably no need to restore registers preserved by aapcs64.
.macro RESTORE_SAVE_REFS_ONLY_FRAME
// Callee-saves.
// Note: Likewise, we could avoid restoring X20 in the case of Baker
// read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
// later; but it's not worth handling this special case.
RESTORE_REG x20, 8
RESTORE_TWO_REGS x21, x22, 16
RESTORE_TWO_REGS x23, x24, 32
RESTORE_TWO_REGS x25, x26, 48
RESTORE_TWO_REGS x27, x28, 64
RESTORE_TWO_REGS x29, xLR, 80
DECREASE_FRAME 96
.endm
.macro SETUP_SAVE_REFS_AND_ARGS_FRAME_INTERNAL base
// Ugly compile-time check, but we only have the preprocessor.
#if (FRAME_SIZE_SAVE_REFS_AND_ARGS != 224)
#error "FRAME_SIZE_SAVE_REFS_AND_ARGS(ARM64) size not as expected."
#endif
// x7, Callee-saves.
// Note: We could avoid saving X20 in the case of Baker read
// barriers, as it is overwritten by REFRESH_MARKING_REGISTER
// later; but it's not worth handling this special case.
stp x7, x20, [\base, #128]
.cfi_rel_offset x20, 136
SAVE_TWO_REGS_BASE \base, x21, x22, 144
SAVE_TWO_REGS_BASE \base, x23, x24, 160
SAVE_TWO_REGS_BASE \base, x25, x26, 176
SAVE_TWO_REGS_BASE \base, x27, x28, 192
// x29(callee-save) and LR.
SAVE_TWO_REGS_BASE \base, x29, xLR, 208
.endm
// TODO: Probably no need to restore registers preserved by aapcs64. (That would require
// auditing all users to make sure they restore aapcs64 callee-save registers they clobber.)
.macro RESTORE_SAVE_REFS_AND_ARGS_FRAME_INTERNAL base
// FP args.
ldp d0, d1, [\base, #16]
ldp d2, d3, [\base, #32]
ldp d4, d5, [\base, #48]
ldp d6, d7, [\base, #64]
// x7, callee-saves and LR.
// Note: Likewise, we could avoid restoring X20 in the case of Baker
// read barriers, as it is overwritten by REFRESH_MARKING_REGISTER
// later; but it's not worth handling this special case.
ldp x7, x20, [\base, #128]
.cfi_restore x20
RESTORE_TWO_REGS_BASE \base, x21, x22, 144
RESTORE_TWO_REGS_BASE \base, x23, x24, 160
RESTORE_TWO_REGS_BASE \base, x25, x26, 176
RESTORE_TWO_REGS_BASE \base, x27, x28, 192
RESTORE_TWO_REGS_BASE \base, x29, xLR, 208
.endm
// Ugly compile-time check, but we only have the preprocessor.
#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVES != 176)
#error "FRAME_SIZE_SAVE_ALL_CALLEE_SAVES(ARM64) size not as expected."
#endif
// Locking is needed for both managed code and JNI stubs.
.macro LOCK_OBJECT_FAST_PATH obj, slow_lock, can_be_null, use_lse
.if \use_lse
.arch_extension lse
.endif
// Use scratch registers x8-x11 (x12 for LSE) as temporaries.
ldr w9, [xSELF, #THREAD_ID_OFFSET]
.if \can_be_null
BRANCH_SYMBOL_CBZ \obj, \slow_lock
.endif
// Exclusive load/store has no immediate anymore.
add x8, \obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET
.if \use_lse
ldr w10, [x8] // With LSE we only need a simple one-time load.
.endif 1:
.if !\use_lse
ldaxr w10, [x8] // Without LSE, acquire needed only in most common case.
.endif
eor w11, w10, w9 // Prepare the value to store if unlocked
// (thread id, count of 0 and preserved read barrier bits),
// or prepare to compare thread id for recursive lock check
// (lock_word.ThreadId() ^ self->ThreadId()).
tst w10, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // Test the non-gc bits.
b.ne 2f // Check if unlocked.
// Unlocked case - store w11: original lock word plus thread id, preserved read barrier bits.
.if \use_lse
mov w12, w10 // Remember old value for comparison.
casa w10, w11, [x8] // CAS Acquire: w10 (expected) -> w11 (new)
cmp w10, w12
b.ne 1b // Retry
.else
stxr w10, w11, [x8]
cbnz w10, 1b // If the store failed, retry.
.endif
ret 2: // w10: original lock word, w9: thread id, w11: w10 ^ w9
// Check lock word state and thread id together,
tst w11, #(LOCK_WORD_STATE_MASK_SHIFTED | LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED)
BRANCH_SYMBOL_NE \slow_lock
add w11, w10, #LOCK_WORD_THIN_LOCK_COUNT_ONE // Increment the recursive lock count.
tst w11, #LOCK_WORD_THIN_LOCK_COUNT_MASK_SHIFTED // Test the new thin lock count.
BRANCH_SYMBOL_EQ \slow_lock // Zero as the new count indicates overflow, go
// slow path.
.if \use_lse
mov w12, w10 // Remember old value for comparison. cas w10, w11, [x8] // CAS: w10 (expected) -> w11 (new). Relaxed ordering.
cmp w10, w12
b.ne 1b // Retry
.else
stxr w10, w11, [x8]
cbnz w10, 1b // If the store failed, retry.
.endif
ret
.if \use_lse
.arch_extension nolse
.endif
.endm
// Unlocking is needed for both managed code and JNI stubs.
.macro UNLOCK_OBJECT_FAST_PATH obj, slow_unlock, can_be_null, use_lse
.if \use_lse
.arch_extension lse
.endif
// Use scratch registers x8-x11 as temporaries.
ldr w9, [xSELF, #THREAD_ID_OFFSET]
.if \can_be_null
BRANCH_SYMBOL_CBZ \obj, \slow_unlock
.endif
// Exclusive load/store has no immediate anymore.
add x8, \obj, #MIRROR_OBJECT_LOCK_WORD_OFFSET
#ifndef USE_READ_BARRIER
ldr w10, [x8]
#else
.if \use_lse
ldr w10, [x8] // With LSE, we still need a simple load to check ownership.
.else 1: // This path is only retaken for non-LSE paths.
ldxr w10, [x8] // Without LSE, we need an exclusive load.
.endif
#endif
eor w11, w10, w9 // Prepare the value to store if simply locked
// (mostly 0s, and preserved read barrier bits),
// or prepare to compare thread id for recursive lock check
// (lock_word.ThreadId() ^ self->ThreadId()).
tst w11, #LOCK_WORD_GC_STATE_MASK_SHIFTED_TOGGLED // Test the non-gc bits.
b.ne 2f // Locked recursively or by other thread?
// Transition to unlocked.
#ifndef USE_READ_BARRIER
stlr w11, [x8]
#else
.if \use_lse
// Memory: [ID | RB] ^ w9: [ID | 0] -> Result: [0 | RB]
steorl w9, [x8] // Atomically clear thread id but preserve read barrier.
.else
stlxr w10, w11, [x8] // Need to use atomic instructions for read barrier.
cbnz w10, 1b // If the store failed, retry.
.endif
#endif
ret 2:
// Check lock word state and thread id together.
tst w11, #(LOCK_WORD_STATE_MASK_SHIFTED | LOCK_WORD_THIN_LOCK_OWNER_MASK_SHIFTED)
BRANCH_SYMBOL_NE \slow_unlock
#ifndef USE_READ_BARRIER sub w11, w10, #LOCK_WORD_THIN_LOCK_COUNT_ONE // decrement count
str w11, [x8]
#else
.if \use_lse
mov w11, #-LOCK_WORD_THIN_LOCK_COUNT_ONE
stadd w11, [x8] // Atomically decrement count field but preserve read barrier.
.else sub w11, w10, #LOCK_WORD_THIN_LOCK_COUNT_ONE // decrement count
stxr w10, w11, [x8] // Need to use atomic instructions for read barrier.
cbnz w10, 1b // If the store failed, retry.
.endif
#endif
ret
.if \use_lse
.arch_extension nolse
.endif
.endm
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.