Skip to content

Commit 29434cc

Browse files
author
Vladimir Ivanov
committed
8376421: C2: Missing branch on SubTypeCheck node
Reviewed-by: kvn, dfenacci
1 parent 2121302 commit 29434cc

2 files changed

Lines changed: 88 additions & 8 deletions

File tree

src/hotspot/share/opto/parse2.cpp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1833,17 +1833,21 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest,
18331833
&obj, &cast_type)) {
18341834
assert(obj != nullptr && cast_type != nullptr, "missing type check info");
18351835
const Type* obj_type = _gvn.type(obj);
1836-
const TypeOopPtr* tboth = obj_type->join_speculative(cast_type)->isa_oopptr();
1837-
if (tboth != nullptr && tboth != obj_type && tboth->higher_equal(obj_type)) {
1836+
const Type* tboth = obj_type->filter_speculative(cast_type);
1837+
assert(tboth->higher_equal(obj_type) && tboth->higher_equal(cast_type), "sanity");
1838+
if (tboth == Type::TOP && KillPathsReachableByDeadTypeNode) {
1839+
// Let dead type node cleaning logic prune effectively dead path for us.
1840+
// CheckCastPP::Value() == TOP and it will trigger the cleanup during GVN.
1841+
// Don't materialize the cast when cleanup is disabled, because
1842+
// it kills data and control leaving IR in broken state.
1843+
tboth = cast_type;
1844+
}
1845+
if (tboth != Type::TOP && tboth != obj_type) {
18381846
int obj_in_map = map()->find_edge(obj);
1839-
JVMState* jvms = this->jvms();
18401847
if (obj_in_map >= 0 &&
1841-
(jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) {
1848+
(jvms()->is_loc(obj_in_map) || jvms()->is_stk(obj_in_map))) {
18421849
TypeNode* ccast = new CheckCastPPNode(control(), obj, tboth);
1843-
const Type* tcc = ccast->as_Type()->type();
1844-
assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve");
1845-
// Delay transform() call to allow recovery of pre-cast value
1846-
// at the control merge.
1850+
// Delay transform() call to allow recovery of pre-cast value at the control merge.
18471851
_gvn.set_type_bottom(ccast);
18481852
record_for_igvn(ccast);
18491853
// Here's the payoff.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
/*
26+
* @test
27+
* @bug 8376421
28+
* @summary "C2: Missing branch on SubTypeCheck node"
29+
*
30+
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions
31+
* -XX:+KillPathsReachableByDeadTypeNode
32+
* compiler.types.TestSubTypeCheckInterfaceNotImplemented
33+
*
34+
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions
35+
* -XX:-KillPathsReachableByDeadTypeNode
36+
* compiler.types.TestSubTypeCheckInterfaceNotImplemented
37+
*/
38+
39+
package compiler.types;
40+
41+
public class TestSubTypeCheckInterfaceNotImplemented {
42+
static abstract class A {}
43+
static abstract class B extends A {}
44+
static final class C extends B {}
45+
46+
interface I {}
47+
static final class BJ1 extends A implements I {}
48+
static final class BJ2 extends A implements I {}
49+
50+
static boolean testHelper2(B o) {
51+
return true;
52+
}
53+
static boolean testHelper1(Object o) {
54+
if (o instanceof B) {
55+
return testHelper2((B)o); // a call to place "o" on JVMS, so the map is updated after the check
56+
} else {
57+
return false;
58+
}
59+
}
60+
61+
static boolean test(A a) {
62+
if (a instanceof I) {
63+
return testHelper1((I)a); // "a" always fails instanceof check against B
64+
} else {
65+
return false;
66+
}
67+
}
68+
69+
public static void main(String[] args) {
70+
for (int i = 0; i < 20_000; i++) {
71+
testHelper1(new C()); // pollute profile
72+
73+
test(new BJ1()); test(new BJ2()); test(new C());
74+
}
75+
}
76+
}

0 commit comments

Comments
 (0)