JDK-8350896 : Integer/Long.compress gets wrong type from CompressBitsNode::Value
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 19,21,24,25
  • Priority: P2
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2025-02-27
  • Updated: 2025-06-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 25
25Unresolved
Related Reports
Causes :  
Description
I found this during work with the Template Framework JDK-8344942.

[~thartmann] found it was a regression of JDK-8283894, which was my suspicion after tracing it back to code in CompressBitsNode::Value and more specifically bitshuffle_value, on this line:

hi = mask_max_bw < max_bw ? (1L << mask_max_bw) - 1 : src_type->hi_as_long();

Reproduce the result like this:

java -Xbatch -XX:CompileCommand=compileonly,Test::test -XX:+PrintIdeal Test.java
CompileCommand: compileonly Test.test bool compileonly = true
AFTER: print_ideal
  0  Root  === 0 28  [[ 0 1 3 21 ]] inner 
  3  Start  === 3 0  [[ 3 5 6 7 8 9 ]]  #{0:control, 1:abIO, 2:memory, 3:rawptr:BotPTR, 4:return_address}
  5  Parm  === 3  [[ 28 ]] Control !jvms: Test::test @ bci:-1 (line 26)
  6  Parm  === 3  [[ 28 ]] I_O !jvms: Test::test @ bci:-1 (line 26)
  7  Parm  === 3  [[ 28 ]] Memory  Memory: @BotPTR *+bot, idx=Bot; !jvms: Test::test @ bci:-1 (line 26)
  8  Parm  === 3  [[ 28 ]] FramePtr !jvms: Test::test @ bci:-1 (line 26)
  9  Parm  === 3  [[ 28 ]] ReturnAdr !jvms: Test::test @ bci:-1 (line 26)
 21  ConI  === 0  [[ 28 ]]  #int:min
 28  Return  === 5 6 7 8 9 returns 21  [[ 0 ]] 
Exception in thread "main" java.lang.RuntimeException: Bad value: -2147483648 0
	at Test.main(Test.java:36)

We can see from the PrintIdeal, that the Integer.compress has been constant folded to the wrong value.


------------------------------------------------------------- The identical issue exists for long:

./java -Xbatch -XX:CompileCommand=compileonly,TestL::test -XX:+PrintIdeal TestL.java
CompileCommand: compileonly TestL.test bool compileonly = true
AFTER: print_ideal
  0  Root  === 0 28  [[ 0 1 3 21 ]] inner 
  3  Start  === 3 0  [[ 3 5 6 7 8 9 ]]  #{0:control, 1:abIO, 2:memory, 3:rawptr:BotPTR, 4:return_address}
  5  Parm  === 3  [[ 28 ]] Control !jvms: TestL::test @ bci:-1 (line 7)
  6  Parm  === 3  [[ 28 ]] I_O !jvms: TestL::test @ bci:-1 (line 7)
  7  Parm  === 3  [[ 28 ]] Memory  Memory: @BotPTR *+bot, idx=Bot; !jvms: TestL::test @ bci:-1 (line 7)
  8  Parm  === 3  [[ 28 ]] FramePtr !jvms: TestL::test @ bci:-1 (line 7)
  9  Parm  === 3  [[ 28 ]] ReturnAdr !jvms: TestL::test @ bci:-1 (line 7)
 21  ConL  === 0  [[ 28 ]]  #long:min
 28  Return  === 5 6 7 8 9 returns 21  [[ 0 ]] 
Exception in thread "main" java.lang.RuntimeException: Bad value: -9223372036854775808 0
	at TestL.main(TestL.java:17)
Comments
Even "simple" partial evaluation expressions in C2 methods are subject to hidden flaws due to C++ UB surprises. This is why, some day, I think all C2 compile-time arithmetic should be performed by a separately curated arithmetic engine. Not be ad hoc C++ expressions mixed into the optimizer. By "arithmetic" I include arithmetic not only against single values, but also against subsets of their types, when those subsets are relevant to C2. That includes signed min/max ranges, and probably unsigned umin/umax ranges, and/or bitwise up/down masks. Most of the relevant formulas are well-known and testable, and have been on the record for a long time. By "separately curated" I mean a C++ interface (for long and its subranges at least) which is sepaartely reviewed by arithmetic experts, and separately stress-tested (for all corner cases) by a gtest (in jtreg format in the source repo).
03-06-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/23947 Date: 2025-03-07 17:37:36 +0000
07-03-2025

Bit compressing an integral value squeezes bits corresponding to the set mask bits. Here, we have a limiting case of constant input and variable mask where input is the min_integral value and range computation results into assignment of min_integral value to both the delimiting values, i.e., TypeInt.lo and TypeInt.hi and thus resulting into incorrect constant folding.
05-03-2025

Thanks [~thartmann] I will take a look
04-03-2025

[~sviswanathan], [~jbhateja], could you please have a look?
28-02-2025

ILW = Incorrect result of C2 compiled code, easy to reproduce but edge case, -XX:DisableIntrinsic=_compress_i,_compress_l = HML = P2
28-02-2025