-/* 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.
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 ***************************************************
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;
/* 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) {
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;
/* 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);
}
}
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;
/* 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 */
_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;
}
/* Could not handle signal */
+#if !defined(NDEBUG)
+ md_dump_context(xpc, _mc);
+#endif
vm_abort("%s: floating point exception at %p, aborting.", __FUNCTION__, xpc);
}
#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 *********************************************
/* 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
*******************************************************************************/
-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;
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