diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 609e0c83f..b29669d33 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,4 +12,4 @@ links to related issues, and the context of the PR. # Review -- [ ] Create a short description of the the change in the CHANGELOG.md file +- [ ] Add a short description of the the change to the CHANGELOG.md file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4672f8d70..ed517016d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#803](https://github.com/wasmerio/wasmer/issues/803) Add method to `Ctx` to invoke functions by their `TableIndex` + ## 0.7.0 - 2019-09-12 Special thanks to @YaronWittenstein @penberg for their contributions. diff --git a/Cargo.toml b/Cargo.toml index 31ba526bd..06b2c2854 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,7 +58,7 @@ members = [ "lib/wasi-tests", "lib/emscripten-tests", "lib/middleware-common-tests", - "examples/plugin-for-example" + "examples/plugin-for-example", ] [build-dependencies] @@ -105,3 +105,7 @@ managed = ["backend-singlepass", "wasmer-runtime-core/managed"] [[example]] name = "plugin" crate-type = ["bin"] + +[[example]] +name = "callback" +crate-type = ["bin"] diff --git a/examples/callback-guest.rs b/examples/callback-guest.rs new file mode 100644 index 000000000..129ad05c8 --- /dev/null +++ b/examples/callback-guest.rs @@ -0,0 +1,24 @@ +extern "C" { + fn call_guest_fn(f: u32) -> u32; + fn call_guest_fn2(f: u32) -> u32; + fn host_callback() -> u32; +} + +#[no_mangle] +fn test_callback() -> u32 { + 42 +} + +#[no_mangle] +fn test_callback2() -> u32 { + 45 +} + +fn main() { + unsafe { call_guest_fn(test_callback as usize as u32) }; + unsafe { call_guest_fn(host_callback as usize as u32) }; + unsafe { call_guest_fn(test_callback2 as usize as u32) }; + unsafe { call_guest_fn2(test_callback2 as usize as u32) }; + unsafe { call_guest_fn2(test_callback as usize as u32) }; + unsafe { call_guest_fn2(host_callback as usize as u32) }; +} diff --git a/examples/callback-guest.wasm b/examples/callback-guest.wasm new file mode 100755 index 000000000..055582975 Binary files /dev/null and b/examples/callback-guest.wasm differ diff --git a/examples/callback.rs b/examples/callback.rs new file mode 100644 index 000000000..732a6a1a4 --- /dev/null +++ b/examples/callback.rs @@ -0,0 +1,46 @@ +/// This example demonstrates the use of callbacks: calling functions (Host and Wasm) +/// passed to us from the Wasm via hostcall +use wasmer_runtime::{compile_with, compiler_for_backend, func, imports, Backend, Ctx}; +use wasmer_runtime_core::{structures::TypedIndex, types::TableIndex}; + +static WASM: &'static str = "examples/callback-guest.wasm"; + +/// This function matches our arbitrarily decided callback signature +/// in this example we'll only call functions that take no arguments and return one value +fn host_callback(_ctx: &mut Ctx) -> u32 { + 55 +} + +fn call_guest_fn(ctx: &mut Ctx, guest_fn: u32) -> u32 { + // We get a TableIndex from our raw value passed in + let guest_fn_typed = TableIndex::new(guest_fn as usize); + // and use it to call the corresponding function + let result = ctx.call_with_table_index(guest_fn_typed, &[]).unwrap(); + + println!("Guest fn {} returned {:?}", guest_fn, result); + + 0 +} + +fn main() { + let wasm_bytes = + std::fs::read(WASM).expect(&format!("Could not read in WASM plugin at {}", WASM)); + + let imports = imports! { + "env" => { + "call_guest_fn" => func!(call_guest_fn), + "call_guest_fn2" => func!(call_guest_fn), + "host_callback" => func!(host_callback), + }, + }; + + let compiler = compiler_for_backend(Backend::default()).unwrap(); + let module = compile_with(&wasm_bytes[..], compiler.as_ref()).unwrap(); + let instance = module + .instantiate(&imports) + .expect("failed to instantiate wasm module"); + + let entry_point = instance.func::<(u32, u32), u32>("main").unwrap(); + + entry_point.call(0, 0).expect("START"); +} diff --git a/lib/runtime-core/src/table/anyfunc.rs b/lib/runtime-core/src/table/anyfunc.rs index 8336b5028..4a63c8f62 100644 --- a/lib/runtime-core/src/table/anyfunc.rs +++ b/lib/runtime-core/src/table/anyfunc.rs @@ -44,7 +44,7 @@ impl<'a> From> for Anyfunc<'a> { } pub struct AnyfuncTable { - pub backing: Vec, + pub(crate) backing: Vec, max: Option, } diff --git a/lib/runtime-core/src/table/mod.rs b/lib/runtime-core/src/table/mod.rs index 8fb321501..1b61cd754 100644 --- a/lib/runtime-core/src/table/mod.rs +++ b/lib/runtime-core/src/table/mod.rs @@ -9,7 +9,8 @@ use std::{cell::RefCell, fmt, ptr, rc::Rc}; mod anyfunc; -pub use self::anyfunc::{Anyfunc, AnyfuncTable}; +pub use self::anyfunc::Anyfunc; +pub(crate) use self::anyfunc::AnyfuncTable; use crate::error::GrowError; pub enum Element<'a> { diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index a4abc7b02..e3084a9c5 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -398,14 +398,16 @@ impl Ctx { } } - /// Calls a host or Wasm function at the given index - pub fn call_with_index(&mut self, index: TableIndex, args: &[Value]) -> CallResult> { + /// Calls a host or Wasm function at the given table index + pub fn call_with_table_index( + &mut self, + index: TableIndex, + args: &[Value], + ) -> CallResult> { let anyfunc_table = unsafe { &*((**self.internal.tables).table as *mut crate::table::AnyfuncTable) }; - let entry = anyfunc_table.backing[index.index()]; + let Anyfunc { func, ctx, sig_id } = anyfunc_table.backing[index.index()]; - let fn_ptr = entry.func; - let sig_id = entry.sig_id; let signature = SigRegistry.lookup_signature(unsafe { std::mem::transmute(sig_id.0) }); let mut rets = vec![]; @@ -420,8 +422,8 @@ impl Ctx { }; call_func_with_index_inner( - self as *mut Ctx, /* doesn't handle all cases */ - NonNull::new(fn_ptr as *mut _).unwrap(), + ctx, + NonNull::new(func as *mut _).unwrap(), &signature, wasm, args,