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