Merged revisions 7501-7598 via svnmerge from
[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 7596 2007-03-28 21:05:53Z twisti $
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                 assert(0);
129
130                 /* get displacement of first instruction (addis) */
131
132                 offset = (s4) (mcode << 16);
133
134                 /* get displacement of second instruction (addi) */
135
136                 mcode = *((u4 *) (ra + 1 * 4));
137
138                 assert((mcode >> 16) != 0x6739);
139
140                 offset += (s2) (mcode & 0x0000ffff);
141
142         } else {
143                 /* get the offset from the instruction */
144
145                 offset = (s2) (mcode & 0x0000ffff);
146
147                 /* check for load from PV */
148
149                 if ((mcode >> 16) == 0x81ad) {
150                         /* get the final data segment address */
151
152                         pa = sfi->pv + offset;
153
154                 } else if ((mcode >> 16) == 0x81ac) {
155                         /* in this case we use the passed method pointer */
156
157                         /* return NULL if no mptr was specified (used for replacement) */
158
159                         if (mptr == NULL)
160                                 return NULL;
161
162                         pa = mptr + offset;
163
164                 } else {
165                         /* catch any problems */
166
167                         assert(0);
168                 }
169         }
170
171         return pa;
172 }
173
174
175 /* md_codegen_get_pv_from_pc ***************************************************
176
177    Machine code:
178
179    7d6802a6    mflr    r11
180    39abffe0    addi    r13,r11,-32
181
182    or
183
184    7d6802a6    mflr    r11
185    3dabffff    addis   r13,r11,-1
186    39ad68b0    addi    r13,r13,26800
187
188 *******************************************************************************/
189
190 u1 *md_codegen_get_pv_from_pc(u1 *ra)
191 {
192         u1 *pv;
193         u4  mcode;
194         s4  offset;
195
196         /* get first instruction word after jump */
197
198         mcode = *((u4 *) (ra + 1 * 4));
199
200         /* check if we have 2 instructions (addis, addi) */
201
202         if ((mcode >> 16) == 0x3dab) {
203                 /* get displacement of first instruction (addis) */
204
205                 offset = (s4) (mcode << 16);
206
207                 /* get displacement of second instruction (addi) */
208
209                 mcode = *((u4 *) (ra + 2 * 4));
210
211                 /* check for addi instruction */
212
213                 assert((mcode >> 16) == 0x39ad);
214
215                 offset += (s2) (mcode & 0x0000ffff);
216
217         } else {
218                 /* check for addi instruction */
219
220                 assert((mcode >> 16) == 0x39ab);
221
222                 /* get offset of first instruction (addi) */
223
224                 offset = (s2) (mcode & 0x0000ffff);
225         }
226
227         /* calculate PV via RA + offset */
228
229         pv = ra + offset;
230
231         return pv;
232 }
233
234
235 /* md_cacheflush ***************************************************************
236
237    Calls the system's function to flush the instruction and data
238    cache.
239
240 *******************************************************************************/
241
242 void md_cacheflush(u1 *addr, s4 nbytes)
243 {
244         asm_cacheflush(addr, nbytes);
245 }
246
247
248 /* md_icacheflush **************************************************************
249
250    Calls the system's function to flush the instruction cache.
251
252 *******************************************************************************/
253
254 void md_icacheflush(u1 *addr, s4 nbytes)
255 {
256         asm_cacheflush(addr, nbytes);
257 }
258
259
260 /* md_dcacheflush **************************************************************
261
262    Calls the system's function to flush the data cache.
263
264 *******************************************************************************/
265
266 void md_dcacheflush(u1 *addr, s4 nbytes)
267 {
268         asm_cacheflush(addr, nbytes);
269 }
270
271
272 /* md_patch_replacement_point **************************************************
273
274    Patch the given replacement point.
275
276 *******************************************************************************/
277
278 #if defined(ENABLE_REPLACEMENT)
279 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
280 {
281         s4 disp;
282         u4 mcode;
283
284         if (index < 0) {
285                 /* restore the patched-over instruction */
286                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
287         }
288         else {
289                 /* save the current machine code */
290                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
291
292                 /* build the machine code for the patch */
293                 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
294                            + index * REPLACEMENT_STUB_SIZE
295                            - 1;
296
297         mcode = (18 << 26) | ((((disp) * 4) + 4) & M_BMASK);
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  */