* src/vm/jit/alpha/md.c (md_patch_replacement_point): Removed debug code.
[cacao.git] / src / vm / jit / powerpc / md.c
1 /* src/vm/jit/powerpc/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 #include "vm/jit/powerpc/codegen.h"
36
37 #include "vm/global.h"
38
39 #include "vm/jit/asmpart.h"
40 #include "vm/jit/stacktrace.h"
41
42
43 /* md_init *********************************************************************
44
45    Do some machine dependent initialization.
46
47 *******************************************************************************/
48
49 void md_init(void)
50 {
51         /* nothing to do */
52 }
53
54
55 /* md_stacktrace_get_returnaddress *********************************************
56
57    Returns the return address of the current stackframe, specified by
58    the passed stack pointer and the stack frame size.
59
60 *******************************************************************************/
61
62 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
63 {
64         u1 *ra;
65
66         /* on PowerPC the return address is located in the linkage area */
67
68         ra = *((u1 **) (sp + framesize + LA_LR_OFFSET));
69
70         return ra;
71 }
72
73
74 /* md_get_method_patch_address *************************************************
75
76    Gets the patch address of the currently compiled method. The offset
77    is extracted from the load instruction(s) before the jump and added
78    to the right base address (PV or REG_METHODPTR).
79
80    INVOKESTATIC/SPECIAL:
81
82    81adffd4    lwz     r13,-44(r13)
83    7da903a6    mtctr   r13
84    4e800421    bctrl
85
86    INVOKEVIRTUAL:
87
88    81830000    lwz     r12,0(r3)
89    81ac0000    lwz     r13,0(r12)
90    7da903a6    mtctr   r13
91    4e800421    bctrl
92
93    INVOKEINTERFACE:
94
95    81830000    lwz     r12,0(r3)
96    818c0000    lwz     r12,0(r12)
97    81ac0000    lwz     r13,0(r12)
98    7da903a6    mtctr   r13
99    4e800421    bctrl
100
101 *******************************************************************************/
102
103 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
104 {
105         u4  mcode;
106         s4  offset;
107         u1 *pa;
108
109         /* go back to the actual load instruction (3 instructions) */
110
111         ra = ra - 3 * 4;
112
113         /* get first instruction word (lwz) */
114
115         mcode = *((u4 *) ra);
116
117         /* check if we have 2 instructions (addis, addi) */
118
119         if ((mcode >> 16) == 0x3c19) {
120                 /* XXX write a regression for this */
121                 pa = NULL;
122                 assert(0);
123
124                 /* get displacement of first instruction (addis) */
125
126                 offset = (s4) (mcode << 16);
127
128                 /* get displacement of second instruction (addi) */
129
130                 mcode = *((u4 *) (ra + 1 * 4));
131
132                 assert((mcode >> 16) != 0x6739);
133
134                 offset += (s2) (mcode & 0x0000ffff);
135         }
136         else {
137                 /* get the offset from the instruction */
138
139                 offset = (s2) (mcode & 0x0000ffff);
140
141                 /* check for load from PV */
142
143                 if ((mcode >> 16) == 0x81ad) {
144                         /* get the final data segment address */
145
146                         pa = sfi->pv + offset;
147                 }
148                 else if ((mcode >> 16) == 0x81ac) {
149                         /* in this case we use the passed method pointer */
150
151                         /* return NULL if no mptr was specified (used for replacement) */
152
153                         if (mptr == NULL)
154                                 return NULL;
155
156                         pa = mptr + offset;
157                 }
158                 else {
159                         /* catch any problems */
160
161                         vm_abort("md_get_method_patch_address: unknown instruction %x",
162                                          mcode);
163
164                         /* keep compiler happy */
165
166                         pa = NULL;
167                 }
168         }
169
170         return pa;
171 }
172
173
174 /* md_codegen_get_pv_from_pc ***************************************************
175
176    Machine code:
177
178    7d6802a6    mflr    r11
179    39abffe0    addi    r13,r11,-32
180
181    or
182
183    7d6802a6    mflr    r11
184    3dabffff    addis   r13,r11,-1
185    39ad68b0    addi    r13,r13,26800
186
187 *******************************************************************************/
188
189 u1 *md_codegen_get_pv_from_pc(u1 *ra)
190 {
191         u1 *pv;
192         u4  mcode;
193         s4  offset;
194
195         /* get first instruction word after jump */
196
197         mcode = *((u4 *) (ra + 1 * 4));
198
199         /* check if we have 2 instructions (addis, addi) */
200
201         if ((mcode >> 16) == 0x3dab) {
202                 /* get displacement of first instruction (addis) */
203
204                 offset = (s4) (mcode << 16);
205
206                 /* get displacement of second instruction (addi) */
207
208                 mcode = *((u4 *) (ra + 2 * 4));
209
210                 /* check for addi instruction */
211
212                 assert((mcode >> 16) == 0x39ad);
213
214                 offset += (s2) (mcode & 0x0000ffff);
215
216         } else {
217                 /* check for addi instruction */
218
219                 assert((mcode >> 16) == 0x39ab);
220
221                 /* get offset of first instruction (addi) */
222
223                 offset = (s2) (mcode & 0x0000ffff);
224         }
225
226         /* calculate PV via RA + offset */
227
228         pv = ra + offset;
229
230         return pv;
231 }
232
233
234 /* md_cacheflush ***************************************************************
235
236    Calls the system's function to flush the instruction and data
237    cache.
238
239 *******************************************************************************/
240
241 void md_cacheflush(u1 *addr, s4 nbytes)
242 {
243         asm_cacheflush(addr, nbytes);
244 }
245
246
247 /* md_icacheflush **************************************************************
248
249    Calls the system's function to flush the instruction cache.
250
251 *******************************************************************************/
252
253 void md_icacheflush(u1 *addr, s4 nbytes)
254 {
255         asm_cacheflush(addr, nbytes);
256 }
257
258
259 /* md_dcacheflush **************************************************************
260
261    Calls the system's function to flush the data cache.
262
263 *******************************************************************************/
264
265 void md_dcacheflush(u1 *addr, s4 nbytes)
266 {
267         asm_cacheflush(addr, nbytes);
268 }
269
270
271 /* md_patch_replacement_point **************************************************
272
273    Patch the given replacement point.
274
275 *******************************************************************************/
276
277 #if defined(ENABLE_REPLACEMENT)
278 void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
279 {
280         u4 mcode;
281
282         if (revert) {
283                 /* restore the patched-over instruction */
284                 *(u4*)(pc) = *(u4*)(savedmcode);
285         }
286         else {
287                 /* save the current machine code */
288                 *(u4*)(savedmcode) = *(u4*)(pc);
289
290                 /* build the machine code for the patch */
291                 assert(0); /* XXX build trap instruction below */
292                 mcode = 0;
293
294                 /* write the new machine code */
295                 *(u4*)(pc) = (u4) mcode;
296         }
297         
298         /* flush instruction cache */
299     md_icacheflush(pc,4);
300 }
301 #endif /* defined(ENABLE_REPLACEMENT) */
302
303 /*
304  * These are local overrides for various environment variables in Emacs.
305  * Please do not remove this and leave it at the end of the file, where
306  * Emacs will automagically detect them.
307  * ---------------------------------------------------------------------
308  * Local variables:
309  * mode: c
310  * indent-tabs-mode: t
311  * c-basic-offset: 4
312  * tab-width: 4
313  * End:
314  * vim:noexpandtab:sw=4:ts=4:
315  */