* Removed all Id tags.
[cacao.git] / src / vm / jit / s390 / md.c
index 6129ff20a1db309d808130c084cb6b6cd47a9d6b..936fa329ac997daaa88eeedf783871c5a1f503da 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 7848 2007-05-01 21:40:26Z pm $
-
 */
 
+
 #define _GNU_SOURCE
 
 #include "config.h"
 
 #include <assert.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <ucontext.h>
 
@@ -50,6 +44,8 @@
 #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)
@@ -77,14 +73,6 @@ void md_dump_context(u1 *pc, mcontext_t *mc);
 
 void md_init(void)
 {
-       struct sigaction act;
-       
-       act.sa_sigaction = md_signal_handler_sigill;
-       act.sa_flags     = SA_NODEFER | SA_SIGINFO;
-
-       if (sigaction(SIGILL, &act, NULL) == -1)        {
-               vm_abort("%s: error registering SIGILL signal handler.", __FUNCTION__);
-       }
 }
 
 /* md_dump_context ************************************************************
@@ -95,7 +83,9 @@ void md_init(void)
 
 void md_dump_context(u1 *pc, mcontext_t *mc) {
        int i;
-       
+       u1 *pv;
+       methodinfo *m;
+
        union {
                u8 l;
                fpreg_t fr;
@@ -105,6 +95,17 @@ void md_dump_context(u1 *pc, mcontext_t *mc) {
 
        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);
@@ -139,17 +140,18 @@ void md_dump_context(u1 *pc, mcontext_t *mc) {
 
 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;
+       stackframeinfo  sfi;
+       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;
@@ -161,6 +163,7 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
        switch (xpc[0]) {
                case 0x58: /* L */
                case 0x50: /* ST */
+               case 0x55: /* CL (array size check on NULL array) */
                        base = (xpc[2] >> 4) & 0xF;
                        if (base == 0) {
                                is_null = 1;
@@ -170,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) {
@@ -179,30 +185,47 @@ void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
                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);
+       /* create stackframeinfo */
+
+       stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+       /* Handle the type. */
+
+       p = signal_handle(xpc, type, val);
+
+       /* remove stackframeinfo */
+
+       stacktrace_remove_stackframeinfo(&sfi);
 
-       _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_ITMP1_XPTR] = (intptr_t) p;
+               _mc->gregs[REG_ITMP2_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)
+{
+       stackframeinfo  sfi;
+       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,16 +241,30 @@ void md_signal_handler_sigill(int sig, siginfo_t *siginfo, void *_p) {
                /* bits 3-0 designate the exception type */
                type = xpc[1] & 0xF;  
 
-               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);
+               /* create stackframeinfo */
+
+               stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
 
-               _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(xpc, type, val);
+
+               /* remove stackframeinfo */
+
+               stacktrace_remove_stackframeinfo(&sfi);
+
+               if (p != NULL) {
+                       _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
+                       _mc->gregs[REG_ITMP2_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);
@@ -245,17 +282,18 @@ 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;
+       stackframeinfo  sfi;
+       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;
@@ -275,7 +313,7 @@ void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
                        (_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 */
@@ -286,21 +324,32 @@ 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);
+                       /* create stackframeinfo */
+
+                       stacktrace_create_extern_stackframeinfo(&sfi, pv, sp, ra, xpc);
+
+                       /* Handle the type. */
+
+                       p = signal_handle(xpc, type, val);
+
+                       /* remove stackframeinfo */
+
+                       stacktrace_remove_stackframeinfo(&sfi);
 
-                       _mc->gregs[REG_ITMP1_XPTR] = (ptrint)e;
-                       _mc->gregs[REG_ITMP2_XPC] = (ptrint)xpc;
-                       _mc->psw.addr = (ptrint) asm_handle_exception;
+                       _mc->gregs[REG_ITMP1_XPTR] = (intptr_t) p;
+                       _mc->gregs[REG_ITMP2_XPC]  = (intptr_t) xpc;
+                       _mc->psw.addr              = (intptr_t) asm_handle_exception;
 
                        return;
                }
@@ -345,17 +394,22 @@ 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);
+       pc = (u1 *)_mc->psw.addr;
 
-       if (pc != NULL)
-               _mc->psw.addr = (ptrint) pc;
+       npc = critical_find_restart_point(pc);
+
+       if (npc != NULL) {
+               log_println("%s: pc=%p, npc=%p", __FUNCTION__, pc, npc);
+               _mc->psw.addr = (ptrint) npc;
+       }
 }
 #endif
 
@@ -403,7 +457,7 @@ 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;
 }
@@ -442,7 +496,7 @@ last 2 instructions the same as in invokevirtual
 
 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
 {
-       u1  base;
+       u1  base, index;
        s4  offset;
        u1 *pa;                             /* patch address                      */
 
@@ -453,32 +507,53 @@ u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
        /* get the base register of the load */
 
        base = ra[2] >> 4;
+       index = ra[1] & 0xF;
 
        /* check for the different calls */
 
-       if (base == 0xd) { /* pv relative */
-               /* INVOKESTATIC/SPECIAL */
+       switch (base) {
+               case 0xd:
+                       /* INVOKESTATIC/SPECIAL */
 
-               /* the offset is in the load before the load */
+               
+                       switch (index) {
+                               case 0x0:
+                                       /* the offset is in the load instruction */
+                                       offset = ((*(u2 *)(ra + 2)) & 0xFFF) + N_PV_OFFSET;
+                                       break;
+                               case 0x1:
+                                       /* the offset is in the immediate load before the load */
+                                       offset = *((s2 *) (ra - 2));
+                                       break;
+                               default:
+                                       assert(0);
+                       }
 
-               offset = *((s2 *) (ra - 2));
+                       /* add the offset to the procedure vector */
 
-               /* add the offset to the procedure vector */
+                       pa = sfi->pv + offset;
 
-               pa = sfi->pv + offset;
-       }
-       else if (base == 0xc) { /* mptr relative */
-               /* INVOKEVIRTUAL/INTERFACE */
+                       break;
 
-               offset = *((u2 *)(ra + 2)) & 0xFFF;
+               case 0xc:
+                       /* mptr relative */
+                       /* INVOKEVIRTUAL/INTERFACE */
 
-               /* add offset to method pointer */
-               
-               pa = mptr + offset;
-       }
-       else {
-               /* catch any problems */
-               assert(0); 
+                       offset = *((u2 *)(ra + 2)) & 0xFFF;
+
+                       /* return NULL if no mptr was specified (used for replacement) */
+
+                       if (mptr == NULL)
+                               return NULL;
+
+                       /* add offset to method pointer */
+                       
+                       pa = mptr + offset;
+                       break;
+               default:
+                       /* catch any problems */
+                       assert(0); 
+                       break;
        }
 
        return pa;
@@ -547,39 +622,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(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
 {
-    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_ITMP1_XPTR);
+       xpc = *(uint8_t **)(regs + REG_ITMP2_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(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_ITMP1_XPTR) = xptr;
+       *(uint8_t **)(regs + REG_ITMP2_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