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