* Removed all Id tags.
[cacao.git] / src / vm / jit / mips / emit.c
index e8becb99ff313a7dc9c3f6b9ae4a4f86d4310f3c..924b09b230c386b30659d913a9e2f40a5f671f1c 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/mips/emit.c - MIPS code emitter functions
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 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:
-
-   $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
-
 */
 
 
 #include "config.h"
 
-#include "vm/types.h"
+#include <assert.h>
 
-#include "md-abi.h"
+#include "vm/types.h"
 
 #include "vm/jit/mips/codegen.h"
+#include "vm/jit/mips/md-abi.h"
 
-#if defined(ENABLE_THREADS)
-# include "threads/native/lock.h"
-#endif
+#include "mm/memory.h"
 
+#include "threads/lock-common.h"
+
+#include "vm/builtin.h"
 #include "vm/exceptions.h"
 #include "vm/stringlocal.h" /* XXX for gen_resolvebranch */
+
+#include "vm/jit/abi.h"
 #include "vm/jit/abi-asm.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/dseg.h"
-#include "vm/jit/emit.h"
+#include "vm/jit/emit-common.h"
 #include "vm/jit/jit.h"
+#include "vm/jit/patcher-common.h"
 #include "vm/jit/replace.h"
 
+#include "vmcore/options.h"
 
-/* code generation functions **************************************************/
 
 /* emit_load *******************************************************************
 
@@ -63,7 +60,7 @@
 
 *******************************************************************************/
 
-s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
        codegendata  *cd;
        s4            disp;
@@ -76,80 +73,121 @@ s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
        if (src->flags & INMEMORY) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 8;
+               disp = src->vv.regoff;
 
-               if (IS_FLT_DBL_TYPE(src->type)) {
-                       if (IS_2_WORD_TYPE(src->type))
-                               M_DLD(tempreg, REG_SP, disp);
-                       else
-                               M_FLD(tempreg, REG_SP, disp);
-               }
-               else
+               switch (src->type) {
+#if SIZEOF_VOID_P == 8
+               case TYPE_INT:
+               case TYPE_LNG:
+               case TYPE_ADR:
+                       M_LLD(tempreg, REG_SP, disp);
+                       break;
+#else
+               case TYPE_INT:
+               case TYPE_ADR:
+                       M_ILD(tempreg, REG_SP, disp);
+                       break;
+               case TYPE_LNG:
                        M_LLD(tempreg, REG_SP, disp);
+                       break;
+#endif
+               case TYPE_FLT:
+                       M_FLD(tempreg, REG_SP, disp);
+                       break;
+               case TYPE_DBL:
+                       M_DLD(tempreg, REG_SP, disp);
+                       break;
+               default:
+                       vm_abort("emit_load: unknown type %d", src->type);
+               }
 
                reg = tempreg;
        }
        else
-               reg = src->regoff;
+               reg = src->vv.regoff;
 
        return reg;
 }
 
-/* emit_load_s1 ****************************************************************
 
-   Emits a possible load of the first source operand.
+/* emit_load_low ***************************************************************
+
+   Emits a possible load of the low 32-bits of an operand.
 
 *******************************************************************************/
 
-s4 emit_load_s1(jitdata *jd, instruction *iptr, s4 tempreg)
+#if SIZEOF_VOID_P == 4
+s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
-       stackptr src;
-       s4       reg;
-
-       src = iptr->s1.var;
-
-       reg = emit_load(jd, iptr, src, tempreg);
-
-       return reg;
-}
+       codegendata  *cd;
+       s4            disp;
+       s4            reg;
 
+       assert(src->type == TYPE_LNG);
 
-/* emit_load_s2 ****************************************************************
+       /* get required compiler data */
 
-   Emits a possible load of the second source operand.
+       cd = jd->cd;
 
-*******************************************************************************/
+       if (src->flags & INMEMORY) {
+               COUNT_SPILLS;
 
-s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
+               disp = src->vv.regoff;
 
-       src = iptr->sx.s23.s2.var;
+#if WORDS_BIGENDIAN == 1
+               M_ILD(tempreg, REG_SP, disp + 4);
+#else
+               M_ILD(tempreg, REG_SP, disp);
+#endif
 
-       reg = emit_load(jd, iptr, src, tempreg);
+               reg = tempreg;
+       }
+       else
+               reg = GET_LOW_REG(src->vv.regoff);
 
        return reg;
 }
