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