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