Skip to content

8311071: Avoid SoftReferences in LambdaFormEditor and MethodTypeForm when storing heap objects into AOT cache#21049

Closed
iklam wants to merge 18 commits intoopenjdk:pr/20959from
iklam:jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
Closed

8311071: Avoid SoftReferences in LambdaFormEditor and MethodTypeForm when storing heap objects into AOT cache#21049
iklam wants to merge 18 commits intoopenjdk:pr/20959from
iklam:jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke

Conversation

@iklam
Copy link
Member

@iklam iklam commented Sep 17, 2024

This is the 6th PR for JEP 483: Ahead-of-Time Class Loading & Linking.

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, 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 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.


See here for the sequence of dependent RFEs for implementing JEP 483.


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Integration blocker

 ⚠️ Dependency #20959 must be integrated first

Issue

  • JDK-8311071: Avoid SoftReferences in LambdaFormEditor and MethodTypeForm when storing heap objects into AOT cache (Enhancement - P4)

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/21049/head:pull/21049
$ git checkout pull/21049

Update a local copy of the PR:
$ git checkout pull/21049
$ git pull https://git.openjdk.org/jdk.git pull/21049/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 21049

View PR using the GUI difftool:
$ git pr show -t 21049

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/21049.diff

Webrev

Link to Webrev Comment

iklam added 5 commits August 27, 2024 20:29
…s' of /jdk3/yak/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
…s' of /jdk3/yak/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
@bridgekeeper
Copy link

bridgekeeper bot commented Sep 17, 2024

👋 Welcome back iklam! A progress list of the required criteria for merging this PR into pr/20959 will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Sep 17, 2024

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk
Copy link

openjdk bot commented Sep 17, 2024

@iklam The following label will be automatically applied to this pull request:

  • core-libs

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the core-libs core-libs-dev@openjdk.org label Sep 17, 2024
@iklam iklam marked this pull request as ready for review September 17, 2024 23:54
@openjdk openjdk bot added the rfr Pull request is ready for review label Sep 17, 2024
@mlbridge
Copy link

mlbridge bot commented Sep 17, 2024

Copy link
Member

@dholmes-ora dholmes-ora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems quite reasonable for dumping the static archive.

A couple of typos.

Thanks

…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
@openjdk
Copy link

openjdk bot commented Sep 18, 2024

⚠️ @iklam This pull request contains merges that bring in commits not present in the target repository. Since this is not a "merge style" pull request, these changes will be squashed when this pull request in integrated. If this is your intention, then please ignore this message. If you want to preserve the commit structure, you must change the title of this pull request to Merge <project>:<branch> where <project> is the name of another project in the OpenJDK organization (for example Merge jdk:master).

@openjdk openjdk bot removed the rfr Pull request is ready for review label Sep 18, 2024
…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
@openjdk openjdk bot added the rfr Pull request is ready for review label Sep 18, 2024
Copy link
Member

@cl4es cl4es left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does archiving and resolution of the linked MethodType instances work? In particular how does archiving fill up the MethodType::internTable to ensure MethodType uniqueness?

…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
@iklam
Copy link
Member Author

iklam commented Sep 23, 2024

How does archiving and resolution of the linked MethodType instances work? In particular how does archiving fill up the MethodType::internTable to ensure MethodType uniqueness?

The details are in the next PR (#21143) which is still in draft state.

At the end of AOT cache assembly phase, the JVM (in MetaspaceShared::preload_and_dump_impl(()) upcalls MethodType::createArchivedObjects() to copy all MethodTypes into a side table (MethodType::AOTHolder::archivedMethodTypes).

During the production run, we first look up from the side table, before checking/interning in the main table.

…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
Copy link
Contributor

@iwanowww iwanowww left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, looks good.

@rose00
Copy link
Contributor

rose00 commented Oct 9, 2024

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.

@rose00
Copy link
Contributor

rose00 commented Oct 10, 2024

Here is a more extensive example of using stable variables to split a single class initializer into multiple phases:

https://cr.openjdk.org/~jrose/leyden/SplitInitsWithStableFields.java

iklam added 2 commits October 14, 2024 16:27
…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
…ndleNatives as a @stable field; use system prop for init
@iklam
Copy link
Member Author

iklam commented Oct 15, 2024

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.

Hi John, I've moved the variable to MethodHandleNatives as static @Stable boolean USE_SOFT_CACHE. Please let me know if it looks good to you.

Copy link
Member

@liach liach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The updated version using MH natives flag looks good.

…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
Copy link
Member

@dholmes-ora dholmes-ora left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still LGTM.

Thanks

@iwanowww
Copy link
Contributor

Still looks good except @Stable on USE_SOFT_CACHE. As it is implemented now, I don't see any point in dropping final in favor of @Stable since it is initialized only once and only from static initializer.

@iklam I'd be surprised if this class is AOT-initialized. I hope it's not the case here.

iklam added 2 commits October 21, 2024 13:34
…s' of /jdk3/yam/open into jep-483-step-06-8311071-avoid-soft-refs-in-java-lang-invoke
@iklam
Copy link
Member Author

iklam commented Oct 22, 2024

Closing this PR as its changes have been combined into #21642.

@iklam iklam closed this Oct 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core-libs core-libs-dev@openjdk.org rfr Pull request is ready for review

Development

Successfully merging this pull request may close these issues.

6 participants