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