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 subl LITERAL(8), %esp // align stack 24 CFI_ADJUST_CFA_OFFSET(8) 25 pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() 26 CFI_ADJUST_CFA_OFFSET(4) 27 // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable() 28 // for @FastNative or @CriticalNative. 29 movl (%esp), %eax // Thread* self 30 movl THREAD_TOP_QUICK_FRAME_OFFSET(%eax), %eax // uintptr_t tagged_quick_frame 31 andl LITERAL(0xfffffffe), %eax // ArtMethod** sp 32 movl (%eax), %eax // ArtMethod* method 33 testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \ 34 ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 35 jne .Llookup_stub_fast_native 36 call SYMBOL(artFindNativeMethod) // (Thread*) 37 jmp .Llookup_stub_continue 38.Llookup_stub_fast_native: 39 call SYMBOL(artFindNativeMethodRunnable) // (Thread*) 40.Llookup_stub_continue: 41 addl LITERAL(12), %esp // remove argument & padding 42 CFI_ADJUST_CFA_OFFSET(-12) 43 testl %eax, %eax // check if returned method code is null 44 jz .Lno_native_code_found // if null, jump to return to handle 45 jmp *%eax // otherwise, tail call to intended method 46.Lno_native_code_found: 47 ret 48END_FUNCTION art_jni_dlsym_lookup_stub 49 50DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub 51 // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is eax. 52 // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub. 53 testl LITERAL(1), %eax 54 jnz art_jni_dlsym_lookup_stub 55 56 // We need to create a GenericJNI managed frame above the stack args. 57 58 // GenericJNI frame is similar to SaveRegsAndArgs frame with the native method 59 // instead of runtime method saved at the bottom. Note that the runtime shall 60 // not examine the args here, otherwise we would have to reload them from stack 61 // to account for the difference between managed and native ABIs. 62 SETUP_SAVE_REFS_AND_ARGS_FRAME_REGISTERS_ONLY 63 pushl %eax // Save the hidden arg as method pointer at the bottom of the stack. 64 CFI_ADJUST_CFA_OFFSET(4) 65 66 // Call artCriticalNativeOutArgsSize(method); method is conveniently at the bottom of the stack. 67 call SYMBOL(artCriticalNativeOutArgsSize) 68 69 // Check if we have any stack args other than return PC. 70 cmp LITERAL(__SIZEOF_POINTER__), %eax 71 jnz .Lcritical_has_stack_args 72 73 // Without stack args, the frame is fully constructed. 74 // Place tagged managed sp in Thread::Current()->top_quick_frame. 75 leal 1(%esp), %eax // Tag as GenericJNI frame. 76 mov %eax, %fs:THREAD_TOP_QUICK_FRAME_OFFSET 77 78 // Call artFindNativeMethodRunnable() 79 subl LITERAL(12), %esp // align stack 80 CFI_ADJUST_CFA_OFFSET(12) 81 pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() 82 CFI_ADJUST_CFA_OFFSET(4) 83 call SYMBOL(artFindNativeMethodRunnable) // (Thread*) 84 addl LITERAL(16), %esp 85 CFI_ADJUST_CFA_OFFSET(-16) 86 87 // Check for exception. 88 test %eax, %eax 89 jz 1f 90 91 // Restore frame and do the tail call. 92 CFI_REMEMBER_STATE 93 RESTORE_SAVE_REFS_AND_ARGS_FRAME 94 jmp *%eax 95 CFI_RESTORE_STATE_AND_DEF_CFA(%esp, FRAME_SIZE_SAVE_REFS_AND_ARGS) 96 971: 98 DELIVER_PENDING_EXCEPTION_FRAME_READY 99 100.Lcritical_has_stack_args: 101 // As mentioned above, the runtime shall not examine the args in the managed frame 102 // and since all args for the native call are on the stack, we can use the managed 103 // args registers as scratch registers. So, EBX, EDX and ECX are available and we 104 // do not need to restore xmm0-xmm3 either. 105 106 // Restore registers as we're about to move stack args over the current SaveRefsAndArgs frame. 107 movl (%esp), %edx // Remember the method in EDX. 108 movl 48(%esp), %ebp 109 CFI_RESTORE(%ebp) 110 movl 52(%esp), %esi 111 CFI_RESTORE(%esi) 112 movl 56(%esp), %edi 113 CFI_RESTORE(%edi) 114 115 // Calculate the address of the end of the move destination and redefine CFI to take 116 // ownership of the JNI stub frame. EBX is conveniently callee-save in native ABI. 117 leal 0(%esp, %eax, 1), %ebx 118 CFI_DEF_CFA(%ebx, FRAME_SIZE_SAVE_REFS_AND_ARGS) 119 120 // Calculate the number of DWORDs to move. 121 shrl LITERAL(2), %eax 122 leal -1(%eax), %ecx // Do not move the return PC. 123 124 // Load our return PC to EAX. 125 movl FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%esp), %eax 126 127 // Save EDI, ESI so that we can use them for moving stack args. 128 pushl %edi // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP. 129 pushl %esi // ditto 130 131 // Mov the stack args. 132 leal 2 * __SIZEOF_POINTER__(%esp), %edi 133 leal FRAME_SIZE_SAVE_REFS_AND_ARGS(%edi), %esi 134 rep movsd 135 136 // Save our return PC. 137 movl %eax, (%edi) 138 139 // Restore EDI, ESI. 140 popl %esi // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP. 141 popl %edi // ditto 142 143 // Re-create the SaveRefsAndArgs frame above the args. 144 movl %edi, 56(%ebx) 145 CFI_REL_OFFSET(%edi, 56) 146 movl %esi, 52(%ebx) 147 CFI_REL_OFFSET(%esi, 52) 148 movl %ebp, 48(%ebx) 149 CFI_REL_OFFSET(%ebp, 48) 150 // Skip managed ABI args EBX, EDX, ECX and FPRs, see above. 151 // (We have already clobbered EBX, EDX, ECX anyway). 152 movl %edx, (%ebx) // Save method pointer. 153 154 // Place tagged managed sp in Thread::Current()->top_quick_frame. 155 leal 1(%ebx), %eax // Tag as GenericJNI frame. 156 movl %eax, %fs:THREAD_TOP_QUICK_FRAME_OFFSET 157 158 // Call artFindNativeMethodRunnable() 159 subl LITERAL(12), %esp // align stack, no `CFI_ADJUST_CFA_OFFSET`. 160 pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() 161 call SYMBOL(artFindNativeMethodRunnable) // (Thread*) 162 addl LITERAL(16), %esp // Pop args, no `CFI_ADJUST_CFA_OFFSET`. 163 164 // Check for exception. 165 test %eax, %eax 166 jz 2f 167 168 // Restore the frame. We shall not need the method anymore. 169 CFI_REMEMBER_STATE 170 movl 48(%ebx), %ebp 171 CFI_RESTORE(%ebp) 172 movl 52(%ebx), %esi 173 CFI_RESTORE(%esi) 174 movl 56(%ebx), %edi 175 CFI_RESTORE(%edi) 176 177 // Remember our return PC in EDX. 178 movl -__SIZEOF_POINTER__(%ebx), %edx 179 180 // Calculate the number of DWORDs to move. 181 leal -__SIZEOF_POINTER__(%ebx), %ecx // Do not move return PC. 182 subl %esp, %ecx 183 shrl LITERAL(2), %ecx 184 185 // Save EDI, ESI so that we can use them for moving stack args. 186 pushl %edi // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP. 187 pushl %esi // ditto 188 189 // Mov stack args to their original place. 190 leal -2 * __SIZEOF_POINTER__(%ebx), %esi 191 leal FRAME_SIZE_SAVE_REFS_AND_ARGS - 2 * __SIZEOF_POINTER__(%ebx), %edi 192 std 193 rep movsd 194 cld 195 196 // Store our return PC. 197 movl %edx, (%edi) 198 199 // Restore EDI, ESI. 200 popl %esi // No `CFI_ADJUST_CFA_OFFSET`, CFA register is currently EBX, not ESP. 201 popl %edi // ditto 202 203 // Redefine CFI to release ownership of the JNI stub frame. 204 CFI_DEF_CFA(%esp, FRAME_SIZE_SAVE_REFS_AND_ARGS) 205 206 // Remove the frame reservation. 207 addl LITERAL(FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__), %esp 208 CFI_ADJUST_CFA_OFFSET(-FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__) 209 210 // Do the tail call. 211 jmp *%eax 212 CFI_RESTORE_STATE_AND_DEF_CFA(%ebx, FRAME_SIZE_SAVE_REFS_AND_ARGS) 213 2142: 215 // Replicate DELIVER_PENDING_EXCEPTION_FRAME_READY without CFI_ADJUST_CFA_OFFSET, 216 // CFA register is currently EBX, not ESP. 217 218 // Outgoing argument set up 219 subl MACRO_LITERAL(12), %esp // alignment padding 220 pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() 221 call SYMBOL(artDeliverPendingExceptionFromCode) // artDeliverPendingExceptionFromCode(Thread*) 222 UNREACHABLE 223END_FUNCTION art_jni_dlsym_lookup_critical_stub 224