blob: 5c805894a1644634e4ce6b84d01a1630297723e9 [file] [log] [blame]
/*
* 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"
/*
* 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
subq LITERAL(72), %rsp
CFI_ADJUST_CFA_OFFSET(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_native
call SYMBOL(artFindNativeMethod) // (Thread*)
jmp .Llookup_stub_continue
.Llookup_stub_fast_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
addq LITERAL(72), %rsp
CFI_ADJUST_CFA_OFFSET(-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
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
// We need to create a GenericJNI managed frame above the stack args.
// GenericJNI frame is similar to SaveRegsAndArgs frame with the native method
// instead of runtime method saved at the bottom.
// As we always have "stack args" on x86-64 (due to xmm12-xmm15 being callee-save
// in managed ABI but caller-save in native ABI), do not create a proper frame yet
// as we do on other architectures where it's useful for no stack args case.
// Reserve space for the frame (return PC is on stack).
subq MACRO_LITERAL(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__), %rsp
CFI_ADJUST_CFA_OFFSET(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__)
// Save GPR args.
PUSH_ARG r9
PUSH_ARG r8
PUSH_ARG rdi
PUSH_ARG rsi
PUSH_ARG rdx
PUSH_ARG rcx
// Create space for FPR args.
subq LITERAL(64), %rsp
CFI_ADJUST_CFA_OFFSET(64)
// 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)
// Add alignment padding.
subq MACRO_LITERAL(__SIZEOF_POINTER__), %rsp
CFI_ADJUST_CFA_OFFSET(__SIZEOF_POINTER__)
// Save hidden arg.
PUSH_ARG rax
// Call artCriticalNativeOutArgsSize(method).
movq %rax, %rdi // Pass the method from hidden arg.
call SYMBOL(artCriticalNativeOutArgsSize)
// Calculate the address of the end of the move destination and redefine CFI to take
// ownership of the JNI stub frame.
leaq 16 * __SIZEOF_POINTER__(%rsp, %rax, 1), %r10 // 16 QWORDs of registers saved above.
CFI_DEF_CFA(%r10, FRAME_SIZE_SAVE_REFS_AND_ARGS)
// Calculate the number of QWORDs to move.
shrq LITERAL(3), %rax
leaq -1(%rax), %rcx // Do not move the return PC.
// Load our return PC to EAX.
movq FRAME_SIZE_SAVE_REFS_AND_ARGS + (16 - 1) * __SIZEOF_POINTER__(%rsp), %rax
// Mov the stack args.
leaq 16 * __SIZEOF_POINTER__(%rsp), %rdi
leaq FRAME_SIZE_SAVE_REFS_AND_ARGS(%rdi), %rsi
rep movsq
// Save our return PC.
movq %rax, (%rdi)
// Pop the hidden arg and alignment padding.
popq %rax // No `.cfi_adjust_cfa_offset`, CFA register is currently R10, not RSP.
addq MACRO_LITERAL(__SIZEOF_POINTER__), %rsp // ditto
// Fill the SaveRefsAndArgs frame above the args, without actual 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.
SAVE_REG_BASE r10, r15, 192
SAVE_REG_BASE r10, r14, 184
SAVE_REG_BASE r10, r13, 176
SAVE_REG_BASE r10, r12, 168
// Skip args r9, r8, rsi.
SAVE_REG_BASE r10, rbp, 136
SAVE_REG_BASE r10, rbx, 128
// Skip args rdx, rcx.
// Skip args xmm0-xmm7.
// Copy managed callee-saves xmm12-xmm15 from out args to the managed frame as they
// may theoretically store variables or unwinding data. (The compiled stub preserves
// them but the artCriticalNativeOutArgsSize() call above may clobber them.)
movq -5 * __SIZEOF_POINTER__(%r10), %xmm12
movq -4 * __SIZEOF_POINTER__(%r10), %xmm13
movq -3 * __SIZEOF_POINTER__(%r10), %xmm14
movq -2 * __SIZEOF_POINTER__(%r10), %xmm15
movq %xmm12, 80(%r10)
movq %xmm13, 88(%r10)
movq %xmm14, 96(%r10)
movq %xmm15, 104(%r10)
// Save the hidden arg as method pointer at the bottom of the stack.
movq %rax, (%r10)
// Move the frame register to a callee-save register.
movq %r10, %rbp
CFI_DEF_CFA_REGISTER(%rbp)
// Place tagged managed sp in Thread::Current()->top_quick_frame.
leaq 1(%rbp), %rax // Tag as GenericJNI frame.
movq %rax, %gs:THREAD_TOP_QUICK_FRAME_OFFSET
// Call artFindNativeMethodRunnable()
movq %gs:THREAD_SELF_OFFSET, %rdi // pass Thread::Current()
call SYMBOL(artFindNativeMethodRunnable) // (Thread*)
// Check for exception.
test %rax, %rax
jz 2f
// Restore the frame. We shall not need the method anymore.
.cfi_remember_state
movq %rbp, %r10
CFI_DEF_CFA_REGISTER(%r10)
// Skip args xmm0-xmm7 and managed callee-saves xmm12-xmm15 (not needed for native call).
// Skip args rdx, rcx.
RESTORE_REG_BASE r10, rbx, 128
RESTORE_REG_BASE r10, rbp, 136
// Skip args r9, r8, rsi.
RESTORE_REG_BASE r10, r12, 168
RESTORE_REG_BASE r10, r13, 176
RESTORE_REG_BASE r10, r14, 184
RESTORE_REG_BASE r10, r15, 192
// Remember our return PC in R11.
movq -__SIZEOF_POINTER__(%r10), %r11
// Calculate the number of DWORDs to move.
leaq -(1 + 14) * __SIZEOF_POINTER__(%r10), %rcx // Do not move return PC, 14 arg regs saved.
subq %rsp, %rcx
shrq LITERAL(3), %rcx
// Mov stack args to their original place.
leaq -2 * __SIZEOF_POINTER__(%r10), %rsi
leaq FRAME_SIZE_SAVE_REFS_AND_ARGS - 2 * __SIZEOF_POINTER__(%r10), %rdi
std
rep movsq
cld
// Store our return PC.
movq %r11, (%rdi)
// Redefine CFI to release ownership of the JNI stub frame.
CFI_DEF_CFA(%rsp, FRAME_SIZE_SAVE_REFS_AND_ARGS + 14 * __SIZEOF_POINTER__)
// Restore args.
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
addq LITERAL(64), %rsp
CFI_ADJUST_CFA_OFFSET(-64)
POP_ARG rcx
POP_ARG rdx
POP_ARG rsi
POP_ARG rdi
POP_ARG r8
POP_ARG r9
// Remove the frame reservation.
addq LITERAL(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__), %rsp
CFI_ADJUST_CFA_OFFSET(-(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__))
// Do the tail call.
jmp *%rax
CFI_RESTORE_STATE_AND_DEF_CFA(%rbp, FRAME_SIZE_SAVE_REFS_AND_ARGS)
2:
// Drop the args from the stack (the RAX and padding was already removed).
addq LITERAL(14 * __SIZEOF_POINTER__), %rsp
DELIVER_PENDING_EXCEPTION_FRAME_READY
END_FUNCTION art_jni_dlsym_lookup_critical_stub