+#endif /* SIZEOF_VOID_P == 4 */
 
 
-/* emit_load_s3 ****************************************************************
+/* emit_load_high **************************************************************
 
-   Emits a possible load of the third source operand.
+   Emits a possible load of the high 32-bits of an operand.
 
 *******************************************************************************/
 
-s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg)
+#if SIZEOF_VOID_P == 4
+s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
-       stackptr src;
-       s4       reg;
+       codegendata  *cd;
+       s4            disp;
+       s4            reg;
 
-       src = iptr->sx.s23.s3.var;
+       assert(src->type == TYPE_LNG);
 
-       reg = emit_load(jd, iptr, src, tempreg);
+       /* get required compiler data */
+
+       cd = jd->cd;
+
+       if (src->flags & INMEMORY) {
+               COUNT_SPILLS;
+
+               disp = src->vv.regoff;
+
+#if WORDS_BIGENDIAN == 1
+               M_ILD(tempreg, REG_SP, disp);
+#else
+               M_ILD(tempreg, REG_SP, disp + 4);
+#endif
+
+               reg = tempreg;
+       }
+       else
+               reg = GET_HIGH_REG(src->vv.regoff);
 
        return reg;
 }
+#endif /* SIZEOF_VOID_P == 4 */
 
 
 /* emit_store ******************************************************************
@@ -158,7 +196,7 @@ s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg)
 
 *******************************************************************************/
 
-void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
+void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 {
        codegendata  *cd;
        s4            disp;
@@ -170,61 +208,116 @@ void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
        if (dst->flags & INMEMORY) {
                COUNT_SPILLS;
 
-               disp = dst->regoff * 8;
+               disp = dst->vv.regoff;
 
-               if (IS_FLT_DBL_TYPE(dst->type)) {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_DST(d, REG_SP, disp);
-                       else
-                               M_FST(d, REG_SP, disp);
-               } else
+               switch (dst->type) {
+#if SIZEOF_VOID_P == 8
+               case TYPE_INT:
+               case TYPE_LNG:
+               case TYPE_ADR:
+                       M_LST(d, REG_SP, disp);
+                       break;
+#else
+               case TYPE_INT:
+               case TYPE_ADR:
+                       M_IST(d, REG_SP, disp);
+                       break;
+               case TYPE_LNG:
                        M_LST(d, REG_SP, disp);
+                       break;
+#endif
+               case TYPE_FLT:
+                       M_FST(d, REG_SP, disp);
+                       break;
+               case TYPE_DBL:
+                       M_DST(d, REG_SP, disp);
+                       break;
+               default:
+                       vm_abort("emit_store: unknown type %d", dst->type);
+               }
        }
 }
 
-/* emit_store_dst **************************************************************
-
-   Emits a possible store to the destination operand of an instruction.
-
-*******************************************************************************/
-
-void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
-{
-       emit_store(jd, iptr, iptr->dst.var, d);
-}
-
 
 /* emit_copy *******************************************************************
 
-   XXX
+   Generates a register/memory to register/memory copy.
 
 *******************************************************************************/
 
