Home | History | Annotate | Download | only in mips
      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