* src/vm/jit/s390/codegen.c,
[cacao.git] / src / vm / jit / s390 / md.c
index ac84e08164c18ed2bb22b4788b2c580aa71cd3a1..431b6e9e26bfdbbc04adbaf845183ce5a7e5851d 100644 (file)
@@ -1,6 +1,6 @@
-/* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
+/* src/vm/jit/s390/md.c - machine dependent s390 Linux functions
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 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
    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 7839 2007-04-29 22:46:56Z pm $
-
 */
 
+
 #define _GNU_SOURCE
 
 #include "config.h"
 
 #include <assert.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <ucontext.h>
 
 #include "vm/jit/s390/md-abi.h"
 
 #if defined(ENABLE_THREADS)
+# include "threads/threads-common.h"
 # include "threads/native/threads.h"
 #endif
 
 #include "vm/exceptions.h"
 #include "vm/signallocal.h"
 #include "vm/jit/asmpart.h"
+#include "vm/jit/abi.h"
+#include "vm/jit/methodheader.h"
 #include "vm/jit/stacktrace.h"
 
 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
 #include "vm/jit/s390/codegen.h"
 
 #include <assert.h>
-#define OOPS() assert(0);
 
 /* prototypes *****************************************************************/
 
+u1 *exceptions_handle_exception(java_object_t *xptro, u1 *xpc, u1 *pv, u1 *sp);
+
 void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
 
+void md_dump_context(u1 *pc, mcontext_t *mc);
+
 /* md_init *********************************************************************
 
    Do some machine dependent initialization.
@@ -74,16 +74,63 @@ void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p);
 
 void md_init(void)
 {
-       struct sigaction act;
-       
-       act.sa_sigaction = md_signal_handler_sigill;
-       act.sa_flags     = SA_NODEFER | SA_SIGINFO;
+}
+
+/* md_dump_context ************************************************************
+   Logs the machine context
+  
+*******************************************************************************/
+
+void md_dump_context(u1 *pc, mcontext_t *mc) {
+       int i;
+       u1 *pv;
+       methodinfo *m;
+
+       union {
+               u8 l;
+               fpreg_t fr;
+       } freg;
+
+       log_println("Dumping context.");
 
-       if (sigaction(SIGILL, &act, NULL) == -1)        {
-               vm_abort("%s: error registering SIGILL signal handler.", __FUNCTION__);
+       log_println("Program counter: 0x%08X", pc);
+
+       pv = codegen_get_pv_from_pc_nocheck(pc);
+       if (pv == NULL) {
+               log_println("No java method found at location.");
+       } else {
+               m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
+               log_println(
+                       "Java method: class %s, method %s, descriptor %s.",
+                       m->class->name->text, m->name->text, m->descriptor->text
+               );
        }
-}
 
+#if defined(ENABLE_DISASSEMBLER)
+       log_println("Printing instruction at program counter:");
+       disassinstr(pc);
+#endif
+
+       log_println("General purpose registers:");
+
+       for (i = 0; i < 16; i++) {
+               log_println("\tr%d:\t0x%08X\t%d", i, mc->gregs[i], mc->gregs[i]);
+       }
+
+       log_println("Floating point registers:");
+
+       for (i = 0; i < 16; i++) {
+               freg.fr.d = mc->fpregs.fprs[i].d;
+               log_println("\tf%d\t0x%016llX\t(double)%e\t(float)%f", i, freg.l, freg.fr.d, freg.fr.f);
+       }
+
+#if defined(ENABLE_THREADS)
+       log_println("Dumping the current stacktrace:");
+       threads_print_stacktrace();
+#endif
+
+}
 
 /* md_signal_handler_sigsegv ***************************************************
 
@@ -94,17 +141,17 @@ void md_init(void)
 
 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
 {
-       ucontext_t        *_uc;
-       mcontext_t        *_mc;
-       u1                *pv;
-       u1                *sp;
-       u1                *ra;
-       u1                *xpc;
-       s4                 type;
-       ptrint             val;
-       java_objectheader *e;
-       s4                 base;
-       s4                 is_null;
+       ucontext_t     *_uc;
+       mcontext_t     *_mc;
+       u1             *pv;
+       u1             *sp;
+       u1             *ra;
+       u1             *xpc;
+       int             type;
+       intptr_t        val;
+       void           *p;
+       s4              base;
+       s4              is_null;
 
        _uc = (ucontext_t *) _p;
        _mc = &_uc->uc_mcontext;
@@ -113,10 +160,11 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
 
        /* Check opcodes and verify it is a null pointer exception */
 