-void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
+void emit_copy(jitdata *jd, instruction *iptr)
 {
-       codegendata  *cd;
-       registerdata *rd;
-       s4            s1, d;
+       codegendata *cd;
+       varinfo     *src;
+       varinfo     *dst;
+       s4           s1, d;
 
        /* get required compiler data */
 
        cd = jd->cd;
-       rd = jd->rd;
 
-       if ((src->regoff != dst->regoff) ||
+       /* get source and destination variables */
+
+       src = VAROP(iptr->s1);
+       dst = VAROP(iptr->dst);
+
+       if ((src->vv.regoff != dst->vv.regoff) ||
                ((src->flags ^ dst->flags) & INMEMORY)) {
-               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
-               s1 = emit_load(jd, iptr, src, d);
 
-               if (s1 != d) {
-                       if (IS_FLT_DBL_TYPE(src->type)) {
-                               if (IS_2_WORD_TYPE(src->type))
-                                       M_DMOV(s1, d);
-                               else
-                                       M_FMOV(s1, d);
-                       }
+               if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
+                       /* emit nothing, as the value won't be used anyway */
+                       return;
+               }
+
+               /* If one of the variables resides in memory, we can eliminate
+                  the register move from/to the temporary register with the
+                  order of getting the destination register and the load. */
+
+               if (IS_INMEMORY(src->flags)) {
+#if SIZEOF_VOID_P == 4
+                       if (IS_2_WORD_TYPE(src->type))
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
                        else
+#endif
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
+                       s1 = emit_load(jd, iptr, src, d);
+               }
+               else {
+                       s1 = emit_load(jd, iptr, src, REG_IFTMP);
+#if SIZEOF_VOID_P == 4
+                       if (IS_2_WORD_TYPE(src->type))
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
+                       else
+#endif
+                               d = codegen_reg_of_var(iptr->opc, dst, s1);
+               }
+
+               if (s1 != d) {
+                       switch (dst->type) {
+#if SIZEOF_VOID_P == 8
+                       case TYPE_INT:
+                       case TYPE_LNG:
+                       case TYPE_ADR:
                                M_MOV(s1, d);
+                               break;
+#else
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_MOV(s1, d);
+                               break;
+                       case TYPE_LNG:
+                               M_LNGMOVE(s1, d);
+                               break;
+#endif
+                       case TYPE_FLT:
+                               M_FMOV(s1, d);
+                               break;
+                       case TYPE_DBL:
+                               M_DMOV(s1, d);
+                               break;
+                       default:
+                               vm_abort("emit_copy: unknown type %d", dst->type);
+                       }
                }
 
                emit_store(jd, iptr, dst, d);
@@ -247,7 +340,7 @@ void emit_iconst(codegendata *cd, s4 d, s4 value)
        else if ((value >= 0) && (value <= 0xffff))
         M_OR_IMM(REG_ZERO, value, d);
        else {
-        disp = dseg_adds4(cd, value);
+        disp = dseg_add_s4(cd, value);
         M_ILD(d, REG_PV, disp);
     }
 }
@@ -263,308 +356,251 @@ void emit_lconst(codegendata *cd, s4 d, s8 value)
 {
        s4 disp;
 
+#if SIZEOF_VOID_P == 8
        if ((value >= -32768) && (value <= 32767))
                M_LADD_IMM(REG_ZERO, value, d);
        else if ((value >= 0) && (value <= 0xffff))
                M_OR_IMM(REG_ZERO, value, d);
        else {
-               disp = dseg_adds8(cd, value);
+               disp = dseg_add_s8(cd, value);
                M_LLD(d, REG_PV, disp);
        }
+#else
+       disp = dseg_add_s8(cd, value);
+       M_LLD(d, REG_PV, disp);
+#endif
 }
 
 
-/* emit_exception_stubs ********************************************************
+/* emit_branch *****************************************************************
+
+   Emits the code for conditional and unconditional branchs.
 
-   Generates the code for the exception stubs.
+   NOTE: The reg argument may contain two packed registers.
 
 *******************************************************************************/
 
-void emit_exception_stubs(jitdata *jd)
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
 {
-       codegendata  *cd;
-       registerdata *rd;
-       exceptionref *eref;
-       s4            targetdisp;
-       s4            disp;
-
-       /* get required compiler data */
-
-       cd = jd->cd;
-       rd = jd->rd;
-
-       /* generate exception stubs */
+       s4 checkdisp;
+       s4 branchdisp;
 
-       targetdisp = 0;
+       /* calculate the different displacements */
 
-       for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
-               gen_resolvebranch(cd->mcodebase + eref->branchpos, 
-                                                 eref->branchpos, cd->mcodeptr - cd->mcodebase);
+       checkdisp  = (disp - 4);
+       branchdisp = (disp - 4) >> 2;
 
-               MCODECHECK(100);
+       /* check which branch to generate */
 
-               /* Check if the exception is an
-                  ArrayIndexOutOfBoundsException.  If so, move index register
-                  into REG_ITMP1. */
+       if (condition == BRANCH_UNCONDITIONAL) {
+               /* check displacement for overflow */
 
-               if (eref->reg != -1)
-                       M_MOV(eref->reg, REG_ITMP1);
+               if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
+                       /* if the long-branches flag isn't set yet, do it */
 
-               /* calcuate exception address */
-
-               M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
-
-               /* move function to call into REG_ITMP3 */
-
-               disp = dseg_addaddress(cd, eref->function);
-               M_ALD(REG_ITMP3, REG_PV, disp);
-
-               if (targetdisp == 0) {
-                       targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
-
-                       M_MOV(REG_PV, rd->argintregs[0]);
-                       M_MOV(REG_SP, rd->argintregs[1]);
-
-                       if (jd->isleafmethod)
-                               M_MOV(REG_RA, rd->argintregs[2]);
-                       else
-                               M_ALD(rd->argintregs[2],
-                                         REG_SP, cd->stackframesize * 8 - SIZEOF_VOID_P);
-
-                       M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
-                       M_MOV(REG_ITMP1, rd->argintregs[4]);
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-                       M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
-                       M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
+                       vm_abort("emit_branch: emit unconditional long-branch code");
+               }
+               else {
+                       M_BR(branchdisp);
+                       M_NOP;
+               }
+       }
+       else {
+               /* and displacement for overflow */
 
-                       if (jd->isleafmethod)
-                               M_AST(REG_RA, REG_SP, 1 * 8);
+               if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
+                       /* if the long-branches flag isn't set yet, do it */
 
-                       M_JSR(REG_RA, REG_ITMP3);
-                       M_NOP;
-                       M_MOV(REG_RESULT, REG_ITMP1_XPTR);
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-                       if (jd->isleafmethod)
-                               M_ALD(REG_RA, REG_SP, 1 * 8);
+                       switch (condition) {
+                       case BRANCH_EQ:
+                               M_BNE(GET_HIGH_REG(reg), GET_LOW_REG(reg), 5);
+                               break;
+                       case BRANCH_NE:
+                               M_BEQ(GET_HIGH_REG(reg), GET_LOW_REG(reg), 5);
+                               break;
+                       case BRANCH_LT:
+                               M_BGEZ(reg, 5);
+                               break;
+                       case BRANCH_GE:
+                               M_BLTZ(reg, 5);
+                               break;
+                       case BRANCH_GT:
+                               M_BLEZ(reg, 5);
+                               break;
+                       case BRANCH_LE:
+                               M_BGTZ(reg, 5);
+                               break;
+                       default:
+                               vm_abort("emit_branch: unknown condition %d", condition);
+                       }
 
-                       M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
-                       M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
+                       /* The actual branch code which is over-jumped (NOTE: we
+                          don't use a branch delay slot here). */
 
-                       disp = dseg_addaddress(cd, asm_handle_exception);
-                       M_ALD(REG_ITMP3, REG_PV, disp);
+                       M_LUI(REG_ITMP3, branchdisp >> 16);
+                       M_OR_IMM(REG_ITMP3, branchdisp, REG_ITMP3);
+                       M_AADD(REG_PV, REG_ITMP3, REG_ITMP3);
                        M_JMP(REG_ITMP3);
                        M_NOP;
+
                }
                else {
-                       disp = (((u4 *) cd->mcodebase) + targetdisp) -
-                               (((u4 *) cd->mcodeptr) + 1);
+                       switch (condition) {
+                       case BRANCH_EQ:
+                               M_BEQ(GET_HIGH_REG(reg), GET_LOW_REG(reg), branchdisp);
+                               break;
+                       case BRANCH_NE:
+                               M_BNE(GET_HIGH_REG(reg), GET_LOW_REG(reg), branchdisp);
+                               break;
+                       case BRANCH_LT:
+                               M_BLTZ(reg, branchdisp);
+                               break;
+                       case BRANCH_GE:
+                               M_BGEZ(reg, branchdisp);
+                               break;
+                       case BRANCH_GT:
+                               M_BGTZ(reg, branchdisp);
+                               break;
+                       case BRANCH_LE:
+                               M_BLEZ(reg, branchdisp);
+                               break;
+                       default:
+                               vm_abort("emit_branch: unknown condition %d", condition);
+                       }
 
-                       M_BR(disp);
+                       /* branch delay */
                        M_NOP;
                }
        }
 }
 
 
-/* emit_patcher_stubs **********************************************************
+/* emit_arithmetic_check *******************************************************
 
-   Generates the code for the patcher stubs.
+   Emit an ArithmeticException check.
 
 *******************************************************************************/
 
-void emit_patcher_stubs(jitdata *jd)
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       codegendata *cd;
-       patchref    *pref;
-       u4           mcode[2];
-       u1          *savedmcodeptr;
-       u1          *tmpmcodeptr;
-       s4           targetdisp;
-       s4           disp;
-
-       /* get required compiler data */
-
-       cd = jd->cd;
-
-       /* generate code patching stub call code */
-
-       targetdisp = 0;
-
-       for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
-               /* check code segment size */
-
-               MCODECHECK(100);
-
-               /* Get machine code which is patched back in later. The
-                  call is 2 instruction words long. */
-
-               tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
-
-               /* We use 2 loads here as an unaligned 8-byte read on 64-bit
-                  MIPS causes a SIGSEGV and using the same code for both
-                  architectures is much better. */
-
-               mcode[0] = ((u4 *) tmpmcodeptr)[0];
-               mcode[1] = ((u4 *) tmpmcodeptr)[1];
-
-               /* Patch in the call to call the following code (done at
-                  compile time). */
-
-               savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
-               cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
-
-               disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
-
-               if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
-                       *exceptionptr =
-                               new_internalerror("Jump offset is out of range: %d > +/-%d",
-                                                                 disp, 0x00007fff);
-                       return;
-               }
-
-               M_BR(disp);
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_BNEZ(reg, 2);
                M_NOP;
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
+       }
+}
 
