if (sub->flags & ACC_INTERFACE)
return (super == class_java_lang_Object);
- linker_classrenumber_mutex->lock();
+#if USES_NEW_SUBTYPE
+ result = fast_subtype_check(sub->vftbl, super->vftbl);
+#else
+ LOCK_CLASSRENUMBER_LOCK;
diffval = sub->vftbl->baseval - super->vftbl->baseval;
result = diffval <= (uint32_t) super->vftbl->diffval;
- linker_classrenumber_mutex->unlock();
+ UNLOCK_CLASSRENUMBER_LOCK;
+#endif
}
return result;
#define REPLACEMENT_PATCH_SIZE 4 /* bytes */
+/* subtype ********************************************************************/
+
+#define USES_NEW_SUBTYPE 1
+
#endif /* _ARCH_H */
M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
M_ALD(REG_ITMP3, REG_PV, disp);
- M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
- /* if (s1 != REG_ITMP1) { */
- /* M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, baseval)); */
- /* M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval)); */
- /* #if defined(ENABLE_THREADS) */
- /* codegen_threadcritstop(cd, (u1 *) mcodeptr - cd->mcodebase); */
- /* #endif */
- /* M_ISUB(REG_ITMP2, REG_ITMP1, REG_ITMP2); */
-
- /* } else { */
- M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
- M_ISUB(REG_ITMP2, REG_ITMP3, REG_ITMP2);
- M_ALD(REG_ITMP3, REG_PV, disp);
- M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
-
- /* } */
- M_CMPULE(REG_ITMP2, REG_ITMP3, REG_ITMP3);
- emit_classcast_check(cd, iptr, BRANCH_EQ, REG_ITMP3, s1);
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_LADD(REG_ITMP1, REG_ITMP2, REG_ITMP1);
+ M_ALD(REG_ITMP1, REG_ITMP1, 0);
+ M_CMPEQ(REG_ITMP1, REG_ITMP3, REG_ITMP1);
+ emit_label_bnez(cd, BRANCH_LABEL_6, REG_ITMP1); /* good */
+
+ if (super == NULL) {
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_CMPEQ_IMM(REG_ITMP1, OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_label_beqz(cd, BRANCH_LABEL_10, REG_ITMP1); /* throw */
+ }
+
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+ M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_depth));
+ M_CMPLE(REG_ITMP1, REG_ITMP3, REG_ITMP3);
+ emit_label_beqz(cd, BRANCH_LABEL_9, REG_ITMP3); /* throw */
+ /* reload */
+ M_ALD(REG_ITMP3, REG_PV, disp);
+ M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ M_S8ADDQ(REG_ITMP1, REG_ITMP2, REG_ITMP2);
+ M_ALD(REG_ITMP1, REG_ITMP2, -DISPLAY_SIZE*8);
+ M_CMPEQ(REG_ITMP1, REG_ITMP3, REG_ITMP1);
+ emit_label_bnez(cd, BRANCH_LABEL_7, REG_ITMP1); /* good */
+
+ emit_label(cd, BRANCH_LABEL_9);
+ if (super == NULL)
+ emit_label(cd, BRANCH_LABEL_10);
+
+ /* reload s1, might have been destroyed */
+ emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ALD_INTERN(s1, REG_ZERO, TRAP_ClassCastException);
+
+ emit_label(cd, BRANCH_LABEL_7);
+ emit_label(cd, BRANCH_LABEL_6);
+ /* reload s1, might have been destroyed */
+ emit_load_s1(jd, iptr, REG_ITMP1);
+ }
+ else {
+ M_ALD(REG_ITMP2, REG_ITMP2, super->vftbl->subtype_offset);
+ M_CMPEQ(REG_ITMP2, REG_ITMP3, REG_ITMP2);
+ emit_classcast_check(cd, iptr, BRANCH_EQ, REG_ITMP2, s1);
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
emit_label_beqz(cd, BRANCH_LABEL_5, s1);
}
- M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
- M_ALD(REG_ITMP2, REG_PV, disp);
+ M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
+ M_ALD(REG_ITMP3, REG_PV, disp);
+
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_LADD(REG_ITMP1, REG_ITMP2, REG_ITMP1);
+ M_ALD(REG_ITMP1, REG_ITMP1, 0);
+ M_CMPEQ(REG_ITMP1, REG_ITMP3, REG_ITMP1);
+ emit_label_beqz(cd, BRANCH_LABEL_8, REG_ITMP1);
+ ICONST(d, 1);
+ emit_label_br(cd, BRANCH_LABEL_6); /* true */
+ emit_label(cd, BRANCH_LABEL_8);
+
+ if (super == NULL) {
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_CMPEQ_IMM(REG_ITMP1, OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_label_beqz(cd, BRANCH_LABEL_10, REG_ITMP1); /* false */
+ }
- M_ILD(REG_ITMP1, REG_ITMP1, OFFSET(vftbl_t, baseval));
- M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, baseval));
- M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, diffval));
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
- M_ISUB(REG_ITMP1, REG_ITMP3, REG_ITMP1);
- M_CMPULE(REG_ITMP1, REG_ITMP2, d);
+ M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_depth));
+ M_CMPLE(REG_ITMP1, REG_ITMP3, REG_ITMP3);
+ emit_label_beqz(cd, BRANCH_LABEL_9, REG_ITMP3); /* false */
+ /* reload */
+ M_ALD(REG_ITMP3, REG_PV, disp);
+ M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ M_S8ADDQ(REG_ITMP1, REG_ITMP2, REG_ITMP2);
+ M_ALD(REG_ITMP1, REG_ITMP2, -DISPLAY_SIZE*8);
+ M_CMPEQ(REG_ITMP1, REG_ITMP3, d);
+
+ if (d == REG_ITMP2)
+ emit_label_br(cd, BRANCH_LABEL_7);
+ emit_label(cd, BRANCH_LABEL_9);
+ if (super == NULL)
+ emit_label(cd, BRANCH_LABEL_10);
+ if (d == REG_ITMP2) {
+ M_CLR(d);
+
+ emit_label(cd, BRANCH_LABEL_7);
+ }
+ emit_label(cd, BRANCH_LABEL_6);
+ }
+ else {
+ M_ALD(REG_ITMP2, REG_ITMP2, super->vftbl->subtype_offset);
+ M_CMPEQ(REG_ITMP2, REG_ITMP3, d);
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
return result;
}
+#if USES_NEW_SUBTYPE
+/* fast_subtype_check **********************************************************
+
+ Checks if s is a subtype of t, using both the restricted subtype relation
+ and the overflow array (see Cliff Click and John Rose: Fast subtype checking
+ in the Hotspot JVM.)
+
+ RETURN VALUE:
+ 1......s is a subtype of t.
+ 0......otherwise
+
+*******************************************************************************/
+
+bool fast_subtype_check(struct _vftbl *s, struct _vftbl *t)
+{
+ if (s->subtype_display[t->subtype_depth] == t)
+ return true;
+ if (t->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]))
+ return false;
+ return s->subtype_depth >= t->subtype_depth && s->subtype_overflow[t->subtype_depth - DISPLAY_SIZE] == t;
+}
+#endif
/* builtin_fast_canstore *******************************************************
if (valuevftbl == componentvftbl)
return 1;
- linker_classrenumber_mutex->lock();
+ LOCK_CLASSRENUMBER_LOCK;
baseval = componentvftbl->baseval;
(valuevftbl->interfacetable[baseval] != NULL));
}
else {
+#if USES_NEW_SUBTYPE
+ result = fast_subtype_check(valuevftbl, componentvftbl);
+#else
diffval = valuevftbl->baseval - componentvftbl->baseval;
result = diffval <= (uint32_t) componentvftbl->diffval;
+#endif
}
- linker_classrenumber_mutex->unlock();
+ UNLOCK_CLASSRENUMBER_LOCK;
}
else if (valuedesc == NULL) {
/* {oa has dimension > 1} */
if (valuevftbl == elementvftbl)
return 1;
- linker_classrenumber_mutex->lock();
+ LOCK_CLASSRENUMBER_LOCK;
baseval = elementvftbl->baseval;
(valuevftbl->interfacetable[baseval] != NULL));
}
else {
+#if USES_NEW_SUBTYPE
+ result = fast_subtype_check(valuevftbl, elementvftbl);
+#else
diffval = valuevftbl->baseval - elementvftbl->baseval;
result = diffval <= (uint32_t) elementvftbl->diffval;
+#endif
}
- linker_classrenumber_mutex->unlock();
+ UNLOCK_CLASSRENUMBER_LOCK;
return result;
}
if (valuevftbl == elementvftbl)
return 1;
- linker_classrenumber_mutex->lock();
+ LOCK_CLASSRENUMBER_LOCK;
+#if USES_NEW_SUBTYPE
+ result = fast_subtype_check(valuevftbl, elementvftbl);
+#else
diffval = valuevftbl->baseval - elementvftbl->baseval;
result = diffval <= (uint32_t) elementvftbl->diffval;
+#endif
- linker_classrenumber_mutex->unlock();
+ UNLOCK_CLASSRENUMBER_LOCK;
return result;
}
* ICMD_BUILTIN3.)
*/
+#if USES_NEW_SUBTYPE
+bool fast_subtype_check(struct _vftbl *, struct _vftbl *);
+#endif
+
bool builtin_instanceof(java_handle_t *obj, classinfo *c);
/* NOT AN OP */
bool builtin_checkcast(java_handle_t *obj, classinfo *c);
#define BRANCH_LABEL_4 4
#define BRANCH_LABEL_5 5
#define BRANCH_LABEL_6 6
+#define BRANCH_LABEL_7 7
+#define BRANCH_LABEL_8 8
+#define BRANCH_LABEL_9 9
+#define BRANCH_LABEL_10 10
/* constant range macros ******************************************************/
#define REPLACEMENT_PATCH_SIZE 2 /* bytes */
+/* subtype ********************************************************************/
+
+#define USES_NEW_SUBTYPE 1
+
#endif /* _ARCH_H */
}
M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
-
if (super == NULL) {
patcher_add_patch_ref(jd, PATCHER_checkcast_class,
iptr->sx.s23.s3.c.ref,
0);
}
-
M_MOV_IMM(supervftbl, REG_ITMP3);
- M_ILD32(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_CMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+ emit_label_beq(cd, BRANCH_LABEL_6); /* good */
- /* if (s1 != REG_ITMP1) { */
- /* emit_mov_membase_reg(cd, REG_ITMP3, OFFSET(vftbl_t, baseval), REG_ITMP1); */
- /* emit_mov_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); */
+ if (super == NULL) {
+ M_ICMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_label_bne(cd, BRANCH_LABEL_10); /* throw */
+ }
- /* } else { */
- M_ILD32(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, baseval));
- M_ISUB(REG_ITMP3, REG_ITMP2);
- M_MOV_IMM(supervftbl, REG_ITMP3);
- M_ILD(REG_ITMP3, REG_ITMP3, OFFSET(vftbl_t, diffval));
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+ M_CMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+ emit_label_bgt(cd, BRANCH_LABEL_9); /* throw */
- /* } */
+ M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ M_CMP_MEMINDEX(REG_ITMP2, -4*DISPLAY_SIZE, REG_ITMP1, 2, REG_ITMP3);
+ emit_label_beq(cd, BRANCH_LABEL_7); /* good */
+
+ emit_label(cd, BRANCH_LABEL_9);
+ if (super == NULL)
+ emit_label(cd, BRANCH_LABEL_10);
+
+ /* reload s1, might have been destroyed */
+ emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ALD_MEM(s1, TRAP_ClassCastException);
+
+ emit_label(cd, BRANCH_LABEL_7);
+ emit_label(cd, BRANCH_LABEL_6);
+ /* reload s1, might have been destroyed */
+ emit_load_s1(jd, iptr, REG_ITMP1);
+ }
+ else {
+ M_CMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
- M_CMP(REG_ITMP3, REG_ITMP2);
- emit_classcast_check(cd, iptr, BRANCH_ULE, REG_ITMP3, s1);
+ emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
emit_label_beq(cd, BRANCH_LABEL_5);
}
- M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
-
+ M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
if (super == NULL) {
patcher_add_patch_ref(jd, PATCHER_instanceof_class,
iptr->sx.s23.s3.c.ref, 0);
}
+ M_MOV_IMM(supervftbl, REG_ITMP3);
+
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_CMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_8); /* jump over INC/SETE */
+ if (d == REG_ITMP2) {
+ M_SETE(d);
+ M_BSEXT(d, d);
+ } else
+ M_IINC(d);
+ emit_label_br(cd, BRANCH_LABEL_6); /* true */
+ emit_label(cd, BRANCH_LABEL_8);
- M_MOV_IMM(supervftbl, REG_ITMP2);
+ if (super == NULL) {
+ M_ICMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_label_bne(cd, BRANCH_LABEL_10); /* false */
+ }
- 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_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+ M_CMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+ emit_label_bgt(cd, BRANCH_LABEL_9); /* false */
- M_ISUB(REG_ITMP2, REG_ITMP1);
- M_CLR(d); /* may be REG_ITMP2 */
- M_CMP(REG_ITMP3, REG_ITMP1);
- M_BA(5);
- M_MOV_IMM(1, d);
+ M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ M_CMP_MEMINDEX(REG_ITMP2, -4*DISPLAY_SIZE, REG_ITMP1, 2, REG_ITMP3);
+ if (d >= 4) {
+ M_SETE(REG_ITMP1);
+ M_BSEXT(REG_ITMP1, d);
+ }
+ else {
+ M_SETE(d);
+ if (d == REG_ITMP2) {
+ M_BSEXT(d, d);
+
+ emit_label_br(cd, BRANCH_LABEL_7); /* jump over M_CLR */
+ }
+ }
+
+ emit_label(cd, BRANCH_LABEL_9);
+ if (super == NULL)
+ emit_label(cd, BRANCH_LABEL_10);
+ if (d == REG_ITMP2) {
+ M_CLR(d);
+
+ emit_label(cd, BRANCH_LABEL_7);
+ }
+ emit_label(cd, BRANCH_LABEL_6);
+ }
+ else {
+ M_CMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
+
+ if (d >= 4) {
+ M_SETE(REG_ITMP1);
+ M_BSEXT(REG_ITMP1, d);
+ }
+ else {
+ M_SETE(d);
+ if (d == REG_ITMP2)
+ M_BSEXT(d, d);
+ }
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
#define M_ISUB_IMM_MEMABS(a,b) emit_alu_imm_memabs(cd, ALU_SUB, (a), (b))
+#define M_IINC(a) emit_inc_reg(cd, (a))
+
#define M_IADDC(a,b) emit_alu_reg_reg(cd, ALU_ADC, (a), (b))
#define M_ISUBB(a,b) emit_alu_reg_reg(cd, ALU_SBB, (a), (b))
#define M_CMP(a,b) emit_alu_reg_reg(cd, ALU_CMP, (a), (b))
#define M_CMP_MEMBASE(a,b,c) emit_alu_membase_reg(cd, ALU_CMP, (a), (b), (c))
+#define M_CMP_MEMINDEX(a,b,c,d,e) emit_alu_memindex_reg(cd, ALU_CMP, (b), (a), (c), (d), (e))
#define M_CMP_IMM(a,b) emit_alu_imm_reg(cd, ALU_CMP, (a), (b))
#define M_CMP_IMM_MEMBASE(a,b,c) emit_alu_imm_membase(cd, ALU_CMP, (a), (b), (c))
#define M_CALL_IMM(a) emit_call_imm(cd, (a))
#define M_RET M_BYTE1(0xc3)
+#define M_ICMP_IMM(a,b) emit_alu_imm_reg(cd, ALU_CMP, (a), (b))
+
#define M_BEQ(a) emit_jcc(cd, CC_E, (a))
#define M_BNE(a) emit_jcc(cd, CC_NE, (a))
#define M_BLT(a) emit_jcc(cd, CC_L, (a))
#define M_BNS(a) emit_jcc(cd, CC_NS, (a))
#define M_BS(a) emit_jcc(cd, CC_S, (a))
+#define M_SETE(a) emit_setcc_reg(cd, CC_E, (a))
+
#define M_JMP(a) emit_jmp_reg(cd, (a))
#define M_JMP_IMM(a) emit_jmp_imm(cd, (a))
case BRANCH_LE:
M_BGT(6);
break;
+ case BRANCH_GE:
+ M_BLT(6);
+ break;
case BRANCH_EQ:
M_BNE(6);
break;
+ case BRANCH_NE:
+ M_BEQ(6);
+ break;
case BRANCH_ULE:
M_BBE(6);
break;
}
}
+void emit_alu_memindex_reg(codegendata *cd, s4 opc, s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg)
+{
+ *(cd->mcodeptr++) = (((u1) (opc)) << 3) + 3;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
void emit_test_reg_reg(codegendata *cd, s4 reg, s4 dreg)
{
/*
* inc, dec operations
*/
+void emit_inc_reg(codegendata *cd, s4 reg)
+{
+ *(cd->mcodeptr++) = 0xff;
+ emit_reg(0,(reg));
+}
+
void emit_dec_mem(codegendata *cd, s4 mem)
{
*(cd->mcodeptr++) = 0xff;
*/
void emit_setcc_reg(codegendata *cd, s4 opc, s4 reg)
{
+ assert(reg < 4); /* Can only operate on al, bl, cl, dl. */
*(cd->mcodeptr++) = 0x0f;
*(cd->mcodeptr++) = 0x90 + (u1) (opc);
emit_reg(0,(reg));
void emit_alu_imm32_reg(codegendata *cd, s4 opc, s4 imm, s4 reg);
void emit_alu_imm_membase(codegendata *cd, s4 opc, s4 imm, s4 basereg, s4 disp);
void emit_alu_imm_memabs(codegendata *cd, s4 opc, s4 imm, s4 disp);
+void emit_alu_memindex_reg(codegendata *cd, s4 opc, s4 disp, s4 basereg, s4 indexreg, s4 scale, s4 reg);
+void emit_inc_reg(codegendata *cd, s4 reg);
void emit_test_reg_reg(codegendata *cd, s4 reg, s4 dreg);
void emit_test_imm_reg(codegendata *cd, s4 imm, s4 dreg);
void emit_dec_mem(codegendata *cd, s4 mem);
/* patch super class' vftbl */
*((ptrint *) (ra + 1)) = (ptrint) c->vftbl;
- *((ptrint *) (ra + 5 + 6 + 6 + 2 + 1)) = (ptrint) c->vftbl;
return true;
}
#define REPLACEMENT_PATCH_SIZE 2 /* bytes */
+/* subtype ********************************************************************/
+
+#define USES_NEW_SUBTYPE 1
+
#endif /* _ARCH_H */
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 (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); */
-
- /* } else { */
-
- 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_ICMP(REG_ITMP3, REG_ITMP2);
- emit_classcast_check(cd, iptr, BRANCH_UGT, REG_ITMP3, s1);
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_LCMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+ emit_label_beq(cd, BRANCH_LABEL_6); /* good */
+
+ if (super == NULL) {
+ M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_label_bne(cd, BRANCH_LABEL_10); /* throw */
+ }
+
+ M_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+ M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+ emit_label_bgt(cd, BRANCH_LABEL_9); /* throw */
+
+ M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ M_LCMP_MEMINDEX(REG_ITMP2, -8*DISPLAY_SIZE, REG_ITMP1, 3, REG_ITMP3);
+ emit_label_beq(cd, BRANCH_LABEL_7); /* good */
+
+ emit_label(cd, BRANCH_LABEL_9);
+ if (super == NULL)
+ emit_label(cd, BRANCH_LABEL_10);
+
+ /* reload s1, might have been destroyed */
+ emit_load_s1(jd, iptr, REG_ITMP1);
+ M_ALD_MEM(s1, TRAP_ClassCastException);
+
+ emit_label(cd, BRANCH_LABEL_7);
+ emit_label(cd, BRANCH_LABEL_6);
+ /* reload s1, might have been destroyed */
+ emit_load_s1(jd, iptr, REG_ITMP1);
+ }
+ else {
+ M_LCMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
+ emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
disp = dseg_add_address(cd, super->vftbl);
}
- M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
- M_ALD(REG_ITMP2, RIP, disp);
+ 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_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_offset));
+ M_LCMP_MEMINDEX(REG_ITMP2, 0, REG_ITMP1, 0, REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_8); /* jump over INC/SETE */
+ if (d == REG_ITMP2) {
+ M_SETE(d);
+ M_BSEXT(d, d);
+ } else
+ M_LINC(d);
+ emit_label_br(cd, BRANCH_LABEL_6); /* true */
+ emit_label(cd, BRANCH_LABEL_8);
+
+ if (super == NULL) {
+ M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP1);
+ emit_label_bne(cd, BRANCH_LABEL_10); /* false */
+ }
- 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_ILD(REG_ITMP1, REG_ITMP3, OFFSET(vftbl_t, subtype_depth));
+ M_ICMP_MEMBASE(REG_ITMP2, OFFSET(vftbl_t, subtype_depth), REG_ITMP1);
+ emit_label_bgt(cd, BRANCH_LABEL_9); /* false */
- M_ISUB(REG_ITMP2, REG_ITMP1);
- M_CLR(d); /* may be REG_ITMP2 */
- M_ICMP(REG_ITMP3, REG_ITMP1);
- M_SETULE(d);
+ M_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ M_LCMP_MEMINDEX(REG_ITMP2, -8*DISPLAY_SIZE, REG_ITMP1, 3, REG_ITMP3);
+ M_SETE(d);
+ if (d == REG_ITMP2) {
+ M_BSEXT(d, d);
+
+ emit_label_br(cd, BRANCH_LABEL_7); /* jump over M_CLR */
+ }
+
+ emit_label(cd, BRANCH_LABEL_9);
+ if (super == NULL)
+ emit_label(cd, BRANCH_LABEL_10);
+ if (d == REG_ITMP2) {
+ M_CLR(d);
+
+ emit_label(cd, BRANCH_LABEL_7);
+ }
+ emit_label(cd, BRANCH_LABEL_6);
+ }
+ else {
+ M_LCMP_MEMBASE(REG_ITMP2, super->vftbl->subtype_offset, REG_ITMP3);
+ M_SETE(d);
+ if (d == REG_ITMP2)
+ M_BSEXT(d, d);
+ }
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
#define M_LMUL_IMM(a,b,c) emit_imul_imm_reg_reg(cd, (b), (a), (c))
#define M_IINC(a) emit_incl_reg(cd, (a))
+#define M_LINC(a) emit_incq_reg(cd, (a))
#define M_IDEC(a) emit_decl_reg(cd, (a))
#define M_ALD(a,b,disp) \
#define M_LCMP_IMM(a,b) emit_alu_imm_reg(cd, ALU_CMP, (a), (b))
#define M_LCMP_IMM_MEMBASE(a,b,c) emit_alu_imm_membase(cd, ALU_CMP, (a), (b), (c))
#define M_LCMP_MEMBASE(a,b,c) emit_alu_membase_reg(cd, ALU_CMP, (a), (b), (c))
+#define M_LCMP_MEMINDEX(a,b,c,d,e) emit_alul_memindex_reg(cd, ALU_CMP, (b), (a), (c), (d), (e))
#define M_ICMP(a,b) emit_alul_reg_reg(cd, ALU_CMP, (a), (b))
#define M_ICMP_IMM(a,b) emit_alul_imm_reg(cd, ALU_CMP, (a), (b))
#define M_ICMP_IMM32(a,b) emit_alul_imm32_reg(cd, ALU_CMP, (a), (b))
#define M_ICMP_IMM_MEMBASE(a,b,c) emit_alul_imm_membase(cd, ALU_CMP, (a), (b), (c))
#define M_ICMP_MEMBASE(a,b,c) emit_alul_membase_reg(cd, ALU_CMP, (a), (b), (c))
+#define M_ICMP_MEMINDEX(a,b,c,d,e) emit_alu_memindex_reg(cd, ALU_CMP, (b), (a), (c), (d), (e))
#define M_BEQ(disp) emit_jcc(cd, CC_E, (disp))
#define M_BNE(disp) emit_jcc(cd, CC_NE, (disp))
#define M_BUGE(disp) emit_jcc(cd, CC_AE, (disp))
#define M_BUGT(disp) emit_jcc(cd, CC_A, (disp))
+#define M_SETE(a) emit_setcc_reg(cd, CC_E, (a))
#define M_SETNE(a) emit_setcc_reg(cd, CC_NE, (a))
#define M_SETULE(a) emit_setcc_reg(cd, CC_BE, (a))
#define M_JMP(a) emit_jmp_reg(cd, (a))
#define M_JMP_IMM(a) emit_jmp_imm(cd, (a))
+#define M_JMP_IMM2(a) emit_jmp_imm2(cd, (a))
#define M_CALL(a) emit_call_reg(cd, (a))
#define M_CALL_IMM(a) emit_call_imm(cd, (a))
#define M_RET M_BYTE1(0xc3)
#define M_RDTSC emit_rdtsc(cd)
#define M_IINC_MEMBASE(a,b) emit_incl_membase(cd, (a), (b))
+#define M_LINC_MEMBASE(a,b) emit_incq_membase(cd, (a), (b))
#define M_IADD_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_ADD, (a), (b), (c))
#define M_IADC_MEMBASE(a,b,c) emit_alul_reg_membase(cd, ALU_ADC, (a), (b), (c))
case BRANCH_LE:
M_BGT(8);
break;
+ case BRANCH_GE:
+ M_BLT(8);
+ break;
case BRANCH_EQ:
M_BNE(8);
break;
+ case BRANCH_NE:
+ M_BEQ(8);
+ break;
case BRANCH_UGT:
M_BULE(8);
break;
}
}
+void emit_alu_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg)
+{
+ emit_rex(1,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 3;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
+
+void emit_alul_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg)
+{
+ emit_rex(0,(reg),(indexreg),(basereg));
+ *(cd->mcodeptr++) = (((opc)) << 3) + 3;
+ emit_memindex(cd, (reg),(disp),(basereg),(indexreg),(scale));
+}
void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
emit_rex(1,(reg),0,(dreg));
}
+void emit_incl_reg(codegendata *cd, s8 reg)
+{
+ *(cd->mcodeptr++) = 0xff;
+ emit_reg(0,(reg));
+}
+
+void emit_incq_reg(codegendata *cd, s8 reg)
+{
+ emit_rex(1,0,0,(reg));
+ *(cd->mcodeptr++) = 0xff;
+ emit_reg(0,(reg));
+}
void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp)
{
emit_membase(cd, (basereg),(disp),0);
}
+void emit_incq_membase(codegendata *cd, s8 basereg, s8 disp)
+{
+ emit_rex(1,0,0,(basereg));
+ *(cd->mcodeptr++) = 0xff;
+ emit_membase(cd, (basereg),(disp),0);
+}
+
void emit_cltd(codegendata *cd) {
emit_imm32((imm));
}
+/* like emit_jmp_imm but allows 8 bit optimization */
+void emit_jmp_imm2(codegendata *cd, s8 imm) {
+ if (IS_IMM8(imm)) {
+ *(cd->mcodeptr++) = 0xeb;
+ emit_imm8((imm));
+ }
+ else {
+ *(cd->mcodeptr++) = 0xe9;
+ emit_imm32((imm));
+ }
+}
+
void emit_jmp_reg(codegendata *cd, s8 reg) {
emit_rex(0,0,0,(reg));
void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg);
void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp);
void emit_alul_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp);
+void emit_alu_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg);
+void emit_alul_memindex_reg(codegendata *cd, s8 opc, s8 disp, s8 basereg, s8 indexreg, s8 scale, s8 reg);
void emit_test_reg_reg(codegendata *cd, s8 reg, s8 dreg);
void emit_testl_reg_reg(codegendata *cd, s8 reg, s8 dreg);
void emit_test_imm_reg(codegendata *cd, s8 imm, s8 reg);
void emit_lea_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
void emit_leal_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg);
+void emit_incl_reg(codegendata *cd, s8 reg);
+void emit_incq_reg(codegendata *cd, s8 reg);
void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp);
+void emit_incq_membase(codegendata *cd, s8 basereg, s8 disp);
void emit_cltd(codegendata *cd);
void emit_cqto(codegendata *cd);
static s4 interfaceindex; /* sequential numbering of interfaces */
static s4 classvalue;
-Mutex *linker_classrenumber_mutex;
+#if !USES_NEW_SUBTYPE
+Mutex *linker_classrenumber_lock;
+#endif
#if defined(__cplusplus)
extern "C" {
interfaceindex = 0;
-#if defined(ENABLE_THREADS)
+#if defined(ENABLE_THREADS) && !USES_NEW_SUBTYPE
/* create the global mutex */
- linker_classrenumber_mutex = new Mutex();
+ linker_classrenumber_lock = new Mutex();
#endif
/* Link the most basic classes. */
}
+#if USES_NEW_SUBTYPE
+/* build_display ***************************************************************
+
+ Builds the entire display for a class. This entails filling the fixed part
+ as well as allocating and initializing the overflow part.
+
+ See Cliff Click and John Rose: Fast subtype checking in the Hotspot JVM.
+
+*******************************************************************************/
+
+static classinfo *build_display(classinfo *c)
+{
+ int depth, i;
+ int depth_fixed;
+ classinfo *super;
+
+ do {
+ /* Handle arrays. */
+ if (c->vftbl->arraydesc) {
+ arraydescriptor *a = c->vftbl->arraydesc;
+ if (a->elementvftbl && a->elementvftbl->clazz->super) {
+ classinfo *cls = a->elementvftbl->clazz->super;
+ int n;
+ for (n=0; n<a->dimension; n++)
+ cls = class_array_of(cls, true);
+ super = cls;
+ break;
+ }
+ if (a->componentvftbl && a->elementvftbl) {
+ super = a->componentvftbl->clazz;
+ break;
+ }
+ }
+ /* Normal classes. */
+ super = c->super;
+ } while (false);
+ if (super) {
+ if (!link_class(super))
+ return NULL;
+ depth = super->vftbl->subtype_depth + 1;
+ } else
+ /* java.lang.Object doesn't have a super class. */
+ depth = 0;
+
+ /* Now copy super's display, append c->vftbl and initialize the remaining fields. */
+ if (depth >= DISPLAY_SIZE) {
+ c->vftbl->subtype_overflow = MNEW(vftbl_t *, depth - DISPLAY_SIZE + 1);
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ count_vftbl_len += sizeof(vftbl_t*) * (depth - DISPLAY_SIZE + 1);
+#endif
+ memcpy(c->vftbl->subtype_overflow, super->vftbl->subtype_overflow, sizeof(vftbl_t*) * (depth - DISPLAY_SIZE));
+ c->vftbl->subtype_overflow[depth - DISPLAY_SIZE] = c->vftbl;
+ depth_fixed = DISPLAY_SIZE;
+ }
+ else {
+ depth_fixed = depth;
+ c->vftbl->subtype_display[depth] = c->vftbl;
+ }
+
+ if (super)
+ memcpy(c->vftbl->subtype_display, super->vftbl->subtype_display, sizeof(vftbl_t*) * depth_fixed);
+ for (i=depth_fixed+1; i<=DISPLAY_SIZE; i++)
+ c->vftbl->subtype_display[i] = NULL;
+ c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[0]) + sizeof(vftbl_t*) * depth_fixed;
+ c->vftbl->subtype_depth = depth;
+
+ return c;
+}
+#endif
+
/* link_class_intern ***********************************************************
Tries to link a class. The function calculates the length in bytes
linker_compute_subclasses(c);
+ /* FIXME: this is completely useless now */
RT_TIMING_GET_TIME(time_subclasses);
+#if USES_NEW_SUBTYPE
+ if (!build_display(c))
+ return NULL;
+#endif
+
/* revert the linking state and class is linked */
c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED;
static void linker_compute_subclasses(classinfo *c)
{
- linker_classrenumber_mutex->lock();
+
+ LOCK_CLASSRENUMBER_LOCK;
if (!(c->flags & ACC_INTERFACE)) {
c->nextsub = NULL;
c->sub = NULL;
+#if USES_NEW_SUBTYPE
+ c->vftbl->baseval = 1; /* so it does not look like an interface */
+#endif
}
if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) {
classvalue = 0;
+#if !USES_NEW_SUBTYPE
/* compute class values */
linker_compute_class_values(class_java_lang_Object);
+#endif
+
+ UNLOCK_CLASSRENUMBER_LOCK;
- linker_classrenumber_mutex->unlock();
}
/* This lock must be taken while renumbering classes or while atomically */
/* accessing classes. */
-extern Mutex *linker_classrenumber_mutex;
+#if USES_NEW_SUBTYPE
+
+#define LOCK_CLASSRENUMBER_LOCK /* nothing */
+#define UNLOCK_CLASSRENUMBER_LOCK /* nothing */
+
+#else
+extern Mutex *linker_classrenumber_lock;
+
+#define LOCK_CLASSRENUMBER_LOCK linker_classrenumber_lock->lock()
+#define UNLOCK_CLASSRENUMBER_LOCK linker_classrenumber_lock->unlock()
+
+#endif
/* function prototypes ********************************************************/
#include "vm/class.hpp"
#include "vm/references.h"
+#if USES_NEW_SUBTYPE
+#define DISPLAY_SIZE 4
+#endif
+
struct _vftbl {
methodptr *interfacetable[1]; /* interface table (access via macro) */
classinfo *clazz; /* class, the vtbl belongs to */
s4 baseval; /* base for runtime type check */
/* (-index for interfaces) */
s4 diffval; /* high - base for runtime type check */
+
+#if USES_NEW_SUBTYPE
+ s4 subtype_depth;
+ s4 subtype_offset;
+ struct _vftbl *subtype_display[DISPLAY_SIZE+1]; /* the last one is cache */
+ struct _vftbl **subtype_overflow;
+#endif
+
s4 *interfacevftbllength; /* length of interface vftbls */
methodptr table[1]; /* class vftbl */
};