* src/vm/jit/x86_64/md.c (md_signal_handler_sigusr2): Fixed comment.
[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 5172 2006-07-25 15:33:58Z twisti $
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         _mc->gregs[REG_RAX] =
99                 (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
100
101         _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
102         _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
103 }
104
105
106 /* md_signal_handler_sigfpe ****************************************************
107
108    ArithmeticException signal handler for hardware divide by zero
109    check.
110
111 *******************************************************************************/
112
113 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
114 {
115         ucontext_t  *_uc;
116         mcontext_t  *_mc;
117         u1          *sp;
118         u1          *ra;
119         u1          *xpc;
120
121         _uc = (ucontext_t *) _p;
122         _mc = &_uc->uc_mcontext;
123
124         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
125            different to the ones in <ucontext.h>. */
126
127         sp  = (u1 *) _mc->gregs[REG_RSP];
128         xpc = (u1 *) _mc->gregs[REG_RIP];
129         ra  = xpc;                          /* return address is equal to xpc     */
130
131         _mc->gregs[REG_RAX] =
132                 (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
133
134         _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
135         _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
136 }
137
138
139 /* md_signal_handler_sigusr2 ***************************************************
140
141    Signal handler for profiling sampling.
142
143 *******************************************************************************/
144
145 #if defined(ENABLE_THREADS)
146 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
147 {
148         threadobject *t;
149         ucontext_t   *_uc;
150         mcontext_t   *_mc;
151         u1           *pc;
152
153         t = THREADOBJECT;
154
155         _uc = (ucontext_t *) _p;
156         _mc = &_uc->uc_mcontext;
157
158         /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
159            different to the ones in <ucontext.h>. */
160
161         pc = (u1 *) _mc->gregs[REG_RIP];
162
163         t->pc = pc;
164 }
165 #endif
166
167
168 #if defined(ENABLE_THREADS)
169 void thread_restartcriticalsection(ucontext_t *_uc)
170 {
171         mcontext_t *_mc;
172         void       *pc;
173
174         _mc = &_uc->uc_mcontext;
175
176         pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]);
177
178         if (pc != NULL)
179                 _mc->gregs[REG_RIP] = (ptrint) pc;
180 }
181 #endif
182
183
184 /* md_stacktrace_get_returnaddress *********************************************
185
186    Returns the return address of the current stackframe, specified by
187    the passed stack pointer and the stack frame size.
188
189 *******************************************************************************/
190
191 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
192 {
193         u1 *ra;
194
195         /* on x86_64 the return address is above the current stack frame */
196
197         ra = *((u1 **) (sp + framesize));
198
199         return ra;
200 }
201
202
203 /* md_get_method_patch_address *************************************************
204
205    Gets the patch address of the currently compiled method. The offset
206    is extracted from the load instruction(s) before the jump and added
207    to the right base address (PV or REG_METHODPTR).
208
209    INVOKESTATIC/SPECIAL:
210
211    49 ba 98 3a ed ab aa 2a 00 00    mov    $0x2aaaabed3a98,%r10
212    49 ff d2                         rex64Z callq  *%r10
213
214    INVOKEVIRTUAL:
215
216    4c 8b 17                         mov    (%rdi),%r10
217    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
218    48 ff d3                         rex64 callq  *%rax
219
220    INVOKEINTERFACE:
221
222    4c 8b 17                         mov    (%rdi),%r10
223    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
224    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
225    48 ff d3                         rex64 callq  *%r11
226
227 *******************************************************************************/
228
229 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
230 {
231         u1  mcode;
232         s4  offset;
233         u1 *pa;                             /* patch address                      */
234
235         /* go back to the actual call instruction (3-bytes) */
236
237         ra = ra - 3;
238
239         /* get the last byte of the call */
240
241         mcode = ra[2];
242
243         /* check for the different calls */
244
245         /* INVOKESTATIC/SPECIAL */
246
247         if (mcode == 0xd2) {
248                 /* patch address is 8-bytes before the call instruction */
249
250                 pa = ra - 8;
251
252         } else if (mcode == 0xd3) {
253                 /* INVOKEVIRTUAL/INTERFACE */
254
255                 /* Get the offset from the instruction (the offset address is
256                    4-bytes before the call instruction). */
257
258                 offset = *((s4 *) (ra - 4));
259
260                 /* add the offset to the method pointer */
261
262                 pa = mptr + offset;
263
264         } else {
265                 /* catch any problems */
266
267                 assert(0);
268         }
269
270         return pa;
271 }
272
273
274 /* md_codegen_findmethod *******************************************************
275
276    On this architecture just a wrapper function to codegen_findmethod.
277
278 *******************************************************************************/
279
280 u1 *md_codegen_findmethod(u1 *ra)
281 {
282         u1 *pv;
283
284         /* the the start address of the function which contains this
285        address from the method table */
286
287         pv = codegen_findmethod(ra);
288
289         return pv;
290 }
291
292
293 /* md_cacheflush ***************************************************************
294
295    Calls the system's function to flush the instruction and data
296    cache.
297
298 *******************************************************************************/
299
300 void md_cacheflush(u1 *addr, s4 nbytes)
301 {
302         /* do nothing */
303 }
304
305
306 /* md_icacheflush **************************************************************
307
308    Calls the system's function to flush the instruction cache.
309
310 *******************************************************************************/
311
312 void md_icacheflush(u1 *addr, s4 nbytes)
313 {
314         /* do nothing */
315 }
316
317
318 /* md_dcacheflush **************************************************************
319
320    Calls the system's function to flush the data cache.
321
322 *******************************************************************************/
323
324 void md_dcacheflush(u1 *addr, s4 nbytes)
325 {
326         /* do nothing */
327 }
328
329
330 /* md_patch_replacement_point **************************************************
331
332    Patch the given replacement point.
333
334 *******************************************************************************/
335
336 void md_patch_replacement_point(rplpoint *rp)
337 {
338     u8 mcode;
339
340         /* XXX this is probably unsafe! */
341
342         /* save the current machine code */
343         mcode = *(u8*)rp->pc;
344
345         /* write spinning instruction */
346         *(u2*)(rp->pc) = 0xebfe;
347
348         /* write 5th byte */
349         rp->pc[4] = (rp->mcode >> 32);
350
351         /* write first word */
352     *(u4*)(rp->pc) = (u4) rp->mcode;
353
354         /* store saved mcode */
355         rp->mcode = mcode;
356         
357 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
358         {
359                 u1* u1ptr = rp->pc;
360                 DISASSINSTR(u1ptr);
361                 fflush(stdout);
362         }
363 #endif
364                         
365     /* XXX if required asm_cacheflush(rp->pc,8); */
366 }
367
368 /*
369  * These are local overrides for various environment variables in Emacs.
370  * Please do not remove this and leave it at the end of the file, where
371  * Emacs will automagically detect them.
372  * ---------------------------------------------------------------------
373  * Local variables:
374  * mode: c
375  * indent-tabs-mode: t
376  * c-basic-offset: 4
377  * tab-width: 4
378  * End:
379  * vim:noexpandtab:sw=4:ts=4:
380  */