-               cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
-
-               /* create stack frame */
-
-               M_ASUB_IMM(REG_SP, 6 * 8, REG_SP);
-
-               /* calculate return address and move it onto the stack */
-
-               M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
-               M_AST(REG_ITMP3, REG_SP, 5 * 8);
-
-               /* move pointer to java_objectheader onto stack */
-
-#if defined(ENABLE_THREADS)
-               /* create a virtual java_objectheader */
-
-               (void) dseg_addaddress(cd, NULL);                          /* flcword */
-               (void) dseg_addaddress(cd, lock_get_initial_lock_word());
-               disp = dseg_addaddress(cd, NULL);                          /* vftbl   */
-
-               M_LDA(REG_ITMP3, REG_PV, disp);
-               M_AST(REG_ITMP3, REG_SP, 4 * 8);
-#else
-               /* do nothing */
-#endif
-
-               /* move machine code onto stack */
-
-               disp = dseg_adds4(cd, mcode[0]);
-               M_ILD(REG_ITMP3, REG_PV, disp);
-               M_IST(REG_ITMP3, REG_SP, 3 * 8);
 
-               disp = dseg_adds4(cd, mcode[1]);
-               M_ILD(REG_ITMP3, REG_PV, disp);
-               M_IST(REG_ITMP3, REG_SP, 3 * 8 + 4);
+/* emit_arrayindexoutofbounds_check ********************************************
 
-               /* move class/method/field reference onto stack */
+   Emit an ArrayIndexOutOfBoundsException check.
 