-       switch (xpc[0]) {
-               case 0x58: /* L */
-               case 0x50: /* ST */
-                       base = (xpc[2] >> 4) & 0xF;
+       switch (N_RX_GET_OPC(xpc)) {
+               case OPC_L:
+               case OPC_ST:
+               case OPC_CL: /* array size check on NULL array */
+                       base = N_RX_GET_BASE(xpc);
                        if (base == 0) {
                                is_null = 1;
                        } else if (_mc->gregs[base] == 0) {
@@ -125,36 +173,50 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
                                is_null = 0;
                        }
                        break;
+               default:
+                       is_null = 0;
+                       break;
        }
 
        if (! is_null) {
+#if !defined(NDEBUG)
+               md_dump_context(xpc, _mc);
+#endif
                vm_abort("%s: segmentation fault at %p, aborting.", __FUNCTION__, xpc);
        }
 
-       pv = (u1 *)_mc->gregs[REG_PV];
+       pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
        sp = (u1 *)_mc->gregs[REG_SP];
        ra = xpc;
        type = EXCEPTION_HARDWARE_NULLPOINTER;
        val = 0;
 
-       e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+       /* Handle the type. */
+
+       p = signal_handle(type, val, pv, sp, ra, xpc, _p);
 
-       _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
-       _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
-       _mc->psw.addr = (ptrint) asm_handle_exception;
+       if (p != NULL) {
+               _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
+               _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
+               _mc->psw.addr              = (intptr_t) asm_handle_exception;
+       }
+       else {
+               _mc->psw.addr              = (intptr_t) xpc;
+       }
 }
 
