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/* 30Function prototype: 31 32void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc, 33 const u4* argv, const char* signature, void* func, JValue* pReturn) 34 35The 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 41We receive a collection of 32-bit values which correspond to arguments from 42the interpreter (e.g. float occupies one, double occupies two). It's up to 43us to convert these into local calling conventions. 44 */ 45 46/* 47ARM ABI notes: 48 49r0-r3 hold first 4 args to a method 50r9 is given special treatment in some situations, but not for us 51r10 (sl) seems to be generally available 52r11 (fp) is used by gcc 53r12 (ip) is scratch -- not preserved across method calls 54r13 (sp) should be managed carefully in case a signal arrives 55r14 (lr) must be preserved 56r15 (pc) can be tinkered with directly 57 58r0 holds returns <= 4 bytes 59r0-r1 hold returns of 5-8 bytes, low word in r0 60 61Stack is "full descending". Only the arguments that don't fit in the first 4 62registers are placed on the stack. "sp" points at the first stacked argument 63(i.e. the 5th arg). 64 65VFP: single-precision results in s0, double-precision results in d0. 66 67Happily we don't have to do anything special here -- the args from the 68interpreter 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/* 77On 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*/ 87dvmPlatformInvoke: 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