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