03c50c82d1508cdcc8c6262c8d6d5523fe165ff1
[cacao.git] / src / vm / jit / mips / md.c
1 /* src/vm/jit/mips/md.c - machine dependent MIPS 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    $Id: md.c 8247 2007-07-31 12:06:44Z michi $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <unistd.h>
34 #include <sys/cachectl.h>
35
36 #include "vm/types.h"
37
38 #include "toolbox/logging.h"
39
40 #include "vm/global.h"
41 #include "vm/vm.h"
42
43 #include "vm/jit/codegen-common.h" /* REMOVEME: only for codegendata */
44 #include "vm/jit/stacktrace.h"
45
46 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
47 #include "vmcore/options.h" /* XXX debug */
48 #include "vm/jit/disass.h" /* XXX debug */
49 #endif
50
51
52 /* md_stacktrace_get_returnaddress *********************************************
53
54    Returns the return address of the current stackframe, specified by
55    the passed stack pointer and the stack frame size.
56
57 *******************************************************************************/
58
59 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
60 {
61         u1 *ra;
62
63         /* on MIPS the return address is located on the top of the stackframe */
64
65         /* XXX change this if we ever want to use 4-byte stackslots */
66         /* ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P)); */
67         ra = *((u1 **) (sp + framesize - 8));
68
69         return ra;
70 }
71
72
73 /* md_get_method_patch_address *************************************************
74
75    Gets the patch address of the currently compiled method. The offset
76    is extracted from the load instruction(s) before the jump and added
77    to the right base address (PV or REG_METHODPTR).
78
79    INVOKESTATIC/SPECIAL:
80
81    dfdeffb8    ld       s8,-72(s8)
82    03c0f809    jalr     s8
83    00000000    nop
84
85    INVOKEVIRTUAL:
86
87    dc990000    ld       t9,0(a0)
88    df3e0000    ld       s8,0(t9)
89    03c0f809    jalr     s8
90    00000000    nop
91
92    INVOKEINTERFACE:
93
94    dc990000    ld       t9,0(a0)
95    df39ff90    ld       t9,-112(t9)
96    df3e0018    ld       s8,24(t9)
97    03c0f809    jalr     s8
98    00000000    nop
99
100 *******************************************************************************/
101
102 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
103 {
104         u4  mcode;
105         s4  offset;
106         u1 *pa;
107
108         /* go back to the actual load instruction (3 instructions on MIPS) */
109
110         ra -= 3 * 4;
111
112         /* get first instruction word on current PC */
113
114         mcode = *((u4 *) ra);
115
116         /* check if we have 2 instructions (lui) */
117
118         if ((mcode >> 16) == 0x3c19) {
119                 /* XXX write a regression for this */
120                 assert(0);
121
122                 /* get displacement of first instruction (lui) */
123
124                 offset = (s4) (mcode << 16);
125
126                 /* get displacement of second instruction (daddiu) */
127
128                 mcode = *((u4 *) (ra + 1 * 4));
129
130                 assert((mcode >> 16) != 0x6739);
131
132                 offset += (s2) (mcode & 0x0000ffff);
133
134                 pa = NULL;
135         }
136         else {
137                 /* get first instruction (ld) */
138
139                 mcode = *((u4 *) ra);
140
141                 /* get the offset from the instruction */
142
143                 offset = (s2) (mcode & 0x0000ffff);
144
145                 /* check for call with REG_METHODPTR: ld s8,x(t9) */
146
147 #if SIZEOF_VOID_P == 8
148                 if ((mcode >> 16) == 0xdf3e) {
149 #else
150                 if ((mcode >> 16) == 0x8f3e) {
151 #endif
152                         /* in this case we use the passed method pointer */
153
154                         /* return NULL if no mptr was specified (used for replacement) */
155
156                         if (mptr == NULL)
157                                 return NULL;
158
159                         pa = mptr + offset;
160                 }
161                 else {
162                         /* in the normal case we check for a `ld s8,x(s8)' instruction */
163
164 #if SIZEOF_VOID_P == 8
165                         assert((mcode >> 16) == 0xdfde);
166 #else
167                         assert((mcode >> 16) == 0x8fde);
168 #endif
169
170                         /* and get the final data segment address */
171
172                         pa = sfi->pv + offset;
173                 }
174         }
175
176         return pa;
177 }
178
179
180 /* md_codegen_get_pv_from_pc ***************************************************
181
182    Machine code:
183
184    03c0f809    jalr     s8
185    00000000    nop
186    27feff9c    addiu    s8,ra,-100
187
188 *******************************************************************************/
189
190 u1 *md_codegen_get_pv_from_pc(u1 *ra)
191 {
192         u1 *pv;
193         u4  mcode;
194         s4  offset;
195
196         /* get the offset of the instructions */
197
198         /* get first instruction word after jump */
199
200         mcode = *((u4 *) ra);
201
202         /* check if we have 2 instructions (lui, daddiu) */
203
204         if ((mcode >> 16) == 0x3c19) {
205                 /* get displacement of first instruction (lui) */
206
207                 offset = (s4) (mcode << 16);
208
209                 /* get displacement of second instruction (daddiu) */
210
211                 mcode = *((u4 *) (ra + 1 * 4));
212
213 #if SIZEOF_VOID_P == 8
214                 assert((mcode >> 16) == 0x6739);
215 #else
216                 assert((mcode >> 16) == 0x2739);
217 #endif
218
219                 offset += (s2) (mcode & 0x0000ffff);
220         }
221         else {
222                 /* get offset of first instruction (daddiu) */
223
224                 mcode = *((u4 *) ra);
225
226 #if SIZEOF_VOID_P == 8
227                 assert((mcode >> 16) == 0x67fe);
228 #else
229                 assert((mcode >> 16) == 0x27fe);
230 #endif
231
232                 offset = (s2) (mcode & 0x0000ffff);
233         }
234
235         /* calculate PV via RA + offset */
236
237         pv = ra + offset;
238
239         return pv;
240 }
241
242
243 /* md_cacheflush ***************************************************************
244
245    Calls the system's function to flush the instruction and data
246    cache.
247
248 *******************************************************************************/
249
250 void md_cacheflush(u1 *addr, s4 nbytes)
251 {
252         cacheflush(addr, nbytes, BCACHE);
253 }
254
255
256 /* md_icacheflush **************************************************************
257
258    Calls the system's function to flush the instruction cache.
259
260 *******************************************************************************/
261
262 void md_icacheflush(u1 *addr, s4 nbytes)
263 {
264         cacheflush(addr, nbytes, ICACHE);
265 }
266
267
268 /* md_dcacheflush **************************************************************
269
270    Calls the system's function to flush the data cache.
271
272 *******************************************************************************/
273
274 void md_dcacheflush(u1 *addr, s4 nbytes)
275 {
276         cacheflush(addr, nbytes, DCACHE);
277 }
278
279
280 /* md_patch_replacement_point **************************************************
281
282    Patch the given replacement point.
283
284 *******************************************************************************/
285
286 #if defined(ENABLE_REPLACEMENT)
287 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp,
288                                                                 u1 *savedmcode)
289 {
290         union {
291                 u8 both;
292                 u4 words[2];
293         } mcode;
294
295         if (index < 0) {
296                 /* restore the patched-over instruction */
297                 *(u8*)(rp->pc) = *(u8*)(savedmcode);
298         }
299         else {
300                 /* save the current machine code */
301                 *(u8*)(savedmcode) = *(u8*)(rp->pc);
302
303                 /* build the machine code for the patch */
304                 assert(0); /* XXX build trap instruction below */
305                 mcode.both = 0;
306
307                 /* write the new machine code */
308                 *(u8*)(rp->pc) = mcode.both;
309         }
310
311 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
312         {
313                 u1* u1ptr = rp->pc;
314                 DISASSINSTR(u1ptr);
315                 DISASSINSTR(u1ptr);
316                 fflush(stdout);
317         }
318 #endif
319
320         /* flush instruction cache */
321     md_icacheflush(rp->pc,2*4);
322 }
323 #endif /* defined(ENABLE_REPLACEMENT) */
324
325 /*
326  * These are local overrides for various environment variables in Emacs.
327  * Please do not remove this and leave it at the end of the file, where
328  * Emacs will automagically detect them.
329  * ---------------------------------------------------------------------
330  * Local variables:
331  * mode: c
332  * indent-tabs-mode: t
333  * c-basic-offset: 4
334  * tab-width: 4
335  * End:
336  * vim:noexpandtab:sw=4:ts=4:
337  */