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