1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
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
8 This file is part of CACAO.
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.
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.
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
25 $Id: md.c 7249 2007-01-29 19:32:52Z twisti $
38 #include "vm/jit/x86_64/md-abi.h"
40 #if defined(ENABLE_THREADS)
41 # include "threads/native/threads.h"
44 #include "vm/exceptions.h"
45 #include "vm/signallocal.h"
47 #include "vm/jit/asmpart.h"
48 #include "vm/jit/stacktrace.h"
50 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
51 #include "vmcore/options.h" /* XXX debug */
52 #include "vm/jit/disass.h" /* XXX debug */
56 /* md_init *********************************************************************
58 Do some machine dependent initialization.
60 *******************************************************************************/
68 /* md_signal_handler_sigsegv ***************************************************
70 NullPointerException signal handler for hardware null pointer
73 *******************************************************************************/
75 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
83 _uc = (ucontext_t *) _p;
84 _mc = &_uc->uc_mcontext;
86 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
87 different to the ones in <ucontext.h>. */
89 sp = (u1 *) _mc->gregs[REG_RSP];
90 xpc = (u1 *) _mc->gregs[REG_RIP];
91 ra = xpc; /* return address is equal to xpc */
94 /* check for StackOverflowException */
96 threads_check_stackoverflow(sp);
100 (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
102 _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */
103 _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
107 /* md_signal_handler_sigfpe ****************************************************
109 ArithmeticException signal handler for hardware divide by zero
112 *******************************************************************************/
114 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
122 _uc = (ucontext_t *) _p;
123 _mc = &_uc->uc_mcontext;
125 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
126 different to the ones in <ucontext.h>. */
128 sp = (u1 *) _mc->gregs[REG_RSP];
129 xpc = (u1 *) _mc->gregs[REG_RIP];
130 ra = xpc; /* return address is equal to xpc */
132 _mc->gregs[REG_RAX] =
133 (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
135 _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */
136 _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
140 /* md_signal_handler_sigusr2 ***************************************************
142 Signal handler for profiling sampling.
144 *******************************************************************************/
146 #if defined(ENABLE_THREADS)
147 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
156 _uc = (ucontext_t *) _p;
157 _mc = &_uc->uc_mcontext;
159 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
160 different to the ones in <ucontext.h>. */
162 pc = (u1 *) _mc->gregs[REG_RIP];
169 #if defined(ENABLE_THREADS)
170 void thread_restartcriticalsection(ucontext_t *_uc)
175 _mc = &_uc->uc_mcontext;
177 pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]);
180 _mc->gregs[REG_RIP] = (ptrint) pc;
185 /* md_codegen_patch_branch *****************************************************
187 Back-patches a branch instruction.
189 *******************************************************************************/
191 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
194 s4 disp; /* branch displacement */
196 /* calculate the patch position */
198 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
200 /* Calculate the branch displacement. */
202 disp = targetmpc - branchmpc;
204 /* I don't think we have to check for branch-displacement
205 overflow. +/-2GB should be enough. */
207 /* patch the branch instruction before the mcodeptr */
213 /* md_stacktrace_get_returnaddress *********************************************
215 Returns the return address of the current stackframe, specified by
216 the passed stack pointer and the stack frame size.
218 *******************************************************************************/
220 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
224 /* on x86_64 the return address is above the current stack frame */
226 ra = *((u1 **) (sp + framesize));
232 /* md_get_method_patch_address *************************************************
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).
238 INVOKESTATIC/SPECIAL:
240 4d 8b 15 e2 fe ff ff mov -286(%rip),%r10
241 49 ff d2 rex64Z callq *%r10
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
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
256 *******************************************************************************/
258 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
262 u1 *pa; /* patch address */
264 /* go back to the actual call instruction (3-bytes) */
268 /* get the last byte of the call */
272 /* check for the different calls */
275 /* INVOKESTATIC/SPECIAL */
277 /* Get the offset from the instruction (the offset address is
278 4-bytes before the call instruction). */
280 offset = *((s4 *) (ra - 4));
282 /* add the offset to the return address (IP-relative addressing) */
286 else if (mcode == 0xd3) {
287 /* INVOKEVIRTUAL/INTERFACE */
289 /* return NULL if no mptr was specified (used for replacement) */
294 /* Get the offset from the instruction (the offset address is
295 4-bytes before the call instruction). */
297 offset = *((s4 *) (ra - 4));
299 /* add the offset to the method pointer */
304 /* catch any problems */
313 /* md_codegen_get_pv_from_pc ***************************************************
315 On this architecture just a wrapper function to
316 codegen_get_pv_from_pc.
318 *******************************************************************************/
320 u1 *md_codegen_get_pv_from_pc(u1 *ra)
324 /* Get the start address of the function which contains this
325 address from the method table. */
327 pv = codegen_get_pv_from_pc(ra);
333 /* md_cacheflush ***************************************************************
335 Calls the system's function to flush the instruction and data
338 *******************************************************************************/
340 void md_cacheflush(u1 *addr, s4 nbytes)
346 /* md_icacheflush **************************************************************
348 Calls the system's function to flush the instruction cache.
350 *******************************************************************************/
352 void md_icacheflush(u1 *addr, s4 nbytes)
358 /* md_dcacheflush **************************************************************
360 Calls the system's function to flush the data cache.
362 *******************************************************************************/
364 void md_dcacheflush(u1 *addr, s4 nbytes)
370 /* md_patch_replacement_point **************************************************
372 Patch the given replacement point.
374 *******************************************************************************/
376 #if defined(ENABLE_REPLACEMENT)
377 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
382 /* XXX this is probably unsafe! */
385 /* write spinning instruction */
386 *(u2*)(rp->pc) = 0xebfe;
389 rp->pc[4] = savedmcode[4];
391 /* write first word */
392 *(u4*)(rp->pc) = *(u4*)(savedmcode);
395 /* save the current machine code */
396 *(u4*)(savedmcode) = *(u4*)(rp->pc);
397 savedmcode[4] = rp->pc[4];
399 /* build the machine code for the patch */
400 disp = (code->replacementstubs - rp->pc)
401 + index * REPLACEMENT_STUB_SIZE
404 mcode = 0xe9 | ((u8) disp << 8);
406 /* write spinning instruction */
407 *(u2*)(rp->pc) = 0xebfe;
410 rp->pc[4] = (mcode >> 32);
412 /* write first word */
413 *(u4*)(rp->pc) = (u4) mcode;
416 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
424 /* XXX if required asm_cacheflush(rp->pc,8); */
426 #endif /* defined(ENABLE_REPLACEMENT) */
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 * ---------------------------------------------------------------------
435 * indent-tabs-mode: t
439 * vim:noexpandtab:sw=4:ts=4: