* src/vm/jit/allocator/simplereg.c: Replaced HAS_4BYTE_STACKSLOT with
[cacao.git] / src / vm / jit / powerpc / emit.c
index b7231d56fdb929e60e1fc0db1a278420cc6117ea..8a1001bbd0be0a715319977e0fb61ec0d59d6411 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 8191 2007-07-08 15:15:53Z twisti $
 
 */
 
@@ -36,6 +30,7 @@
 #include "config.h"
 
 #include <assert.h>
+#include <stdint.h>
 
 #include "vm/types.h"
 
 
 #include "vm/jit/powerpc/codegen.h"
 
+#include "mm/memory.h"
+
+#include "threads/lock-common.h"
+
 #include "vm/builtin.h"
+#include "vm/exceptions.h"
+
+#include "vm/jit/abi.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;
+
+               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;
 
                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,194 +156,17 @@ 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;
 
                M_ILD(tempreg, REG_SP, disp);
 
                reg = tempreg;
        }
        else
-               reg = GET_HIGH_REG(src->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 ****************************************************************
-
-   Emits a possible load of the second source operand.
-
-*******************************************************************************/
-
-s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       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.
-
-*******************************************************************************/
-
-s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s3.var;
-
-       reg = emit_load(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s1_low ************************************************************
-
-   Emits a possible load of the low 32-bits of the first long source
-   operand.
-
-*******************************************************************************/
-
-s4 emit_load_s1_low(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->s1.var;
-
-       reg = emit_load_low(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s2_low ************************************************************
-
-   Emits a possible load of the low 32-bits of the second long source
-   operand.
-
-*******************************************************************************/
-
-s4 emit_load_s2_low(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s2.var;
-
-       reg = emit_load_low(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s3_low ************************************************************
-
-   Emits a possible load of the low 32-bits of the third long source
-   operand.
-
-*******************************************************************************/
-
-s4 emit_load_s3_low(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s3.var;
-
-       reg = emit_load_low(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s1_high ***********************************************************
-
-   Emits a possible load of the high 32-bits of the first long source
-   operand.
-
-*******************************************************************************/
-
-s4 emit_load_s1_high(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->s1.var;
-
-       reg = emit_load_high(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s2_high ***********************************************************
-
-   Emits a possible load of the high 32-bits of the second long source
-   operand.
-
-*******************************************************************************/
-
-s4 emit_load_s2_high(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s2.var;
-
-       reg = emit_load_high(jd, iptr, src, tempreg);
-
-       return reg;
-}
-
-
-/* emit_load_s3_high ***********************************************************
-
-   Emits a possible load of the high 32-bits of the third long source
-   operand.
-
-*******************************************************************************/
-
-s4 emit_load_s3_high(jitdata *jd, instruction *iptr, s4 tempreg)
-{
-       stackptr src;
-       s4       reg;
-
-       src = iptr->sx.s23.s3.var;
-
-       reg = emit_load_high(jd, iptr, src, tempreg);
+               reg = GET_HIGH_REG(src->vv.regoff);
 
        return reg;
 }
@@ -341,71 +174,74 @@ s4 emit_load_s3_high(jitdata *jd, instruction *iptr, s4 tempreg)
 
 /* emit_store ******************************************************************
 
-   XXX
+   Emit a possible store for the given variable.
 
 *******************************************************************************/
 
-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;
 
        /* get required compiler data */
 
        cd = jd->cd;
 
-       if (dst->flags & INMEMORY) {
+       if (IS_INMEMORY(dst->flags)) {
                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);
+               disp = dst->vv.regoff;
+
+               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_store_dst **************************************************************
-
-   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 *******************************************************************
 
    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) ||
-               ((src->flags ^ dst->flags) & INMEMORY)) {
+       /* get source and destination variables */
+
+       src = VAROP(iptr->s1);
+       dst = VAROP(iptr->dst);
+
+       if ((src->vv.regoff != dst->vv.regoff) ||
+               (IS_INMEMORY(src->flags ^ dst->flags))) {
+
+               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
@@ -413,9 +249,9 @@ void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
 
                if (IS_INMEMORY(src->flags)) {
                        if (IS_LNG_TYPE(src->type))
-                               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_ITMP12_PACKED);
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
                        else
-                               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
 
                        s1 = emit_load(jd, iptr, src, d);
                }
@@ -425,19 +261,25 @@ void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
                        else
                                s1 = emit_load(jd, iptr, src, REG_IFTMP);
 
-                       d = codegen_reg_of_var(rd, iptr->opc, dst, s1);
+                       d = codegen_reg_of_var(iptr->opc, dst, s1);
                }
 
                if (s1 != d) {
-                       if (IS_FLT_DBL_TYPE(src->type))
+                       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);
-                       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);
+                               break;
+                       default:
+                               vm_abort("emit_copy: unknown type %d", src->type);
                        }
                }
 
@@ -465,98 +307,201 @@ void emit_iconst(codegendata *cd, s4 d, s4 value)
 }
 
 
-/* emit_exception_stubs ********************************************************
+/* emit_branch *****************************************************************
 
-   Generates the code for the exception stubs.
+   Emits the code for conditional and unconditional branchs.
 
 *******************************************************************************/
 
-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;
+       s4 checkdisp;
+       s4 branchdisp;
 
-       /* get required compiler data */
+       /* calculate the different displacements */
 
-       cd = jd->cd;
-       rd = jd->rd;
+       checkdisp  =  disp + 4;
+       branchdisp = (disp - 4) >> 2;
 
-       /* generate exception stubs */
+       /* check which branch to generate */
 
-       targetdisp = 0;
+       if (condition == BRANCH_UNCONDITIONAL) {
+               /* check displacement for overflow */
 
-       for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
-               gen_resolvebranch(cd->mcodebase + eref->branchpos, 
-                                                 eref->branchpos, cd->mcodeptr - cd->mcodebase);
+               if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
+                       /* if the long-branches flag isn't set yet, do it */
 
-               MCODECHECK(100);
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-               /* Move the value register to a temporary register, if
-                  there is the need for it. */
+                       vm_abort("emit_branch: emit unconditional long-branch code");
+               }
+               else {
+                       M_BR(branchdisp);
+               }
+       }
+       else {
+               /* and 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 */
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-               M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
+                       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);
+                       }
+               }
+       }
+}
 
