X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Farm%2Fmd.c;h=4149a7eaadcacea2c96ca43a855ffdd39e9cd3e0;hb=67702ed5605e84f33724aeee9ccf5f82ea774084;hp=b150f1a14831499f59267ff14222b67708e1627d;hpb=3a16b0602c73972b42f6db5280092e57e38b4287;p=cacao.git diff --git a/src/vm/jit/arm/md.c b/src/vm/jit/arm/md.c index b150f1a14..4149a7eaa 100644 --- a/src/vm/jit/arm/md.c +++ b/src/vm/jit/arm/md.c @@ -1,7 +1,8 @@ /* src/vm/jit/arm/md.c - machine dependent ARM functions - Copyright (C) 1996-2005, 2006, 2007, 2008 + 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. @@ -28,9 +29,13 @@ #include #include +#include "vm/jit/arm/codegen.h" #include "vm/jit/arm/md.h" #include "vm/jit/arm/md-abi.h" +#include "vm/jit/executionstate.h" +#include "vm/jit/trap.hpp" + /* md_init ********************************************************************* @@ -59,10 +64,18 @@ void md_init(void) 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!) @@ -76,7 +89,7 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) { uint32_t *pc; uint32_t mcode; - int32_t offset; + int32_t disp; void *pa; /* patch address */ /* Go back to the actual load instruction. */ @@ -87,22 +100,39 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) mcode = pc[0]; - /* sanity check: are we inside jit code? */ + /* Sanity check: Are we inside jit code? */ assert(pc[1] == 0xe1a0e00f /*MOV LR,PC*/); assert(pc[2] == 0xe1a0f00c /*MOV PC,IP*/); - /* get the load instruction and offset */ - - offset = (int32_t) (mcode & 0x0fff); + /* Sanity check: We unconditionally loaded a word into REG_PV? */ assert ((mcode & 0xff70f000) == 0xe510c000); - if ((mcode & 0x000f0000) == 0x000b0000) { - /* sanity check: offset was positive */ + /* Get load displacement. */ + + disp = (int32_t) (mcode & 0x0fff); + + /* Case: We loaded from base REG_PV with negative displacement. */ + + if (M_MEM_GET_Rbase(mcode) == REG_PV && (mcode & 0x00800000) == 0) { + /* We loaded from data segment, displacement can be larger. */ + + mcode = pc[-1]; + + /* check for "SUB IP, IP, #??, ROTL 12" */ + + if ((mcode & 0xffffff00) == 0xe24cca00) + disp += (int32_t) ((mcode & 0x00ff) << 12); - assert((mcode & 0x00800000) == 0x00800000); + /* and get the final data segment address */ + + pa = ((uint8_t *) pv) - disp; + } + /* 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) */ if (mptr == NULL) @@ -110,32 +140,109 @@ void *md_jit_method_patch_address(void *pv, void *ra, void *mptr) /* we loaded from REG_METHODPTR */ - pa = ((uint8_t *) mptr) + offset; + pa = ((uint8_t *) mptr) + disp; } - else { - /* sanity check: we loaded from REG_IP; offset was negative or zero */ - assert((mcode & 0x008f0000) == 0x000c0000 || - (mcode & 0x008f0fff) == 0x008c0000); + /* Case: We loaded from base REG_PV with positive offset. */ - /* we loaded from data segment; offset can be larger */ + 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. */ mcode = pc[-1]; - /* check for "SUB IP, IP, #??, ROTL 12" */ + /* check for "ADD IP, FP, #??, ROTL 12" */ - if ((mcode & 0xffffff00) == 0xe24cca00) - offset += (int32_t) ((mcode & 0x00ff) << 12); + if ((mcode & 0xffffff00) == 0xe28bca00) { + /* We loaded from REG_METHODPTR with a larger displacement. */ - /* and get the final data segment address */ + assert(mptr != NULL); + disp += (int32_t) ((mcode & 0x00ff) << 12); + pa = ((uint8_t *) mptr) + disp; + } - pa = ((uint8_t *) pv) - offset; + /* 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. */ + + disp += (int32_t) ((mcode & 0x00ff) << 12); + pa = ((uint8_t *) pv) - disp; + } + + /* Case is not covered, something is severely wrong. */ + + else { + vm_abort_disassemble(pc - 1, 4, "md_jit_method_patch_address: unknown instruction %x", mcode); + + /* Keep compiler happy. */ + + pa = NULL; + } + } + + /* Case is not covered, something is severely wrong. */ + + else { + vm_abort_disassemble(pc, 3, "md_jit_method_patch_address: unknown instruction %x", mcode); + + /* Keep compiler happy. */ + + pa = NULL; } return pa; } +/** + * 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; + } + } + + default: + return false; + } +} + + /** * Patch the given replacement point. */