wasm3 / wasm3-rs

Rust wrapper for Wasm3, the fastest WebAssembly interpreter
MIT License
155 stars 43 forks source link

Hello world sample #1

Open autodidaddict opened 4 years ago

autodidaddict commented 4 years ago

I'm struggling to find the right functions to call to make this work. I'd love to see a sample that utilizes the Rust bindings that:

If there are some docs or some other source of information you can point me at, I can take a stab at this.

Veykril commented 4 years ago

I have only started writing this wrapper very recently(2 days ago to be precise), so I have to look more into the implementation source before I'll be able to create something usable. I'll try to get some examples working soon though 😄

autodidaddict commented 4 years ago

I hope I didn't come across like I expected this stuff to be there after just a few days. I'd like to help with this if possible, though my FFI skills aren't as good as they could be.

Veykril commented 4 years ago

No worries, it didn't sound like that at all. Since there isn't really much to work with in the crate, helping seems rather difficult. But I'd be happy to take some helping hands once there is a rough structure.

matiasinsaurralde commented 4 years ago

Very interesting, feel free to inspect my Go implementation in case it's useful, I have a few samples too (two of them use WASI): https://github.com/matiasinsaurralde/go-wasm3

Best.

Veykril commented 4 years ago

Got far enough implementation-wise that it is now possible to call exported functions(though I have not tested it too much yet). Added a very small example to show how it works currently.

autodidaddict commented 4 years ago

Took a look at the same and it definitely looks like bi-directional calls are working. It looks like there is no return value from a host function, and that the return value is the last parameter in the function list (e.g. the seconds to millis demo). So if I had a function that took 3 input parameters and had one return value, the signature for that host func (linked) would look like this:

unsafe extern "C" fn millis(
    _rt: ffi::IM3Runtime,
    p1: u64,
    p2: u64,
    p3: u64
    retval: *mut u64,
    _mem: *mut std::ffi::c_void,
) -> *const std::ffi::c_void {
    // do unsafe things...
    ffi::m3Err_none as _
}

?

autodidaddict commented 4 years ago

My real goal is to be able to add a config feature flag to the wapc crate so that I can choose whether I want to compile that library using wasmtime (running on servers/server OSes) or wasm3 (running on limited/embedded devices)

Veykril commented 4 years ago

No, the signature of the extern function is always the same, you would have to retrieve the arguments from the stackpointer, which is the second argument to that function.

So something like this:


unsafe extern "C" fn millis(
    _rt: ffi::IM3Runtime,
    sp: *mut u64,
    _mem: *mut std::ffi::c_void,
) -> *const std::ffi::c_void {
    let p1 = *sp;
    let p2 = *sp.add(1);
    let p3 = *sp.add(2);
    *sp = MILLIS; // this is the return value, aka the first value on the stack will be it
    ffi::m3Err_none as _ // this is the result return, whether the call was successful(m3Err_none) or not(like returning a trap for example)
}

I am thinking about how to make this nicer to use so that the consumer doesn't have to dip into this extern mess themselves, but that most likely will involve some use of macros and im not sure about how I want to do this.

Veykril commented 4 years ago

I just added a small basic macro to aid in creating an extern wrapper function around a rust function that should help to avoid having to write this stuff manually. Should work in most cases I hope, haven't tested it too much yet. https://github.com/Veykril/wasm3-rs/blob/7915db91c4a7461cf827195e89124b9d91319727/examples/wasm_link.rs#L24-L27

You basically call the macro with the wrapper_function name followed by the to be wrapped functions signature. So if you have a function with the signature fn foo(bar: u64, baz: u32) -> f32 you'd call the macro with wasm3::make_func_wrapper!(foo_wrap: foo(bar: u64, baz: u32) -> f32);

vshymanskyy commented 3 years ago

@Veykril what's the easiest way to run the examples? I was able to:

python wasm_bin_builder.py ./examples/wasm/wasm_add
rustc examples/call_wasm.rs -L ./target/release/deps

But, it requires extern crate wasm3; on top of call_wasm.rs. For wasm_print I also need to specify --cfg 'feature="wasi"' explicitly.

Veykril commented 3 years ago

@vshymanskyy You can simply run an example by invoking cargo run --example call_wasm, and cargo run --example wasm_print --features=wasi for the wasm_print example.

imotai commented 2 years ago

@vshymanskyy You can simply run an example by invoking cargo run --example call_wasm, and cargo run --example wasm_print --features=wasi for the wasm_print example.

I have some errors when running example

$ python3 wasm_bin_builder.py examples/wasm/wasm_add
    Finished release [optimized] target(s) in 0.01s
$ RUST_BACKTRACE=1 cargo run --example call_wasm
   error: failed to run custom build command for `wasm3-sys v0.1.2 (/media/psf/Home/opensource/wasm3-rs/wasm3-sys)`

Caused by:
  process didn't exit successfully: `/media/psf/Home/opensource/wasm3-rs/target/debug/build/wasm3-sys-f63c8693949f9c0d/build-script-build` (exit status: 101)
  --- stderr
  thread 'main' panicked at 'Unable to generate bindings: Os { code: 2, kind: NotFound, message: "No such file or directory" }', wasm3-sys/build.rs:78:35
  stack backtrace:
     0: rust_begin_unwind
               at /rustc/f22819bcce4abaff7d1246a56eec493418f9f4ee/library/std/src/panicking.rs:584:5
     1: core::panicking::panic_fmt
               at /rustc/f22819bcce4abaff7d1246a56eec493418f9f4ee/library/core/src/panicking.rs:142:14
     2: core::result::unwrap_failed
               at /rustc/f22819bcce4abaff7d1246a56eec493418f9f4ee/library/core/src/result.rs:1814:5
     3: core::result::Result<T,E>::expect
               at /rustc/f22819bcce4abaff7d1246a56eec493418f9f4ee/library/core/src/result.rs:1064:23
     4: build_script_build::gen_bindings
               at ./build.rs:78:18
     5: build_script_build::main
               at ./build.rs:127:5
     6: core::ops::function::FnOnce::call_once
               at /rustc/f22819bcce4abaff7d1246a56eec493418f9f4ee/library/core/src/ops/function.rs:248:5
  note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Veykril commented 2 years ago

Make sure you have initialized the submodule