Skip to content

Commit

Permalink
Merge #803
Browse files Browse the repository at this point in the history
803: Add method to call function at index on Ctx r=MarkMcCaskey a=MarkMcCaskey

For #638 and #670

```Rust
fn call_guest_fn(ctx: &mut Ctx, guest_fn: u32) -> u32 {
    println!("{}", guest_fn);

    let guest_fn_typed = unsafe { std::mem::transmute(guest_fn) };

    let result = ctx.call_with_table_index(guest_fn_typed, &[]).unwrap();
    println!("  -> {:?}", result);

    0
}
```
is what this looks like from the Host side

See `examples/callback.rs` for an example that doesn't require `transmute`


# Review

- [x] Create a short description of the the change in the CHANGELOG.md file


Co-authored-by: Mark McCaskey <[email protected]>
Co-authored-by: Mark McCaskey <[email protected]>
  • Loading branch information
3 people authored Sep 19, 2019
2 parents aa67dbe + 3b200fa commit 0790ebf
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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`
- [#790](https://github.com/wasmerio/wasmer/pull/790) Fix flaky test failure with LLVM, switch to large code model.
- [#788](https://github.com/wasmerio/wasmer/pull/788) Use union merge on the changelog file.
- [#785](https://github.com/wasmerio/wasmer/pull/785) Include Apache license file for spectests.
Expand Down
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -105,3 +105,7 @@ managed = ["backend-singlepass", "wasmer-runtime-core/managed"]
[[example]]
name = "plugin"
crate-type = ["bin"]

[[example]]
name = "callback"
crate-type = ["bin"]
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: spectests emtests clean build install lint precommit docs
.PHONY: spectests emtests clean build install lint precommit docs examples

# Generate files
generate-spectests:
Expand Down Expand Up @@ -111,12 +111,16 @@ test: spectests emtests middleware wasitests circleci-clean test-rest


# Integration tests
integration-tests: release-clif
integration-tests: release-clif examples
echo "Running Integration Tests"
./integration_tests/lua/test.sh
./integration_tests/nginx/test.sh
./integration_tests/cowsay/test.sh

examples:
cargo run --example plugin
cargo run --example callback


# Utils
lint:
Expand Down
5 changes: 5 additions & 0 deletions examples/callback-guest/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Call back guest

This is part of the `callback` example. This Wasm module passes host imports and its own functions to the Wasm host to execute.

See `examples/callback.rs` for the host
24 changes: 24 additions & 0 deletions examples/callback-guest/callback-guest.rs
Original file line number Diff line number Diff line change
@@ -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) };
}
Binary file added examples/callback-guest/callback-guest.wasm
Binary file not shown.
46 changes: 46 additions & 0 deletions examples/callback.rs
Original file line number Diff line number Diff line change
@@ -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/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");
}
54 changes: 34 additions & 20 deletions lib/runtime-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -527,29 +527,12 @@ fn call_func_with_index(
args: &[Value],
rets: &mut Vec<Value>,
) -> CallResult<()> {
rets.clear();

let sig_index = *info
.func_assoc
.get(func_index)
.expect("broken invariant, incorrect func index");

let signature = &info.signatures[sig_index];
let num_results = signature.returns().len();
let num_results = num_results
+ signature
.returns()
.iter()
.filter(|&&ty| ty == Type::V128)
.count();
rets.reserve(num_results);

if !signature.check_param_value_types(args) {
Err(ResolveError::Signature {
expected: signature.clone(),
found: args.iter().map(|val| val.ty()).collect(),
})?
}

let func_ptr = match func_index.local_or_import(info) {
LocalOrImport::Local(local_func_index) => {
Expand All @@ -567,6 +550,39 @@ fn call_func_with_index(
}
};

let wasm = runnable
.get_trampoline(info, sig_index)
.expect("wasm trampoline");

call_func_with_index_inner(ctx_ptr, func_ptr, signature, wasm, args, rets)
}

pub(crate) fn call_func_with_index_inner(
ctx_ptr: *mut vm::Ctx,
func_ptr: NonNull<vm::Func>,
signature: &FuncSig,
wasm: Wasm,
args: &[Value],
rets: &mut Vec<Value>,
) -> CallResult<()> {
rets.clear();

let num_results = signature.returns().len();
let num_results = num_results
+ signature
.returns()
.iter()
.filter(|&&ty| ty == Type::V128)
.count();
rets.reserve(num_results);

if !signature.check_param_value_types(args) {
Err(ResolveError::Signature {
expected: signature.clone(),
found: args.iter().map(|val| val.ty()).collect(),
})?
}

let mut raw_args: SmallVec<[u64; 8]> = SmallVec::new();
for v in args {
match v {
Expand Down Expand Up @@ -598,9 +614,7 @@ fn call_func_with_index(
trampoline,
invoke,
invoke_env,
} = runnable
.get_trampoline(info, sig_index)
.expect("wasm trampoline");
} = wasm;

let run_wasm = |result_space: *mut u64| unsafe {
let mut trap_info = WasmTrapInfo::Unknown;
Expand Down
2 changes: 1 addition & 1 deletion lib/runtime-core/src/table/anyfunc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<'a> From<DynFunc<'a>> for Anyfunc<'a> {
}

pub struct AnyfuncTable {
backing: Vec<vm::Anyfunc>,
pub(crate) backing: Vec<vm::Anyfunc>,
max: Option<u32>,
}

Expand Down
2 changes: 1 addition & 1 deletion lib/runtime-core/src/table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::{cell::RefCell, fmt, ptr, rc::Rc};
mod anyfunc;

pub use self::anyfunc::Anyfunc;
use self::anyfunc::AnyfuncTable;
pub(crate) use self::anyfunc::AnyfuncTable;
use crate::error::GrowError;

pub enum Element<'a> {
Expand Down
43 changes: 41 additions & 2 deletions lib/runtime-core/src/vm.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
pub use crate::backing::{ImportBacking, LocalBacking, INTERNALS_SIZE};
use crate::{
error::CallResult,
instance::call_func_with_index_inner,
memory::{Memory, MemoryType},
module::{ModuleInfo, ModuleInner},
sig_registry::SigRegistry,
structures::TypedIndex,
types::{LocalOrImport, MemoryIndex},
types::{LocalOrImport, MemoryIndex, TableIndex, Value},
vmcalls,
};
use std::{
cell::UnsafeCell,
ffi::c_void,
mem, ptr,
mem,
ptr::{self, NonNull},
sync::atomic::{AtomicUsize, Ordering},
sync::Once,
};
Expand Down Expand Up @@ -393,6 +397,41 @@ impl Ctx {
(*self.internal.internals)[field.index()] = value;
}
}

/// Calls a host or Wasm function at the given table index
pub fn call_with_table_index(
&mut self,
index: TableIndex,
args: &[Value],
) -> CallResult<Vec<Value>> {
let anyfunc_table =
unsafe { &*((**self.internal.tables).table as *mut crate::table::AnyfuncTable) };
let Anyfunc { func, ctx, sig_id } = anyfunc_table.backing[index.index()];

let signature = SigRegistry.lookup_signature(unsafe { std::mem::transmute(sig_id.0) });
let mut rets = vec![];

let wasm = {
let module = unsafe { &*self.module };
let runnable = &module.runnable_module;

let sig_index = SigRegistry.lookup_sig_index(signature.clone());
runnable
.get_trampoline(&module.info, sig_index)
.expect("wasm trampoline")
};

call_func_with_index_inner(
ctx,
NonNull::new(func as *mut _).unwrap(),
&signature,
wasm,
args,
&mut rets,
)?;

Ok(rets)
}
}

#[doc(hidden)]
Expand Down

0 comments on commit 0790ebf

Please sign in to comment.