Skip to content
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

Enable BigInt for binaryen.js #7167

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Enable BigInt for binaryen.js #7167

wants to merge 2 commits into from

Conversation

tlively
Copy link
Member

@tlively tlively commented Dec 20, 2024

We previously had a build option for enabling BigInt support when
compiling with Emscripten, but the test suite did not actually pass with
it enabled. The problem was that the binaryen.js glue code assumed that
C API functions that took i64 parameters would be transformed to take a
pair of i32 parameters instead, but this assumption was incorrect when
BigInt support was enabled.

Emscripten has now enabled BigInt by default, so update binaryen.js to
use BigInt as well. Fix the JS API glue code to pass i64s as BigInts
rather than pairs of numbers and fix the tests accordingly. Also fix
some other small problems with the tests that only show up in debug
builds.

Resolves #7163.

We previously had a build option for enabling BigInt support when
compiling with Emscripten, but the test suite did not actually pass with
it enabled. The problem was that the binaryen.js glue code assumed that
C API functions that took i64 parameters would be transformed to take a
pair of i32 parameters instead, but this assumption was incorrect when
BigInt support was enabled.

Emscripten has now enabled BigInt by default, so update binaryen.js to
use BigInt as well. Fix the JS API glue code to pass i64s as BigInts
rather than pairs of numbers and fix the tests accordingly. Also fix
some other small problems with the tests that only show up in debug
builds.

Resolves #7163.
@tlively tlively requested review from dschuff and kripken December 20, 2024 00:06
return preserveStack(() => {
const tempLiteral = stackAlloc(sizeOfLiteral);
Module['_BinaryenLiteralInt64'](tempLiteral, x, y);
Module['_BinaryenLiteralInt64'](tempLiteral, BigInt(x));
Copy link
Member

@kripken kripken Dec 20, 2024

Choose a reason for hiding this comment

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

What do you think about making this backwards compatible? We could support (i32, undefined), (i32, i32), and (BigInt, undefined) with this code:

        // Convert to a BigInt. We support (x, undefined) where x is either a
        // BigInt or not, and also (x, y) where neither is a BigInt and y is the
        // higher bits.
        if (typeof x !== 'bigint') {
          x = BigInt(x || 0) | (BigInt(y || 0) << 32n);
        }

Copy link
Member

Choose a reason for hiding this comment

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

A small code size cost seems reasonable to me here, personally. And it is nice to write binaryen.i64.const(42) and not need to remember 42n each time.

Copy link
Member Author

Choose a reason for hiding this comment

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

binaryen.i64.const(42) already works because of the explicit BigInt(x) conversion here. Except for compatibility, I don't think there's much benefit to supporting the two-argument version. How much do we value compatibility here? Would we have a deprecation plan, or would we support the two-argument version indefinitely?

Copy link
Member

Choose a reason for hiding this comment

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

I think compatibility makes sense: there are users that are creating i64s with two arguments, and I don't see a strong reason to break them, given the burden on supporting the old format is minimal.

@tlively
Copy link
Member Author

tlively commented Dec 20, 2024

"em++: error: WASM_BIGINT=1 is not compatible with WASM=0 (wasm2js)" seems like a problem... Do we need to drop the JS build? Do we need to use WASM_BIGINT=0 forever? Is there a third option?

@kripken
Copy link
Member

kripken commented Dec 20, 2024

About the JS build, that makes me worried actually... I don't know offhand how important JS builds are for binaryen specifically, but in general, I would guess there are people that need JS builds. If they need both JS and wasm builds then if wasm2js doesn't support bigint, that means they'd need to either

  1. Disable bigint in wasm, or
  2. Support both bigint and non-bigint versions, which can be annoying if they pass i64s on the boundary, as binaryen.js does.

This makes me think we should just support bigint with wasm2js. We don't need full bigint support in codegen - only to make imports and exports from the wasm be able to convert from bigints on the outside into i32,i32 on the inside (that is, the inside stays the same).

cc @dschuff - what do you think? If this makes sense, maybe we should do it before releasing the first Emscripten version with bigint by default.

@dschuff
Copy link
Member

dschuff commented Dec 20, 2024

Yeah, I think adding BigInt support for wasm2js by converting BigInt <-> Number pairs on the boundaries makes sense, since as you say it would let people use the same interface for JS and wasm.
As for whether we should wait on releasing the next version: maybe? If we do the release, people will have to turn bigint off manually, which is annoying but not the end of the world. If we add support, would it be seamless? Or would someone have to manually opt-into the conversion somehow? I guess this is a question for the bindings layer as much as the end user; I guess binaryen.js essentially has its own, right?

@kripken
Copy link
Member

kripken commented Dec 20, 2024

I think if we make wasm2s support bigint then the "bigint by default" update would become frictionless/unnoticeable for most users. People doing manual bindings like binaryen.js will need updates as in this PR, but I'm hoping that's rare.

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.

Binaryen's Emscripten bindings do not support WASM_BIGINT
3 participants