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