8337251: C1: Improve Class.isInstance intrinsic

Reviewed-by: vlivanov
This commit is contained in:
Andrew Haley 2025-02-07 17:39:10 +00:00
parent 88a84835a3
commit b40f8eef98
13 changed files with 141 additions and 9 deletions

View File

@ -1316,6 +1316,11 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) {
x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci());
}
// Intrinsic for Class::isInstance
address LIRGenerator::isInstance_entry() {
return Runtime1::entry_for(C1StubId::is_instance_of_id);
}
void LIRGenerator::do_If(If* x) {
assert(x->number_of_sux() == 2, "inconsistency");
ValueTag tag = x->x()->type()->tag();

View File

@ -900,6 +900,55 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
}
break;
case C1StubId::is_instance_of_id:
{
// Mirror: c_rarg0
// Object: c_rarg1
// Temps: r3, r4, r5, r6
// Result: r0
// Get the Klass* into c_rarg6
Register klass = c_rarg6, obj = c_rarg1, result = r0;
__ ldr(klass, Address(c_rarg0, java_lang_Class::klass_offset()));
Label fail, is_secondary, success;
__ cbz(klass, fail); // Klass is null
__ cbz(obj, fail); // obj is null
__ ldrw(r3, Address(klass, in_bytes(Klass::super_check_offset_offset())));
__ cmpw(r3, in_bytes(Klass::secondary_super_cache_offset()));
__ br(Assembler::EQ, is_secondary); // Klass is a secondary superclass
// Klass is a concrete class
__ load_klass(r5, obj);
__ ldr(rscratch1, Address(r5, r3));
__ cmp(klass, rscratch1);
__ cset(result, Assembler::EQ);
__ ret(lr);
__ bind(is_secondary);
__ load_klass(obj, obj);
// This is necessary because I am never in my own secondary_super list.
__ cmp(obj, klass);
__ br(Assembler::EQ, success);
__ lookup_secondary_supers_table_var(obj, klass,
/*temps*/r3, r4, r5, v0,
result,
&success);
__ bind(fail);
__ mov(result, 0);
__ ret(lr);
__ bind(success);
__ mov(result, 1);
__ ret(lr);
}
break;
case C1StubId::monitorexit_nofpu_id:
save_fpu_registers = false;
// fall through

View File

@ -1125,6 +1125,11 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) {
x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci());
}
// Intrinsic for Class::isInstance
address LIRGenerator::isInstance_entry() {
return CAST_FROM_FN_PTR(address, Runtime1::is_instance_of);
}
#ifdef __SOFTFP__
// Turn operator if (f <op> g) into runtime call:

View File

