/* *Jnidlsymlookupstubfor@CriticalNative.
*/
ENTRY art_jni_dlsym_lookup_critical_stub
// The hidden arg holding the tagged method (bit 0set means GenericJNI) is r4.
// For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
tst r4, #1
bne art_jni_dlsym_lookup_stub
// Reserve space for a SaveRefsAndArgs managed frame, either for the actual runtime
// method or for a GenericJNI frame which is similar but has a native method and a tag.
// Do this eagerly, so that we can use these registers as temps without the need to
// save and restore them multiple times.
INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS
// Save args, the hidden arg and caller PC. No CFI needed for args and the hidden arg.
push {r0, r1, r2, r3, r4, lr}
.cfi_adjust_cfa_offset 24
.cfi_rel_offset lr, 20
// Prepare the return address for managed stack walk of the SaveRefsAndArgs frame.
// If we're coming from JNI stub with tail call, it is LR. If we're coming from
// JNI stub that saved the return address, it will be the last value we copy below.
// If we're coming directly from compiled code, it is LR, set further down.
ldr lr, [sp, #20]
// Move the stack args if any.
add r4, sp, #24
cbz r0, .Lcritical_skip_copy_args
.Lcritical_copy_args_loop:
ldrd ip, lr, [r4, #FRAME_SIZE_SAVE_REFS_AND_ARGS]
subs r0, r0, #8
strd ip, lr, [r4], #8
bne .Lcritical_copy_args_loop
.Lcritical_skip_copy_args:
// The managed frame address is now in R4. This is conveniently a callee-save in native ABI.
// Restore args.
pop {r0, r1, r2, r3}
.cfi_adjust_cfa_offset -16
// Spill registers for the SaveRefsAndArgs frame above the stack args.
// Note that the runtime shall not examine the args here, otherwise we would have to
// move them in registers and stack to account for the difference between managed and
// native ABIs.
add ip, r4, #FRAME_SIZE_SAVE_REFS_AND_ARGS - 40
stmia ip, {r1-r3, r5-r8, r10-r11, lr} // LR: Save return address for tail call from JNI stub.
// (If there were any stack args, we're storing the value that's already there.
// For direct calls from compiled managed code, we shall overwrite this below.)
// Skip args r1-r3.
CFI_EXPRESSION_BREG 5, 4, FRAME_SIZE_SAVE_REFS_AND_ARGS - 28
CFI_EXPRESSION_BREG 6, 4, FRAME_SIZE_SAVE_REFS_AND_ARGS - 24
CFI_EXPRESSION_BREG 7, 4, FRAME_SIZE_SAVE_REFS_AND_ARGS - 20
CFI_EXPRESSION_BREG 8, 4, FRAME_SIZE_SAVE_REFS_AND_ARGS - 16
CFI_EXPRESSION_BREG 10, 4, FRAME_SIZE_SAVE_REFS_AND_ARGS - 12
CFI_EXPRESSION_BREG 11, 4, FRAME_SIZE_SAVE_REFS_AND_ARGS - 8
// The saved return PC for managed stack walk is not necessarily our LR.
// Skip managed FP args as these are native ABI caller-saves and not args.
// Restore the hidden arg to r1 and caller PC.
pop {r1, lr}
.cfi_adjust_cfa_offset -8
.cfi_restore lr
// Save our return PC in the padding.
str lr, [r4, #__SIZEOF_POINTER__]
CFI_EXPRESSION_BREG 14, 4, __SIZEOF_POINTER__
// When coming from a compiled method, the return PC for managed stack walk is LR.
// (When coming from a compiled stub, the correct return PC is already stored above.)
str lr, [r4, #(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__)]
// Replace the target method with the SaveRefsAndArgs runtime method.
LOAD_RUNTIME_INSTANCE r1
ldr r1, [r1, #RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET]
mov r2, r4 // Prepare untagged managed SP for the runtime method.
.Lcritical_skip_prepare_runtime_method:
// Store the method on the bottom of the managed frame.
str r1, [r4]
// Place (maybe tagged) managed SP in Thread::Current()->top_quick_frame.
str r2, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET]
// Preserve the native arg register r0 in callee-save register r10 which was saved above.
mov r10, r0
// Restore the native arg register r0.
mov r0, r10
// Restore the frame. We shall not need the method anymore.
add r1, r4, #FRAME_SIZE_SAVE_REFS_AND_ARGS - 40
ldmia r1, {r1-r3, r5-r8, r10-r11}
.cfi_restore r5
.cfi_restore r6
.cfi_restore r7
.cfi_restore r8
.cfi_restore r10
.cfi_restore r11
REFRESH_MARKING_REGISTER
// Check for exception before moving args back to keep the return PC for managed stack walk.
cmp ip, #0
CFI_REMEMBER_STATE
beq .Lcritical_deliver_exception
// Remove the frame reservation.
DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS
// Do the tail call.
bx ip
.Lcritical_deliver_exception:
CFI_RESTORE_STATE_AND_DEF_CFA sp, FRAME_SIZE_SAVE_REFS_AND_ARGS
// The exception delivery checks that rSELF was saved but the SaveRefsAndArgs
// frame does not save it, so we cannot use the existing SaveRefsAndArgs frame.
// That's why we checked for exception after restoring registers from it.
// We need to build a SaveAllCalleeSaves frame instead. Args are irrelevant at this
// point but keep the area allocated for stack args to keep CFA definition simple.
#if FRAME_SIZE_SAVE_REFS_AND_ARGS != FRAME_SIZE_SAVE_ALL_CALLEE_SAVES
# error "Expected FRAME_SIZE_SAVE_REFS_AND_ARGS == FRAME_SIZE_SAVE_ALL_CALLEE_SAVES"
// Otherwise we would need to adjust SP and R4 and move our return PC which is at [R4, #4].
// (Luckily, both SaveRefsAndArgs and SaveAllCalleeSaves frames have padding there.)
#endif
// Spill registers for the SaveAllCalleeSaves frame above the stack args area.
add ip, r4, #FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 32
stmia ip, {r5-r11} // Keep the caller PC for managed stack walk.
CFI_EXPRESSION_BREG 5, 4, FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 32
CFI_EXPRESSION_BREG 6, 4, FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 28
CFI_EXPRESSION_BREG 7, 4, FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 24
CFI_EXPRESSION_BREG 8, 4, FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 20
CFI_EXPRESSION_BREG 9, 4, FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 16
CFI_EXPRESSION_BREG 10, 4, FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 12
CFI_EXPRESSION_BREG 11, 4, FRAME_SIZE_SAVE_ALL_CALLEE_SAVES - 8
// Skip R4, it is callee-save in managed ABI.
add ip, r4, #12
vstmia ip, {s16-s31}
// Store ArtMethod* Runtime::callee_save_methods_[kSaveAllCalleeSaves] to the managed frame.
LOAD_RUNTIME_INSTANCE ip
ldr ip, [ip, #RUNTIME_SAVE_ALL_CALLEE_SAVES_METHOD_OFFSET]
str ip, [r4]
// Place the managed frame SP in Thread::Current()->top_quick_frame.
str r4, [rSELF, #THREAD_TOP_QUICK_FRAME_OFFSET]
DELIVER_PENDING_EXCEPTION_FRAME_READY
END art_jni_dlsym_lookup_critical_stub
/* *Readbarrierforthemethod'sdeclaringclassneededbyJNIstubforstaticmethods. *(We'reusingapointertothedeclaringclassin`ArtMethod`as`jclass`.)
*/
// The method argument is already in r0 for call to `artJniReadBarrier(ArtMethod*)`.
JNI_SAVE_MANAGED_ARGS_TRAMPOLINE art_jni_read_barrier, artJniReadBarrier
/* *EntryfromJNIstubthattriestolocktheobjectinafastpathand *calls`artLockObjectFromCode()`(thesameasformanagedcode)forthe *difficultcases,mayblockforGC. *Customcallingconvention: *r4holdsthenon-nullobjecttolock. *Callee-saveregistershavebeensavedandcanbeusedastemporaries. *Allargumentregistersneedtobepreserved.
*/
ENTRY art_jni_lock_object
// Note: the slow path is actually the art_jni_lock_object_no_inline (tail call).
LOCK_OBJECT_FAST_PATH r4, r5, r6, r7, .Llock_object_jni_slow, /*can_be_null*/ 0
END art_jni_lock_object
/* *EntryfromJNIstubthatcalls`artLockObjectFromCode()` *(thesameasformanagedcode),mayblockforGC. *Customcallingconvention: *r4holdsthenon-nullobjecttolock. *Callee-saveregistershavebeensavedandcanbeusedastemporaries. *Allargumentregistersneedtobepreserved.
*/
.extern artLockObjectFromCode
ENTRY art_jni_lock_object_no_inline
// This is also the slow path for art_jni_lock_object.
// Note that we need a local label as the assembler emits bad instructions
// for CBZ/CBNZ if we try to jump to `art_jni_lock_object_no_inline`.
.Llock_object_jni_slow:
// Save managed args, r4 (for stack alignment) and LR.
SAVE_MANAGED_ARGS_R4_LR_INCREASE_FRAME
// Call `artLockObjectFromCode()`
mov r0, r4 @ Pass the object to lock.
mov r1, rSELF @ Pass Thread::Current().
bl artLockObjectFromCode @ (Object* obj, Thread*)
// Check result.
cbnz r0, 1f
// Restore args and r4 and return.
RESTORE_MANAGED_ARGS_R4_AND_RETURN /*restore_cfa*/ 1 1:
// All args are irrelevant when throwing an exception and R4 is preserved
// by the `artLockObjectFromCode()` call. Load LR and drop saved args and R4.
ldr lr, [sp, #(MANAGED_ARGS_R4_LR_SAVE_SIZE - 4)]
.cfi_restore lr
DECREASE_FRAME MANAGED_ARGS_R4_LR_SAVE_SIZE
// Make a call to `artDeliverPendingExceptionFromCode()`.
// Rely on the JNI transition frame constructed in the JNI stub.
mov r0, rSELF @ Pass Thread::Current().
bl artDeliverPendingExceptionFromCode @ (Thread*)
bl art_quick_do_long_jump @ (Context*)
bkpt // Unreached
END art_jni_lock_object_no_inline
/* *EntryfromJNIstubthattriestounlocktheobjectinafastpathandcalls *`artJniUnlockObject()`forthedifficultcases.Notethatfailuretounlock *isfatal,sowedonotneedtocheckforexceptionsintheslowpath. *Customcallingconvention: *r4holdsthenon-nullobjecttounlock. *Callee-saveregistershavebeensavedandcanbeusedastemporaries. *Returnregistersr0-r1ands0-s1needtobepreserved.
*/
ENTRY art_jni_unlock_object
// Note: the slow path is actually the art_jni_unlock_object_no_inline (tail call).
UNLOCK_OBJECT_FAST_PATH r4, r5, r6, r7, .Lunlock_object_jni_slow, /*can_be_null*/ 0
END art_jni_unlock_object
/* *EntryfromJNIstubthatcalls`artJniUnlockObject()`.Notethatfailureto *unlockisfatal,sowedonotneedtocheckforexceptions. *Customcallingconvention: *r4holdsthenon-nullobjecttounlock. *Callee-saveregistershavebeensavedandcanbeusedastemporaries. *Returnregistersr0-r1ands0-s1needtobepreserved.
*/
// This is also the slow path for art_jni_unlock_object.
JNI_SAVE_RETURN_VALUE_TRAMPOLINE art_jni_unlock_object_no_inline, artJniUnlockObject, r4, rSELF, \ /* Note that we need a local label as the assembler emits bad instructions */ \ /* for CBZ/CBNZ if we try to jump to `art_jni_unlock_object_no_inline`. */ \
.Lunlock_object_jni_slow
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-29)
¤
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.