Merged subtype branch to new head.
[cacao.git] / src / vm / jit / x86_64 / codegen.c
index 900780064d5195e64c9dca785e6d992e903f5f44..379792aefff8e51fb69fb03beae4497f698b51e9 100644 (file)
@@ -2486,6 +2486,8 @@ gen_method:
                                classinfo *super;
                                s4         superindex;
 
+                               s4 looptarget;
+
                                if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                        super      = NULL;
                                        superindex = 0;
@@ -2567,30 +2569,67 @@ gen_method:
                                        M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
                                        M_ALD(REG_ITMP3, RIP, disp);
 
-                                       M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+                                       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);
 
-                                       /*                                      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); */
+                                       M_ALD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
 
-                                       /*                                      } else { */
+                                       *(cd->mcodeptr++) = 0x4d;
+                                       *(cd->mcodeptr++) = 0x3b;
+                                       *(cd->mcodeptr++) = 0x1c;
+                                       *(cd->mcodeptr++) = 0x02;
+                                       /* cmp (ITMP2, ITMP1, 1), ITMP3 */
 
-                                       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));
-                                       /*                                      } */
+                                       emit_label_beq(cd, BRANCH_LABEL_6); /* good */
+
+                                       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 */
+
+                                       M_LCMP_MEMBASE(REG_SP, -16 + 32, REG_ITMP3);
+                                       emit_label_beq(cd, BRANCH_LABEL_7); /* good, pop */
+
+                                       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);
 
-                                       M_ICMP(REG_ITMP3, REG_ITMP2);
-                                       emit_classcast_check(cd, iptr, BRANCH_UGT, REG_ITMP3, s1);
+                                       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);
@@ -2643,6 +2682,8 @@ gen_method:
                        classinfo *super;
                        s4         superindex;
 
+                       s4 looptarget;
+
                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                super      = NULL;
                                superindex = 0;
@@ -2730,17 +2771,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);
-
-                               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));
+                               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); /* ende 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); /* ende 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); /* ende 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); /* ende 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);