* src/vm/builtin.c (builtin_throw_exception): Changed return type and
[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 4673 2006-03-22 15:30:06Z edwin $
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_assembler_get_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    Machine code:
126
127    a77bffb8    ldq     pv,-72(pv)
128    6b5b4000    jsr     (pv)
129
130    or
131
132    a77c0000    ldq     pv,0(at)
133    6b5b4000    jsr     (pv)
134
135 *******************************************************************************/
136
137 u1 *md_assembler_get_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                         pa = mptr + offset;
184
185                 } else {
186                         /* in the normal case we check for a `ldq pv,-72(pv)' instruction */
187
188                         assert((mcode >> 16) == 0xa77b);
189
190                         /* and get the final data segment address */
191
192                         pa = sfi->pv + offset;
193                 }
194         }
195
196         return pa;
197 }
198
199
200 /* md_codegen_findmethod *******************************************************
201
202    Machine code:
203
204    6b5b4000    jsr     (pv)
205    277afffe    ldah    pv,-2(ra)
206    237ba61c    lda     pv,-23012(pv)
207
208 *******************************************************************************/
209
210 u1 *md_codegen_findmethod(u1 *ra)
211 {
212         u1 *pv;
213         u4  mcode;
214         s4  offset;
215
216         pv = ra;
217
218         /* get first instruction word after jump */
219
220         mcode = *((u4 *) ra);
221
222         /* check if we have 2 instructions (ldah, lda) */
223
224         if ((mcode >> 16) == 0x277a) {
225                 /* get displacement of first instruction (ldah) */
226
227                 offset = (s4) (mcode << 16);
228                 pv += offset;
229
230                 /* get displacement of second instruction (lda) */
231
232                 mcode = *((u4 *) (ra + 1 * 4));
233
234                 assert((mcode >> 16) == 0x237b);
235
236                 offset = (s2) (mcode & 0x0000ffff);
237                 pv += offset;
238
239         } else {
240                 /* get displacement of first instruction (lda) */
241
242                 assert((mcode >> 16) == 0x237a);
243
244                 offset = (s2) (mcode & 0x0000ffff);
245                 pv += offset;
246         }
247
248         return pv;
249 }
250
251
252 /* md_cacheflush ***************************************************************
253
254    Calls the system's function to flush the instruction and data
255    cache.
256
257 *******************************************************************************/
258
259 void md_cacheflush(u1 *addr, s4 nbytes)
260 {
261         asm_cacheflush(addr, nbytes);
262 }
263
264
265 /* md_icacheflush **************************************************************
266
267    Calls the system's function to flush the instruction cache.
268
269 *******************************************************************************/
270
271 void md_icacheflush(u1 *addr, s4 nbytes)
272 {
273         asm_cacheflush(addr, nbytes);
274 }
275
276
277 /* md_patch_replacement_point **************************************************
278
279    Patch the given replacement point.
280
281 *******************************************************************************/
282
283 void md_patch_replacement_point(rplpoint *rp)
284 {
285     u8 mcode;
286
287         /* save the current machine code */
288         mcode = *(u4*)rp->pc;
289
290         /* write the new machine code */
291     *(u4*)(rp->pc) = (u4) rp->mcode;
292
293         /* store saved mcode */
294         rp->mcode = mcode;
295         
296 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
297         {
298                 u1* u1ptr = rp->pc;
299                 DISASSINSTR(u1ptr);
300                 fflush(stdout);
301         }
302 #endif
303                         
304         /* flush instruction cache */
305     md_icacheflush(rp->pc,4);
306 }
307
308 /*
309  * These are local overrides for various environment variables in Emacs.
310  * Please do not remove this and leave it at the end of the file, where
311  * Emacs will automagically detect them.
312  * ---------------------------------------------------------------------
313  * Local variables:
314  * mode: c
315  * indent-tabs-mode: t
316  * c-basic-offset: 4
317  * tab-width: 4
318  * End:
319  * vim:noexpandtab:sw=4:ts=4:
320  */