* src/threads/posix/thread-posix.cpp: Eliminated some easy-to-fix or pointless compil...
[cacao.git] / src / vm / jit / arm / md.c
index 80c6b2fd2cc238365f7c225c7bc8ac2a06d0e1d5..4149a7eaadcacea2c96ca43a855ffdd39e9cd3e0 100644 (file)
@@ -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.
 
 
    This file is part of CACAO.
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Michael Starzinger
-            Christian Thalinger
-
-   $Id: md.c 6591 2007-01-02 19:14:25Z twisti $
-
 */
 
 
 #include "config.h"
 
 #include <assert.h>
 */
 
 
 #include "config.h"
 
 #include <assert.h>
+#include <stdint.h>
 
 
-#include "vm/global.h"
-#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/jit/arm/md-abi.h"
 
-#include "vm/exceptions.h"
-#include "vm/stringlocal.h"
-#include "vm/jit/asmpart.h"
+#include "vm/jit/executionstate.h"
+#include "vm/jit/trap.hpp"
 
 
 /* md_init *********************************************************************
 
 
 /* md_init *********************************************************************
@@ -58,58 +49,7 @@ void md_init(void)
 }
 
 
 }
 
 
-/* md_codegen_patch_branch *****************************************************
-
-   Back-patches a branch instruction.
-
-*******************************************************************************/
-
-void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
-{
-       s4 *mcodeptr;
-       s4  disp;                           /* branch displacement                */
-
-       /* calculate the patch position */
-
-       mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
-
-       /* Calculate the branch displacement. */
-
-       disp = (targetmpc - branchmpc - 4) >> 2;
-
-       if ((disp < (s4) 0xff000000) || (disp > (s4) 0x00ffffff))
-               vm_abort("md_codegen_patch_branch: branch displacement out of range: %d > +/-%d", disp, 0x00ffffff);
-
-       /* patch the branch instruction before the mcodeptr */
-
-       mcodeptr[-1] |= (disp & 0x00ffffff);
-}
-
-
-/* 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;
-
-       /*printf("md_stacktrace_get_returnaddress(): called (sp=%x, framesize=%d)\n", sp, framesize);*/
-
-       /* 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));
-
-       /*printf("md_stacktrace_get_returnaddress(): result (ra=%x)\n", ra);*/
-
-       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
 
    Gets the patch address of the currently compiled method. The offset
    is extracted from the load instruction(s) before the jump and added
@@ -124,10 +64,18 @@ u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
    or
 
    e590b000    ldr   fp, [r0]
    or
 
    e590b000    ldr   fp, [r0]
-   e59bc000    ldr   ip, [fp]
+   e59bc004    ldr   ip, [fp, #4]
    e1a0e00f    mov   lr, pc
    e1a0f00c    mov   pc, ip
 
    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!)
    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!)
@@ -137,137 +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);
+       /* Sanity check: Are we inside jit code? */
 
 
-       if ((mcode & 0x000f0000) == 0x000b0000) {
-               /* sanity check: offset was positive */
+       assert(pc[1] == 0xe1a0e00f /*MOV LR,PC*/);
+       assert(pc[2] == 0xe1a0f00c /*MOV PC,IP*/);
 
 
-               assert((mcode & 0x00800000) == 0x00800000);
+       /* Sanity check: We unconditionally loaded a word into REG_PV? */
 
 
-               /* we loaded from REG_METHODPTR */
+       assert ((mcode & 0xff70f000) == 0xe510c000);
 
 
-               pa = mptr + offset;
-       }
-       else {
-               /* sanity check: we loaded from REG_IP; offset was negative or zero */
+       /* Get load displacement. */
+
+       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)
 
                /* 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 */
 
 
                /* 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) */
-               throw_cacao_exception_exit(string_java_lang_InternalError,
-                  "Unable to find method: %p (instr=%x)\n",
-                  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;
+               }
+       }
 
 
+       /* Case is not covered, something is severely wrong. */
 
 
-/* md_icacheflush **************************************************************
+       else {
+               vm_abort_disassemble(pc, 3, "md_jit_method_patch_address: unknown instruction %x", mcode);
 
 
-   Calls the system's function to flush the instruction cache.
+               /* Keep compiler happy. */
 
 
-*******************************************************************************/
+               pa = NULL;
+       }
 
 
-void md_icacheflush(u1 *addr, s4 nbytes)
-{
-       asm_cacheflush(addr, nbytes);
+       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
 
 
 /*
 
 
 /*