Stream: git-wasmtime

Topic: wasmtime / issue #8273 Help, wasmtime rust asynchronous h...


view this post on Zulip Wasmtime GitHub notifications bot (Apr 01 2024 at 02:26):

silence-coding opened issue #8273:

Can the community provide a sample asynchronous wasm implementation for Rust or tools to help developers implement asynchronous wasm for Rust (e.g. wasm-bindgen-futures). I've looked up a lot of information, but nothing has solved my problem.

I was expecting to compile the following rust code into an asynchronous wasm function and execute it via wasmtime, but I'm getting a type mismatch error.
Example:

   //  wasm function
    #[no_mangle]
    pub async fn fetch_add(id: i32) -> i32 {
        id + 1
    }

   //   execute it via wasmtime
    let mut config = Config::new();
    config.async_support(true);
    let engine = Engine::new(&config).unwrap();
    let mut linker: Linker<WasiP1Ctx> = Linker::new(&engine);
    preview1::add_to_linker_async(&mut linker, |s| s)?;
    let module = Module::from_file(&engine, "target/wasm32-wasi/debug/async.wasm")?;
    let wasi = WasiCtxBuilder::new()
        .inherit_stdout()
        .inherit_stderr()
        .build_p1();
    let mut store = Store::new(&engine, wasi);
    let instance = linker.instantiate_async(&mut store, &module).await?;
    let func = instance.get_typed_func::<i32,i32>(&mut store, "fetch_add")?;
    let i = func.call_async(&mut store, 1).await?;

ERR:

Error: failed to convert function `fetch_add` to given type

Caused by:
    0: type mismatch with parameters
    1: expected 1 types, found 2

When I converted the wasm to wat, I found that it was strangely typed. How do I properly develop an asynchronous wasm implementation of Rust?

(module
  (type (;0;) (func (param i32 i32)))
  (type (;1;) (func))
  (func $fetch_add (type 0) (param i32 i32)
    (local i32 i32 i32 i32)
    global.get $__stack_pointer
    local.set 2
    i32.const 16
    local.set 3
    local.get 2
    local.get 3
    i32.sub
    local.set 4
    local.get 4
    local.get 1
    i32.store offset=12
    local.get 0
    local.get 1
    i32.store
    i32.const 0
    local.set 5
    local.get 0
    local.get 5
    i32.store8 offset=4
    return)
  (func $dummy (type 1))
  (func $__wasm_call_dtors (type 1)
    call $dummy
    call $dummy)
  (func $fetch_add.command_export (type 0) (param i32 i32)
    local.get 0
    local.get 1
    call $fetch_add
    call $__wasm_call_dtors)
  (table (;0;) 1 1 funcref)
  (memory (;0;) 16)
  (global $__stack_pointer (mut i32) (i32.const 1048576))
  (export "memory" (memory 0))
  (export "fetch_add" (func $fetch_add.command_export)))

view this post on Zulip Wasmtime GitHub notifications bot (Apr 01 2024 at 12:01):

bjorn3 commented on issue #8273:

You can't directly export an async function using #[no_mangle] async fn. Rust doesn't have a stable ABI, so at least it would need to be #[no_mangle] async extern "C" fn to use the C abi, which would then result in

warning: `extern` fn uses type `impl Future<Output = i32>`, which is not FFI-safe
 --> src/lib.rs:1:1
  |
