AOTHolder pattern for caching heap objects
Claes Redestad
claes.redestad at oracle.com
Thu Aug 29 17:39:59 UTC 2024
Hi,
I think everyone will be happy to see CDS.initializeFromArchive go!
Some random thoughts:
- Rather than hardcoding on AOTHolder should we put some internal marker annotation to signal intent? E.g @Archivable
- I wonder if this initialization indirection could be generalized using StableValues[1] - along with a marker annotation. That would feel very streamlined and avoid the need for most Holder classes (which is a design center of SVs).
/Claes
> 29 aug. 2024 kl. 19:10 skrev ioi.lam at oracle.com:
>
> For the development of JDK-8293336 [1], I am experimenting with a pattern of Java code to indicate what heap objects should be stored in the AOT cache. This code has been pushed to the premain branch.
>
> It looks like this [2]:
>
> class java.lang.invoke.MethodType {
>
> static class AOTHolder {
> private static final @Stable MethodType[] objectOnlyTypes = new MethodType[20];
> private static @Stable HashMap<MethodType,MethodType> archivedMethodTypes;
> }
>
> Essentially the class MethodType$AOTHolder will be stored in its "already initialized" state in the AOT cache. In the production run, MethodType$AOTHolder.<clinit> will NOT be run. Its static fields are already initialized and point to the objects that were created during the assembly phase.
>
> Currently, the JVM is hard-wired to recognize only a few known AOTHolder classes. This pattern is used strictly for the AOT-caching of MethodType.internTable.
>
> I want to hear people's reaction to this. I think other internal JDK classes can use a similar pattern as well.
>
> (In the long term, we will need a more generalized way (a.k.a. the "Scrambled Egg API"), but I need to have a mechanism that works for the short term).
>
> ***
>
> The reason I needed to use the AOTHolder pattern is to remove this horrible hack [3]. (It's now removed from the premain branch). You can see more info in the comments of [3], but the gist is:
>
> - The old way of CDS heap object caching depends on re-executing the <clinit> methods of classes that want to cache heap objects
>
> - These classes would call CDS.initializeFromArchive() to fetch the cached objects.
>
> - Before CDS.initializeFromArchive() returns the objects, it wants to initialize all the classes of these objects (or else the caller would end up with an object whose class is not yet initialized)
>
> - This scheme breaks down when several classes want to cache heap objects, and their <clinit> intertwine with each other.
>
> The old code in [3] tries to work around a NullPointerException that happens due to the intertwining. That is certainly not a sustainable approach.
>
> ***
>
> The AOTHolder pattern tries to accomplish two things
>
> - Clearly identify what objects should be AOT-cached. In the case of MethodType.java, I moved only two of its many fields into its AOTHolder inner class.
>
> - Cache the static fields in all the AOTHolder classes as a single snapshot. Avoid the need to run <clinit> so we don't need to worry about execution order, etc.
>
> ======
>
> [1] https://bugs.openjdk.org/browse/JDK-8293336
>
> [2] https://github.com/openjdk/leyden/blob/e33ecb3ec42d142569227b4bd1987124e5551cde/src/java.base/share/classes/java/lang/invoke/MethodType.java#L438-L441
>
> [3] https://github.com/openjdk/leyden/blob/3a84df9d9860e743684e335282e3910b14cc982b/src/hotspot/share/cds/heapShared.cpp#L1415-L1466
>
More information about the leyden-dev
mailing list