* src/vm/jit/codegen-common.c (codegen_findmethod): Renamed to
[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 5233 2006-08-14 10:59:39Z 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 #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_stacktrace_get_returnaddress *********************************************
191
192    Returns the return address of the current stackframe, specified by
193    the passed stack pointer and the stack frame size.
194
195 *******************************************************************************/
196
197 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
198 {
199         u1 *ra;
200
201         /* on x86_64 the return address is above the current stack frame */
202
203         ra = *((u1 **) (sp + framesize));
204
205         return ra;
206 }
207
208
209 /* md_get_method_patch_address *************************************************
210
211    Gets the patch address of the currently compiled method. The offset
212    is extracted from the load instruction(s) before the jump and added
213    to the right base address (PV or REG_METHODPTR).
214
215    INVOKESTATIC/SPECIAL:
216
217    4d 8b 15 e2 fe ff ff             mov    -286(%rip),%r10
218    49 ff d2                         rex64Z callq  *%r10
219
220    INVOKEVIRTUAL:
221
222    4c 8b 17                         mov    (%rdi),%r10
223    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
224    48 ff d3                         rex64 callq  *%rax
225
226    INVOKEINTERFACE:
227
228    4c 8b 17                         mov    (%rdi),%r10
229    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
230    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
231    48 ff d3                         rex64 callq  *%r11
232
233 *******************************************************************************/
234
235 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
236 {
237         u1  mcode;
238         s4  offset;
239         u1 *pa;                             /* patch address                      */
240
241         /* go back to the actual call instruction (3-bytes) */
242
243         ra = ra - 3;
244
245         /* get the last byte of the call */
246
247         mcode = ra[2];
248
249         /* check for the different calls */
250
251         if (mcode == 0xd2) {
252                 /* INVOKESTATIC/SPECIAL */
253
254                 /* Get the offset from the instruction (the offset address is
255                    4-bytes before the call instruction). */
256
257                 offset = *((s4 *) (ra - 4));
258
259                 /* add the offset to the return address (IP-relative addressing) */
260
261                 pa = ra + offset;
262         }
263         else if (mcode == 0xd3) {
264                 /* INVOKEVIRTUAL/INTERFACE */
265
266                 /* Get the offset from the instruction (the offset address is
267                    4-bytes before the call instruction). */
268
269                 offset = *((s4 *) (ra - 4));
270
271                 /* add the offset to the method pointer */
272
273                 pa = mptr + offset;
274         }
275         else {
276                 /* catch any problems */
277
278                 assert(0);
279         }
280
281         return pa;
282 }
283
284
285 /* md_codegen_get_pv_from_pc ***************************************************
286
287    On this architecture just a wrapper function to
288    codegen_get_pv_from_pc.
289
290 *******************************************************************************/
291
292 u1 *md_codegen_get_pv_from_pc(u1 *ra)
293 {
294         u1 *pv;
295
296         /* Get the start address of the function which contains this
297        address from the method table. */
298
299         pv = codegen_get_pv_from_pc(ra);
300
301         return pv;
302 }
303
304
305 /* md_cacheflush ***************************************************************
306
307    Calls the system's function to flush the instruction and data
308    cache.
309
310 *******************************************************************************/
311
312 void md_cacheflush(u1 *addr, s4 nbytes)
313 {
314         /* do nothing */
315 }
316
317
318 /* md_icacheflush **************************************************************
319
320    Calls the system's function to flush the instruction cache.
321
322 *******************************************************************************/
323
324 void md_icacheflush(u1 *addr, s4 nbytes)
325 {
326         /* do nothing */
327 }
328
329
330 /* md_dcacheflush **************************************************************
331
332    Calls the system's function to flush the data cache.
333
334 *******************************************************************************/
335
336 void md_dcacheflush(u1 *addr, s4 nbytes)
337 {
338         /* do nothing */
339 }
340
341
342 /* md_patch_replacement_point **************************************************
343
344    Patch the given replacement point.
345
346 *******************************************************************************/
347
348 void md_patch_replacement_point(rplpoint *rp)
349 {
350     u8 mcode;
351
352         /* XXX this is probably unsafe! */
353
354         /* save the current machine code */
355         mcode = *(u8*)rp->pc;
356
357         /* write spinning instruction */
358         *(u2*)(rp->pc) = 0xebfe;
359
360         /* write 5th byte */
361         rp->pc[4] = (rp->mcode >> 32);
362
363         /* write first word */
364     *(u4*)(rp->pc) = (u4) rp->mcode;
365
366         /* store saved mcode */
367         rp->mcode = mcode;
368         
369 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
370         {
371                 u1* u1ptr = rp->pc;
372                 DISASSINSTR(u1ptr);
373                 fflush(stdout);
374         }
375 #endif
376                         
377     /* XXX if required asm_cacheflush(rp->pc,8); */
378 }
379
380 /*
381  * These are local overrides for various environment variables in Emacs.
382  * Please do not remove this and leave it at the end of the file, where
383  * Emacs will automagically detect them.
384  * ---------------------------------------------------------------------
385  * Local variables:
386  * mode: c
387  * indent-tabs-mode: t
388  * c-basic-offset: 4
389  * tab-width: 4
390  * End:
391  * vim:noexpandtab:sw=4:ts=4:
392  */