* Removed all Id tags.
[cacao.git] / src / vm / jit / powerpc64 / emit.c
index a308b05c3ab1e64f6cdd52fafaf43126df1f1c4d..041f8da4d347b4e8be6c909fe4161385d0c2cbf6 100644 (file)
@@ -1,6 +1,6 @@
-/* src/vm/jit/powerpc64/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 "md-abi.h"
+#include "mm/memory.h"
 
-#include "vm/jit/emit.h"
-#include "vm/jit/jit.h"
+#include "md-abi.h"
 #include "vm/jit/powerpc64/codegen.h"
+
+#include "threads/lock-common.h"
+
 #include "vm/builtin.h"
+#include "vm/exceptions.h"
+#include "vm/vm.h"
 
+#include "vm/jit/abi.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/emit-common.h"
+#include "vm/jit/jit.h"
+
+#include "vmcore/options.h"
 
-/* code generation functions **************************************************/
 
 /* emit_load *******************************************************************
 
@@ -55,7 +56,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;
@@ -68,94 +69,31 @@ s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
        if (src->flags & INMEMORY) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 8;
+               disp = src->vv.regoff;
 
                if (IS_FLT_DBL_TYPE(src->type)) {
-                       if (IS_2_WORD_TYPE(src->type))
-                               M_DLD(tempreg, REG_SP, disp);
-                       else
-                               M_FLD(tempreg, REG_SP, disp);
-
-               } else {
-                       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;
-
-       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);
+       }
+       else
+               reg = src->vv.regoff;
 
        return reg;
 }
 
 
-
 /* emit_store ******************************************************************
 
    Emits a possible store to a 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;
 
@@ -167,57 +105,64 @@ void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
                COUNT_SPILLS;
 
                if (IS_FLT_DBL_TYPE(dst->type)) {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_DST(d, REG_SP, dst->regoff * 8);
-                       else
-                               M_FST(d, REG_SP, dst->regoff * 8);
-
-               } else {
-                       M_LST(d, REG_SP, dst->regoff * 8);
+                       M_DST(d, REG_SP, dst->vv.regoff);
+               }
+               else {
+                       M_LST(d, REG_SP, dst->vv.regoff);
                }
        }
 }
 
 
-/* emit_store_dst **************************************************************
+/* emit_copy *******************************************************************
 
-   Emits a possible store to the destination operand of an instruction.
+   Generates a register/memory to register/memory copy.
 
 *******************************************************************************/
 
-void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
+void emit_copy(jitdata *jd, instruction *iptr)
 {
-       emit_store(jd, iptr, iptr->dst.var, d);
-}
+       codegendata *cd;
+       varinfo     *src;
+       varinfo     *dst;
+       s4           s1, d;
 
+       /* get required compiler data */
 
-/* emit_copy *******************************************************************
+       cd = jd->cd;
 
-   XXX
+       /* get source and destination variables */
 
-*******************************************************************************/
+       src = VAROP(iptr->s1);
+       dst = VAROP(iptr->dst);
 
-void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
-{
-       codegendata  *cd;
-       registerdata *rd;
-       s4            s1, d;
-
-       /* get required compiler data */
+       if ((src->vv.regoff != dst->vv.regoff) ||
+               ((src->flags ^ dst->flags) & INMEMORY)) {
 
-       cd = jd->cd;
-       rd = jd->rd;
+               if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
+                       /* emit nothing, as the value won't be used anyway */
+                       return;
+               }
 
-       if ((src->regoff != dst->regoff) || 
-                       ((src->flags ^ dst->flags) & INMEMORY)) {
+               /* 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. */
 
-               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
-               s1 = emit_load_s1(jd, iptr, src, d);
+               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);
+               }
 
-               if (IS_FLT_DBL_TYPE(src->type))
-                       M_FLTMOVE(s1, d);
-               else
-                       M_INTMOVE(s1, d);
+               if (s1 != d) {
+                       if (IS_FLT_DBL_TYPE(src->type))
+                               M_FMOV(s1, d);
+                       else
+                               M_MOV(s1, d);
+               }
 
                emit_store(jd, iptr, dst, d);
        }
