On Thu, 28 May 2026 21:56:58 GMT, Vladimir Ivanov <[email protected]> wrote:
>> On bytecode level booleans are represented as ints and HotSpot JVM >> normalizes boolean values on memory accesses. It unconditionally applies >> normalization on boolean stores, but trusts on-heap boolean locations to >> hold normalized values. Normalization is applied on loads for off-heap and >> mismatched unsafe accesses . >> >> There are 2 normalization procedures used: (1) cast int to byte and test it >> against zero; and (2) truncation to least-significant bit. Truncation is >> preferred (due to performance considerations), but JNI mandates testing >> against zero and, historically, `#1` was used for off-heap unsafe accesses >> as well. It complicated the implementation (leading to subtle bugs) and >> introduced divergence in behavior at runtime (depending on execution mode >> and JIT-compilation peculiarities). >> >> The fix uses truncation uniformly across all execution modes. It simplifies >> implementation and eliminates possible divergence in behavior between >> execution modes. Also, it drastically simplifies future Unsafe API >> refactorings. >> >> There's one scenario left when it's possible to observe non-normalized >> values: when mismatched access pollutes the Java heap with a bogus boolean >> value, but then the value is read with a well-typed boolean access. >> >> Testing: hs-tier1 - hs-tier6 >> >> - [x] I confirm that I make this contribution in accordance with the >> [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai). > > Vladimir Ivanov has updated the pull request incrementally with one > additional commit since the last revision: > > normalize_for_read/normalize_for_write => normalize test/hotspot/jtreg/compiler/unsafe/UnsafeBooleanTest.java line 32: > 30: * @modules java.base/jdk.internal.misc > 31: * java.base/jdk.internal.vm.annotation > 32: * @run main/bootclasspath/othervm -Xbatch ${test.main.class} Maybe add a second test, to get both MEMBAR settings? test/hotspot/jtreg/compiler/unsafe/UnsafeBooleanTest.java line 54: > 52: static final Unsafe UNSAFE = Unsafe.getUnsafe(); > 53: > 54: enum Mode { // The regression test uses only mode LSB. // See attached log files on JDK-8385119 for sample outputs from other modes. test/hotspot/jtreg/compiler/unsafe/UnsafeBooleanTest.java line 65: > 63: static final boolean VERBOSE = Boolean.getBoolean("VERBOSE"); > 64: static final boolean MEMBAR = > Boolean.parseBoolean(System.getProperty("MEMBAR", Boolean.TRUE.toString())); > 65: // The memory barrier, if present, disrupts certain optimizations // like store-to-load chaining. There must be no errors reported // in either setting, but the "interesting" anomalies might change. test/hotspot/jtreg/compiler/unsafe/UnsafeBooleanTest.java line 76: > 74: // unsafe.putBoolean(base, offset, value); > 75: // return unsafe.getByte(base, offset); > 76: // } // That is, write a normalized 0/1, then read whatever byte appeared in memory. test/hotspot/jtreg/compiler/unsafe/UnsafeBooleanTest.java line 82: > 80: // unsafe.putByte(base, offset, value); > 81: // return unsafe.getBoolean(base, offset); > 82: // } // That is, smash an arbitrary byte into memory (even if typed as a boolean), // then read as a boolean, normalizing the read byte to 0/1. test/hotspot/jtreg/compiler/unsafe/UnsafeBooleanTest.java line 88: > 86: // unsafe.putBoolean(base, offset, value); > 87: // return unsafe.getBoolean(base, offset); > 88: // } // That is, write a normalized 0/1 byte, then normalize again on read. // This is the safest route. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/31249#discussion_r3321010161 PR Review Comment: https://git.openjdk.org/jdk/pull/31249#discussion_r3321002330 PR Review Comment: https://git.openjdk.org/jdk/pull/31249#discussion_r3321013899 PR Review Comment: https://git.openjdk.org/jdk/pull/31249#discussion_r3321017008 PR Review Comment: https://git.openjdk.org/jdk/pull/31249#discussion_r3321020995 PR Review Comment: https://git.openjdk.org/jdk/pull/31249#discussion_r3321023464
