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 host env via trait with proc macro #1739

Merged
merged 47 commits into from
Dec 1, 2020
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3c7dfe2
Add hacked together vertical slice of host env updating idea
Oct 20, 2020
ed12021
Clean up code a bit
Oct 20, 2020
103ea03
Rename trait, get tests running
Oct 20, 2020
011ec22
Merge branch 'master' into feature/host-env-prototype
MarkMcCaskey Oct 20, 2020
b78447f
Fix up merge, use new union
Oct 20, 2020
d64908d
Fix package tests
Oct 21, 2020
46204d6
Fix up more tests
Oct 21, 2020
1b71887
Remove VMContext port to union, split into #1753
Oct 22, 2020
f3b7f42
Remove union logic from deprecated crate too
Oct 22, 2020
c5b94c5
Add first draft of `WasmerEnv` derive macro
Oct 22, 2020
a7abee6
Add lazy abstraction, improve macro, use macro internally
Oct 23, 2020
cfa87b2
Add misc changes, update from feedback
Oct 26, 2020
5b67b2f
Merge branch 'master' into feature/host-env-prototype
MarkMcCaskey Oct 27, 2020
1dd6d8d
Add modified attribute to get `NativeFunc` working
Oct 28, 2020
8233001
Add support for generics and lifetimes for WasmerEnv derive
Oct 28, 2020
8b87526
Create single interface to get exports from Instance.exports
Oct 28, 2020
be3ab95
Add error handling to host init logic
Oct 29, 2020
83008a7
Fix up error handling code, get tests passing
Oct 29, 2020
78f958b
Clean up misc code
Oct 29, 2020
a25288a
Improve error messages on `WasmerEnv` macro, clean up code, add tests
Oct 29, 2020
52191a0
Clean up and fix test
Oct 29, 2020
1c9fc1f
Fix up doc tests in api
Oct 29, 2020
2690e5e
Merge branch 'master' into feature/host-env-prototype
MarkMcCaskey Nov 16, 2020
a19705a
Remove free method, call finalizers in C API
Nov 17, 2020
7570710
Add test initializing and calling host function manually
Nov 17, 2020
655ac09
Fix up helpers generated by WasmerEnv; add `unchecked` variant
Nov 17, 2020
619afb5
Add support for tuple structs and unit structs in derive(WasmerEnv)
Nov 17, 2020
38b296e
Move `WasmerEnv` into its own mod, implement it for stdlib types
Nov 17, 2020
2b0464a
Port wasmer-emscripten to use `WasmerEnv`
Nov 18, 2020
6aab77e
Add default impl for `WasmerEnv::finish` remove macro
Nov 18, 2020
3580f16
Rename `WasmerEnv::finish` to `WasmerEnv::init_with_instance`
Nov 18, 2020
7131caa
Implement `WasmerEnv` for `dyn Any`
Nov 18, 2020
15e88a1
Clean up error message in proc macro, improve docs on WasmerEnv
Nov 18, 2020
2065556
Merge branch 'master' into feature/host-env-prototype
MarkMcCaskey Nov 18, 2020
85169f6
Add misc clean ups and corrections
Nov 18, 2020
0e03544
Merge branch 'feature/host-env-prototype' of github.com:wasmerio/wasm…
Nov 18, 2020
37d0c36
Clean up code, reduce memory usage, improve correctness
Nov 18, 2020
de6cb9c
Merge branch 'master' into feature/host-env-prototype
Nov 20, 2020
7013163
WIP attempt to make an Export wrapper type
Nov 25, 2020
40eec3f
Address feedback: misc clean ups
Nov 25, 2020
8669e92
Move `EngineExport` to engine
Nov 26, 2020
9e0cfce
Rename vm::Export to vm::VMExport
Nov 30, 2020
03410c1
Rename `EngineExport` to `Export`
Nov 30, 2020
2c9ca4a
Add engine::export
Nov 30, 2020
d0c44c6
Merge pull request #1842 from wasmerio/host-env-prototype-export-change
MarkMcCaskey Nov 30, 2020
4ef3286
Merge branch 'master' into feature/host-env-prototype
Dec 1, 2020
e960220
Update changelog with info about `WasmerEnv`
Dec 1, 2020
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
3 changes: 0 additions & 3 deletions examples/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let import_object = wasi_env.import_object(&module)?;
let instance = Instance::new(&module, &import_object)?;

// WASI requires to explicitly set the memory for the `WasiEnv`
wasi_env.set_memory(instance.exports.get_memory("memory")?.clone());
MarkMcCaskey marked this conversation as resolved.
Show resolved Hide resolved

