492 lines
17 KiB
ArmAsm
492 lines
17 KiB
ArmAsm
/*
|
|
* Copyright (C) 2012 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "asm_support_x86_64.S"
|
|
|
|
#define MANAGED_ARGS_SAVE_SIZE /*xmm0-xmm7*/ 8 * 8 + /*padding*/ 8 + /* GPR args */ 6 * 8
|
|
|
|
MACRO0(SAVE_MANAGED_ARGS_INCREASE_FRAME)
|
|
// Return address is on the stack.
|
|
PUSH_ARG r9
|
|
PUSH_ARG r8
|
|
PUSH_ARG rcx
|
|
PUSH_ARG rdx
|
|
PUSH_ARG rsi
|
|
PUSH_ARG rdi
|
|
INCREASE_FRAME (/*FPRs*/ 8 * 8 + /*padding*/ 8)
|
|
movsd %xmm0, 0(%rsp)
|
|
movsd %xmm1, 8(%rsp)
|
|
movsd %xmm2, 16(%rsp)
|
|
movsd %xmm3, 24(%rsp)
|
|
movsd %xmm4, 32(%rsp)
|
|
movsd %xmm5, 40(%rsp)
|
|
movsd %xmm6, 48(%rsp)
|
|
movsd %xmm7, 56(%rsp)
|
|
END_MACRO
|
|
|
|
MACRO0(RESTORE_MANAGED_ARGS_DECREASE_FRAME)
|
|
movsd 0(%rsp), %xmm0
|
|
movsd 8(%rsp), %xmm1
|
|
movsd 16(%rsp), %xmm2
|
|
movsd 24(%rsp), %xmm3
|
|
movsd 32(%rsp), %xmm4
|
|
movsd 40(%rsp), %xmm5
|
|
movsd 48(%rsp), %xmm6
|
|
movsd 56(%rsp), %xmm7
|
|
DECREASE_FRAME (/*FPRs*/ 8 * 8 + /*padding*/ 8)
|
|
POP_ARG rdi
|
|
POP_ARG rsi
|
|
POP_ARG rdx
|
|
POP_ARG rcx
|
|
POP_ARG r8
|
|
POP_ARG r9
|
|
END_MACRO
|
|
|
|
MACRO3(JNI_SAVE_MANAGED_ARGS_TRAMPOLINE, name, cxx_name, arg1)
|
|
DEFINE_FUNCTION \name
|
|
// Note: Managed callee-save registers have been saved by the JNI stub.
|
|
// Save register args RDI, RSI, RDX, RCX, R8, R9, mmx0-mmx7 and align stack.
|
|
SAVE_MANAGED_ARGS_INCREASE_FRAME
|
|
// Call `cxx_name()`.
|
|
.ifnc \arg1, none
|
|
mov REG_VAR(arg1), %rdi // Pass arg1.
|
|
.endif
|
|
call CALLVAR(cxx_name) // Call cxx_name(...).
|
|
// Restore register args RDI, RSI, RDX, RCX, R8, R9, mmx0-mmx7 and return.
|
|
RESTORE_MANAGED_ARGS_DECREASE_FRAME
|
|
ret
|
|
END_FUNCTION \name
|
|
END_MACRO
|
|
|
|
MACRO4(JNI_SAVE_RETURN_VALUE_TRAMPOLINE, name, cxx_name, arg1, arg2)
|
|
DEFINE_FUNCTION \name
|
|
// Save return registers and return address.
|
|
PUSH_ARG rax
|
|
INCREASE_FRAME /*mmx0*/ 8 + /*padding*/ 8
|
|
movsd %xmm0, 0(%rsp)
|
|
// Call `cxx_name()`.
|
|
mov REG_VAR(arg1), %rdi // Pass arg1.
|
|
.ifnc \arg2, none
|
|
mov REG_VAR(arg2), %rsi // Pass arg2.
|
|
.endif
|
|
call CALLVAR(cxx_name) // Call cxx_name(...).
|
|
// Restore return registers and return.
|
|
movsd 0(%rsp), %xmm0
|
|
DECREASE_FRAME /*mmx0*/ 8 + /*padding*/ 8
|
|
POP_ARG rax
|
|
ret
|
|
END_FUNCTION \name
|
|
END_MACRO
|
|
|
|
/*
|
|
* Jni dlsym lookup stub.
|
|
*/
|
|
DEFINE_FUNCTION art_jni_dlsym_lookup_stub
|
|
// Save callee and GPR args.
|
|
PUSH_ARG r9 // Arg.
|
|
PUSH_ARG r8 // Arg.
|
|
PUSH_ARG rdi // Arg. (JniEnv for normal and @FastNative)
|
|
PUSH_ARG rsi // Arg.
|
|
PUSH_ARG rdx // Arg.
|
|
PUSH_ARG rcx // Arg.
|
|
// Create space for FPR args, plus padding for alignment
|
|
INCREASE_FRAME 72
|
|
// Save FPRs.
|
|
movq %xmm0, 0(%rsp)
|
|
movq %xmm1, 8(%rsp)
|
|
movq %xmm2, 16(%rsp)
|
|
movq %xmm3, 24(%rsp)
|
|
movq %xmm4, 32(%rsp)
|
|
movq %xmm5, 40(%rsp)
|
|
movq %xmm6, 48(%rsp)
|
|
movq %xmm7, 56(%rsp)
|
|
// prepare call
|
|
movq %gs:THREAD_SELF_OFFSET, %rdi // RDI := Thread::Current()
|
|
// Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable()
|
|
// for @FastNative or @CriticalNative.
|
|
movq THREAD_TOP_QUICK_FRAME_OFFSET(%rdi), %rax // uintptr_t tagged_quick_frame
|
|
andq LITERAL(0xfffffffffffffffe), %rax // ArtMethod** sp
|
|
movq (%rax), %rax // ArtMethod* method
|
|
testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \
|
|
ART_METHOD_ACCESS_FLAGS_OFFSET(%rax)
|
|
jne .Llookup_stub_fast_or_critical_native
|
|
call SYMBOL(artFindNativeMethod) // (Thread*)
|
|
jmp .Llookup_stub_continue
|
|
.Llookup_stub_fast_or_critical_native:
|
|
call SYMBOL(artFindNativeMethodRunnable) // (Thread*)
|
|
.Llookup_stub_continue:
|
|
// restore arguments
|
|
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
|
|
DECREASE_FRAME 72
|
|
POP_ARG rcx // Arg.
|
|
POP_ARG rdx // Arg.
|
|
POP_ARG rsi // Arg.
|
|
POP_ARG rdi // Arg. (JniEnv for normal and @FastNative)
|
|
POP_ARG r8 // Arg.
|
|
POP_ARG r9 // Arg.
|
|
testq %rax, %rax // check if returned method code is null
|
|
jz .Lno_native_code_found // if null, jump to return to handle
|
|
jmp *%rax // otherwise, tail call to intended method
|
|
.Lno_native_code_found:
|
|
ret
|
|
END_FUNCTION art_jni_dlsym_lookup_stub
|
|
|
|
/*
|
|
* Jni dlsym lookup stub for @CriticalNative.
|
|
*/
|
|
DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub
|
|
// The hidden arg holding the tagged method (bit 0 set means GenericJNI) is RAX.
|
|
// For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub.
|
|
testq LITERAL(1), %rax
|
|
jnz art_jni_dlsym_lookup_stub
|
|
|
|
// Save GPR args and method.
|
|
PUSH_ARG r9
|
|
PUSH_ARG r8
|
|
PUSH_ARG rdi
|
|
PUSH_ARG rsi
|
|
PUSH_ARG rdx
|
|
PUSH_ARG rcx
|
|
PUSH_ARG rax
|
|
// Create space for FPR args.
|
|
INCREASE_FRAME 8 * 8
|
|
// Save FPRs.
|
|
movq %xmm0, 0(%rsp)
|
|
movq %xmm1, 8(%rsp)
|
|
movq %xmm2, 16(%rsp)
|
|
movq %xmm3, 24(%rsp)
|
|
movq %xmm4, 32(%rsp)
|
|
movq %xmm5, 40(%rsp)
|
|
movq %xmm6, 48(%rsp)
|
|
movq %xmm7, 56(%rsp)
|
|
// Note: It's the caller's responsibility to preserve xmm12-xmm15 as the tail call
|
|
// to native shall always risk clobbering those.
|
|
|
|
// Call artCriticalNativeFrameSize(method, caller_pc).
|
|
movq %rax, %rdi // Pass the method from hidden arg.
|
|
movq 120(%rsp), %rsi // Pass caller PC.
|
|
call SYMBOL(artCriticalNativeFrameSize)
|
|
|
|
// Restore registers.
|
|
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
|
|
DECREASE_FRAME 8 * 8
|
|
POP_ARG r10 // Restore method to R10.
|
|
POP_ARG rcx
|
|
POP_ARG rdx
|
|
POP_ARG rsi
|
|
POP_ARG rdi
|
|
POP_ARG r8
|
|
POP_ARG r9
|
|
|
|
// Load caller PC to R11 and redefine return PC for CFI.
|
|
movq (%rsp), %r11
|
|
CFI_REGISTER(%rip, %r11)
|
|
|
|
// 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 QWORDs to move.
|
|
shrq LITERAL(3), %rax
|
|
jz .Lcritical_skip_copy_args
|
|
|
|
// Save RDI, RSI, RCX so that we can use them for moving stack args.
|
|
PUSH_ARG rdi
|
|
PUSH_ARG rsi
|
|
PUSH_ARG rcx
|
|
|
|
// Move the stack args.
|
|
movq %rax, %rcx
|
|
leaq 3 * __SIZEOF_POINTER__(%rsp), %rdi
|
|
leaq FRAME_SIZE_SAVE_REFS_AND_ARGS(%rdi), %rsi
|
|
rep movsq
|
|
|
|
// Restore RDI, RSI, RCX.
|
|
POP_ARG rcx
|
|
POP_ARG rsi
|
|
POP_ARG rdi
|
|
|
|
.Lcritical_skip_copy_args:
|
|
// Calculate the base address of the managed frame.
|
|
leaq (%rsp, %rax, 8), %rax
|
|
|
|
// 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. Do not update CFI while we hold the frame address in RAX and the values
|
|
// in registers are unchanged.
|
|
movq %r15, 192(%rax)
|
|
movq %r14, 184(%rax)
|
|
movq %r13, 176(%rax)
|
|
movq %r12, 168(%rax)
|
|
movq %r9, 160(%rax)
|
|
movq %r8, 152(%rax)
|
|
movq %rsi, 144(%rax)
|
|
movq %rbp, 136(%rax)
|
|
movq %rbx, 128(%rax)
|
|
movq %rdx, 120(%rax)
|
|
movq %rcx, 112(%rax)
|
|
movq %xmm0, 16(%rax)
|
|
movq %xmm1, 24(%rax)
|
|
movq %xmm2, 32(%rax)
|
|
movq %xmm3, 40(%rax)
|
|
movq %xmm4, 48(%rax)
|
|
movq %xmm5, 56(%rax)
|
|
movq %xmm6, 64(%rax)
|
|
movq %xmm7, 72(%rax)
|
|
// Skip managed ABI callee-saves xmm12-xmm15.
|
|
|
|
// Move the managed frame address to native callee-save register RBP and update CFI.
|
|
movq %rax, %rbp
|
|
CFI_EXPRESSION_BREG CFI_REG(r15), CFI_REG(rbp), 192
|
|
CFI_EXPRESSION_BREG CFI_REG(r14), CFI_REG(rbp), 184
|
|
CFI_EXPRESSION_BREG CFI_REG(r13), CFI_REG(rbp), 176
|
|
CFI_EXPRESSION_BREG CFI_REG(r12), CFI_REG(rbp), 168
|
|
// Skip args r9, r8, rsi.
|
|
CFI_EXPRESSION_BREG CFI_REG(rbp), CFI_REG(rbp), 136
|
|
CFI_EXPRESSION_BREG CFI_REG(rbx), CFI_REG(rbp), 128
|
|
// Skip args rdx, rcx.
|
|
// Skip args xmm0-xmm7.
|
|
|
|
leaq 1(%rbp), %rax // Prepare managed SP tagged for a GenericJNI frame.
|
|
testl LITERAL(ACCESS_FLAGS_METHOD_IS_NATIVE), ART_METHOD_ACCESS_FLAGS_OFFSET(%r10)
|
|
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.)
|
|
movq %r11, FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%rbp)
|
|
|
|
// Replace the target method with the SaveRefsAndArgs runtime method.
|
|
LOAD_RUNTIME_INSTANCE r10
|
|
movq RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET(%r10), %r10
|
|
|
|
movq %rbp, %rax // Prepare untagged managed SP for the runtime method.
|
|
|
|
.Lcritical_skip_prepare_runtime_method:
|
|
// Store the method on the bottom of the managed frame.
|
|
movq %r10, (%rbp)
|
|
|
|
// Place (maybe tagged) managed SP in Thread::Current()->top_quick_frame.
|
|
movq %rax, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
|
|
|
|
// Save our return PC in the padding.
|
|
movq %r11, __SIZEOF_POINTER__(%rbp)
|
|
CFI_EXPRESSION_BREG CFI_REG(rip), CFI_REG(rbp), __SIZEOF_POINTER__
|
|
|
|
// Preserve the native arg register RDI in callee-save register RBX which was saved above.
|
|
movq %rdi, %rbx
|
|
|
|
// Call artFindNativeMethodRunnable()
|
|
movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current()
|
|
call SYMBOL(artFindNativeMethodRunnable) // (Thread*)
|
|
|
|
// Check for exception.
|
|
test %rax, %rax
|
|
jz .Lcritical_deliver_exception
|
|
|
|
CFI_REMEMBER_STATE
|
|
|
|
// Restore the native arg register RDI.
|
|
movq %rbx, %rdi
|
|
|
|
// Remember our return PC in R11.
|
|
movq __SIZEOF_POINTER__(%rbp), %r11
|
|
CFI_REGISTER(%rip, %r11)
|
|
|
|
// Remember the frame base address in r10 but do not redefine CFI.
|
|
movq %rbp, %r10
|
|
|
|
// Restore the frame. We shall not need the method anymore.
|
|
movq 16(%rbp), %xmm0
|
|
movq 24(%rbp), %xmm1
|
|
movq 32(%rbp), %xmm2
|
|
movq 40(%rbp), %xmm3
|
|
movq 48(%rbp), %xmm4
|
|
movq 56(%rbp), %xmm5
|
|
movq 64(%rbp), %xmm6
|
|
movq 72(%rbp), %xmm7
|
|
// Skip managed callee-saves xmm12-xmm15.
|
|
movq 112(%rbp), %rcx
|
|
movq 120(%rbp), %rdx
|
|
RESTORE_REG_BASE rbp, rbx, 128
|
|
// Delay restoring RBP as it's the managed frame base.
|
|
movq 144(%rbp), %rsi
|
|
movq 152(%rbp), %r8
|
|
movq 160(%rbp), %r9
|
|
RESTORE_REG_BASE rbp, r12, 168
|
|
RESTORE_REG_BASE rbp, r13, 176
|
|
RESTORE_REG_BASE rbp, r14, 184
|
|
RESTORE_REG_BASE rbp, r15, 192
|
|
// Restore RBP last.
|
|
RESTORE_REG_BASE rbp, rbp, 136
|
|
|
|
cmp %r10, %rsp
|
|
je .Lcritical_skip_copy_args_back
|
|
|
|
// Save RDI, RSI, RCX so that we can use them for moving stack args.
|
|
PUSH_ARG rdi
|
|
PUSH_ARG rsi
|
|
PUSH_ARG rcx
|
|
|
|
// Calculate the number of QWORDs to move.
|
|
leaq -3 * __SIZEOF_POINTER__(%r10), %rcx
|
|
subq %rsp, %rcx
|
|
shrq LITERAL(3), %rcx
|
|
|
|
// Move the stack args.
|
|
leaq -__SIZEOF_POINTER__(%r10), %rsi
|
|
leaq FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%r10), %rdi
|
|
std
|
|
rep movsq
|
|
cld
|
|
|
|
// Restore RDI, RSI, RCX.
|
|
POP_ARG rcx
|
|
POP_ARG rsi
|
|
POP_ARG rdi
|
|
|
|
.Lcritical_skip_copy_args_back:
|
|
// Remove the frame reservation.
|
|
DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__
|
|
|
|
// Store our return PC.
|
|
movq %r11, (%rsp)
|
|
CFI_REL_OFFSET(%rip, 0)
|
|
|
|
// Do the tail call.
|
|
jmp *%rax
|
|
CFI_RESTORE_STATE_AND_DEF_CFA %rbp, FRAME_SIZE_SAVE_REFS_AND_ARGS
|
|
|
|
.Lcritical_deliver_exception:
|
|
DELIVER_PENDING_EXCEPTION_FRAME_READY
|
|
END_FUNCTION art_jni_dlsym_lookup_critical_stub
|
|
|
|
/*
|
|
* Read barrier for the method's declaring class needed by JNI stub for static methods.
|
|
* (We're using a pointer to the declaring class in `ArtMethod` as `jclass`.)
|
|
*/
|
|
JNI_SAVE_MANAGED_ARGS_TRAMPOLINE art_jni_read_barrier, artJniReadBarrier, none
|
|
|
|
/*
|
|
* Trampoline to `artJniMethodStart()` that preserves all managed arguments.
|
|
*/
|
|
JNI_SAVE_MANAGED_ARGS_TRAMPOLINE art_jni_method_start, artJniMethodStart, gs:THREAD_SELF_OFFSET
|
|
|
|
/*
|
|
* Trampoline to `artJniMonitoredMethodStart()` that preserves all managed arguments.
|
|
*/
|
|
JNI_SAVE_MANAGED_ARGS_TRAMPOLINE \
|
|
art_jni_monitored_method_start, artJniMonitoredMethodStart, gs:THREAD_SELF_OFFSET
|
|
|
|
/*
|
|
* Trampoline to `artJniMethodEnd()` that preserves all return registers.
|
|
*/
|
|
JNI_SAVE_RETURN_VALUE_TRAMPOLINE art_jni_method_end, artJniMethodEnd, gs:THREAD_SELF_OFFSET, none
|
|
|
|
/*
|
|
* Trampoline to `artJniMonitoredMethodEnd()` that preserves all return registers.
|
|
*/
|
|
JNI_SAVE_RETURN_VALUE_TRAMPOLINE \
|
|
art_jni_monitored_method_end, artJniMonitoredMethodEnd, gs:THREAD_SELF_OFFSET, none
|
|
|
|
/*
|
|
* Entry from JNI stub that tries to lock the object in a fast path and
|
|
* calls `artLockObjectFromCode()` (the same as for managed code) for the
|
|
* difficult cases, may block for GC.
|
|
* Custom calling convention:
|
|
* RBX holds the non-null object to lock.
|
|
* Callee-save registers have been saved and can be used as temporaries (except RBX).
|
|
* All argument registers need to be preserved.
|
|
*/
|
|
DEFINE_FUNCTION art_jni_lock_object
|
|
LOCK_OBJECT_FAST_PATH rbx, ebp, art_jni_lock_object_no_inline
|
|
END_FUNCTION art_jni_lock_object
|
|
|
|
/*
|
|
* Entry from JNI stub that calls `artLockObjectFromCode()`
|
|
* (the same as for managed code), may block for GC.
|
|
* Custom calling convention:
|
|
* RBX holds the non-null object to lock.
|
|
* Callee-save registers have been saved and can be used as temporaries (except RBX).
|
|
* All argument registers need to be preserved.
|
|
*/
|
|
DEFINE_FUNCTION art_jni_lock_object_no_inline
|
|
// This is also the slow path for art_jni_lock_object.
|
|
// Save register args RDI, RSI, RDX, RCX, R8, R9, mmx0-mmx7 and align stack.
|
|
SAVE_MANAGED_ARGS_INCREASE_FRAME
|
|
// Call `artLockObjectFromCode()`
|
|
movq %rbx, %rdi // Pass the object to lock.
|
|
movq %gs:THREAD_SELF_OFFSET, %rsi // Pass Thread::Current().
|
|
call SYMBOL(artLockObjectFromCode) // (object, Thread*)
|
|
// Check result.
|
|
testl %eax, %eax
|
|
jnz 1f
|
|
// Restore register args RDI, RSI, RDX, RCX, R8, R9, mmx0-mmx7 and return.
|
|
RESTORE_MANAGED_ARGS_DECREASE_FRAME
|
|
ret
|
|
.cfi_adjust_cfa_offset MANAGED_ARGS_SAVE_SIZE
|
|
1:
|
|
// All args are irrelevant when throwing an exception. Remove the spill area.
|
|
DECREASE_FRAME MANAGED_ARGS_SAVE_SIZE
|
|
// Rely on the JNI transition frame constructed in the JNI stub.
|
|
movq %gs:THREAD_SELF_OFFSET, %rdi // Pass Thread::Current().
|
|
jmp SYMBOL(artDeliverPendingExceptionFromCode) // (Thread*); tail call.
|
|
END_FUNCTION art_jni_lock_object_no_inline
|
|
|
|
/*
|
|
* Entry from JNI stub that tries to unlock the object in a fast path and calls
|
|
* `artJniUnlockObject()` for the difficult cases. Note that failure to unlock
|
|
* is fatal, so we do not need to check for exceptions in the slow path.
|
|
* Custom calling convention:
|
|
* RBX holds the non-null object to unlock.
|
|
* Callee-save registers have been saved and can be used as temporaries (except RBX).
|
|
* Return registers RAX and mmx0 need to be preserved.
|
|
*/
|
|
DEFINE_FUNCTION art_jni_unlock_object
|
|
movq %rax, %r12 // Preserve RAX in a different register.
|
|
UNLOCK_OBJECT_FAST_PATH rbx, ebp, /*saved_rax*/ r12, .Lunlock_object_jni_slow
|
|
|
|
.Lunlock_object_jni_slow:
|
|
movq %r12, %rax // Restore RAX.
|
|
jmp SYMBOL(art_jni_unlock_object_no_inline)
|
|
END_FUNCTION art_jni_unlock_object
|
|
|
|
/*
|
|
* Entry from JNI stub that calls `artJniUnlockObject()`. Note that failure to
|
|
* unlock is fatal, so we do not need to check for exceptions.
|
|
* Custom calling convention:
|
|
* RBX holds the non-null object to unlock.
|
|
* Callee-save registers have been saved and can be used as temporaries (except RBX).
|
|
* Return registers RAX and mmx0 need to be preserved.
|
|
*/
|
|
// This is also the slow path for art_jni_unlock_object.
|
|
JNI_SAVE_RETURN_VALUE_TRAMPOLINE \
|
|
art_jni_unlock_object_no_inline, artJniUnlockObject, rbx, gs:THREAD_SELF_OFFSET
|