* src/vm/jit/s390/arch.h (JIT_COMPILER_VIA_SIGNAL): defined.
[cacao.git] / src / vm / jit / s390 / md.c
index 23dedb80bb3ff26ff81556a0abf3b5a1e3a78766..626f382349d2a094da487cd131ea13722a6b67f8 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 8178 2007-07-05 11:13:20Z michi $
-
 */
 
+
 #define _GNU_SOURCE
 
 #include "config.h"
 
 #include <assert.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <ucontext.h>
 
@@ -50,6 +44,7 @@
 #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"
 
 #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);
@@ -90,7 +86,7 @@ void md_dump_context(u1 *pc, mcontext_t *mc) {
        int i;
        u1 *pv;
        methodinfo *m;
-       
+
        union {
                u8 l;
                fpreg_t fr;
@@ -104,10 +100,10 @@ void md_dump_context(u1 *pc, mcontext_t *mc) {
        if (pv == NULL) {
                log_println("No java method found at location.");
        } else {
-               m = ((codeinfo *)(pv + CodeinfoPointer))->m;
+               m = (*(codeinfo **)(pv + CodeinfoPointer))->m;
                log_println(
                        "Java method: class %s, method %s, descriptor %s.",
-                       utf_bytes(m->class->name), utf_bytes(m->name), utf_bytes(m->descriptor)
+                       m->class->name->text, m->name->text, m->descriptor->text
                );
        }
 
@@ -145,18 +141,17 @@ void md_dump_context(u1 *pc, mcontext_t *mc) {
 
 void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
 {
-       stackframeinfo     sfi;
-       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;
@@ -165,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) {
@@ -177,6 +173,9 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
                                is_null = 0;
                        }
                        break;
+               default:
+                       is_null = 0;
+                       break;
        }
 
        if (! is_null) {
@@ -192,25 +191,32 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
        type = EXCEPTION_HARDWARE_NULLPOINTER;
        val = 0;
 
-       e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val, &sfi);
+       /* Handle the type. */
 
-       _mc->gregs[REG_ITMP2_XPC] = (ptrint) xpc;
-       _mc->gregs[REG_ITMP1_XPTR] = (ptrint) e;
-       _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;
+       }
 }
 
-void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
-       stackframeinfo     sfi;
-       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;
@@ -218,24 +224,51 @@ 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] - 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, &sfi);
+               if (EXCEPTION_HARDWARE_COMPILER == type) {
+                       /* The PV from the compiler stub is equal to the XPC. */
+
+                       pv = xpc;
+
+                       /* The return address in is REG_RA */
+
+                       ra = (u1 *)_mc->gregs[REG_RA];
+               }
 
-               _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
-               _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
-               _mc->psw.addr = (ptrint) asm_handle_exception;
+               /* Handle the type. */
 
+               p = signal_handle(type, val, pv, sp, ra, xpc, _p);
+
+               if (EXCEPTION_HARDWARE_COMPILER == type) {
+                       if (NULL == p) {
+                               _mc->gregs[REG_ITMP3_XPTR] = (intptr_t) builtin_retrieve_exception();
+                               _mc->gregs[REG_ITMP1_XPC]  = (intptr_t) xpc;
+                               _mc->psw.addr              = (intptr_t) asm_handle_exception;
+                       } else {
+                               _mc->gregs[REG_PV]         = (intptr_t) p;
+                               _mc->psw.addr              = (intptr_t) p;
+                       }
+               } else {
+                       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);
@@ -253,18 +286,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)
 {
-       stackframeinfo      sfi;
-       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;
@@ -274,17 +306,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 */
@@ -295,7 +327,8 @@ 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] - N_PV_OFFSET;
@@ -305,11 +338,13 @@ void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
                        type = EXCEPTION_HARDWARE_ARITHMETIC;
                        val = 0;
 
-                       e = exceptions_new_hardware_exception(pv, sp, ra, xpc, type, val, &sfi);
+                       /* 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;
                }
@@ -374,36 +409,6 @@ void md_critical_section_restart(ucontext_t *_uc)
 #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);
-
-       /* Calculate the branch displacement. */
-
-       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);
-}
-
-
 /* md_stacktrace_get_returnaddress *********************************************
 
    Returns the return address of the current stackframe, specified by
@@ -417,13 +422,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
@@ -454,36 +459,36 @@ 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, index;
-       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;
-       index = ra[1] & 0xF;
+       base  = N_RX_GET_BASE(pc);
+       index = N_RX_GET_INDEX(pc);
 
        /* check for the different calls */
 
        switch (base) {
-               case 0xd:
+               case REG_PV:
                        /* INVOKESTATIC/SPECIAL */
 
-               
                        switch (index) {
-                               case 0x0:
+                               case R0:
                                        /* the offset is in the load instruction */
-                                       offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
+                                       offset = N_RX_GET_DISP(pc) + N_PV_OFFSET;
                                        break;
-                               case 0x1:
+                               case REG_ITMP1:
                                        /* the offset is in the immediate load before the load */
-                                       offset = *((s2 *) (ra - 2));
+                                       offset = N_RI_GET_IMM(pc - SZ_L);
                                        break;
                                default:
                                        assert(0);
@@ -491,23 +496,28 @@ u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
 
                        /* add the offset to the procedure vector */
 
-                       pa = sfi->pv + offset;
-
+                       pa = ((uint8_t *) pv) + offset;
                        break;
 
-               case 0xc:
+               case REG_METHODPTR:
                        /* mptr relative */
                        /* INVOKEVIRTUAL/INTERFACE */
 
-                       offset = *((u2 *)(ra + 2)) & 0xFFF;
+                       offset = N_RX_GET_DISP(pc);
+
+                       /* return NULL if no mptr was specified (used for replacement) */
+
+                       if (mptr == NULL)
+                               return NULL;
 
                        /* add offset to method pointer */
                        
-                       pa = mptr + offset;
+                       pa = (uint8_t *)mptr + offset;
                        break;
+
                default:
                        /* catch any problems */
-                       assert(0); 
+                       vm_abort("md_jit_method_patch_address");
                        break;
        }
 
@@ -577,39 +587,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) {
+
+       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;
 
-       /* save the current machine code */
-       mcode = *(u8*)rp->pc;
+       /* get registers */
 
-       /* write spinning instruction */
-       *(u2*)(rp->pc) = 0xebfe;
+       xptr = *(uint8_t **)(regs + REG_ITMP3_XPTR);
+       xpc = *(uint8_t **)(regs + REG_ITMP1_XPC);
+       sp = *(uint8_t **)(regs + REG_SP);
 
-       /* write 5th byte */
-       rp->pc[4] = (rp->mcode >> 32);
 
-       /* write first word */
-    *(u4*)(rp->pc) = (u4) rp->mcode;
+       /* initialize number of calle saved int regs to restore to 0 */
+       out[0] = 0;
 
-       /* 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 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