-void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
-       ucontext_t        *_uc;
-       mcontext_t        *_mc;
-       u1                *xpc;
-       u1                *ra;
-       u1                *pv;
-       u1                *sp;
-       s4                 type;
-       ptrint             val;
-       java_objectheader *e;
-       s4                 reg;
+void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p)
+{
+       ucontext_t     *_uc;
+       mcontext_t     *_mc;
+       u1             *xpc;
+       u1             *ra;
+       u1             *pv;
+       u1             *sp;
+       int             type;
+       intptr_t        val;
+       void           *p;
+       s4              reg;
 
        _uc = (ucontext_t *) _p;
        _mc = &_uc->uc_mcontext;
@@ -162,25 +224,34 @@ void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
 
        /* Our trap instruction has the format: { 0x02, one_byte_of_data }. */
 
-       if ((siginfo->si_code == ILL_ILLOPC) && (xpc[0] == 0x02)) {
+       if ((siginfo->si_code == ILL_ILLOPC) && (N_RR_GET_OPC(xpc) == OPC_ILL)) {
 
                /* bits 7-4 contain a register holding a value */
-               reg = (xpc[1] >> 4) & 0xF;
+               reg = N_ILL_GET_REG(xpc);
 
                /* bits 3-0 designate the exception type */
-               type = xpc[1] & 0xF;  
+               type = N_ILL_GET_TYPE(xpc);
 
-               pv = (u1 *)_mc->gregs[REG_PV];
+               pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
                sp = (u1 *)_mc->gregs[REG_SP];
                val = (ptrint)_mc->gregs[reg];
 
-               e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+               /* Handle the type. */
 
-               _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
-               _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
-               _mc->psw.addr = (ptrint) asm_handle_exception;
+               p = signal_handle(type, val, pv, sp, ra, xpc, _p);
 
+               if (p != NULL) {
+                       _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
+                       _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
+                       _mc->psw.addr              = (intptr_t) asm_handle_exception;
+               }
+               else {
+                       _mc->psw.addr              = (intptr_t) xpc;
+               }
        } else {
+#if !defined(NDEBUG)
+               md_dump_context(xpc, _mc);
+#endif
                vm_abort("%s: illegal instruction at %p, aborting.", __FUNCTION__, xpc);
        }
 }
@@ -194,17 +265,17 @@ void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
 
 void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
 {
-       ucontext_t         *_uc;
-       mcontext_t         *_mc;
-       u1                 *pv;
-       u1                 *sp;
-       u1                 *ra;
-       u1                 *xpc;
-       u1                 *pc;
-       s4                  r1, r2;
-       s4                  type;
-       ptrint              val;
-       java_objectheader  *e;
+       ucontext_t     *_uc;
+       mcontext_t     *_mc;
+       u1             *pv;
+       u1             *sp;
+       u1             *ra;
+       u1             *xpc;
+       u1             *pc;
+       int             r1, r2;
+       int             type;
+       intptr_t        val;
+       void           *p;
 
        _uc = (ucontext_t *) _p;
        _mc = &_uc->uc_mcontext;
@@ -214,17 +285,17 @@ void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
 
        /* Check opcodes */
 
-       if (xpc[0] == 0x1D) { /* DR */
+       if (N_RR_GET_OPC(xpc) == OPC_DR) { /* DR */
 
-               r1 = (xpc[1] >> 4) & 0xF;
-               r2 = xpc[1] & 0xF;
+               r1 = N_RR_GET_REG1(xpc);
+               r2 = N_RR_GET_REG2(xpc);
 
                if (
                        (_mc->gregs[r1] == 0xFFFFFFFF) &&
                        (_mc->gregs[r1 + 1] == 0x80000000) && 
                        (_mc->gregs[r2] == 0xFFFFFFFF)
                ) {
-                       /* handle special case */
+                       /* handle special case 0x80000000 / 0xFFFFFFFF that fails on hardware */
                        /* next instruction */
                        pc = (u1 *)_mc->psw.addr;
                        /* reminder */
@@ -235,21 +306,24 @@ void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
                        _mc->psw.addr = (ptrint) pc;
 
                        return;
-               } else if (_mc->gregs[r2] == 0) {
+               }
+               else if (_mc->gregs[r2] == 0) {
                        /* division by 0 */
 
-                       pv = (u1 *)_mc->gregs[REG_PV];
+                       pv = (u1 *)_mc->gregs[REG_PV] - N_PV_OFFSET;
                        sp = (u1 *)_mc->gregs[REG_SP];
                        ra = xpc;
 
                        type = EXCEPTION_HARDWARE_ARITHMETIC;
                        val = 0;
 
-                       e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val);
+                       /* Handle the type. */
+
+                       p = signal_handle(type, val, pv, sp, ra, xpc, _p);
 
-                       _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
-                       _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
-                       _mc->psw.addr = (ptrint) asm_handle_exception;
+                       _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) p;
+                       _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
+                       _mc->psw.addr              = (intptr_t) asm_handle_exception;
 
                        return;
                }
@@ -257,6 +331,9 @@ void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
 
        /* Could not handle signal */
 
+#if !defined(NDEBUG)
+       md_dump_context(xpc, _mc);
+#endif
        vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
 }
 
@@ -291,49 +368,24 @@ void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p)
 
 
 #if defined(ENABLE_THREADS)
-void thread_restartcriticalsection(ucontext_t *_uc)
+void md_critical_section_restart(ucontext_t *_uc)
 {
        mcontext_t *_mc;
-       void       *pc;
+       u1         *pc;
+       void       *npc;
 
        _mc = &_uc->uc_mcontext;
 
-       pc = critical_find_restart_point((void *) _mc->psw.addr);
-
-       if (pc != NULL)
-               _mc->psw.addr = (ptrint) pc;
-}
-#endif
-
-
-/* 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);
+       pc = (u1 *)_mc->psw.addr;
 
-       /* Calculate the branch displacement. */
+       npc = critical_find_restart_point(pc);
 
