ccfb4b11fee7586d4a01a025a78e83d42e655c09
[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: 
30
31    $Id: md.c 4498 2006-02-12 23:43:09Z twisti $
32
33 */
34
35
36 #include "config.h"
37
38 #include <assert.h>
39 #include <sys/mman.h>
40 #include <unistd.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
49 void docacheflush(u1 *p, long bytelen)
50 {
51         u1 *e = p + bytelen;
52         long psize = sysconf(_SC_PAGESIZE);
53         p -= (long) p & (psize - 1);
54         e += psize - ((((long) e - 1) & (psize - 1)) + 1);
55         bytelen = e-p;
56         mprotect(p, bytelen, PROT_READ | PROT_WRITE | PROT_EXEC);
57 }
58
59
60 /* md_stacktrace_get_returnaddress *********************************************
61
62    Returns the return address of the current stackframe, specified by
63    the passed stack pointer and the stack frame size.
64
65 *******************************************************************************/
66
67 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
68 {
69         u1 *ra;
70
71         /* on MIPS the return address is located on the top of the stackframe */
72
73         /* XXX change this if we ever want to use 4-byte stackslots */
74         /* ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P)); */
75         ra = *((u1 **) (sp + framesize - 8));
76
77         return ra;
78 }
79
80
81 /* md_assembler_get_patch_address **********************************************
82
83    Gets the patch address of the currently compiled method. The offset
84    is extracted from the load instruction(s) before the jump and added
85    to the right base address (PV or REG_METHODPTR).
86
87 *******************************************************************************/
88
89 u1 *md_assembler_get_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
90 {
91         u4  mcode;
92         s4  offset;
93         u1 *pa;
94
95         /* go back to the actual load instruction (3 instructions on MIPS) */
96
97         ra -= 3 * 4;
98
99         /* get first instruction word on current PC */
100
101         mcode = *((u4 *) ra);
102
103         /* check if we have 2 instructions (lui) */
104
105         if ((mcode >> 16) == 0x3c19) {
106                 /* XXX write a regression for this */
107                 assert(0);
108
109                 /* get displacement of first instruction (lui) */
110
111                 offset = (s4) (mcode << 16);
112
113                 /* get displacement of second instruction (daddiu) */
114
115                 mcode = *((u4 *) (ra + 1 * 4));
116
117                 assert((mcode >> 16) != 0x6739);
118
119                 offset += (s2) (mcode & 0x0000ffff);
120
121         } else {
122                 /* get first instruction (ld) */
123
124                 mcode = *((u4 *) ra);
125
126                 /* get the offset from the instruction */
127
128                 offset = (s2) (mcode & 0x0000ffff);
129
130                 /* check for call with REG_METHODPTR: ld s8,x(t9) */
131
132 #if SIZEOF_VOID_P == 8
133                 if ((mcode >> 16) == 0xdf3e) {
134 #else
135                 if ((mcode >> 16) == 0x8f3e) {
136 #endif
137                         /* in this case we use the passed method pointer */
138
139                         pa = mptr + offset;
140
141                 } else {
142                         /* in the normal case we check for a `ld s8,x(s8)' instruction */
143
144 #if SIZEOF_VOID_P == 8
145                         assert((mcode >> 16) == 0xdfde);
146 #else
147                         assert((mcode >> 16) == 0x8fde);
148 #endif
149
150                         /* and get the final data segment address */
151
152                         pa = sfi->pv + offset;
153                 }
154         }
155
156         return pa;
157 }
158
159
160 /* md_codegen_findmethod *******************************************************
161
162    Machine code:
163
164    03c0f809    jalr     s8
165    00000000    nop
166    27feff9c    addiu    s8,ra,-100
167
168 *******************************************************************************/
169
170 u1 *md_codegen_findmethod(u1 *ra)
171 {
172         u1 *pv;
173         u4  mcode;
174         s4  offset;
175
176         /* get the offset of the instructions */
177
178         /* get first instruction word after jump */
179
180         mcode = *((u4 *) ra);
181
182         /* check if we have 2 instructions (lui, daddiu) */
183
184         if ((mcode >> 16) == 0x3c19) {
185                 /* get displacement of first instruction (lui) */
186
187                 offset = (s4) (mcode << 16);
188
189                 /* get displacement of second instruction (daddiu) */
190
191                 mcode = *((u4 *) (ra + 1 * 4));
192
193 #if SIZEOF_VOID_P == 8
194                 assert((mcode >> 16) == 0x6739);
195 #else   
196                 assert((mcode >> 16) == 0x2739);
197 #endif
198
199                 offset += (s2) (mcode & 0x0000ffff);
200
201         } else {
202                 /* get offset of first instruction (daddiu) */
203
204                 mcode = *((u4 *) ra);
205
206 #if SIZEOF_VOID_P == 8
207                 assert((mcode >> 16) == 0x67fe);
208 #else
209                 assert((mcode >> 16) == 0x27fe);
210 #endif
211
212                 offset = (s2) (mcode & 0x0000ffff);
213         }
214
215         /* calculate PV via RA + offset */
216
217         pv = ra + offset;
218
219         return pv;
220 }
221
222
223 /*
224  * These are local overrides for various environment variables in Emacs.
225  * Please do not remove this and leave it at the end of the file, where
226  * Emacs will automagically detect them.
227  * ---------------------------------------------------------------------
228  * Local variables:
229  * mode: c
230  * indent-tabs-mode: t
231  * c-basic-offset: 4
232  * tab-width: 4
233  * End:
234  */