@@ -234,28 +179,39 @@ void emit_iconst(codegendata *cd, s4 d, s4 value)
 {
        s4 disp;
 
-       if ((value >= -32768) && (value <= 32767))
+       if ((value >= -32768) && (value <= 32767)) {
                M_LDA_INTERN(d, REG_ZERO, value);
-       else {
-               disp = dseg_adds4(cd, 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_verbosecall_enter ******************************************************
- *
- *    Generates the code for the call trace.
- *
- ********************************************************************************/
 
-void emit_verbosecall_enter (jitdata *jd)
+   Generates the code for the call trace.
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
+void emit_verbosecall_enter(jitdata *jd)
 {
        methodinfo   *m;
        codegendata  *cd;
        registerdata *rd;
-       s4 s1, p, t, d;
-/*     int stack_off; */
+       s4 s1, p, t;
        int stack_size;
        methoddesc *md;
 
@@ -287,25 +243,6 @@ void emit_verbosecall_enter (jitdata *jd)
        /* mark trace code */
        M_NOP;
 
-       /* save up to TRACE_ARGS_NUM arguments into the reserved stack space */
-#if 0
-#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_LST(d, REG_SP, LA_SIZE + PA_SIZE + 4 * 8 + 8 + p * 8);
-       }
-       p = 4;
-#endif
-#endif
        M_MFLR(REG_ZERO);
        M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
        M_STDU(REG_SP, REG_SP, -stack_size);
@@ -314,15 +251,15 @@ void emit_verbosecall_enter (jitdata *jd)
                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);
+                               M_LST(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;
+                               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];
+                               s1 = md->params[p].regoff;
                                M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
                        } else { /* on Stack */
                                /* this should not happen */
@@ -331,12 +268,8 @@ void emit_verbosecall_enter (jitdata *jd)
                }
        }
 
-       /* 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);
-       }
+       #warning "emit_verbosecall_enter not implemented"
 #else
        /* LINUX */
        /* Set integer and float argument registers for trace_args call */
@@ -344,13 +277,13 @@ void emit_verbosecall_enter (jitdata *jd)
        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);
+                       M_LLD(abi_registers_integer_argument[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]);
+                               s1 = md->params[p].regoff;
+                               M_MOV(s1, abi_registers_integer_argument[p]);
                        } else  {
                                assert(0);
                        }
@@ -359,7 +292,7 @@ void emit_verbosecall_enter (jitdata *jd)
 #endif
 
        /* put methodinfo pointer on Stackframe */
-       p = dseg_addaddress(cd, m);
+       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); 
@@ -374,33 +307,33 @@ void emit_verbosecall_enter (jitdata *jd)
 #endif
        /* call via function descriptor */
        /* XXX: what about TOC? */
-       p = dseg_addaddress(cd, builtin_trace_args);
+       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__)
-       /* 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) {
-                               M_LLD(rd->argintregs[md->params[p].regoff], REG_SP, stack_off);
-                       } else  {
-                               assert(0);
-                       }
-               }
-       }
+       #warning "emit_verbosecall_enter not implemented"
 #else
        /* LINUX */
        for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
-               d = rd->argintregs[p];
-               /* restore integer argument registers */
-               M_LLD(d, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
+               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(abi_registers_integer_argument[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(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);
@@ -410,20 +343,31 @@ void emit_verbosecall_enter (jitdata *jd)
        /* mark trace code */
        M_NOP;
 }
+#endif
 
 
 /* emit_verbosecall_exit ******************************************************
- *
- *    Generates the code for the call trace.
- *
- ********************************************************************************/
 
+   Generates the code for the call trace.
+
+   void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
+
+*******************************************************************************/
+
+#if !defined(NDEBUG)
 void emit_verbosecall_exit(jitdata *jd)
 {
-       codegendata *cd = jd->cd;
-       s4 disp;
+       methodinfo   *m;
+       codegendata  *cd;
+       s4            disp;
+
+       /* get required compiler data */
+
+       m  = jd->m;
+       cd = jd->cd;
 
        /* mark trace code */
+
        M_NOP;
 
        M_MFLR(REG_ZERO);
@@ -432,18 +376,15 @@ void emit_verbosecall_exit(jitdata *jd)
        M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
        M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
 
-#if defined(__DARWIN__)
-       M_MOV(REG_RESULT, jd->rd->argintregs[1]);
-#else
-       M_MOV(REG_RESULT, jd->rd->argintregs[1]);
-#endif
+       M_MOV(REG_RESULT, REG_A0);
+
+       M_FLTMOVE(REG_FRESULT, REG_FA0);
+       M_FLTMOVE(REG_FRESULT, REG_FA1);
 
-       disp = dseg_addaddress(cd, jd->m);
-       M_ALD(jd->rd->argintregs[0], REG_PV, disp);
+       disp = dseg_add_address(cd, m);
+       M_ALD(REG_A3, REG_PV, disp);
 
-       M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[0]);
-       M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[1]);
-       disp = dseg_addaddress(cd, builtin_displaymethodstop);
+       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);
@@ -457,10 +398,383 @@ void emit_verbosecall_exit(jitdata *jd)
        M_MTLR(REG_ZERO);
 
        /* mark trace code */
