1 /* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
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
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 Contact: cacao@cacaojvm.org
27 Authors: Christian Thalinger
29 Changes: Edwin Steiner
31 $Id: md.c 6265 2007-01-02 20:40:57Z edwin $
44 #include "vm/jit/x86_64/md-abi.h"
46 #if defined(ENABLE_THREADS)
47 # include "threads/native/threads.h"
50 #include "vm/exceptions.h"
51 #include "vm/signallocal.h"
52 #include "vm/jit/asmpart.h"
53 #include "vm/jit/stacktrace.h"
55 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
56 #include "vm/options.h" /* XXX debug */
57 #include "vm/jit/disass.h" /* XXX debug */
61 /* md_init *********************************************************************
63 Do some machine dependent initialization.
65 *******************************************************************************/
73 /* md_signal_handler_sigsegv ***************************************************
75 NullPointerException signal handler for hardware null pointer
78 *******************************************************************************/
80 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
88 _uc = (ucontext_t *) _p;
89 _mc = &_uc->uc_mcontext;
91 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
92 different to the ones in <ucontext.h>. */
94 sp = (u1 *) _mc->gregs[REG_RSP];
95 xpc = (u1 *) _mc->gregs[REG_RIP];
96 ra = xpc; /* return address is equal to xpc */
99 /* check for StackOverflowException */
101 threads_check_stackoverflow(sp);
104 _mc->gregs[REG_RAX] =
105 (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
107 _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */
108 _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
112 /* md_signal_handler_sigfpe ****************************************************
114 ArithmeticException signal handler for hardware divide by zero
117 *******************************************************************************/
119 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
127 _uc = (ucontext_t *) _p;
128 _mc = &_uc->uc_mcontext;
130 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
131 different to the ones in <ucontext.h>. */
133 sp = (u1 *) _mc->gregs[REG_RSP];
134 xpc = (u1 *) _mc->gregs[REG_RIP];
135 ra = xpc; /* return address is equal to xpc */
137 _mc->gregs[REG_RAX] =
138 (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
140 _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */
141 _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
145 /* md_signal_handler_sigusr2 ***************************************************
147 Signal handler for profiling sampling.
149 *******************************************************************************/
151 #if defined(ENABLE_THREADS)
152 void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
161 _uc = (ucontext_t *) _p;
162 _mc = &_uc->uc_mcontext;
164 /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
165 different to the ones in <ucontext.h>. */
167 pc = (u1 *) _mc->gregs[REG_RIP];
174 #if defined(ENABLE_THREADS)
175 void thread_restartcriticalsection(ucontext_t *_uc)
180 _mc = &_uc->uc_mcontext;
182 pc = critical_find_restart_point((void *) _mc->gregs[REG_RIP]);
185 _mc->gregs[REG_RIP] = (ptrint) pc;
190 /* md_codegen_patch_branch *****************************************************
192 Back-patches a branch instruction.
194 *******************************************************************************/
196 void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
199 s4 disp; /* branch displacement */
201 /* calculate the patch position */
203 mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
205 /* Calculate the branch displacement. */
207 disp = targetmpc - branchmpc;
209 /* I don't think we have to check for branch-displacement
210 overflow. +/-2GB should be enough. */
212 /* patch the branch instruction before the mcodeptr */
218 /* md_stacktrace_get_returnaddress *********************************************
220 Returns the return address of the current stackframe, specified by
221 the passed stack pointer and the stack frame size.
223 *******************************************************************************/
225 u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
229 /* on x86_64 the return address is above the current stack frame */
231 ra = *((u1 **) (sp + framesize));
237 /* md_get_method_patch_address *************************************************
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).
243 INVOKESTATIC/SPECIAL:
245 4d 8b 15 e2 fe ff ff mov -286(%rip),%r10
246 49 ff d2 rex64Z callq *%r10
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
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
261 *******************************************************************************/
263 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
267 u1 *pa; /* patch address */
269 /* go back to the actual call instruction (3-bytes) */
273 /* get the last byte of the call */
277 /* check for the different calls */
280 /* INVOKESTATIC/SPECIAL */
282 /* Get the offset from the instruction (the offset address is
283 4-bytes before the call instruction). */
285 offset = *((s4 *) (ra - 4));
287 /* add the offset to the return address (IP-relative addressing) */
291 else if (mcode == 0xd3) {
292 /* INVOKEVIRTUAL/INTERFACE */
294 /* return NULL if no mptr was specified (used for replacement) */
299 /* Get the offset from the instruction (the offset address is
300 4-bytes before the call instruction). */
302 offset = *((s4 *) (ra - 4));
304 /* add the offset to the method pointer */
309 /* catch any problems */
318 /* md_codegen_get_pv_from_pc ***************************************************
320 On this architecture just a wrapper function to
321 codegen_get_pv_from_pc.
323 *******************************************************************************/
325 u1 *md_codegen_get_pv_from_pc(u1 *ra)
329 /* Get the start address of the function which contains this
330 address from the method table. */
332 pv = codegen_get_pv_from_pc(ra);
338 /* md_cacheflush ***************************************************************
340 Calls the system's function to flush the instruction and data
343 *******************************************************************************/
345 void md_cacheflush(u1 *addr, s4 nbytes)
351 /* md_icacheflush **************************************************************
353 Calls the system's function to flush the instruction cache.
355 *******************************************************************************/
357 void md_icacheflush(u1 *addr, s4 nbytes)
363 /* md_dcacheflush **************************************************************
365 Calls the system's function to flush the data cache.
367 *******************************************************************************/
369 void md_dcacheflush(u1 *addr, s4 nbytes)
375 /* md_patch_replacement_point **************************************************
377 Patch the given replacement point.
379 *******************************************************************************/
381 #if defined(ENABLE_REPLACEMENT)
382 void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
387 /* XXX this is probably unsafe! */
390 /* write spinning instruction */
391 *(u2*)(rp->pc) = 0xebfe;
394 rp->pc[4] = savedmcode[4];
396 /* write first word */
397 *(u4*)(rp->pc) = *(u4*)(savedmcode);
400 /* save the current machine code */
401 *(u4*)(savedmcode) = *(u4*)(rp->pc);
402 savedmcode[4] = rp->pc[4];
404 /* build the machine code for the patch */
405 disp = (code->replacementstubs - rp->pc)
406 + index * REPLACEMENT_STUB_SIZE
409 mcode = 0xe9 | ((u8) disp << 8);
411 /* write spinning instruction */
412 *(u2*)(rp->pc) = 0xebfe;
415 rp->pc[4] = (mcode >> 32);
417 /* write first word */
418 *(u4*)(rp->pc) = (u4) mcode;
421 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
429 /* XXX if required asm_cacheflush(rp->pc,8); */
431 #endif /* defined(ENABLE_REPLACEMENT) */
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 * ---------------------------------------------------------------------
440 * indent-tabs-mode: t
444 * vim:noexpandtab:sw=4:ts=4: