diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 1ba6896170e..6bfdae1cf5c 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3268,8 +3268,9 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, Node* *failure_control) { kill_dead_locals(); // Benefit all the uncommon traps - const TypeKlassPtr *tk = _gvn.type(superklass)->is_klassptr()->try_improve(); - const TypeOopPtr *toop = tk->cast_to_exactness(false)->as_instance_type(); + const TypeKlassPtr* klass_ptr_type = _gvn.type(superklass)->is_klassptr(); + const TypeKlassPtr* improved_klass_ptr_type = klass_ptr_type->try_improve(); + const TypeOopPtr* toop = improved_klass_ptr_type->cast_to_exactness(false)->as_instance_type(); // Fast cutout: Check the case that the cast is vacuously true. // This detects the common cases where the test will short-circuit @@ -3277,10 +3278,10 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, // because if the test is going to turn into zero code, we don't // want a residual null check left around. (Causes a slowdown, // for example, in some objArray manipulations, such as a[i]=a[j].) - if (tk->singleton()) { + if (improved_klass_ptr_type->singleton()) { const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr(); if (objtp != nullptr) { - switch (C->static_subtype_check(tk, objtp->as_klass_type())) { + switch (C->static_subtype_check(improved_klass_ptr_type, objtp->as_klass_type())) { case Compile::SSC_always_true: // If we know the type check always succeed then we don't use // the profiling data at this bytecode. Don't lose it, feed it @@ -3346,7 +3347,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, } Node* cast_obj = nullptr; - if (tk->klass_is_exact()) { + if (improved_klass_ptr_type->klass_is_exact()) { // The following optimization tries to statically cast the speculative type of the object // (for example obtained during profiling) to the type of the superklass and then do a // dynamic check that the type of the object is what we expect. To work correctly @@ -3356,7 +3357,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, // a speculative type use it to perform an exact cast. ciKlass* spec_obj_type = obj_type->speculative_type(); if (spec_obj_type != nullptr || data != nullptr) { - cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk, spec_obj_type, safe_for_replace); + cast_obj = maybe_cast_profiled_receiver(not_null_obj, improved_klass_ptr_type, spec_obj_type, safe_for_replace); if (cast_obj != nullptr) { if (failure_control != nullptr) // failure is now impossible (*failure_control) = top(); @@ -3368,7 +3369,11 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, if (cast_obj == nullptr) { // Generate the subtype check - Node* not_subtype_ctrl = gen_subtype_check(not_null_obj, superklass ); + Node* improved_superklass = superklass; + if (improved_klass_ptr_type != klass_ptr_type && improved_klass_ptr_type->singleton()) { + improved_superklass = makecon(improved_klass_ptr_type); + } + Node* not_subtype_ctrl = gen_subtype_check(not_null_obj, improved_superklass); // Plug in success path into the merge cast_obj = _gvn.transform(new CheckCastPPNode(control(), not_null_obj, toop)); diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeCheckUniqueSubclass.java b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckUniqueSubclass.java new file mode 100644 index 00000000000..ceee83f3d6a --- /dev/null +++ b/test/hotspot/jtreg/compiler/types/TestSubTypeCheckUniqueSubclass.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8328480 + * @summary Test that SubTypeCheckNode takes improved unique concrete klass constant in order to fold consecutive sub + * type checks. + * @library /test/lib / + * @run driver compiler.types.TestSubTypeCheckUniqueSubclass + */ + +package compiler.types; + +import compiler.lib.ir_framework.*; + +public class TestSubTypeCheckUniqueSubclass { + static Object o = new C(); // Make sure C is loaded. + static Object o2 = new C2(); // Make sure C2 is loaded while NeverLoaded is not. + + public static void main(String[] args) { + TestFramework.run(); + } + + @Test + @Warmup(0) + @IR(counts = {IRNode.SUBTYPE_CHECK, "1"}, + phase = CompilePhase.ITER_GVN1) + static void testAbstractAbstract() { + A a = (A)o; + A a2 = (B)o; + } + + @Test + @Warmup(0) + @IR(counts = {IRNode.SUBTYPE_CHECK, "1"}, + phase = CompilePhase.ITER_GVN1) + static void testAbstractAbstractWithUnloaded() { + A2 a = (A2)o2; + A2 a2 = (B2)o2; + } +} + +abstract class A {} +abstract class B extends A {} +class C extends B {} + +abstract class A2 {} +abstract class B2 extends A2 {} +class C2 extends B2 {} + +// Class never loaded -> C2 looks like unique sub class. +class NeverLoaded extends B2 {}