/* * Copyright (C) 2008 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. */ /* * JNI method invocation. This is used to call a C/C++ JNI method. The * argument list has to be pushed onto the native stack according to * local calling conventions. * * This version supports 32-bit x86 */ /* Function prototype: void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc, const u4* argv, const char* signature, void* func, JValue* pReturn) The method we are calling has the form: return_type func(JNIEnv* pEnv, ClassObject* clazz, ...) -or- return_type func(JNIEnv* pEnv, Object* this, ...) We receive a collection of 32-bit values which correspond to arguments from the interpreter (e.g. float occupies one, double occupies two). It's up to us to convert these into local calling conventions. */ /* x86 notes: The native code expects arguments on the stack, pushed from right to left. This matches what Dalvik is passing here. EAX, EDX and ECX are scratch. 4-byte alignment is required for long long and double, so we won't pad Non-FP return types <= 4 bytes come back in EAX Non-FP return types of 8 bytes come back in EAX:EDX, with lsw in EAX. Float and double returned on top of FP stack. */ .text .global dvmPlatformInvoke .type dvmPlatformInvoke, @function /* * On entry: * [ 8] arg0 JNIEnv (can be left alone) * [12] arg1 clazz (NULL for virtual method calls, non-NULL for static) * [16] arg2 arg info * [20] arg3 argc * [24] arg4 argv * [28] arg5 short signature * [32] arg6 func * [36] arg7 pReturn * * For a virtual method call, the "this" reference is in argv[0]. * * argInfo (32-bit int) layout: * SRRRZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA * * Z - reserved * S - if set, argInfo hints are invalid * R - return type enumeration (see jniInternal.h) * VOID -> 0 * FLOAT -> 1 * DOUBLE -> 2 * S8 -> 3 * S4 -> 4 * A - size of the variable argument block in 32-bit words * */ dvmPlatformInvoke: /* Establish the frame pointer, spill & align to 16b */ pushl %ebp movl %esp,%ebp pushl %edi pushl %esi pushl %ebx subl $12,%esp /* For 386 ABI, argInfo hints should always be valid. Abort if not. */ movl 16(%ebp),%ebx testl %ebx,%ebx js dvmAbort /* Get the size of the variable region and grow (preserving alignment) */ movl %ebx,%ecx leal 12(,%ecx,4),%ecx andl $0x0003FFF0,%ecx subl %ecx,%esp /* Handle this/class */ movl 8(%ebp),%ecx movl 12(%ebp),%eax movl 24(%ebp),%esi testl %eax,%eax jne isClass movl (%esi),%eax addl $4,%esi isClass: pushl %eax pushl %ecx /* Now, copy the variable arguments region */ movl %ebx,%ecx andl $0x0000FFFF,%ecx leal 8(%esp),%edi cld rep movsd /* Ready to go - call the native code */ call *32(%ebp) /* Store the result. */ sarl $28,%ebx /* Is void? */ testl %ebx,%ebx je cleanUpAndExit movl 36(%ebp),%ecx /* Is FP? */ cmpl $2,%ebx jle isFP cmpl $4,%ebx /* smaller than 32-bits? */ jg isSmall storeRetval: /* Blindly storing 64-bits won't hurt 32-bit case */ movl %eax,(%ecx) movl %edx,4(%ecx) jmp cleanUpAndExit isSmall: cmpl $7,%ebx /* S1? */ jne checkShort movsbl %al,%eax movl %eax,(%ecx) jmp cleanUpAndExit checkShort: cmpl $6,%ebx /* U2? */ jne isSignedShort movzwl %ax,%eax movl %eax,(%ecx) jmp cleanUpAndExit isSignedShort: /* Must be S2 */ movswl %ax,%eax movl %eax,(%ecx) jmp cleanUpAndExit isFP: /* Is Float? */ cmpl $1,%ebx je saveFloat fstpl (%ecx) jmp cleanUpAndExit saveFloat: fstps (%ecx) cleanUpAndExit: leal -12(%ebp),%esp pop %ebx pop %esi pop %edi pop %ebp ret .size dvmPlatformInvoke, .-dvmPlatformInvoke .section .note.GNU-stack,"",@progbits