On Wed, 15 Oct 2025 15:20:27 GMT, Erik Österlund <[email protected]> wrote:
>> This is the implementation of JEP 516: Ahead-of-Time Object Caching with Any
>> GC.
>>
>> The current mechanism for the AOT cache to cache heap objects is by using
>> mmap to place bytes from a file directly in the GC managed heap. This
>> mechanism poses compatibility challenges that all GCs have to have bit by
>> bit identical object and reference formats, as the layout decisions are
>> offline. This has so far meant that AOT cache optimizations requiring heap
>> objects are not available when using ZGC. This work ensures that all GCs,
>> including ZGC, are able to use the more advanced AOT cache functionality
>> going forward.
>>
>> This JEP introduces a new mechanism for archiving a primordial heap, without
>> such compatibility problems. It embraces online layouts and allocates
>> objects one by one, linking them using the Access API, like normal objects.
>> This way, archived objects quack like any other object to the GC, and the GC
>> implementations are decoupled from the archiving mechanism.
>>
>> The key to doing this GC agnostic object loading is to represent object
>> references between objects as object indices (e.g. 1, 2, 3) instead of raw
>> pointers that we hope all GCs will recognise the same. These object indices
>> become the key way of identifying objects. One table maps object indices to
>> archived objects, and another table maps object indices to heap objects that
>> have been allocated at runtime. This allows online linking of the
>> materialized heap objects.
>>
>> The main interface to the cached heap is roots. Different components can
>> register object roots at dump time. Each root gets assigned a root index. At
>> runtime, requests can be made to get a reference to an object at a root
>> index. The new implementation uses lazy materialization and concurrency.
>> When a thread asks for a root object, it must ensure that the given root
>> object and its transitively reachable objects are reachable. A new
>> background thread called the AOTThread, tries to perform the bulk of the
>> work, so that the startup impact of processing the objects one by one is not
>> impacting the bootstrapping thread.
>>
>> Since the background thread performs the bulk of the work, the archived is
>> laid out to ensure it can run as fast as possible.
>> Objects are laid out inf DFS pre order over the roots in the archive, such
>> that the object indices and the DFS traversal orders are the same. This way,
>> the DFS traversal that the background thread is performing is the same order
>> as linearly materializing the objects one by one in the or...
>
> Erik Österlund has updated the pull request incrementally with four
> additional commits since the last revision:
>
> - Dont print error message when there are no archived objects
> - Fix issue in new test
> - Change is_aot_thread implementation
> - update AotJdk problem lists
Hi Eric, looks very good overall.
I have gone through some of the code and have some comments. More to come.
src/hotspot/share/cds/cds_globals.hpp line 79:
> 77: "the CDS archive, in the specified file")
> \
> 78:
> \
> 79: product(bool, AOTStreamableObjects, true,
> \
The default should be `false`, as that will be the mode that the user will get
with no GC options are specified.
src/hotspot/share/cds/heapShared.cpp line 355:
> 353: }
> 354:
> 355: bool HeapShared::is_loading_mapping_mode() {
I think `is_loading_mapping_mode()` should be removed and we should use only
`is_loading_streaming_mode()`. This will make it easy to find all the places
that checks between mapping/streaming. Same for `is_writing_xxx_mode()`.
Also, instead of having a tri-state of `_heap_load_mode`, it's better to have
two boolean states:
- _is_loading_heap
- _is_loading_heap_streaming_mode
The first boolean is the main switch, but most of the code will be checking
only the second boolean.
src/hotspot/share/cds/heapShared.cpp line 410:
> 408: FLAG_SET_ERGO(AOTStreamableObjects, true);
> 409: _heap_write_mode = HeapArchiveMode::_streaming;
> 410: return;
This should be changed to `if (!UseZGC) {`, as all other GCs support writing
the "mapping" format.
src/hotspot/share/cds/heapShared.cpp line 418:
> 416:
> 417: // Select default mode
> 418: if (UseG1GC && UseCompressedOops) {
This is different than specified in JEP 516. The condition should be `if
(UseCompressedOops)`.
test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java line 117:
> 115: small2,
> 116: coops,
> 117: "-XX:-AOTStreamableObjects",
Is this change necessary?
test/hotspot/jtreg/runtime/cds/appcds/TestSerialGCWithCDS.java line 147:
> 145: // Regardless of which GC dumped the heap, there will be an
> object archive, either
> 146: // created with mapping if dumped with G1, or streaming if
> dumped with serial GC.
> 147: // At exec time, try to load them into a small SerialGC heap
> that may be too small.
Actually the original check of `dumpWithSerial == false` was obsolete, as
SerialGC can also dump heap objects. `dumpWithSerial == false` should be
removed. The first two lines of comments should also be removed.
-------------
PR Review: https://git.openjdk.org/jdk/pull/27732#pullrequestreview-3342741298
PR Review Comment: https://git.openjdk.org/jdk/pull/27732#discussion_r2434315273
PR Review Comment: https://git.openjdk.org/jdk/pull/27732#discussion_r2434294269
PR Review Comment: https://git.openjdk.org/jdk/pull/27732#discussion_r2434328432
PR Review Comment: https://git.openjdk.org/jdk/pull/27732#discussion_r2434316323
PR Review Comment: https://git.openjdk.org/jdk/pull/27732#discussion_r2434295055
PR Review Comment: https://git.openjdk.org/jdk/pull/27732#discussion_r2434331254