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