// Save register args and adds space for outgoing arguments.
// With `call_args_space = 0`, the ESP shall be 8-byte aligned but not 16-byte aligned,
// so either the `call_args_space` should be 8 (or 24, 40, ...) or the user of the macro
// needs to adjust the ESP explicitly afterwards.
MACRO1(SAVE_MANAGED_ARGS_INCREASE_FRAME, call_args_space)
// Return address is on the stack.
PUSH_ARG ebx
PUSH_ARG edx
PUSH_ARG ecx
PUSH_ARG eax
// Make xmm<n> spill slots 8-byte aligned.
INCREASE_FRAME (\call_args_space + /*FPRs*/ 4 * 8 + /*padding*/ 4)
movsd %xmm0, \call_args_space + 0(%esp)
movsd %xmm1, \call_args_space + 8(%esp)
movsd %xmm2, \call_args_space + 16(%esp)
movsd %xmm3, \call_args_space + 24(%esp)
END_MACRO
/* *Jnidlsymlookupstubfor@CriticalNative.
*/
DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub
// The hidden arg holding the tagged method (bit 0set means GenericJNI) is eax.
// For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
testl LITERAL(1), %eax
jnz art_jni_dlsym_lookup_stub
// Since the native call args are all on the stack, we can use the managed args
// registers as scratch registers. So, EBX, EDX and ECX are available.
// Load caller PC.
movl (%esp), %ecx
// Save the caller method from the hidden arg.
PUSH_ARG eax
// Load caller PC to EDX and redefine return PC for CFI.
movl (%esp), %edx
CFI_REGISTER(%eip, %edx)
// 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.
INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__
// Calculate the number of DWORDs to move.
movl %eax, %ecx
shrl LITERAL(2), %ecx
jecxz .Lcritical_skip_copy_args
// Save EDI, ESI so that we can use them for moving stack args.
PUSH edi
PUSH esi
.Lcritical_skip_copy_args:
// Calculate the base address of the managed frame.
leal (%esp, %eax, 1), %eax
leal 1(%eax), %ecx // Prepare managed SP tagged for a GenericJNI frame.
testl LITERAL(ACCESS_FLAGS_METHOD_IS_NATIVE), ART_METHOD_ACCESS_FLAGS_OFFSET(%ebx)
jnz .Lcritical_skip_prepare_runtime_method
// Save the return PC for managed stack walk.
// (When coming from a compiled stub, the correct return PC is already there.)
movl %edx, FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%eax)
// Replace the target method with the SaveRefsAndArgs runtime method.
LOAD_RUNTIME_INSTANCE ebx
movl RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET(%ebx), %ebx
movl %eax, %ecx // Prepare untagged managed SP for the runtime method.
.Lcritical_skip_prepare_runtime_method:
// Store the method on the bottom of the managed frame.
movl %ebx, (%eax)
// Move the managed frame address to native callee-save register EBX.
movl %eax, %ebx
// Spill registers for the SaveRefsAndArgs frame above the stack args.
movl %edi, 56(%ebx)
CFI_EXPRESSION_BREG CFI_REG(edi), CFI_REG(ebx), 56
movl %esi, 52(%ebx)
CFI_EXPRESSION_BREG CFI_REG(esi), CFI_REG(ebx), 52
movl %ebp, 48(%ebx)
CFI_EXPRESSION_BREG CFI_REG(ebp), CFI_REG(ebx), 48
// Skip managed ABI args EBX, EDX, ECX and FPRs. The runtime shall not examine the
// args in the managed frame. (We have already clobbered EBX, EDX, ECX anyway.)
// Place (maybe tagged) managed SP in Thread::Current()->top_quick_frame.
movl %ecx, %fs:THREAD_TOP_QUICK_FRAME_OFFSET
// Save our return PC in a slot reserved for first FP arg in managed ABI.
movl %edx, __SIZEOF_POINTER__(%ebx)
CFI_EXPRESSION_BREG CFI_REG(eip), CFI_REG(ebx), __SIZEOF_POINTER__
// Check for exception.
test %eax, %eax
CFI_REMEMBER_STATE
jz .Lcritical_deliver_exception
// Remember our return PC in EDX.
movl __SIZEOF_POINTER__(%ebx), %edx
CFI_REGISTER(%eip, %edx)
// Restore callee-save registers from the frame. We shall not need the method anymore.
movl 48(%ebx), %ebp
CFI_RESTORE(%ebp)
movl 52(%ebx), %esi
CFI_RESTORE(%esi)
movl 56(%ebx), %edi
CFI_RESTORE(%edi)
// Calculate the number of DWORDs to move.
movl %ebx, %ecx
subl %esp, %ecx
shrl LITERAL(2), %ecx
jecxz .Lcritical_skip_copy_args_back
// Save EDI, ESI so that we can use them for moving stack args.
PUSH edi
PUSH esi
// Move stack args to their original place.
leal -__SIZEOF_POINTER__(%ebx), %esi
leal FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%ebx), %edi
std
rep movsd
cld
// Restore EDI, ESI.
POP esi
POP edi
.Lcritical_skip_copy_args_back:
// Remove the frame reservation.
DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__
// Store our return PC.
movl %edx, (%esp)
CFI_REL_OFFSET(%eip, 0)
/* *EntryfromJNIstubthatcalls`artLockObjectFromCode()` *(thesameasformanagedcode),mayblockforGC. *Customcallingconvention: *EBPholdsthenon-nullobjecttolock. *Callee-saveregistershavebeensavedandcanbeusedastemporaries(exceptEBP). *Allargumentregistersneedtobepreserved.
*/
DEFINE_FUNCTION art_jni_lock_object_no_inline
// This is also the slow path for art_jni_lock_object.
// Save register args EAX, ECX, EDX, EBX, mmx0-mmx3; original value of EAX is in EDI.
SAVE_MANAGED_ARGS_INCREASE_FRAME /*call_args_space*/ 0
// Note: The stack is not 16-byte aligned here but it shall be after pushing args for the call.
// Call `artLockObjectFromCode()`
pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current().
CFI_ADJUST_CFA_OFFSET(4)
PUSH_ARG ebp // Pass the object to lock.
call SYMBOL(artLockObjectFromCode) // (object, Thread*)
// Check result.
testl %eax, %eax
jnz 1f
// Restore register args EAX, ECX, EDX, EBX, mmx0-mmx3 and return.
RESTORE_MANAGED_ARGS_DECREASE_FRAME /*call_args_space*/ 8
ret
.cfi_adjust_cfa_offset (/*call args*/ 8 + MANAGED_ARGS_SAVE_SIZE) 1:
// All args are irrelevant when throwing an exception.
// Remove the spill area except for new padding to align stack.
DECREASE_FRAME (/*call args*/ 8 + MANAGED_ARGS_SAVE_SIZE - /*new padding*/ 8)
// Rely on the JNI transition frame constructed in the JNI stub.
pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
CFI_ADJUST_CFA_OFFSET(4)
call SYMBOL(artDeliverPendingExceptionFromCode) // (Thread*)
call SYMBOL(art_quick_do_long_jump)
UNREACHABLE
END_FUNCTION art_jni_lock_object_no_inline
/* *EntryfromJNIstubthattriestounlocktheobjectinafastpathandcalls *`artJniUnlockObject()`forthedifficultcases.Notethatfailuretounlock *isfatal,sowedonotneedtocheckforexceptionsintheslowpath. *Customcallingconvention: *EBPholdsthenon-nullobjecttounlock. *Callee-saveregistershavebeensavedandcanbeusedastemporaries(exceptEBP). *ReturnregistersEAX,EDXandmmx0needtobepreserved.
*/
DEFINE_FUNCTION art_jni_unlock_object
movl %eax, %edi // Preserve EAX in a different register.
UNLOCK_OBJECT_FAST_PATH ebp, esi, /*saved_eax*/ edi, .Lunlock_object_jni_slow
/* *EntryfromJNIstubthatcalls`artJniUnlockObject()`.Notethatfailureto *unlockisfatal,sowedonotneedtocheckforexceptions. *Customcallingconvention: *EBPholdsthenon-nullobjecttounlock. *Callee-saveregistershavebeensavedandcanbeusedastemporaries(exceptEBP). *ReturnregistersEAX,EDXandmmx0needtobepreserved.
*/
// This is also the slow path for art_jni_unlock_object.
JNI_SAVE_RETURN_VALUE_TRAMPOLINE \
art_jni_unlock_object_no_inline, artJniUnlockObject, ebp, fs:THREAD_SELF_OFFSET
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.13 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.