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