+
        M_NOP;
 }
+#endif
 
 
+/* emit_branch *****************************************************************
+
+   Emits the code for conditional and unconditional branchs.
+
+*******************************************************************************/
+
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
+{
+       s4 checkdisp;
+       s4 branchdisp;
+
+       /* calculate the different displacements */
+
+       checkdisp  =  disp + 4;
+       branchdisp = (disp - 4) >> 2;
+
+       /* check which branch to generate */
+
+       if (condition == BRANCH_UNCONDITIONAL) {
+               /* check displacement for overflow */
+
+               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);
+                       }
+
+                       vm_abort("emit_branch: emit unconditional long-branch code");
+               }
+               else {
+                       M_BR(branchdisp);
+               }
+       }
+       else {
+               /* and displacement for overflow */
+
+               if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
+                       /* 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);
+                       }
+
+                       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_array_t, size));
+               M_CMPU(s2, REG_ITMP3);
+               codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
+               BRANCH_NOPS;
+#else
+               M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, 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_arithmetic_check *******************************************************
+
+   Emit an ArithmeticException check.
+
+*******************************************************************************/
+
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, 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
+       }
+}
+
+#if 0
+/* emit_arraystore_check *******************************************************
+
+   Emit an ArrayStoreException check.
+
+*******************************************************************************/
+
+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
+
+/* emit_classcast_check ********************************************************
+
+   Emit a ClassCastException check.
+
+*******************************************************************************/
+
+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_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);
+               /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
+               M_LWZ(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))       {
+       #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;
+
+       /* generate code patching stub call code */
+
+       targetdisp = 0;
+
+       for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
+               /* check code segment size */
+
+               MCODECHECK(32);
+
+               /* Get machine code which is patched back in later. The
+                  call is 1 instruction word long. */
+
+               tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
+
+               mcode = *((u4 *) tmpmcodeptr);
+
+               /* Patch in the call to call the following code (done at
+                  compile time). */
+
+               savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
+               cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
+
+               disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
+               M_BR(disp);
+
+               cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
+
+               /* create stack frame - keep stack 16-byte aligned */
+               M_AADD_IMM(REG_SP, -8 * 8, REG_SP);
+
+               /* calculate return address and move it onto the stack */
+               M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 5 * 8);
+
+               /* move pointer to java_objectheader onto stack */
+
+#if defined(ENABLE_THREADS)
+               /* order reversed because of data segment layout */
+
+               (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
+
+               /* move machine code onto stack */
+               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 */
+               disp = dseg_add_address(cd, pref->ref);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 2 * 8);
+
+               /* move data segment displacement onto stack */
+               disp = dseg_add_s4(cd, pref->disp);
+               M_ILD(REG_ITMP3, REG_PV, disp);
+               M_IST_INTERN(REG_ITMP3, REG_SP, 1 * 8);
+
+               /* move patcher function pointer onto stack */
+               disp = dseg_add_functionptr(cd, pref->patcher);
+               M_ALD(REG_ITMP3, REG_PV, disp);
+               M_AST_INTERN(REG_ITMP3, REG_SP, 0 * 8);
+
+               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);
+               }
+       }
+}
+
+
+/* emit_trap *******************************************************************
+
+   Emit a trap instruction and return the original machine code.
+
+*******************************************************************************/
+
+uint32_t emit_trap(codegendata *cd)
+{
+       uint32_t mcode;
+
+       /* Get machine code which is patched back in later. The
+          trap is 1 instruction word long. */
+
+       mcode = *((uint32_t *) cd->mcodeptr);
+
+       M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
+
+       return mcode;
+}
+
 
 /*
  * These are local overrides for various environment variables in Emacs.