* src/mm/cacao-gc/gc.h: Added GC_EXECUTIONSTATE and GC_SOURCESTATE defines.
[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 7483 2007-03-08 13:17:40Z 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_codegen_patch_branch *****************************************************
53
54    Back-patches a branch instruction.
55
56 *******************************************************************************/
57
58 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
59 {
60         s4 *mcodeptr;
61         s4  mcode;
62         s4  disp;                           /* branch displacement                */
63         s4  lo;
64         s4  hi;
65
66         /* calculate the patch position */
67
68         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
69
70         /* get the instruction before the exception point */
71
72         mcode = mcodeptr[-1];
73
74         /* check for: ori t9,t9,0 */
75
76         if ((mcode >> 16) == 0x3739) {
77                 /* Calculate the branch displacement.  For jumps we need a
78                    displacement relative to PV. */
79
80                 disp = targetmpc;
81
82         lo = (short) disp;
83         hi = (short) ((disp - lo) >> 16);
84
85                 /* patch the two instructions before the mcodeptr */
86
87                 mcodeptr[-2] |= (hi & 0x0000ffff);
88                 mcodeptr[-1] |= (lo & 0x0000ffff);
89         }
90         else {
91                 /* Calculate the branch displacement.  For branches we need a
92                    displacement relative and shifted to the branch PC. */
93
94                 disp = (targetmpc - branchmpc) >> 2;
95
96                 /* On the MIPS we can only branch signed 16-bit instruction words
97                    (signed 18-bit = 32KB = +/- 16KB). Check this! */
98
99                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff))
100                         vm_abort("jump displacement is out of range: %d > +/-%d", disp, 0x00007fff);
101
102                 /* patch the branch instruction before the mcodeptr */
103
104                 mcodeptr[-1] |= (disp & 0x0000ffff);
105         }
106 }
107
108
109 /* md_stacktrace_get_returnaddress *********************************************
110
111    Returns the return address of the current stackframe, specified by
112    the passed stack pointer and the stack frame size.
113
114 *******************************************************************************/
115
116 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
117 {
118         u1 *ra;
119
120         /* on MIPS the return address is located on the top of the stackframe */
121
122         /* XXX change this if we ever want to use 4-byte stackslots */
123         /* ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P)); */
124         ra = *((u1 **) (sp + framesize - 8));
125
126         return ra;
127 }
128
129
130 /* md_get_method_patch_address *************************************************
131
132    Gets the patch address of the currently compiled method. The offset
133    is extracted from the load instruction(s) before the jump and added
134    to the right base address (PV or REG_METHODPTR).
135
136    INVOKESTATIC/SPECIAL:
137
138    dfdeffb8    ld       s8,-72(s8)
139    03c0f809    jalr     s8
140    00000000    nop
141
142    INVOKEVIRTUAL:
143
144    dc990000    ld       t9,0(a0)
145    df3e0000    ld       s8,0(t9)
146    03c0f809    jalr     s8
147    00000000    nop
148
149    INVOKEINTERFACE:
150
151    dc990000    ld       t9,0(a0)
152    df39ff90    ld       t9,-112(t9)
153    df3e0018    ld       s8,24(t9)
154    03c0f809    jalr     s8
155    00000000    nop
156
157 *******************************************************************************/
158
159 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
160 {
161         u4  mcode;
162         s4  offset;
163         u1 *pa;
164
165         /* go back to the actual load instruction (3 instructions on MIPS) */
166
167         ra -= 3 * 4;
168
169         /* get first instruction word on current PC */
170
171         mcode = *((u4 *) ra);
172
173         /* check if we have 2 instructions (lui) */
174
175         if ((mcode >> 16) == 0x3c19) {
176                 /* XXX write a regression for this */
177                 assert(0);
178
179                 /* get displacement of first instruction (lui) */
180
181                 offset = (s4) (mcode << 16);
182
183                 /* get displacement of second instruction (daddiu) */
184
185                 mcode = *((u4 *) (ra + 1 * 4));
186
187                 assert((mcode >> 16) != 0x6739);
188
189                 offset += (s2) (mcode & 0x0000ffff);
190
191                 pa = NULL;
192         }
193         else {
194                 /* get first instruction (ld) */
195
196                 mcode = *((u4 *) ra);
197
198                 /* get the offset from the instruction */
199
200                 offset = (s2) (mcode & 0x0000ffff);
201
202                 /* check for call with REG_METHODPTR: ld s8,x(t9) */
203
204 #if SIZEOF_VOID_P == 8
205                 if ((mcode >> 16) == 0xdf3e) {
206 #else
207                 if ((mcode >> 16) == 0x8f3e) {
208 #endif
209                         /* in this case we use the passed method pointer */
210
211                         /* return NULL if no mptr was specified (used for replacement) */
212
213                         if (mptr == NULL)
214                                 return NULL;
215
216                         pa = mptr + offset;
217                 }
218                 else {
219                         /* in the normal case we check for a `ld s8,x(s8)' instruction */
220
221 #if SIZEOF_VOID_P == 8
222                         assert((mcode >> 16) == 0xdfde);
223 #else
224                         assert((mcode >> 16) == 0x8fde);
225 #endif
226
227                         /* and get the final data segment address */
228
229                         pa = sfi->pv + offset;
230                 }
231         }
232
233         return pa;
234 }
235
236
237 /* md_codegen_get_pv_from_pc ***************************************************
238
239    Machine code:
240
241    03c0f809    jalr     s8
242    00000000    nop
243    27feff9c    addiu    s8,ra,-100
244
245 *******************************************************************************/
246
247 u1 *md_codegen_get_pv_from_pc(u1 *ra)
248 {
249         u1 *pv;
250         u4  mcode;
251         s4  offset;
252
253         /* get the offset of the instructions */
254
255         /* get first instruction word after jump */
256
257         mcode = *((u4 *) ra);
258
259         /* check if we have 2 instructions (lui, daddiu) */
260
261         if ((mcode >> 16) == 0x3c19) {
262                 /* get displacement of first instruction (lui) */
263
264                 offset = (s4) (mcode << 16);
265
266                 /* get displacement of second instruction (daddiu) */
267
268                 mcode = *((u4 *) (ra + 1 * 4));
269
270 #if SIZEOF_VOID_P == 8
271                 assert((mcode >> 16) == 0x6739);
272 #else
273                 assert((mcode >> 16) == 0x2739);
274 #endif
275
276                 offset += (s2) (mcode & 0x0000ffff);
277         }
278         else {
279                 /* get offset of first instruction (daddiu) */
280
281                 mcode = *((u4 *) ra);
282
283 #if SIZEOF_VOID_P == 8
284                 assert((mcode >> 16) == 0x67fe);
285 #else
286                 assert((mcode >> 16) == 0x27fe);
287 #endif
288
289                 offset = (s2) (mcode & 0x0000ffff);
290         }
291
292         /* calculate PV via RA + offset */
293
294         pv = ra + offset;
295
296         return pv;
297 }
298
299
300 /* md_cacheflush ***************************************************************
301
302    Calls the system's function to flush the instruction and data
303    cache.
304
305 *******************************************************************************/
306
307 void md_cacheflush(u1 *addr, s4 nbytes)
308 {
309         cacheflush(addr, nbytes, BCACHE);
310 }
311
312
313 /* md_icacheflush **************************************************************
314
315    Calls the system's function to flush the instruction cache.
316
317 *******************************************************************************/
318
319 void md_icacheflush(u1 *addr, s4 nbytes)
320 {
321         cacheflush(addr, nbytes, ICACHE);
322 }
323
324
325 /* md_dcacheflush **************************************************************
326
327    Calls the system's function to flush the data cache.
328
329 *******************************************************************************/
330
331 void md_dcacheflush(u1 *addr, s4 nbytes)
332 {
333         cacheflush(addr, nbytes, DCACHE);
334 }
335
336
337 /* md_patch_replacement_point **************************************************
338
339    Patch the given replacement point.
340
341 *******************************************************************************/
342
343 #if defined(ENABLE_REPLACEMENT)
344 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp,
345                                                                 u1 *savedmcode)
346 {
347         s4 disp;
348         union {
349                 u8 both;
350                 u4 words[2];
351         } mcode;
352
353         if (index < 0) {
354                 /* restore the patched-over instruction */
355                 *(u8*)(rp->pc) = *(u8*)(savedmcode);
356         }
357         else {
358                 /* save the current machine code */
359                 *(u8*)(savedmcode) = *(u8*)(rp->pc);
360
361                 /* make machine code for patching */
362
363                 disp = ((u4*)code->replacementstubs - (u4*)rp->pc)
364                            + index * REPLACEMENT_STUB_SIZE
365                            - 1;
366
367                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff))
368                         vm_abort("Jump offset is out of range: %d > +/-%d",
369                                          disp, 0x00007fff);
370
371                 /* BR */
372         mcode.words[0] = (((0x04) << 26) | ((0) << 21) | ((0) << 16) | ((disp) & 0xffff));
373                 mcode.words[1] = 0; /* NOP in delay slot */ 
374
375                 /* write the new machine code */
376                 *(u8*)(rp->pc) = mcode.both;
377         }
378
379 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
380         {
381                 u1* u1ptr = rp->pc;
382                 DISASSINSTR(u1ptr);
383                 DISASSINSTR(u1ptr);
384                 fflush(stdout);
385         }
386 #endif
387
388         /* flush instruction cache */
389     md_icacheflush(rp->pc,2*4);
390 }
391 #endif /* defined(ENABLE_REPLACEMENT) */
392
393 /*
394  * These are local overrides for various environment variables in Emacs.
395  * Please do not remove this and leave it at the end of the file, where
396  * Emacs will automagically detect them.
397  * ---------------------------------------------------------------------
398  * Local variables:
399  * mode: c
400  * indent-tabs-mode: t
401  * c-basic-offset: 4
402  * tab-width: 4
403  * End:
404  * vim:noexpandtab:sw=4:ts=4:
405  */