JDK-8299155 : C2: SubTypeCheckNode::verify() should not produce dependencies / oop pool entries
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 18,19,20,21
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2022-12-20
  • Updated: 2022-12-21
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 21
21Unresolved
Related Reports
Relates :  
Relates :  
Description
C2's SubTypeCheckNode::verify() produce dependencies which in turn produce entries in the oop pool which affect the unloading behaviour of the nmethod. This can hide issues of the release build which will not have the dependencies and oop pool entries.

The attachment CallFinalVirtualFromOtherLoader.java is a reproducer. ClassA_LVL_1.testMethod_dojit() has a virtual call that can be statically bound because the target method is final. It is loaded by a subclassloader though. SubTypeCheckNode::verify() adds a dependency to the subclassloader 'CallFinalVirtualFromOtherLoader$DirectLeveledClassLoader$Level2' (see attachment output.log:1411). This is redundant as a dependency is added by ClassLoaderData::record_dependency().

Without calling SubTypeCheckNode::verify() the dependency is not added (see output_UseNewCode.log:1406)
The run was produced with the following patch:

diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp
index 8ef50b73be9..04ccf6ae674 100644
--- a/src/hotspot/share/opto/subtypenode.cpp
+++ b/src/hotspot/share/opto/subtypenode.cpp
@@ -110,7 +110,7 @@ Node *SubTypeCheckNode::Ideal(PhaseGVN* phase, bool can_reshape) {
 
   // Verify that optimizing the subtype check to a simple code pattern
   // when possible would not constant fold better
-  assert(verify(phase), "missing Value() optimization");
+  assert(UseNewCode || verify(phase), "missing Value() optimization");
 
   return NULL;
 }

The redundant dependency is added here:

#0  Dependencies::assert_leaf_type (this=0x7fe266d3fbe0 <Compile::dependencies()+36>, ctxk=0x7fe20baf7010) at .../jdk/src/hotspot/share/code/dependencies.cpp:84
#1  0x00007fe267ba6799 in TypeInstPtr::as_klass_type (this=0x7fe1ec036978, try_for_exact=true) at .../jdk/src/hotspot/share/opto/type.cpp:4328
#2  0x00007fe2677aad4d in LoadNode::klass_value_common (this=0x7fe1ec054d28, phase=0x7fe20baf8040) at .../jdk/src/hotspot/share/opto/memnode.cpp:2340
#3  0x00007fe2677ab273 in LoadNKlassNode::Value (this=0x7fe1ec054d28, phase=0x7fe20baf8040) at .../jdk/src/hotspot/share/opto/memnode.cpp:2449
#4  0x00007fe2678dc8cc in PhaseGVN::transform_no_reclaim (this=0x7fe20baf8040, n=0x7fe1ec054d28) at .../jdk/src/hotspot/share/opto/phaseX.cpp:862
#5  0x00007fe2678dc77b in PhaseGVN::transform (this=0x7fe20baf8040, n=0x7fe1ec054d28) at .../jdk/src/hotspot/share/opto/phaseX.cpp:829
#6  0x00007fe2677aa989 in LoadKlassNode::make (gvn=..., ctl=0x0, mem=0x7fe1ec0521e8, adr=0x7fe1ec054c88, at=0x7fe1ec023b28, tk=0x7fe1ec0269a8) at .../jdk/src/hotspot/share/opto/memnode.cpp:2276
#7  0x00007fe267b0ac79 in SubTypeCheckNode::verify (this=0x7fe1ec054b80, phase=0x7fe20baf8040) at .../jdk/src/hotspot/share/opto/subtypenode.cpp:173
#8  0x00007fe267b0a763 in SubTypeCheckNode::Ideal (this=0x7fe1ec054b80, phase=0x7fe20baf8040, can_reshape=false) at .../jdk/src/hotspot/share/opto/subtypenode.cpp:113
#9  0x00007fe2678dc74a in PhaseGVN::apply_ideal (this=0x7fe20baf8040, k=0x7fe1ec054b80, can_reshape=false) at .../jdk/src/hotspot/share/opto/phaseX.cpp:820
#10 0x00007fe2678dc7bf in PhaseGVN::transform_no_reclaim (this=0x7fe20baf8040, n=0x7fe1ec054b80) at .../jdk/src/hotspot/share/opto/phaseX.cpp:840
#11 0x00007fe2678dc77b in PhaseGVN::transform (this=0x7fe20baf8040, n=0x7fe1ec054b80) at .../jdk/src/hotspot/share/opto/phaseX.cpp:829
#12 0x00007fe2673354d0 in GraphKit::gen_subtype_check (this=0x7fe20baf75d0, obj_or_subklass=0x7fe1ec054a70, superklass=0x7fe1ec054b10) at .../jdk/src/hotspot/share/opto/graphKit.cpp:2834
#13 0x00007fe2673359db in GraphKit::subtype_check_receiver (this=0x7fe20baf75d0, receiver=0x7fe1ec054a70, klass=0x7fe1ec02dec8, casted_receiver=0x7fe20baf7510) at .../jdk/src/hotspot/share/opto/graphKit.cpp:2879
#14 0x00007fe266ef5a34 in PredictedCallGenerator::generate (this=0x7fe1ec056008, jvms=0x7fe1ec055d00) at .../jdk/src/hotspot/share/opto/callGenerator.cpp:885
#15 0x00007fe267191119 in Parse::do_call (this=0x7fe20baf7b90) at .../jdk/src/hotspot/share/opto/doCall.cpp:662
#16 0x00007fe2678c91c1 in Parse::do_one_bytecode (this=0x7fe20baf7b90) at .../jdk/src/hotspot/share/opto/parse2.cpp:2704
#17 0x00007fe2678b8226 in Parse::do_one_block (this=0x7fe20baf7b90) at .../jdk/src/hotspot/share/opto/parse1.cpp:1555
#18 0x00007fe2678b44c3 in Parse::do_all_blocks (this=0x7fe20baf7b90) at .../jdk/src/hotspot/share/opto/parse1.cpp:707
#19 0x00007fe2678b400b in Parse::Parse (this=0x7fe20baf7b90, caller=0x7fe1ec055a70, parse_method=0x7fe1ec02c078, expected_uses=6784) at .../jdk/src/hotspot/share/opto/parse1.cpp:614

This was noticed while working on JDK-8296440. The intention there was to assert during call resolution that the loader of a statically bound callee is reachable from the caller.

Comments
While the problematic verification code is in there since JDK-8238691 in JDK 15, I can only reproduce this after JDK 18 b3, probably because of changes like JDK-8268405. ILW = Redundant leaf_type dependency in C2 compiled code, only with debug builds, no workaround = MLH = P4
21-12-2022