d11f44643efe7a6a7b0a99f3164a72dc4f38380e
[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 7259 2007-01-30 13:58:35Z 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
45 /* md_init *********************************************************************
46
47    Do some machine dependent initialization.
48
49 *******************************************************************************/
50
51 void md_init(void)
52 {
53         /* do nothing here */
54 }
55
56
57 /* md_codegen_patch_branch *****************************************************
58
59    Back-patches a branch instruction.
60
61 *******************************************************************************/
62
63 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
64 {
65         s4 *mcodeptr;
66         s4  disp;                           /* branch displacement                */
67
68         /* calculate the patch position */
69
70         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
71
72         /* Calculate the branch displacement. */
73
74         disp = (targetmpc - branchmpc - 4) >> 2;
75
76         if ((disp < (s4) 0xff000000) || (disp > (s4) 0x00ffffff))
77                 vm_abort("md_codegen_patch_branch: branch displacement out of range: %d > +/-%d", disp, 0x00ffffff);
78
79         /* patch the branch instruction before the mcodeptr */
80
81         mcodeptr[-1] |= (disp & 0x00ffffff);
82 }
83
84
85 /* md_stacktrace_get_returnaddress *********************************************
86
87    Returns the return address of the current stackframe, specified by
88    the passed stack pointer and the stack frame size.
89
90 *******************************************************************************/
91
92 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
93 {
94         u1 *ra;
95
96         /*printf("md_stacktrace_get_returnaddress(): called (sp=%x, framesize=%d)\n", sp, framesize);*/
97
98         /* on ARM the return address is located on the top of the stackframe */
99         /* ATTENTION: this is only true for non-leaf methods !!! */
100         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
101
102         /*printf("md_stacktrace_get_returnaddress(): result (ra=%x)\n", ra);*/
103
104         return ra;
105 }
106
107
108 /* md_assembler_get_patch_address **********************************************
109
110    Gets the patch address of the currently compiled method. The offset
111    is extracted from the load instruction(s) before the jump and added
112    to the right base address (PV or REG_METHODPTR).
113
114    Machine code:
115
116    e51cc040    ldr   ip, [ip, #-64]
117    e1a0e00f    mov   lr, pc
118    e1a0f00c    mov   pc, ip
119
120    or
121
122    e590b000    ldr   fp, [r0]
123    e59bc000    ldr   ip, [fp]
124    e1a0e00f    mov   lr, pc
125    e1a0f00c    mov   pc, ip
126
127    How we find out the patching address to store new method pointer:
128     - loaded IP with LDR IP,[METHODPTR]?
129         yes=INVOKEVIRTUAL or INVOKEINTERFACE (things are easy!)
130     - loaded IP from data segment
131         yes=INVOKESTATIC or INVOKESPECIAL (things are complicated)
132         recompute pointer to data segment, maybe larger offset 
133
134 *******************************************************************************/
135
136 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
137 {
138         u4  mcode;
139         s4  offset;
140         u1 *pa;                             /* patch address                      */
141
142         /* sanity check: are we inside jit code? */
143
144         assert(*((u4 *) (ra - 2*4)) == 0xe1a0e00f /*MOV LR,PC*/);
145         assert(*((u4 *) (ra - 1*4)) == 0xe1a0f00c /*MOV PC,IP*/);
146
147         /* get the load instruction and offset */
148
149         mcode  = *((u4 *) (ra - 12));
150         offset = (s4) (mcode & 0x0fff);
151
152         assert ((mcode & 0xff70f000) == 0xe510c000);
153
154         if ((mcode & 0x000f0000) == 0x000b0000) {
155                 /* sanity check: offset was positive */
156
157                 assert((mcode & 0x00800000) == 0x00800000);
158
159                 /* we loaded from REG_METHODPTR */
160
161                 pa = mptr + offset;
162         }
163         else {
164                 /* sanity check: we loaded from REG_IP; offset was negative or zero */
165
166                 assert((mcode & 0x008f0000) == 0x000c0000 ||
167                        (mcode & 0x008f0fff) == 0x008c0000);
168
169                 /* we loaded from data segment; offset can be larger */
170
171                 mcode = *((u4 *) (ra - 4*4));
172
173                 /* check for "SUB IP, IP, #??, ROTL 12" */
174
175                 if ((mcode & 0xffffff00) == 0xe24cca00)
176                         offset += (s4) ((mcode & 0x00ff) << 12);
177
178                 /* and get the final data segment address */
179
180                 pa = sfi->pv - offset;        
181         }
182
183         return pa;
184 }
185
186
187 /* md_codegen_get_pv_from_pc ***************************************************
188
189    TODO: document me
190
191 *******************************************************************************/
192
193 u1 *md_codegen_get_pv_from_pc(u1 *ra)
194 {
195         u1 *pv;
196         u4  mcode1, mcode2, mcode3;
197
198         pv = ra;
199
200         /* this can either be a RECOMPUTE_IP in JIT code or a fake in asm_calljavafunction */
201         mcode1 = *((u4*) ra);
202         if ((mcode1 & 0xffffff00) == 0xe24fcf00 /*sub ip,pc,#__*/)
203                 pv -= (s4) ((mcode1 & 0x000000ff) <<  2);
204         else if ((mcode1 & 0xffffff00) == 0xe24fc000 /*sub ip,pc,#__*/)
205                 pv -= (s4) (mcode1 & 0x000000ff);
206         else {
207                 /* if this happens, we got an unexpected instruction at (*ra) */
208                 vm_abort("Unable to find method: %p (instr=%x)", ra, mcode1);
209         }
210
211         /* if we have a RECOMPUTE_IP there can be more than one instruction */
212         mcode2 = *((u4*) (ra + 4));
213         mcode3 = *((u4*) (ra + 8));
214         if ((mcode2 & 0xffffff00) == 0xe24ccb00 /*sub ip,ip,#__*/)
215                 pv -= (s4) ((mcode2 & 0x000000ff) << 10);
216         if ((mcode3 & 0xffffff00) == 0xe24cc700 /*sub ip,ip,#__*/)
217                 pv -= (s4) ((mcode3 & 0x000000ff) << 18);
218
219         /* we used PC-relative adressing; but now it is LR-relative */
220         pv += 8;
221
222         /* if we found our method the data segment has to be valid */
223         /* we check this by looking up the IsLeaf field, which has to be boolean */
224         assert( *((s4*)pv-4) == (s4)true || *((s4*)pv-4) == (s4)false ); 
225
226         return pv;
227 }
228
229
230 /* md_cacheflush ***************************************************************
231
232    Calls the system's function to flush the instruction and data
233    cache.
234
235 *******************************************************************************/
236
237 void md_cacheflush(u1 *addr, s4 nbytes)
238 {
239         asm_cacheflush(addr, nbytes);
240 }
241
242
243 /* md_icacheflush **************************************************************
244
245    Calls the system's function to flush the instruction cache.
246
247 *******************************************************************************/
248
249 void md_icacheflush(u1 *addr, s4 nbytes)
250 {
251         asm_cacheflush(addr, nbytes);
252 }
253
254
255 /* md_dcacheflush **************************************************************
256
257    Calls the system's function to flush the data cache.
258
259 *******************************************************************************/
260
261 void md_dcacheflush(u1 *addr, s4 nbytes)
262 {
263         asm_cacheflush(addr, nbytes);
264 }
265
266
267 /*
268  * These are local overrides for various environment variables in Emacs.
269  * Please do not remove this and leave it at the end of the file, where
270  * Emacs will automagically detect them.
271  * ---------------------------------------------------------------------
272  * Local variables:
273  * mode: c
274  * indent-tabs-mode: t
275  * c-basic-offset: 4
276  * tab-width: 4
277  * End:
278  * vim:noexpandtab:sw=4:ts=4:
279  */