* src/vm/jit/x86_64/md.c: Fixed includes for cacaoh-changes.
[cacao.git] / src / vm / jit / x86_64 / md.c
1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux 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 7249 2007-01-29 19:32:52Z twisti $
26
27 */
28
29
30 #define _GNU_SOURCE
31
32 #include "config.h"
33
34 #include <assert.h>
35 #include <stdlib.h>
36 #include <ucontext.h>
37
38 #include "vm/jit/x86_64/md-abi.h"
39
40 #if defined(ENABLE_THREADS)
41 # include "threads/native/threads.h"
42 #endif
43
44 #include "vm/exceptions.h"
45 #include "vm/signallocal.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 /* md_init *********************************************************************
57
58    Do some machine dependent initialization.
59
60 *******************************************************************************/
61
62 void md_init(void)
63 {
64         /* nothing to do */
65 }
66
67
68 /* md_signal_handler_sigsegv ***************************************************
69
70    NullPointerException signal handler for hardware null pointer
71    check.
72
73 *******************************************************************************/
74
75 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
76 {
77         ucontext_t *_uc;
78         mcontext_t *_mc;
79         u1         *sp;
80         u1         *ra;
81         u1         *xpc;
82
83         _uc = (ucontext_t *) _p;
84         _mc = &_uc->uc_mcontext;
85
86         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
87            different to the ones in <ucontext.h>. */
88
89         sp  = (u1 *) _mc->gregs[REG_RSP];
90         xpc = (u1 *) _mc->gregs[REG_RIP];
91         ra  = xpc;                          /* return address is equal to xpc     */
92
93 #if 0
94         /* check for StackOverflowException */
95
96         threads_check_stackoverflow(sp);
97 #endif
98
99         _mc->gregs[REG_RAX] =
100                 (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
101
102         _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
103         _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
104 }
105
106
107 /* md_signal_handler_sigfpe ****************************************************
108
109    ArithmeticException signal handler for hardware divide by zero
110    check.
111
112 *******************************************************************************/
113
114 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
115 {
116         ucontext_t  *_uc;
117         mcontext_t  *_mc;
118         u1          *sp;
119         u1          *ra;
120         u1          *xpc;
121
122         _uc = (ucontext_t *) _p;
123         _mc = &_uc->uc_mcontext;
124
125         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
126            different to the ones in <ucontext.h>. */
127
128         sp  = (u1 *) _mc->gregs[REG_RSP];
129         xpc = (u1 *) _mc->gregs[REG_RIP];
130         ra  = xpc;                          /* return address is equal to xpc     */
131
132         _mc->gregs[REG_RAX] =
133                 (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
134
135         _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
136         _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
137 }
138
139
140 /* md_signal_handler_sigusr2 ***************************************************
141
142    Signal handler for profiling sampling.
143
144 *******************************************************************************/
145
146 #if defined(ENABLE_THREADS)
147 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
148 {
149         threadobject *t;
150         ucontext_t   *_uc;
151         mcontext_t   *_mc;
152         u1           *pc;
153
154         t = THREADOBJECT;
155
156         _uc = (ucontext_t *) _p;
157         _mc = &_uc->uc_mcontext;
158
159         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
160            different to the ones in <ucontext.h>. */
161
162         pc = (u1 *) _mc->gregs[REG_RIP];
163
164         t->pc = pc;
165 }
166 #endif
167
168
169 #if defined(ENABLE_THREADS)
170 void thread_restartcriticalsection(ucontext_t *_uc)
171 {
172         mcontext_t *_mc;
173         void       *pc;
174
175         _mc = &_uc->uc_mcontext;
176
177         pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]);
178
179         if (pc != NULL)
180                 _mc->gregs[REG_RIP] = (ptrint) pc;
181 }
182 #endif
183
184
185 /* md_codegen_patch_branch *****************************************************
186
187    Back-patches a branch instruction.
188
189 *******************************************************************************/
190
191 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
192 {
193         s4 *mcodeptr;
194         s4  disp;                           /* branch displacement                */
195
196         /* calculate the patch position */
197
198         mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
199
200         /* Calculate the branch displacement. */
201
202         disp = targetmpc - branchmpc;
203
204         /* I don't think we have to check for branch-displacement
205            overflow.  +/-2GB should be enough. */
206
207         /* patch the branch instruction before the mcodeptr */
208
209         mcodeptr[-1] = disp;
210 }
211
212
213 /* md_stacktrace_get_returnaddress *********************************************
214
215    Returns the return address of the current stackframe, specified by
216    the passed stack pointer and the stack frame size.
217
218 *******************************************************************************/
219
220 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
221 {
222         u1 *ra;
223
224         /* on x86_64 the return address is above the current stack frame */
225
226         ra = *((u1 **) (sp + framesize));
227
228         return ra;
229 }
230
231
232 /* md_get_method_patch_address *************************************************
233
234    Gets the patch address of the currently compiled method. The offset
235    is extracted from the load instruction(s) before the jump and added
236    to the right base address (PV or REG_METHODPTR).
237
238    INVOKESTATIC/SPECIAL:
239
240    4d 8b 15 e2 fe ff ff             mov    -286(%rip),%r10
241    49 ff d2                         rex64Z callq  *%r10
242
243    INVOKEVIRTUAL:
244
245    4c 8b 17                         mov    (%rdi),%r10
246    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
247    48 ff d3                         rex64 callq  *%rax
248
249    INVOKEINTERFACE:
250
251    4c 8b 17                         mov    (%rdi),%r10
252    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
253    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
254    48 ff d3                         rex64 callq  *%r11
255
256 *******************************************************************************/
257
258 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
259 {
260         u1  mcode;
261         s4  offset;
262         u1 *pa;                             /* patch address                      */
263
264         /* go back to the actual call instruction (3-bytes) */
265
266         ra = ra - 3;
267
268         /* get the last byte of the call */
269
270         mcode = ra[2];
271
272         /* check for the different calls */
273
274         if (mcode == 0xd2) {
275                 /* INVOKESTATIC/SPECIAL */
276
277                 /* Get the offset from the instruction (the offset address is
278                    4-bytes before the call instruction). */
279
280                 offset = *((s4 *) (ra - 4));
281
282                 /* add the offset to the return address (IP-relative addressing) */
283
284                 pa = ra + offset;
285         }
286         else if (mcode == 0xd3) {
287                 /* INVOKEVIRTUAL/INTERFACE */
288
289                 /* return NULL if no mptr was specified (used for replacement) */
290
291                 if (mptr == NULL)
292                         return NULL;
293
294                 /* Get the offset from the instruction (the offset address is
295                    4-bytes before the call instruction). */
296
297                 offset = *((s4 *) (ra - 4));
298
299                 /* add the offset to the method pointer */
300
301                 pa = mptr + offset;
302         }
303         else {
304                 /* catch any problems */
305
306                 assert(0);
307         }
308
309         return pa;
310 }
311
312
313 /* md_codegen_get_pv_from_pc ***************************************************
314
315    On this architecture just a wrapper function to
316    codegen_get_pv_from_pc.
317
318 *******************************************************************************/
319
320 u1 *md_codegen_get_pv_from_pc(u1 *ra)
321 {
322         u1 *pv;
323
324         /* Get the start address of the function which contains this
325        address from the method table. */
326
327         pv = codegen_get_pv_from_pc(ra);
328
329         return pv;
330 }
331
332
333 /* md_cacheflush ***************************************************************
334
335    Calls the system's function to flush the instruction and data
336    cache.
337
338 *******************************************************************************/
339
340 void md_cacheflush(u1 *addr, s4 nbytes)
341 {
342         /* do nothing */
343 }
344
345
346 /* md_icacheflush **************************************************************
347
348    Calls the system's function to flush the instruction cache.
349
350 *******************************************************************************/
351
352 void md_icacheflush(u1 *addr, s4 nbytes)
353 {
354         /* do nothing */
355 }
356
357
358 /* md_dcacheflush **************************************************************
359
360    Calls the system's function to flush the data cache.
361
362 *******************************************************************************/
363
364 void md_dcacheflush(u1 *addr, s4 nbytes)
365 {
366         /* do nothing */
367 }
368
369
370 /* md_patch_replacement_point **************************************************
371
372    Patch the given replacement point.
373
374 *******************************************************************************/
375
376 #if defined(ENABLE_REPLACEMENT)
377 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
378 {
379         s4 disp;
380         u8 mcode;
381
382         /* XXX this is probably unsafe! */
383
384         if (index < 0) {
385                 /* write spinning instruction */
386                 *(u2*)(rp->pc) = 0xebfe;
387
388                 /* write 5th byte */
389                 rp->pc[4] = savedmcode[4];
390
391                 /* write first word */
392                 *(u4*)(rp->pc) = *(u4*)(savedmcode);
393         }
394         else {
395                 /* save the current machine code */
396                 *(u4*)(savedmcode) = *(u4*)(rp->pc);
397                 savedmcode[4] = rp->pc[4];
398
399                 /* build the machine code for the patch */
400                 disp = (code->replacementstubs - rp->pc)
401                            + index * REPLACEMENT_STUB_SIZE
402                            - 5;
403
404                 mcode = 0xe9 | ((u8) disp << 8);
405
406                 /* write spinning instruction */
407                 *(u2*)(rp->pc) = 0xebfe;
408
409                 /* write 5th byte */
410                 rp->pc[4] = (mcode >> 32);
411
412                 /* write first word */
413                 *(u4*)(rp->pc) = (u4) mcode;
414         }
415
416 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
417         {
418                 u1* u1ptr = rp->pc;
419                 DISASSINSTR(u1ptr);
420                 fflush(stdout);
421         }
422 #endif
423                         
424     /* XXX if required asm_cacheflush(rp->pc,8); */
425 }
426 #endif /* defined(ENABLE_REPLACEMENT) */
427
428 /*
429  * These are local overrides for various environment variables in Emacs.
430  * Please do not remove this and leave it at the end of the file, where
431  * Emacs will automagically detect them.
432  * ---------------------------------------------------------------------
433  * Local variables:
434  * mode: c
435  * indent-tabs-mode: t
436  * c-basic-offset: 4
437  * tab-width: 4
438  * End:
439  * vim:noexpandtab:sw=4:ts=4:
440  */