if (sub->flags & ACC_INTERFACE)
return (super == class_java_lang_Object);
- linker_classrenumber_mutex->lock();
-
- diffval = sub->vftbl->baseval - super->vftbl->baseval;
- result = diffval <= (uint32_t) super->vftbl->diffval;
-
- linker_classrenumber_mutex->unlock();
+ result = fast_subtype_check(sub->vftbl, super->vftbl);
}
return result;
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);
*******************************************************************************/
+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;
+}
+
bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o)
{
arraydescriptor *desc;
if (valuevftbl == componentvftbl)
return 1;
- linker_classrenumber_mutex->lock();
-
baseval = componentvftbl->baseval;
if (baseval <= 0) {
(valuevftbl->interfacetable[baseval] != NULL));
}
else {
- diffval = valuevftbl->baseval - componentvftbl->baseval;
- result = diffval <= (uint32_t) componentvftbl->diffval;
+ result = fast_subtype_check(valuevftbl, componentvftbl);
}
-
- linker_classrenumber_mutex->unlock();
}
else if (valuedesc == NULL) {
/* {oa has dimension > 1} */
if (valuevftbl == elementvftbl)
return 1;
- linker_classrenumber_mutex->lock();
-
baseval = elementvftbl->baseval;
if (baseval <= 0) {
(valuevftbl->interfacetable[baseval] != NULL));
}
else {
- diffval = valuevftbl->baseval - elementvftbl->baseval;
- result = diffval <= (uint32_t) elementvftbl->diffval;
+ result = fast_subtype_check(valuevftbl, elementvftbl);
}
- linker_classrenumber_mutex->unlock();
-
return result;
}
if (valuevftbl == elementvftbl)
return 1;
- linker_classrenumber_mutex->lock();
-
- diffval = valuevftbl->baseval - elementvftbl->baseval;
- result = diffval <= (uint32_t) elementvftbl->diffval;
-
- linker_classrenumber_mutex->unlock();
+ result = fast_subtype_check(valuevftbl, elementvftbl);
return result;
}
* ICMD_BUILTIN3.)
*/
+bool fast_subtype_check(struct _vftbl *, struct _vftbl *);
+
bool builtin_instanceof(java_handle_t *obj, classinfo *c);
/* NOT AN OP */
bool builtin_checkcast(java_handle_t *obj, classinfo *c);
emit_label_bccz(cd, label, BRANCH_EQ, reg, BRANCH_OPT_NONE);
}
+void emit_label_bnez(codegendata *cd, s4 label, s4 reg)
+{
+ emit_label_bccz(cd, label, BRANCH_NE, reg, BRANCH_OPT_NONE);
+}
+
#endif /* SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER */
#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 ******************************************************/
#if SUPPORT_BRANCH_CONDITIONAL_ONE_INTEGER_REGISTER
void emit_label_beqz(codegendata *cd, s4 label, s4 reg);
+void emit_label_bnez(codegendata *cd, s4 label, s4 reg);
#endif
#if SUPPORT_BRANCH_CONDITIONAL_CONDITION_REGISTER
}
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);
JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super);
- 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);
- JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super);
- 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_ITMP2);
+ M_MOV_IMM(supervftbl, REG_ITMP3);
JITCACHE_ADD_CACHED_REF_JD(jd, CRT_CLASSINFO_VFTBL, super);
- 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_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);
+
+ 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);
+
+ 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_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_ALD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, subtype_overflow));
+ M_CMP_MEMINDEX(REG_ITMP2, -4*DISPLAY_SIZE, REG_ITMP1, 2, 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_CMP_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_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_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;
}
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;
-
/* private functions **********************************************************/
interfaceindex = 0;
-#if defined(ENABLE_THREADS)
- /* create the global mutex */
-
- linker_classrenumber_mutex = Mutex_new();
-#endif
-
/* Link the most basic classes. */
if (!link_class(class_java_lang_Object))
*******************************************************************************/
+static int build_display_inner(classinfo *topc, classinfo *c, int i)
+{
+ int depth;
+ if (!c)
+ return 0;
+ do {
+ 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);
+ depth = build_display_inner(topc, cls, i+1);
+ break;
+ }
+ if (a->componentvftbl && a->elementvftbl)
+ {
+ depth = build_display_inner(topc, a->componentvftbl->clazz, i+1);
+ break;
+ }
+ }
+ depth = build_display_inner(topc, c->super, i+1);
+ } while (false);
+ if (depth >= DISPLAY_SIZE)
+ {
+ if (depth == DISPLAY_SIZE)
+ {
+ topc->vftbl->subtype_overflow = malloc(sizeof(void*) * (i+1));
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ count_vftbl_len += sizeof(void*) * (i+1);
+#endif
+ }
+ topc->vftbl->subtype_overflow[depth - DISPLAY_SIZE] = c->vftbl;
+ return depth + 1;
+ }
+ topc->vftbl->subtype_display[depth] = c->vftbl;
+ return depth + 1;
+}
+
+static void build_display(classinfo *c)
+{
+ int depth;
+ int i;
+
+ depth = build_display_inner(c, c, 0) - 1;
+ c->vftbl->subtype_depth = depth;
+ if (depth >= DISPLAY_SIZE)
+ {
+ c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]);
+ }
+ else
+ {
+ c->vftbl->subtype_offset = OFFSET(vftbl_t, subtype_display[0]) + sizeof(void*) * depth;
+ for (i=depth+1; i<=DISPLAY_SIZE; i++)
+ c->vftbl->subtype_display[i] = NULL;
+ }
+}
+
static classinfo *link_class_intern(classinfo *c)
{
classinfo *super; /* super class */
linker_compute_subclasses(c);
+ /* FIXME: this is completely useless now */
RT_TIMING_GET_TIME(time_subclasses);
+ build_display(c);
+
/* revert the linking state and class is linked */
c->state = (c->state & ~CLASS_LINKING) | CLASS_LINKED;
static void linker_compute_subclasses(classinfo *c)
{
- Mutex_lock(linker_classrenumber_mutex);
if (!(c->flags & ACC_INTERFACE)) {
c->nextsub = NULL;
c->sub = NULL;
+ c->vftbl->baseval = 1; /* so it does not look like an interface */
}
if (!(c->flags & ACC_INTERFACE) && (c->super != NULL)) {
classvalue = 0;
- /* compute class values */
-
- linker_compute_class_values(class_java_lang_Object);
-
- Mutex_unlock(linker_classrenumber_mutex);
}
};
-/* global variables ***********************************************************/
-
-/* This lock must be taken while renumbering classes or while atomically */
-/* accessing classes. */
-
-extern Mutex *linker_classrenumber_mutex;
-
-
/* function prototypes ********************************************************/
#ifdef __cplusplus
#include "vm/class.hpp"
#include "vm/references.h"
+#define DISPLAY_SIZE 4
+
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 */
+
+ s4 subtype_depth;
+ s4 subtype_offset;
+ struct _vftbl *subtype_display[DISPLAY_SIZE+1]; /* the last one is cache */
+ struct _vftbl **subtype_overflow;
+
s4 *interfacevftbllength; /* length of interface vftbls */
methodptr table[1]; /* class vftbl */
};