* Merged in twisti-branch.
[cacao.git] / src / vm / jit / powerpc64 / emit.c
index ec9ad6ea1843f6656624006a3b5f8cbc69b31608..43fd7ed74c0a8daacc877a58a85c23eb9690c5a3 100644 (file)
@@ -1,6 +1,6 @@
-/* src/vm/jit/powerpc/emit.c - PowerPC code emitter functions
+/* src/vm/jit/powerpc64/emit.c - PowerPC64 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 "vm/types.h"
 
+#include "mm/memory.h"
+
 #include "md-abi.h"
+#include "vm/jit/powerpc64/codegen.h"
 
-#include "vm/jit/emit.h"
+#include "vmcore/options.h"
+
+#include "vm/builtin.h"
+#include "vm/jit/emit-common.h"
 #include "vm/jit/jit.h"
-#include "vm/jit/powerpc/codegen.h"
+#include "vm/vm.h"
+#include "vm/jit/asmpart.h"
+#include "vm/exceptions.h"
 
+#if defined(ENABLE_THREADS)
+# include "threads/native/lock.h"
+#endif
 
-/* code generation functions **************************************************/
 
-/* emit_load_s1 ****************************************************************
+/* emit_load *******************************************************************
 
-   Emits a possible load of the first source operand.
+   Emits a possible load of an operand.
 
 *******************************************************************************/
 
-s4 emit_load_s1(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
        codegendata  *cd;
        s4            disp;
@@ -67,422 +71,798 @@ s4 emit_load_s1(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
        if (src->flags & INMEMORY) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 4;
+               disp = src->vv.regoff * 8;
 
                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);
+                       M_DLD(tempreg, REG_SP, disp);
+               }
+               else {
+                       M_LLD(tempreg, REG_SP, disp);
                }
 
                reg = tempreg;
-       } else
-               reg = src->regoff;
+       }
+       else
+               reg = src->vv.regoff;
 
        return reg;
 }
 
 
-/* emit_load_s2 ****************************************************************
+/* emit_store ******************************************************************
 
-   Emits a possible load of the second source operand.
+   Emits a possible store to a variable.
 
 *******************************************************************************/
 
-s4 emit_load_s2(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 {
        codegendata  *cd;
-       s4            disp;
-       s4            reg;
 
        /* get required compiler data */
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (dst->flags & INMEMORY) {
                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);
+               if (IS_FLT_DBL_TYPE(dst->type)) {
+                       M_DST(d, REG_SP, dst->vv.regoff * 8);
                }
-
-               reg = tempreg;
-       } else
-               reg = src->regoff;
-
-       return reg;
+               else {
+                       M_LST(d, REG_SP, dst->vv.regoff * 8);
+               }
+       }
 }
 
 
-/* emit_load_s3 ****************************************************************
+/* emit_copy *******************************************************************
 
-   Emits a possible load of the third source operand.
+   Generates a register/memory to register/memory copy.
 
 *******************************************************************************/
 
