On Fri, 11 Sep 2026 07:18:40 GMT, Marc Chevalier <[email protected]> wrote:
>> The identity hash code of value objects currently can produce 0. A zero >> value is usually not anticipated for System.identityHashCode calls unless >> the argument is null; the 0 hash also cannot be cached. Thus, we should move >> away from the 0 hash. >> >> --------- >> - [x] I confirm that I make this contribution in accordance with the >> [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai). > > src/java.base/share/classes/java/lang/runtime/ValueObjectMethods.java line > 176: > >> 174: // to enable caching. The identity hash of the value class >> distinguishes >> 175: // different value classes and is easy for the compiler to >> fetch. >> 176: return (result & 0x7fffffff) == 0 ? typeHash : result; > > We need to check if the hash that will be retrieved later is null or not, but > between this return and the storage, the hash is masked to fit in the cache > of the mark word, which is at most 31 bits. So, 0x80_00_00_00 will also be > cut into a 0 hash. > > I made this masking here in a quick and dirty way: it assumes we will keep 31 > bits, which I think it wrong at least on 32 bits architectures (if I > understand the comments about the mark word correctly). Yet, I didn't manage > to get the mask from the VM as we do in Mark.java. So, this is to be fixed by > somebody who knows this side of JDK better than me. > > If we omit the masking here (and we do `result == 0`), then the test > `test/hotspot/jtreg/compiler/valhalla/valuetypes/TestHashcodeFastPath.java` > fails. Specifically the first instance of the assert > > Asserts.assertNE(h(would_have_zero_hashcode1), 0); > > since it actually runs fully in the interpreter (`h` is excluded and the > enclosing method is marked with `@Run`, so not compiled). > > Another option is not to do the filtering here, but somewhere around > https://github.com/openjdk/jdk/blob/e45a4e7a8514c1193e2ff92ead04630d93a760ec/src/hotspot/share/prims/jvm.cpp#L815 > in the caller, where we are in the C++ world and accessing the mask is easy > (but there, getting `System.identityHashCode(type)` is harder). Here's the markword format given in markWord.hpp: // Bit-format of an object header (most significant first, big endian layout below): // // 32 bits: // -------- // hash:25 age:4 self-fwd:1 lock:2 // // 64 bits (without compact headers): // ---------------------------------- // unused:22 hash:31 valhalla:4 age:4 self-fwd:1 lock:2 // // 64 bits (with compact headers): // ------------------------------- // klass:22 hash:31 valhalla:4 age:4 self-fwd:1 lock:2 ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/32660#discussion_r4027231866
