On Thu, 23 May 2024 03:35:19 GMT, Ioi Lam <ik...@openjdk.org> wrote:

>> ### Overview
>> 
>> This PR archives `CONSTANT_FieldRef` entries in the _resolved_ state when 
>> it's safe to do so.
>> 
>> I.e., when a `CONSTANT_FieldRef` constant pool entry in class `A` refers to 
>> a *non-static* field `B.F`, 
>> - `B` is the same class as `A`; or
>> - `B` is a supertype of `A`; or
>> - `B` is one of the 
>> [vmClasses](https://github.com/openjdk/jdk/blob/3d4185a9ce482cc655a4c67f39cb2682b02ae4fe/src/hotspot/share/classfile/vmClasses.hpp),
>>  and `A` is loaded by the boot class loader.
>> 
>> Under these conditions, it's guaranteed that whenever `A` tries to use this 
>> entry at runtime, `B` is guaranteed to have already been resolved in A's 
>> system dictionary, to the same value as resolved during dump time.
>> 
>> Therefore, we can safely archive the `ResolvedFieldEntry` in class `A` that 
>> refers to `B.F`.
>> 
>> (Note that we do not archive the `CONSTANT_FieldRef` entries for static 
>> fields, as the resolution of such entries can lead to class initialization 
>> at runtime. We plan to handle them in a future RFE.)
>> 
>> ### Static CDS Archive
>> 
>> This feature is implemented in three steps for static CDS archive dump:
>> 
>> 1. At the end of the training run, `ClassListWriter` iterates over all 
>> loaded classes and writes the indices of their resolved `Class` and 
>> `FieldRef` constant pool entries into the classlist file, with the `@cp` 
>> prefix. E.g., the following means that the constant pool entries at indices 
>> 2, 19 and 106 were resolved during the training run:
>> 
>> @cp java/util/Objects 2 19 106
>> 
>> 2. When creating the static CDS archive from the classlist file, 
>> `ClassListParser` processes the `@cp` entries and resolves all the indicated 
>> entries. 
>>  
>> 3. Inside the `ArchiveBuilder::make_klasses_shareable()` function,  we 
>> iterate over all entries in all archived `ConstantPools`. When we see a  
>> _resolved_ entry that does not  satisfy the safety requirements as stated in 
>> _Overview_, we revert it back to the unresolved state.
>> 
>> ### Dynamic CDS Archive
>> 
>> When dumping the dynamic CDS archive, `ClassListWriter` and 
>> `ClassListParser` are not used, so steps 1 and 2 are skipped. We only 
>> perform step 3 when the archive is being written.
>> 
>> ### Limitations
>> 
>> - For safety, we limit this optimization to only classes loaded by the boot, 
>> platform, and app class loaders. This may be relaxed in the future.
>> - We archive only the constant pool entries that are actually resolved 
>> during the training run. We don't speculatively resolve other entries, as 
>> doing so may cause C2 to...
>
> 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 two additional commits since the 
> last revision:
> 
>  - Merge branch 'master' into 8293980-resolve-fields-at-dumptime
>  - 8293980: Resolve CONSTANT_FieldRef at CDS dump time

After making a quick first pass over this, I have some comments about the 
constant pool and cpcache code.

src/hotspot/share/oops/constantPool.cpp line 301:

> 299:   objArrayOop rr = resolved_references();
> 300:   if (rr != nullptr) {
> 301:     ConstantPool* orig_pool = 
> ArchiveBuilder::current()->get_source_addr(this);

Are the changes below necessary? I think the original was fine but I may be 
missing the point of this change.

src/hotspot/share/oops/constantPool.cpp line 464:

> 462:   if (cache() != nullptr) {
> 463:     // cache() is null if this class is not yet linked.
> 464:     remove_resolved_field_entries_if_non_deterministic();

These methods look like they can belong to the constant pool cache instead. Can 
cpCache call the ClassLinker code instead so this can be part of 
`cache()->remove_unshareable_info()`?

src/hotspot/share/oops/constantPool.cpp line 520:

> 518:       int cp_index = rfi->constant_pool_index();
> 519:       bool archived = false;
> 520:       bool resolved = rfi->is_resolved(Bytecodes::_putfield)  ||

Is one of these meant to be `is_resolved(Bytecodes::get_field)` ?

src/hotspot/share/oops/resolvedFieldEntry.hpp line 65:

> 63:     _tos_state = other._tos_state;
> 64:     _flags = other._flags;
> 65:     _get_code = other._get_code;

The fields `_get_code` and `_put_code` are normally set atomically, does this 
need to be the case when copying as well?

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

PR Review: https://git.openjdk.org/jdk/pull/19355#pullrequestreview-2074929387
PR Review Comment: https://git.openjdk.org/jdk/pull/19355#discussion_r1612265561
PR Review Comment: https://git.openjdk.org/jdk/pull/19355#discussion_r1612288001
PR Review Comment: https://git.openjdk.org/jdk/pull/19355#discussion_r1612277435
PR Review Comment: https://git.openjdk.org/jdk/pull/19355#discussion_r1612261360

Reply via email to