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 284: > 282: > 283: static final HashMap<Test,HashMap<Result,String>> INTERESTING = new > HashMap<>(); > 284: // The "interesting" thing is an anomaly where a bad heap // byte (poked in by Unsafe::putByte) comes back as a bad // boolean (unsigned byte, no sign extension). When the // anomaly is absent, the `x&1` normalization was applied // by the interpreter or by the compiled code. When // present, the compiler has optimized away the &1 in // x&1, on the grounds that it clearly sees a load from a // Java-heap boolean variable (field or array element), // which can never ever be anything other than 0 or 1. // Unless some buffoon called Unsafe::putByte to poke in // something else. We are emulating such buffoons, to // make sure their damage would be somewhat limited. // // This anomaly only occurs for a constant reference to a // container (instance or array) and a strongly-typed // variable in that container (boolean field or element). // Thus, if the container is off-heap, or the reference // is not not strongly typed, or if it is typed but the // poked byte is in a non-boolean variable (a // "mismatch"), then the x&1 normalization is retained in // the compiled code. We test the strongly-typed case by // binding the container object (instance or array) as a // constant into the test loop (using insertArguments). ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/31249#discussion_r3321086281
