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