RFR: 8311071: Avoid SoftReferences in LambdaFormEditor and MethodTypeForm when storing heap objects into AOT cache [v7]

John R Rose jrose at openjdk.org
Wed Oct 9 21:43:19 UTC 2024


On Wed, 2 Oct 2024 01:06:20 GMT, Ioi Lam <iklam at openjdk.org> wrote:

>> This is the 6th PR for [JEP 483: Ahead-of-Time Class Loading & Linking](https://bugs.openjdk.org/browse/JDK-8315737).
>> 
>> The implementation of java.lang.invoke uses SoftReferences so that unused MethodHandles, LambdaForms, etc, can be garbage collected.
>> 
>> However, if we want to store java.lang.invoke objects in the AOT cache ([JDK-8293336](https://bugs.openjdk.org/browse/JDK-8293336), the final step in JEP 493), it's difficult to cache these SoftReferences -- SoftReferences in turn point to ReferenceQueues, etc, which have dependencies on the current execution state (Threads, etc) which are difficult to cache.
>> 
>> The proposal is to add a new flag: `MethodHandleStatics.NO_SOFT_CACHE`. When this flag is true, we avoid using SoftReferences, and store a direct reference to the target object instead.
>> 
>> [JDK-8293336](https://bugs.openjdk.org/browse/JDK-8293336) stores only java.lang.invoke objects that refer to classes loaded by the boot/platform/app loaders. These classes are never unloaded, so it's not necessary to point to them using SoftReferences.
>> 
>> This RFE modifies only the LambdaFormEditor and MethodTypeForm classes, as that's the minimal modification required by [JDK-8293336](https://bugs.openjdk.org/browse/JDK-8293336).
>> 
>> ---
>> See [here](https://bugs.openjdk.org/browse/JDK-8315737) for the sequence of dependent RFEs for implementing JEP 483.
>
> Ioi Lam has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 13 additional commits since the last revision:
> 
>  - Merge branch 'jep-483-step-05-8293337-archive-method-handle-intrinsics' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
>  - Merge branch 'jep-483-step-05-8293337-archive-method-handle-intrinsics' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
>  - Merge branch 'jep-483-step-05-8293337-archive-method-handle-intrinsics' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
>  - @liach and @cl4es comments
>  - Merge branch 'jep-483-step-05-8293337-archive-method-handle-intrinsics' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
>  - @dholmes-ora review comments
>  - Merge branch 'jep-483-step-05-8293337-archive-method-handle-intrinsics' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
>  - Merge branch 'jep-483-step-05-8293337-archive-method-handle-intrinsics' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
>  - Do not use system property to limit usage to only CDS static dumps
>  - Merge branch 'jep-483-step-05-8293337-archive-method-handle-intrinsics' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
>  - ... and 3 more: https://git.openjdk.org/jdk/compare/c68bb02b...1b067b7b

This is good although hacky, due to incomplete "build out" of Leyden-related functionality.  For a first JEP it is fine.  But it leaves some debt to pay off later.

Later, we need to decide how to more fully embrace SoftReference.  There is nothing inherently wrong with mixing SR's and AOT, even if they interfere somewhat.  I think the right answer might be forcing them to get along better.  We need to get their queueing status into a quiet state order to push them into the AOT cache (and then pull them out as the production run states).  It seems to me we should (first) try pruning away most of the queueing infrastructure during the assembly phase, and patching it up in the production run (at some appropriate `VM::initState` level), so that the SRs "go live" at a controlled point during boot-up.

Or, we could do a Three Table (or Two Table) solution.  This PR is an example of a Two Table solution.  (One could say the handoff from AOT table to runtime table is overly subtle but it works, and maybe that subtlety just comes with the territory.)  The various cache variables (`Transform.cache` and `MTF.LFs/MHs`) right now are polymorphically SRs or hard references.  The variable `MethodHandleStatics.NO_SOFT_CACHE` controls which "table" is active.  (This is a sort of "sharded" table, not a centralized table object.)  Cached values are inserted into the table using soft or hard refs, depending on NO_SOFT_CACHE.  They are extracted in a robust way, using instanceof, which is good.  There is no plan for converting hard to soft refs, which is probably OK; we can fix this later if we need to.

If we have a sudden flash of insight how to support AOT of soft references (SRs), then this PR goes away.  Otherwise, I have one request, related to MethodHandleStatics.  I think we should be moving towards respecting the finals of that class, like any other class, as AOT-able values.  Using just one static as a secret channel for AOT logic is too edgy for my taste.

First, `NO_SOFT_CACHE should probably be a @Stable variable, not a final, so it can be patched.  And it should be inverted:  `@Stable boolean USE_SOFT_CACHES`.  When the VM goes to the right init-phase (but never during assembly phase), that boolean should be set true, and it will act like a constant true boolean forever after.

Also, consider moving it (as a stable non-final) to `MethodHandleNatives`, since its state depends on stuff below the level of Java proper.  I think `MethodHandleStatics` stuff has a different area of responsibility than `USE_SOFT_CACHES`.

-------------

PR Comment: https://git.openjdk.org/jdk/pull/21049#issuecomment-2403478570


More information about the core-libs-dev mailing list