-       disp = targetmpc - branchmpc;
-       disp += 4; /* size of branch */
-       disp /= 2; /* specified in halfwords */
-
-       ASSERT_VALID_BRANCH(disp);      
-
-       /* patch the branch instruction before the mcodeptr */
-
-       mcodeptr[-1] |= (disp & 0xFFFF);
+       if (npc != NULL) {
+               log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
+               _mc->psw.addr = (ptrint) npc;
+       }
 }
+#endif
 
 
 /* md_stacktrace_get_returnaddress *********************************************
@@ -349,13 +401,13 @@ u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
 
        /* on S390 the return address is located on the top of the stackframe */
 
-       ra = *((u1 **) (sp + framesize - SIZEOF_VOID_P));
+       ra = *((u1 **) (sp + framesize - 8));
 
        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
@@ -386,45 +438,66 @@ last 2 instructions the same as in invokevirtual
 
 *******************************************************************************/
 
-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  base;
-       s4  offset;
-       u1 *pa;                             /* patch address                      */
+       uint8_t *pc;
+       uint8_t  base, index;
+       int32_t  offset;
+       void    *pa;                        /* patch address                      */
 
        /* go back to the load before the call instruction */
 
-       ra = ra - 2 /* sizeof bcr */ - 4 /* sizeof l */;
+       pc = ((uint8_t *) ra) - SZ_BCR - SZ_L;
 
        /* get the base register of the load */
 
-       base = ra[2] >> 4;
+       base  = N_RX_GET_BASE(pc);
+       index = N_RX_GET_INDEX(pc);
 
        /* check for the different calls */
 
