// For x86, the CFA is esp+4, the address above the pushed return address on the stack.
/* *Macrothatsetsupthecalleesaveframetoconformwith *Runtime::CreateCalleeSaveMethod(kSaveRefsAndArgs)
*/
MACRO0(SETUP_SAVE_REFS_AND_ARGS_FRAME)
#if defined(__APPLE__)
int3
int3
#else
SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
// R10 := Runtime::Current()
LOAD_RUNTIME_INSTANCE r10
// R10 := ArtMethod* for ref and args callee save frame method.
movq RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET(%r10), %r10
// Store ArtMethod* to bottom of stack.
movq %r10, 0(%rsp)
// Store rsp as the top quick frame.
movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
#endif // __APPLE__
END_MACRO
MACRO0(SETUP_SAVE_REFS_AND_ARGS_FRAME_WITH_METHOD_IN_RDI)
SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY
// Store ArtMethod to bottom of stack.
movq %rdi, 0(%rsp)
// Store rsp as the stop quick frame.
movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
END_MACRO
/* *Macrothatsetsupthecalleesaveframetoconformwith *Runtime::CreateCalleeSaveMethod(kSaveEverything) *whenR14andR15arealreadysaved.
*/
MACRO1(SETUP_SAVE_EVERYTHING_FRAME_R14_R15_SAVED, runtime_method_offset = RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET)
#if defined(__APPLE__)
int3
int3
#else
// Save core registers from highest to lowest to agree with core spills bitmap.
// R14 and R15, or at least placeholders for them, are already on the stack.
PUSH r13
PUSH r12
PUSH r11
PUSH r10
PUSH r9
PUSH r8
PUSH rdi
PUSH rsi
PUSH rbp
PUSH rbx
PUSH rdx
PUSH rcx
PUSH rax
// Create space for FPRs and stack alignment padding.
INCREASE_FRAME 8 + 16 * 8
// R10 := Runtime::Current()
LOAD_RUNTIME_INSTANCE r10
// Save FPRs.
movq %xmm0, 8(%rsp)
movq %xmm1, 16(%rsp)
movq %xmm2, 24(%rsp)
movq %xmm3, 32(%rsp)
movq %xmm4, 40(%rsp)
movq %xmm5, 48(%rsp)
movq %xmm6, 56(%rsp)
movq %xmm7, 64(%rsp)
movq %xmm8, 72(%rsp)
movq %xmm9, 80(%rsp)
movq %xmm10, 88(%rsp)
movq %xmm11, 96(%rsp)
movq %xmm12, 104(%rsp)
movq %xmm13, 112(%rsp)
movq %xmm14, 120(%rsp)
movq %xmm15, 128(%rsp)
// Push ArtMethod* for save everything frame method.
pushq \runtime_method_offset(%r10)
CFI_ADJUST_CFA_OFFSET(8)
// Store rsp as the top quick frame.
movq %rsp, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
// Ugly compile-time check, but we only have the preprocessor.
// Last +8: implicit return address pushed on stack when caller made call.
#if (FRAME_SIZE_SAVE_EVERYTHING != 15 * 8 + 16 * 8 + 16 + 8)
#error "FRAME_SIZE_SAVE_EVERYTHING(X86_64) size not as expected."
#endif
#endif // __APPLE__
END_MACRO
MACRO0(RESTORE_SAVE_EVERYTHING_FRAME_GPRS_EXCEPT_RAX)
// Restore callee and GPR args (except RAX), mixed together to agree with core spills bitmap.
POP rcx
POP rdx
POP rbx
POP rbp
POP rsi
POP rdi
POP r8
POP r9
POP r10
POP r11
POP r12
POP r13
POP r14
POP r15
END_MACRO
/* *Quickinvocationstub. *Onentry: *[sp]=returnaddress *rdi=methodpointer *rsi=argumentarraythatmustatleastcontainthethispointer. *rdx=sizeofargumentarrayinbytes *rcx=(managed)threadpointer *r8=JValue*result *r9=char*shorty
*/
DEFINE_FUNCTION art_quick_invoke_stub
#if defined(__APPLE__)
int3
int3
#else
// Set up argument XMM registers.
leaq 1(%r9), %r10 // R10 := shorty + 1 ; ie skip return arg character.
leaq 4(%rsi), %r11 // R11 := arg_array + 4 ; ie skip this pointer.
LOOP_OVER_SHORTY_LOADING_XMMS xmm0, .Lxmm_setup_finished
LOOP_OVER_SHORTY_LOADING_XMMS xmm1, .Lxmm_setup_finished
LOOP_OVER_SHORTY_LOADING_XMMS xmm2, .Lxmm_setup_finished
LOOP_OVER_SHORTY_LOADING_XMMS xmm3, .Lxmm_setup_finished
LOOP_OVER_SHORTY_LOADING_XMMS xmm4, .Lxmm_setup_finished
LOOP_OVER_SHORTY_LOADING_XMMS xmm5, .Lxmm_setup_finished
LOOP_OVER_SHORTY_LOADING_XMMS xmm6, .Lxmm_setup_finished
LOOP_OVER_SHORTY_LOADING_XMMS xmm7, .Lxmm_setup_finished
.balign 16
.Lxmm_setup_finished:
PUSH rbp // Save rbp.
PUSH r8 // Save r8/result*.
PUSH r9 // Save r9/shorty*.
PUSH rbx // Save native callee save rbx
PUSH r12 // Save native callee save r12
PUSH r13 // Save native callee save r13
PUSH r14 // Save native callee save r14
PUSH r15 // Save native callee save r15
movq %rsp, %rbp // Copy value of stack pointer into base pointer.
CFI_DEF_CFA_REGISTER(rbp)
movl %edx, %r10d
addl LITERAL(100), %edx // Reserve space for return addr, StackReference<method>, rbp,
// r8, r9, rbx, r12, r13, r14, and r15 in frame.
andl LITERAL(0xFFFFFFF0), %edx // Align frame size to 16 bytes.
subl LITERAL(72), %edx // Remove space for return address, rbp, r8, r9, rbx, r12,
// r13, r14, and r15
subq %rdx, %rsp // Reserve stack space for argument array.
#if (STACK_REFERENCE_SIZE != 4)
#error "STACK_REFERENCE_SIZE(X86_64) size not as expected."
#endif
movq LITERAL(0), (%rsp) // Store null for method*
movl %r10d, %ecx // Place size of args in rcx.
movq %rdi, %rax // rax := method to be called
movq %rsi, %r11 // r11 := arg_array
leaq 8(%rsp), %rdi // rdi is pointing just above the ArtMethod* in the stack
// arguments.
// Copy arg array into stack.
rep movsb // while (rcx--) { *rdi++ = *rsi++ }
leaq 1(%r9), %r10 // r10 := shorty + 1 ; ie skip return arg character
movq %rax, %rdi // rdi := method to be called
movl (%r11), %esi // rsi := this pointer
addq LITERAL(4), %r11 // arg_array++
LOOP_OVER_SHORTY_LOADING_GPRS rdx, edx, .Lgpr_setup_finished
LOOP_OVER_SHORTY_LOADING_GPRS rcx, ecx, .Lgpr_setup_finished
LOOP_OVER_SHORTY_LOADING_GPRS r8, r8d, .Lgpr_setup_finished
LOOP_OVER_SHORTY_LOADING_GPRS r9, r9d, .Lgpr_setup_finished
.Lgpr_setup_finished:
call *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // Call the method.
movq %rbp, %rsp // Restore stack pointer.
POP r15 // Pop r15
POP r14 // Pop r14
POP r13 // Pop r13
POP r12 // Pop r12
POP rbx // Pop rbx
POP r9 // Pop r9 - shorty*
POP r8 // Pop r8 - result*.
POP rbp // Pop rbp
cmpb LITERAL(68), (%r9) // Test if result type char == 'D'.
je .Lreturn_double_quick
cmpb LITERAL(70), (%r9) // Test if result type char == 'F'.
je .Lreturn_float_quick
movq %rax, (%r8) // Store the result assuming its a long, int or Object*
ret
.Lreturn_double_quick:
movsd %xmm0, (%r8) // Store the double floating point result.
ret
.Lreturn_float_quick:
movss %xmm0, (%r8) // Store the floating point result.
ret
#endif // __APPLE__
END_FUNCTION art_quick_invoke_stub
/* *Quickinvocationstub. *Onentry: *[sp]=returnaddress *rdi=methodpointer *rsi=argumentarrayornullifnoarguments. *rdx=sizeofargumentarrayinbytes *rcx=(managed)threadpointer *r8=JValue*result *r9=char*shorty
*/
DEFINE_FUNCTION art_quick_invoke_static_stub
#if defined(__APPLE__)
int3
int3
#else
// Set up argument XMM registers.
leaq 1(%r9), %r10 // R10 := shorty + 1 ; ie skip return arg character
movq %rsi, %r11 // R11 := arg_array
LOOP_OVER_SHORTY_LOADING_XMMS xmm0, .Lxmm_setup_finished2
LOOP_OVER_SHORTY_LOADING_XMMS xmm1, .Lxmm_setup_finished2
LOOP_OVER_SHORTY_LOADING_XMMS xmm2, .Lxmm_setup_finished2
LOOP_OVER_SHORTY_LOADING_XMMS xmm3, .Lxmm_setup_finished2
LOOP_OVER_SHORTY_LOADING_XMMS xmm4, .Lxmm_setup_finished2
LOOP_OVER_SHORTY_LOADING_XMMS xmm5, .Lxmm_setup_finished2
LOOP_OVER_SHORTY_LOADING_XMMS xmm6, .Lxmm_setup_finished2
LOOP_OVER_SHORTY_LOADING_XMMS xmm7, .Lxmm_setup_finished2
.balign 16
.Lxmm_setup_finished2:
PUSH rbp // Save rbp.
PUSH r8 // Save r8/result*.
PUSH r9 // Save r9/shorty*.
PUSH rbx // Save rbx
PUSH r12 // Save r12
PUSH r13 // Save r13
PUSH r14 // Save r14
PUSH r15 // Save r15
movq %rsp, %rbp // Copy value of stack pointer into base pointer.
CFI_DEF_CFA_REGISTER(rbp)
movl %edx, %r10d
addl LITERAL(100), %edx // Reserve space for return addr, StackReference<method>, rbp,
// r8, r9, r12, r13, r14, and r15 in frame.
andl LITERAL(0xFFFFFFF0), %edx // Align frame size to 16 bytes.
subl LITERAL(72), %edx // Remove space for return address, rbp, r8, r9, rbx, r12,
// r13, r14, and r15.
subq %rdx, %rsp // Reserve stack space for argument array.
#if (STACK_REFERENCE_SIZE != 4)
#error "STACK_REFERENCE_SIZE(X86_64) size not as expected."
#endif
movq LITERAL(0), (%rsp) // Store null for method*
movl %r10d, %ecx // Place size of args in rcx.
movq %rdi, %rax // rax := method to be called
movq %rsi, %r11 // r11 := arg_array
leaq 8(%rsp), %rdi // rdi is pointing just above the ArtMethod* in the
// stack arguments.
// Copy arg array into stack.
rep movsb // while (rcx--) { *rdi++ = *rsi++ }
leaq 1(%r9), %r10 // r10 := shorty + 1 ; ie skip return arg character
movq %rax, %rdi // rdi := method to be called
LOOP_OVER_SHORTY_LOADING_GPRS rsi, esi, .Lgpr_setup_finished2
LOOP_OVER_SHORTY_LOADING_GPRS rdx, edx, .Lgpr_setup_finished2
LOOP_OVER_SHORTY_LOADING_GPRS rcx, ecx, .Lgpr_setup_finished2
LOOP_OVER_SHORTY_LOADING_GPRS r8, r8d, .Lgpr_setup_finished2
LOOP_OVER_SHORTY_LOADING_GPRS r9, r9d, .Lgpr_setup_finished2
.Lgpr_setup_finished2:
call *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // Call the method.
movq %rbp, %rsp // Restore stack pointer.
POP r15 // Pop r15
POP r14 // Pop r14
POP r13 // Pop r13
POP r12 // Pop r12
POP rbx // Pop rbx
POP r9 // Pop r9 - shorty*.
POP r8 // Pop r8 - result*.
POP rbp // Pop rbp
cmpb LITERAL(68), (%r9) // Test if result type char == 'D'.
je .Lreturn_double_quick2
cmpb LITERAL(70), (%r9) // Test if result type char == 'F'.
je .Lreturn_float_quick2
movq %rax, (%r8) // Store the result assuming its a long, int or Object*
ret
.Lreturn_double_quick2:
movsd %xmm0, (%r8) // Store the double floating point result.
ret
.Lreturn_float_quick2:
movss %xmm0, (%r8) // Store the floating point result.
ret
#endif // __APPLE__
END_FUNCTION art_quick_invoke_static_stub
/* *Longjumpstub. *Onentryrdiisthelongjumpcontext.Thisisexpectedtobereturnedfromaprevious *entrypointcallwhichthrewanexceptionordeoptimized.
*/
DEFINE_FUNCTION art_quick_do_long_jump
#if defined(__APPLE__)
int3
int3
#else
// Reserve space for the gprs + fprs;
INCREASE_FRAME X86_64_LONG_JUMP_CONTEXT_SIZE
MACRO1(DEOPT_OR_RETURN, is_ref = 0)
cmpl LITERAL(0), %gs:THREAD_DEOPT_CHECK_REQUIRED_OFFSET
jne 2f
ret 2:
SETUP_SAVE_EVERYTHING_FRAME
movq LITERAL(\is_ref), %rdx // pass if result is a reference
movq %rax, %rsi // pass the result
movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current
call SYMBOL(artDeoptimizeIfNeeded)
MACRO1(DEOPT_OR_RESTORE_SAVE_EVERYTHING_FRAME_AND_RETURN_RAX, is_ref = 0)
cmpl LITERAL(0), %gs:THREAD_DEOPT_CHECK_REQUIRED_OFFSET
CFI_REMEMBER_STATE
jne 2f
RESTORE_SAVE_EVERYTHING_FRAME_KEEP_RAX
ret 2:
CFI_RESTORE_STATE_AND_DEF_CFA rsp, FRAME_SIZE_SAVE_EVERYTHING
movq %rax, SAVE_EVERYTHING_FRAME_RAX_OFFSET(%rsp) // update result in the frame
movq LITERAL(\is_ref), %rdx // pass if result is a reference
movq %rax, %rsi // pass the result
movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current
call SYMBOL(artDeoptimizeIfNeeded)
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_rosalloc, RosAlloc).
MACRO2(ART_QUICK_ALLOC_OBJECT_ROSALLOC, c_name, cxx_name)
DEFINE_FUNCTION VAR(c_name)
// Fast path rosalloc allocation.
// RDI: mirror::Class*, RAX: return value
// RSI, RDX, RCX, R8, R9: free.
// Check if the thread local
// allocation stack has room.
movq %gs:THREAD_SELF_OFFSET, %r8 // r8 = thread
movq THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%r8), %rcx // rcx = alloc stack top.
cmpq THREAD_LOCAL_ALLOC_STACK_END_OFFSET(%r8), %rcx
jae .Lslow_path\c_name
// Load the object size
movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%rdi), %eax
// Check if the size is for a thread
// local allocation. Also does the
// initialized and finalizable checks.
cmpl LITERAL(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE), %eax
ja .Lslow_path\c_name
// Compute the rosalloc bracket index
// from the size.
shrq LITERAL(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT), %rax
// Load the rosalloc run (r9)
// Subtract __SIZEOF_POINTER__ to
// subtract one from edi as there is no
// 0 byte run and the size is already
// aligned.
movq (THREAD_ROSALLOC_RUNS_OFFSET - __SIZEOF_POINTER__)(%r8, %rax, __SIZEOF_POINTER__), %r9
// Load the free list head (rax). This
// will be the return val.
movq (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%r9), %rax
testq %rax, %rax
jz .Lslow_path\c_name
// "Point of no slow path". Won't go to the slow path from here on. OK to clobber rdi and rsi.
// Push the new object onto the thread
// local allocation stack and
// increment the thread local
// allocation stack top.
movl %eax, (%rcx)
addq LITERAL(COMPRESSED_REFERENCE_SIZE), %rcx
movq %rcx, THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET(%r8)
// Load the next pointer of the head
// and update the list head with the
// next pointer.
movq ROSALLOC_SLOT_NEXT_OFFSET(%rax), %rcx
movq %rcx, (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_HEAD_OFFSET)(%r9)
// Store the class pointer in the
// header. This also overwrites the
// next pointer. The offsets are
// asserted to match.
#if ROSALLOC_SLOT_NEXT_OFFSET != MIRROR_OBJECT_CLASS_OFFSET
#error "Class pointer needs to overwrite next pointer."
#endif
POISON_HEAP_REF edi
movl %edi, MIRROR_OBJECT_CLASS_OFFSET(%rax)
// Decrement the size of the free list
decl (ROSALLOC_RUN_FREE_LIST_OFFSET + ROSALLOC_RUN_FREE_LIST_SIZE_OFFSET)(%r9)
// No fence necessary for x86.
ret
.Lslow_path\c_name:
SETUP_SAVE_REFS_ONLY_FRAME // save ref containing registers for GC
// Outgoing argument set up
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
call CALLVAR(cxx_name) // cxx_name(arg0, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_OR_DEOPT_IF_RESULT_IS_NON_NULL_OR_DELIVER // return or deliver exception
END_FUNCTION VAR(c_name)
END_MACRO
// The common fast path code for art_quick_alloc_object_resolved_region_tlab.
// TODO: delete ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH since it is the same as
// ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH.
//
// RDI: the class, RAX: return value.
// RCX, RSI, RDX: scratch, r8: Thread::Current().
MACRO1(ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH, slowPathLabel)
ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH(RAW_VAR(slowPathLabel))
END_MACRO
// The fast path code for art_quick_alloc_object_initialized_region_tlab.
//
// RDI: the class, RSI: ArtMethod*, RAX: return value.
// RCX, RSI, RDX: scratch, r8: Thread::Current().
MACRO1(ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH, slowPathLabel)
movq %gs:THREAD_SELF_OFFSET, %r8 // r8 = thread
movl MIRROR_CLASS_OBJECT_SIZE_ALLOC_FAST_PATH_OFFSET(%rdi), %ecx // Load the object size.
movq THREAD_LOCAL_POS_OFFSET(%r8), %rax
addq %rax, %rcx // Add size to pos, note that these
// are both 32 bit ints, overflow
// will cause the add to be past the
// end of the thread local region.
cmpq THREAD_LOCAL_END_OFFSET(%r8), %rcx // Check if it fits.
ja RAW_VAR(slowPathLabel)
movq %rcx, THREAD_LOCAL_POS_OFFSET(%r8) // Update thread_local_pos.
// Store the class pointer in the
// header.
// No fence needed for x86.
POISON_HEAP_REF edi
movl %edi, MIRROR_OBJECT_CLASS_OFFSET(%rax)
ret // Fast path succeeded.
END_MACRO
// The fast path code for art_quick_alloc_array_region_tlab.
// Inputs: RDI: the class, RSI: int32_t component_count, R9: total_size
// Free temps: RCX, RDX, R8
// Output: RAX: return value.
MACRO1(ALLOC_ARRAY_TLAB_FAST_PATH_RESOLVED_WITH_SIZE, slowPathLabel)
movq %gs:THREAD_SELF_OFFSET, %rcx // rcx = thread
// Mask out the unaligned part to make sure we are 8 byte aligned.
andq LITERAL(OBJECT_ALIGNMENT_MASK_TOGGLED64), %r9
cmpq LITERAL(MIN_LARGE_OBJECT_THRESHOLD), %r9 // Possibly a large object.
jae RAW_VAR(slowPathLabel) // Go to slow path if large object
movq THREAD_LOCAL_POS_OFFSET(%rcx), %rax
addq %rax, %r9
cmpq THREAD_LOCAL_END_OFFSET(%rcx), %r9 // Check if it fits.
ja RAW_VAR(slowPathLabel)
movq %r9, THREAD_LOCAL_POS_OFFSET(%rcx) // Update thread_local_pos.
// Store the class pointer in the
// header.
// No fence needed for x86.
POISON_HEAP_REF edi
movl %edi, MIRROR_OBJECT_CLASS_OFFSET(%rax)
movl %esi, MIRROR_ARRAY_LENGTH_OFFSET(%rax)
ret // Fast path succeeded.
END_MACRO
// The common slow path code for art_quick_alloc_object_{resolved, initialized}_tlab
// and art_quick_alloc_object_{resolved, initialized}_region_tlab.
MACRO1(ALLOC_OBJECT_TLAB_SLOW_PATH, cxx_name)
SETUP_SAVE_REFS_ONLY_FRAME // save ref containing registers for GC
// Outgoing argument set up
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
call CALLVAR(cxx_name) // cxx_name(arg0, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_OR_DEOPT_IF_RESULT_IS_NON_NULL_OR_DELIVER // return or deliver exception
END_MACRO
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_tlab, TLAB). May be
// called with CC if the GC is not active.
DEFINE_FUNCTION art_quick_alloc_object_resolved_tlab
// RDI: mirror::Class* klass
// RDX, RSI, RCX, R8, R9: free. RAX: return val.
ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_tlab_slow_path
.Lart_quick_alloc_object_resolved_tlab_slow_path:
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeResolvedTLAB
END_FUNCTION art_quick_alloc_object_resolved_tlab
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_tlab, TLAB).
// May be called with CC if the GC is not active.
DEFINE_FUNCTION art_quick_alloc_object_initialized_tlab
// RDI: mirror::Class* klass
// RDX, RSI, RCX, R8, R9: free. RAX: return val.
ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH .Lart_quick_alloc_object_initialized_tlab_slow_path
.Lart_quick_alloc_object_initialized_tlab_slow_path:
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeInitializedTLAB
END_FUNCTION art_quick_alloc_object_initialized_tlab
MACRO0(COMPUTE_ARRAY_SIZE_UNKNOWN)
movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%rdi), %ecx // Load component type.
UNPOISON_HEAP_REF ecx
movl MIRROR_CLASS_OBJECT_PRIMITIVE_TYPE_OFFSET(%rcx), %ecx // Load primitive type.
shrq MACRO_LITERAL(PRIMITIVE_TYPE_SIZE_SHIFT_SHIFT), %rcx // Get component size shift.
movq %rsi, %r9
salq %cl, %r9 // Calculate array count shifted.
// Add array header + alignment rounding.
addq MACRO_LITERAL(MIRROR_INT_ARRAY_DATA_OFFSET + OBJECT_ALIGNMENT_MASK), %r9
// Add 4 extra bytes if we are doing a long array.
addq MACRO_LITERAL(1), %rcx
andq MACRO_LITERAL(4), %rcx
#if MIRROR_LONG_ARRAY_DATA_OFFSET != MIRROR_INT_ARRAY_DATA_OFFSET + 4
#error Long array data offset must be 4 greater than int array data offset.
#endif
addq %rcx, %r9
END_MACRO
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_RESOLVED(_region_tlab, RegionTLAB).
DEFINE_FUNCTION art_quick_alloc_object_resolved_region_tlab
// Fast path region tlab allocation.
// RDI: mirror::Class* klass
// RDX, RSI, RCX, R8, R9: free. RAX: return val.
ASSERT_USE_READ_BARRIER
ALLOC_OBJECT_RESOLVED_TLAB_FAST_PATH .Lart_quick_alloc_object_resolved_region_tlab_slow_path
.Lart_quick_alloc_object_resolved_region_tlab_slow_path:
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeResolvedRegionTLAB
END_FUNCTION art_quick_alloc_object_resolved_region_tlab
// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT_INITIALIZED(_region_tlab, RegionTLAB).
DEFINE_FUNCTION art_quick_alloc_object_initialized_region_tlab
// Fast path region tlab allocation.
// RDI: mirror::Class* klass
// RDX, RSI, RCX, R8, R9: free. RAX: return val.
ASSERT_USE_READ_BARRIER
// No read barrier since the caller is responsible for that.
ALLOC_OBJECT_INITIALIZED_TLAB_FAST_PATH .Lart_quick_alloc_object_initialized_region_tlab_slow_path
.Lart_quick_alloc_object_initialized_region_tlab_slow_path:
ALLOC_OBJECT_TLAB_SLOW_PATH artAllocObjectFromCodeInitializedRegionTLAB
END_FUNCTION art_quick_alloc_object_initialized_region_tlab
/* *Entryfrommanagedcodethatcalls`artUnlockObjectFromCode()` *anddeliversexceptiononfailure. *RDIholdsthepossiblynullobjecttounlock.
*/
DEFINE_FUNCTION art_quick_unlock_object_no_inline
// This is also the slow path for art_quick_unlock_object.
SETUP_SAVE_REFS_ONLY_FRAME
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
call SYMBOL(artUnlockObjectFromCode) // artUnlockObjectFromCode(object, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_OR_DEOPT_IF_INT_RESULT_IS_ZERO_OR_DELIVER
END_FUNCTION art_quick_unlock_object_no_inline
DEFINE_FUNCTION art_quick_check_instance_of
// Type check using the bit string passes null as the target class. In that case just throw.
testl %esi, %esi
jz .Lthrow_class_cast_exception_for_bitstring_check
// We could check the super classes here but that is usually already checked in the caller.
PUSH rdi // Save args for exc
PUSH rsi
subq LITERAL(8), %rsp // Alignment padding.
CFI_ADJUST_CFA_OFFSET(8)
SETUP_FP_CALLEE_SAVE_FRAME
call SYMBOL(artInstanceOfFromCode) // (Object* obj, Class* ref_klass)
CFI_REMEMBER_STATE
testq %rax, %rax
jz .Lthrow_class_cast_exception // jump forward if not assignable
RESTORE_FP_CALLEE_SAVE_FRAME
addq LITERAL(24), %rsp // pop arguments
CFI_ADJUST_CFA_OFFSET(-24)
ret
.Lthrow_class_cast_exception:
CFI_RESTORE_STATE_AND_DEF_CFA rsp, 64 // Reset unwind info so following code unwinds.
RESTORE_FP_CALLEE_SAVE_FRAME
addq LITERAL(8), %rsp // pop padding
CFI_ADJUST_CFA_OFFSET(-8)
POP rsi // Pop arguments
POP rdi
.Lthrow_class_cast_exception_for_bitstring_check:
SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context
mov %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
call SYMBOL(artThrowClassCastExceptionForObject) // (Object* src, Class* dest, Thread*)
movq %rax, %rdi // pass Context*
call SYMBOL(art_quick_do_long_jump)
UNREACHABLE
END_FUNCTION art_quick_check_instance_of
// Restore reg's value if reg is not the same as exclude_reg, otherwise just adjust stack.
MACRO2(POP_REG_NE, reg, exclude_reg)
.ifc RAW_VAR(reg), RAW_VAR(exclude_reg)
DECREASE_FRAME 8
.else
POP RAW_VAR(reg)
.endif
END_MACRO
DEFINE_FUNCTION art_quick_aput_obj
test %edx, %edx // store of null
jz .Laput_obj_null
movl MIRROR_OBJECT_CLASS_OFFSET(%rdi), %ecx
UNPOISON_HEAP_REF ecx
#ifdef USE_READ_BARRIER
cmpl LITERAL(0), %gs:THREAD_IS_GC_MARKING_OFFSET
CFI_REMEMBER_STATE
jnz .Laput_obj_gc_marking
#endif // USE_READ_BARRIER
movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%rcx), %ecx
cmpl MIRROR_OBJECT_CLASS_OFFSET(%rdx), %ecx // Both poisoned if heap poisoning is enabled.
jne .Laput_obj_check_assignability
.Laput_obj_store:
POISON_HEAP_REF edx
movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
movq %gs:THREAD_CARD_TABLE_OFFSET, %rdx
shrl LITERAL(CARD_TABLE_CARD_SHIFT), %edi
movb %dl, (%rdx, %rdi)
ret
.Laput_obj_null:
movl %edx, MIRROR_OBJECT_ARRAY_DATA_OFFSET(%rdi, %rsi, 4)
ret
.Laput_obj_throw_array_store_exception:
SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // Save all registers as basis for long jump context.
// Outgoing argument set up.
movq %rdx, %rsi // Pass arg 2 = value.
movq %gs:THREAD_SELF_OFFSET, %rdx // Pass arg 3 = Thread::Current().
// Pass arg 1 = array.
call SYMBOL(artThrowArrayStoreException) // (array, value, Thread*)
movq %rax, %rdi // pass Context*
call SYMBOL(art_quick_do_long_jump)
UNREACHABLE
#ifdef USE_READ_BARRIER
.Laput_obj_gc_marking:
CFI_RESTORE_STATE_AND_DEF_CFA rsp, 8
// We need to align stack for `art_quick_read_barrier_mark_regNN`.
INCREASE_FRAME 8 // Stack alignment.
call SYMBOL(art_quick_read_barrier_mark_reg01) // Mark ECX
movl MIRROR_CLASS_COMPONENT_TYPE_OFFSET(%rcx), %ecx
UNPOISON_HEAP_REF ecx
call SYMBOL(art_quick_read_barrier_mark_reg01) // Mark ECX
movl MIRROR_OBJECT_CLASS_OFFSET(%rdx), %eax
UNPOISON_HEAP_REF eax
call SYMBOL(art_quick_read_barrier_mark_reg00) // Mark EAX
DECREASE_FRAME 8 // Remove stack alignment.
cmpl %eax, %ecx
je .Laput_obj_store
// Prepare arguments in line with `.Laput_obj_check_assignability_call` and jump there.
PUSH_ARG rdi // Save arguments.
PUSH_ARG rsi
PUSH_ARG rdx
movl %eax, %esi // Pass arg2 - type of the value to be stored.
// The arg1 shall be moved at `.Ldo_assignability_check_call`.
jmp .Laput_obj_check_assignability_call
#endif // USE_READ_BARRIER
END_FUNCTION art_quick_aput_obj
// TODO: This is quite silly on X86_64 now.
DEFINE_FUNCTION art_quick_memcpy
call PLT_SYMBOL(memcpy) // (void*, const void*, size_t)
ret
END_FUNCTION art_quick_memcpy
DEFINE_FUNCTION art_quick_test_suspend
SETUP_SAVE_EVERYTHING_FRAME RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET // save everything for GC
// Outgoing argument set up
movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current()
call SYMBOL(artTestSuspendFromCode) // (Thread*)
movq %gs:THREAD_SELF_OFFSET, %rdx // Pass Thread::Current().
movq %rsp, %rcx // Pass SP.
call SYMBOL(artQuickProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
RESTORE_SAVE_REFS_AND_ARGS_FRAME
movq %rax, %xmm0 // Copy return value in case of float returns.
RETURN_OR_DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_proxy_invoke_handler
/* *Calledtoresolveanimtconflict. *rdiistheconflictArtMethod. *raxisahiddenargumentthatholdsthetargetinterfacemethod. * *Notethatthisstubwritestordi.
*/
DEFINE_FUNCTION art_quick_imt_conflict_trampoline
#if defined(__APPLE__)
int3
int3
#else
movq ART_METHOD_JNI_OFFSET_64(%rdi), %rdi // Load ImtConflictTable
.Limt_table_iterate:
cmpq %rax, 0(%rdi)
jne .Limt_table_next_entry
// We successfully hit an entry in the table. Load the target method
// and jump to it.
movq __SIZEOF_POINTER__(%rdi), %rdi
jmp *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi)
.Limt_table_next_entry:
// If the entry is null, the interface method is not in the ImtConflictTable.
cmpq LITERAL(0), 0(%rdi)
jz .Lconflict_trampoline
// Iterate over the entries of the ImtConflictTable.
addq LITERAL(2 * __SIZEOF_POINTER__), %rdi
jmp .Limt_table_iterate
.Lconflict_trampoline:
// Call the runtime stub to populate the ImtConflictTable and jump to the
// resolved method.
movq %rax, %rdi // Load interface method
INVOKE_TRAMPOLINE_BODY artInvokeInterfaceTrampoline
#endif // __APPLE__
END_FUNCTION art_quick_imt_conflict_trampoline
DEFINE_FUNCTION art_quick_resolution_trampoline
SETUP_SAVE_REFS_AND_ARGS_FRAME
movq %gs:THREAD_SELF_OFFSET, %rdx
movq %rsp, %rcx
call SYMBOL(artQuickResolutionTrampoline) // (called, receiver, Thread*, SP)
movq %rax, %r10 // Remember returned code pointer in R10.
movq (%rsp), %rdi // Load called method into RDI.
RESTORE_SAVE_REFS_AND_ARGS_FRAME
testq %r10, %r10 // If code pointer is null goto deliver pending exception.
jz 1f
jmp *%r10 // Tail call into method. 1:
DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_resolution_trampoline
// The C call will have registered the complete save-frame on success.
// The result of the call is:
// %rax: pointer to native code, 0 on error.
// The bottom of the reserved area contains values for arg registers,
// hidden arg register and SP for out args for the call.
// Check for error (class init check or locking for synchronized native method can throw).
test %rax, %rax
jz .Lexception_in_native
// pop from the register-passing alloca region
// what's the right layout?
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %r8
popq %r9
// TODO: skip floating point if unused, some flag.
movq 0(%rsp), %xmm0
movq 8(%rsp), %xmm1
movq 16(%rsp), %xmm2
movq 24(%rsp), %xmm3
movq 32(%rsp), %xmm4
movq 40(%rsp), %xmm5
movq 48(%rsp), %xmm6
movq 56(%rsp), %xmm7
// Save call target in scratch register.
movq %rax, %r11
// Load hidden arg (rax) for @CriticalNative.
movq 64(%rsp), %rax
// Load SP for out args, releasing unneeded reserved area.
movq 72(%rsp), %rsp
// native call
call *%r11
// result sign extension is handled in C code
// prepare for artQuickGenericJniEndTrampoline call
// (Thread*, result, result_f)
// rdi rsi rdx <= C calling convention
// gs:... rax xmm0 <= where they are
movq %gs:THREAD_SELF_OFFSET, %rdi
movq %rax, %rsi
movq %xmm0, %rdx
call SYMBOL(artQuickGenericJniEndTrampoline)
// Pending exceptions possible.
// TODO: use cmpq, needs direct encoding because of gas bug
movq %gs:THREAD_EXCEPTION_OFFSET, %rcx
test %rcx, %rcx
jnz .Lexception_in_native
// Tear down the alloca.
movq %rbp, %rsp
// store into fpr, for when it's a fpr return...
movq %rax, %xmm0
DEFINE_FUNCTION art_deliver_pending_exception
// This will create a new save-all frame, required by the runtime.
DELIVER_PENDING_EXCEPTION
END_FUNCTION art_deliver_pending_exception
/* *CalledtobridgefromthequicktointerpreterABI.Onentrytheargumentsmatchthose *ofaquickcall: *RDI=methodbeingcalled/tobridgeto. *RSI,RDX,RCX,R8,R9areargumentstothatmethod.
*/
DEFINE_FUNCTION art_quick_to_interpreter_bridge
SETUP_SAVE_REFS_AND_ARGS_FRAME // Set up frame and save arguments.
movq %gs:THREAD_SELF_OFFSET, %rsi // RSI := Thread::Current()
movq %rsp, %rdx // RDX := sp
call SYMBOL(artQuickToInterpreterBridge) // (method, Thread*, SP)
RESTORE_SAVE_REFS_AND_ARGS_FRAME // TODO: no need to restore arguments in this case.
movq %rax, %xmm0 // Place return value also into floating point return value.
RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
END_FUNCTION art_quick_to_interpreter_bridge
DEFINE_FUNCTION art_quick_string_builder_append
SETUP_SAVE_REFS_ONLY_FRAME // save ref containing registers for GC
// Outgoing argument set up
leaq FRAME_SIZE_SAVE_REFS_ONLY + __SIZEOF_POINTER__(%rsp), %rsi // pass args
movq %gs:THREAD_SELF_OFFSET, %rdx // pass Thread::Current()
call artStringBuilderAppend // (uint32_t, const unit32_t*, Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME // restore frame up to return address
RETURN_OR_DEOPT_IF_RESULT_IS_NON_NULL_OR_DELIVER // return or deopt or deliver exception
END_FUNCTION art_quick_string_builder_append
// Create a function `name` calling the ReadBarrier::Mark routine,
// getting its argument and returning its result through register
// `reg`, saving and restoring all caller-save registers.
//
// The generated function follows a non-standard runtime calling
// convention:
// - register `reg` (which may be different from RDI) is used to pass the (sole) argument,
// - register `reg` (which may be different from RAX) is used to return the result,
// - all other registers are callee-save (the values they hold are preserved).
MACRO2(READ_BARRIER_MARK_REG, name, reg)
DEFINE_FUNCTION VAR(name)
// Null check so that we can load the lock word.
testq REG_VAR(reg), REG_VAR(reg)
jz .Lret_rb_\name
.Lnot_null_\name:
// Check the mark bit, if it is 1 return.
testl LITERAL(LOCK_WORD_MARK_BIT_MASK_SHIFTED), MIRROR_OBJECT_LOCK_WORD_OFFSET(REG_VAR(reg))
jz .Lslow_rb_\name
ret
.Lslow_rb_\name:
PUSH rax
movl MIRROR_OBJECT_LOCK_WORD_OFFSET(REG_VAR(reg)), %eax
addl LITERAL(LOCK_WORD_STATE_FORWARDING_ADDRESS_OVERFLOW), %eax
// Jump if the addl caused eax to unsigned overflow. The only case where it overflows is the
// forwarding address one.
// Taken ~25% of the time.
CFI_REMEMBER_STATE
jnae .Lret_forwarding_address\name
pushq LITERAL(0) // Push null for ArtMethod*.
CFI_ADJUST_CFA_OFFSET(8)
movl %esi, %ecx // rcx := size of stack
movq %rdi, %rsi // rsi := stack to copy
movq %rsp, %rbp // Save stack pointer to RBP for CFI use in .Losr_entry.
CFI_REMEMBER_STATE
call .Losr_entry
// Restore stack and callee-saves.
addq LITERAL(8), %rsp
CFI_ADJUST_CFA_OFFSET(-8)
POP r15
POP r14
POP r13
POP r12
POP rbx
POP r8
POP rcx
POP rbp
movq %rax, (%rcx) // Store the result.
ret
.Losr_entry:
CFI_RESTORE_STATE_AND_DEF_CFA rsp, 80
// Since the call has pushed the return address we need to switch the CFA register to RBP.
CFI_DEF_CFA_REGISTER(rbp)
subl LITERAL(8), %ecx // Given stack size contains pushed frame pointer, substract it.
subq %rcx, %rsp
movq %rsp, %rdi // rdi := beginning of stack
rep movsb // while (rcx--) { *rdi++ = *rsi++ }
jmp *%rdx
END_FUNCTION art_quick_osr_stub
DEFINE_FUNCTION art_quick_invoke_polymorphic
// On entry: RDI := unused, RSI := receiver
SETUP_SAVE_REFS_AND_ARGS_FRAME // save callee saves
movq %rsi, %rdi // RDI := receiver
movq %gs:THREAD_SELF_OFFSET, %rsi // RSI := Thread (self)
movq %rsp, %rdx // RDX := pass SP
call SYMBOL(artInvokePolymorphic) // invoke with (receiver, self, SP)
// save the code pointer
RESTORE_SAVE_REFS_AND_ARGS_FRAME
movq %rax, %xmm0 // Result is in RAX. Copy to FP result register.
RETURN_OR_DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_invoke_polymorphic
/* *SlowpathforMethodHandle.invokeExactintrinsic. *Thatintrinsichasacustomcallingconvention:theargumentallocationdoesn'tstartfrom *thereceiver(MethodHandle)object,butfromtheargumentfollowingit.That'sdonetomatch *expectationoftheunderlyingmethodwhenMethodHandletargetsamethod.Thatalsoaffects *thewayargumentsarespilledontothestack.
*/
DEFINE_FUNCTION art_quick_invoke_polymorphic_with_hidden_receiver
// On entry: RDI := receiver
SETUP_SAVE_REFS_AND_ARGS_FRAME // save callee saves
movq %gs:THREAD_SELF_OFFSET, %rsi // RSI := Thread (self)
movq %rsp, %rdx // RDX := pass SP
call SYMBOL(artInvokePolymorphicWithHiddenReceiver) // invoke with (receiver, self, SP)
// save the code pointer
RESTORE_SAVE_REFS_AND_ARGS_FRAME
movq %rax, %xmm0 // Result is in RAX. Copy to FP result register.
RETURN_OR_DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_invoke_polymorphic_with_hidden_receiver
DEFINE_FUNCTION art_quick_invoke_custom
SETUP_SAVE_REFS_AND_ARGS_FRAME // save callee saves
// RDI := call_site_index
movq %gs:THREAD_SELF_OFFSET, %rsi // RSI := Thread::Current()
movq %rsp, %rdx // RDX := SP
call SYMBOL(artInvokeCustom) // artInvokeCustom(Thread*, SP)
RESTORE_SAVE_REFS_AND_ARGS_FRAME
movq %rax, %xmm0 // Result is in RAX. Copy to FP result register.
RETURN_OR_DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_invoke_custom
// On entry: edi is the class, r11 is the inline cache. r10 and rax are available.
DEFINE_FUNCTION art_quick_update_inline_cache
#if (INLINE_CACHE_SIZE != 5)
#error "INLINE_CACHE_SIZE not as expected."
#endif
// Don't update the cache if we are marking.
cmpl LITERAL(0), %gs:THREAD_IS_GC_MARKING_OFFSET
jnz .Ldone
.Lentry1:
movl INLINE_CACHE_CLASSES_OFFSET(%r11), %eax
cmpl %edi, %eax
je .Ldone
cmpl LITERAL(0), %eax
jne .Lentry2
lock cmpxchg %edi, INLINE_CACHE_CLASSES_OFFSET(%r11)
jz .Ldone
jmp .Lentry1
.Lentry2:
movl (INLINE_CACHE_CLASSES_OFFSET+4)(%r11), %eax
cmpl %edi, %eax
je .Ldone
cmpl LITERAL(0), %eax
jne .Lentry3
lock cmpxchg %edi, (INLINE_CACHE_CLASSES_OFFSET+4)(%r11)
jz .Ldone
jmp .Lentry2
.Lentry3:
movl (INLINE_CACHE_CLASSES_OFFSET+8)(%r11), %eax
cmpl %edi, %eax
je .Ldone
cmpl LITERAL(0), %eax
jne .Lentry4
lock cmpxchg %edi, (INLINE_CACHE_CLASSES_OFFSET+8)(%r11)
jz .Ldone
jmp .Lentry3
.Lentry4:
movl (INLINE_CACHE_CLASSES_OFFSET+12)(%r11), %eax
cmpl %edi, %eax
je .Ldone
cmpl LITERAL(0), %eax
jne .Lentry5
lock cmpxchg %edi, (INLINE_CACHE_CLASSES_OFFSET+12)(%r11)
jz .Ldone
jmp .Lentry4
.Lentry5:
// Unconditionally store, the cache is megamorphic.
movl %edi, (INLINE_CACHE_CLASSES_OFFSET+16)(%r11)
.Ldone:
ret
END_FUNCTION art_quick_update_inline_cache
// On entry, method is at the bottom of the stack.
DEFINE_FUNCTION art_quick_compile_optimized
SETUP_SAVE_EVERYTHING_FRAME
movq FRAME_SIZE_SAVE_EVERYTHING(%rsp), %rdi // pass ArtMethod
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
call SYMBOL(artCompileOptimized) // (ArtMethod*, Thread*)
RESTORE_SAVE_EVERYTHING_FRAME // restore frame up to return address
ret
END_FUNCTION art_quick_compile_optimized
// On entry, method is at the bottom of the stack.
DEFINE_FUNCTION art_quick_compile_baseline
SETUP_SAVE_EVERYTHING_FRAME
movq FRAME_SIZE_SAVE_EVERYTHING(%rsp), %rdi // pass ArtMethod
movq %gs:THREAD_SELF_OFFSET, %rsi // pass Thread::Current()
call SYMBOL(artCompileBaseline) // (ArtMethod*, Thread*)
RESTORE_SAVE_EVERYTHING_FRAME // restore frame up to return address
ret
END_FUNCTION art_quick_compile_baseline
// On entry, method is at the bottom of the stack.
DEFINE_FUNCTION art_quick_method_entry_hook
SETUP_SAVE_EVERYTHING_FRAME
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.