WebAssembly / binaryen

Optimizer and compiler/toolchain library for WebAssembly
Apache License 2.0
7.42k stars 734 forks source link

How to access wasm2js bulk memory #5390

Closed willcohen closed 1 year ago

willcohen commented 1 year ago

In attempting to load a wasm2js-generated js file on graaljs, I hit the following error:

failed to compile wasm module: TypeError: Cannot read property 'buffer' of undefined
Execution error (PolyglotException) at <js>/asmFunc (src.js:493).
TypeError: Cannot read property 'buffer' of undefined

It's referring to these lines in the transpiled js, implying that the env.memory section is undefined.

function asmFunc(env) {
 var memory = env.memory;
 var buffer = memory.buffer;

This error occurs when using the shell environment, which I suppose graal isn't, but running the transpilation without setting an env fails with Aborted(Assertion failed: shell environment detected but not enabled at build time. Add 'shell' to-sENVIRONMENTto enable.)

Should I be using a different environment, does this mean that the shell environment needs something else to generate a WebAssembly.Memory, or does there need to be an entirely new graal environment?

willcohen commented 1 year ago

I should note that graalwasm loads the wasm fine and can handle the bulk memory, but since graalwasm isn't available as a standalone item, being able to run a js file as a fallback still has a use case. The error continues with -s SHARED_MEMORY=1, which I assume is also needed.

kripken commented 1 year ago

Yes, if graaljs is not close enough to either the node or shell environments in Emscripten, then something will need to be done. One option might be to add some polyfills right before loading the js+wasm, to make it look like either node or a shell. See this related issue:

https://github.com/emscripten-core/emscripten/issues/12203

As mentioned there, web/worker/node/shell used to be enough, but these days there is also deno, bun, and more (like graaljs in fact) so we probably need a more scalable solution. The idea in that issue would make it hopefully simple to add such a "polyfill file" for something like graaljs.

willcohen commented 1 year ago

Excellent, many thanks -- I think this gets me much of the way there. Looks like this may actually be more of an emscripten issue, but before I open another issue there, seeing if I can find the precise issue. The graal stack trace is:

1. Unhandled org.graalvm.polyglot.PolyglotException
   TypeError: Cannot read property 'buffer' of undefined

                    src.js:  411  <js>/asmFunc
                    src.js:873854  <js>/instantiate
                    src.js:  342  <js>/Instance
                    src.js:874495  <js>/instantiateSync
                    src.js:874552  <js>/createWasm
                    src.js:879540  <js>/:program

Tracing through the -O0 file, the failures are as follows: asmFunc's env doesn't have a memory:

Screenshot 2023-01-05 at 11 05 02 AM

The env is derived from asmLibraryArg:

Screenshot 2023-01-05 at 11 06 10 AM

asmLibraryArg comes from instantiate:

Screenshot 2023-01-05 at 11 07 50 AM

asmLibraryArg's memory comes from wasmMemory:

Screenshot 2023-01-05 at 11 11 51 AM

This requires WebAssembly.Memory:

Screenshot 2023-01-05 at 11 13 02 AM

Implying that something about the creation of the buffer by the emscripten js might be where the failure happens:

Screenshot 2023-01-05 at 11 14 34 AM

I am passing a Graal/native-backed-and-proxied-to js ArrayBuffer via Module['buffer'] as pre-js (as noted here) which should be the graal-friendly way to do this, but it doesn't seem like it's being called or referenced anywhere. I do see the changelog mentioning a while back that Module.buffer was a removed internal detail a while back.

Do you know if there is another preferred way to pass a non-wasm ArrayBuffer?

willcohen commented 1 year ago

Using the emcc options at https://github.com/emscripten-core/emscripten/blob/a6e8d85e2a70aac8dfaa9e96e92491d4e350736e/test/test_browser.py#L4582 and adding an INITIAL_MEMORY to the pre-js Module per https://github.com/emscripten-core/emscripten/blob/main/test/test_preallocated_heap_shell.html#L79-L80, the error continues.

That said, given that the functionality seems to be present and actively tested, it's probably just an incantation problem on my end somewhere with the flags or options rather than a emscripten bug.

willcohen commented 1 year ago

Closing in favor of https://github.com/emscripten-core/emscripten/issues/18474.