X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fx86_64%2Fmd.c;h=cf682e09f76b387c7814716abf7124b776596774;hb=c987fe35316e518b923e13757a4399f6688c6548;hp=f3be618c523712a59b09b68bb5dcdb63016dd9d0;hpb=2387631c383529898674ff25d076735457bd94cc;p=cacao.git diff --git a/src/vm/jit/x86_64/md.c b/src/vm/jit/x86_64/md.c index f3be618c5..cf682e09f 100644 --- a/src/vm/jit/x86_64/md.c +++ b/src/vm/jit/x86_64/md.c @@ -1,9 +1,8 @@ -/* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions +/* src/vm/jit/x86_64/md.c - machine dependent x86_64 functions - Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel, - C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, - E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, - J. Wenninger, Institut f. Computersprachen - TU Wien + Copyright (C) 1996-2005, 2006, 2007, 2008 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -22,36 +21,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Contact: cacao@cacaojvm.org - - Authors: Christian Thalinger - - Changes: Edwin Steiner - - $Id: md.c 4908 2006-05-12 16:49:50Z edwin $ - */ -#define _GNU_SOURCE - #include "config.h" #include +#include #include -#include +#include "vm/jit/x86_64/codegen.h" #include "vm/jit/x86_64/md-abi.h" -#include "vm/exceptions.h" -#include "vm/signallocal.h" -#include "vm/jit/asmpart.h" -#include "vm/jit/stacktrace.h" +#include "vm/vm.hpp" -#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) -#include "vm/options.h" /* XXX debug */ -#include "vm/jit/disass.h" /* XXX debug */ -#endif +#include "vm/jit/codegen-common.hpp" +#include "vm/jit/executionstate.h" +#include "vm/jit/jit.hpp" +#include "vm/jit/trap.hpp" /* md_init ********************************************************************* @@ -66,105 +53,7 @@ void md_init(void) } -/* md_signal_handler_sigsegv *************************************************** - - NullPointerException signal handler for hardware null pointer - check. - -*******************************************************************************/ - -void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p) -{ - ucontext_t *_uc; - mcontext_t *_mc; - u1 *sp; - u1 *ra; - u1 *xpc; - - _uc = (ucontext_t *) _p; - _mc = &_uc->uc_mcontext; - - /* ATTENTION: Don't use CACAO's internal REG_* defines as they are - different to the ones in . */ - - sp = (u1 *) _mc->gregs[REG_RSP]; - xpc = (u1 *) _mc->gregs[REG_RIP]; - ra = xpc; /* return address is equal to xpc */ - - _mc->gregs[REG_RAX] = - (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc); - - _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */ - _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception; -} - - -/* md_signal_handler_sigfpe **************************************************** - - ArithmeticException signal handler for hardware divide by zero - check. - -*******************************************************************************/ - -void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p) -{ - ucontext_t *_uc; - mcontext_t *_mc; - u1 *sp; - u1 *ra; - u1 *xpc; - - _uc = (ucontext_t *) _p; - _mc = &_uc->uc_mcontext; - - /* ATTENTION: Don't use CACAO's internal REG_* defines as they are - different to the ones in . */ - - sp = (u1 *) _mc->gregs[REG_RSP]; - xpc = (u1 *) _mc->gregs[REG_RIP]; - ra = xpc; /* return address is equal to xpc */ - - _mc->gregs[REG_RAX] = - (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc); - - _mc->gregs[REG_R10] = (ptrint) xpc; /* REG_ITMP2_XPC */ - _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception; -} - - -#if defined(USE_THREADS) && defined(NATIVE_THREADS) -void thread_restartcriticalsection(ucontext_t *uc) -{ - void *critical; - - critical = critical_find_restart_point((void *) uc->uc_mcontext.gregs[REG_RIP]); - - if (critical) - uc->uc_mcontext.gregs[REG_RIP] = (ptrint) critical; -} -#endif - - -/* md_stacktrace_get_returnaddress ********************************************* - - Returns the return address of the current stackframe, specified by - the passed stack pointer and the stack frame size. - -*******************************************************************************/ - -u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) -{ - u1 *ra; - - /* on x86_64 the return address is above the current stack frame */ - - ra = *((u1 **) (sp + framesize)); - - return ra; -} - - -/* md_get_method_patch_address ************************************************* +/* md_jit_method_patch_address ************************************************* Gets the patch address of the currently compiled method. The offset is extracted from the load instruction(s) before the jump and added @@ -172,7 +61,7 @@ u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) INVOKESTATIC/SPECIAL: - 49 ba 98 3a ed ab aa 2a 00 00 mov $0x2aaaabed3a98,%r10 + 4d 8b 15 e2 fe ff ff mov -286(%rip),%r10 49 ff d2 rex64Z callq *%r10 INVOKEVIRTUAL: @@ -190,104 +79,130 @@ u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) *******************************************************************************/ -u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr) +void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) { - u1 mcode; - s4 offset; - u1 *pa; /* patch address */ + uint8_t *pc; + uint8_t mcode; + int32_t offset; + void *pa; /* patch address */ /* go back to the actual call instruction (3-bytes) */ - ra = ra - 3; + pc = ((uint8_t *) ra) - 3; /* get the last byte of the call */ - mcode = ra[2]; + mcode = pc[2]; /* check for the different calls */ - /* INVOKESTATIC/SPECIAL */ - if (mcode == 0xd2) { - /* patch address is 8-bytes before the call instruction */ - - pa = ra - 8; - - } else if (mcode == 0xd3) { - /* INVOKEVIRTUAL/INTERFACE */ + /* INVOKESTATIC/SPECIAL */ /* Get the offset from the instruction (the offset address is 4-bytes before the call instruction). */ - offset = *((s4 *) (ra - 4)); + offset = *((int32_t *) (pc - 4)); - /* add the offset to the method pointer */ - - pa = mptr + offset; - - } else { - /* catch any problems */ + /* add the offset to the return address (IP-relative addressing) */ - assert(0); + pa = pc + offset; } + else if (mcode == 0xd3) { + /* INVOKEVIRTUAL/INTERFACE */ - return pa; -} - - -/* md_codegen_findmethod ******************************************************* - - On this architecture just a wrapper function to codegen_findmethod. - -*******************************************************************************/ + /* return NULL if no mptr was specified (used for replacement) */ -u1 *md_codegen_findmethod(u1 *ra) -{ - u1 *pv; + if (mptr == NULL) + return NULL; - /* the the start address of the function which contains this - address from the method table */ + /* Get the offset from the instruction (the offset address is + 4-bytes before the call instruction). */ - pv = codegen_findmethod(ra); + offset = *((int32_t *) (pc - 4)); - return pv; -} + /* add the offset to the method pointer */ + pa = ((uint8_t *) mptr) + offset; + } + else { + /* catch any problems */ -/* md_cacheflush *************************************************************** + vm_abort("md_jit_method_patch_address: unknown instruction %x", mcode); - Calls the system's function to flush the instruction and data - cache. + /* keep compiler happy */ -*******************************************************************************/ + pa = NULL; + } -void md_cacheflush(u1 *addr, s4 nbytes) -{ - /* do nothing */ + return pa; } -/* md_icacheflush ************************************************************** - - Calls the system's function to flush the instruction cache. - -*******************************************************************************/ - -void md_icacheflush(u1 *addr, s4 nbytes) +/** + * Decode the trap instruction at the given PC. + * + * @param trp information about trap to be filled + * @param sig signal number + * @param xpc exception PC + * @param es execution state of the machine + * @return true if trap was decoded successfully, false otherwise. + */ +bool md_trap_decode(trapinfo_t* trp, int sig, void* _xpc, executionstate_t* es) { - /* do nothing */ -} - + uint8_t* xpc = (uint8_t*) _xpc; -/* md_dcacheflush ************************************************************** - - Calls the system's function to flush the data cache. - -*******************************************************************************/ +#if 0 + // Check for StackOverflowException. + threads_check_stackoverflow(sp); +#endif -void md_dcacheflush(u1 *addr, s4 nbytes) -{ - /* do nothing */ + switch (sig) { + case TRAP_SIGFPE: + // Check for ArithmeticException. + trp->type = TRAP_ArithmeticException; + trp->value = 0; + return true; + + case TRAP_SIGILL: + // Check for valid trap instruction. + if (patcher_is_valid_trap_instruction_at(xpc)) { + trp->type = TRAP_PATCHER; + trp->value = 0; + return true; + } + return false; + + case TRAP_SIGSEGV: + { + // Get exception-throwing instruction. + uint8_t opc = M_ALD_MEM_GET_OPC(xpc); + uint8_t mod = M_ALD_MEM_GET_MOD(xpc); + uint8_t rm = M_ALD_MEM_GET_RM(xpc); + + // Check for hardware exception, for values + // see emit_mov_mem_reg and emit_mem. + if ((opc == 0x8b) && (mod == 0) && (rm == 4)) { + int32_t d = M_ALD_MEM_GET_REG(xpc); + int32_t disp = M_ALD_MEM_GET_DISP(xpc); + + // We use the exception type as load displacement. + trp->type = disp; + trp->value = es->intregs[d]; + return true; + } + + // Default case is a normal NullPointerException. + else { + trp->type = TRAP_NullPointerException; + trp->value = 0; + return true; + } + } + + default: + return false; + } } @@ -297,37 +212,30 @@ void md_dcacheflush(u1 *addr, s4 nbytes) *******************************************************************************/ -void md_patch_replacement_point(rplpoint *rp) +#if defined(ENABLE_REPLACEMENT) +void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert) { - u8 mcode; - - /* XXX this is probably unsafe! */ - - /* save the current machine code */ - mcode = *(u8*)rp->pc; - - /* write spinning instruction */ - *(u2*)(rp->pc) = 0xebfe; + u2 mcode; - /* write 5th byte */ - rp->pc[4] = (rp->mcode >> 32); + if (revert) { + /* write saved machine code */ + *(u2*)(pc) = *(u2*)(savedmcode); + } + else { + /* save the current machine code */ + *(u2*)(savedmcode) = *(u2*)(pc); - /* write first word */ - *(u4*)(rp->pc) = (u4) rp->mcode; + /* build the machine code for the patch */ + mcode = 0x0b0f; - /* store saved mcode */ - rp->mcode = mcode; - -#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) - { - u1* u1ptr = rp->pc; - DISASSINSTR(u1ptr); - fflush(stdout); + /* write new machine code */ + *(u2*)(pc) = (u2) mcode; } -#endif - - /* XXX if required asm_cacheflush(rp->pc,8); */ + + /* XXX if required asm_cacheflush(pc,8); */ } +#endif /* defined(ENABLE_REPLACEMENT) */ + /* * These are local overrides for various environment variables in Emacs.