1 /* 2 * Copyright (C) 2008 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 /* 18 * JNI method invocation. This is used to call a C/C++ JNI method. The 19 * argument list has to be pushed onto the native stack according to 20 * local calling conventions. 21 * 22 * This version supports the "old" ARM ABI. 23 */ 24 25 #include <machine/cpu-features.h> 26 27 #ifndef __ARM_EABI__ 28 29 /* 30 Function prototype: 31 32 void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc, 33 const u4* argv, const char* signature, void* func, JValue* pReturn) 34 35 The method we are calling has the form: 36 37 return_type func(JNIEnv* pEnv, ClassObject* clazz, ...) 38 -or- 39 return_type func(JNIEnv* pEnv, Object* this, ...) 40 41 We receive a collection of 32-bit values which correspond to arguments from 42 the interpreter (e.g. float occupies one, double occupies two). It's up to 43 us to convert these into local calling conventions. 44 */ 45 46 /* 47 ARM ABI notes: 48 49 r0-r3 hold first 4 args to a method 50 r9 is given special treatment in some situations, but not for us 51 r10 (sl) seems to be generally available 52 r11 (fp) is used by gcc 53 r12 (ip) is scratch -- not preserved across method calls 54 r13 (sp) should be managed carefully in case a signal arrives 55 r14 (lr) must be preserved 56 r15 (pc) can be tinkered with directly 57 58 r0 holds returns <= 4 bytes 59 r0-r1 hold returns of 5-8 bytes, low word in r0 60 61 Stack is "full descending". Only the arguments that don't fit in the first 4 62 registers are placed on the stack. "sp" points at the first stacked argument 63 (i.e. the 5th arg). 64 65 VFP: single-precision results in s0, double-precision results in d0. 66 67 Happily we don't have to do anything special here -- the args from the 68 interpreter work directly as C/C++ args on ARM (with the "classic" ABI). 69 */ 70 71 .text 72 .align 2 73 .global dvmPlatformInvoke 74 .type dvmPlatformInvoke, %function 75 76 /* 77 On entry: 78 r0 JNIEnv 79 r1 clazz (NULL for virtual method calls, non-NULL for static) 80 r2 arg info (ignored) 81 r3 argc 82 [sp] argv 83 [sp,#4] signature (ignored) 84 [sp,#8] func 85 [sp,#12] pReturn 86 */ 87 dvmPlatformInvoke: 88 @ Standard gcc stack frame setup. We don't need to push the original 89 @ sp or the current pc if "-fomit-frame-pointer" is in use for the 90 @ rest of the code. If we don't plan to use a debugger we can speed 91 @ this up a little. 92 mov ip, sp 93 stmfd sp!, {r4, r5, r6, fp, ip, lr, pc} 94 sub fp, ip, #4 @ set up fp, same way gdb does 95 96 @ We need to push a variable number of arguments onto the stack. 97 @ Rather than keep a count and pop them off after, we just hold on to 98 @ the stack pointers. 99 @ 100 @ In theory we don't need to keep sp -- we can do an ldmdb instead of 101 @ an ldmia -- but we're doing the gcc frame trick where we push the 102 @ pc on with stmfd and don't pop it off. 103 mov r4, ip 104 mov r5, sp 105 106 @ argc is already in a scratch register (r3). Put argv into one. Note 107 @ argv can't go into r0-r3 because we need to use it to load those. 108 ldr ip, [r4, #0] @ ip <-- argv 109 110 @ Is this a static method? 111 cmp r1, #0 112 113 @ No: set r1 to *argv++, and set argc--. 114 @ (r0=pEnv, r1=this) 115 ldreq r1, [ip], #4 116 subeq r3, r3, #1 117 118 @ While we still have the use of r2/r3, copy excess args from argv 119 @ to the stack. We need to push the last item in argv first, and we 120 @ want the first two items in argv to end up in r2/r3. 121 subs r3, r3, #2 122 ble .Lno_copy 123 124 @ If there are N args, we want to skip 0 and 1, and push (N-1)..2. We 125 @ have N-2 in r3. If we set argv=argv+1, we can count from N-2 to 1 126 @ inclusive and get the right set of args. 127 add r6, ip, #4 128 129 .Lcopy: 130 @ *--sp = argv[count] 131 ldr r2, [r6, r3, lsl #2] 132 str r2, [sp, #-4]! 133 subs r3, r3, #1 134 bne .Lcopy 135 136 .Lno_copy: 137 @ Load the last two args. These are coming out of the interpreted stack, 138 @ and the VM preserves an overflow region at the bottom, so it should be 139 @ safe to load two items out of argv even if we're at the end. 140 ldr r2, [ip] 141 ldr r3, [ip, #4] 142 143 @ Show time. Tuck the pc into lr and load the pc from the method 144 @ address supplied by the caller. The value for "pc" is offset by 8 145 @ due to instruction prefetching. 146 @ 147 #ifdef __ARM_HAVE_PC_INTERWORK 148 mov lr, pc 149 ldr pc, [r4, #8] 150 #else 151 ldr ip, [r4, #8] 152 blx ip 153 #endif 154 155 @ We're back, result is in r0 or (for long/double) r0-r1. 156 @ 157 @ In theory, we need to use the "return type" arg to figure out what 158 @ we have and how to return it. However, unless we have an FPU, 159 @ all we need to do is copy r0-r1 into the JValue union. 160 ldr ip, [r4, #12] 161 stmia ip, {r0-r1} 162 163 #ifdef __ARM_HAVE_PC_INTERWORK 164 @ Restore the registers we saved and return. Note this remaps stuff, 165 @ so that "sp" comes from "ip", "pc" comes from "lr", and the "pc" 166 @ we pushed on evaporates when we restore "sp". 167 ldmfd r5, {r4, r5, r6, fp, sp, pc} 168 #else 169 ldmfd r5, {r4, r5, r6, fp, sp, lr} 170 bx lr 171 #endif 172 173 #endif /*__ARM_EABI__*/ 174