@ -1128,6 +1128,11 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) {
x->profiled_method(), x->profiled_bci());
}
// Intrinsic for Class::isInstance
address LIRGenerator::isInstance_entry() {
return CAST_FROM_FN_PTR(address, Runtime1::is_instance_of);
}
void LIRGenerator::do_If(If* x) {
assert(x->number_of_sux() == 2, "inconsistency");

View File

@ -1102,6 +1102,11 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) {
x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci());
}
// Intrinsic for Class::isInstance
address LIRGenerator::isInstance_entry() {
return CAST_FROM_FN_PTR(address, Runtime1::is_instance_of);
}
void LIRGenerator::do_If(If* x) {
// If should have two successors
assert(x->number_of_sux() == 2, "inconsistency");

View File

@ -959,6 +959,11 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) {
x->profiled_method(), x->profiled_bci());
}
// Intrinsic for Class::isInstance
address LIRGenerator::isInstance_entry() {
return CAST_FROM_FN_PTR(address, Runtime1::is_instance_of);
}
void LIRGenerator::do_If (If* x) {
assert(x->number_of_sux() == 2, "inconsistency");

View File

@ -1490,6 +1490,11 @@ void LIRGenerator::do_InstanceOf(InstanceOf* x) {
x->direct_compare(), patching_info, x->profiled_method(), x->profiled_bci());
}
// Intrinsic for Class::isInstance
address LIRGenerator::isInstance_entry() {
return Runtime1::entry_for(C1StubId::is_instance_of_id);
}
void LIRGenerator::do_If(If* x) {
assert(x->number_of_sux() == 2, "inconsistency");

View File

@ -1317,6 +1317,60 @@ OopMapSet* Runtime1::generate_code_for(C1StubId id, StubAssembler* sasm) {
}
break;
case C1StubId::is_instance_of_id:
{
// Mirror: c_rarg0 (Windows: rcx, SysV: rdi)
// Object: c_rarg1 (Windows: rdx, SysV: rsi)
// ObjClass: r9
// Temps: rcx, r8, r10, r11
// Result: rax
Register klass = r9, obj = c_rarg1, result = rax;
Register temp0 = rcx, temp1 = r8, temp2 = r10, temp3 = r11;
// Get the Klass* into r9. c_rarg0 is now dead.
__ movptr(klass, Address(c_rarg0, java_lang_Class::klass_offset()));
Label done, is_secondary, same;
__ xorq(result, result);
__ testq(klass, klass);
__ jcc(Assembler::equal, done); // Klass is null
__ testq(obj, obj);
__ jcc(Assembler::equal, done); // obj is null
__ movl(temp0, Address(klass, in_bytes(Klass::super_check_offset_offset())));
__ cmpl(temp0, in_bytes(Klass::secondary_super_cache_offset()));
__ jcc(Assembler::equal, is_secondary); // Klass is a secondary superclass
// Klass is a concrete class
__ load_klass(temp2, obj, /*tmp*/temp1);
__ cmpptr(klass, Address(temp2, temp0));
__ setcc(Assembler::equal, result);
__ ret(0);
__ bind(is_secondary);
__ load_klass(obj, obj, /*tmp*/temp1);
// This is necessary because I am never in my own secondary_super list.
__ cmpptr(obj, klass);
__ jcc(Assembler::equal, same);
__ lookup_secondary_supers_table_var(obj, klass,
/*temps*/temp0, temp1, temp2, temp3,
result);
__ testq(result, result);
__ bind(same);
__ setcc(Assembler::equal, result);
__ bind(done);
__ ret(0);
}
break;
case C1StubId::monitorenter_nofpu_id:
save_fpu_registers = false;
// fall through

View File

@ -523,7 +523,7 @@ void Canonicalizer::do_Intrinsic (Intrinsic* x) {
ciType* t = c->value()->java_mirror_type();
if (t->is_klass()) {
// substitute cls.isInstance(obj) of a constant Class into
// an InstantOf instruction
// an InstanceOf instruction
InstanceOf* i = new InstanceOf(t->as_klass(), x->argument_at(1), x->state_before());
set_canonical(i);
// and try to canonicalize even further

View File

@ -1231,13 +1231,6 @@ void LIRGenerator::do_Reference_get(Intrinsic* x) {
void LIRGenerator::do_isInstance(Intrinsic* x) {
assert(x->number_of_arguments() == 2, "wrong type");
// TODO could try to substitute this node with an equivalent InstanceOf
// if clazz is known to be a constant Class. This will pick up newly found
// constants after HIR construction. I'll leave this to a future change.
// as a first cut, make a simple leaf call to runtime to stay platform independent.
// could follow the aastore example in a future change.
LIRItem clazz(x->argument_at(0), this);
LIRItem object(x->argument_at(1), this);
clazz.load_item();
@ -1250,8 +1243,9 @@ void LIRGenerator::do_isInstance(Intrinsic* x) {
__ null_check(clazz.result(), info);
}
address pd_instanceof_fn = isInstance_entry();
LIR_Opr call_result = call_runtime(clazz.value(), object.value(),
CAST_FROM_FN_PTR(address, Runtime1::is_instance_of),
pd_instanceof_fn,
x->type(),
nullptr); // null CodeEmitInfo results in a leaf call
__ move(call_result, result);

View File

@ -536,6 +536,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
LIR_Opr syncTempOpr();
LIR_Opr atomicLockOpr();
// Intrinsic for Class::isInstance
address isInstance_entry();
// returns a register suitable for saving the thread in a
// call_runtime_leaf if one is needed.
LIR_Opr getThreadTemp();

View File

@ -246,6 +246,7 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, C1StubId id) {
case C1StubId::fpu2long_stub_id:
case C1StubId::unwind_exception_id:
case C1StubId::counter_overflow_id:
case C1StubId::is_instance_of_id:
expect_oop_map = false;
break;
default:

View File

@ -100,6 +100,7 @@
do_blob(throw_class_cast_exception) \
do_blob(throw_incompatible_class_change_error) \
do_blob(slow_subtype_check) \
do_blob(is_instance_of) \
do_blob(monitorenter) \
do_blob(monitorenter_nofpu) /* optimized version that does not preserve fpu registers */ \
do_blob(monitorexit) \