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#define MANAGED_ARGS_SAVE_SIZE /*xmm0-xmm3*/ 4 * 8 + /*padding*/ 4 + /* GPR args */ 4 * 4 20 21// Save register args and adds space for outgoing arguments. 22// With `call_args_space = 0`, the ESP shall be 8-byte aligned but not 16-byte aligned, 23// so either the `call_args_space` should be 8 (or 24, 40, ...) or the user of the macro 24// needs to adjust the ESP explicitly afterwards. 25MACRO1(SAVE_MANAGED_ARGS_INCREASE_FRAME, call_args_space) 26 // Return address is on the stack. 27 PUSH_ARG ebx 28 PUSH_ARG edx 29 PUSH_ARG ecx 30 PUSH_ARG eax 31 // Make xmm<n> spill slots 8-byte aligned. 32 INCREASE_FRAME (\call_args_space + /*FPRs*/ 4 * 8 + /*padding*/ 4) 33 movsd %xmm0, \call_args_space + 0(%esp) 34 movsd %xmm1, \call_args_space + 8(%esp) 35 movsd %xmm2, \call_args_space + 16(%esp) 36 movsd %xmm3, \call_args_space + 24(%esp) 37END_MACRO 38 39MACRO1(RESTORE_MANAGED_ARGS_DECREASE_FRAME, call_args_space) 40 movsd \call_args_space + 0(%esp), %xmm0 41 movsd \call_args_space + 8(%esp), %xmm1 42 movsd \call_args_space + 16(%esp), %xmm2 43 movsd \call_args_space + 24(%esp), %xmm3 44 DECREASE_FRAME \call_args_space + /*FPR args*/ 4 * 8 + /*padding*/ 4 45 POP_ARG eax 46 POP_ARG ecx 47 POP_ARG edx 48 POP_ARG ebx 49END_MACRO 50 51MACRO3(JNI_SAVE_MANAGED_ARGS_TRAMPOLINE, name, cxx_name, arg1) 52DEFINE_FUNCTION \name 53 // Note: Managed callee-save registers have been saved by the JNI stub. 54 // Save register args EAX, ECX, EDX, EBX, mmx0-mmx3, add and padding above `arg1`. 55 SAVE_MANAGED_ARGS_INCREASE_FRAME /*padding*/ 4 56 // Call `cxx_name()`. 57 PUSH_ARG RAW_VAR(arg1) // Pass arg1. 58 call CALLVAR(cxx_name) // Call cxx_name(...). 59 // Restore register args EAX, ECX, EDX, EBX, mmx0-mmx3 and return. 60 RESTORE_MANAGED_ARGS_DECREASE_FRAME /*arg1*/ 4 + /*padding*/ 4 61 ret 62END_FUNCTION \name 63END_MACRO 64 65MACRO4(JNI_SAVE_RETURN_VALUE_TRAMPOLINE, name, cxx_name, arg1, arg2) 66DEFINE_FUNCTION \name 67 // Save return registers. 68 PUSH_ARG edx 69 PUSH_ARG eax 70 .ifnc \arg2, none 71 INCREASE_FRAME /*mmx0*/ 8 + /*padding*/ 4 72 movsd %xmm0, 0(%esp) 73 PUSH_ARG RAW_VAR(arg2) // Pass arg2. 74 .else 75 INCREASE_FRAME /*padding*/ 4 + /*mmx0*/ 8 + /*padding*/ 4 76 movsd %xmm0, 4(%esp) 77 .endif 78 // Call `cxx_name()`. 79 PUSH_ARG RAW_VAR(arg1) // Pass arg1. 80 call CALLVAR(cxx_name) // Call cxx_name(...). 81 // Restore return registers and return. 82 movsd 8(%esp), %xmm0 83 DECREASE_FRAME /*call args*/ 8 + /*xmm0*/ 8 + /*padding*/ 4 84 POP_ARG eax 85 POP_ARG edx 86 ret 87END_FUNCTION \name 88END_MACRO 89 90 /* 91 * Jni dlsym lookup stub. 92 */ 93DEFINE_FUNCTION art_jni_dlsym_lookup_stub 94 INCREASE_FRAME 8 // Align stack. 95 pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). 96 CFI_ADJUST_CFA_OFFSET(4) 97 // Call artFindNativeMethod() for normal native and artFindNativeMethodRunnable() 98 // for @FastNative or @CriticalNative. 99 movl (%esp), %eax // Thread* self 100 movl THREAD_TOP_QUICK_FRAME_OFFSET(%eax), %eax // uintptr_t tagged_quick_frame 101 andl LITERAL(TAGGED_JNI_SP_MASK_TOGGLED32), %eax // ArtMethod** sp 102 movl (%eax), %eax // ArtMethod* method 103 testl LITERAL(ACCESS_FLAGS_METHOD_IS_FAST_NATIVE | ACCESS_FLAGS_METHOD_IS_CRITICAL_NATIVE), \ 104 ART_METHOD_ACCESS_FLAGS_OFFSET(%eax) 105 jne .Llookup_stub_fast_or_critical_native 106 call SYMBOL(artFindNativeMethod) // (Thread*) 107 jmp .Llookup_stub_continue 108.Llookup_stub_fast_or_critical_native: 109 call SYMBOL(artFindNativeMethodRunnable) // (Thread*) 110.Llookup_stub_continue: 111 DECREASE_FRAME 12 // Remove argument & padding. 112 testl %eax, %eax // Check if returned method code is null. 113 jz .Lno_native_code_found // If null, jump to return to handle. 114 jmp *%eax // Otherwise, tail call to intended method. 115.Lno_native_code_found: 116 ret 117END_FUNCTION art_jni_dlsym_lookup_stub 118 119 /* 120 * Jni dlsym lookup stub for @CriticalNative. 121 */ 122DEFINE_FUNCTION art_jni_dlsym_lookup_critical_stub 123 // The hidden arg holding the tagged method (bit 0 set means GenericJNI) is eax. 124 // For Generic JNI we already have a managed frame, so we reuse the art_jni_dlsym_lookup_stub. 125 testl LITERAL(1), %eax 126 jnz art_jni_dlsym_lookup_stub 127 128 // Since the native call args are all on the stack, we can use the managed args 129 // registers as scratch registers. So, EBX, EDX and ECX are available. 130 131 // Load caller PC. 132 movl (%esp), %ecx 133 134 // Save the caller method from the hidden arg. 135 PUSH_ARG eax 136 137 // Call artCriticalNativeFrameSize(method, caller_pc). 138 PUSH_ARG ecx // Pass caller PC. 139 PUSH_ARG eax // Pass method. 140 call SYMBOL(artCriticalNativeFrameSize) // (method, caller_pc) 141 DECREASE_FRAME 8 // Remove args. 142 143 // Restore method register to EBX. 144 POP_ARG ebx 145 146 // Load caller PC to EDX and redefine return PC for CFI. 147 movl (%esp), %edx 148 CFI_REGISTER(%eip, %edx) 149 150 // Reserve space for a SaveRefsAndArgs managed frame, either for the actual runtime 151 // method or for a GenericJNI frame which is similar but has a native method and a tag. 152 INCREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__ 153 154 // Calculate the number of DWORDs to move. 155 movl %eax, %ecx 156 shrl LITERAL(2), %ecx 157 jecxz .Lcritical_skip_copy_args 158 159 // Save EDI, ESI so that we can use them for moving stack args. 160 PUSH edi 161 PUSH esi 162 163 // Move the stack args. 164 leal 2 * __SIZEOF_POINTER__(%esp), %edi 165 leal FRAME_SIZE_SAVE_REFS_AND_ARGS(%edi), %esi 166 rep movsd 167 168 // Restore EDI, ESI. 169 POP esi 170 POP edi 171 172.Lcritical_skip_copy_args: 173 // Calculate the base address of the managed frame. 174 leal (%esp, %eax, 1), %eax 175 176 leal 1(%eax), %ecx // Prepare namaged SP tagged for a GenericJNI frame. 177 testl LITERAL(ACCESS_FLAGS_METHOD_IS_NATIVE), ART_METHOD_ACCESS_FLAGS_OFFSET(%ebx) 178 jnz .Lcritical_skip_prepare_runtime_method 179 180 // Save the return PC for managed stack walk. 181 // (When coming from a compiled stub, the correct return PC is already there.) 182 movl %edx, FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%eax) 183 184 // Replace the target method with the SaveRefsAndArgs runtime method. 185 LOAD_RUNTIME_INSTANCE ebx 186 movl RUNTIME_SAVE_REFS_AND_ARGS_METHOD_OFFSET(%ebx), %ebx 187 188 movl %eax, %ecx // Prepare untagged managed SP for the runtime method. 189 190.Lcritical_skip_prepare_runtime_method: 191 // Store the method on the bottom of the managed frame. 192 movl %ebx, (%eax) 193 194 // Move the managed frame address to native callee-save register EBX. 195 movl %eax, %ebx 196 197 // Spill registers for the SaveRefsAndArgs frame above the stack args. 198 movl %edi, 56(%ebx) 199 CFI_EXPRESSION_BREG CFI_REG(edi), CFI_REG(ebx), 56 200 movl %esi, 52(%ebx) 201 CFI_EXPRESSION_BREG CFI_REG(esi), CFI_REG(ebx), 52 202 movl %ebp, 48(%ebx) 203 CFI_EXPRESSION_BREG CFI_REG(ebp), CFI_REG(ebx), 48 204 // Skip managed ABI args EBX, EDX, ECX and FPRs. The runtime shall not examine the 205 // args in the managed frame. (We have already clobbered EBX, EDX, ECX anyway.) 206 207 // Place (maybe tagged) managed SP in Thread::Current()->top_quick_frame. 208 movl %ecx, %fs:THREAD_TOP_QUICK_FRAME_OFFSET 209 210 // Save our return PC in a slot reserved for first FP arg in managed ABI. 211 movl %edx, __SIZEOF_POINTER__(%ebx) 212 CFI_EXPRESSION_BREG CFI_REG(eip), CFI_REG(ebx), __SIZEOF_POINTER__ 213 214 // Call artFindNativeMethodRunnable() 215 INCREASE_FRAME 12 // Align stack. 216 pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() 217 CFI_ADJUST_CFA_OFFSET(4) 218 call SYMBOL(artFindNativeMethodRunnable) // (Thread*) 219 addl LITERAL(16), %esp 220 CFI_ADJUST_CFA_OFFSET(-16) 221 222 // Check for exception. 223 test %eax, %eax 224 jz .Lcritical_deliver_exception 225 226 CFI_REMEMBER_STATE 227 228 // Remember our return PC in EDX. 229 movl __SIZEOF_POINTER__(%ebx), %edx 230 CFI_REGISTER(%eip, %edx) 231 232 // Restore callee-save registers from the frame. We shall not need the method anymore. 233 movl 48(%ebx), %ebp 234 CFI_RESTORE(%ebp) 235 movl 52(%ebx), %esi 236 CFI_RESTORE(%esi) 237 movl 56(%ebx), %edi 238 CFI_RESTORE(%edi) 239 240 // Calculate the number of DWORDs to move. 241 movl %ebx, %ecx 242 subl %esp, %ecx 243 shrl LITERAL(2), %ecx 244 jecxz .Lcritical_skip_copy_args_back 245 246 // Save EDI, ESI so that we can use them for moving stack args. 247 PUSH edi 248 PUSH esi 249 250 // Move stack args to their original place. 251 leal -__SIZEOF_POINTER__(%ebx), %esi 252 leal FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__(%ebx), %edi 253 std 254 rep movsd 255 cld 256 257 // Restore EDI, ESI. 258 POP esi 259 POP edi 260 261.Lcritical_skip_copy_args_back: 262 // Remove the frame reservation. 263 DECREASE_FRAME FRAME_SIZE_SAVE_REFS_AND_ARGS - __SIZEOF_POINTER__ 264 265 // Store our return PC. 266 movl %edx, (%esp) 267 CFI_REL_OFFSET(%eip, 0) 268 269 // Do the tail call. 270 jmp *%eax 271 CFI_RESTORE_STATE_AND_DEF_CFA %esp, FRAME_SIZE_SAVE_REFS_AND_ARGS 272 273.Lcritical_deliver_exception: 274 DELIVER_PENDING_EXCEPTION_FRAME_READY 275END_FUNCTION art_jni_dlsym_lookup_critical_stub 276 277 /* 278 * Read barrier for the method's declaring class needed by JNI stub for static methods. 279 * (We're using a pointer to the declaring class in `ArtMethod` as `jclass`.) 280 */ 281JNI_SAVE_MANAGED_ARGS_TRAMPOLINE art_jni_read_barrier, artJniReadBarrier, eax 282 283 /* 284 * Trampoline to `artJniMethodStart()` that preserves all managed arguments. 285 */ 286JNI_SAVE_MANAGED_ARGS_TRAMPOLINE art_jni_method_start, artJniMethodStart, fs:THREAD_SELF_OFFSET 287 288 /* 289 * Trampoline to `artJniMethodEntryHook` that preserves all managed arguments. 290 */ 291JNI_SAVE_MANAGED_ARGS_TRAMPOLINE \ 292 art_jni_method_entry_hook, artJniMethodEntryHook, fs:THREAD_SELF_OFFSET 293 294 /* 295 * Trampoline to `artJniMonitoredMethodStart()` that preserves all managed arguments. 296 */ 297JNI_SAVE_MANAGED_ARGS_TRAMPOLINE \ 298 art_jni_monitored_method_start, artJniMonitoredMethodStart, fs:THREAD_SELF_OFFSET 299 300 /* 301 * Trampoline to `artJniMethodEnd()` that preserves all return registers. 302 */ 303JNI_SAVE_RETURN_VALUE_TRAMPOLINE art_jni_method_end, artJniMethodEnd, fs:THREAD_SELF_OFFSET, none 304 305 /* 306 * Trampoline to `artJniMonitoredMethodEnd()` that preserves all return registers. 307 */ 308JNI_SAVE_RETURN_VALUE_TRAMPOLINE \ 309 art_jni_monitored_method_end, artJniMonitoredMethodEnd, fs:THREAD_SELF_OFFSET, none 310 311 /* 312 * Entry from JNI stub that tries to lock the object in a fast path and 313 * calls `artLockObjectFromCode()` (the same as for managed code) for the 314 * difficult cases, may block for GC. 315 * Custom calling convention: 316 * EBP holds the non-null object to lock. 317 * Callee-save registers have been saved and can be used as temporaries (except EBP). 318 * All argument registers need to be preserved. 319 */ 320DEFINE_FUNCTION art_jni_lock_object 321 movl %eax, %edi // Preserve EAX in a callee-save register. 322 LOCK_OBJECT_FAST_PATH ebp, esi, /*saved_eax*/ edi .Llock_object_jni_slow 323 324.Llock_object_jni_slow: 325 movl %edi, %eax // Restore EAX. 326 jmp SYMBOL(art_jni_lock_object_no_inline) 327END_FUNCTION art_jni_lock_object 328 329 /* 330 * Entry from JNI stub that calls `artLockObjectFromCode()` 331 * (the same as for managed code), may block for GC. 332 * Custom calling convention: 333 * EBP holds the non-null object to lock. 334 * Callee-save registers have been saved and can be used as temporaries (except EBP). 335 * All argument registers need to be preserved. 336 */ 337DEFINE_FUNCTION art_jni_lock_object_no_inline 338 // This is also the slow path for art_jni_lock_object. 339 // Save register args EAX, ECX, EDX, EBX, mmx0-mmx3; original value of EAX is in EDI. 340 SAVE_MANAGED_ARGS_INCREASE_FRAME /*call_args_space*/ 0 341 // Note: The stack is not 16-byte aligned here but it shall be after pushing args for the call. 342 // Call `artLockObjectFromCode()` 343 pushl %fs:THREAD_SELF_OFFSET // Pass Thread::Current(). 344 CFI_ADJUST_CFA_OFFSET(4) 345 PUSH_ARG ebp // Pass the object to lock. 346 call SYMBOL(artLockObjectFromCode) // (object, Thread*) 347 // Check result. 348 testl %eax, %eax 349 jnz 1f 350 // Restore register args EAX, ECX, EDX, EBX, mmx0-mmx3 and return. 351 RESTORE_MANAGED_ARGS_DECREASE_FRAME /*call_args_space*/ 8 352 ret 353 .cfi_adjust_cfa_offset (/*call args*/ 8 + MANAGED_ARGS_SAVE_SIZE) 3541: 355 // All args are irrelevant when throwing an exception. 356 // Remove the spill area except for new padding to align stack. 357 DECREASE_FRAME (/*call args*/ 8 + MANAGED_ARGS_SAVE_SIZE - /*new padding*/ 8) 358 // Rely on the JNI transition frame constructed in the JNI stub. 359 pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() 360 CFI_ADJUST_CFA_OFFSET(4) 361 call SYMBOL(artDeliverPendingExceptionFromCode) // (Thread*) 362 UNREACHABLE 363END_FUNCTION art_jni_lock_object_no_inline 364 365 /* 366 * Entry from JNI stub that tries to unlock the object in a fast path and calls 367 * `artJniUnlockObject()` for the difficult cases. Note that failure to unlock 368 * is fatal, so we do not need to check for exceptions in the slow path. 369 * Custom calling convention: 370 * EBP holds the non-null object to unlock. 371 * Callee-save registers have been saved and can be used as temporaries (except EBP). 372 * Return registers EAX, EDX and mmx0 need to be preserved. 373 */ 374DEFINE_FUNCTION art_jni_unlock_object 375 movl %eax, %edi // Preserve EAX in a different register. 376 UNLOCK_OBJECT_FAST_PATH ebp, esi, /*saved_eax*/ edi, .Lunlock_object_jni_slow 377 378 .Lunlock_object_jni_slow: 379 movl %edi, %eax // Restore EAX. 380 jmp SYMBOL(art_jni_unlock_object_no_inline) 381END_FUNCTION art_jni_unlock_object 382 383 /* 384 * Entry from JNI stub that calls `artJniUnlockObject()`. Note that failure to 385 * unlock is fatal, so we do not need to check for exceptions. 386 * Custom calling convention: 387 * EBP holds the non-null object to unlock. 388 * Callee-save registers have been saved and can be used as temporaries (except EBP). 389 * Return registers EAX, EDX and mmx0 need to be preserved. 390 */ 391 // This is also the slow path for art_jni_unlock_object. 392JNI_SAVE_RETURN_VALUE_TRAMPOLINE \ 393 art_jni_unlock_object_no_inline, artJniUnlockObject, ebp, fs:THREAD_SELF_OFFSET 394