-               disp = dseg_addaddress(cd, pref->ref);
-               M_ALD(REG_ITMP3, REG_PV, disp);
-               M_AST(REG_ITMP3, REG_SP, 2 * 8);
+*******************************************************************************/
 
-               /* move data segment displacement onto stack */
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_array_t, size));
+               M_CMPULT(s2, REG_ITMP3, REG_ITMP3);
+               M_BNEZ(REG_ITMP3, 2);
+               M_NOP;
+               M_ALD_INTERN(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
+       }
+}
 
-               disp = dseg_adds4(cd, pref->disp);
-               M_ILD(REG_ITMP3, REG_PV, disp);
-               M_IST(REG_ITMP3, REG_SP, 1 * 8);
 
-               /* move patcher function pointer onto stack */
+/* emit_classcast_check ********************************************************
 
-               disp = dseg_addaddress(cd, pref->patcher);
-               M_ALD(REG_ITMP3, REG_PV, disp);
-               M_AST(REG_ITMP3, REG_SP, 0 * 8);
+   Emit a ClassCastException check.
 
-               if (targetdisp == 0) {
-                       targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
+*******************************************************************************/
 
-                       disp = dseg_addaddress(cd, asm_patcher_wrapper);
-                       M_ALD(REG_ITMP3, REG_PV, disp);
-                       M_JMP(REG_ITMP3);
-                       M_NOP;
+void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               switch (condition) {
+               case ICMD_IFEQ:
+                       M_BNEZ(reg, 2);
+                       break;
+
+               case ICMD_IFNE:
+                       M_BEQZ(reg, 2);
+                       break;
+
+               case ICMD_IFLE:
+                       M_BGTZ(reg, 2);
+                       break;
+
+               default:
+                       vm_abort("emit_classcast_check: unknown condition %d", condition);
                }
-               else {
-                       disp = (((u4 *) cd->mcodebase) + targetdisp) -
-                               (((u4 *) cd->mcodeptr) + 1);
 
-                       M_BR(disp);
-                       M_NOP;
-               }
+               M_NOP;
+               M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
        }
 }
 
 
