diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index 64f1799a759..e85daed7324 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -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(); diff --git a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp index 5ab753188cb..7082b4110cd 100644 --- a/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_Runtime1_aarch64.cpp @@ -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 diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp index 39c20700a2d..ef5691f84a3 100644 --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -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 g) into runtime call: diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index b0cf941fb7a..d9ccf63bed3 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -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"); diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index 00de4488793..e31a1024f76 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -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"); diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index bce2f142aef..8cb8cef2b6b 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -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"); diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index 262683323ab..7e28b288f71 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -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"); diff --git a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp index caa9344e04d..cb4cb3af8c3 100644 --- a/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp +++ b/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp @@ -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 diff --git a/src/hotspot/share/c1/c1_Canonicalizer.cpp b/src/hotspot/share/c1/c1_Canonicalizer.cpp index 9a8d517822f..cda565519ec 100644 --- a/src/hotspot/share/c1/c1_Canonicalizer.cpp +++ b/src/hotspot/share/c1/c1_Canonicalizer.cpp @@ -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 diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 930e5e9df1b..2f0d12b4d7c 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -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); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index a66758054d7..52b1ed54fb0 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -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(); diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index d1b0818701c..3a30c9846aa 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -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: diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index 05f27fd078a..6930ded7fb8 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -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) \