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