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

Reply via email to