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