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