[master] RFR: 8320761: [Lilliput] Implement compact identity hashcode [v3]
Roman Kennke
rkennke at openjdk.org
Wed Jan 22 12:07:16 UTC 2025
> This reimplements identity hash-code such that it allocates the space for the i-hash only on-demand. The idea is that most objects never get i-hashed, and therefore we don't want to penalize those objects which don't by carrying 32 unused bits for no reason.
>
> I'm proposing that we only reserve two bits in the header to track the state of an object:
>
> - One bit to indicate that an object has been i-hashed
> - Another bit to indicate that an object has been 'expanded' to hold the i-hash in a field.
>
> The transition would then be as follows:
> 1. Object starts out with state 00: not i-hashed, and not expanded.
> 2. The first time when Object.identityHashCode() is called, advance the state to 01 (i-hashed, but not expanded). Generate an i-hash based on the object's address, and return that.
> 3. Whenever Object.identityHashCode() is called in that state, and as long as that object stays at its address, keep generating the i-hash based on its address.
> 4. As soon as the object gets moved to a new address (by the GC), advance the state to 11 (i-hashed and expanded), generate the i-hash based on the original address one last time, and write it to the hidden field in the expanded object.
> 5. Whenever Object.identityHashCode() is called in that state, read the hidden field and return the i-hashed that has been stored there.
>
> Transitioning to the 'expanded' state does not necessarily mean that the object actually needs to be expanded. The offset of the hidden field for any class is computed at class-loading-time. That field may fit into any gaps in the field layout, including alignment gaps at the end of an object. Only when no such gaps are found, we need to actually expand the object during GC. That appears to happen approx 50% of the time.
>
> For a discussion why it is not a problem to expand objects during GC, see here: [https://wiki.openjdk.org/display/lilliput/Compact+Identity+Hashcode](https://wiki.openjdk.org/display/lilliput/Compact+Identity+Hashcode)
>
> One caveat is that ParallelGC is currently does not supported. Parallel's full-GC precalculates block sizes based on the assumption that objects don't grow. I will propose a fix for this as a follow-up, but it's likely a somewhat complex change.
>
> I ran some I-hash heavy benchmarks (e.g. SPECjvm compiler benchmarks), and have not seen a performance difference. It would be nice to make some micro-benchmarks for the various scenarios (e.g. is it faster to compute the i-hash or read it from memory?), and compare that with the ...
Roman Kennke has updated the pull request incrementally with one additional commit since the last revision:
Cast size_t to int
-------------
Changes:
- all: https://git.openjdk.org/lilliput/pull/192/files
- new: https://git.openjdk.org/lilliput/pull/192/files/5d693277..42b53dae
Webrevs:
- full: https://webrevs.openjdk.org/?repo=lilliput&pr=192&range=02
- incr: https://webrevs.openjdk.org/?repo=lilliput&pr=192&range=01-02
Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
Patch: https://git.openjdk.org/lilliput/pull/192.diff
Fetch: git fetch https://git.openjdk.org/lilliput.git pull/192/head:pull/192
PR: https://git.openjdk.org/lilliput/pull/192
More information about the lilliput-dev
mailing list