summaryrefslogtreecommitdiff
path: root/examples/reentrance.rs
blob: 432fac76c3fa8ad529a4b198c9e914db05a332ae (plain)
use eyre::Result;
use tinywasm::{FuncContext, HostFunction, Imports, ModuleInstance, Store};

const WASM: &str = r#"
(module
  (import "host" "call_add_twice" (func $call_add_twice (param i32) (result i32)))

  (func $add_one (export "add_one") (param i32) (result i32)
    local.get 0
    i32.const 1
    i32.add)

  (func (export "run") (param i32) (result i32)
    local.get 0
    call $call_add_twice
    i32.const 10
    i32.add))
"#;

fn main() -> Result<()> {
    let wasm = wat::parse_str(WASM)?;
    let module = tinywasm::parse_bytes(&wasm)?;
    let mut store = Store::default();

    let call_add_twice = HostFunction::from(&mut store, |mut ctx: FuncContext<'_>, value: i32| {
        let add_one = ctx.module().func::<i32, i32>(ctx.store(), "add_one")?;

        // Use ctx.call for reentrant calls from host functions. Function::call
        // starts a root invocation and cannot preserve the active call stacks.
        let value = ctx.call(&add_one, value)?;
        ctx.call(&add_one, value)
    });

    let mut imports = Imports::new();
    imports.define("host", "call_add_twice", call_add_twice);

    let instance = ModuleInstance::instantiate(&mut store, &module, Some(imports))?;
    let run = instance.func::<i32, i32>(&store, "run")?;

    assert_eq!(run.call(&mut store, 40)?, 52);

    Ok(())
}