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

Problematic JS BigInt coercion #1399

Open
dcodeIO opened this issue Feb 28, 2021 · 5 comments
Open

Problematic JS BigInt coercion #1399

dcodeIO opened this issue Feb 28, 2021 · 5 comments

Comments

@dcodeIO
Copy link

dcodeIO commented Feb 28, 2021

It has recently been reported to me that the JS API for BigInt integration can cause unexpected problems when omitting arguments. Say one has the following Wasm module

export function test(a: i64 = 0): void { }

and wants to call exports.test() externally, with the a argument omitted for some reason, then the call will fail with

Uncaught TypeError: Cannot convert undefined to a BigInt

Without some sort of bindings generation, the JS module does not know however that a is of type i64 and should be passed a 0n default value. Something similar also happens when the argument is 0, or another number:

Uncaught TypeError: Cannot convert number to a BigInt

So I wonder: Would it be useful to define a coercion from undefined to 0n when calling Wasm exports, and perhaps also a coercion from number? I guess this is not a V8 bug?

@Ms2ger
Copy link

Ms2ger commented Mar 2, 2021

Spec context: https://webassembly.github.io/spec/js-api/#call-an-exported-function calls ToWebAssemblyValue → ToBigInt64 → ToBigInt which throws on undefined. (i32 gets zero, the floats get NaN.)

export function test(a: i64 = 0): void { }

The = 0 here doesn't refer to anything in WebAssembly, does it? You mean a function with the type [i64] → []?

@dcodeIO
Copy link
Author

dcodeIO commented Mar 2, 2021

Yes, in Wasm this would be an [i64] -> [] function, called externally with the argument omitted where a compiler allows to do this. AssemblyScript for example has a mechanism for filling in default values of omitted arguments post-call, by hinting arguments.length pre-call.

@MaxGraey
Copy link

MaxGraey commented Mar 9, 2021

I guess better address this issue to this discussion: https://es.discourse.group/t/why-is-bigint-broken/567/18

@devsnek
Copy link
Member

devsnek commented Mar 16, 2021

I don't think that this issue is as specific as the issue OP implies:

For example:

export function test(a: i64 = 3): void { }

or for that matter,

export function test(a: f64 = 0): void { } // will be NaN if you call test() in js, not 0

@dcodeIO
Copy link
Author

dcodeIO commented Mar 26, 2021

Thanks for noting, I overlooked that, since in the specific use case I am describing the value does not matter, as it is only important that the call succeeds (the default value replaces what's is passed). I agree that there is more to think about here.

Also, in #1402 (comment) it was noted that Wasm could allow duplicate exports, which seems like a preferable solution over what I suggested here, at least for that specific use case. With duplicate exports, I'd expect the JS/Wasm binding to pick the export with matching arity (not sure if that's a realistic expectation?), so the problem can be worked around fairly easily by exporting both a test() and a test(a: T).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants