diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 1531a1721b1..217b613b58e 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4691,6 +4691,7 @@ bool LibraryCallKit::inline_native_subtype_check() { // {P,P} & superc!=subc => false _prim_same_path, // {P,P} & superc==subc => true _prim_1_path, // {N,P} => false + _ref_same_path, // {N,N} & superk==subk => true _ref_subtype_path, // {N,N} & subtype check wins => true _both_ref_path, // {N,N} & subtype check loses => false PATH_LIMIT @@ -4738,6 +4739,16 @@ bool LibraryCallKit::inline_native_subtype_check() { // now we have two reference types, in klasses[0..1] Node* subk = klasses[1]; // the argument to isAssignableFrom Node* superk = klasses[0]; // the receiver + + // gen_subtype_check() refines exact array superklasses for comparison with + // (refined) klasses loaded from the header. Since both operands here are unrefined + // klasses, handle equality first. Unequal types then use the regular hierarchy check. + Node* cmp = _gvn.transform(new CmpPNode(subk, superk)); + Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq)); + IfNode* iff = create_and_xform_if(control(), bol, PROB_STATIC_FREQUENT, COUNT_UNKNOWN); + region->set_req(_ref_same_path, _gvn.transform(new IfTrueNode(iff))); + set_control(_gvn.transform(new IfFalseNode(iff))); + region->set_req(_both_ref_path, gen_subtype_check(subk, superk)); region->set_req(_ref_subtype_path, control()); } @@ -4762,6 +4773,7 @@ bool LibraryCallKit::inline_native_subtype_check() { // these are the only paths that produce 'true': phi->set_req(_prim_same_path, intcon(1)); + phi->set_req(_ref_same_path, intcon(1)); phi->set_req(_ref_subtype_path, intcon(1)); // pull together the cases: diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsAssignableFrom.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsAssignableFrom.java new file mode 100644 index 00000000000..fd532da93ec --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIsAssignableFrom.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2026, 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 8389341 + * @summary Test that Class.isAssignableFrom returns true for two identical arguments. + * @library /test/lib + * @run main ${test.main.class} + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * -XX:CompileCommand=delayinline,${test.main.class}::helperDelayed + * ${test.main.class} + */ + +package compiler.valhalla.inlinetypes; + +import jdk.test.lib.Asserts; + +public final class TestIsAssignableFrom { + static boolean test(Class c) { + return TestIsAssignableFrom[].class.isAssignableFrom(c); + } + + static Class helperDelayed() { + return TestIsAssignableFrom[].class; + } + + static boolean testLate(Class c) { + return helperDelayed().isAssignableFrom(c); + } + + public static void main(String[] args) { + Asserts.assertEQ(test(TestIsAssignableFrom[].class), true); + Asserts.assertEQ(testLate(TestIsAssignableFrom[].class), true); + } +} +