On Wed, 11 Mar 2026 17:00:03 GMT, Joe Darcy <[email protected]> wrote:
>> FloatEntryImpl.equals() and DoubleEntryImpl.equals() used == for comparison, >> which returns false for NaN == NaN per IEEE 754. This caused two different >> FloatEntry/DoubleEntry objects holding NaN to not be considered equal, >> violating the equals/hashCode contract (same hashCode but equals returns >> false). >> >> Similarly, SplitConstantPool.findFloatEntry() and findDoubleEntry() used == >> to match values, so NaN entries could never be found in the pool, causing >> every floatEntry(Float.NaN) or doubleEntry(Double.NaN) call to create a >> duplicate entry and bloat the constant pool. >> >> Fix by using Float.floatToRawIntBits() and Double.doubleToRawLongBits() for >> bitwise comparison, which correctly handles NaN and also properly >> distinguishes +0.0 from -0.0. > > FYI, this discussion in Double about representation equivalence vs bit-wise > equivalence may be useful here: > https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/lang/Double.html#equivalenceRelation > HTH Thanks for the pointer, @jddarcy! I chose floatToRawIntBits / doubleToRawLongBits (bit-wise equivalence) because constant pool entries correspond to exact byte sequences in the class file — different NaN bit patterns produce different bytes and should be distinct entries. That said, floatToIntBits / doubleToLongBits (representation equivalence) would also be a reasonable choice here, since non-canonical NaN values are extremely rare in practice, and it would be consistent with the hashCode implementation which already uses Float.hashCode() → floatToIntBits. I'm happy to switch to floatToIntBits / doubleToLongBits if you think representation equivalence is more appropriate for this use case. ------------- PR Comment: https://git.openjdk.org/jdk/pull/30196#issuecomment-4042900429