-s4 emit_load_s3(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
 {
        codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       registerdata *rd;
+       s4            s1, d;
 
        /* get required compiler data */
 
        cd = jd->cd;
+       rd = jd->rd;
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+       if ((src->vv.regoff != dst->vv.regoff) ||
+               ((src->flags ^ dst->flags) & INMEMORY)) {
 
-               disp = src->regoff * 4;
+               /* 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_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);
+               if (IS_INMEMORY(src->flags)) {
+                       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);
+                       d = codegen_reg_of_var(iptr->opc, dst, s1);
+               }
 
-               } else {
-                       if (IS_2_WORD_TYPE(src->type))
-                               M_LLD(tempreg, REG_SP, disp);
+               if (s1 != d) {
+                       if (IS_FLT_DBL_TYPE(src->type))
+                               M_FMOV(s1, d);
                        else
-                               M_ILD(tempreg, REG_SP, disp);
+                               M_MOV(s1, d);
                }
 
-               reg = tempreg;
-       } else
-               reg = src->regoff;
+               emit_store(jd, iptr, dst, d);
+       }
+}
 
-       return reg;
+
+/* emit_iconst *****************************************************************
+
+   XXX
+
+*******************************************************************************/
+
+void emit_iconst(codegendata *cd, s4 d, s4 value)
+{
+       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);
+       }
+}
+
+void emit_lconst(codegendata *cd, s4 d, s8 value)
+{
+       s4 disp;
+       if ((value >= -32768) && (value <= 32767)) {
+               M_LDA_INTERN(d, REG_ZERO, value);
+       } else {
+               disp = dseg_add_s8(cd, value);
+               M_LLD(d, REG_PV, disp);
+       }
 }
 
 
-/* emit_load_s1_low ************************************************************
+/* emit_verbosecall_enter ******************************************************
 
-   Emits a possible load of the low 32-bits of the first long source
-   operand.
+   Generates the code for the call trace.
 
 *******************************************************************************/
 
-s4 emit_load_s1_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_verbosecall_enter (jitdata *jd)
 {
+       methodinfo   *m;
        codegendata  *cd;
-       s4            disp;
-       s4            reg;
-
-       assert(src->type == TYPE_LNG);
+       registerdata *rd;
+       s4 s1, p, t;
+       int stack_size;
+       methoddesc *md;
 
        /* get required compiler data */
 
+       m  = jd->m;
        cd = jd->cd;
+       rd = jd->rd;
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
-
-               disp = src->regoff * 4;
-
-               M_ILD(tempreg, REG_SP, disp + 4);
+       md = m->parseddesc;
+       
+       /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
+       /* For Darwin:                                                        */
+       /* TODO                                                               */
+       /* For Linux:                                                         */
+       /* setup stack for TRACE_ARGS_NUM registers                           */
+       /* == LA_SIZE + PA_SIZE + 8 (methodinfo argument) + TRACE_ARGS_NUM*8 + 8 (itmp1)              */
+       
+       /* 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 = LA_SIZE + PA_SIZE + 8 + TRACE_ARGS_NUM * 8 + 8;
+#endif
+
+       /* mark trace code */
+       M_NOP;
+
+       M_MFLR(REG_ZERO);
+       M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
+       M_STDU(REG_SP, REG_SP, -stack_size);
+
+       for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
+               t = md->paramtypes[p].type;
+               if (IS_INT_LNG_TYPE(t)) {
+                       if (!md->params[p].inmemory) { /* Param in Arg Reg */
+                               M_LST(rd->argintregs[md->params[p].regoff], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
+                       } else { /* Param on Stack */
+                               s1 = (md->params[p].regoff + cd->stackframesize) * 8 + stack_size;
+                               M_LLD(REG_ITMP2, REG_SP, s1);
+                               M_LST(REG_ITMP2, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
+                       }
+               } else { /* IS_FLT_DBL_TYPE(t) */
+                       if (!md->params[p].inmemory) { /* in Arg Reg */
+                               s1 = rd->argfltregs[md->params[p].regoff];
+                               M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
+                       } else { /* on Stack */
+                               /* this should not happen */
+                               assert(0);
+                       }
+               }
+       }
 
-               reg = tempreg;
-       } else
-               reg = GET_LOW_REG(src->regoff);
+#if defined(__DARWIN__)
+       #warning "emit_verbosecall_enter not implemented"
+#else
+       /* LINUX */
+       /* Set integer and float argument registers for trace_args call */
+       /* offset to saved integer argument registers                   */
+       for (p = 0; (p < TRACE_ARGS_NUM) && (p < md->paramcount); p++) {
+               t = md->paramtypes[p].type;
+               if (IS_INT_LNG_TYPE(t)) {
+                       M_LLD(rd->argintregs[p], REG_SP,LA_SIZE + PA_SIZE + 8 + p * 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];
+                               M_MOV(s1, rd->argintregs[p]);
+                       } else  {
+                               assert(0);
+                       }
+               }
+       }
+#endif
+
+       /* put methodinfo pointer on Stackframe */
+       p = dseg_add_address(cd, m);
+       M_ALD(REG_ITMP1, REG_PV, p);
+#if defined(__DARWIN__)
+       M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
+#else
+       if (TRACE_ARGS_NUM == 8)        {
+               /* need to pass via stack */
+               M_AST(REG_ITMP1, REG_SP, LA_SIZE + PA_SIZE);
+       } else {
+               /* pass via register, reg 3 is the first  */
+               M_MOV(REG_ITMP1, 3 + TRACE_ARGS_NUM);
+       }
+#endif
+       /* call via function descriptor */
+       /* XXX: what about TOC? */
+       p = dseg_add_functionptr(cd, builtin_verbosecall_enter);
+       M_ALD(REG_ITMP2, REG_PV, p);
+       M_ALD(REG_ITMP1, REG_ITMP2, 0);
+       M_MTCTR(REG_ITMP1);
+       M_JSR;
+
+#if defined(__DARWIN__)
+       #warning "emit_verbosecall_enter not implemented"
+#else
+       /* LINUX */
+       for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
+               t = md->paramtypes[p].type;
+               if (IS_INT_LNG_TYPE(t)) {
+                       if (!md->params[p].inmemory) { /* Param in Arg Reg */
+                               /* restore integer argument registers */
+                               M_LLD(rd->argintregs[p], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
+                       } else {
+                               assert(0);      /* TODO: implement this */
+                       }
+               } else { /* FLT/DBL */
+                       if (!md->params[p].inmemory) { /* Param in Arg Reg */
+                               M_DLD(rd->argfltregs[md->params[p].regoff], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
+                       } else {
+                               assert(0); /* this shoudl never happen */
+                       }
+                       
+               }
+       }
+#endif
+       M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
+       M_MTLR(REG_ZERO);
+       M_LDA(REG_SP, REG_SP, stack_size);
 
-       return reg;
+       /* mark trace code */
+       M_NOP;
 }
 
 
-/* emit_load_s2_low ************************************************************
+/* emit_verbosecall_exit ******************************************************
+
+   Generates the code for the call trace.
 
-   Emits a possible load of the low 32-bits of the second long source
-   operand.
+   void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
 
 *******************************************************************************/
 
-s4 emit_load_s2_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_verbosecall_exit(jitdata *jd)
 {
+       methodinfo   *m;
        codegendata  *cd;
        s4            disp;
-       s4            reg;
-
-       assert(src->type == TYPE_LNG);
 
        /* get required compiler data */
 
+       m  = jd->m;
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+       /* mark trace code */
 
-               disp = src->regoff * 4;
+       M_NOP;
 
-               M_ILD(tempreg, REG_SP, disp + 4);
+       M_MFLR(REG_ZERO);
+       M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
+       M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
+       M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
+       M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
 
-               reg = tempreg;
-       } else
-               reg = GET_LOW_REG(src->regoff);
+       M_MOV(REG_RESULT, REG_A0);
 
-       return reg;
-}
+       M_FLTMOVE(REG_FRESULT, REG_FA0);
+       M_FLTMOVE(REG_FRESULT, REG_FA1);
+
+       disp = dseg_add_address(cd, m);
+       M_ALD(REG_A3, REG_PV, disp);
 
