1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "asm_support_x86.S" 18 19 /* 20 * Jni dlsym lookup stub. 21 */ 22DEFINE_FUNCTION art_jni_dlsym_lookup_stub 23 INCREASE_FRAME 8 // Align stack. 24 pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). 25 CFI_ADJUST_CFA_OFFSET(4) 26 // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable() 27 // for @FastNative or @CriticalNative. 28 movl (%esp), %eax // Thread* self 29 movl THREAD_TOP_QUICK_FRAME_OFFSET(%eax), %eax // uintptr_t tagged_quick_frame 30 andl LITERAL(0xfffffffe), %eax // ArtMethod** sp 31 movl (%eax), %eax // ArtMethod* method 32 testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \ 33 ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 34 jne .Llookup_stub_fast_or_critical_native 35 call SYMBOL(artFindNativeMethod) // (Thread*) 36 jmp .Llookup_stub_continue 37.Llookup_stub_fast_or_critical_native: 38 call SYMBOL(artFindNativeMethodRunnable) // (Thread*) 39.Llookup_stub_continue: 40 DECREASE_FRAME 12 // Remove argument & padding. 41 testl %eax, %eax // Check if returned method code is null. 42 jz .Lno_native_code_found // If null, jump to return to handle. 43 jmp *%eax // Otherwise, tail call to intended method. 44.Lno_native_code_found: 45 ret 46END_FUNCTION art_jni_dlsym_lookup_stub 47 48DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub 49 // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is eax. 50 // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub. 51 testl LITERAL(1), %eax 52 jnz art_jni_dlsym_lookup_stub 53 54 // Since the native call args are all on the stack, we can use the managed args 55 // registers as scratch registers. So, EBX, EDX and ECX are available. 56 57 // Load caller PC. 58 movl (%esp), %ecx 59 60 // Save the caller method from the hidden arg. 61 PUSH_ARG eax 62 63 // Call artCriticalNativeFrameSize(method, caller_pc). 64 PUSH_ARG ecx // Pass caller PC. 65 PUSH_ARG eax // Pass method. 66 call SYMBOL(artCriticalNativeFrameSize) // (method, caller_pc) 67 DECREASE_FRAME 8 // Remove args. 68 69 // Restore method register to EBX. 70 POP_ARG ebx 71 72 // Load caller PC to EDX and redefine return PC for CFI. 73 movl (%esp), %edx 74 CFI_REGISTER(%eip, %edx) 75 76 // Reserve space for a SaveRefsAndArgs managed frame, either for the actual runtime 77 // method or for a GenericJNI frame which is similar but has a native method and a tag. 78 INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__ 79 80 // Calculate the number of DWORDs to move. 81 movl %eax, %ecx 82 shrl LITERAL(2), %ecx 83 jecxz .Lcritical_skip_copy_args 84 85 // Save EDI, ESI so that we can use them for moving stack args. 86 PUSH edi 87 PUSH esi 88 89 // Move the stack args. 90 leal 2 * __SIZEOF_POINTER__(%esp), %edi 91 leal FRAME_SIZE_SAVE_REFS_AND_ARGS(%edi), %esi 92 rep movsd 93 94 // Restore EDI, ESI. 95 POP esi 96 POP edi 97 98.Lcritical_skip_copy_args: 99 // Calculate the base address of the managed frame. 100 leal (%esp, %eax, 1), %eax 101 102 leal 1(%eax), %ecx // Prepare namaged SP tagged for a GenericJNI frame. 103 testl LITERAL(ACCESS_FLAGS_METHOD_IS_NATIVE), ART_METHOD_ACCESS_FLAGS_OFFSET(%ebx) 104 jnz .Lcritical_skip_prepare_runtime_method 105 106 // Save the return PC for managed stack walk. 107 // (When coming from a compiled stub, the correct return PC is already there.) 108 movl %edx, FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%eax) 109 110 // Replace the target method with the SaveRefsAndArgs runtime method. 111 LOAD_RUNTIME_INSTANCE ecx, ebx 112 movl RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET(%ecx), %ebx 113 114 movl %eax, %ecx // Prepare untagged managed SP for the runtime method. 115 116.Lcritical_skip_prepare_runtime_method: 117 // Store the method on the bottom of the managed frame. 118 movl %ebx, (%eax) 119 120 // Move the managed frame address to native callee-save register EBX. 121 movl %eax, %ebx 122 123 // Spill registers for the SaveRefsAndArgs frame above the stack args. 124 movl %edi, 56(%ebx) 125 CFI_EXPRESSION_BREG CFI_REG(edi), CFI_REG(ebx), 56 126 movl %esi, 52(%ebx) 127 CFI_EXPRESSION_BREG CFI_REG(esi), CFI_REG(ebx), 52 128 movl %ebp, 48(%ebx) 129 CFI_EXPRESSION_BREG CFI_REG(ebp), CFI_REG(ebx), 48 130 // Skip managed ABI args EBX, EDX, ECX and FPRs. The runtime shall not examine the 131 // args in the managed frame. (We have already clobbered EBX, EDX, ECX anyway.) 132 133 // Place (maybe tagged) managed SP in Thread::Current()->top_quick_frame. 134 movl %ecx, %fs:THREAD_TOP_QUICK_FRAME_OFFSET 135 136 // Save our return PC in a slot reserved for first FP arg in managed ABI. 137 movl %edx, __SIZEOF_POINTER__(%ebx) 138 CFI_EXPRESSION_BREG CFI_REG(eip), CFI_REG(ebx), __SIZEOF_POINTER__ 139 140 // Call artFindNativeMethodRunnable() 141 INCREASE_FRAME 12 // Align stack. 142 pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() 143 CFI_ADJUST_CFA_OFFSET(4) 144 call SYMBOL(artFindNativeMethodRunnable) // (Thread*) 145 addl LITERAL(16), %esp 146 CFI_ADJUST_CFA_OFFSET(-16) 147 148 // Check for exception. 149 test %eax, %eax 150 jz .Lcritical_deliver_exception 151 152 CFI_REMEMBER_STATE 153 154 // Remember our return PC in EDX. 155 movl __SIZEOF_POINTER__(%ebx), %edx 156 CFI_REGISTER(%eip, %edx) 157 158 // Restore callee-save registers from the frame. We shall not need the method anymore. 159 movl 48(%ebx), %ebp 160 CFI_RESTORE(%ebp) 161 movl 52(%ebx), %esi 162 CFI_RESTORE(%esi) 163 movl 56(%ebx), %edi 164 CFI_RESTORE(%edi) 165 166 // Calculate the number of DWORDs to move. 167 movl %ebx, %ecx 168 subl %esp, %ecx 169 shrl LITERAL(2), %ecx 170 jecxz .Lcritical_skip_copy_args_back 171 172 // Save EDI, ESI so that we can use them for moving stack args. 173 PUSH edi 174 PUSH esi 175 176 // Move stack args to their original place. 177 leal -__SIZEOF_POINTER__(%ebx), %esi 178 leal FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%ebx), %edi 179 std 180 rep movsd 181 cld 182 183 // Restore EDI, ESI. 184 POP esi 185 POP edi 186 187.Lcritical_skip_copy_args_back: 188 // Remove the frame reservation. 189 DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__ 190 191 // Store our return PC. 192 movl %edx, (%esp) 193 CFI_REL_OFFSET(%eip, 0) 194 195 // Do the tail call. 196 jmp *%eax 197 CFI_RESTORE_STATE_AND_DEF_CFA(%esp, FRAME_SIZE_SAVE_REFS_AND_ARGS) 198 199.Lcritical_deliver_exception: 200 DELIVER_PENDING_EXCEPTION_FRAME_READY 201END_FUNCTION art_jni_dlsym_lookup_critical_stub 202