Replies: 2 comments 6 replies
-
For completeness's sake, the following docs describe the JS APIs which were added to the SQLite project to help support 64-bit mode: https://sqlite.org/wasm/doc/trunk/api-wasm.md#wasm-ptr |
Beta Was this translation helpful? Give feedback.
-
Thanks @sgbeal. I sounds like you (sqlite) went with an approach the doesn't try to hide the "pointers can be BigInt" from the end user code. As you probably know emscripten instead tried to keep the "pointers are numbers" fiction even on 64-bit, although (as you probably also know) there are places where this abstraction is leaky (e.g. EM_JS function that take to return pointer value) and users may still need to modify their code. I have long considered a second mode that does try to hide the bigint values and instead lets bigints flow through all the JS APIs. There could be some efficiency advantages, but also more useability pitfalls. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
What follows are random tips for folks who are interested in using Emscripten's
-sMEMORY64=1
flag, based on recent work to get SQLite's JS pieces working with that. This post is primarily about friction encountered when porting JS code to work in both 32- and 64-bit builds. None of what follows is a criticism of how Emscripten handles 64-bit builds - it's doing completely the right things. Unfortunately, though, some of those right things (baked into the corresponding language standards) are easy to trip over.Part One:
BigInt !== Number
First off, 64-bit builds necessarily change the data type of pointers from Number to BigInt. While that may sound pretty innocuous, it leads to discrepancies like:
Sigh. More surprising to me was:
That's relevant here because JS code using C libraries via WASM commonly has to do pointer arithmetic. Much of the above-linked work was ironing out that one difference by converting all pointer arithmetic into function calls:
Regarding
__ptrSize
: that value is most readily available by calling any WASM function which returns a pointer. In my case that looked like:Part Two:
BigInt != Number
Most of the effort in aforementioned port to 64-bit builds was caused by the previous point. A secondary problem is that some functions do not like BigInt arguments. The WASM heap is a byte array, and we copy memory out of it by taking slices of that array:
That won't work if
ptrStart
is a BigInt. We instead need:(Which is ironic, given that BigInt is there to provide access to a full 64 bits and the byte array APIs will never let us make use of more than Number's 53 integer bits, so Number would, in practice, suffice as a pointer type in 64-bit builds.)
That's easy to account for but is tedious and it's easy to forget to do, leading to code which "just works" in 32-bit builds but fails miserably in 64-bit.
More insidious and surprising, however, is that some APIs change which type they expect in 64-bit builds. For example,
WebAssembly.Table.get()
wants a Number in 32-bit builds (and when-sMEMORY64=2
) but a BigInt when using-sMEMORY64=1
, and will throw if given the other type. One workaround for that is:Noting that the purely-JS APIs, e.g. the TypedArrays used for the WASM heap, do not change their signatures. The WebAssembly namespace is a special case.
Pics or it didn't happen:
Part 3: That might be all
There may be other porting holes which my feet have randomly avoided so far, but this post covers the biggest (IMO) pitfalls.
Hopefully this post has been of some use.
Beta Was this translation helpful? Give feedback.
All reactions