1 | async extern "C" fn fetch_add(id: i32) -> i32 {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
  |
  = note: opaque types have no C equivalent
  = note: `#[warn(improper_ctypes_definitions)]` on by default

as Rust futures don't have a C abi.

I haven't used it myself, but could maybe try https://github.com/dicej/isyswasfa.

view this post on Zulip Wasmtime GitHub notifications bot (Apr 01 2024 at 12:25):

silence-coding commented on issue #8273:

You can't directly export an async function using #[no_mangle] async fn. Rust doesn't have a stable ABI, so at least it would need to be #[no_mangle] async extern "C" fn to use the C abi, which would then result in

warning: `extern` fn uses type `impl Future<Output = i32>`, which is not FFI-safe --> src/lib.rs:1:1 | 1 | async extern "C" fn fetch_add(id: i32) -> i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: opaque types have no C equivalent = note: `#[warn(improper_ctypes_definitions)]` on by default

as Rust futures don't have a C abi.

I haven't used it myself, but could maybe try https://github.com/dicej/isyswasfa.

You're right, I was hoping for a solution like wasm-bindgen-futures

view this post on Zulip Wasmtime GitHub notifications bot (Apr 01 2024 at 13:09):

bjorn3 commented on issue #8273:

I was hoping for a solution like wasm-bindgen-futures

That would be https://github.com/dicej/isyswasfa from my understanding.

view this post on Zulip Wasmtime GitHub notifications bot (Apr 01 2024 at 15:13):

alexcrichton closed issue #8273:

Can the community provide a sample asynchronous wasm implementation for Rust or tools to help developers implement asynchronous wasm for Rust (e.g. wasm-bindgen-futures). I've looked up a lot of information, but nothing has solved my problem.

I was expecting to compile the following rust code into an asynchronous wasm function and execute it via wasmtime, but I'm getting a type mismatch error.
Example:

   //  wasm function
    #[no_mangle]
    pub async fn fetch_add(id: i32) -> i32 {
        id + 1
    }

   //   execute it via wasmtime
    let mut config = Config::new();
    config.async_support(true);
    let engine = Engine::new(&config).unwrap();
    let mut linker: Linker<WasiP1Ctx> = Linker::new(&engine);
    preview1::add_to_linker_async(&mut linker, |s| s)?;
    let module = Module::from_file(&engine, "target/wasm32-wasi/debug/async.wasm")?;
    let wasi = WasiCtxBuilder::new()
        .inherit_stdout()
        .inherit_stderr()
        .build_p1();
    let mut store = Store::new(&engine, wasi);
    let instance = linker.instantiate_async(&mut store, &module).await?;
    let func = instance.get_typed_func::<i32,i32>(&mut store, "fetch_add")?;
    let i = func.call_async(&mut store, 1).await?;

ERR:

Error: failed to convert function `fetch_add` to given type

Caused by:
    0: type mismatch with parameters
    1: expected 1 types, found 2

When I converted the wasm to wat, I found that it was strangely typed. How do I properly develop an asynchronous wasm implementation of Rust?

(module
  (type (;0;) (func (param i32 i32)))
  (type (;1;) (func))
  (func $fetch_add (type 0) (param i32 i32)
    (local i32 i32 i32 i32)
    global.get $__stack_pointer
    local.set 2
    i32.const 16
    local.set 3
    local.get 2
    local.get 3
    i32.sub
    local.set 4
    local.get 4
    local.get 1
    i32.store offset=12
    local.get 0
    local.get 1
    i32.store
    i32.const 0
    local.set 5
    local.get 0
    local.get 5
    i32.store8 offset=4
    return)
  (func $dummy (type 1))
  (func $__wasm_call_dtors (type 1)
    call $dummy
    call $dummy)
  (func $fetch_add.command_export (type 0) (param i32 i32)
    local.get 0
    local.get 1
    call $fetch_add
    call $__wasm_call_dtors)
  (table (;0;) 1 1 funcref)
  (memory (;0;) 16)
  (global $__stack_pointer (mut i32) (i32.const 1048576))
  (export "memory" (memory 0))
  (export "fetch_add" (func $fetch_add.command_export)))

view this post on Zulip Wasmtime GitHub notifications bot (Apr 01 2024 at 15:13):

alexcrichton commented on issue #8273:

I'd recommend reading up on what @bjorn3 linked as well. Otherwise though I'd recommend continuing this discussion on Zulip as this doesn't have much to do with Wasmtime itself.

In general I'll say though that it's early days for async. There is no drop-in replacement for wasm-bindgen-futures and there is no host which runs async wasm like wasm-bindgen-futures works with JS. There's no inherent reason for this per-se, it just hasn't been prioritized yet. Wasmtime as-is, though, is not suitable for the full "power" of wasm-bindgen-futures yet. You can invoke multiple host functions concurrently but Wasmtime cannot invoke multiple guest functions concurrently at this time.


Last updated: Dec 23 2024 at 12:05 UTC