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