Merged PR72 fix.
[cacao.git] / src / vm / jit / x86_64 / codegen.c
index b81fd9486ecc4f6fdfbd9ef92758e260cb925f5d..5ef87728158078f3e54854a7c9fbfb8702c79ba3 100644 (file)
@@ -2487,6 +2487,8 @@ gen_method:
                                classinfo *super;
                                s4         superindex;
 
+                               s4 looptarget;
+
                                if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                        super      = NULL;
                                        superindex = 0;
@@ -2496,9 +2498,6 @@ gen_method:
                                        superindex = super->index;
                                }
 
-                               if ((super == NULL) || !(super->flags & ACC_INTERFACE))
-                                       CODEGEN_CRITICAL_SECTION_NEW;
-
                                s1 = emit_load_s1(jd, iptr, REG_ITMP1);
 
                                /* if class is not resolved, check which code to call */
@@ -2571,34 +2570,67 @@ gen_method:
                                        M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
                                        M_ALD(REG_ITMP3, RIP, disp);
 
-                                       CODEGEN_CRITICAL_SECTION_START;
+                                       if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                                       M_AADD_IMM(-32, REG_SP); /* need some stack */
+                                       if (s1 == REG_ITMP1)
+                                               M_AST(REG_ITMP1, REG_SP, -8 + 32);
 
-                                       M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+                                       M_ALD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
 
-                                       /*                                      if (s1 != REG_ITMP1) { */
-                                       /*                                              emit_movl_membase_reg(cd, REG_ITMP3, */
-                                       /*                                                                                              OFFSET(vftbl_t, baseval), */
-                                       /*                                                                                              REG_ITMP1); */
-                                       /*                                              emit_movl_membase_reg(cd, REG_ITMP3, */
-                                       /*                                                                                              OFFSET(vftbl_t, diffval), */
-                                       /*                                                                                              REG_ITMP3); */
-                                       /*  #if defined(ENABLE_THREADS) */
-                                       /*                                              codegen_threadcritstop(cd, cd->mcodeptr - cd->mcodebase); */
-                                       /*  #endif */
-                                       /*                                              emit_alu_reg_reg(cd, ALU_SUB, REG_ITMP1, REG_ITMP2); */
+                                       *(cd->mcodeptr++) = 0x4d;
+                                       *(cd->mcodeptr++) = 0x3b;
+                                       *(cd->mcodeptr++) = 0x1c;
+                                       *(cd->mcodeptr++) = 0x02;
+                                       /* cmp (ITMP2, ITMP1, 1), ITMP3 */
 
-                                       /*                                      } else { */
+                                       emit_label_beq(cd, BRANCH_LABEL_6);  /* good */
 
-                                       M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
-                                       M_ISUB(REG_ITMP3, REG_ITMP2);
-                                       M_ALD(REG_ITMP3, RIP, disp);
-                                       M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
-                                       /*                                      } */
+                                       M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                                       emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+
+                                       M_AST(REG_ITMP3, REG_SP, -16 + 32);
+                                       M_AST_IMM32(0, REG_SP, -24 + 32);
+                                       M_ALD(REG_ITMP1, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                                       looptarget = cd->mcodeptr - cd->mcodebase;
+
+                                       M_ALD(REG_ITMP3, REG_SP, -24 + 32);
+                                       M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP3);
+                                       emit_label_bge(cd, BRANCH_LABEL_9);  /* throw */
+
+                                       *(cd->mcodeptr++) = 0x4e;
+                                       *(cd->mcodeptr++) = 0x8b;
+                                       *(cd->mcodeptr++) = 0x1c;
+                                       *(cd->mcodeptr++) = 0xd8;
+                                       /* movq (ITMP1, ITMP3, 8), ITMP3 */
 
-                                       CODEGEN_CRITICAL_SECTION_END;
+                                       M_LCMP_MEMBASE(REG_SP, -16 + 32, REG_ITMP3);
+                                       emit_label_beq(cd, BRANCH_LABEL_7);  /* good */
 
-                                       M_ICMP(REG_ITMP3, REG_ITMP2);
-                                       emit_classcast_check(cd, iptr, BRANCH_UGT, REG_ITMP3, s1);
+                                       M_LINC_MEMBASE(REG_SP, -24 + 32);
+                                       M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
+
+                                       emit_label(cd, BRANCH_LABEL_9);
+                                       M_AADD_IMM(32, REG_SP); /* restore stack frame */
+                                       M_ALD_MEM(REG_ITMP3, TRAP_ClassCastException);
+
+                                       emit_label(cd, BRANCH_LABEL_7);
+
+                                       emit_label(cd, BRANCH_LABEL_6);
+
+                                       if (s1 == REG_ITMP1)
+                                               M_ALD(REG_ITMP1, REG_SP, -8 + 32);
+                                       M_AADD_IMM(32, REG_SP);
+                                       }
+                                       else {
+                                               assert(super->vftbl->subtype_offset < 0x80);
+                                               *(cd->mcodeptr++) = 0x4d;
+                                               *(cd->mcodeptr++) = 0x3b;
+                                               *(cd->mcodeptr++) = 0x5a;
+                                               *(cd->mcodeptr++) = super->vftbl->subtype_offset;
+                                               /* cmp off(ITMP1), ITMP2 */
+
+                                               emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+                                       }
 
                                        if (super != NULL)
                                                emit_label(cd, BRANCH_LABEL_5);
