blob: e436d1e06aceda650baf37cb4ff98479ebb172fd [file] [log] [blame]
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001/*
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/*
26Function prototype:
27
28void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
29 const u4* argv, const char* signature, void* func, JValue* pReturn)
30
31The 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
37We receive a collection of 32-bit values which correspond to arguments from
38the interpreter (e.g. float occupies one, double occupies two). It's up to
39us to convert these into local calling conventions.
40
41Please 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
130dvmPlatformInvoke:
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
1581:
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