* Merged in twisti-branch.
[cacao.git] / src / vm / jit / powerpc / emit.c
index 7490696454a916d2e39c09393e860cfb7c051e19..1b77a9f0c67591444869a5e9546ba3529b8e3652 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/powerpc/emit.c - PowerPC 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 $
+   $Id: emit.c 4398 2006-01-31 23:43:08Z twisti $
 
 */
 
 
 #include "vm/jit/powerpc/codegen.h"
 
+#include "mm/memory.h"
+
+#if defined(ENABLE_THREADS)
+# include "threads/native/lock.h"
+#endif
+
 #include "vm/builtin.h"
+#include "vm/exceptions.h"
+
 #include "vm/jit/asmpart.h"
+#include "vm/jit/codegen-common.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/replace.h"
 
+#include "vmcore/options.h"
+
 
 /* emit_load *******************************************************************
 
@@ -57,7 +62,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;
@@ -67,28 +72,33 @@ s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 4;
-
-               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 {
-                       if (IS_2_WORD_TYPE(src->type))
-                               M_LLD(tempreg, REG_SP, disp);
-                       else
-                               M_ILD(tempreg, REG_SP, disp);
+               disp = src->vv.regoff * 4;
+
+               switch (src->type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+                       M_ILD(tempreg, REG_SP, disp);
+                       break;
+               case TYPE_LNG:
+                       M_LLD(tempreg, REG_SP, disp);
+                       break;
+               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;
 }
@@ -100,7 +110,7 @@ s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
 
 *******************************************************************************/
 
-s4 emit_load_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
        codegendata  *cd;
        s4            disp;
@@ -112,17 +122,17 @@ s4 emit_load_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 4;
+               disp = src->vv.regoff * 4;
 
                M_ILD(tempreg, REG_SP, disp + 4);
 
                reg = tempreg;
        }
        else
-               reg = GET_LOW_REG(src->regoff);
+               reg = GET_LOW_REG(src->vv.regoff);
 
        return reg;
 }
@@ -134,7 +144,7 @@ s4 emit_load_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
 
 *******************************************************************************/
 
-s4 emit_load_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
        codegendata  *cd;
        s4            disp;
@@ -146,402 +156,340 @@ s4 emit_load_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 4;
+               disp = src->vv.regoff * 4;
 
                M_ILD(tempreg, REG_SP, disp);
 
                reg = tempreg;
        }
        else
-               reg = GET_HIGH_REG(src->regoff);
+               reg = GET_HIGH_REG(src->vv.regoff);
 
        return reg;
 }
 
 
