-/* 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>
#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);
int i;
u1 *pv;
methodinfo *m;
-
+
union {
u8 l;
fpreg_t fr;
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
);
}
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;
/* 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) {
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;
/* 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);
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;
/* 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] - N_PV_OFFSET;
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;
}
#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
/* 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, 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);
/* 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;
}
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