* src/vm/jit/i386/codegen.c: fixed DUP2_X1 instruction, a "->prev" was missing
[cacao.git] / src / vm / jit / i386 / codegen.c
index 83277ec6038d7918d9de11479e6603453b4c5d8d..eda6a4cb32d3f9d3027c7233359b48a64f8b5f67 100644 (file)
@@ -30,7 +30,7 @@
    Changes: Joseph Wenninger
             Christian Ullrich
 
-   $Id: codegen.c 3567 2005-11-04 16:33:20Z twisti $
+   $Id: codegen.c 3949 2005-12-20 20:39:09Z edwin $
 
 */
 
@@ -55,7 +55,6 @@
 #include "vm/global.h"
 #include "vm/loader.h"
 #include "vm/stringlocal.h"
-#include "vm/tables.h"
 #include "vm/utf8.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/jit.h"
@@ -80,7 +79,7 @@
 
 *******************************************************************************/
 
-void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
+bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 {
        s4     len, s1, s2, s3, d, off;
        ptrint a;
@@ -576,16 +575,17 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
                        /* REG_RES Register usage: see lsra.inc icmd_uses_tmp */
                        /* EAX: NO ECX: NO EDX: NO */
+
                        d = reg_of_var(rd, iptr->dst, REG_ITMP1);
                        if (iptr->dst->flags & INMEMORY) {
-                               i386_mov_imm_membase(cd, iptr->val.i, REG_SP, iptr->dst->regoff * 4);
+                               M_IST_IMM(iptr->val.i, REG_SP, iptr->dst->regoff * 4);
 
                        } else {
                                if (iptr->val.i == 0) {
-                                       i386_alu_reg_reg(cd, ALU_XOR, d, d);
+                                       M_CLR(d);
 
                                } else {
-                                       i386_mov_imm_reg(cd, iptr->val.i, d);
+                                       M_MOV_IMM(iptr->val.i, d);
                                }
                        }
                        break;
@@ -595,10 +595,11 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
                        /* REG_RES Register usage: see lsra.inc icmd_uses_tmp */
                        /* EAX: NO ECX: NO EDX: NO */
+
                        d = reg_of_var(rd, iptr->dst, REG_ITMP1);
                        if (iptr->dst->flags & INMEMORY) {
-                               i386_mov_imm_membase(cd, iptr->val.l, REG_SP, iptr->dst->regoff * 4);
-                               i386_mov_imm_membase(cd, iptr->val.l >> 32, REG_SP, iptr->dst->regoff * 4 + 4);
+                               M_IST_IMM(iptr->val.l, REG_SP, iptr->dst->regoff * 4);
+                               M_IST_IMM(iptr->val.l >> 32, REG_SP, iptr->dst->regoff * 4 + 4);
                                
                        } else {
                                log_text("LCONST: longs have to be in memory");
@@ -608,6 +609,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
                case ICMD_FCONST:     /* ...  ==> ..., constant                       */
                                      /* op1 = 0, val.f = constant                    */
+
                        /* REG_RES Register usage: see lsra.inc icmd_uses_tmp */
                        /* EAX: YES ECX: NO EDX: NO */
 
@@ -643,6 +645,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                
                case ICMD_DCONST:     /* ...  ==> ..., constant                       */
                                      /* op1 = 0, val.d = constant                    */
+
                        /* REG_RES Register usage: see lsra.inc icmd_uses_tmp */
                        /* EAX: YES ECX: NO EDX: NO */
 
@@ -678,19 +681,34 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
                case ICMD_ACONST:     /* ...  ==> ..., constant                       */
                                      /* op1 = 0, val.a = constant                    */
+
                        /* REG_RES Register usage: see lsra.inc icmd_uses_tmp */
                        /* EAX: YES ECX: NO EDX: NO */
 
                        d = reg_of_var(rd, iptr->dst, REG_ITMP1);
-                       if (iptr->dst->flags & INMEMORY) {
-                               i386_mov_imm_membase(cd, (s4) iptr->val.a, REG_SP, iptr->dst->regoff * 4);
+
+                       if ((iptr->target != NULL) && (iptr->val.a == NULL)) {
+                               codegen_addpatchref(cd, cd->mcodeptr,
+                                                                       PATCHER_aconst,
+                                                                       (unresolved_class *) iptr->target, 0);
+
+                               if (opt_showdisassemble) {
+                                       M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
+                               }
+
+                               M_MOV_IMM((ptrint) iptr->val.a, d);
+                               store_reg_to_var_int(iptr->dst, d);
 
                        } else {
-                               if ((s4) iptr->val.a == 0) {
-                                       i386_alu_reg_reg(cd, ALU_XOR, d, d);
+                               if (iptr->dst->flags & INMEMORY) {
+                                       M_AST_IMM((ptrint) iptr->val.a, REG_SP, iptr->dst->regoff * 4);
 
                                } else {
-                                       i386_mov_imm_reg(cd, (s4) iptr->val.a, d);
+                                       if ((ptrint) iptr->val.a == 0) {
+                                               M_CLR(d);
+                                       } else {
+                                               M_MOV_IMM((ptrint) iptr->val.a, d);
+                                       }
                                }
                        }
                        break;
@@ -940,7 +958,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        M_COPY(src->prev,       iptr->dst->prev);
                        M_COPY(src->prev->prev, iptr->dst->prev->prev);
                        M_COPY(iptr->dst,       iptr->dst->prev->prev->prev);
-                       M_COPY(iptr->dst->prev, iptr->dst->prev->prev->prev);
+                       M_COPY(iptr->dst->prev, iptr->dst->prev->prev->prev->prev);
                        break;
 
                case ICMD_DUP2_X2:    /* ..., a, b, c, d ==> ..., c, d, a, b, c, d    */
@@ -2963,22 +2981,21 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        break;
 
                case ICMD_AASTORE:    /* ..., arrayref, index, value  ==> ...         */
+
                        /* REG_RES Register usage: see icmd_uses_reg_res.inc */
                        /* EAX: S|YES ECX: S|YES EDX: S|YES OUTPUT: REG_NULL */
 
                        var_to_reg_int(s1, src->prev->prev, REG_ITMP1);
                        var_to_reg_int(s2, src->prev, REG_ITMP2);
-/*                     if (iptr->op1 == 0) { */
+                       if (iptr->op1 == 0) {
                                gen_nullptr_check(s1);
                                gen_bound_check;
-/*                     } */
+                       }
                        var_to_reg_int(s3, src, REG_ITMP3);
 
-                       bte = iptr->val.a;
-
                        M_AST(s1, REG_SP, 0 * 4);
                        M_AST(s3, REG_SP, 1 * 4);
-                       M_MOV_IMM((ptrint) bte->fp, REG_ITMP1);
+                       M_MOV_IMM((ptrint) BUILTIN_canstore, REG_ITMP1);
                        M_CALL(REG_ITMP1);
                        M_TEST(REG_RESULT);
                        M_BEQ(0);
@@ -3090,7 +3107,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        } else {
                                fieldinfo *fi = iptr->val.a;
 
-                               if (!fi->class->initialized) {
+                               if (!(fi->class->state & CLASS_INITIALIZED)) {
                                        codegen_addpatchref(cd, cd->mcodeptr,
                                                                                PATCHER_clinit, fi->class, 0);
 
@@ -3158,7 +3175,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        } else {
                                fieldinfo *fi = iptr->val.a;
 
-                               if (!fi->class->initialized) {
+                               if (!(fi->class->state & CLASS_INITIALIZED)) {
                                        codegen_addpatchref(cd, cd->mcodeptr,
                                                                                PATCHER_clinit, fi->class, 0);
 
@@ -3226,7 +3243,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        } else {
                                fieldinfo *fi = iptr[1].val.a;
 
-                               if (!fi->class->initialized) {
+                               if (!(fi->class->state & CLASS_INITIALIZED)) {
                                        codegen_addpatchref(cd, cd->mcodeptr,
                                                                                PATCHER_clinit, fi->class, 0);
 
@@ -3409,6 +3426,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        var_to_reg_int(s1, src, REG_ITMP1);
                        M_INTMOVE(s1, REG_ITMP1_XPTR);
 
+#ifdef ENABLE_VERIFIER
                        if (iptr->val.a) {
                                codegen_addpatchref(cd, cd->mcodeptr,
                                                                        PATCHER_athrow_areturn,
@@ -3418,6 +3436,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                                        M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
                                }
                        }
+#endif /* ENABLE_VERIFIER */
 
                        M_CALL_IMM(0);                            /* passing exception pc */
                        M_POP(REG_ITMP2_XPC);
@@ -4061,6 +4080,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        var_to_reg_int(s1, src, REG_RESULT);
                        M_INTMOVE(s1, REG_RESULT);
 
+#ifdef ENABLE_VERIFIER
                        if (iptr->val.a) {
                                codegen_addpatchref(cd, cd->mcodeptr,
                                                                        PATCHER_athrow_areturn,
@@ -4070,6 +4090,7 @@ void codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                                        M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
                                }
                        }
+#endif /* ENABLE_VERIFIER */
                        goto nowperformreturn;
 
                case ICMD_FRETURN:      /* ..., retvalue ==> ...                      */
@@ -4131,17 +4152,17 @@ nowperformreturn:
                                        break;
 
                                case ICMD_FRETURN:
-                                       i386_fsts_membase(cd, REG_SP, rd->memuse * 4);
+                                       i386_fstps_membase(cd, REG_SP, rd->memuse * 4);
                                        break;
 
                                case ICMD_DRETURN:
-                                       i386_fstl_membase(cd, REG_SP, rd->memuse * 4);
+                                       i386_fstpl_membase(cd, REG_SP, rd->memuse * 4);
                                        break;
                                }
 
                                M_AST(REG_ITMP2, REG_SP, 0);
-                               i386_mov_imm_reg(cd, (ptrint) BUILTIN_monitorexit, REG_ITMP1);
-                               i386_call_reg(cd, REG_ITMP1);
+                               M_MOV_IMM((ptrint) BUILTIN_monitorexit, REG_ITMP1);
+                               M_CALL(REG_ITMP1);
 
                                /* and now restore the proper return value */
                                switch (iptr->opc) {
@@ -4292,16 +4313,17 @@ nowperformreturn:
                case ICMD_INVOKESPECIAL:/* ..., objectref, [arg1, [arg2 ...]] ==> ... */
                case ICMD_INVOKEVIRTUAL:/* op1 = arg count, val.a = method pointer    */
                case ICMD_INVOKEINTERFACE:
+
                        /* REG_RES Register usage: see icmd_uses_reg_res.inc */
-                       /* EAX: S|YES ECX: YES EDX: YES OUTPUT: EAX*/
+                       /* EAX: S|YES ECX: YES EDX: YES OUTPUT: EAX */
 
                        lm = iptr->val.a;
 
-                       if (lm)
-                               md = lm->parseddesc;
-                       else {
+                       if (lm == NULL) {
                                unresolved_method *um = iptr->target;
                                md = um->methodref->parseddesc.md;
+                       } else {
+                               md = lm->parseddesc;
                        }
 
 gen_method:
@@ -4362,20 +4384,7 @@ gen_method:
 
                        switch (iptr->opc) {
                        case ICMD_BUILTIN:
-                               if (iptr->target) {
-                                       codegen_addpatchref(cd, cd->mcodeptr, bte->fp,
-                                                                               iptr->target, 0);
-
-                                       if (opt_showdisassemble) {
-                                               M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
-                                       }
-
-                                       a = 0;
-
-                               } else {
-                                       a = (ptrint) bte->fp;
-                               }
-
+                               a = (ptrint) bte->fp;
                                d = md->returntype.type;
 
                                M_MOV_IMM(a, REG_ITMP1);
@@ -4400,7 +4409,7 @@ gen_method:
                                /* fall through */
 
                        case ICMD_INVOKESTATIC:
-                               if (!lm) {
+                               if (lm == NULL) {
                                        unresolved_method *um = iptr->target;
 
                                        codegen_addpatchref(cd, cd->mcodeptr,
@@ -4423,10 +4432,10 @@ gen_method:
                                break;
 
                        case ICMD_INVOKEVIRTUAL:
-                               i386_mov_membase_reg(cd, REG_SP, 0, REG_ITMP1);
+                               M_ALD(REG_ITMP1, REG_SP, 0 * 4);
                                gen_nullptr_check(REG_ITMP1);
 
-                               if (!lm) {
+                               if (lm == NULL) {
                                        unresolved_method *um = iptr->target;
 
                                        codegen_addpatchref(cd, cd->mcodeptr,
@@ -4454,7 +4463,7 @@ gen_method:
                                M_ALD(REG_ITMP1, REG_SP, 0 * 4);
                                gen_nullptr_check(REG_ITMP1);
 
-                               if (!lm) {
+                               if (lm == NULL) {
                                        unresolved_method *um = iptr->target;
 
                                        codegen_addpatchref(cd, cd->mcodeptr,
@@ -4521,12 +4530,12 @@ gen_method:
 
 
                case ICMD_CHECKCAST:  /* ..., objectref ==> ..., objectref            */
-                       /* REG_RES Register usage: see icmd_uses_reg_res.inc */
-                       /* EAX: YES ECX: I|YES EDX: I|YES OUTPUT: REG_NULL*/ 
-
                                      /* op1:   0 == array, 1 == class                */
                                      /* val.a: (classinfo*) superclass               */
 
+                       /* REG_RES Register usage: see icmd_uses_reg_res.inc */
+                       /* EAX: YES ECX: I|YES EDX: I|YES OUTPUT: REG_NULL */
+
                        /*  superclass is an interface:
                         *
                         *  OK if ((sub == NULL) ||
@@ -4540,221 +4549,215 @@ gen_method:
                         *         super->vftbl->diffval));
                         */
 
-                       {
-                       classinfo *super;
-                       vftbl_t   *supervftbl;
-                       s4         superindex;
+                       if (iptr->op1 == 1) {
+                               /* object type cast-check */
 
-                       super = (classinfo *) iptr->val.a;
+                               classinfo *super;
+                               vftbl_t   *supervftbl;
+                               s4         superindex;
 
-                       if (!super) {
-                               superindex = 0;
-                               supervftbl = NULL;
+                               super = (classinfo *) iptr->val.a;
 
-                       } else {
-                               superindex = super->index;
-                               supervftbl = super->vftbl;
-                       }
+                               if (!super) {
+                                       superindex = 0;
+                                       supervftbl = NULL;
+
+                               } else {
+                                       superindex = super->index;
+                                       supervftbl = super->vftbl;
+                               }
                        
 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                       codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase);
+                               codegen_threadcritrestart(cd, cd->mcodeptr - cd->mcodebase);
 #endif
-                       var_to_reg_int(s1, src, REG_ITMP1);
+                               var_to_reg_int(s1, src, REG_ITMP1);
 
-                       /* calculate interface checkcast code size */
+                               /* calculate interface checkcast code size */
 
-                       s2 = 2; /* mov_membase_reg */
-                       CALCOFFSETBYTES(s2, s1, OFFSET(java_objectheader, vftbl));
+                               s2 = 2; /* mov_membase_reg */
+                               CALCOFFSETBYTES(s2, s1, OFFSET(java_objectheader, vftbl));
 
-                       s2 += (2 + 4 /* mov_membase32_reg */ + 2 + 4 /* sub imm32 */ +
-                                  2 /* test */ + 6 /* jcc */ + 2 + 4 /* mov_membase32_reg */ +
-                                  2 /* test */ + 6 /* jcc */);
+                               s2 += (2 + 4 /* mov_membase32_reg */ + 2 + 4 /* sub imm32 */ +
+                                          2 /* test */ + 6 /* jcc */ + 2 + 4 /* mov_membase32_reg */ +
+                                          2 /* test */ + 6 /* jcc */);
 
-                       if (!super)
-                               s2 += (opt_showdisassemble ? 5 : 0);
+                               if (!super)
+                                       s2 += (opt_showdisassemble ? 5 : 0);
 
-                       /* calculate class checkcast code size */
+                               /* calculate class checkcast code size */
 
-                       s3 = 2; /* mov_membase_reg */
-                       CALCOFFSETBYTES(s3, s1, OFFSET(java_objectheader, vftbl));
+                               s3 = 2; /* mov_membase_reg */
+                               CALCOFFSETBYTES(s3, s1, OFFSET(java_objectheader, vftbl));
 
-                       s3 += 5 /* mov_imm_reg */ + 2 + 4 /* mov_membase32_reg */;
+                               s3 += 5 /* mov_imm_reg */ + 2 + 4 /* mov_membase32_reg */;
 
 #if 0
-                       if (s1 != REG_ITMP1) {
-                               a += 2;
-                               CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, baseval));
+                               if (s1 != REG_ITMP1) {
+                                       a += 2;
+                                       CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, baseval));
                                
-                               a += 2;
-                               CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, diffval));
+                                       a += 2;
+                                       CALCOFFSETBYTES(a, REG_ITMP3, OFFSET(vftbl_t, diffval));
                                
-                               a += 2;
+                                       a += 2;
                                
-                       } else
+                               } else
 #endif
-                               {
-                                       s3 += (2 + 4 /* mov_membase32_reg */ + 2 /* sub */ +
-                                                  5 /* mov_imm_reg */ + 2 /* mov_membase_reg */);
-                                       CALCOFFSETBYTES(s3, REG_ITMP3, OFFSET(vftbl_t, diffval));
-                               }
-
-                       s3 += 2 /* cmp */ + 6 /* jcc */;
-
-                       if (!super)
-                               s3 += (opt_showdisassemble ? 5 : 0);
-
-                       /* if class is not resolved, check which code to call */
-
-                       if (!super) {
-                               i386_test_reg_reg(cd, s1, s1);
-                               i386_jcc(cd, I386_CC_Z, 5 + (opt_showdisassemble ? 5 : 0) + 6 + 6 + s2 + 5 + s3);
-
-                               codegen_addpatchref(cd, cd->mcodeptr,
-                                                                       PATCHER_checkcast_instanceof_flags,
-                                                                       (constant_classref *) iptr->target, 0);
+                                       {
+                                               s3 += (2 + 4 /* mov_membase32_reg */ + 2 /* sub */ +
+                                                          5 /* mov_imm_reg */ + 2 /* mov_membase_reg */);
+                                               CALCOFFSETBYTES(s3, REG_ITMP3, OFFSET(vftbl_t, diffval));
+                                       }
 
-                               if (opt_showdisassemble) {
-                                       M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
-                               }
+                               s3 += 2 /* cmp */ + 6 /* jcc */;
 
-                               i386_mov_imm_reg(cd, 0, REG_ITMP2); /* super->flags */
-                               i386_alu_imm_reg(cd, ALU_AND, ACC_INTERFACE, REG_ITMP2);
-                               i386_jcc(cd, I386_CC_Z, s2 + 5);
-                       }
+                               if (!super)
+                                       s3 += (opt_showdisassemble ? 5 : 0);
 
-                       /* interface checkcast code */
+                               /* if class is not resolved, check which code to call */
 
-                       if (!super || (super->flags & ACC_INTERFACE)) {
-                               if (super) {
+                               if (!super) {
                                        i386_test_reg_reg(cd, s1, s1);
-                                       i386_jcc(cd, I386_CC_Z, s2);
-                               }
+                                       i386_jcc(cd, I386_CC_Z, 5 + (opt_showdisassemble ? 5 : 0) + 6 + 6 + s2 + 5 + s3);
 
-                               i386_mov_membase_reg(cd, s1,
-                                                                        OFFSET(java_objectheader, vftbl),
-                                                                        REG_ITMP2);
-
-                               if (!super) {
                                        codegen_addpatchref(cd, cd->mcodeptr,
-                                                                               PATCHER_checkcast_instanceof_interface,
+                                                                               PATCHER_checkcast_instanceof_flags,
                                                                                (constant_classref *) iptr->target, 0);
 
                                        if (opt_showdisassemble) {
                                                M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
                                        }
+
+                                       i386_mov_imm_reg(cd, 0, REG_ITMP2); /* super->flags */
+                                       i386_alu_imm_reg(cd, ALU_AND, ACC_INTERFACE, REG_ITMP2);
+                                       i386_jcc(cd, I386_CC_Z, s2 + 5);
                                }
 
-                               i386_mov_membase32_reg(cd, REG_ITMP2,
-                                                                          OFFSET(vftbl_t, interfacetablelength),
-                                                                          REG_ITMP3);
-                               i386_alu_imm32_reg(cd, ALU_SUB, superindex, REG_ITMP3);
-                               i386_test_reg_reg(cd, REG_ITMP3, REG_ITMP3);
-                               i386_jcc(cd, I386_CC_LE, 0);
-                               codegen_addxcastrefs(cd, cd->mcodeptr);
-                               i386_mov_membase32_reg(cd, REG_ITMP2,
-                                                                          OFFSET(vftbl_t, interfacetable[0]) -
-                                                                          superindex * sizeof(methodptr*),
-                                                                          REG_ITMP3);
-                               i386_test_reg_reg(cd, REG_ITMP3, REG_ITMP3);
-                               i386_jcc(cd, I386_CC_E, 0);
-                               codegen_addxcastrefs(cd, cd->mcodeptr);
+                               /* interface checkcast code */
 
-                               if (!super)
-                                       i386_jmp_imm(cd, s3);
-                       }
+                               if (!super || (super->flags & ACC_INTERFACE)) {
+                                       if (super) {
+                                               i386_test_reg_reg(cd, s1, s1);
+                                               i386_jcc(cd, I386_CC_Z, s2);
+                                       }
 
-                       /* class checkcast code */
+                                       i386_mov_membase_reg(cd, s1,
+                                                                                OFFSET(java_objectheader, vftbl),
+                                                                                REG_ITMP2);
 
-                       if (!super || !(super->flags & ACC_INTERFACE)) {
-                               if (super) {
-                                       i386_test_reg_reg(cd, s1, s1);
-                                       i386_jcc(cd, I386_CC_Z, s3);
+                                       if (!super) {
+                                               codegen_addpatchref(cd, cd->mcodeptr,
+                                                                                       PATCHER_checkcast_instanceof_interface,
+                                                                                       (constant_classref *) iptr->target, 0);
+
+                                               if (opt_showdisassemble) {
+                                                       M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
+                                               }
+                                       }
+
+                                       i386_mov_membase32_reg(cd, REG_ITMP2,
+                                                                                  OFFSET(vftbl_t, interfacetablelength),
+                                                                                  REG_ITMP3);
+                                       i386_alu_imm32_reg(cd, ALU_SUB, superindex, REG_ITMP3);
+                                       i386_test_reg_reg(cd, REG_ITMP3, REG_ITMP3);
+                                       i386_jcc(cd, I386_CC_LE, 0);
+                                       codegen_addxcastrefs(cd, cd->mcodeptr);
+                                       i386_mov_membase32_reg(cd, REG_ITMP2,
+                                                                                  OFFSET(vftbl_t, interfacetable[0]) -
+                                                                                  superindex * sizeof(methodptr*),
+                                                                                  REG_ITMP3);
+                                       i386_test_reg_reg(cd, REG_ITMP3, REG_ITMP3);
+                                       i386_jcc(cd, I386_CC_E, 0);
+                                       codegen_addxcastrefs(cd, cd->mcodeptr);
+
+                                       if (!super)
+                                               i386_jmp_imm(cd, s3);
                                }
 
-                               i386_mov_membase_reg(cd, s1,
-                                                                        OFFSET(java_objectheader, vftbl),
-                                                                        REG_ITMP2);
+                               /* class checkcast code */
 
-                               if (!super) {
-                                       codegen_addpatchref(cd, cd->mcodeptr,
-                                                                               PATCHER_checkcast_class,
-                                                                               (constant_classref *) iptr->target, 0);
+                               if (!super || !(super->flags & ACC_INTERFACE)) {
+                                       if (super) {
+                                               i386_test_reg_reg(cd, s1, s1);
+                                               i386_jcc(cd, I386_CC_Z, s3);
+                                       }
 
-                                       if (opt_showdisassemble) {
-                                               M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
+                                       i386_mov_membase_reg(cd, s1,
+                                                                                OFFSET(java_objectheader, vftbl),
+                                                                                REG_ITMP2);
+
+                                       if (!super) {
+                                               codegen_addpatchref(cd, cd->mcodeptr,
+                                                                                       PATCHER_checkcast_class,
+                                                                                       (constant_classref *) iptr->target, 0);
+
+                                               if (opt_showdisassemble) {
+                                                       M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
+                                               }
                                        }
-                               }
 
-                               i386_mov_imm_reg(cd, (ptrint) supervftbl, REG_ITMP3);
+                                       i386_mov_imm_reg(cd, (ptrint) supervftbl, REG_ITMP3);
 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                               codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
+                                       codegen_threadcritstart(cd, cd->mcodeptr - cd->mcodebase);
 #endif
-                               i386_mov_membase32_reg(cd, REG_ITMP2,
-                                                                          OFFSET(vftbl_t, baseval),
-                                                                          REG_ITMP2);
-
-/*                             if (s1 != REG_ITMP1) { */
-/*                                     i386_mov_membase_reg(cd, REG_ITMP3, OFFSET(vftbl_t, baseval), REG_ITMP1); */
-/*                                     i386_mov_membase_reg(cd, REG_ITMP3, OFFSET(vftbl_t, diffval), REG_ITMP3); */
-/* #if defined(USE_THREADS) && defined(NATIVE_THREADS) */
-/*                                     codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */
-/* #endif */
-/*                                     i386_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */
-
-/*                             } else { */
-                               i386_mov_membase32_reg(cd, REG_ITMP3,
-                                                                          OFFSET(vftbl_t, baseval),
-                                                                          REG_ITMP3);
-                               i386_alu_reg_reg(cd, ALU_SUB, REG_ITMP3, REG_ITMP2);
-                               i386_mov_imm_reg(cd, (ptrint) supervftbl, REG_ITMP3);
-                               i386_mov_membase_reg(cd, REG_ITMP3,
-                                                                        OFFSET(vftbl_t, diffval),
-                                                                        REG_ITMP3);
+                                       i386_mov_membase32_reg(cd, REG_ITMP2,
+                                                                                  OFFSET(vftbl_t, baseval),
+                                                                                  REG_ITMP2);
+
+                                       /*                              if (s1 != REG_ITMP1) { */
+                                       /*                                      i386_mov_membase_reg(cd, REG_ITMP3, OFFSET(vftbl_t, baseval), REG_ITMP1); */
+                                       /*                                      i386_mov_membase_reg(cd, REG_ITMP3, OFFSET(vftbl_t, diffval), REG_ITMP3); */
+                                       /* #if defined(USE_THREADS) && defined(NATIVE_THREADS) */
+                                       /*                                      codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */
+                                       /* #endif */
+                                       /*                                      i386_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */
+
+                                       /*                              } else { */
+                                       i386_mov_membase32_reg(cd, REG_ITMP3,
+                                                                                  OFFSET(vftbl_t, baseval),
+                                                                                  REG_ITMP3);
+                                       i386_alu_reg_reg(cd, ALU_SUB, REG_ITMP3, REG_ITMP2);
+                                       i386_mov_imm_reg(cd, (ptrint) supervftbl, REG_ITMP3);
+                                       i386_mov_membase_reg(cd, REG_ITMP3,
+                                                                                OFFSET(vftbl_t, diffval),
+                                                                                REG_ITMP3);
 #if defined(USE_THREADS) && defined(NATIVE_THREADS)
-                               codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
+                                       codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase);
 #endif
-/*                             } */
+                                       /*                              } */
 
-                               i386_alu_reg_reg(cd, ALU_CMP, REG_ITMP3, REG_ITMP2);
-                               i386_jcc(cd, I386_CC_A, 0);    /* (u) REG_ITMP2 > (u) REG_ITMP3 -> jump */
-                               codegen_addxcastrefs(cd, cd->mcodeptr);
-                       }
-                       d = reg_of_var(rd, iptr->dst, REG_ITMP3);
-                       M_INTMOVE(s1, d);
-                       store_reg_to_var_int(iptr->dst, d);
-                       }
-                       break;
-
-               case ICMD_ARRAYCHECKCAST: /* ..., objectref ==> ..., objectref        */
-                                         /* op1: 1... resolved, 0... not resolved    */
+                                       i386_alu_reg_reg(cd, ALU_CMP, REG_ITMP3, REG_ITMP2);
+                                       i386_jcc(cd, I386_CC_A, 0);    /* (u) REG_ITMP2 > (u) REG_ITMP3 -> jump */
+                                       codegen_addxcastrefs(cd, cd->mcodeptr);
+                               }
+                               d = reg_of_var(rd, iptr->dst, REG_ITMP3);
 
-                       var_to_reg_int(s1, src, REG_ITMP1);
-                       M_AST(s1, REG_SP, 0 * 4);
+                       } else {
+                               /* array type cast-check */
 
-                       bte = iptr->val.a;
+                               var_to_reg_int(s1, src, REG_ITMP1);
+                               M_AST(s1, REG_SP, 0 * 4);
 
-                       if (!iptr->op1) {
-                               codegen_addpatchref(cd, cd->mcodeptr, bte->fp, iptr->target, 0);
+                               if (iptr->val.a == NULL) {
+                                       codegen_addpatchref(cd, cd->mcodeptr,
+                                                                               PATCHER_builtin_arraycheckcast,
+                                                                               iptr->target, 0);
 
-                               if (opt_showdisassemble) {
-                                       M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
+                                       if (opt_showdisassemble) {
+                                               M_NOP; M_NOP; M_NOP; M_NOP; M_NOP;
+                                       }
                                }
 
-                               a = 0;
+                               M_AST_IMM((ptrint) iptr->val.a, REG_SP, 1 * 4);
+                               M_MOV_IMM((ptrint) BUILTIN_arraycheckcast, REG_ITMP3);
+                               M_CALL(REG_ITMP3);
+                               M_TEST(REG_RESULT);
+                               M_BEQ(0);
+                               codegen_addxcastrefs(cd, cd->mcodeptr);
 
-                       } else {
-                               a = (ptrint) bte->fp;
+                               var_to_reg_int(s1, src, REG_ITMP1);
+                               d = reg_of_var(rd, iptr->dst, s1);
                        }
-
-                       M_AST_IMM((ptrint) iptr->target, REG_SP, 1 * 4);
-                       M_MOV_IMM((ptrint) a, REG_ITMP3);
-                       M_CALL(REG_ITMP3);
-                       M_TEST(REG_RESULT);
-                       M_BEQ(0);
-                       codegen_addxcastrefs(cd, cd->mcodeptr);
-
-                       var_to_reg_int(s1, src, REG_ITMP1);
-                       d = reg_of_var(rd, iptr->dst, s1);
                        M_INTMOVE(s1, d);
                        store_reg_to_var_int(iptr->dst, d);
                        break;
@@ -5023,8 +5026,9 @@ gen_method:
                        break;
 
                default:
-                       throw_cacao_exception_exit(string_java_lang_InternalError,
-                                                                          "Unknown ICMD %d", iptr->opc);
+                       *exceptionptr =
+                               new_internalerror("Unknown ICMD %d", iptr->opc);
+                       return false;
        } /* switch */
                
        } /* for instruction */
@@ -5102,22 +5106,15 @@ gen_method:
        xcodeptr = NULL;
        
        for (bref = cd->xdivrefs; bref != NULL; bref = bref->next) {
-               if ((cd->exceptiontablelength == 0) && (xcodeptr != NULL)) {
-                       gen_resolvebranch(cd->mcodebase + bref->branchpos, 
-                                                         bref->branchpos,
-                                                         xcodeptr - cd->mcodebase - (5 + 6));
-                       continue;
-               }
-
                gen_resolvebranch(cd->mcodebase + bref->branchpos, 
                                  bref->branchpos,
                                                  cd->mcodeptr - cd->mcodebase);
 
-               MCODECHECK(100);
+               MCODECHECK(512);
 
-               M_MOV_IMM(0, REG_ITMP2_XPC);                               /* 5 bytes */
+               M_MOV_IMM(0, REG_ITMP2_XPC);
                dseg_adddata(cd, cd->mcodeptr);
-               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);          /* 6 bytes */
+               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);
 
                if (xcodeptr != NULL) {
                        M_JMP_IMM((xcodeptr - cd->mcodeptr) - 5);
@@ -5157,15 +5154,15 @@ gen_method:
                                  bref->branchpos,
                                                  cd->mcodeptr - cd->mcodebase);
 
-               MCODECHECK(100);
+               MCODECHECK(512);
 
                /* move index register into REG_ITMP1 */
 
-               M_INTMOVE(bref->reg, REG_ITMP1);                           /* 2 bytes */
+               M_INTMOVE(bref->reg, REG_ITMP1);
 
-               M_MOV_IMM(0, REG_ITMP2_XPC);                               /* 5 bytes */
+               M_MOV_IMM(0, REG_ITMP2_XPC);
                dseg_adddata(cd, cd->mcodeptr);
-               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);          /* 6 bytes */
+               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);
 
                if (xcodeptr != NULL) {
                        M_JMP_IMM((xcodeptr - cd->mcodeptr) - 5);
@@ -5202,22 +5199,15 @@ gen_method:
        xcodeptr = NULL;
        
        for (bref = cd->xstorerefs; bref != NULL; bref = bref->next) {
-               if ((cd->exceptiontablelength == 0) && (xcodeptr != NULL)) {
-                       gen_resolvebranch(cd->mcodebase + bref->branchpos, 
-                                                         bref->branchpos,
-                                                         xcodeptr - cd->mcodebase - (5 + 6));
-                       continue;
-               }
-
                gen_resolvebranch(cd->mcodebase + bref->branchpos, 
                                  bref->branchpos,
                                                  cd->mcodeptr - cd->mcodebase);
 
-               MCODECHECK(100);
+               MCODECHECK(512);
 
-               M_MOV_IMM(0, REG_ITMP2_XPC);                               /* 5 bytes */
+               M_MOV_IMM(0, REG_ITMP2_XPC);
                dseg_adddata(cd, cd->mcodeptr);
-               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);          /* 6 bytes */
+               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);
 
                if (xcodeptr != NULL) {
                        M_JMP_IMM((xcodeptr - cd->mcodeptr) - 5);
@@ -5253,22 +5243,15 @@ gen_method:
        xcodeptr = NULL;
        
        for (bref = cd->xcastrefs; bref != NULL; bref = bref->next) {
-               if ((cd->exceptiontablelength == 0) && (xcodeptr != NULL)) {
-                       gen_resolvebranch(cd->mcodebase + bref->branchpos, 
-                                                         bref->branchpos,
-                                                         xcodeptr - cd->mcodebase - (5 + 6));
-                       continue;
-               }
-
                gen_resolvebranch(cd->mcodebase + bref->branchpos, 
                                  bref->branchpos,
                                                  cd->mcodeptr - cd->mcodebase);
 
-               MCODECHECK(100);
+               MCODECHECK(512);
 
-               M_MOV_IMM(0, REG_ITMP2_XPC);                               /* 5 bytes */
+               M_MOV_IMM(0, REG_ITMP2_XPC);
                dseg_adddata(cd, cd->mcodeptr);
-               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);          /* 6 bytes */
+               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);
 
                if (xcodeptr != NULL) {
                        M_JMP_IMM((xcodeptr - cd->mcodeptr) - 5);
@@ -5303,22 +5286,15 @@ gen_method:
        xcodeptr = NULL;
        
        for (bref = cd->xnullrefs; bref != NULL; bref = bref->next) {
-               if ((cd->exceptiontablelength == 0) && (xcodeptr != NULL)) {
-                       gen_resolvebranch(cd->mcodebase + bref->branchpos, 
-                                                         bref->branchpos,
-                                                         xcodeptr - cd->mcodebase - (5 + 6));
-                       continue;
-               }
-
                gen_resolvebranch(cd->mcodebase + bref->branchpos, 
                                                  bref->branchpos,
                                                  cd->mcodeptr - cd->mcodebase);
                
-               MCODECHECK(100);
+               MCODECHECK(512);
 
-               M_MOV_IMM(0, REG_ITMP2_XPC);                               /* 5 bytes */
+               M_MOV_IMM(0, REG_ITMP2_XPC);
                dseg_adddata(cd, cd->mcodeptr);
-               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);          /* 6 bytes */
+               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);
                
                if (xcodeptr != NULL) {
                        M_JMP_IMM((xcodeptr - cd->mcodeptr) - 5);
@@ -5354,22 +5330,15 @@ gen_method:
        xcodeptr = NULL;
        
        for (bref = cd->xexceptionrefs; bref != NULL; bref = bref->next) {
-               if ((cd->exceptiontablelength == 0) && (xcodeptr != NULL)) {
-                       gen_resolvebranch(cd->mcodebase + bref->branchpos,
-                                                         bref->branchpos,
-                                                         xcodeptr - cd->mcodebase - (5 + 6));
-                       continue;
-               }
-
                gen_resolvebranch(cd->mcodebase + bref->branchpos, 
                                  bref->branchpos,
                                                  cd->mcodeptr - cd->mcodebase);
 
-               MCODECHECK(100);
+               MCODECHECK(512);
 
-               M_MOV_IMM(0, REG_ITMP2_XPC);                               /* 5 bytes */
+               M_MOV_IMM(0, REG_ITMP2_XPC);
                dseg_adddata(cd, cd->mcodeptr);
-               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);          /* 6 bytes */
+               M_AADD_IMM32(bref->branchpos - 6, REG_ITMP2_XPC);
 
                if (xcodeptr != NULL) {
                        M_JMP_IMM((xcodeptr - cd->mcodeptr) - 5);
@@ -5411,7 +5380,7 @@ gen_method:
                for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
                        /* check code segment size */
 
-                       MCODECHECK(100);
+                       MCODECHECK(512);
 
                        /* Get machine code which is patched back in later. A             */
                        /* `call rel32' is 5 bytes long.                                  */
@@ -5452,6 +5421,10 @@ gen_method:
        }
        
        codegen_finish(m, cd, (ptrint) (cd->mcodeptr - cd->mcodebase));
+
+       /* everything's ok */
+
+       return true;
 }
 
 
@@ -5463,7 +5436,7 @@ gen_method:
 
 #define COMPILERSTUB_SIZE    12
 
-functionptr createcompilerstub(methodinfo *m)
+u1 *createcompilerstub(methodinfo *m)
 {
     u1          *s;                     /* memory to hold the stub            */
        codegendata *cd;
@@ -5493,7 +5466,7 @@ functionptr createcompilerstub(methodinfo *m)
 
        dump_release(dumpsize);
        
-    return (functionptr) (ptrint) s;
+    return s;
 }
 
 
@@ -5509,8 +5482,8 @@ functionptr createcompilerstub(methodinfo *m)
 static java_objectheader **(*callgetexceptionptrptr)() = builtin_get_exceptionptrptr;
 #endif
 
-functionptr createnativestub(functionptr f, methodinfo *m, codegendata *cd,
-                                                        registerdata *rd, methoddesc *nmd)
+u1 *createnativestub(functionptr f, methodinfo *m, codegendata *cd,
+                                        registerdata *rd, methoddesc *nmd)
 {
        methoddesc *md;
        s4          nativeparams;