CallO32.S revision a8b91c52fd8a90b784835dfe1f8898035266c4dd
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/*
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
283