-/* emit_replacement_stubs ******************************************************
+/* emit_nullpointer_check ******************************************************
 
-   Generates the code for the replacement stubs.
+   Emit a NullPointerException check.
 
 *******************************************************************************/
 
-void emit_replacement_stubs(jitdata *jd)
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       codegendata *cd;
-       codeinfo    *code;
-       rplpoint    *rplp;
-       u1          *savedmcodeptr;
-       s4           disp;
-       s4           i;
-
-       /* get required compiler data */
-
-       cd   = jd->cd;
-       code = jd->code;
-
-       rplp = code->rplpoints;
-
-       for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
-               /* check code segment size */
-
-               MCODECHECK(100);
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_BNEZ(reg, 2);
+               M_NOP;
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
+       }
+}
 
-               /* note start of stub code */
 
-               rplp->outcode = (u1 *) (ptrint) (cd->mcodeptr - cd->mcodebase);
+/* emit_exception_check ********************************************************
 
-               /* make machine code for patching */
+   Emit an Exception check.
 
-               savedmcodeptr = cd->mcodeptr;
-               cd->mcodeptr  = (u1 *) &(rplp->mcode);
+*******************************************************************************/
 
-               disp = (ptrint) ((s4 *) rplp->outcode - (s4 *) rplp->pc) - 1;
+void emit_exception_check(codegendata *cd, instruction *iptr)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_BNEZ(REG_RESULT, 2);
+               M_NOP;
+               M_ALD_INTERN(REG_RESULT, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
+       }
+}
 
-               if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
-                       *exceptionptr =
-                               new_internalerror("Jump offset is out of range: %d > +/-%d",
-                                                                 disp, 0x00007fff);
-                       return;
-               }
 
-               M_BR(disp);
-               M_NOP; /* delay slot */
+/* emit_trap *******************************************************************
 
-               cd->mcodeptr = savedmcodeptr;
+   Emit a trap instruction and return the original machine code.
 
-               /* create stack frame - 16-byte aligned */
+*******************************************************************************/
 
-               M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
+uint32_t emit_trap(codegendata *cd)
+{
+       uint32_t mcode;
 
-               /* push address of `rplpoint` struct */
+       /* Get machine code which is patched back in later. The
+          trap is 1 instruction word long. */
 
-               disp = dseg_addaddress(cd, rplp);
-               M_ALD(REG_ITMP3, REG_PV, disp);
-               M_AST(REG_ITMP3, REG_SP, 0 * 8);
+       mcode = *((u4 *) cd->mcodeptr);
 
-               /* jump to replacement function */
+       M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
 
-               disp = dseg_addaddress(cd, asm_replacement_out);
-               M_ALD(REG_ITMP3, REG_PV, disp);
-               M_JMP(REG_ITMP3);
-               M_NOP; /* delay slot */
-       }
+       return mcode;
 }
 
 
@@ -582,7 +618,7 @@ void emit_verbosecall_enter(jitdata *jd)
        registerdata *rd;
        methoddesc   *md;
        s4            disp;
-       s4            i, t;
+       s4            i, j, t;
 
        /* get required compiler data */
 
@@ -596,48 +632,74 @@ void emit_verbosecall_enter(jitdata *jd)
 
        M_NOP;
 
-       M_LDA(REG_SP, REG_SP, -(2 + ARG_CNT + TMP_CNT) * 8);
-       M_AST(REG_RA, REG_SP, 1 * 8);
+       M_LDA(REG_SP, REG_SP, -(PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8));
+       M_AST(REG_RA, REG_SP, PA_SIZE + 1 * 8);
 
-       /* save argument registers */
+       /* save argument registers (we store the registers as address
+          types, so it's correct for MIPS32 too) */
 
        for (i = 0; i < INT_ARG_CNT; i++)
-               M_LST(rd->argintregs[i], REG_SP, (2 + i) * 8);
+               M_AST(abi_registers_integer_argument[i], REG_SP, PA_SIZE + (2 + i) * 8);
 
        for (i = 0; i < FLT_ARG_CNT; i++)
