5de83eecfbffccbaaa18b5bef4504da5b74eedb8
[cacao.git] / src / vm / jit / alpha / md.c
1 /* src/vm/jit/alpha/md.c - machine dependent Alpha 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 8247 2007-07-31 12:06:44Z michi $
26
27 */
28
29
30 #include "config.h"
31
32 #include <assert.h>
33 #include <ucontext.h>
34
35 #if defined(__LINUX__)
36 # include <asm/fpu.h>
37
38 extern unsigned long ieee_get_fp_control();
39 extern void ieee_set_fp_control(unsigned long fp_control);
40 #endif
41
42 #include "vm/types.h"
43
44 #include "vm/jit/alpha/md-abi.h"
45
46 #include "vm/exceptions.h"
47 #include "vm/stringlocal.h"
48
49 #include "vm/jit/asmpart.h"
50 #include "vm/jit/stacktrace.h"
51
52 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
53 #include "vmcore/options.h" /* XXX debug */
54 #include "vm/jit/disass.h" /* XXX debug */
55 #endif
56
57
58 /* global variables ***********************************************************/
59
60 bool has_ext_instr_set = false;             /* has instruction set extensions */
61
62
63 /* md_init *********************************************************************
64
65    Do some machine dependent initialization.
66
67 *******************************************************************************/
68
69 void md_init(void)
70 {
71         /* check for extended instruction set */
72
73         has_ext_instr_set = !asm_md_init();
74
75 #if defined(__LINUX__)
76         /* Linux on Digital Alpha needs an initialisation of the ieee
77            floating point control for IEEE compliant arithmetic (option
78            -mieee of GCC). Under Digital Unix this is done
79            automatically. */
80
81         /* initialize floating point control */
82
83         ieee_set_fp_control(ieee_get_fp_control()
84                                                 & ~IEEE_TRAP_ENABLE_INV
85                                                 & ~IEEE_TRAP_ENABLE_DZE
86 /*                                              & ~IEEE_TRAP_ENABLE_UNF   we dont want underflow */
87                                                 & ~IEEE_TRAP_ENABLE_OVF);
88 #endif
89 }
90
91
92 /* md_stacktrace_get_returnaddress *********************************************
93
94    Returns the return address of the current stackframe, specified by
95    the passed stack pointer and the stack frame size.
96
97 *******************************************************************************/
98
99 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
100 {
101         u1 *ra;
102
103         /* on Alpha the return address is located on the top of the stackframe */
104
105         ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
106
107         return ra;
108 }
109
110
111 /* md_get_method_patch_address *************************************************
112
113    Gets the patch address of the currently compiled method. The offset
114    is extracted from the load instruction(s) before the jump and added
115    to the right base address (PV or REG_METHODPTR).
116
117    INVOKESTATIC/SPECIAL:
118
119    a77bffb8    ldq     pv,-72(pv)
120    6b5b4000    jsr     (pv)
121
122    INVOKEVIRTUAL:
123
124    a7900000    ldq     at,0(a0)
125    a77c0000    ldq     pv,0(at)
126    6b5b4000    jsr     (pv)
127
128    INVOKEINTERFACE:
129
130    a7900000    ldq     at,0(a0)
131    a79cff98    ldq     at,-104(at)
132    a77c0018    ldq     pv,24(at)
133    6b5b4000    jsr     (pv)
134
135 *******************************************************************************/
136
137 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
138 {
139         u4  mcode;
140         s4  offset;
141         u1 *pa;                             /* patch address                      */
142
143         /* go back to the actual load instruction (2 instructions on Alpha) */
144
145         ra = ra - 2 * 4;
146
147         /* get first instruction word on current PC */
148
149         mcode = *((u4 *) ra);
150
151         /* check if we have 2 instructions (lui) */
152
153         if ((mcode >> 16) == 0x3c19) {
154                 /* XXX write a regression for this */
155                 assert(0);
156
157                 /* get displacement of first instruction (lui) */
158
159                 offset = (s4) (mcode << 16);
160
161                 /* get displacement of second instruction (daddiu) */
162
163                 mcode = *((u4 *) (ra + 1 * 4));
164
165                 assert((mcode >> 16) == 0x6739);
166
167                 offset += (s2) (mcode & 0x0000ffff);
168
169         } else {
170                 /* get first instruction (ldq) */
171
172                 mcode = *((u4 *) ra);
173
174                 /* get the offset from the instruction */
175
176                 offset = (s2) (mcode & 0x0000ffff);
177
178                 /* check for call with REG_METHODPTR: ldq pv,0(at) */
179
180                 if ((mcode >> 16) == 0xa77c) {
181                         /* in this case we use the passed method pointer */
182
183                         /* return NULL if no mptr was specified (used for replacement) */
184
185                         if (mptr == NULL)
186                                 return NULL;
187
188                         pa = mptr + offset;
189
190                 } else {
191                         /* in the normal case we check for a `ldq pv,-72(pv)' instruction */
192
193                         assert((mcode >> 16) == 0xa77b);
194
195                         /* and get the final data segment address */
196
197                         pa = sfi->pv + offset;
198                 }
199         }
200
201         return pa;
202 }
203
204
205 /* md_codegen_get_pv_from_pc ***************************************************
206
207    Machine code:
208
209    6b5b4000    jsr     (pv)
210    277afffe    ldah    pv,-2(ra)
211    237ba61c    lda     pv,-23012(pv)
212
213 *******************************************************************************/
214
215 u1 *md_codegen_get_pv_from_pc(u1 *ra)
216 {
217         u1 *pv;
218         u4  mcode;
219         s4  offset;
220
221         pv = ra;
222
223         /* get first instruction word after jump */
224
225         mcode = *((u4 *) ra);
226
227         /* check if we have 2 instructions (ldah, lda) */
228
229         if ((mcode >> 16) == 0x277a) {
230                 /* get displacement of first instruction (ldah) */
231
232                 offset = (s4) (mcode << 16);
233                 pv += offset;
234
235                 /* get displacement of second instruction (lda) */
236
237                 mcode = *((u4 *) (ra + 1 * 4));
238
239                 assert((mcode >> 16) == 0x237b);
240
241                 offset = (s2) (mcode & 0x0000ffff);
242                 pv += offset;
243         }
244         else {
245                 /* get displacement of first instruction (lda) */
246
247                 assert((mcode >> 16) == 0x237a);
248
249                 offset = (s2) (mcode & 0x0000ffff);
250                 pv += offset;
251         }
252
253         return pv;
254 }
255
256
257 /* md_cacheflush ***************************************************************
258
259    Calls the system's function to flush the instruction and data
260    cache.
261
262 *******************************************************************************/
263
264 void md_cacheflush(u1 *addr, s4 nbytes)
265 {
266         asm_cacheflush(addr, nbytes);
267 }
268
269
270 /* md_icacheflush **************************************************************
271
272    Calls the system's function to flush the instruction cache.
273
274 *******************************************************************************/
275
276 void md_icacheflush(u1 *addr, s4 nbytes)
277 {
278         asm_cacheflush(addr, nbytes);
279 }
280
281
282 /* md_patch_replacement_point **************************************************
283
284    Patch the given replacement point.
285
286 *******************************************************************************/
287
288 #if defined(ENABLE_REPLACEMENT)
289 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
290 {
291         u4 mcode;
292
293         if (index < 0) {
294                 /* restore the patched-over instruction */
295                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
296         }
297         else {
298                 /* save the current machine code */
299                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
300
301                 /* build the machine code for the patch */
302                 mcode = (0xa41f0000 | (EXCEPTION_HARDWARE_PATCHER));
303
304                 /* write the new machine code */
305                 *(u4*)(rp->pc) = mcode;
306         }
307         
308 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
309         {
310                 u1* u1ptr = rp->pc;
311                 DISASSINSTR(u1ptr);
312                 fflush(stdout);
313         }
314 #endif
315                         
316         /* flush instruction cache */
317     md_icacheflush(rp->pc,4);
318 }
319 #endif /* defined(ENABLE_REPLACEMENT) */
320
321
322 /*
323  * These are local overrides for various environment variables in Emacs.
324  * Please do not remove this and leave it at the end of the file, where
325  * Emacs will automagically detect them.
326  * ---------------------------------------------------------------------
327  * Local variables:
328  * mode: c
329  * indent-tabs-mode: t
330  * c-basic-offset: 4
331  * tab-width: 4
332  * End:
333  * vim:noexpandtab:sw=4:ts=4:
334  */