+       disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
+       /* call via function descriptor, XXX: what about TOC ? */
+       M_ALD(REG_ITMP2, REG_PV, disp);
+       M_ALD(REG_ITMP2, REG_ITMP2, 0);
+       M_MTCTR(REG_ITMP2);
+       M_JSR;
 
-/* emit_load_s3_low ************************************************************
+       M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
+       M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
+       M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
+       M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
+       M_MTLR(REG_ZERO);
 
-   Emits a possible load of the low 32-bits of the third long source
-   operand.
+       /* mark trace code */
+
+       M_NOP;
+}
+
+/* emit_branch *****************************************************************
+
+   Emits the code for conditional and unconditional branchs.
 
 *******************************************************************************/
 
-s4 emit_load_s3_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       s4 checkdisp;
+       s4 branchdisp;
 
-       assert(src->type == TYPE_LNG);
+       /* calculate the different displacements */
 
-       /* get required compiler data */
+       checkdisp  =  disp + 4;
+       branchdisp = (disp - 4) >> 2;
 
-       cd = jd->cd;
+       /* check which branch to generate */
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+       if (condition == BRANCH_UNCONDITIONAL) {
+               /* check displacement for overflow */
 
-               disp = src->regoff * 4;
+               if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
+                       /* if the long-branches flag isn't set yet, do it */
 
-               M_ILD(tempreg, REG_SP, disp + 4);
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               log_println("setting error");
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-               reg = tempreg;
-       } else
-               reg = GET_LOW_REG(src->regoff);
+                       vm_abort("emit_branch: emit unconditional long-branch code");
+               }
+               else {
+                       M_BR(branchdisp);
+               }
+       }
+       else {
+               /* and displacement for overflow */
 
-       return reg;
+               if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
+                       /* if the long-branches flag isn't set yet, do it */
+
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               log_println("setting error");
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
+                       log_println("generating long-branch");
+
+                       branchdisp --;          /* we jump from the second instruction */
+                       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_arrayindexoutofbounds_check ********************************************
+
+   Emit a ArrayIndexOutOfBoundsException check.
+
+*******************************************************************************/
+
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
+{
+       if (checkbounds) {
+#define SOFTEX 0
+#if SOFTEX
+               M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
+               M_CMPU(s2, REG_ITMP3);
+               codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
+               BRANCH_NOPS;
+#else
+               M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
+               M_CMPU(s2, REG_ITMP3);
+               M_BLT(1);
+               /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
+               M_LWZ(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
+#endif
+       }
 }
 
 
-/* emit_load_s1_high ***********************************************************
+/* emit_arithmetic_check *******************************************************
 
-   Emits a possible load of the high 32-bits of the first long source
-   operand.
+   Emit an ArithmeticException check.
 
 *******************************************************************************/
 
-s4 emit_load_s1_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       if (INSTRUCTION_MUST_CHECK(iptr))       {
+       #if SOFTEX
+               M_TST(reg);
+               codegen_add_arithmeticexception_ref(cd);
+               BRANCH_NOPS;
+       #else
+               M_TST(reg);
+               M_BNE(1);
+               /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
+               M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
+       #endif
+       }
+}
 
-       assert(src->type == TYPE_LNG);
+#if 0
+/* emit_arraystore_check *******************************************************
 
-       /* get required compiler data */
+   Emit an ArrayStoreException check.
 
-       cd = jd->cd;
+*******************************************************************************/
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+void emit_arraystore_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr))       {
+               M_TST(REG_RESULT);
+               codegen_add_arraystoreexception_ref(cd);
+               BRANCH_NOPS;
+       }
+}
+#endif
 