@@ -2651,6 +2683,8 @@ gen_method:
                        classinfo *super;
                        s4         superindex;
 
+                       s4 looptarget;
+
                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                super      = NULL;
                                superindex = 0;
@@ -2660,9 +2694,6 @@ gen_method:
                                superindex = super->index;
                        }
 
-                       if ((super == NULL) || !(super->flags & ACC_INTERFACE))
-                               CODEGEN_CRITICAL_SECTION_NEW;
-
                        s1 = emit_load_s1(jd, iptr, REG_ITMP1);
                        d = codegen_reg_of_dst(jd, iptr, REG_ITMP2);
 
@@ -2741,21 +2772,82 @@ gen_method:
                                        disp = dseg_add_address(cd, super->vftbl);
                                }
 
-                               M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
-                               M_ALD(REG_ITMP2, RIP, disp);
-
-                               CODEGEN_CRITICAL_SECTION_START;
-
-                               M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
-                               M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, diffval));
-                               M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
-
-                               CODEGEN_CRITICAL_SECTION_END;
+                               M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
+                               M_ALD(REG_ITMP3, RIP, disp);
+
+                               if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+                               M_AADD_IMM(-32, REG_SP); /* need some stack */
+                               M_ALD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+
+                               *(cd->mcodeptr++) = 0x4d;
+                               *(cd->mcodeptr++) = 0x3b;
+                               *(cd->mcodeptr++) = 0x1c;
+                               *(cd->mcodeptr++) = 0x02;
+                               /* cmp (ITMP2, ITMP1, 1), ITMP3 */
+
+                               emit_label_bne(cd, BRANCH_LABEL_6);
+                               if (d == REG_ITMP2) {
+                                       M_SETE(d);
+                                       M_BSEXT(d, d);
+                               } else
+                                       M_LINC(d);
+                               emit_label_br(cd, BRANCH_LABEL_7);    /* done, true */
+
+                               emit_label(cd, BRANCH_LABEL_6);
+
+                               M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+                               emit_label_bne(cd, BRANCH_LABEL_6);   /* done, false */
+
+                               M_AST(REG_ITMP3, REG_SP, -16 + 32);
+                               M_AST_IMM32(0, REG_SP, -24 + 32);
+                               M_ALD(REG_ITMP1, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+                               looptarget = cd->mcodeptr - cd->mcodebase;
+
+                               M_ALD(REG_ITMP3, REG_SP, -24 + 32);
+                               M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP3);
+                               emit_label_bge(cd, BRANCH_LABEL_8);   /* done, false */
+
+                               *(cd->mcodeptr++) = 0x4e;
+                               *(cd->mcodeptr++) = 0x8b;
+                               *(cd->mcodeptr++) = 0x1c;
+                               *(cd->mcodeptr++) = 0xd8;
+                               /* movq (ITMP1, ITMP3, 8), ITMP3 */
+
+                               M_LCMP_MEMBASE(REG_SP, -16 + 32, REG_ITMP3);
+                               emit_label_bne(cd, BRANCH_LABEL_9);
+                               if (d == REG_ITMP2) {
+                                       M_SETE(d);
+                                       M_BSEXT(d, d);
+                               } else
+                                       M_LINC(d);
+                               emit_label_br(cd, BRANCH_LABEL_10);   /* done, true */
+                               emit_label(cd, BRANCH_LABEL_9);
+
+                               M_LINC_MEMBASE(REG_SP, -24 + 32);
+                               M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
+
+                               emit_label(cd, BRANCH_LABEL_8);
+                               emit_label(cd, BRANCH_LABEL_6);
+
+                               if (d == REG_ITMP2)
+                                       M_CLR(d);
 
-                               M_ISUB(REG_ITMP2, REG_ITMP1);
-                               M_CLR(d); /* may be REG_ITMP2 */
-                               M_ICMP(REG_ITMP3, REG_ITMP1);
-                               M_SETULE(d);
+                               emit_label(cd, BRANCH_LABEL_10);
+                               emit_label(cd, BRANCH_LABEL_7);
+                               M_AADD_IMM(32, REG_SP);
+                               }
+                               else {
+                                       assert(super->vftbl->subtype_offset < 0x80);
+                                       *(cd->mcodeptr++) = 0x4d;
+                                       *(cd->mcodeptr++) = 0x3b;
+                                       *(cd->mcodeptr++) = 0x5a;
+                                       *(cd->mcodeptr++) = super->vftbl->subtype_offset;
+                                       /* cmp off(ITMP1), ITMP2 */
+
+                                       M_SETE(d);
+                                       if (d == REG_ITMP2)
+                                               M_BSEXT(d, d);
+                               }
 
                                if (super != NULL)
                                        emit_label(cd, BRANCH_LABEL_5);