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