bjorn3 / browser_wasi_shim

A WASI shim for in the browser
Apache License 2.0
307 stars 41 forks source link

Instantiate a wasm library #36

Closed jakob-lilliemarck closed 1 year ago

jakob-lilliemarck commented 1 year ago

Hey @bjorn3, Thanks for sharing this library - exciting stuff!

I've been trying to find a way to invoke a function on a wasm32-wasi library. As it is a library is has no start function. Is there a way to avoid calling wasi.start(instance) and instead just call functions exported by the instance?

Something along these lines perhaps?

wasi.invoke(instance.exports.my_func)

Would be awesome - please let me know if I'm just missing something

bjorn3 commented 1 year ago

For wasi a wasm module is either a command (program like) which exports _start, or it is a reactor (library like) which exports _initialize and any amount of other functions which can be called after _initialize. Assuming that you have a wasi reactor you can use wasi.initialize(instance) instead of wasi.start(instance) and then directly call the exports of instance.

jakob-lilliemarck commented 1 year ago

I'm somewhat of a beginner with wasm and wasi (especially using javascript), but when I log inst.exports it doesn't seem to include any _initialize() funtion. Only thing there is my own exported function run() along with memory. Should I expect to find the _initialize() at inst.exports._initialize?

I'm running in to this error while trying the above suggestion:

Uncaught TypeError: instance.exports._initialize is not a function

It seems the _initialize() function can not be expected to always be present?

I have no issues running the module in rust using wasmtime and wasi :thinking: I've written the module in rust, if it makes any sense to you the extern function declaration just looks like this:

#[no_mangle]
pub extern "C" fn run() {
  // some rust coe
}

Compiled with cargo using wasm32-wasi target.

What's the signature and expected behaviour of _initialize() in case I should define it myself?

jakob-lilliemarck commented 1 year ago

Ah, I think I found the reference myself! Indeed adding an empty _initialize() function to my wasm module made it stop complaining. It seems though, that I'm still not able to call the functions though, probably due to some missing implementation. I'm getting this:

Uncaught RuntimeError: unreachable executed

These are the functions of wasi_snapshot_preview1 the module requires:

jakob-lilliemarck commented 1 year ago

Looking at the code it seems all the required methods are defined, but all fd_-prefixed ones seem to just have a placeholder implementation on the wasi.wasiImport object. However, they seem to be implemented on the class OpenFile

bjorn3 commented 1 year ago

Right, for cdylib's rustc by default produces something that doesn't fit either model. I think you can skip wasi.start(instance) and wasi.initialize(instance) entirely.

The fd_* methods on wasi.wasiImport should dispatch to the fd_* method on the corresponding OpenFile/OpenDirectory of the fd that was passed as argument. What did you pass in as third argument of new WASI()?

jakob-lilliemarck commented 1 year ago

Ah that explains it, thanks! I instantiated it like this, so I guess it should be fine:

let fds = [
  new OpenFile(new File([])), // stdin
  new OpenFile(new File([])), // stdout
  new OpenFile(new File([])), // stderr
];
let wasi = new WASI([], [], fds);

I think I got it running now, still running into some errors but I don't think it's related to wasi :)

bjorn3 commented 1 year ago

I instantiated it like this, so I guess it should be fine:

Yeah, that should work.

I think I got it running now, still running into some errors but I don't think it's related to wasi :)

👍 Can this issue be closed?

jakob-lilliemarck commented 1 year ago

hey @bjorn3 - sorry about the late reply. Yes this issue can be closed. thanks for you help :) In the end I managed to run my WASI module in the browser thanks to your advise.