X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Farm%2Fmd.c;h=4149a7eaadcacea2c96ca43a855ffdd39e9cd3e0;hb=67702ed5605e84f33724aeee9ccf5f82ea774084;hp=e97ca5df4a968b6266a75c98561c8e68f8913bea;hpb=f31d9529376c680ed23b572270a2067aee639300;p=cacao.git diff --git a/src/vm/jit/arm/md.c b/src/vm/jit/arm/md.c index e97ca5df4..4149a7eaa 100644 --- a/src/vm/jit/arm/md.c +++ b/src/vm/jit/arm/md.c @@ -1,9 +1,8 @@ -/* src/vm/jit/arm/md.c - machine dependent Arm functions +/* src/vm/jit/arm/md.c - machine dependent ARM functions - Copyright (C) 1996-2005, 2006, 2007 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, 2010 + CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO + Copyright (C) 2009 Theobroma Systems Ltd. This file is part of CACAO. @@ -22,26 +21,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: md.c 8185 2007-07-05 21:34:47Z michi $ - */ #include "config.h" #include +#include -#include "vm/types.h" - +#include "vm/jit/arm/codegen.h" +#include "vm/jit/arm/md.h" #include "vm/jit/arm/md-abi.h" -#include "vm/exceptions.h" -#include "vm/global.h" - -#include "vm/jit/asmpart.h" -#include "vm/jit/md.h" - -#include "vm/jit/codegen-common.h" /* REMOVE ME: for codegendata */ +#include "vm/jit/executionstate.h" +#include "vm/jit/trap.hpp" /* md_init ********************************************************************* @@ -56,28 +49,7 @@ void md_init(void) } -/* 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 ARM the return address is located on the top of the - stackframe. */ - /* ATTENTION: This is only true for non-leaf methods!!! */ - - ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P)); - - return ra; -} - - -/* md_assembler_get_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 @@ -92,10 +64,18 @@ u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize) or e590b000 ldr fp, [r0] - e59bc000 ldr ip, [fp] + e59bc004 ldr ip, [fp, #4] e1a0e00f mov lr, pc e1a0f00c mov pc, ip + or + + e590b000 ldr fp, [r0] + e28bca01 add ip, fp, #4096 ; 0x1000 + e59cc004 ldr ip, [ip, #4] + e1a0e00f mov lr, pc + e1a0f00c mov pc, ip + How we find out the patching address to store new method pointer: - loaded IP with LDR IP,[METHODPTR]? yes=INVOKEVIRTUAL or INVOKEINTERFACE (things are easy!) @@ -105,140 +85,173 @@ 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) { - u4 mcode; - s4 offset; - u1 *pa; /* patch address */ + uint32_t *pc; + uint32_t mcode; + int32_t disp; + void *pa; /* patch address */ - /* sanity check: are we inside jit code? */ + /* Go back to the actual load instruction. */ - assert(*((u4 *) (ra - 2*4)) == 0xe1a0e00f /*MOV LR,PC*/); - assert(*((u4 *) (ra - 1*4)) == 0xe1a0f00c /*MOV PC,IP*/); + pc = ((uint32_t *) ra) - 3; - /* get the load instruction and offset */ + /* Get first instruction word on current PC. */ - mcode = *((u4 *) (ra - 12)); - offset = (s4) (mcode & 0x0fff); + mcode = pc[0]; - assert ((mcode & 0xff70f000) == 0xe510c000); - - if ((mcode & 0x000f0000) == 0x000b0000) { - /* sanity check: offset was positive */ + /* Sanity check: Are we inside jit code? */ - assert((mcode & 0x00800000) == 0x00800000); + assert(pc[1] == 0xe1a0e00f /*MOV LR,PC*/); + assert(pc[2] == 0xe1a0f00c /*MOV PC,IP*/); - /* return NULL if no mptr was specified (used for replacement) */ + /* Sanity check: We unconditionally loaded a word into REG_PV? */ - if (mptr == NULL) - return NULL; + assert ((mcode & 0xff70f000) == 0xe510c000); - /* we loaded from REG_METHODPTR */ + /* Get load displacement. */ - pa = mptr + offset; - } - else { - /* sanity check: we loaded from REG_IP; offset was negative or zero */ + disp = (int32_t) (mcode & 0x0fff); - assert((mcode & 0x008f0000) == 0x000c0000 || - (mcode & 0x008f0fff) == 0x008c0000); + /* Case: We loaded from base REG_PV with negative displacement. */ - /* we loaded from data segment; offset can be larger */ + if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0) { + /* We loaded from data segment, displacement can be larger. */ - mcode = *((u4 *) (ra - 4*4)); + mcode = pc[-1]; /* check for "SUB IP, IP, #??, ROTL 12" */ if ((mcode & 0xffffff00) == 0xe24cca00) - offset += (s4) ((mcode & 0x00ff) << 12); + disp += (int32_t) ((mcode & 0x00ff) << 12); /* and get the final data segment address */ - pa = sfi->pv - offset; + pa = ((uint8_t *) pv) - disp; } - return pa; -} + /* Case: We loaded from base REG_METHODPTR with positive displacement. */ + else if (M_MEM_GET_Rbase(mcode) == REG_METHODPTR && (mcode & 0x00800000) == 0x00800000) { + /* return NULL if no mptr was specified (used for replacement) */ -/* md_codegen_get_pv_from_pc *************************************************** + if (mptr == NULL) + return NULL; - TODO: document me + /* we loaded from REG_METHODPTR */ -*******************************************************************************/ + pa = ((uint8_t *) mptr) + disp; + } -u1 *md_codegen_get_pv_from_pc(u1 *ra) -{ - u1 *pv; - u4 mcode1, mcode2, mcode3; + /* Case: We loaded from base REG_PV with positive offset. */ - pv = ra; + else if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0x00800000) { + /* We loaded with a larger displacement. Normally this means we loaded + from REG_METHODPTR. However there is a corner case if we loaded + from the data segment at an address aligned to 12 bit, which leads to a + zero (positive) displacement for the last instruction. */ - /* this can either be a RECOMPUTE_IP in JIT code or a fake in asm_calljavafunction */ - mcode1 = *((u4*) ra); - if ((mcode1 & 0xffffff00) == 0xe24fcf00 /*sub ip,pc,#__*/) - pv -= (s4) ((mcode1 & 0x000000ff) << 2); - else if ((mcode1 & 0xffffff00) == 0xe24fc000 /*sub ip,pc,#__*/) - pv -= (s4) (mcode1 & 0x000000ff); - else { - /* if this happens, we got an unexpected instruction at (*ra) */ - vm_abort("Unable to find method: %p (instr=%x)", ra, mcode1); - } + mcode = pc[-1]; - /* if we have a RECOMPUTE_IP there can be more than one instruction */ - mcode2 = *((u4*) (ra + 4)); - mcode3 = *((u4*) (ra + 8)); - if ((mcode2 & 0xffffff00) == 0xe24ccb00 /*sub ip,ip,#__*/) - pv -= (s4) ((mcode2 & 0x000000ff) << 10); - if ((mcode3 & 0xffffff00) == 0xe24cc700 /*sub ip,ip,#__*/) - pv -= (s4) ((mcode3 & 0x000000ff) << 18); + /* check for "ADD IP, FP, #??, ROTL 12" */ - /* we used PC-relative adressing; but now it is LR-relative */ - pv += 8; + if ((mcode & 0xffffff00) == 0xe28bca00) { + /* We loaded from REG_METHODPTR with a larger displacement. */ - /* if we found our method the data segment has to be valid */ - /* we check this by looking up the IsLeaf field, which has to be boolean */ - assert( *((s4*)pv-4) == (s4)true || *((s4*)pv-4) == (s4)false ); + assert(mptr != NULL); + disp += (int32_t) ((mcode & 0x00ff) << 12); + pa = ((uint8_t *) mptr) + disp; + } - return pv; -} + /* check for "SUB IP, IP, #??, ROTL 12" (corner case) */ + else if ((mcode & 0xffffff00) == 0xe24cca00 && disp == 0) { + /* We loaded from data segment with a larger displacement aligned to 12 bit. */ -/* md_cacheflush *************************************************************** + disp += (int32_t) ((mcode & 0x00ff) << 12); + pa = ((uint8_t *) pv) - disp; + } - Calls the system's function to flush the instruction and data - cache. + /* Case is not covered, something is severely wrong. */ -*******************************************************************************/ + else { + vm_abort_disassemble(pc - 1, 4, "md_jit_method_patch_address: unknown instruction %x", mcode); -void md_cacheflush(u1 *addr, s4 nbytes) -{ - asm_cacheflush(addr, nbytes); -} + /* Keep compiler happy. */ + pa = NULL; + } + } -/* md_icacheflush ************************************************************** + /* Case is not covered, something is severely wrong. */ - Calls the system's function to flush the instruction cache. + else { + vm_abort_disassemble(pc, 3, "md_jit_method_patch_address: unknown instruction %x", mcode); -*******************************************************************************/ + /* Keep compiler happy. */ -void md_icacheflush(u1 *addr, s4 nbytes) -{ - asm_cacheflush(addr, nbytes); + pa = NULL; + } + + return pa; } -/* md_dcacheflush ************************************************************** +/** + * 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) +{ + // Get the exception-throwing instruction. + uint32_t mcode = *((uint32_t*) xpc); + + switch (sig) { + case TRAP_SIGILL: + // Check for valid trap instruction. + if (patcher_is_valid_trap_instruction_at(xpc)) { + trp->type = (mcode >> 8) & 0x0fff; + trp->value = es->intregs[mcode & 0x0f]; + return true; + } + return false; + + case TRAP_SIGSEGV: + { + // Sanity check for load/store instruction. + // FIXME Implement this! + + // Retrieve base address of load/store instruction. + uintptr_t addr = es->intregs[(mcode >> 16) & 0x0f]; + + // Check for implicit NullPointerException. + if (addr == 0) { + trp->type = TRAP_NullPointerException; + trp->value = 0; + return true; + } + } - Calls the system's function to flush the data cache. + default: + return false; + } +} -*******************************************************************************/ -void md_dcacheflush(u1 *addr, s4 nbytes) +/** + * Patch the given replacement point. + */ +#if defined(ENABLE_REPLACEMENT) +void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert) { - asm_cacheflush(addr, nbytes); + vm_abort("md_patch_replacement_point: IMPLEMENT ME!"); } +#endif /*