RFR: 8293187: Store initialized Enum classes in AOTCache [v3]

Ashutosh Mehra asmehra at openjdk.org
Tue Sep 17 20:36:08 UTC 2024


On Tue, 17 Sep 2024 00:02:19 GMT, Ioi Lam <iklam at openjdk.org> wrote:

>> This is the 4th PR for [JEP 483: Ahead-of-Time Class Loading & Linking](https://bugs.openjdk.org/browse/JDK-8315737).
>> 
>> **Problem:**
>> 
>> This PR is necessary to support [JDK-8293336: AOT-linking of invokedynamic for lambda expression and string concat](https://bugs.openjdk.org/browse/JDK-8293336), which needs to store [`sun.invoke.util.Wrapper`](https://github.com/openjdk/jdk/blob/c3711dc90980fb3e63ff199612c201c4464626bf/src/java.base/share/classes/sun/invoke/util/Wrapper.java) enums in the AOT cache. Although CDS has some limited support for storing enums, the `Wrapper` type is too complex for the existing solution to handle. Please see the JBS issue for details.
>> 
>> **Solution:**
>> 
>> In the assembly phase, we store the initialized states of the `Wrapper` class (captured in a `java.lang.Class` object, a.k.a. the *mirror* of this class) into the AOT cache. 
>> 
>> In production run, we no longer execute `Wrapper::<clinit>`, because all the static fields (contained in its mirror) are already initialized.
>> 
>> **Review Notes:**
>> 
>> - The new capability is controlled by `CDSConfig::is_initing_classes_at_dump_time()`. We can aot-initialize classes only if `-XX:+AOTClassLinking`  is enabled.
>>     - The old (more limited) support for enums is still there (it's required when `AOTClassLinking` is disabled). See the call to `CDSEnumKlass::handle_enum_obj()` in heapShared.cpp. 
>> - `AOTClassInitializer::can_archive_initialized_mirror()` decides what classes can be aot-initialized. This is currently a very small set of classes, but will expand in [JDK-8293336](https://bugs.openjdk.org/browse/JDK-8293336)
>> - Before, `HeapShared::archive_java_mirrors()` would clear out all the states in the archived mirrors. With this PR, the states of aot-initialized classes are preserved via `HeapShared::copy_aot_initialized_mirror()`.
>> - During the early state of the production run, `AOTLinkedClassBulkLoader::init_required_classes_for_loader()` is called to make sure that:
>>     - all aot-initialized classes are moved into the `initialized` state (without executing its `<clinit>` method). This is done in `InstanceKlass::initialize_from_cds()`
>>     - the classes of all the objects that are reachable from the aot-initialized mirrors are initialized. See comments above ` HeapShared::init_classes_reachable_from_archived_mirrors()` 
>> 
>> **Caveats:**
>> 
>> Not all Enum classes can be stored in the initialized state. E.g., some Enums might have static fields that depend on the e...
>
> Ioi Lam has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 11 commits:
> 
>  - Merge branch 'jep-483-step-03-8329706-implement-xx-aot-class-linking' of /jdk3/yak/open into jep-483-step-04-8293187-support-sun-invoke-util-wrapper-in-cds-archive-heap
>  - @vnkozlov comments
>  - Clean up; removed unrelated changes in classPrinter.cpp
>  - more cleanup
>  - Merge branch 'jep-483-step-03-8329706-implement-xx-aot-class-linking' of /jdk3/yak/open into jep-483-step-04-8293187-support-sun-invoke-util-wrapper-in-cds-archive-heap
>  - More clean up for JDK-8293187
>  - Merge branch 'jep-483-step-03-8329706-implement-xx-aot-class-linking' of /jdk3/yak/open into jep-483-step-04-8293187-support-sun-invoke-util-wrapper-in-cds-archive-heap
>  - Merge branch 'jep-483-step-03-8329706-implement-xx-aot-class-linking' into jep-483-step-04-8293187-support-sun-invoke-util-wrapper-in-cds-archive-heap
>  - Merge branch 'jep-483-step-03-8329706-implement-xx-aot-class-linking' into jep-483-step-04-8293187-support-sun-invoke-util-wrapper-in-cds-archive-heap
>  - Simplified implemented by AOTClassInitializer.
>  - ... and 1 more: https://git.openjdk.org/jdk/compare/bcddf963...e15e76cd

src/hotspot/share/cds/aotClassInitializer.cpp line 40:

> 38:     return true;
> 39:   } else if (ik->is_initialized() &&
> 40:              (ik->name()->equals("jdk/internal/constant/PrimitiveClassDescImpl") ||

Is it possible for one of these classes to be not initialized at this stage? IIUC `ik` must be initialized if it is one of these classes. In so, can `ik->is_initialized()` be turned into an assert?

src/hotspot/share/cds/heapShared.cpp line 996:

> 994: 
> 995:   assert( _runtime_default_subgraph_info != nullptr, "must be");
> 996:   Array<Klass*>* klasses = _runtime_default_subgraph_info->subgraph_object_klasses();

Couple of questions here:
1. Does `_runtime_default_subgraph_info` only hold archived mirrors? 

2. If we are init-ing classes required for archived mirrors here, why do we need special aot-initialization for `PrimitiveClassDescImpl`, `ReferenceClassDescImpl` and `ConstantDescs` in AOTClassInitializer::can_archive_initialized_mirror?

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

PR Review Comment: https://git.openjdk.org/jdk/pull/20958#discussion_r1763982914
PR Review Comment: https://git.openjdk.org/jdk/pull/20958#discussion_r1763982827


More information about the hotspot-dev mailing list