-               M_DST(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
+               M_DST(abi_registers_float_argument[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
 
        /* save temporary registers for leaf methods */
 
        if (jd->isleafmethod) {
                for (i = 0; i < INT_TMP_CNT; i++)
-                       M_LST(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
+                       M_AST(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
 
                for (i = 0; i < FLT_TMP_CNT; i++)
-                       M_DST(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
+                       M_DST(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
        }
 
-       /* load float arguments into integer registers */
+       /* Load float arguments into integer registers.  MIPS32 has less
+          float argument registers than integer ones, we need to check
+          that. */
 
-       for (i = 0; i < md->paramcount && i < INT_ARG_CNT; i++) {
+       for (i = 0; i < md->paramcount && i < INT_ARG_CNT && i < FLT_ARG_CNT; i++) {
                t = md->paramtypes[i].type;
 
                if (IS_FLT_DBL_TYPE(t)) {
                        if (IS_2_WORD_TYPE(t)) {
-                               M_DST(rd->argfltregs[i], REG_SP, 0 * 8);
-                               M_LLD(rd->argintregs[i], REG_SP, 0 * 8);
+                               M_DST(abi_registers_float_argument[i], REG_SP, 0 * 8);
+                               M_LLD(abi_registers_integer_argument[i], REG_SP, 0 * 8);
                        }
                        else {
-                               M_FST(rd->argfltregs[i], REG_SP, 0 * 8);
-                               M_ILD(rd->argintregs[i], REG_SP, 0 * 8);
+                               M_FST(abi_registers_float_argument[i], REG_SP, 0 * 8);
+                               M_ILD(abi_registers_integer_argument[i], REG_SP, 0 * 8);
                        }
                }
        }
 
-       disp = dseg_addaddress(cd, m);
+#if SIZEOF_VOID_P == 4
+               for (i = 0, j = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
+                       t = md->paramtypes[i].type;
+
+                       if (IS_INT_LNG_TYPE(t)) {
+                               if (IS_2_WORD_TYPE(t)) {
+                                       M_ILD(abi_registers_integer_argument[j], REG_SP, PA_SIZE + (2 + i) * 8);
+                                       M_ILD(abi_registers_integer_argument[j + 1], REG_SP, PA_SIZE + (2 + i) * 8 + 4);
+                               }
+                               else {
+# if WORDS_BIGENDIAN == 1
+                                       M_MOV(REG_ZERO, abi_registers_integer_argument[j]);
+                                       M_ILD(abi_registers_integer_argument[j + 1], REG_SP, PA_SIZE + (2 + i) * 8);
+# else
+                                       M_ILD(abi_registers_integer_argument[j], REG_SP, PA_SIZE + (2 + i) * 8);
+                                       M_MOV(REG_ZERO, abi_registers_integer_argument[j + 1]);
+# endif
+                               }
+                               j += 2;
+                       }
+               }
+#endif
+
+       disp = dseg_add_address(cd, m);
        M_ALD(REG_ITMP1, REG_PV, disp);
-       M_AST(REG_ITMP1, REG_SP, 0 * 8);
-       disp = dseg_addaddress(cd, builtin_trace_args);
+       M_AST(REG_ITMP1, REG_SP, PA_SIZE + 0 * 8);
+       disp = dseg_add_functionptr(cd, builtin_verbosecall_enter);
        M_ALD(REG_ITMP3, REG_PV, disp);
        M_JSR(REG_RA, REG_ITMP3);
        M_NOP;
@@ -645,23 +707,23 @@ void emit_verbosecall_enter(jitdata *jd)
        /* restore argument registers */
 
        for (i = 0; i < INT_ARG_CNT; i++)
-               M_LLD(rd->argintregs[i], REG_SP, (2 + i) * 8);
+               M_ALD(abi_registers_integer_argument[i], REG_SP, PA_SIZE + (2 + i) * 8);
 
        for (i = 0; i < FLT_ARG_CNT; i++)
-               M_DLD(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
+               M_DLD(abi_registers_float_argument[i], REG_SP, PA_SIZE + (2 + INT_ARG_CNT + i) * 8);
 
        /* restore temporary registers for leaf methods */
 
        if (jd->isleafmethod) {
                for (i = 0; i < INT_TMP_CNT; i++)
-                       M_LLD(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
+                       M_ALD(rd->tmpintregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + i) * 8);
 
                for (i = 0; i < FLT_TMP_CNT; i++)
-                       M_DLD(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
+                       M_DLD(rd->tmpfltregs[i], REG_SP, PA_SIZE + (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
        }
 
-       M_ALD(REG_RA, REG_SP, 1 * 8);
-       M_LDA(REG_SP, REG_SP, (2 + ARG_CNT + TMP_CNT) * 8);
+       M_ALD(REG_RA, REG_SP, PA_SIZE + 1 * 8);
+       M_LDA(REG_SP, REG_SP, PA_SIZE + (2 + ARG_CNT + TMP_CNT) * 8);
 
        /* mark trace code */
 
@@ -674,6 +736,8 @@ void emit_verbosecall_enter(jitdata *jd)
 
    Generates the code for the call trace.
 
+   void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
+
 *******************************************************************************/
 
 #if !defined(NDEBUG)
@@ -682,6 +746,7 @@ void emit_verbosecall_exit(jitdata *jd)
        methodinfo   *m;
        codegendata  *cd;
        registerdata *rd;
+       methoddesc   *md;
        s4            disp;
 
        /* get required compiler data */
@@ -690,33 +755,73 @@ void emit_verbosecall_exit(jitdata *jd)
        cd = jd->cd;
        rd = jd->rd;
 
+       md = m->parseddesc;
+
        /* mark trace code */
 
        M_NOP;
 
-       M_LDA(REG_SP, REG_SP, -4 * 8);              /* keep stack 16-byte aligned */
-       M_LST(REG_RA, REG_SP, 0 * 8);
+#if SIZEOF_VOID_P == 8
+       M_ASUB_IMM(REG_SP, 4 * 8, REG_SP);          /* keep stack 16-byte aligned */
+       M_AST(REG_RA, REG_SP, 0 * 8);
 
        M_LST(REG_RESULT, REG_SP, 1 * 8);
        M_DST(REG_FRESULT, REG_SP, 2 * 8);
 
-       disp = dseg_addaddress(cd, m);
-       M_ALD(rd->argintregs[0], REG_PV, disp);
+       M_MOV(REG_RESULT, REG_A0);
+       M_DMOV(REG_FRESULT, REG_FA1);
+       M_FMOV(REG_FRESULT, REG_FA2);
+
+       disp = dseg_add_address(cd, m);
+       M_ALD(REG_A4, REG_PV, disp);
+#else
+       M_ASUB_IMM(REG_SP, (8*4 + 4 * 8), REG_SP);
+       M_AST(REG_RA, REG_SP, 8*4 + 0 * 8);
+
+       M_LST(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
+       M_DST(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
+
+       switch (md->returntype.type) {
+       case TYPE_LNG:
+               M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
+               break;
+
+       default:
+# if WORDS_BIGENDIAN == 1
+               M_MOV(REG_ZERO, REG_A0);
+               M_MOV(REG_RESULT, REG_A1);
+# else
+               M_MOV(REG_RESULT, REG_A0);
+               M_MOV(REG_ZERO, REG_A1);
+# endif
+       }
 
-       M_MOV(REG_RESULT, rd->argintregs[1]);
-       M_DMOV(REG_FRESULT, rd->argfltregs[2]);
-       M_FMOV(REG_FRESULT, rd->argfltregs[3]);
+       M_LLD(REG_A2_A3_PACKED, REG_SP, 8*4 + 2 * 8);
+       M_FST(REG_FRESULT, REG_SP, 4*4 + 0 * 4);
 
-       disp = dseg_addaddress(cd, builtin_displaymethodstop);
+       disp = dseg_add_address(cd, m);
+       M_ALD(REG_ITMP1, REG_PV, disp);
+       M_AST(REG_ITMP1, REG_SP, 4*4 + 1 * 4);
+#endif
+
+       disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
        M_ALD(REG_ITMP3, REG_PV, disp);
        M_JSR(REG_RA, REG_ITMP3);
        M_NOP;
 
+#if SIZEOF_VOID_P == 8
        M_DLD(REG_FRESULT, REG_SP, 2 * 8);
        M_LLD(REG_RESULT, REG_SP, 1 * 8);
 
-       M_LLD(REG_RA, REG_SP, 0 * 8);
-       M_LDA(REG_SP, REG_SP, 4 * 8);
+       M_ALD(REG_RA, REG_SP, 0 * 8);
+       M_AADD_IMM(REG_SP, 4 * 8, REG_SP);
+#else
+       M_DLD(REG_FRESULT, REG_SP, 8*4 + 2 * 8);
+       M_LLD(REG_RESULT_PACKED, REG_SP, 8*4 + 1 * 8);
+
+       M_ALD(REG_RA, REG_SP, 8*4 + 0 * 8);
+       M_AADD_IMM(REG_SP, 8*4 + 4 * 8, REG_SP);
+#endif
 
        /* mark trace code */