Skip to content

Fix #5208: Introduce raw floating point bit manipulation. #5209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 14, 2025

Conversation

sjrd
Copy link
Member

@sjrd sjrd commented Jul 12, 2025

We repurpose the previous opcodes to mean the raw variants. They do not provide any guarantee for the NaN bit patterns (other than being one of the NaN patterns, obviously).

We now implement the canonicalizing variants in user-space on top of the raw variants.

On Wasm, we had to do that anyway, except the "user-space" was in the function emitter. On JavaScript, despite the spec "suggesting" that NaN's be canonicalized, real-world engines do not canonicalize all NaN's. Doing it in user-space is the only reliable way to guarantee our spec.


We replace usages of the canonicalizing variants by raw variants in the low-level javalib methods where we can. Either they are in code paths where NaN's have been excluded, or where it does not actually matter what bit pattern we receive for NaN's. This allows not to regress on performance and code size for some low-level methods. Unfortunately, Double.hashCode does require one more branch, but that is inevitable to guarantee the correct semantics.

ByteBuffer methods putFloat and putDouble do not specify the bit patterns of NaNs, and experimentally, I was able to observe non-canonical bit patterns on the JVM. So in that case, we also use the raw variants, which is consistent with using the DataView methods in TypedArray-backed byte buffers.

@sjrd sjrd requested a review from gzm0 July 12, 2025 20:05
@sjrd sjrd force-pushed the really-canonicalize-nan-bit-patterns branch 2 times, most recently from 53d2535 to 8d07f6f Compare July 13, 2025 08:52
Copy link
Contributor

@gzm0 gzm0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a readability suggestion (optional).

valueInt
else if (isNaNBitPattern(bits))
Long.hashCode(0x7ff8000000000000L)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the canonicalized NaN bit pattern a constant for readability?

@inline def floatToIntBits(value: scala.Float): scala.Int = {
val rawBits = floatToRawIntBits(value)
if (isNaNBitPattern(rawBits))
0x7fc00000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same: Make this a compile time constant for readability?

We repurpose the previous opcodes to mean the raw variants. They
do not provide any guarantee for the NaN bit patterns (other than
being one of the NaN patterns, obviously).

We now implement the canonicalizing variants in user-space on top
of the raw variants.

On Wasm, we had to do that anyway, except the "user-space" was in
the function emitter. On JavaScript, despite the spec "suggesting"
that NaN's be canonicalized, real-world engines do not canonicalize
all NaN's. Doing it in user-space is the only reliable way to
guarantee our spec.

---

We replace usages of the canonicalizing variants by raw variants in
the low-level javalib methods where we can. Either they are in code
paths where NaN's have been excluded, or where it does not actually
matter what bit pattern we receive for NaN's. This allows not to
regress on performance and code size for some low-level methods.
Unfortunately, `Double.hashCode` does require one more branch, but
that is inevitable to guarantee the correct semantics.

`ByteBuffer` methods `putFloat` and `putDouble` do not specify the
bit patterns of `NaN`s, and experimentally, I was able to observe
non-canonical bit patterns on the JVM. So in that case, we also use
the raw variants, which is consistent with using the `DataView`
methods in `TypedArray`-backed byte buffers.
@sjrd sjrd force-pushed the really-canonicalize-nan-bit-patterns branch from 8d07f6f to 47498f2 Compare July 14, 2025 09:05
@sjrd sjrd enabled auto-merge July 14, 2025 09:07
@sjrd sjrd merged commit 849495b into scala-js:main Jul 14, 2025
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy