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

wasm64 + EM_JS requires special handling for pointer types (and long and size_t) #16975

Open
sbc100 opened this issue May 19, 2022 · 8 comments

Comments

@sbc100
Copy link
Collaborator

sbc100 commented May 19, 2022

Under wasm64 pointer types (and long and size_t) get passed as BigInt.

This means that EM_JS functions that take or return pointers will most likely need modifications (since BigInt and Number in JS are not generally compatible).

Should we try to find a way to avoid this type of thing:

EM_JS(char*, return_ptr, (void), {   
#if __wasm64__                                                                   
    return BigInt(addressAsNumber);                                             
#else                                                                            
    return addressAsNumber;                                                                                                   
#endif                                                                              
});    

For JS library functions have use the __sig metadata to encode certain arguments and return values are being "pointers" which means that get cooerced to Number/int53 in the JS glue code.

Should we do that same for EM_JS?

@Wora112

This comment was marked as duplicate.

@kripken
Copy link
Member

kripken commented Jan 7, 2025

A partial workaround for this, discussed in #23325, is to make functions that receive a pointer, like UTF8ToString, handle both Numbers and BigInts, so that they work in EM_JS's automatically. The downside would be increased code size, however, so it's probably not a good idea.

@sbc100
Copy link
Collaborator Author

sbc100 commented Jan 7, 2025

That doesn't really help the more general problem though. Having these be bigints means that cannot be used in numbers. .e.g this simple function won't work:

EM_JS(int*, get_next, (int* addr), {   
  return addr + 4;
})

This will result in Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions

In general code the is written to expect number will just not work if you give it a bigint, so as long as these things remain bigint we will have major issues.

@cwoffenden
Copy link
Contributor

Continuing from #23486, the same applies to the likes of stackAlloc() when called from JS library code, am I expected always to convert to BigInt myself before passing to a Wasm function expecting a pointer?

(I'm late to the party on this, is there a rational I can read on why BigInt in JS over int53? I'm guessing it's forward looking for 4TB+ RAM on something other than browsers? Having just added support for MEMORY64 to a lib there's trial and error over what works and what needs converting.)

@sbc100
Copy link
Collaborator Author

sbc100 commented Jan 24, 2025

All JS API that take or return pointer values (or size_t/intptr_t values) should take/return "number" and not "bigint". So stackAlloc will take and return "number".

The idea is that where possible these number should automatically be converted to/from BigInt when calling into and out of wasm.

For calling out of Wasm into JS library code we have __sig attributes which are largely auto-generated: https://github.com/emscripten-core/emscripten/blob/main/src/lib/libsigs.js. Any time a p appears in the signature emscripten will generated and automatic wrapper function.

For calling into Wasm the mechanism is not quite as easy to use. We basically have a fixed list of known signatures, which can be extended with the -sSIGNATURE_CONVERSIONS setting: https://github.com/emscripten-core/emscripten/blob/main/tools/emscripten.py#L1018-L1100

@sbc100
Copy link
Collaborator Author

sbc100 commented Jan 24, 2025

I'm late to the party on this, is there a rational I can read on why BigInt in JS over int53? I'm guessing it's forward looking for 4TB+ RAM on something other than browsers?

I think exposing i64 as bigint makes sense if you think of all possible i64 values, not just pointers. I think bigint it really the logical choice for expressing the i64 type in JS. Sure dealing with bigint when you have an existing codebase that expects numbers, but that is really a problem for bigint itself, not just the Wasm/Bigint integration. For more on the Wasm/BigInt integration see https://github.com/WebAssembly/JS-BigInt-integration

@cwoffenden
Copy link
Contributor

Thanks, I'll take a look at the __sig attribute and -sSIGNATURE_CONVERSIONS (and the internal list, since for example, the process callback params in audio_worklet.js needs wrapping in BigInts).

@sbc100
Copy link
Collaborator Author

sbc100 commented Jan 24, 2025

Thanks, I'll take a look at the __sig attribute and -sSIGNATURE_CONVERSIONS (and the internal list, since for example, the process callback params in audio_worklet.js needs wrapping in BigInts).

For user callback into Wasm see the makeDynCall mechanism. It uses the same signature format which can include p for pointer-width types.

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

No branches or pull requests

4 participants