RFR: JDK-8311035: CDS should not use dump time JVM narrow Klass encoding to pre-compute Klass ids
Thomas Stuefe
stuefe at openjdk.org
Fri Jun 30 07:03:06 UTC 2023
On Wed, 28 Jun 2023 15:48:01 GMT, Ioi Lam <iklam at openjdk.org> wrote:
>> I recently spent a day trying to understand the interleaving of narrow Klass decoding with CDS. Thanks to @iklam for clarifying some details. This patch aims to make these interleavings easier to understand and more correct.
>>
>> ----
>>
>> CDS narrow Klass handling plays a role for archived heap objects.
>>
>> When dumping heap objects, we must recompute their narrow Klass ids since the relative positions of archived Klass instances change compared to their live counterparts in the dump time JVM.
>> We recompute those narrow Klass ids using the following encoding scheme:
>> - base = future assumed mapping start address
>> - shift = dump time (!) JVMs encoding shift (A)
>> see `ArchiveHeapWriter::update_header_for_requested_obj` https://github.com/openjdk/jdk/blob/c3f10e847999ec254893de5a1a5de32fd07f715a/src/hotspot/share/cds/archiveHeapWriter.cpp#L419-L425
>>
>> At CDS runtime, we load the CDS archive, then place the class space behind it. We then initialize narrow Klass encoding for the resulting combined Klass range such that:
>> - encoding base is the range start address (mapping base)
>> - encoding shift is always zero
>> see `CompressedKlassPointers::initialize` : https://github.com/openjdk/jdk/blob/c3f10e847999ec254893de5a1a5de32fd07f715a/src/hotspot/share/oops/compressedOops.cpp#L195-L231
>>
>> The lengthy comment there is misleading and partly wrong (regrettable since it was mine :)
>>
>> At dump time, when initializing the JVM, we also set the encoding base to klass range start and shift to zero (also `CompressedKlassPointers::initialize`). That is the shift we later use for (A); hence, that shift is zero.
>>
>> -------------------
>>
>> There are some small things wrong with the current code. That wrongness does not lead to errors but makes understanding the code difficult.
>>
>> Mainly, the *dump time* VM's narrow Klass encoding scheme is irrelevant for the encoding employed on the future runtime archive since we recalculate the narrow Klass ids for archived heap objects. That means:
>>
>> In `CompressedKlassPointers::initialize` there is no need to fix the encoding base and shift for the *dump time* JVM. Dump time JVM can use whatever base+shift it pleases; it can use the same code path as when CDS is off (e.g. use zero-based encoding).
>>
>> In `ArchiveHeapWriter::update_header_for_requested_obj`, we should not use the dump time JVM shift for pre-computing the narrow Klass ids. Instead, we should use the *minimal shift needed for the maximal possible futu...
>
> Hi Thomas, thanks for doing the clean up.
>
> I am not quite sure about the meaning of `precomputed_narrow_klass_base_delta`. Is it intended to be used for Lilliput, where a non-zero value may be used?
>
> Since it's hard-coded to zero now, it's hard to observe how it would affect the calculation.
>
> Before Liliput:
>
> At dump time, all narrowKlass values are updated to be relative to `_requested_static_archive_bottom`, with `ArchiveHeapWriter::precomputed_narrow_klass_shift` (which is hard coded to zero)
>
> At runtime, we always set `CompressedKlassPointers::base()` to `header()->mapped_base_address()` in here:
>
> https://github.com/openjdk/jdk/blob/46e4ee1e80652203bd59d968ea72b27681bdf312/src/hotspot/share/cds/metaspaceShared.cpp#L1149
>
> Currently it's impossible to set an alternative `CompressedClassSpaceBaseAddress` when using CDS:
>
>
> develop(size_t, CompressedClassSpaceBaseAddress, 0, \
> "Force the class space to be allocated at this address or " \
> "fails VM initialization (requires -Xshare=off.") \
>
>
> Also we will always have zero shifts, as we don't allow CompressedClassSpaceSize to be larger than 3G:
>
>
> product(size_t, CompressedClassSpaceSize, 1*G, \
> "Maximum size of class area in Metaspace when compressed " \
> "class pointers are used") \
> range(1*M, 3*G) \
> \
>
>
> This means we can actually always use the archived Java objects, and this "if" block can be turned into an assert
>
>
> if (archive_narrow_klass_base != CompressedKlassPointers::base() ||
> narrow_klass_shift() != CompressedKlassPointers::shift()) {
> log_info(cds)("CDS heap data cannot be used because the archive was created with an incompatible narrow klass encoding mode.");
> return false;
>
>
> I think for the current implementation, we might as well get rid of these fields in filemap.hpp.
>
>
> size_t _narrow_klass_base_delta; // narrow Klass base and shift used to pre-calculate nKlass ids
> int _narrow_klass_shift; // in archived objects (see comment in archiveHeapWriter.hpp)
>
>
> Having them there will create more confusion. They may be useful for the future, but it's hard to understand how these fields would be used without implementing the "future" :-)
@iklam : I removed the "delta" constant and replaced it with hopefully clear comments. I also removed the narrow_klass_xxx fields from FileMap. And translated runtime fail conditions to asserts in FileMapInfo::can_use_heap_region().
-------------
PR Comment: https://git.openjdk.org/jdk/pull/14688#issuecomment-1614217691
More information about the hotspot-dev
mailing list