Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add method to call function at index on Ctx #803

Merged
merged 7 commits into from
Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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