61d33173929bff6a4263fe4abda2e531cd1b8688
[cacao.git] / src / vm / jit / arm / md.c
1 /* src/vm/jit/arm/md.c - machine dependent Arm functions
2
3    Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25    $Id: md.c 7504 2007-03-12 13:17:07Z twisti $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33
34 #include "vm/types.h"
35
36 #include "vm/jit/arm/md-abi.h"
37
38 #include "vm/exceptions.h"
39 #include "vm/global.h"
40
41 #include "vm/jit/asmpart.h"
42 #include "vm/jit/md.h"
43
44 #include "vm/jit/codegen-common.h" /* REMOVE ME: for codegendata */
45
46
47 /* md_init *********************************************************************
48
49    Do some machine dependent initialization.
50
51 *******************************************************************************/
52
53 void md_init(void)
54 {
55         /* do nothing here */
56 }
57
58
59 /* md_codegen_patch_branch *****************************************************
60
61    Back-patches a branch instruction.
62
63 *******************************************************************************/
64
65 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
66 {
67         s4 *mcodeptr;
68         s4  disp;                           /* branch displacement                */
69
70         /* calculate the patch position */
71
72         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
73
74         /* Calculate the branch displacement. */
75
76         disp = (targetmpc - branchmpc - 4) >> 2;
77
78         if ((disp < (s4) 0xff000000) || (disp > (s4) 0x00ffffff))
79                 vm_abort("md_codegen_patch_branch: branch displacement out of range: %d > +/-%d", disp, 0x00ffffff);
80
81         /* patch the branch instruction before the mcodeptr */
82
83         mcodeptr[-1] |= (disp & 0x00ffffff);
84 }
85
86
87 /* md_stacktrace_get_returnaddress *********************************************
88
89    Returns the return address of the current stackframe, specified by
90    the passed stack pointer and the stack frame size.
91
92 *******************************************************************************/
93
94 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
95 {
96         u1 *ra;
97
98         /*printf("md_stacktrace_get_returnaddress(): called (sp=%x, framesize=%d)\n", sp, framesize);*/
99
100         /* on ARM the return address is located on the top of the stackframe */
101         /* ATTENTION: this is only true for non-leaf methods !!! */
102         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
103
104         /*printf("md_stacktrace_get_returnaddress(): result (ra=%x)\n", ra);*/
105
106         return ra;
107 }
108
109
110 /* md_assembler_get_patch_address **********************************************
111
112    Gets the patch address of the currently compiled method. The offset
113    is extracted from the load instruction(s) before the jump and added
114    to the right base address (PV or REG_METHODPTR).
115
116    Machine code:
117
118    e51cc040    ldr   ip, [ip, #-64]
119    e1a0e00f    mov   lr, pc
120    e1a0f00c    mov   pc, ip
121
122    or
123
124    e590b000    ldr   fp, [r0]
125    e59bc000    ldr   ip, [fp]
126    e1a0e00f    mov   lr, pc
127    e1a0f00c    mov   pc, ip
128
129    How we find out the patching address to store new method pointer:
130     - loaded IP with LDR IP,[METHODPTR]?
131         yes=INVOKEVIRTUAL or INVOKEINTERFACE (things are easy!)
132     - loaded IP from data segment
133         yes=INVOKESTATIC or INVOKESPECIAL (things are complicated)
134         recompute pointer to data segment, maybe larger offset 
135
136 *******************************************************************************/
137
138 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
139 {
140         u4  mcode;
141         s4  offset;
142         u1 *pa;                             /* patch address                      */
143
144         /* sanity check: are we inside jit code? */
145
146         assert(*((u4 *) (ra - 2*4)) == 0xe1a0e00f /*MOV LR,PC*/);
147         assert(*((u4 *) (ra - 1*4)) == 0xe1a0f00c /*MOV PC,IP*/);
148
149         /* get the load instruction and offset */
150
151         mcode  = *((u4 *) (ra - 12));
152         offset = (s4) (mcode & 0x0fff);
153
154         assert ((mcode & 0xff70f000) == 0xe510c000);
155
156         if ((mcode & 0x000f0000) == 0x000b0000) {
157                 /* sanity check: offset was positive */
158
159                 assert((mcode & 0x00800000) == 0x00800000);
160
161                 /* we loaded from REG_METHODPTR */
162
163                 pa = mptr + offset;
164         }
165         else {
166                 /* sanity check: we loaded from REG_IP; offset was negative or zero */
167
168                 assert((mcode & 0x008f0000) == 0x000c0000 ||
169                        (mcode & 0x008f0fff) == 0x008c0000);
170
171                 /* we loaded from data segment; offset can be larger */
172
173                 mcode = *((u4 *) (ra - 4*4));
174
175                 /* check for "SUB IP, IP, #??, ROTL 12" */
176
177                 if ((mcode & 0xffffff00) == 0xe24cca00)
178                         offset += (s4) ((mcode & 0x00ff) << 12);
179
180                 /* and get the final data segment address */
181
182                 pa = sfi->pv - offset;        
183         }
184
185         return pa;
186 }
187
188
189 /* md_codegen_get_pv_from_pc ***************************************************
190
191    TODO: document me
192
193 *******************************************************************************/
194
195 u1 *md_codegen_get_pv_from_pc(u1 *ra)
196 {
197         u1 *pv;
198         u4  mcode1, mcode2, mcode3;
199
200         pv = ra;
201
202         /* this can either be a RECOMPUTE_IP in JIT code or a fake in asm_calljavafunction */
203         mcode1 = *((u4*) ra);
204         if ((mcode1 & 0xffffff00) == 0xe24fcf00 /*sub ip,pc,#__*/)
205                 pv -= (s4) ((mcode1 & 0x000000ff) <<  2);
206         else if ((mcode1 & 0xffffff00) == 0xe24fc000 /*sub ip,pc,#__*/)
207                 pv -= (s4) (mcode1 & 0x000000ff);
208         else {
209                 /* if this happens, we got an unexpected instruction at (*ra) */
210                 vm_abort("Unable to find method: %p (instr=%x)", ra, mcode1);
211         }
212
213         /* if we have a RECOMPUTE_IP there can be more than one instruction */
214         mcode2 = *((u4*) (ra + 4));
215         mcode3 = *((u4*) (ra + 8));
216         if ((mcode2 & 0xffffff00) == 0xe24ccb00 /*sub ip,ip,#__*/)
217                 pv -= (s4) ((mcode2 & 0x000000ff) << 10);
218         if ((mcode3 & 0xffffff00) == 0xe24cc700 /*sub ip,ip,#__*/)
219                 pv -= (s4) ((mcode3 & 0x000000ff) << 18);
220
221         /* we used PC-relative adressing; but now it is LR-relative */
222         pv += 8;
223
224         /* if we found our method the data segment has to be valid */
225         /* we check this by looking up the IsLeaf field, which has to be boolean */
226         assert( *((s4*)pv-4) == (s4)true || *((s4*)pv-4) == (s4)false ); 
227
228         return pv;
229 }
230
231
232 /* md_cacheflush ***************************************************************
233
234    Calls the system's function to flush the instruction and data
235    cache.
236
237 *******************************************************************************/
238
239 void md_cacheflush(u1 *addr, s4 nbytes)
240 {
241         asm_cacheflush(addr, nbytes);
242 }
243
244
245 /* md_icacheflush **************************************************************
246
247    Calls the system's function to flush the instruction cache.
248
249 *******************************************************************************/
250
251 void md_icacheflush(u1 *addr, s4 nbytes)
252 {
253         asm_cacheflush(addr, nbytes);
254 }
255
256
257 /* md_dcacheflush **************************************************************
258
259    Calls the system's function to flush the data cache.
260
261 *******************************************************************************/
262
263 void md_dcacheflush(u1 *addr, s4 nbytes)
264 {
265         asm_cacheflush(addr, nbytes);
266 }
267
268
269 /*
270  * These are local overrides for various environment variables in Emacs.
271  * Please do not remove this and leave it at the end of the file, where
272  * Emacs will automagically detect them.
273  * ---------------------------------------------------------------------
274  * Local variables:
275  * mode: c
276  * indent-tabs-mode: t
277  * c-basic-offset: 4
278  * tab-width: 4
279  * End:
280  * vim:noexpandtab:sw=4:ts=4:
281  */