-               /* move function to call into REG_ITMP3 */
 
-               disp = dseg_add_functionptr(cd, eref->function);
-               M_ALD(REG_ITMP3, REG_PV, disp);
+/* emit_arithmetic_check *******************************************************
 
-               if (targetdisp == 0) {
-                   targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
+   Emit an ArithmeticException check.
 
-                       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]);
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(reg);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
+       }
+}
 
-                       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]);
+/* emit_arrayindexoutofbounds_check ********************************************
 
-                       M_STWU(REG_SP, REG_SP, -(LA_SIZE + 6 * 4));
-                       M_AST(REG_ITMP2_XPC, REG_SP, LA_SIZE + 5 * 4);
+   Emit a ArrayIndexOutOfBoundsException check.
 
-                       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);
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
+               M_TRAPGEU(s2, REG_ITMP3);
+       }
+}
 
-                       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);
-                       }
+/* emit_classcast_check ********************************************************
 
-                       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);
+   Emit a ClassCastException check.
+
+*******************************************************************************/
+
+void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
+{
+       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);
                }
+               M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
+       }
+}
+
+
+/* emit_nullpointer_check ******************************************************
+
+   Emit a NullPointerException check.
+
+*******************************************************************************/
+
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(reg);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
+       }
+}
+
+
+/* emit_exception_check ********************************************************
+
+   Emit an Exception check.
+
+*******************************************************************************/
+
+void emit_exception_check(codegendata *cd, instruction *iptr)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(REG_RESULT);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
        }
 }
 
@@ -679,14 +624,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 */
 
@@ -695,24 +643,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 */
 