println!("Call WASI `_start` function...");
// And we just call the `_start` function!
let start = instance.exports.get_function("_start")?;
Expand Down
50 changes: 39 additions & 11 deletions lib/api/src/externals/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ use std::cmp::max;
use std::fmt;
use wasmer_vm::{
raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction,
VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
VMTrampoline,
FunctionExtraData, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody,
VMFunctionKind, VMTrampoline,
};

/// A function defined in the Wasm module
Expand Down Expand Up @@ -85,7 +85,9 @@ impl Function {
// The engine linker will replace the address with one pointing to a
// generated dynamic trampoline.
let address = std::ptr::null() as *const VMFunctionBody;
let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext;
let vmctx = FunctionExtraData {
host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _,
};

Self {
store: store.clone(),
Expand All @@ -94,6 +96,7 @@ impl Function {
address,
kind: VMFunctionKind::Dynamic,
vmctx,
function_ptr: None,
signature: ty.clone(),
call_trampoline: None,
},
Expand All @@ -105,12 +108,16 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv, Instance};
/// # let store = Store::default();
///
/// struct Env {
/// multiplier: i32,
/// };
/// impl WasmerEnv for Env {
/// fn finish(&mut self, _instance: &Instance) {}
/// fn free(&mut self) {}
/// }
/// let env = Env { multiplier: 2 };
///
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
Expand All @@ -124,7 +131,7 @@ impl Function {
pub fn new_with_env<F, Env>(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self
where
F: Fn(&mut Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static,
Env: Sized + 'static,
Env: Sized + crate::WasmerEnv + 'static,
MarkMcCaskey marked this conversation as resolved.
Show resolved Hide resolved
{
let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv {
env: RefCell::new(env),
Expand All @@ -135,7 +142,12 @@ impl Function {
// The engine linker will replace the address with one pointing to a
// generated dynamic trampoline.
let address = std::ptr::null() as *const VMFunctionBody;
let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext;
let vmctx = FunctionExtraData {
host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _,
};
// TODO: look into removing transmute by changing API type signatures
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How we can change the API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no good way to do this that I can think of yet. The only way to avoid the transmutes would be to to make the WasmerEnv::init_with_instance function take void* directly... but that seems like a bad trade off.

let function_ptr = Some(unsafe { std::mem::transmute::<fn(_, _), fn(_, _)>(Env::finish) });
//dbg!(function_ptr);

Self {
store: store.clone(),
Expand All @@ -144,6 +156,7 @@ impl Function {
address,
kind: VMFunctionKind::Dynamic,
vmctx,
function_ptr,
signature: ty.clone(),
call_trampoline: None,
},
Expand Down Expand Up @@ -176,7 +189,9 @@ impl Function {
{
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address() as *const VMFunctionBody;
let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext;
let vmctx = FunctionExtraData {
host_env: std::ptr::null_mut() as *mut _,
};
let signature = function.ty();

Self {
Expand All @@ -186,6 +201,9 @@ impl Function {
address,
vmctx,
signature,
// TODO: figure out what's going on in this function: it takes an `Env`
// param but also marks itself as not having an env
function_ptr: None,
kind: VMFunctionKind::Static,
call_trampoline: None,
},
Expand All @@ -200,12 +218,16 @@ impl Function {
/// # Example
///
/// ```
/// # use wasmer::{Store, Function};
/// # use wasmer::{Store, Function, WasmerEnv, Instance};
/// # let store = Store::default();
///
/// struct Env {
/// multiplier: i32,
/// };
/// impl WasmerEnv for Env {
/// fn finish(&mut self, _instance: &Instance) {}
/// fn free(&mut self) {}
/// }
/// let env = Env { multiplier: 2 };
///
/// fn sum_and_multiply(env: &mut Env, a: i32, b: i32) -> i32 {
Expand All @@ -219,7 +241,7 @@ impl Function {
F: HostFunction<Args, Rets, WithEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: Sized + 'static,
Env: Sized + crate::WasmerEnv + 'static,
{
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address();
Expand All @@ -230,7 +252,12 @@ impl Function {
// In the case of Host-defined functions `VMContext` is whatever environment
// the user want to attach to the function.
let box_env = Box::new(env);
let vmctx = Box::into_raw(box_env) as *mut _ as *mut VMContext;
let vmctx = FunctionExtraData {
host_env: Box::into_raw(box_env) as *mut _,
};
// TODO: look into removing transmute by changing API type signatures
let function_ptr = Some(unsafe { std::mem::transmute::<fn(_, _), fn(_, _)>(Env::finish) });
//dbg!(function_ptr as usize);
let signature = function.ty();

Self {
Expand All @@ -240,6 +267,7 @@ impl Function {
address,
kind: VMFunctionKind::Static,
vmctx,
function_ptr,
signature,
call_trampoline: None,
},
Expand Down Expand Up @@ -365,7 +393,7 @@ impl Function {
Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition {
has_env: !wasmer_export.vmctx.is_null(),
has_env: !unsafe { wasmer_export.vmctx.host_env.is_null() },
}),
exported: wasmer_export,
}
Expand Down
12 changes: 10 additions & 2 deletions lib/api/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,19 @@ impl Instance {
})
.collect::<Exports>();

Ok(Self {
let instance = Self {
handle,
module: module.clone(),
exports,
})
};

unsafe {
MarkMcCaskey marked this conversation as resolved.
Show resolved Hide resolved
instance
.handle
.initialize_host_envs(&instance as *const _ as *const _);
}

Ok(instance)
}

/// Gets the [`Module`] associated with this instance.
Expand Down
23 changes: 23 additions & 0 deletions lib/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,26 @@ pub use wasmer_engine_native::{Native, NativeArtifact, NativeEngine};

/// Version number of this crate.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");

// --------------------------------------------------------------
// TODO: put this in a proper location, just prototyping for now:
// TODO: rename everything, all names are throw-away names
MarkMcCaskey marked this conversation as resolved.
Show resolved Hide resolved

/// Prototype trait for finishing envs.
pub trait WasmerEnv {
/// The function that Wasmer will call on your type to let it finish
/// instantiating.
MarkMcCaskey marked this conversation as resolved.
Show resolved Hide resolved
fn finish(&mut self, instance: &Instance);

/// Frees memory written to `self` so it can be dropped without any memory leaks.
fn free(&mut self);
}

impl<T: WasmerEnv> WasmerEnv for &'static mut T {
fn finish(&mut self, instance: &Instance) {
(*self).finish(instance)
}
fn free(&mut self) {
(*self).free()
}
}
25 changes: 17 additions & 8 deletions lib/api/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ use crate::{FromToNativeWasmType, Function, FunctionType, RuntimeError, Store, W
use std::panic::{catch_unwind, AssertUnwindSafe};
use wasmer_types::NativeWasmType;
use wasmer_vm::{
ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind,
ExportFunction, FunctionExtraData, VMContext, VMDynamicFunctionContext, VMFunctionBody,
VMFunctionKind,
};

/// A WebAssembly function that can be called natively
Expand All @@ -26,7 +27,7 @@ pub struct NativeFunc<'a, Args = (), Rets = ()> {
definition: FunctionDefinition,
store: Store,
address: *const VMFunctionBody,
vmctx: *mut VMContext,
vmctx: FunctionExtraData,
arg_kind: VMFunctionKind,
// exported: ExportFunction,
_phantom: PhantomData<(&'a (), Args, Rets)>,
Expand All @@ -42,7 +43,7 @@ where
pub(crate) fn new(
store: Store,
address: *const VMFunctionBody,
vmctx: *mut VMContext,
vmctx: FunctionExtraData,
arg_kind: VMFunctionKind,
definition: FunctionDefinition,
) -> Self {
Expand All @@ -68,6 +69,8 @@ where
address: other.address,
vmctx: other.vmctx,
signature,
// TODO:
function_ptr: None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really think this doesn't belong here.

kind: other.arg_kind,
call_trampoline: None,
}
Expand All @@ -88,6 +91,8 @@ where
address: other.address,
vmctx: other.vmctx,
signature,
// TODO:
function_ptr: None,
kind: other.arg_kind,
call_trampoline: None,
},
Expand Down Expand Up @@ -165,7 +170,7 @@ macro_rules! impl_native_traits {
match self.arg_kind {
VMFunctionKind::Static => {
let results = catch_unwind(AssertUnwindSafe(|| unsafe {
let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address);
let f = std::mem::transmute::<_, unsafe extern "C" fn( FunctionExtraData, $( $x, )*) -> Rets::CStruct>(self.address);
// We always pass the vmctx
f( self.vmctx, $( $x, )* )
})).map_err(|e| RuntimeError::new(format!("{:?}", e)))?;
Expand All @@ -175,12 +180,16 @@ macro_rules! impl_native_traits {
let params_list = [ $( $x.to_native().to_value() ),* ];
let results = if !has_env {
type VMContextWithoutEnv = VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv>;
let ctx = self.vmctx as *mut VMContextWithoutEnv;
unsafe { (*ctx).ctx.call(&params_list)? }
unsafe {
let ctx = self.vmctx.host_env as *mut VMContextWithoutEnv;
(*ctx).ctx.call(&params_list)?
}
} else {
type VMContextWithEnv = VMDynamicFunctionContext<VMDynamicFunctionWithEnv<std::ffi::c_void>>;
let ctx = self.vmctx as *mut VMContextWithEnv;
unsafe { (*ctx).ctx.call(&params_list)? }
unsafe {
let ctx = self.vmctx.host_env as *mut VMContextWithEnv;
(*ctx).ctx.call(&params_list)?
}
};
let mut rets_list_array = Rets::empty_array();
let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128;
Expand Down
7 changes: 6 additions & 1 deletion lib/api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ impl ValFuncRef for Val {
Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc {
func_ptr: ptr::null(),
type_index: wasmer_vm::VMSharedSignatureIndex::default(),
vmctx: ptr::null_mut(),
vmctx: wasmer_vm::FunctionExtraData {
host_env: ptr::null_mut(),
},
},
Self::FuncRef(f) => f.checked_anyfunc(),
_ => return Err(RuntimeError::new("val is not funcref")),
Expand All @@ -74,6 +76,9 @@ impl ValFuncRef for Val {
let export = wasmer_vm::ExportFunction {
address: item.func_ptr,
signature,
// TODO:
// figure out if we ever need a value here: need testing with complicated import patterns
function_ptr: None,
// All functions in tables are already Static (as dynamic functions
// are converted to use the trampolines with static signatures).
kind: wasmer_vm::VMFunctionKind::Static,
Expand Down
9 changes: 9 additions & 0 deletions lib/api/tests/externals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,11 @@ fn function_new_env() -> Result<()> {
let store = Store::default();
#[derive(Clone)]
struct MyEnv {};
impl WasmerEnv for MyEnv {
fn finish(&mut self, _instance: &Instance) {}
fn free(&mut self) {}
}

let my_env = MyEnv {};
let function = Function::new_native_with_env(&store, my_env.clone(), |_env: &mut MyEnv| {});
assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
Expand Down Expand Up @@ -273,6 +278,10 @@ fn function_new_dynamic_env() -> Result<()> {
#[derive(Clone)]
struct MyEnv {};
let my_env = MyEnv {};
impl WasmerEnv for MyEnv {
fn finish(&mut self, _instance: &Instance) {}
fn free(&mut self) {}
}

let function_type = FunctionType::new(vec![], vec![]);
let function = Function::new_with_env(
Expand Down
5 changes: 5 additions & 0 deletions lib/c-api/src/deprecated/import/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,11 @@ pub(crate) struct LegacyEnv {
pub(crate) instance_ptr: Option<NonNull<CAPIInstance>>,
}

impl wasmer::WasmerEnv for LegacyEnv {
fn finish(&mut self, _instance: &wasmer::Instance) {}
fn free(&mut self) {}
}

impl LegacyEnv {
pub(crate) fn ctx_ptr(&self) -> *mut CAPIInstance {
self.instance_ptr
Expand Down
7 changes: 1 addition & 6 deletions lib/c-api/src/deprecated/import/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use libc::c_uchar;
use std::path::PathBuf;
use std::ptr;
use std::str;
use wasmer::{Memory, MemoryType, NamedResolver};
use wasmer::NamedResolver;
use wasmer_wasi as wasi;

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -213,11 +213,6 @@ pub unsafe extern "C" fn wasmer_wasi_generate_default_import_object() -> *mut wa
let mut wasi_state_builder = wasi::WasiState::new("wasmer-wasi-default-program-name");
let wasi_state = wasi_state_builder.build().unwrap();
let mut wasi_env = wasi::WasiEnv::new(wasi_state);
// this API will now leak a `Memory`
let memory_type = MemoryType::new(0, None, false);
let memory = Memory::new(store, memory_type).expect("create memory");
wasi_env.set_memory(memory);
// TODO(mark): review lifetime of `Memory` here
MarkMcCaskey marked this conversation as resolved.
Show resolved Hide resolved
let import_object_inner: Box<dyn NamedResolver> = Box::new(
wasi::generate_import_object_from_env(store, wasi_env, wasi::WasiVersion::Latest),
);
Expand Down
Loading