-       if (base == 0xd) { /* pv relative */
-               /* INVOKESTATIC/SPECIAL */
+       switch (base) {
+               case REG_PV:
+                       /* INVOKESTATIC/SPECIAL */
+
+                       switch (index) {
+                               case R0:
+                                       /* the offset is in the load instruction */
+                                       offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
+                                       break;
+                               case REG_ITMP1:
+                                       /* the offset is in the immediate load before the load */
+                                       offset = N_RI_GET_IMM(pc - SZ_L);
+                                       break;
+                               default:
+                                       assert(0);
+                       }
+
+                       /* add the offset to the procedure vector */
 
-               /* the offset is in the load before the load */
+                       pa = ((uint8_t *) pv) + offset;
+                       break;
 
-               offset = *((s2 *) (ra - 2));
+               case REG_METHODPTR:
+                       /* mptr relative */
+                       /* INVOKEVIRTUAL/INTERFACE */
 
-               /* add the offset to the procedure vector */
+                       offset = N_RX_GET_DISP(pc);
 
-               pa = sfi->pv + offset;
-       }
-       else if (base == 0xc) { /* mptr relative */
-               /* INVOKEVIRTUAL/INTERFACE */
+                       /* return NULL if no mptr was specified (used for replacement) */
 
-               offset = *((u2 *)(ra + 2)) & 0xFFF;
+                       if (mptr == NULL)
+                               return NULL;
 
-               /* add offset to method pointer */
-               
-               pa = mptr + offset;
-       }
-       else {
-               /* catch any problems */
-               assert(0); 
+                       /* add offset to method pointer */
+                       
+                       pa = (uint8_t *)mptr + offset;
+                       break;
+
+               default:
+                       /* catch any problems */
+                       vm_abort("md_jit_method_patch_address");
+                       break;
        }
 
        return pa;
@@ -493,39 +566,117 @@ void md_dcacheflush(u1 *addr, s4 nbytes)
    Patch the given replacement point.
 
 *******************************************************************************/
-#if 0
-void md_patch_replacement_point(rplpoint *rp)
+#if defined(ENABLE_REPLACEMENT)
+void md_patch_replacement_point(u1 *pc, u1 *savedmcode, bool revert)
 {
-    u8 mcode;
+       assert(0);
+}
+#endif
 
-       /* XXX this is probably unsafe! */
+void md_handle_exception(int32_t *regs, int64_t *fregs, int32_t *out) {
 
-       /* save the current machine code */
-       mcode = *(u8*)rp->pc;
+       uint8_t *xptr;
+       uint8_t *xpc;
+       uint8_t *sp;
+       uint8_t *pv;
+       uint8_t *ra;
+       uint8_t *handler;
+       int32_t framesize;
+       int32_t intsave;
+       int32_t fltsave;
+       int64_t *savearea;
+       int i;
+       int reg;
+       int loops = 0;
 
-       /* write spinning instruction */
-       *(u2*)(rp->pc) = 0xebfe;
+       /* get registers */
 
-       /* write 5th byte */
-       rp->pc[4] = (rp->mcode >> 32);
+       xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
+       xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
+       sp = *(uint8_t **)(regs + REG_SP);
 
-       /* write first word */
-    *(u4*)(rp->pc) = (u4) rp->mcode;
 
-       /* store saved mcode */
-       rp->mcode = mcode;
-       
-#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
-       {
-               u1* u1ptr = rp->pc;
-               DISASSINSTR(u1ptr);
-               fflush(stdout);
-       }
-#endif
-                       
-    /* XXX if required asm_cacheflush(rp->pc,8); */
+       /* initialize number of calle saved int regs to restore to 0 */
+       out[0] = 0;
+
+       /* initialize number of calle saved flt regs to restore to 0 */
+       out[1] = 0;
+
+       do {
+
+               ++loops;
+
+               pv = codegen_get_pv_from_pc(xpc);
+
+               handler = exceptions_handle_exception((java_object_t *)xptr, xpc, pv, sp);
+
+               if (handler == NULL) {
+
+                       /* exception was not handled
+                        * get values of calee saved registers and remove stack frame 
+                        */
+
+                       /* read stuff from data segment */
+
+                       framesize = *(int32_t *)(pv + FrameSize);
+
+                       intsave = *(int32_t *)(pv + IntSave);
+                       if (intsave > out[0]) {
+                               out[0] = intsave;
+                       }
+
+                       fltsave = *(int32_t *)(pv + FltSave);
+                       if (fltsave > out[1]) {
+                               out[1] = fltsave;
+                       }
+
+                       /* pointer to register save area */
+
+                       savearea = (int64_t *)(sp + framesize - 8);
+
+                       /* return address */
+
+                       ra = *(uint8_t **)(sp + framesize - 8);
+
+                       /* restore saved registers */
+
+                       for (i = 0; i < intsave; ++i) {
+                               --savearea;
+                               reg = abi_registers_integer_saved[INT_SAV_CNT - 1 - i];
+                               regs[reg] = *(int32_t *)(savearea);
+                       }
+
+                       for (i = 0; i < fltsave; ++i) {
+                               --savearea;
+                               reg = abi_registers_float_saved[FLT_SAV_CNT - 1 - i];
+                               fregs[reg] = *savearea;
+                       }
+
+                       /* remove stack frame */
+
+                       sp += framesize;
+
+                       /* new xpc is call before return address */
+
+                       xpc = ra;
+
+               } else {
+                       xpc = handler;
+               }
+       } while (handler == NULL);
+
+       /* write new values for registers */
+
+       *(uint8_t **)(regs + REG_ITMP3_XPTR) = xptr;
+       *(uint8_t **)(regs + REG_ITMP1_XPC) = xpc;
+       *(uint8_t **)(regs + REG_SP) = sp;
+       *(uint8_t **)(regs + REG_PV) = pv - 0XFFC;
+
+       /* maybe leaf flag */
+
+       out[2] = (loops == 1);
 }
-#endif
+
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where