-               disp = src->regoff * 4;
+/* emit_classcast_check ********************************************************
 
-               M_ILD(tempreg, REG_SP, disp);
+   Emit a ClassCastException check.
 
-               reg = tempreg;
-       } else
-               reg = GET_HIGH_REG(src->regoff);
+*******************************************************************************/
 
-       return reg;
+void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr))       {
+       #if SOFTEX
+               codegen_add_classcastexception_ref(cd, condition, s1);
+               BRANCH_NOPS;
+               M_NOP;
+       #else
+               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);
+               }
+               /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
+               M_LWZ(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
+       #endif
+       }
 }
 
 
-/* emit_load_s2_high ***********************************************************
+/* emit_nullpointer_check ******************************************************
 
-   Emits a possible load of the high 32-bits of the second long source
-   operand.
+   Emit a NullPointerException check.
 
 *******************************************************************************/
 
-s4 emit_load_s2_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       if (INSTRUCTION_MUST_CHECK(iptr))       {
+               M_TST(reg);
+               M_BNE(1);
+               /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
+               M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
+       }
+}
 
-       assert(src->type == TYPE_LNG);
+/* emit_exception_check ********************************************************
 
-       /* get required compiler data */
+   Emit an Exception check.
+
+*******************************************************************************/
+
+void emit_exception_check(codegendata *cd, instruction *iptr)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr))       {
+       #if SOFTEX
+               M_CMPI(REG_RESULT, 0);
+               codegen_add_fillinstacktrace_ref(cd);
+               BRANCH_NOPS;
+       #else
+               M_TST(REG_RESULT);
+               M_BNE(1);
+               /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
+               M_LWZ(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
+       #endif
+       }
+}
+
+
+/* emit_patcher_stubs **********************************************************
+
+   Generates the code for the patcher stubs.
+
+*******************************************************************************/
+void emit_patcher_stubs(jitdata *jd)
+{
+       codegendata *cd;
+       patchref    *pref;
+       u4           mcode;
+       u1          *savedmcodeptr;
+       u1          *tmpmcodeptr;
+       s4           targetdisp;
+       s4           disp;
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+       /* generate code patching stub call code */
 
-               disp = src->regoff * 4;
+       targetdisp = 0;
 
-               M_ILD(tempreg, REG_SP, disp);
+       for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
+               /* check code segment size */
 
-               reg = tempreg;
-       } else
-               reg = GET_HIGH_REG(src->regoff);
+               MCODECHECK(16);
 
