Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Remove all user-space asUint/toUint in the libraries. #5194

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 3 commits into from
Jun 22, 2025

Conversation

sjrd
Copy link
Member

@sjrd sjrd commented Jun 7, 2025

Instead, we use Integer.toUnsignedLong(x).toDouble, which is semantically equivalent. The only remaining use of x >>> 0 is in the JS-only runtime libraries, notably RuntimeLong.

We add some optimizations to generate the best possible code on all targets.

For JS with RuntimeLong, we need to mark RuntimeLong.toDouble as fully inline. That is fine, as its body is actually very short (shorter than most methods of RuntimeLong). Moreover, we need a tailored rewrite in the optimizer to get rid of a Double addition of 0.0 + y when y is provably non-negative.

For JS with bigints, we directly fold (double) <toLongUnsigned>(x) into x >>> 0. Otherwise, we unnecessarily go through a bigint with Number(BigInt(x >>> 0)).

For Wasm, we fold the same shape into a single operation f64.convert_i32_u, which we add in WasmTransients.

Overall, this has no real impact on the JS target. However, it removes two round-trips from Wasm to JS. Previously, we needed to call a helper function to do the x >>> 0, then call the $uD helper to retrieve the result. Now, the same operations stays entirely within Wasm.

@sjrd sjrd force-pushed the no-touint-in-lib branch 2 times, most recently from 7d70ace to 509e955 Compare June 8, 2025 09:08
@sjrd sjrd marked this pull request as ready for review June 8, 2025 09:08
@sjrd sjrd requested a review from gzm0 June 8, 2025 09:08
@sjrd
Copy link
Member Author

sjrd commented Jun 8, 2025

This will need a rebase on top of #5192 once it's merged, in order to also change the calls to toUint introduced there. Otherwise ready for review. Rebased.

@sjrd sjrd force-pushed the no-touint-in-lib branch from 509e955 to 4127fd9 Compare June 8, 2025 20:53
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.

The code in itself LGTM (modulo the minor comments).

What I'm not entirely clear about is why this is a desirable change. Could you add a comment about this in the PR description?

}

newTree match {
// Unless both arguments are (convertible to) bigint's, | always returns an Int
Copy link
Contributor

Choose a reason for hiding this comment

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

The "(convertible to)" feels confusing here. At least node seems to disallow any implicitness here:

> 1n | 1
Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
> 1n | "1"
Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

I assume this is specified?

Maybe also add "| always returns an Int or throws".

Copy link
Member Author

@sjrd sjrd Jun 18, 2025

Choose a reason for hiding this comment

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

I elaborated the comment. Primitive numbers cannot be mixed in this way, but objects with a valueOf() method returning a bigint can be converted to bigints.

@sjrd sjrd force-pushed the no-touint-in-lib branch from 4127fd9 to f377fbc Compare June 18, 2025 10:19
@sjrd sjrd requested a review from gzm0 June 18, 2025 10:21
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 typo.

/* Unless it throws, `x | y` returns either a signed 32-bit integer
* (an `Int`) or a bigint.
*
* The only case in which it returns it bigint is when both arguments
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* The only case in which it returns it bigint is when both arguments
* The only case in which it returns a bigint is when both arguments

sjrd added 3 commits June 21, 2025 23:11
We use these in some low-level routines, notably in `RuntimeLong`.
Introducing casts avoids unnecessary `AsInstanceOf`s around them.
Its implementation is shorter than many of the methods we already
inline, like additions and multiplications. We do pay a little
code size cost for this change.

This will be particularly useful for the following commit, which
will rely on folding to happen within `toDouble`, once inlined at
call site.
Instead, we use `Integer.toUnsignedLong(x).toDouble`, which is
semantically equivalent. The only remaining use of `x >>> 0` is in
the JS-only runtime libraries, notably `RuntimeLong`.

We add some optimizations to generate the best possible code on all
targets.

For JS with `RuntimeLong`, we need a tailored rewrite in the
optimizer to get rid of a `Double` addition of `0.0 + y` when `y`
is provably non-negative. This shape comes from inlining
`RuntimeLong.toDouble`.

For JS with `bigint`s, we directly fold
`(double) <toLongUnsigned>(x)` into `x >>> 0`. Otherwise, we
unnecessarily go through a `bigint` with `Number(BigInt(x >>> 0))`.

For Wasm, we fold the same shape into a single operation
`f64.convert_i32_u`, which we add in `WasmTransients`.

Overall, this has no real impact on the JS target. However, it
removes two round-trips from Wasm to JS. Previously, we needed to
call a helper function to do the `x >>> 0`, then call the `$uD`
helper to retrieve the result. Now, the same operations stays
entirely within Wasm.
@sjrd sjrd force-pushed the no-touint-in-lib branch from f377fbc to 5fb3aab Compare June 21, 2025 21:11
@sjrd sjrd enabled auto-merge June 21, 2025 21:30
@sjrd sjrd merged commit c0b6ce2 into scala-js:main Jun 22, 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