RFR: 8368095: [leyden] Fix klass dependency recording [v3]
Aleksey Shipilev
shade at openjdk.org
Mon Sep 22 08:59:16 UTC 2025
On Fri, 19 Sep 2025 13:57:05 GMT, Aleksey Shipilev <shade at openjdk.org> wrote:
>> See the bug for symptoms. https://github.com/openjdk/leyden/commit/7b7648a4c9f67be509c6fccbcbc0502648388fdc exposed that our dependency recording is not actually accurate. Now that we check that precompiled tasks have dependencies recorded, before we treat class IK as fully initialized, _missing dependencies_ lead to premature replacement of AP4 -> A4, and potential trap from A4.
>>
>> I see there are several missing things:
>> 1. We need to record dependencies on object klasses as well, not only on plain metadata.
>> 2. Since ciObjectFactory is shared, we need to notice objects/metadata even on cache hits.
>> 3. It looks like we need to observe dependencies even when `cik->is_initialized()` returns `false` at the moment.
>>
>> Additional testing:
>> - [x] Linux x86_64 server fastdebug, `runtime/cds`
>> - [x] Benchmarks
>
> Aleksey Shipilev has updated the pull request incrementally with one additional commit since the last revision:
>
> Revert "Retract some unneccesary paths"
>
> This reverts commit cb48aacac9d7915e6fd890398020442aedac7948.
Answering both questions at once. I am seeing **a lot** more deopts when accepting only IK in initialized state. A majority of newly accepted IK dependencies are in uninitialized state. My theory is that A4 traps out with class initialization checks without waiting for AP4 to run through clinit barriers. So the AP4 -> A4 replacement looks premature -- isn't that what we want to prevent with dependency tracking? Dropping the initialization check makes the dependency more conservative, indeed, but it apparently covers lots of bad cases well.
Benchmark 1: build/linux-x86_64-server-release/images/jdk/bin/java -Xms64m -Xmx1g -XX:+UseSerialGC -cp JavacBenchApp.jar -XX:AOTCache=app.aot JavacBenchApp 50
# This PR in current form, accepting all IKs as dependencies
Time (mean ± σ): 345.3 ms ± 2.7 ms [User: 569.3 ms, System: 85.5 ms]
Range (min … max): 342.7 ms … 351.0 ms 10 runs
Total traps: 118
Reason_Uninitialized + !Action_None traps: 2
# This PR + (IK->is_initialized()) check
Time (mean ± σ): 407.9 ms ± 27.0 ms [User: 1051.5 ms, System: 132.3 ms]
Range (min … max): 389.5 ms … 479.9 ms 10 runs
Total traps: 276
Reason_Uninitialized + !Action_None traps: 138
# This PR + (IK->is_initialized() || IK->is_being_initialized()) check
Time (mean ± σ): 403.1 ms ± 22.4 ms [User: 1019.9 ms, System: 122.6 ms]
Range (min … max): 379.9 ms … 438.4 ms 10 runs
Total traps: 277
Reason_Uninitialized + !Action_None traps: 136
This is the example for one of the hot methods in javac:
# @70ms: AP4 loads
70 W0.0 Q34.4 C0.1 A0.1 829 AP 4 com.sun.tools.javac.code.Symtab::lookupPackage (259 bytes)
# @157ms: A4 replaces the AP4 version
157 829 AP 4 com.sun.tools.javac.code.Symtab::lookupPackage (259 bytes) made not entrant: not used
157 W0.0 Q61.1 C0.1 A0.0 3984 A 4 com.sun.tools.javac.code.Symtab::lookupPackage (259 bytes)
# ... and immediately traps at uninitialized class:
[0.157s][debug][deoptimization] cid=3984 level=4 com.sun.tools.javac.code.Symtab::lookupPackage(Lcom/sun/tools/javac/code/Symbol$ModuleSymbol;Lcom/sun/tools/javac/util/Name;Z)Lcom/sun/tools/javac/code/Symbol$PackageSymbol; trap_bci=101 uninitialized reinterpret pc=0x000077bf28520d04 relative_pc=0x0000000000000a04
157 3984 A 4 com.sun.tools.javac.code.Symtab::lookupPackage (259 bytes) made not entrant: uncommon trap
# ...and goes to recompile:
159 W0.0 Q0.0 C1.3 4459 2 com.sun.tools.javac.code.Symtab::lookupPackage (259 bytes)
222 4459 2 com.sun.tools.javac.code.Symtab::lookupPackage (259 bytes) made not entrant: not used
222 W9.1 Q0.0 C33.6 4734 4 com.sun.tools.javac.code.Symtab::lookupPackage (259 bytes)
-------------
PR Comment: https://git.openjdk.org/leyden/pull/97#issuecomment-3317644542
More information about the leyden-dev
mailing list