-       return reg;
-}
+               /* Get machine code which is patched back in later. The
+                  call is 1 instruction word long. */
 
+               tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
 
-/* emit_load_s3_high ***********************************************************
+               mcode = *((u4 *) tmpmcodeptr);
 
-   Emits a possible load of the high 32-bits of the third long source
-   operand.
+               /* 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 */
 
-s4 emit_load_s3_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
-{
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+               disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
+               M_BR(disp);
 
-       assert(src->type == TYPE_LNG);
+               cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
 
-       /* get required compiler data */
+               /* create stack frame - keep stack 16-byte aligned */
 
-       cd = jd->cd;
+               M_AADD_IMM(REG_SP, -8 * 8, REG_SP);
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+               /* calculate return address and move it onto the stack */
 
-               disp = src->regoff * 4;
+               M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 5 * 8);
 
-               M_ILD(tempreg, REG_SP, disp);
+               /* move pointer to java_objectheader onto stack */
 
-               reg = tempreg;
-       } else
-               reg = GET_HIGH_REG(src->regoff);
+#if defined(ENABLE_THREADS)
+               /* order reversed because of data segment layout */
 
-       return reg;
-}
+               (void) dseg_add_unique_address(cd, NULL);                         /* flcword    */
+               (void) dseg_add_unique_address(cd, lock_get_initial_lock_word()); /* monitorPtr */
+               disp = dseg_add_unique_address(cd, NULL);                         /* vftbl      */
 
+               M_LDA(REG_ITMP3, REG_PV, disp);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 4 * 8);
+#else
+               /* do nothing */
+#endif
 
-/* emit_store ******************************************************************
+               /* move machine code onto stack */
 
-   XXX
+               disp = dseg_add_s4(cd, mcode);
+               M_ILD(REG_ITMP3, REG_PV, disp);
+               M_IST_INTERN(REG_ITMP3, REG_SP, 3 * 8);
 
-*******************************************************************************/
+               /* move class/method/field reference onto stack */
 
-void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
-{
-       codegendata  *cd;
+               disp = dseg_add_address(cd, pref->ref);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 2 * 8);
 
-       /* get required compiler data */
+               /* move data segment displacement onto stack */
 
-       cd = jd->cd;
+               disp = dseg_add_s4(cd, pref->disp);
+               M_ILD(REG_ITMP3, REG_PV, disp);
+               M_IST_INTERN(REG_ITMP3, REG_SP, 1 * 8);
+               M_NOP;
 
-       if (dst->flags & INMEMORY) {
-               COUNT_SPILLS;
+               /* move patcher function pointer onto stack */
 
-               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);
+               disp = dseg_add_functionptr(cd, pref->patcher);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 8);
 
-               } 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 0
+               disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_MTCTR(REG_ITMP3);
+               M_RTS;
+#else
+               if (targetdisp == 0) {
+                       targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
+
+                       disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
+                       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);
                }
+#endif
        }
 }
 
 
-/* emit_copy *******************************************************************
+/* emit_replacement_stubs ******************************************************
 
-   XXX
+   Generates the code for the replacement stubs.
 
 *******************************************************************************/
 
