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