src/vm/jit/powerpc64/md.c (md_get_method_patch_address): Fixed opcodes in
[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 5248 2006-08-17 17:51:40Z 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    e9ceffb8    ld      r14,-72(r14)     
92    7dc903a6    mtctr   r14              
93    4e800421    bctrl
94
95    INVOKEVIRTUAL:
96
97 FIXME   81830000    lwz     r12,0(r3)
98    e9cc0000     ld      r14,0(r12)
99    7dc903a6     mtctr   r14
100    4e800421     bctrl
101
102
103    INVOKEINTERFACE:
104
105 FIXME   81830000    lwz     r12,0(r3)
106 FIXME   818c0000    lwz     r12,0(r12)
107 FIXME   81ac0000    lwz     r13,0(r12)
108   7dc903a6    mtctr   r14
109   4e800421    bctrl
110
111 *******************************************************************************/
112
113 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
114 {
115         u4  mcode;
116         s4  offset;
117         u1 *pa;
118
119         /* go back to the actual load instruction (3 instructions) */
120
121         ra = ra - 3 * 4;
122
123         /* get first instruction word (lwz) */
124
125         mcode = *((u4 *) ra);
126
127         /* check if we have 2 instructions (addis, addi) */
128
129         if ((mcode >> 16) == 0x3c19) {
130                 /* XXX write a regression for this */
131                 assert(0);
132
133                 /* get displacement of first instruction (addis) */
134
135                 offset = (s4) (mcode << 16);
136
137                 /* get displacement of second instruction (addi) */
138
139                 mcode = *((u4 *) (ra + 1 * 4));
140
141                 assert((mcode >> 16) != 0x6739);
142
143                 offset += (s2) (mcode & 0x0000ffff);
144
145         } else {
146                 /* get the offset from the instruction */
147
148                 offset = (s2) (mcode & 0x0000ffff);
149
150                 /* check for load from PV */
151
152                 if ((mcode >> 16) == 0xe9ce) {  
153                         /* get the final data segment address */
154
155                         pa = sfi->pv + offset;
156
157                 } else if ((mcode >> 16) == 0xe9cc) { 
158                         /* in this case we use the passed method pointer */
159
160                         pa = mptr + offset;
161
162                 } else {
163                         /* catch any problems */
164
165                         assert(0);
166                 }
167         }
168
169         return pa;
170 }
171
172
173 /* md_codegen_get_pv_from_pc ***************************************************
174
175    Machine code:
176
177    7d6802a6    mflr    r11
178    39cbffe0    addi    r14r11,-32
179
180    or
181
182    7d6802a6    mflr    r11
183    3dcbffff    addis   r14r11,-1
184    39ce68b0    addi    r14,r13,26800
185
186 *******************************************************************************/
187
188 u1 *md_codegen_get_pv_from_pc(u1 *ra)
189 {
190         u1 *pv;
191         u4  mcode;
192         s4  offset;
193
194         /* get first instruction word after jump */
195
196         mcode = *((u4 *) (ra + 1 * 4));
197
198         /* check if we have 2 instructions (addis, addi) */
199
200         if ((mcode >> 16) == 0x3dcb) {
201                 /* get displacement of first instruction (addis) */
202
203                 offset = (s4) (mcode << 16);
204
205                 /* get displacement of second instruction (addi) */
206
207                 mcode = *((u4 *) (ra + 2 * 4));
208
209                 /* check for addi instruction */
210
211                 assert((mcode >> 16) == 0x39ce);
212
213                 offset += (s2) (mcode & 0x0000ffff);
214
215         } else {
216                 /* check for addi instruction */
217
218                 assert((mcode >> 16) == 0x39cb);
219
220                 /* get offset of first instruction (addi) */
221
222                 offset = (s2) (mcode & 0x0000ffff);
223         }
224
225         /* calculate PV via RA + offset */
226
227         pv = ra + offset;
228
229         return pv;
230 }
231
232
233 /* md_cacheflush ***************************************************************
234
235    Calls the system's function to flush the instruction and data
236    cache.
237
238 *******************************************************************************/
239
240 void md_cacheflush(u1 *addr, s4 nbytes)
241 {
242         asm_cacheflush(addr, nbytes);
243 }
244
245
246 /* md_icacheflush **************************************************************
247
248    Calls the system's function to flush the instruction cache.
249
250 *******************************************************************************/
251
252 void md_icacheflush(u1 *addr, s4 nbytes)
253 {
254         asm_cacheflush(addr, nbytes);
255 }
256
257
258 /* md_dcacheflush **************************************************************
259
260    Calls the system's function to flush the data cache.
261
262 *******************************************************************************/
263
264 void md_dcacheflush(u1 *addr, s4 nbytes)
265 {
266         asm_cacheflush(addr, nbytes);
267 }
268
269
270 /* md_patch_replacement_point **************************************************
271
272    Patch the given replacement point.
273
274 *******************************************************************************/
275
276 void md_patch_replacement_point(rplpoint *rp)
277 {
278     u8 mcode;
279
280         /* save the current machine code */
281         mcode = *(u4*)rp->pc;
282
283         /* write the new machine code */
284     *(u4*)(rp->pc) = (u4) rp->mcode;
285
286         /* store saved mcode */
287         rp->mcode = mcode;
288         
289 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
290         {
291                 u1* u1ptr = rp->pc;
292                 DISASSINSTR(u1ptr);
293                 fflush(stdout);
294         }
295 #endif
296                         
297         /* flush instruction cache */
298     md_icacheflush(rp->pc,4);
299 }
300
301 /*
302  * These are local overrides for various environment variables in Emacs.
303  * Please do not remove this and leave it at the end of the file, where
304  * Emacs will automagically detect them.
305  * ---------------------------------------------------------------------
306  * Local variables:
307  * mode: c
308  * indent-tabs-mode: t
309  * c-basic-offset: 4
310  * tab-width: 4
311  * End:
312  * vim:noexpandtab:sw=4:ts=4:
313  */