e07b3532a403235a399b08f41329f42902982a76
[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 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
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                 pa = NULL;
172                 assert(0);
173
174                 /* get displacement of first instruction (addis) */
175
176                 offset = (s4) (mcode << 16);
177
178                 /* get displacement of second instruction (addi) */
179
180                 mcode = *((u4 *) (ra + 1 * 4));
181
182                 assert((mcode >> 16) != 0x6739);
183
184                 offset += (s2) (mcode & 0x0000ffff);
185         }
186         else {
187                 /* get the offset from the instruction */
188
189                 offset = (s2) (mcode & 0x0000ffff);
190
191                 /* check for load from PV */
192
193                 if ((mcode >> 16) == 0xe9ce) {  
194                         /* get the final data segment address */
195
196                         pa = sfi->pv + offset;
197                 }
198                 else if ((mcode >> 16) == 0xe9cc) { 
199                         /* in this case we use the passed method pointer */
200
201                         /* return NULL if no mptr was specified (used for replacement) */
202
203                         if (mptr == NULL)
204                                 return NULL;
205
206                         pa = mptr + offset;
207                 }
208                 else {
209                         /* catch any problems */
210
211                         vm_abort("md_get_method_patch_address: unknown instruction %x",
212                                          mcode);
213
214                         /* keep compiler happy */
215
216                         pa = NULL;
217                 }
218         }
219
220         return pa;
221 }
222
223
224 /* md_codegen_get_pv_from_pc ***************************************************
225
226    Machine code:
227
228    7d6802a6    mflr    r11
229    39cbffe0    addi    r14,r11,-32
230
231    or
232
233    7d6802a6    mflr    r11
234    3dcbffff    addis   r14,r11,-1
235    39ce68b0    addi    r14,r13,26800
236
237 *******************************************************************************/
238
239 u1 *md_codegen_get_pv_from_pc(u1 *ra)
240 {
241         u1 *pv;
242         u4  mcode;
243         s4  offset;
244
245         /* get first instruction word after jump */
246
247         mcode = *((u4 *) (ra + 1 * 4));
248
249         /* check if we have 2 instructions (addis, addi) */
250
251         if ((mcode >> 16) == 0x3dcb) {
252                 /* get displacement of first instruction (addis) */
253
254                 offset = (s4) (mcode << 16);
255
256                 /* get displacement of second instruction (addi) */
257
258                 mcode = *((u4 *) (ra + 2 * 4));
259
260                 /* check for addi instruction */
261
262                 assert((mcode >> 16) == 0x39ce);
263
264                 offset += (s2) (mcode & 0x0000ffff);
265         }
266         else if ((mcode >> 16) == 0x39cb) {
267                 /* get offset of first instruction (addi) */
268
269                 offset = (s2) (mcode & 0x0000ffff);
270         }
271         else {
272                 vm_abort("md_codegen_get_pv_from_pc: unknown instruction %x", mcode);
273
274                 /* keep compiler happy */
275
276                 offset = 0;
277         }
278
279         /* calculate PV via RA + offset */
280
281         pv = ra + offset;
282
283         return pv;
284 }
285
286
287 /* md_cacheflush ***************************************************************
288
289    Calls the system's function to flush the instruction and data
290    cache.
291
292 *******************************************************************************/
293
294 void md_cacheflush(u1 *addr, s4 nbytes)
295 {
296         asm_cacheflush(addr, nbytes);
297 }
298
299
300 /* md_icacheflush **************************************************************
301
302    Calls the system's function to flush the instruction cache.
303
304 *******************************************************************************/
305
306 void md_icacheflush(u1 *addr, s4 nbytes)
307 {
308         asm_cacheflush(addr, nbytes);
309 }
310
311
312 /* md_dcacheflush **************************************************************
313
314    Calls the system's function to flush the data cache.
315
316 *******************************************************************************/
317
318 void md_dcacheflush(u1 *addr, s4 nbytes)
319 {
320         asm_cacheflush(addr, nbytes);
321 }
322
323
324 /* md_patch_replacement_point **************************************************
325
326    Patch the given replacement point.
327
328 *******************************************************************************/
329
330 #if defined(ENABLE_REPLACEMENT)
331 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
332 {
333         u4 mcode;
334
335         if (index < 0) {
336                 /* restore the patched-over instruction */
337                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
338         }
339         else {
340                 /* save the current machine code */
341                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
342
343                 /* build the machine code for the patch */
344                 assert(0); /* XXX build trap instruction below */
345                 mcode = 0;
346
347                 /* write the new machine code */
348                 *(u4*)(rp->pc) = (u4) mcode;
349         }
350         
351 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
352         {
353                 u1* u1ptr = rp->pc;
354                 DISASSINSTR(u1ptr);
355                 fflush(stdout);
356         }
357 #endif
358                         
359         /* flush instruction cache */
360     md_icacheflush(rp->pc,4);
361 }
362 #endif /* defined(ENABLE_REPLACEMENT) */
363
364 /*
365  * These are local overrides for various environment variables in Emacs.
366  * Please do not remove this and leave it at the end of the file, where
367  * Emacs will automagically detect them.
368  * ---------------------------------------------------------------------
369  * Local variables:
370  * mode: c
371  * indent-tabs-mode: t
372  * c-basic-offset: 4
373  * tab-width: 4
374  * End:
375  * vim:noexpandtab:sw=4:ts=4:
376  */