@@ -730,8 +677,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 ******************************************************
@@ -742,13 +692,18 @@ void emit_replacement_stubs(jitdata *jd)
 
 void emit_verbosecall_enter(jitdata *jd)
 {
+#if !defined(NDEBUG)
        methodinfo   *m;
        codegendata  *cd;
        registerdata *rd;
-       s4 s1, p, t, d;
-       int stack_off;
-       int stack_size;
-       methoddesc *md;
+       methoddesc   *md;
+       int32_t       disp;
+       int32_t       i;
+       int32_t       s, d;
+       int32_t       x;
+
+       if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               return;
 
        /* get required compiler data */
 
@@ -757,27 +712,6 @@ void emit_verbosecall_enter(jitdata *jd)
        rd = jd->rd;
 
        md = m->parseddesc;
-       
-       /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
-       /* For Darwin:                                                        */
-       /* LA + TRACE_ARGS_NUM u8 args + methodinfo + LR                      */
-       /* LA_SIZE(=6*4) + 8*8         + 4          + 4  + 0(Padding)         */
-       /* 6 * 4 + 8 * 8 + 2 * 4 = 12 * 8 = 6 * 16                            */
-       /* For Linux:                                                         */
-       /* LA + (TRACE_ARGS_NUM - INT_ARG_CNT/2) u8 args + methodinfo         */
-       /* + INT_ARG_CNT * 4 ( save integer registers) + LR + 8 + 8 (Padding) */
-       /* LA_SIZE(=2*4) + 4 * 8 + 4 + 8 * 4 + 4 + 8                          */
-       /* 2 * 4 + 4 * 8 + 10 * 4 + 1 * 8 + 8= 12 * 8 = 6 * 16                */
-       
-       /* in nativestubs no Place to save the LR (Link Register) would be needed */
-       /* but since the stack frame has to be aligned the 4 Bytes would have to  */
-       /* be padded again */
-
-#if defined(__DARWIN__)
-       stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
-#else
-       stack_size = 6 * 16;
-#endif
 
        /* mark trace code */
 
@@ -785,165 +719,98 @@ void emit_verbosecall_enter(jitdata *jd)
 
        M_MFLR(REG_ZERO);
        M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
-       M_STWU(REG_SP, REG_SP, -stack_size);
-
-       M_CLR(REG_ITMP1);    /* clear help register */
-
-       /* save up to TRACE_ARGS_NUM arguments into the reserved stack space */
-#if defined(__DARWIN__)
-       /* Copy Params starting from first to Stack                          */
-       /* since TRACE_ARGS == INT_ARG_CNT all used integer argument regs    */ 
-       /* are saved                                                         */
-       p = 0;
-#else
-       /* Copy Params starting from fifth to Stack (INT_ARG_CNT/2) are in   */
-       /* integer argument regs                                             */
-       /* all integer argument registers have to be saved                   */
-       for (p = 0; p < 8; p++) {
-               d = rd->argintregs[p];
-               /* save integer argument registers */
-               M_IST(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4);
-       }
-       p = 4;
-#endif
-       stack_off = LA_SIZE;
-       for (; p < md->paramcount && p < TRACE_ARGS_NUM; p++, stack_off += 8) {
-               t = md->paramtypes[p].type;
-               if (IS_INT_LNG_TYPE(t)) {
-                       if (!md->params[p].inmemory) { /* Param in Arg Reg */
-                               if (IS_2_WORD_TYPE(t)) {
-                                       M_IST(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)]
-                                                 , REG_SP, stack_off);
-                                       M_IST(rd->argintregs[GET_LOW_REG(md->params[p].regoff)]
-                                                 , REG_SP, stack_off + 4);
-                               } else {
-                                       M_IST(REG_ITMP1, REG_SP, stack_off);
-                                       M_IST(rd->argintregs[md->params[p].regoff]
-                                                 , REG_SP, stack_off + 4);
-                               }
-                       } else { /* Param on Stack */
-                               s1 = (md->params[p].regoff + cd->stackframesize) * 4 
-                                       + stack_size;
-                               if (IS_2_WORD_TYPE(t)) {
-                                       M_ILD(REG_ITMP2, REG_SP, s1);
-                                       M_IST(REG_ITMP2, REG_SP, stack_off);
-                                       M_ILD(REG_ITMP2, REG_SP, s1 + 4);
-                                       M_IST(REG_ITMP2, REG_SP, stack_off + 4);
-                               } else {
-                                       M_IST(REG_ITMP1, REG_SP, stack_off);
-                                       M_ILD(REG_ITMP2, REG_SP, s1);
-                                       M_IST(REG_ITMP2, REG_SP, stack_off + 4);
-                               }
-                       }
-               } else { /* IS_FLT_DBL_TYPE(t) */
-                       if (!md->params[p].inmemory) { /* in Arg Reg */
-                               s1 = rd->argfltregs[md->params[p].regoff];
-                               if (!IS_2_WORD_TYPE(t)) {
-                                       M_IST(REG_ITMP1, REG_SP, stack_off);
-                                       M_FST(s1, REG_SP, stack_off + 4);
-                               } else {
-                                       M_DST(s1, REG_SP, stack_off);
-                               }
-                       } else { /* on Stack */
-                               /* this should not happen */
+       M_STWU(REG_SP, REG_SP, -(LA_SIZE + (1 + ARG_CNT + TMP_CNT) * 8));
+
+       M_CLR(REG_ITMP1);                            /* prepare a "zero" register */
+
+       /* save argument registers */
+
+       for (i = 0; i < md->paramcount; i++) {
+               if (!md->params[i].inmemory) {
+                       s = md->params[i].regoff;
+                       d = LA_SIZE + (1 + i) * 8;
+
+                       switch (md->paramtypes[i].type) {
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_IST(REG_ITMP1, REG_SP, d);            /* high-bits are zero */
+                               M_IST(s, REG_SP, d + 4);
+                               break;
+                       case TYPE_LNG:
+                               M_LST(s, REG_SP, d);
+                               break;
+                       case TYPE_FLT:
+                               M_IST(REG_ITMP1, REG_SP, d);            /* high-bits are zero */
+                               M_FST(s, REG_SP, d + 4);
+                               break;
+                       case TYPE_DBL:
+                               M_DST(s, REG_SP, d);
+                               break;
                        }
                }
        }
 
-       /* load first 4 (==INT_ARG_CNT/2) arguments into integer registers */
-#if defined(__DARWIN__)
-       for (p = 0; p < 8; p++) {
-               d = rd->argintregs[p];
-               M_ILD(d, REG_SP, LA_SIZE + p * 4);
-       }
-#else
-       /* LINUX */
-       /* Set integer and float argument registers vor trace_args call */
-       /* offset to saved integer argument registers                   */
-       stack_off = LA_SIZE + 4 * 8 + 4;
-       for (p = 0; (p < 4) && (p < md->paramcount); p++) {
-               t = md->paramtypes[p].type;
-               if (IS_INT_LNG_TYPE(t)) {
-                       /* "stretch" int types */
-                       if (!IS_2_WORD_TYPE(t)) {
-                               M_CLR(rd->argintregs[2 * p]);
-                               M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off);
-                               stack_off += 4;
-                       } else {
-                               M_ILD(rd->argintregs[2 * p + 1], REG_SP,stack_off + 4);
-                               M_ILD(rd->argintregs[2 * p], REG_SP,stack_off);
-                               stack_off += 8;
-                       }
-               } else { /* Float/Dbl */
-                       if (!md->params[p].inmemory) { /* Param in Arg Reg */
-                               /* use reserved Place on Stack (sp + 5 * 16) to copy  */
-                               /* float/double arg reg to int reg                    */
-                               s1 = rd->argfltregs[md->params[p].regoff];
-                               if (!IS_2_WORD_TYPE(t)) {
-                                       M_FST(s1, REG_SP, 5 * 16);
-                                       M_ILD(rd->argintregs[2 * p + 1], REG_SP, 5 * 16);
-                                       M_CLR(rd->argintregs[2 * p]);
-                               } else {
-                                       M_DST(s1, REG_SP, 5 * 16);
-                                       M_ILD(rd->argintregs[2 * p + 1], REG_SP,  5 * 16 + 4);
-                                       M_ILD(rd->argintregs[2 * p], REG_SP, 5 * 16);
-                               }
-                       }
-               }
+       /* load arguments as longs */
+
+       d = 0;
+
+       for (i = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
+               s = LA_SIZE + (1 + i) * 8;
+               x = PACK_REGS(abi_registers_integer_argument[d + 1],
+                                         abi_registers_integer_argument[d]);
+
+               M_LLD(x, REG_SP, s);
+
+               d += 2;
        }
-#endif
 
-       /* put methodinfo pointer on Stackframe */
-       p = dseg_add_address(cd, m);
-       M_ALD(REG_ITMP1, REG_PV, p);
+       /* put methodinfo pointer as last argument on the stack */
+
+       disp = dseg_add_address(cd, m);
+       M_ALD(REG_ITMP1, REG_PV, disp);
 #if defined(__DARWIN__)
        M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
 #else
-       M_AST(REG_ITMP1, REG_SP, LA_SIZE + 4 * 8);
+       M_AST(REG_ITMP1, REG_SP, LA_SIZE);
 #endif
-       p = dseg_add_functionptr(cd, builtin_trace_args);
-       M_ALD(REG_ITMP2, REG_PV, p);
+       disp = dseg_add_functionptr(cd, builtin_verbosecall_enter);
+       M_ALD(REG_ITMP2, REG_PV, disp);
        M_MTCTR(REG_ITMP2);
        M_JSR;
 
-#if defined(__DARWIN__)
-       /* restore integer argument registers from the reserved stack space */
-
-       stack_off = LA_SIZE;
-       for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; 
-                p++, stack_off += 8) {
-               t = md->paramtypes[p].type;
-
-               if (IS_INT_LNG_TYPE(t)) {
-                       if (!md->params[p].inmemory) {
-                               if (IS_2_WORD_TYPE(t)) {
-                                       M_ILD(rd->argintregs[GET_HIGH_REG(md->params[p].regoff)]
-                                                 , REG_SP, stack_off);
-                                       M_ILD(rd->argintregs[GET_LOW_REG(md->params[p].regoff)]
-                                                 , REG_SP, stack_off + 4);
-                               } else {
-                                       M_ILD(rd->argintregs[md->params[p].regoff]
-                                                 , REG_SP, stack_off + 4);
-                               }
+       /* restore argument registers */
+
+       for (i = 0; i < md->paramcount; i++) {
+               if (!md->params[i].inmemory) {
+                       s = LA_SIZE + (1 + i) * 8;
+                       d = md->params[i].regoff;
+
+                       switch (md->paramtypes[i].type) {
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_ILD(d, REG_SP, s + 4);                      /* get low-bits */
+                               break;
+                       case TYPE_LNG:
+                               M_LLD(d, REG_SP, s);
+                               break;
+                       case TYPE_FLT:
+                               M_FLD(d, REG_SP, s + 4);                      /* get low-bits */
+                               break;
+                       case TYPE_DBL:
+                               M_DLD(d, REG_SP, s);
+                               break;
                        }
                }
        }
-#else
-       /* LINUX */
-       for (p = 0; p < 8; p++) {
-               d = rd->argintregs[p];
-               /* save integer argument registers */
-               M_ILD(d, REG_SP, LA_SIZE + 4 * 8 + 4 + p * 4);
-       }
-#endif
 
-       M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
+       M_ALD(REG_ZERO, REG_SP, LA_SIZE + (1 + ARG_CNT + TMP_CNT) * 8 + LA_LR_OFFSET);
        M_MTLR(REG_ZERO);
-       M_LDA(REG_SP, REG_SP, stack_size);
+       M_LDA(REG_SP, REG_SP, LA_SIZE + (1 + ARG_CNT + TMP_CNT) * 8);
 
        /* mark trace code */
 
        M_NOP;
+#endif /* !defined(NDEBUG) */
 }
 
 
@@ -951,16 +818,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;
@@ -986,33 +859,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;
@@ -1029,6 +891,7 @@ void emit_verbosecall_exit(jitdata *jd)
        /* mark trace code */
 
        M_NOP;
+#endif /* !defined(NDEBUG) */
 }