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