On Thu, 21 May 2026 21:42:49 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). This PR deletes some unmaintainable code which nobody understands. Turns out nobody understands it because it is trying to do something that is impossible, and is therefore partially incorrect. The root cause is a poor choice (made years ago by me and others) to try to use two different conventions for cleaning booleans. It was never a good idea and has aged poorly. FTR, you don't change the JNI behavior per se, you just stop adopting it in places where it was not specified (and is not easy to implement consistently). The JNI behavior applies when returning a `jboolean` from a C-coded native method. The JNI designers had to define some specific rule, and the `x!=0` rule is it. The `x&1` rule would have been faster and less sensitive to word-size issues, but an extra test on a JNI native call is totally in the noise. The bug here is trying to cross-apply the `x!=0` rule to other contexts, where it can be a slowdown, and it interferes with the competing rule `x&1`. Regarding that “one scenario left”: It is poking a bad byte into a Java heap boolean, and then reading the boolean under the uniform assumption that nobody pokes any bad bytes into Java heap booleans. There’s no way to recover from such a poke, just as there’s no way to recover from poking a byte into the middle of a managed pointer. You can use Unsafe to break the VM. The only way to recover would be to normalize all heap boolean accesses, which has a performance cost that we have chosen to avoid. There seem to be some bugs and/or inefficiencies in the new jtreg test; will comment on the file. This is very welcome work! ------------- PR Comment: https://git.openjdk.org/jdk/pull/31249#issuecomment-4526658948
