* Removed all Id tags.
[cacao.git] / src / vm / jit / powerpc / md.c
1 /* src/vm/jit/powerpc/md.c - machine dependent PowerPC 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
32 #include "vm/types.h"
33
34 #include "md-abi.h"
35 #include "vm/jit/powerpc/codegen.h"
36
37 #include "vm/global.h"
38
39 #include "vm/jit/asmpart.h"
40 #include "vm/jit/stacktrace.h"
41
42 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
43 # include "vm/jit/disass.h" /* XXX debug */
44 # include "vmcore/options.h" /* XXX debug */
45 #endif
46
47
48 /* md_init *********************************************************************
49
50    Do some machine dependent initialization.
51
52 *******************************************************************************/
53
54 void md_init(void)
55 {
56         /* nothing to do */
57 }
58
59
60 /* md_stacktrace_get_returnaddress *********************************************
61
62    Returns the return address of the current stackframe, specified by
63    the passed stack pointer and the stack frame size.
64
65 *******************************************************************************/
66
67 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
68 {
69         u1 *ra;
70
71         /* on PowerPC the return address is located in the linkage area */
72
73         ra = *((u1 **) (sp + framesize + LA_LR_OFFSET));
74
75         return ra;
76 }
77
78
79 /* md_get_method_patch_address *************************************************
80
81    Gets the patch address of the currently compiled method. The offset
82    is extracted from the load instruction(s) before the jump and added
83    to the right base address (PV or REG_METHODPTR).
84
85    INVOKESTATIC/SPECIAL:
86
87    81adffd4    lwz     r13,-44(r13)
88    7da903a6    mtctr   r13
89    4e800421    bctrl
90
91    INVOKEVIRTUAL:
92
93    81830000    lwz     r12,0(r3)
94    81ac0000    lwz     r13,0(r12)
95    7da903a6    mtctr   r13
96    4e800421    bctrl
97
98    INVOKEINTERFACE:
99
100    81830000    lwz     r12,0(r3)
101    818c0000    lwz     r12,0(r12)
102    81ac0000    lwz     r13,0(r12)
103    7da903a6    mtctr   r13
104    4e800421    bctrl
105
106 *******************************************************************************/
107
108 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
109 {
110         u4  mcode;
111         s4  offset;
112         u1 *pa;
113
114         /* go back to the actual load instruction (3 instructions) */
115
116         ra = ra - 3 * 4;
117
118         /* get first instruction word (lwz) */
119
120         mcode = *((u4 *) ra);
121
122         /* check if we have 2 instructions (addis, addi) */
123
124         if ((mcode >> 16) == 0x3c19) {
125                 /* XXX write a regression for this */
126                 pa = NULL;
127                 assert(0);
128
129                 /* get displacement of first instruction (addis) */
130
131                 offset = (s4) (mcode << 16);
132
133                 /* get displacement of second instruction (addi) */
134
135                 mcode = *((u4 *) (ra + 1 * 4));
136
137                 assert((mcode >> 16) != 0x6739);
138
139                 offset += (s2) (mcode & 0x0000ffff);
140         }
141         else {
142                 /* get the offset from the instruction */
143
144                 offset = (s2) (mcode & 0x0000ffff);
145
146                 /* check for load from PV */
147
148                 if ((mcode >> 16) == 0x81ad) {
149                         /* get the final data segment address */
150
151                         pa = sfi->pv + offset;
152                 }
153                 else if ((mcode >> 16) == 0x81ac) {
154                         /* in this case we use the passed method pointer */
155
156                         /* return NULL if no mptr was specified (used for replacement) */
157
158                         if (mptr == NULL)
159                                 return NULL;
160
161                         pa = mptr + offset;
162                 }
163                 else {
164                         /* catch any problems */
165
166                         vm_abort("md_get_method_patch_address: unknown instruction %x",
167                                          mcode);
168
169                         /* keep compiler happy */
170
171                         pa = NULL;
172                 }
173         }
174
175         return pa;
176 }
177
178
179 /* md_codegen_get_pv_from_pc ***************************************************
180
181    Machine code:
182
183    7d6802a6    mflr    r11
184    39abffe0    addi    r13,r11,-32
185
186    or
187
188    7d6802a6    mflr    r11
189    3dabffff    addis   r13,r11,-1
190    39ad68b0    addi    r13,r13,26800
191
192 *******************************************************************************/
193
194 u1 *md_codegen_get_pv_from_pc(u1 *ra)
195 {
196         u1 *pv;
197         u4  mcode;
198         s4  offset;
199
200         /* get first instruction word after jump */
201
202         mcode = *((u4 *) (ra + 1 * 4));
203
204         /* check if we have 2 instructions (addis, addi) */
205
206         if ((mcode >> 16) == 0x3dab) {
207                 /* get displacement of first instruction (addis) */
208
209                 offset = (s4) (mcode << 16);
210
211                 /* get displacement of second instruction (addi) */
212
213                 mcode = *((u4 *) (ra + 2 * 4));
214
215                 /* check for addi instruction */
216
217                 assert((mcode >> 16) == 0x39ad);
218
219                 offset += (s2) (mcode & 0x0000ffff);
220
221         } else {
222                 /* check for addi instruction */
223
224                 assert((mcode >> 16) == 0x39ab);
225
226                 /* get offset of first instruction (addi) */
227
228                 offset = (s2) (mcode & 0x0000ffff);
229         }
230
231         /* calculate PV via RA + offset */
232
233         pv = ra + offset;
234
235         return pv;
236 }
237
238
239 /* md_cacheflush ***************************************************************
240
241    Calls the system's function to flush the instruction and data
242    cache.
243
244 *******************************************************************************/
245
246 void md_cacheflush(u1 *addr, s4 nbytes)
247 {
248         asm_cacheflush(addr, nbytes);
249 }
250
251
252 /* md_icacheflush **************************************************************
253
254    Calls the system's function to flush the instruction cache.
255
256 *******************************************************************************/
257
258 void md_icacheflush(u1 *addr, s4 nbytes)
259 {
260         asm_cacheflush(addr, nbytes);
261 }
262
263
264 /* md_dcacheflush **************************************************************
265
266    Calls the system's function to flush the data cache.
267
268 *******************************************************************************/
269
270 void md_dcacheflush(u1 *addr, s4 nbytes)
271 {
272         asm_cacheflush(addr, nbytes);
273 }
274
275
276 /* md_patch_replacement_point **************************************************
277
278    Patch the given replacement point.
279
280 *******************************************************************************/
281
282 #if defined(ENABLE_REPLACEMENT)
283 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
284 {
285         u4 mcode;
286
287         if (index < 0) {
288                 /* restore the patched-over instruction */
289                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
290         }
291         else {
292                 /* save the current machine code */
293                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
294
295                 /* build the machine code for the patch */
296                 assert(0); /* XXX build trap instruction below */
297                 mcode = 0;
298
299                 /* write the new machine code */
300                 *(u4*)(rp->pc) = (u4) mcode;
301         }
302         
303 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
304         {
305                 u1* u1ptr = rp->pc;
306                 DISASSINSTR(u1ptr);
307                 fflush(stdout);
308         }
309 #endif
310                         
311         /* flush instruction cache */
312     md_icacheflush(rp->pc,4);
313 }
314 #endif /* defined(ENABLE_REPLACEMENT) */
315
316 /*
317  * These are local overrides for various environment variables in Emacs.
318  * Please do not remove this and leave it at the end of the file, where
319  * Emacs will automagically detect them.
320  * ---------------------------------------------------------------------
321  * Local variables:
322  * mode: c
323  * indent-tabs-mode: t
324  * c-basic-offset: 4
325  * tab-width: 4
326  * End:
327  * vim:noexpandtab:sw=4:ts=4:
328  */