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 MIPS O32 ABI. 23 */ 24 25 /* 26 Function prototype: 27 28 void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc, 29 const u4* argv, const char* signature, void* func, JValue* pReturn) 30 31 The method we are calling has the form: 32 33 return_type func(JNIEnv* pEnv, ClassObject* clazz, ...) 34 -or- 35 return_type func(JNIEnv* pEnv, Object* this, ...) 36 37 We receive a collection of 32-bit values which correspond to arguments from 38 the interpreter (e.g. float occupies one, double occupies two). It's up to 39 us to convert these into local calling conventions. 40 41 Please notice that argc in dvmPlatformInvoke does NOT include pEnv and clazz/this. 42 */ 43 44 .text 45 .align 2 46 .globl dvmPlatformInvoke 47 .ent dvmPlatformInvoke 48 /* 49 * On entry: 50 * a0 JNIEnv (can be left alone) 51 * a1 clazz (NULL for virtual method calls, non-NULL for static) 52 * a2 argInfo 53 * a3 argc (number of 32-bit values in argv) 54 * MIPS reservers 16 bytes on stack even if the first 4 args are passed by 55 * reg a0-a3. That's different from ARM. 56 * [sp + 16] argv 57 * [sp + 20] short signature 58 * [sp + 24] func 59 * [sp + 28] pReturn 60 * 61 * For a virtual method call, the "this" reference is in argv[0]. 62 * 63 * argInfo (32-bit int) layout: 64 * SRRRLLLL FFFFFFFF FFFFFFFF FFFFFFFF 65 * 66 * S - if set, do things the hard way (scan the signature) 67 * R - return type enumeration, really only important for hardware FP 68 * L - number of double-words (64 bits!) of storage required on stack (0-30 words) 69 * F - pad flag -- if set, write a pad word to the stack 70 * 71 * With this arrangement we can efficiently push up to 24 words of arguments 72 * onto the stack. Anything requiring more than that -- which should happen 73 * rarely to never -- can do the slow signature scan. 74 * 75 * (We could pack the Fs more efficiently -- we know we never push two pads 76 * in a row, and the first word can never be a pad -- but there's really 77 * no need for it.) 78 * 79 * NOTE: if the called function has more than 4 words of arguments, gdb 80 * will not be able to unwind the stack past this method. The only way 81 * around this is to convince gdb to respect an explicit frame pointer. 82 */ 83 84 /* Stack: 85 * High 86 * ____________ 87 * |__28______| pReturn 88 * |__24______| func 89 * |__20______| short signature 90 * |__16______| argv 91 * |__12______| reserved (a3: argc) 92 * |__8_______| reserved (a2: arg) 93 * |__4_______| reserved (a1: clazz) 94 *__sp on entry_->_|__0_______|_reserved (a0: JNIenv) 95 * |__________| saved ra 96 * |__________| saved fp 97 * |__________| saved s0 98 * |__________| spare 99 * |__________| saved s2 100 *"framepointer"->_|__________| pad for 8 bytes aligned 101 * |__________| other argv or pad 102 * |__________| other argv or pad 103 * |__________| other argv or pad 104 * |__________| other argv or pad 105 * |__________| other argv or pad 106 * |__________| other argv or pad 107 * |__________| reserved for a3 108 * |__________| reserved for a2 109 * |__________| reserved for a1 110 *_____new sp___-> |__________| reserved for a0 111 * (new sp: sp when call native method) 112 */ 113 114 /* Register usage: 115 * 116 * s0: pReturn 117 * s2: Return type 118 * These registers should be saved to and restored from stack. 119 * 120 * t0: argv 121 * t9: func 122 * These registers do not need to be saved. 123 * 124 * We put the stack size into register s1 because we can not know the size 125 * of stack at the beginning. This size can be calculated with the help 126 * of hints in jniarginfo. 127 * 128 */ 129 130 dvmPlatformInvoke: 131 .set noreorder 132 .cpload $t9 133 .set reorder 134 135 /* Do we have arg padding flags in "argInfo"? Check bit 31 */ 136 bltz $a2,.Lno_arginfo 137 138 /* Fast path. We have hints. */ 139 /* save fp and ra to stack */ 140 #define FSIZE 24 141 subu $sp,FSIZE 142 sw $ra,20($sp) 143 sw $fp,16($sp) 144 sw $s0,12($sp) 145 sw $s2,4($sp) 146 move $fp,$sp 147 148 lw $t0,FSIZE+16($sp) /* t0 <- argv */ 149 lw $t9,FSIZE+24($sp) /* t9 <- func */ 150 lw $s0,FSIZE+28($sp) /* s0 <- pReturn */ 151 152 /* Is the method static? */ 153 bnez $a1,1f 154 /* Not static: a1 <- *argv++ ("this"), argc-- */ 155 lw $a1,($t0) 156 addiu $t0,4 157 addiu $a3,-1 158 1: 159 /* expand the stack for args */ 160 srl $s2,$a2,28 /* s2 <- returnType */ 161 srl $t1,$a2,21 162 andi $t1,0x78 /* t1 <- stackSize in bytes */ 163 164 addiu $t1,16 /* include space for a0/a1/a2/a3 */ 165 subu $sp,$t1 166 addiu $t1,$sp,8 167 168 /* 169 * t0 :argv 170 * t1 :sp+8(first arg position in stack except pEnv and clazz/this) 171 * a2 :argInfo 172 * a3 :argc 173 * sp :new stack bottom 174 */ 175 176 /* first two args or one args and pad */ 177 blez $a3,.Largs_done 178 lw $t2,($t0) 179 addiu $t0,4 180 addiu $a3,-1 181 sw $t2,($t1) 182 addiu $t1,4 183 srl $a2,1 184 blez $a3,.Largs_done 185 186 andi $t3,$a2,0x1 /* the second position is a pad? */ 187 bnez $t3,.Lpad0 188 189 lw $t2,($t0) 190 addiu $t0,4 191 addiu $a3,-1 192 sw $t2,($t1) 193 .Lpad0: 194 addiu $t1,4 195 srl $a2,1 196 blez $a3,.Largs_done 197 198 .Lloop1: 199 /* copy other args 200 * $fp: sp top for args 201 * $t1: sp for next arg 202 */ 203 beq $t1,$fp,.Largs_done 204 andi $t3,$a2,0x1 205 srl $a2,1 206 bnez $t3,.Lpad 207 lw $t2,($t0) 208 addiu $t0,4 209 sw $t2,($t1) 210 .Lpad: 211 addiu $t1,4 212 b .Lloop1 213 214 .Largs_done: 215 216 /* 217 * We have copied args into stacks. Then copy argv[0]/argv[1] into 218 * reg a2/a3. You may find that if argv[0] is 32 bits and argv[1] 219 * is 64 bits, then we do not need to set reg a3 since it is a pad. 220 * However, copy a3 from argv is harmless. We do not need to set 221 * a0(pEnv)/a1(clazz/this) since they are already there. 222 */ 223 224 /* 225 * sp: new stack 226 * s0: pReturn 227 * s2: Return type 228 * 229 */ 230 lw $a2,8($sp) 231 lw $a3,12($sp) 232 233 /* Linux/PIC needs $t9 points to function address. 234 * call the function 235 */ 236 jalr $t9 237 238 /* function call return */ 239 /* 1. check the return type 240 * 2. if the return type is not DALVIK_JNI_RETURN_VOID then copy v0/v1 241 * to pReturn 242 */ 243 beqz $s2,.Lend /* don't set result if return type is void */ 244 245 #ifdef __mips_hard_float 246 mfc1 $t0,$f0 /* Get float ($f0) or double ($f1$f0) result */ 247 mfc1 $t1,$f1 248 sltiu $t2,$s2,3 /* set t2 if return type is float or double */ 249 #ifdef HAVE_LITTLE_ENDIAN 250 /* Note: for little endian, the double result is in $v1:$v0 and float result is in $v0 */ 251 movn $v0,$t0,$t2 /* If the result type is float or double overwrite $v1/$v0 */ 252 movn $v1,$t1,$t2 253 #else 254 /* Note: for big endian, the double result is in $v0:$v1 and float result is in $v0 */ 255 movn $v1,$t0,$t2 /* If the result type is float or double overwrite $v0/$v1 */ 256 movn $v0,$t1,$t2 257 sltiu $t3,$s2,2 /* set t3 if return type is float */ 258 movn $v0,$t0,$t3 /* If the result type is float overwrite $v0 */ 259 #endif 260 #endif 261 262 /* Store the result */ 263 sw $v0,0($s0) 264 sw $v1,4($s0) 265 266 .Lend: 267 /* restore saved registers */ 268 move $sp,$fp 269 lw $ra,20($sp) 270 lw $fp,16($sp) 271 lw $s0,12($sp) 272 lw $s2,4($sp) 273 addiu $sp,FSIZE 274 jr $ra 275 276 /* Slow path - just tail call the generic routine */ 277 .Lno_arginfo: 278 279 la $t9,dvmPlatformInvokeFFI 280 j $t9 281 282 .end dvmPlatformInvoke 283