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