-/* emit_load_s1 ****************************************************************
-
-   Emits a possible load of the first source operand.
-
-*******************************************************************************/
-
-s4 emit_load_s1(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->s1.var;
-
-       reg = emit_load(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s2 ****************************************************************
+/* emit_store ******************************************************************
 
-   Emits a possible load of the second source operand.
+   Emit a possible store for the given variable.
 
 *******************************************************************************/
 
-s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg)
+void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 {
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s2.var;
-
-       reg = emit_load(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s3 ****************************************************************
-
-   Emits a possible load of the third source operand.
-
-*******************************************************************************/
+       codegendata *cd;
+       s4           disp;
 
-s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
+       /* get required compiler data */
 
-       src = iptr->sx.s23.s3.var;
+       cd = jd->cd;
 
-       reg = emit_load(jd, iptr, src, tempreg);
+       if (IS_INMEMORY(dst->flags)) {
+               COUNT_SPILLS;
 
-       return reg;
+               disp = dst->vv.regoff * 4;
+
+               switch (dst->type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+                       M_IST(d, REG_SP, disp);
+                       break;
+               case TYPE_LNG:
+                       M_LST(d, REG_SP, disp);
+                       break;
+               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_load_s1_low ************************************************************
+/* emit_copy *******************************************************************
 
-   Emits a possible load of the low 32-bits of the first long source
-   operand.
+   Generates a register/memory to register/memory copy.
 
 *******************************************************************************/
 
-s4 emit_load_s1_low(jitdata *jd, instruction *iptr, s4 tempreg)
+void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
 {
-       stackptr src;
-       s4       reg;
-
-       src = iptr->s1.var;
-
-       reg = emit_load_low(jd, iptr, src, tempreg);
+       codegendata  *cd;
+       s4            s1, d;
 
-       return reg;
-}
+       /* get required compiler data */
 
+       cd = jd->cd;
 
-/* emit_load_s2_low ************************************************************
+       if ((src->vv.regoff != dst->vv.regoff) ||
+               (IS_INMEMORY(src->flags ^ dst->flags))) {
 
-   Emits a possible load of the low 32-bits of the second long source
-   operand.
+               /* 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 (IS_LNG_TYPE(src->type))
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
+                       else
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
 
-s4 emit_load_s2_low(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
+                       s1 = emit_load(jd, iptr, src, d);
+               }
+               else {
+                       if (IS_LNG_TYPE(src->type))
+                               s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
+                       else
+                               s1 = emit_load(jd, iptr, src, REG_IFTMP);
 
-       src = iptr->sx.s23.s2.var;
+                       d = codegen_reg_of_var(iptr->opc, dst, s1);
+               }
 
-       reg = emit_load_low(jd, iptr, src, tempreg);
+               if (s1 != d) {
+                       switch (src->type) {
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_MOV(s1, d);
+                               break;
+                       case TYPE_LNG:
+                               M_MOV(GET_LOW_REG(s1), GET_LOW_REG(d));
+                               M_MOV(GET_HIGH_REG(s1), GET_HIGH_REG(d));
+                               break;
+                       case TYPE_FLT:
+                       case TYPE_DBL:
+                               M_FMOV(s1, d);
+                               break;
+                       default:
+                               vm_abort("emit_copy: unknown type %d", dst->type);
+                       }
+               }
 
-       return reg;
+               emit_store(jd, iptr, dst, d);
+       }
 }
 
 
-/* emit_load_s3_low ************************************************************
+/* emit_iconst *****************************************************************
 
-   Emits a possible load of the low 32-bits of the third long source
-   operand.
+   XXX
 
 *******************************************************************************/
 
-s4 emit_load_s3_low(jitdata *jd, instruction *iptr, s4 tempreg)
+void emit_iconst(codegendata *cd, s4 d, s4 value)
 {
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s3.var;
-
-       reg = emit_load_low(jd, iptr, src, tempreg);
+       s4 disp;
 
-       return reg;
+       if ((value >= -32768) && (value <= 32767))
+               M_LDA_INTERN(d, REG_ZERO, value);
+       else {
+               disp = dseg_add_s4(cd, value);
+               M_ILD(d, REG_PV, disp);
+       }
 }
 
 
-/* emit_load_s1_high ***********************************************************
+/* emit_branch *****************************************************************
 
-   Emits a possible load of the high 32-bits of the first long source
-   operand.
+   Emits the code for conditional and unconditional branchs.
 
 *******************************************************************************/
 
-s4 emit_load_s1_high(jitdata *jd, instruction *iptr, s4 tempreg)
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
 {
-       stackptr src;
-       s4       reg;
+       s4 checkdisp;
+       s4 branchdisp;
 
-       src = iptr->s1.var;
+       /* calculate the different displacements */
 
-       reg = emit_load_high(jd, iptr, src, tempreg);
-
-       return reg;
-}
+       checkdisp  =  disp + 4;
+       branchdisp = (disp - 4) >> 2;
 
+       /* check which branch to generate */
 
-/* emit_load_s2_high ***********************************************************
+       if (condition == BRANCH_UNCONDITIONAL) {
+               /* check displacement for overflow */
 
-   Emits a possible load of the high 32-bits of the second long source
-   operand.
+               if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
+                       /* if the long-branches flag isn't set yet, do it */
 
-*******************************************************************************/
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-s4 emit_load_s2_high(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
+                       vm_abort("emit_branch: emit unconditional long-branch code");
+               }
+               else {
+                       M_BR(branchdisp);
+               }
+       }
+       else {
+               /* and displacement for overflow */
 
-       src = iptr->sx.s23.s2.var;
+               if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
+                       /* if the long-branches flag isn't set yet, do it */
 
-       reg = emit_load_high(jd, iptr, src, tempreg);
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-       return reg;
+                       switch (condition) {
+                       case BRANCH_EQ:
+                               M_BNE(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_NE:
+                               M_BEQ(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_LT:
+                               M_BGE(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_GE:
+                               M_BLT(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_GT:
+                               M_BLE(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_LE:
+                               M_BGT(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_NAN:
+                               vm_abort("emit_branch: long BRANCH_NAN");
+                               break;
+                       default:
+                               vm_abort("emit_branch: unknown condition %d", condition);
+                       }
+               }
+               else {
+                       switch (condition) {
+                       case BRANCH_EQ:
+                               M_BEQ(branchdisp);
+                               break;
+                       case BRANCH_NE:
+                               M_BNE(branchdisp);
+                               break;
+                       case BRANCH_LT:
+                               M_BLT(branchdisp);
+                               break;
+                       case BRANCH_GE:
+                               M_BGE(branchdisp);
+                               break;
+                       case BRANCH_GT:
+                               M_BGT(branchdisp);
+                               break;
+                       case BRANCH_LE:
+                               M_BLE(branchdisp);
+                               break;
+                       case BRANCH_NAN:
+                               M_BNAN(branchdisp);
+                               break;
+                       default:
+                               vm_abort("emit_branch: unknown condition %d", condition);
+                       }
+               }
+       }
 }
 
 
-/* emit_load_s3_high ***********************************************************
+/* emit_arithmetic_check *******************************************************
 
-   Emits a possible load of the high 32-bits of the third long source
-   operand.
+   Emit an ArithmeticException check.
 
 *******************************************************************************/
 
-s4 emit_load_s3_high(jitdata *jd, instruction *iptr, s4 tempreg)
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s3.var;
-
-       reg = emit_load_high(jd, iptr, src, tempreg);
-
-       return reg;
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(reg);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
+       }
 }
 
 
-/* emit_store ******************************************************************
+/* emit_arrayindexoutofbounds_check ********************************************
 
-   XXX
+   Emit a ArrayIndexOutOfBoundsException check.
 
 *******************************************************************************/
 
-void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
 {
-       codegendata *cd;
-
-       /* get required compiler data */
-
-       cd = jd->cd;
-
-       if (dst->flags & INMEMORY) {
-               COUNT_SPILLS;
-
-               if (IS_FLT_DBL_TYPE(dst->type)) {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_DST(d, REG_SP, dst->regoff * 4);
-                       else
-                               M_FST(d, REG_SP, dst->regoff * 4);
-               }
-               else {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_LST(d, REG_SP, dst->regoff * 4);
-                       else
-                               M_IST(d, REG_SP, dst->regoff * 4);
-               }
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
+               M_TRAPGEU(s2, REG_ITMP3);
        }
 }
 
 
-/* emit_store_dst **************************************************************
+/* emit_classcast_check ********************************************************
 
-   This function generates the code to store the result of an
-   operation back into a spilled pseudo-variable.  If the
-   pseudo-variable has not been spilled in the first place, this
-   function will generate nothing.
-    
-*******************************************************************************/
-
-void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
-{
-       emit_store(jd, iptr, iptr->dst.var, d);
-}
-
-
-/* emit_copy *******************************************************************
-
-   XXX
+   Emit a ClassCastException check.
 
 *******************************************************************************/
 
-void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
+void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
 {
-       codegendata  *cd;
-       registerdata *rd;
-       s4            s1, d;
-
-       /* get required compiler data */
-
-       cd = jd->cd;
-       rd = jd->rd;
-
-       if (src->type == TYPE_LNG)
-               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_ITMP12_PACKED);
-       else
-               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
-
-       if ((src->regoff != dst->regoff) ||
-               ((src->flags ^ dst->flags) & INMEMORY)) {
-               s1 = emit_load(jd, iptr, src, d);
-
-               if (s1 != d) {
-                       if (IS_FLT_DBL_TYPE(src->type))
-                               M_FMOV(s1, d);
-                       else {
-                               if (IS_2_WORD_TYPE(src->type)) {
-                                       M_MOV(GET_LOW_REG(s1), GET_LOW_REG(d));
-                                       M_MOV(GET_HIGH_REG(s1), GET_HIGH_REG(d));
-                }
-                               else
-                    M_MOV(s1, d);
-                       }
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               switch (condition) {
+               case BRANCH_LE:
+                       M_BGT(1);
+                       break;
+               case BRANCH_EQ:
+                       M_BNE(1);
+                       break;
+               case BRANCH_GT:
+                       M_BLE(1);
+                       break;
+               default:
+                       vm_abort("emit_classcast_check: unknown condition %d", condition);
                }
-
-               emit_store(jd, iptr, dst, d);
+               M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
        }
 }
 
 
-/* emit_iconst *****************************************************************
+/* emit_nullpointer_check ******************************************************
 
-   XXX
+   Emit a NullPointerException check.
 
 *******************************************************************************/
 
-void emit_iconst(codegendata *cd, s4 d, s4 value)
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       s4 disp;
-
-       if ((value >= -32768) && (value <= 32767))
-               M_LDA_INTERN(d, REG_ZERO, value);
-       else {
-               disp = dseg_add_s4(cd, value);
-               M_ILD(d, REG_PV, disp);
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(reg);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
        }
 }
 
 
-/* emit_exception_stubs ********************************************************
+/* emit_exception_check ********************************************************
 
-   Generates the code for the exception stubs.
+   Emit an Exception check.
 
 *******************************************************************************/
 
-void emit_exception_stubs(jitdata *jd)
+void emit_exception_check(codegendata *cd, instruction *iptr)
 {
-       codegendata  *cd;
-       registerdata *rd;
-       exceptionref *eref;
-       s4            targetdisp;
-       s4            disp;
-
-       /* get required compiler data */
-
-       cd = jd->cd;
-       rd = jd->rd;
-
-       /* generate exception stubs */
-
-       targetdisp = 0;
-
-       for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
-               gen_resolvebranch(cd->mcodebase + eref->branchpos, 
-                                                 eref->branchpos, cd->mcodeptr - cd->mcodebase);
-
-               MCODECHECK(100);
-
-               /* Move the value register to a temporary register, if
-                  there is the need for it. */
-
-               if (eref->reg != -1)
-                       M_MOV(eref->reg, REG_ITMP1);
-
-               /* calcuate exception address */
-
-               M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
-
-               /* move function to call into REG_ITMP3 */
-
-               disp = dseg_add_functionptr(cd, eref->function);
-               M_ALD(REG_ITMP3, REG_PV, disp);
-
-               if (targetdisp == 0) {
-                   targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
-
-                       if (jd->isleafmethod) {
-                               M_MFLR(REG_ZERO);
-                               M_AST(REG_ZERO, REG_SP, cd->stackframesize * 4 + LA_LR_OFFSET);
-                       }
-
-                       M_MOV(REG_PV, rd->argintregs[0]);
-                       M_MOV(REG_SP, rd->argintregs[1]);
-
-                       if (jd->isleafmethod)
-                               M_MOV(REG_ZERO, rd->argintregs[2]);
-                       else
-                               M_ALD(rd->argintregs[2],
-                                         REG_SP, cd->stackframesize * 4 + LA_LR_OFFSET);
-
-                       M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
-                       M_MOV(REG_ITMP1, rd->argintregs[4]);
-
-                       M_STWU(REG_SP, REG_SP, -(LA_SIZE + 6 * 4));
-                       M_AST(REG_ITMP2_XPC, REG_SP, LA_SIZE + 5 * 4);
-
-                       M_MTCTR(REG_ITMP3);
-                       M_JSR;
-                       M_MOV(REG_RESULT, REG_ITMP1_XPTR);
-
-                       M_ALD(REG_ITMP2_XPC, REG_SP, LA_SIZE + 5 * 4);
-                       M_IADD_IMM(REG_SP, LA_SIZE + 6 * 4, REG_SP);
-
-                       if (jd->isleafmethod) {
-                               /* XXX FIXME: REG_ZERO can cause problems here! */
-                               assert(cd->stackframesize * 4 <= 32767);
-
-                               M_ALD(REG_ZERO, REG_SP, cd->stackframesize * 4 + LA_LR_OFFSET);
-                               M_MTLR(REG_ZERO);
-                       }
-
-                       disp = dseg_add_functionptr(cd, asm_handle_exception);
-                       M_ALD(REG_ITMP3, REG_PV, disp);
-                       M_MTCTR(REG_ITMP3);
-                       M_RTS;
-               }
-               else {
-                       disp = (((u4 *) cd->mcodebase) + targetdisp) -
-                               (((u4 *) cd->mcodeptr) + 1);
-                       M_BR(disp);
-               }
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(REG_RESULT);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
        }
 }
 
@@ -664,14 +612,17 @@ void emit_patcher_stubs(jitdata *jd)
 
 *******************************************************************************/
 
+#if defined(ENABLE_REPLACEMENT)
 void emit_replacement_stubs(jitdata *jd)
 {
        codegendata *cd;
        codeinfo    *code;
        rplpoint    *rplp;
-       u1          *savedmcodeptr;
        s4           disp;
        s4           i;
+#if !defined(NDEBUG)
+       u1          *savedmcodeptr;
+#endif
 
        /* get required compiler data */
 
@@ -680,24 +631,23 @@ void emit_replacement_stubs(jitdata *jd)
 
        rplp = code->rplpoints;
 
-       for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
-               /* check code segment size */
-
-               MCODECHECK(100);
+       /* store beginning of replacement stubs */
 
-               /* note start of stub code */
+       code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
 
-               rplp->outcode = (u1 *) (cd->mcodeptr - cd->mcodebase);
+       for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
+               /* do not generate stubs for non-trappable points */
 
-               /* make machine code for patching */
+               if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
+                       continue;
 
-               savedmcodeptr = cd->mcodeptr;
-               cd->mcodeptr  = (u1 *) &(rplp->mcode) + 1;              /* big-endian */
+               /* check code segment size */
 
-               disp = (ptrint) ((s4 *) rplp->outcode - (s4 *) rplp->pc) - 1;
-               M_BR(disp);
+               MCODECHECK(100);
 
-               cd->mcodeptr = savedmcodeptr;
+#if !defined(NDEBUG)
+               savedmcodeptr = cd->mcodeptr;
+#endif
 
                /* create stack frame - keep 16-byte aligned */
 
@@ -715,8 +665,11 @@ void emit_replacement_stubs(jitdata *jd)
                M_ALD(REG_ITMP3, REG_PV, disp);
                M_MTCTR(REG_ITMP3);
                M_RTS;
+
+               assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
        }
 }
+#endif /* defined(ENABLE_REPLACEMENT) */
 
 
 /* emit_verbosecall_enter ******************************************************
@@ -727,6 +680,7 @@ void emit_replacement_stubs(jitdata *jd)
 
 void emit_verbosecall_enter(jitdata *jd)
 {
+#if !defined(NDEBUG)
        methodinfo   *m;
        codegendata  *cd;
        registerdata *rd;
@@ -735,6 +689,9 @@ void emit_verbosecall_enter(jitdata *jd)
        int stack_size;
        methoddesc *md;
 
+       if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               return;
+
        /* get required compiler data */
 
        m  = jd->m;
@@ -886,7 +843,7 @@ void emit_verbosecall_enter(jitdata *jd)
 #else
        M_AST(REG_ITMP1, REG_SP, LA_SIZE + 4 * 8);
 #endif
-       p = dseg_add_functionptr(cd, builtin_trace_args);
+       p = dseg_add_functionptr(cd, builtin_verbosecall_enter);
        M_ALD(REG_ITMP2, REG_PV, p);
        M_MTCTR(REG_ITMP2);
        M_JSR;
@@ -929,6 +886,7 @@ void emit_verbosecall_enter(jitdata *jd)
        /* mark trace code */
 
        M_NOP;
+#endif /* !defined(NDEBUG) */
 }
 
 
@@ -936,16 +894,22 @@ 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);
+
 *******************************************************************************/
 
 void emit_verbosecall_exit(jitdata *jd)
 {
+#if !defined(NDEBUG)
        methodinfo   *m;
        codegendata  *cd;
        registerdata *rd;
        methoddesc   *md;
        s4            disp;
 
+       if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               return;
+
        /* get required compiler data */
 
        m  = jd->m;
@@ -971,33 +935,22 @@ void emit_verbosecall_exit(jitdata *jd)
        switch (md->returntype.type) {
        case TYPE_INT:
        case TYPE_ADR:
-#if defined(__DARWIN__)
-               M_MOV(REG_RESULT, rd->argintregs[2]);
-               M_CLR(rd->argintregs[1]);
-#else
-               M_MOV(REG_RESULT, rd->argintregs[3]);
-               M_CLR(rd->argintregs[2]);
-#endif
+               M_INTMOVE(REG_RESULT, REG_A1);
+               M_CLR(REG_A0);
                break;
 
        case TYPE_LNG:
-#if defined(__DARWIN__)
-               M_MOV(REG_RESULT2, rd->argintregs[2]);
-               M_MOV(REG_RESULT, rd->argintregs[1]);
-#else
-               M_MOV(REG_RESULT2, rd->argintregs[3]);
-               M_MOV(REG_RESULT, rd->argintregs[2]);
-#endif
+               M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
                break;
        }
 
-       M_FLTMOVE(REG_FRESULT, rd->argfltregs[0]);
-       M_FLTMOVE(REG_FRESULT, rd->argfltregs[1]);
+       M_FLTMOVE(REG_FRESULT, REG_FA0);
+       M_FLTMOVE(REG_FRESULT, REG_FA1);
 
        disp = dseg_add_address(cd, m);
-       M_ALD(rd->argintregs[0], REG_PV, disp);
+       M_ALD(REG_A2, REG_PV, disp);
 
-       disp = dseg_add_functionptr(cd, builtin_displaymethodstop);
+       disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
        M_ALD(REG_ITMP2, REG_PV, disp);
        M_MTCTR(REG_ITMP2);
        M_JSR;
@@ -1014,6 +967,7 @@ void emit_verbosecall_exit(jitdata *jd)
        /* mark trace code */
 
        M_NOP;
+#endif /* !defined(NDEBUG) */
 }