return NULL;
}
+bool fast_subtype_check(struct _vftbl *s, struct _vftbl *t)
+{
+ vm_abort("fast_subtype_check: Not implemented.");
+ return 0;
+}
+
bool builtin_isanysubclass(classinfo *sub, classinfo *super)
{
vm_abort("builtin_isanysubclass: Not implemented.");
*******************************************************************************/
+bool fast_subtype_check(struct _vftbl *s, struct _vftbl *t)
+{
+ int i;
+ if (s->subtype_display[t->subtype_depth] == t)
+ return true;
+ if (t->subtype_offset != OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]))
+ return false;
+ for (i=0; i<s->subtype_overflow_length; i++)
+ if (s->subtype_overflow[i] == t)
+ return true;
+ return false;
+}
+
bool builtin_fast_canstore(java_objectarray_t *oa, java_object_t *o)
{
arraydescriptor *desc;
if (valuevftbl == componentvftbl)
return 1;
- LOCK_MONITOR_ENTER(linker_classrenumber_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);
}
-
- LOCK_MONITOR_EXIT(linker_classrenumber_lock);
}
else if (valuedesc == NULL) {
/* {oa has dimension > 1} */
if (valuevftbl == elementvftbl)
return 1;
- LOCK_MONITOR_ENTER(linker_classrenumber_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);
}
- LOCK_MONITOR_EXIT(linker_classrenumber_lock);
-
return result;
}
if (valuevftbl == elementvftbl)
return 1;
- LOCK_MONITOR_ENTER(linker_classrenumber_lock);
-
- diffval = valuevftbl->baseval - elementvftbl->baseval;
- result = diffval <= (uint32_t) elementvftbl->diffval;
-
- LOCK_MONITOR_EXIT(linker_classrenumber_lock);
+ 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 *class);
/* NOT AN OP */
bool builtin_checkcast(java_handle_t *obj, classinfo *class);
#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 ******************************************************/
classinfo *super;
s4 superindex;
+ s4 looptarget;
+
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
super = NULL;
superindex = 0;
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 */
disp = dseg_add_address(cd, super->vftbl);
}
- M_ALD(REG_ITMP2, s1, OFFSET(java_object_t, vftbl));
- M_ALD(REG_ITMP3, RIP, disp);
+ if (s1 == REG_ITMP1)
+ M_AST(REG_ITMP1, REG_SP, -8); /* store in red zone */
+
+ M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
+ M_ALD(REG_ITMP2, RIP, disp);
+
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_ALD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_offset));
+
+ *(cd->mcodeptr++) = 0x4e;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x14;
+ *(cd->mcodeptr++) = 0x18;
+ /* cmp (ITMP1, ITMP3, 1), ITMP2 */
+
+ emit_label_beq(cd, BRANCH_LABEL_6); /* good */
- CODEGEN_CRITICAL_SECTION_START;
+ M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP3);
+ emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
- M_ILD(REG_ITMP2, REG_ITMP2, OFFSET(vftbl_t, baseval));
+ /* use red zone */
+ M_AST(REG_ITMP2, REG_SP, -16);
+ M_AST_IMM32(0, REG_SP, -24);
+ M_ALD(REG_ITMP3, REG_ITMP1, OFFSET(vftbl_t, subtype_overflow));
+ looptarget = cd->mcodeptr - cd->mcodebase;
- /* 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_ITMP2, REG_SP, -24);
+ M_ICMP_MEMBASE(REG_ITMP1, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP2);
- /* } else { */
+ emit_classcast_check(cd, iptr, BRANCH_GE, REG_ITMP3, s1);
- 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));
- /* } */
+ *(cd->mcodeptr++) = 0x4f;
+ *(cd->mcodeptr++) = 0x8b;
+ *(cd->mcodeptr++) = 0x14;
+ *(cd->mcodeptr++) = 0xd3;
+ /* movq (ITMP3, ITMP2, 8), ITMP2 */
- CODEGEN_CRITICAL_SECTION_END;
+ M_LCMP_MEMBASE(REG_SP, -16, REG_ITMP2);
+ emit_label_beq(cd, BRANCH_LABEL_7); /* good, pop */
+
+ M_LINC_MEMBASE(REG_SP, -24);
+ M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
+
+ emit_label(cd, BRANCH_LABEL_7);
+
+ emit_label(cd, BRANCH_LABEL_6);
+ }
+ else {
+ assert(super->vftbl->subtype_offset < 0x80);
+ *(cd->mcodeptr++) = 0x4c;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x50;
+ *(cd->mcodeptr++) = super->vftbl->subtype_offset;
+ /* cmp off(ITMP1), ITMP2 */
+
+ emit_classcast_check(cd, iptr, BRANCH_NE, REG_ITMP3, s1);
+ }
- 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);
if (super != NULL)
emit_label(cd, BRANCH_LABEL_5);
classinfo *super;
s4 superindex;
+ s4 looptarget;
+
if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
super = NULL;
superindex = 0;
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);
M_ALD(REG_ITMP1, s1, OFFSET(java_object_t, vftbl));
M_ALD(REG_ITMP2, RIP, disp);
- CODEGEN_CRITICAL_SECTION_START;
+ if (super == NULL || super->vftbl->subtype_depth >= DISPLAY_SIZE) {
+ M_ALD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, subtype_offset));
+
+ *(cd->mcodeptr++) = 0x4e;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x14;
+ *(cd->mcodeptr++) = 0x18;
+ /* cmp (ITMP1, ITMP3, 1), ITMP2 */
+
+ emit_label_bne(cd, BRANCH_LABEL_6);
+ M_LINC(d);
+ emit_label_br(cd, BRANCH_LABEL_7); /* ende */
+
+ emit_label(cd, BRANCH_LABEL_6);
+
+ M_LCMP_IMM(OFFSET(vftbl_t, subtype_display[DISPLAY_SIZE]), REG_ITMP3);
+ emit_label_bne(cd, BRANCH_LABEL_6); /* ende */
+
+ /* use the red zone */
+ M_AST(REG_ITMP2, REG_SP, -16);
+ M_AST_IMM32(0, REG_SP, -24);
+ M_ALD(REG_ITMP3, REG_ITMP1, OFFSET(vftbl_t, subtype_overflow));
+ looptarget = cd->mcodeptr - cd->mcodebase;
- 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, REG_SP, -24);
+ M_ICMP_MEMBASE(REG_ITMP1, OFFSET(vftbl_t, subtype_overflow_length), REG_ITMP2);
+ emit_label_bge(cd, BRANCH_LABEL_8); /* ende pop */
- CODEGEN_CRITICAL_SECTION_END;
+ *(cd->mcodeptr++) = 0x4f;
+ *(cd->mcodeptr++) = 0x8b;
+ *(cd->mcodeptr++) = 0x14;
+ *(cd->mcodeptr++) = 0xd3;
+ /* movq (ITMP3, ITMP2, 8), ITMP2 */
- M_ISUB(REG_ITMP2, REG_ITMP1);
- M_CLR(d); /* may be REG_ITMP2 */
- M_ICMP(REG_ITMP3, REG_ITMP1);
- M_SETULE(d);
+ M_LCMP_MEMBASE(REG_SP, -16, REG_ITMP2);
+ emit_label_bne(cd, BRANCH_LABEL_9);
+ M_LINC(d);
+ emit_label_br(cd, BRANCH_LABEL_10); /* ende pop */
+ emit_label(cd, BRANCH_LABEL_9);
+
+ M_LINC_MEMBASE(REG_SP, -24);
+ M_JMP_IMM2(looptarget - (cd->mcodeptr - cd->mcodebase) - 2); /* 1 byte displacement */
+
+ emit_label(cd, BRANCH_LABEL_8);
+ emit_label(cd, BRANCH_LABEL_10);
+
+ emit_label(cd, BRANCH_LABEL_6);
+ emit_label(cd, BRANCH_LABEL_7);
+ }
+ else {
+ assert(super->vftbl->subtype_offset < 0x80);
+ *(cd->mcodeptr++) = 0x4c;
+ *(cd->mcodeptr++) = 0x3b;
+ *(cd->mcodeptr++) = 0x50;
+ *(cd->mcodeptr++) = super->vftbl->subtype_offset;
+ /* cmp off(ITMP1), ITMP2 */
+
+ emit_label_bne(cd, BRANCH_LABEL_6);
+ M_LINC(d);
+ emit_label(cd, BRANCH_LABEL_6);
+ }
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_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_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_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);
if (sub->flags & ACC_INTERFACE)
return (super == class_java_lang_Object);
- LOCK_MONITOR_ENTER(linker_classrenumber_lock);
-
- diffval = sub->vftbl->baseval - super->vftbl->baseval;
- result = diffval <= (uint32_t) super->vftbl->diffval;
-
- LOCK_MONITOR_EXIT(linker_classrenumber_lock);
+ result = fast_subtype_check(sub->vftbl, super->vftbl);
}
return result;
static s4 interfaceindex; /* sequential numbering of interfaces */
static s4 classvalue;
-java_object_t *linker_classrenumber_lock;
-
/* private functions **********************************************************/
interfaceindex = 0;
-#if defined(ENABLE_THREADS)
- /* create the global lock object */
-
- linker_classrenumber_lock = NEW(java_object_t);
-
- LOCK_INIT_OBJECT_LOCK(linker_classrenumber_lock);
-#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_length = i+1;
+ 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;
+ c->vftbl->subtype_overflow_length = 0;
+ }
+}
+
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)
{
- LOCK_MONITOR_ENTER(linker_classrenumber_lock);
-
#if 0 && defined(ENABLE_THREADS) && !defined(DISABLE_GC)
threads_stopworld();
#endif
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);
-
- LOCK_MONITOR_EXIT(linker_classrenumber_lock);
-
#if 0 && defined(ENABLE_THREADS) && !defined(DISABLE_GC)
threads_startworld();
#endif
*******************************************************************************/
+#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;
+ ptrint subtype_offset;
+ struct _vftbl *subtype_display[DISPLAY_SIZE+1]; /* the last one is cache */
+ s4 subtype_overflow_length;
+ struct _vftbl **subtype_overflow;
+
s4 *interfacevftbllength; /* length of interface vftbls */
methodptr table[1]; /* class vftbl */
};
};
-/* global variables ***********************************************************/
-
-/* This lock must be taken while renumbering classes or while atomically */
-/* accessing classes. */
-
-extern java_object_t *linker_classrenumber_lock;
-
-
/* function prototypes ********************************************************/
void linker_preinit(void);