GoogleChromeLabs / asyncify

Standalone Asyncify helper for Binaryen

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Import node.js's WASI imports in Asyncify

Pl8tinium opened this issue · comments

Hi,

TLDR: Would it be possible to import the default node.js WASI.wasiImport for wasi_snapshot_preview1?

My goal is to run execute golang code that is compiled to WASI in node.js.

For that I used the tinygo compiler and as I compile to WASI am required to provide the import wasi_snapshot_preview1. Usually, without Asyncify, that works fine for me. I just take the default implementation from node.js's WASI.

const { WASI } = require("wasi");
const wasi = new WASI();

WebAssembly.instantiate(wasm, {
            wasi_snapshot_preview1: wasi.wasiImport,
            env: {
                  ...

This does not seem to work in the implementation of Asyncify.

        const wasmInstance = new Asyncify.Instance(wasmModule, {
            wasi_snapshot_preview1: wasi.wasiImport,
            env: {
                      ...

In this concrete example i get

Module loading failed: TypeError: WebAssembly.Instance(): Import #0 module="wasi_snapshot_preview1" error: module is not an object or function at new Instance (c:\Users\...\asyncify.mjs:171:5)

Which is probably because of how the imports are wrapped and handled inside of asyncify. Therefore I thought I should directly try it in the asyncify.mjs file like so:

export class Instance extends WebAssembly.Instance {
  constructor(module, imports) {
    let state = new Asyncify();
    let a = { env: state.wrapImports(imports).env, wasi_snapshot_preview1: wasi.wasiImport }
    console.log(a)
    super(module, a);
    state.init(this, imports);
  }
...
}

This yieds the following error:

'TypeError: Cannot read properties of undefine…\wasi.js:14:30', message: 'Cannot read properties of undefined (reading 'memory')'}

My issue might be somewhat related to [this issue].(#8)

As mentioned in the other issue, it might be that my problem needs to be fixed on the tinygo side. Im not entirely sure though.

Expected Behavior

I would be able to import the default wasi implementation of node.js.

Actual Behavior

I cant import the default wasi implementation of node.js.

Steps to Reproduce the Problem

see examples above

Specifications

  • Version: 1.2.0
  • Platform: Windows/ WSL2

Module loading failed: TypeError: WebAssembly.Instance(): Import #0 module="wasi_snapshot_preview1" error: module is not an object or function at new Instance (c:\Users...\asyncify.mjs:171:5)

What is wasm in your example?

This yieds the following error:

'TypeError: Cannot read properties of undefine…\wasi.js:14:30', message: 'Cannot read properties of undefined (reading 'memory')'}

It's really hard to tell what's going on without error stacktrace, but it sounds like some side is expecting memory to be either imported or exported. At least from Asyncify side, it expects that there is a memory export in the Wasm module - is there one?

Also, I see you're manually wrapping imports, but are you wrapping exports as well?

Okay, i think ive made a mistake in the first example, i put everything together and now i do get the same memory error on both solutions.

...Cannot read properties of undefined (reading 'memory')'}

Nevertheless left it in my fork where i demonstrate my issue. Should now be relatively straight forward to understand what my issue is.

https://github.com/Pl8tinium/asyncify/blob/master/example/node_golang/setup.md

i think its the "responsibility" of the WebAssembly.Instance class to export memory (WebAssembly.Memory), which in theory should happen as you just inherit from it, though this doesnt seem to be the case. But not sure if my assumptions here are going into the right direction..

"but are you wrapping exports as well" is this necessary? without using asyncify i just had to provide the imports

"but are you wrapping exports as well" is this necessary

Yes, otherwise your exports won't become Promises, and will return too early.

mmh im a bit clueless, is what you mean by wrapping exports to put them into a separate file and export them instead?

https://github.com/Pl8tinium/asyncify/blob/master/example/node_golang/imports.mjs

Or do you mean that to invoke the function i need to screw the exports back on the original WASI object?

import pkg from 'asyncify-wasm';
const Asyncify = pkg;
import { WASI }  from "wasi";
const wasi = new WASI();
...

const wasmInstance = new Asyncify.Instance(wasmModule, {
  wasi_snapshot_preview1: wasi.wasiImport,
...


wasi.exports = wasmInstance.exports;
console.log(wasi.exports.MyAsyncFunction())

As far as i understand it asyncify now needs explicit mentions of the async functions(WebAssembly/binaryen#2322). Thats what this "wrapping exports" is for, right?

And at the end i still got my memory issue, which i was not successful to solve. The "wrapping exports" should not be related to this issue, right?

@RReverser do you have an idea on what i could try or look into next?

Sorry, no, I'm afraid I don't have time to dig in into a 3rd-party project. I can fix a bug if it turns out to be one in this library, but I'll heave to leave further investigation to you.

i found out my issues:

  • only use node version 16 (or lower?)

  • never use a debugger when running wasm code inside of js

everything works now as expected

ty, for your quick responses!