-void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
+#if defined(ENABLE_REPLACEMENT)
+void emit_replacement_stubs(jitdata *jd)
 {
-       codegendata  *cd;
-       registerdata *rd;
-       s4            s1, d;
+       codegendata *cd;
+       codeinfo    *code;
+       rplpoint    *replacementpoint;
+       s4           disp;
+       s4           i;
+#if !defined(NDEBUG)
+       u1          *savedmcodeptr;
+#endif
 
        /* get required compiler data */
 
-       cd = jd->cd;
-       rd = jd->rd;
+       cd   = jd->cd;
+       code = jd->code;
 
-       if (src->type == TYPE_LNG)
-               d = codegen_reg_of_var(rd, iptr->opc, dst, PACK_REGS(REG_ITMP2, REG_ITMP1));
-       else
-               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
+       replacementpoint = jd->code->rplpoints;
 
-       if ((src->regoff != dst->regoff) ||
-               ((src->flags ^ dst->flags) & INMEMORY)) {
-               s1 = emit_load_s1(jd, iptr, src, d);
+       for (i = 0; i < code->rplpointcount; ++i, ++replacementpoint) {
+               /* do not generate stubs for non-trappable points */
 
-               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 (replacementpoint->flags & RPLPOINT_FLAG_NOTRAP)
+                       continue;
 
-               emit_store(jd, iptr, dst, d);
-       }
-}
 
+               /* check code segment size */
 
-/* emit_iconst *****************************************************************
+               MCODECHECK(100);
 
-   XXX
+#if !defined(NDEBUG)
+               savedmcodeptr = cd->mcodeptr;
+#endif
+               /* create stack frame - keep 16-byte aligned */
 
-*******************************************************************************/
+               M_AADD_IMM(REG_SP, -4 * 8, REG_SP);
 
-void emit_iconst(codegendata *cd, s4 d, s4 value)
-{
-       s4 disp;
+               /* push address of `rplpoint` struct */
 
-       if ((value >= -32768) && (value <= 32767))
-               M_LDA_INTERN(d, REG_ZERO, value);
-       else {
-               disp = dseg_adds4(cd, value);
-               M_ILD(d, REG_PV, disp);
+               disp = dseg_add_address(cd, replacementpoint);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 8);
+
+               /* jump to replacement function */
+
+               disp = dseg_add_functionptr(cd, asm_replacement_out);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_MTCTR(REG_ITMP3);
+               M_RTS;
+
+               assert((cd->mcodeptr - savedmcodeptr) == 4*REPLACEMENT_STUB_SIZE);
+
+#if 0
+               /* note start of stub code */
+
+               replacementpoint->outcode = (u1 *) (cd->mcodeptr - cd->mcodebase);
+
+               /* make machine code for patching */
+
+               savedmcodeptr  = cd->mcodeptr;
+               cd->mcodeptr = (u1 *) &(replacementpoint->mcode) + 1 /* big-endian */;
+
+               disp = (ptrint)((s4*)replacementpoint->outcode - (s4*)replacementpoint->pc) - 1;
+               M_BR(disp);
+
+               cd->mcodeptr = savedmcodeptr;
+
+               /* create stack frame - keep 16-byte aligned */
+
+               M_AADD_IMM(REG_SP, -4 * 4, REG_SP);
+
+               /* push address of `rplpoint` struct */
+
+               disp = dseg_add_unique_address(cd, replacementpoint);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 4);
+
+               /* jump to replacement function */
+
+               disp = dseg_add_functionptr(cd, asm_replacement_out);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_MTCTR(REG_ITMP3);
+               M_RTS;
+#endif
        }
 }
-
+#endif /* define(ENABLE_REPLACEMENT) */
 
 /*
- * These are local overrides for various environment variables in Emacs.
- * Please do not remove this and leave it at the end of the file, where
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
+* These are local overrides for various environment variables in Emacs.
+* Please do not remove this and leave it at the end of the file, where
+* Emacs will automagically detect them.
+* ---------------------------------------------------------------------
+* Local variables:
+* mode: c
+* indent-tabs-mode: t
+* c-basic-offset: 4
+* tab-width: 4
+* End:
+* vim:noexpandtab:sw=4:ts=4:
+*/