From 3c7dfe29f31f1597cd6c903f07d9e2456c4125ad Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 19 Oct 2020 17:19:46 -0700 Subject: [PATCH 01/39] Add hacked together vertical slice of host env updating idea --- lib/api/src/externals/function.rs | 30 ++++++++++++++----- lib/api/src/instance.rs | 15 ++++++++-- lib/api/src/lib.rs | 14 +++++++++ lib/api/src/module.rs | 15 ++++++++-- lib/api/src/native.rs | 25 +++++++++++----- lib/api/src/types.rs | 6 +++- lib/cli/Cargo.toml | 2 +- lib/cli/src/commands/run/wasi.rs | 2 +- lib/engine/src/artifact.rs | 29 ++++++++++++++++-- lib/engine/src/resolver.rs | 4 ++- lib/vm/src/export.rs | 4 ++- lib/vm/src/instance.rs | 50 +++++++++++++++++++++---------- lib/vm/src/lib.rs | 8 ++--- lib/vm/src/trap/traphandlers.rs | 14 ++++----- lib/vm/src/vmcontext.rs | 39 ++++++++++++++++++++---- lib/vm/src/vmoffsets.rs | 2 +- lib/wasi/src/lib.rs | 29 ++++++++++++++---- tests/lib/wast/src/wasi_wast.rs | 2 +- 18 files changed, 222 insertions(+), 68 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index fcf00b74342..ac0b5f26b4b 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -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 @@ -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(), @@ -94,6 +96,7 @@ impl Function { address, kind: VMFunctionKind::Dynamic, vmctx, + function_ptr: 0, signature: ty.clone(), }, } @@ -134,7 +137,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(), @@ -143,6 +148,8 @@ impl Function { address, kind: VMFunctionKind::Dynamic, vmctx, + // TODO: + function_ptr: 0, signature: ty.clone(), }, } @@ -174,7 +181,9 @@ impl Function { { let function = inner::Function::::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 { @@ -184,6 +193,8 @@ impl Function { address, vmctx, signature, + // TODO: + function_ptr: 0, kind: VMFunctionKind::Static, }, } @@ -216,7 +227,7 @@ impl Function { F: HostFunction, Args: WasmTypeList, Rets: WasmTypeList, - Env: Sized + 'static, + Env: Sized + crate::WasmerPostInstantiate + 'static, { let function = inner::Function::::new(func); let address = function.address(); @@ -227,7 +238,11 @@ 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 _, + }; + let function_ptr = Env::finish as usize; + dbg!(function_ptr); let signature = function.ty(); Self { @@ -237,6 +252,7 @@ impl Function { address, kind: VMFunctionKind::Static, vmctx, + function_ptr, signature, }, } diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index cac647fce10..61f51a43ae1 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -73,7 +73,7 @@ impl Instance { pub fn new(module: &Module, resolver: &dyn Resolver) -> Result { let store = module.store(); - let handle = module.instantiate(resolver)?; + let (handle, thunks) = module.instantiate(resolver)?; let exports = module .exports() @@ -85,11 +85,20 @@ impl Instance { }) .collect::(); - Ok(Self { + let instance = Self { handle, module: module.clone(), exports, - }) + }; + + for (func, env) in thunks.iter() { + dbg!(func, env); + unsafe { + func(*env, (&instance) as *const _ as *const _); + } + } + + Ok(instance) } /// Gets the [`Module`] associated with this instance. diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 2a1f42c246c..ce4d8204a83 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -118,3 +118,17 @@ 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 + +/// Prototype trait for finishing envs. +pub trait WasmerPostInstantiate { + /// The function that Wasmer will call on your type to let it finish + /// instantiating. + fn finish(&mut self, instance: &Instance); + + /// Frees memory written to `self` so it can be dropped without any memory leaks. + fn free(&mut self); +} diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 714991cba58..74b361a8d3f 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -261,9 +261,18 @@ impl Module { pub(crate) fn instantiate( &self, resolver: &dyn Resolver, - ) -> Result { + ) -> Result< + ( + InstanceHandle, + Vec<( + fn(*mut std::ffi::c_void, *const std::ffi::c_void), + *mut std::ffi::c_void, + )>, + ), + InstantiationError, + > { unsafe { - let instance_handle = + let (instance_handle, thunks) = self.artifact .instantiate(self.store.tunables(), resolver, Box::new(()))?; @@ -274,7 +283,7 @@ impl Module { // instance tables. self.artifact.finish_instantiation(&instance_handle)?; - Ok(instance_handle) + Ok((instance_handle, thunks)) } } diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index 5a73083f2cb..9957e23bb63 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -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 @@ -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)>, @@ -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 { @@ -68,6 +69,8 @@ where address: other.address, vmctx: other.vmctx, signature, + // TODO: + function_ptr: 0, kind: other.arg_kind, } } @@ -87,6 +90,8 @@ where address: other.address, vmctx: other.vmctx, signature, + // TODO: + function_ptr: 0, kind: other.arg_kind, }, } @@ -163,7 +168,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)))?; @@ -173,12 +178,16 @@ macro_rules! impl_native_traits { let params_list = [ $( $x.to_native().to_value() ),* ]; let results = if !has_env { type VMContextWithoutEnv = VMDynamicFunctionContext; - let ctx = self.vmctx as *mut VMContextWithoutEnv; - unsafe { (*ctx).ctx.call(¶ms_list)? } + unsafe { + let ctx = self.vmctx.host_env as *mut VMContextWithoutEnv; + (*ctx).ctx.call(¶ms_list)? + } } else { type VMContextWithEnv = VMDynamicFunctionContext>; - let ctx = self.vmctx as *mut VMContextWithEnv; - unsafe { (*ctx).ctx.call(¶ms_list)? } + unsafe { + let ctx = self.vmctx.host_env as *mut VMContextWithEnv; + (*ctx).ctx.call(¶ms_list)? + } }; let mut rets_list_array = Rets::empty_array(); let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128; diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index b085f6a2419..cea1336d60f 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -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")), @@ -74,6 +76,8 @@ impl ValFuncRef for Val { let export = wasmer_vm::ExportFunction { address: item.func_ptr, signature, + // TODO: + function_ptr: 0, // All functions in tables are already Static (as dynamic functions // are converted to use the trampolines with static signatures). kind: wasmer_vm::VMFunctionKind::Static, diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index 2ffdede2d3c..9ec6f6f6868 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -58,7 +58,7 @@ default = [ "object-file", "cache", "wasi", - "emscripten", + # "emscripten", ] engine = [] jit = [ diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index 71f41c95291..d74dbd3f63a 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -58,7 +58,7 @@ impl Wasi { let import_object = wasi_env.import_object(&module)?; let instance = Instance::new(&module, &import_object)?; - wasi_env.set_memory(instance.exports.get_memory("memory")?.clone()); + //wasi_env.set_memory(instance.exports.get_memory("memory")?.clone()); let start = instance.exports.get_function("_start")?; let result = start.call(&[]); diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index f74fc4717bf..5719fa6d21e 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -86,7 +86,16 @@ pub trait Artifact: Send + Sync + Upcastable { tunables: &dyn Tunables, resolver: &dyn Resolver, host_state: Box, - ) -> Result { + ) -> Result< + ( + InstanceHandle, + Vec<( + fn(*mut std::ffi::c_void, *const std::ffi::c_void), + *mut std::ffi::c_void, + )>, + ), + InstantiationError, + > { self.preinstantiate()?; let module = self.module(); @@ -98,6 +107,19 @@ pub trait Artifact: Send + Sync + Upcastable { self.table_styles(), ) .map_err(InstantiationError::Link)?; + + let mut thunks = vec![]; + // ------------ + for func in imports.functions.values() { + unsafe { + let finish: fn(*mut std::ffi::c_void, instance: *const std::ffi::c_void) = + std::mem::transmute(func.function_ptr); + dbg!(func.extra_data.host_env); + thunks.push((finish, func.extra_data.host_env)); + } + } + // ------------ + let finished_memories = tunables .create_memories(&module, self.memory_styles()) .map_err(InstantiationError::Link)? @@ -113,7 +135,7 @@ pub trait Artifact: Send + Sync + Upcastable { self.register_frame_info(); - InstanceHandle::new( + let handle = InstanceHandle::new( module, self.finished_functions().clone(), finished_memories, @@ -123,7 +145,8 @@ pub trait Artifact: Send + Sync + Upcastable { self.signatures().clone(), host_state, ) - .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap))) + .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))?; + Ok((handle, thunks)) } /// Finishes the instantiation of a just created `InstanceHandle`. diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index 82b5df6251d..0e27426f60c 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -167,7 +167,9 @@ pub fn resolve_imports( }; function_imports.push(VMFunctionImport { body: address, - vmctx: f.vmctx, + extra_data: f.vmctx, + // TODO: + function_ptr: f.function_ptr, }); } Export::Table(ref t) => { diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 7879c92d16a..23672aa8f17 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -30,7 +30,9 @@ pub struct ExportFunction { /// The address of the native-code function. pub address: *const VMFunctionBody, /// Pointer to the containing `VMContext`. - pub vmctx: *mut VMContext, + pub vmctx: crate::vmcontext::FunctionExtraData, + /// temp code to set vmctx for host functions + pub function_ptr: usize, /// The function type, used for compatibility checking. pub signature: FunctionType, /// The function kind (it defines how it's the signature that provided `address` have) diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index d5a674ceee3..055d57e2cfc 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -291,13 +291,19 @@ impl Instance { match export { ExportIndex::Function(index) => { let sig_index = &self.module.functions[*index]; - let (address, vmctx) = if let Some(def_index) = self.module.local_func_index(*index) - { - (self.functions[def_index].0 as *const _, self.vmctx_ptr()) - } else { - let import = self.imported_function(*index); - (import.body, import.vmctx) - }; + let (address, vmctx, function_ptr) = + if let Some(def_index) = self.module.local_func_index(*index) { + ( + self.functions[def_index].0 as *const _, + crate::vmcontext::FunctionExtraData { + vmctx: self.vmctx_ptr(), + }, + 0, + ) + } else { + let import = self.imported_function(*index); + (import.body, import.extra_data, import.function_ptr) + }; let signature = self.module.signatures[*sig_index].clone(); ExportFunction { address, @@ -308,6 +314,7 @@ impl Instance { kind: VMFunctionKind::Static, signature, vmctx, + function_ptr, } .into() } @@ -365,28 +372,34 @@ impl Instance { None => return Ok(()), }; - let (callee_address, callee_vmctx) = match self.module.local_func_index(start_index) { + let (callee_address, callee_extra_data) = match self.module.local_func_index(start_index) { Some(local_index) => { let body = self .functions .get(local_index) .expect("function index is out of bounds") .0; - (body as *const _, self.vmctx_ptr()) + ( + body as *const _, + crate::FunctionExtraData { + vmctx: self.vmctx_ptr(), + }, + ) } None => { assert_lt!(start_index.index(), self.module.num_imported_functions); let import = self.imported_function(start_index); - (import.body, import.vmctx) + (import.body, import.extra_data) } }; // Make the call. unsafe { - catch_traps(callee_vmctx, || { - mem::transmute::<*const VMFunctionBody, unsafe extern "C" fn(*mut VMContext)>( - callee_address, - )(callee_vmctx) + catch_traps(callee_extra_data, || { + mem::transmute::< + *const VMFunctionBody, + unsafe extern "C" fn(crate::FunctionExtraData), + >(callee_address)(callee_extra_data) }) } } @@ -556,10 +569,15 @@ impl Instance { let type_index = self.signature_id(sig); let (func_ptr, vmctx) = if let Some(def_index) = self.module.local_func_index(index) { - (self.functions[def_index].0 as *const _, self.vmctx_ptr()) + ( + self.functions[def_index].0 as *const _, + crate::FunctionExtraData { + vmctx: self.vmctx_ptr(), + }, + ) } else { let import = self.imported_function(index); - (import.body, import.vmctx) + (import.body, import.extra_data) }; VMCallerCheckedAnyfunc { func_ptr, diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index f8e649f591f..b9e9e39e153 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -48,10 +48,10 @@ pub use crate::sig_registry::SignatureRegistry; pub use crate::table::{LinearTable, Table, TableStyle}; pub use crate::trap::*; pub use crate::vmcontext::{ - VMBuiltinFunctionIndex, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, - VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, - VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, - VMTrampoline, + FunctionExtraData, VMBuiltinFunctionIndex, VMCallerCheckedAnyfunc, VMContext, + VMDynamicFunctionContext, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, + VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, + VMTableImport, VMTrampoline, }; pub use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets}; diff --git a/lib/vm/src/trap/traphandlers.rs b/lib/vm/src/trap/traphandlers.rs index 613e8ec1035..a09b13bf537 100644 --- a/lib/vm/src/trap/traphandlers.rs +++ b/lib/vm/src/trap/traphandlers.rs @@ -429,13 +429,13 @@ impl Trap { /// Wildly unsafe because it calls raw function pointers and reads/writes raw /// function pointers. pub unsafe fn wasmer_call_trampoline( - vmctx: *mut VMContext, + vmctx: crate::FunctionExtraData, trampoline: VMTrampoline, callee: *const VMFunctionBody, values_vec: *mut u8, ) -> Result<(), Trap> { catch_traps(vmctx, || { - mem::transmute::<_, extern "C" fn(*mut VMContext, *const VMFunctionBody, *mut u8)>( + mem::transmute::<_, extern "C" fn(crate::FunctionExtraData, *const VMFunctionBody, *mut u8)>( trampoline, )(vmctx, callee, values_vec) }) @@ -447,7 +447,7 @@ pub unsafe fn wasmer_call_trampoline( /// # Safety /// /// Highly unsafe since `closure` won't have any destructors run. -pub unsafe fn catch_traps(vmctx: *mut VMContext, mut closure: F) -> Result<(), Trap> +pub unsafe fn catch_traps(vmctx: crate::FunctionExtraData, mut closure: F) -> Result<(), Trap> where F: FnMut(), { @@ -481,7 +481,7 @@ where /// /// Check [`catch_traps`]. pub unsafe fn catch_traps_with_result( - vmctx: *mut VMContext, + vmctx: crate::FunctionExtraData, mut closure: F, ) -> Result where @@ -501,7 +501,7 @@ pub struct CallThreadState { jmp_buf: Cell<*const u8>, reset_guard_page: Cell, prev: Option<*const CallThreadState>, - vmctx: *mut VMContext, + vmctx: crate::FunctionExtraData, handling_trap: Cell, } @@ -518,7 +518,7 @@ enum UnwindReason { } impl CallThreadState { - fn new(vmctx: *mut VMContext) -> Self { + fn new(vmctx: crate::FunctionExtraData) -> Self { Self { unwind: Cell::new(UnwindReason::None), vmctx, @@ -561,7 +561,7 @@ impl CallThreadState { fn any_instance(&self, func: impl Fn(&InstanceHandle) -> bool) -> bool { unsafe { - if func(&InstanceHandle::from_vmctx(self.vmctx)) { + if func(&InstanceHandle::from_vmctx(self.vmctx.vmctx)) { return true; } match self.prev { diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index 367a207629c..d1de6b3110b 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -15,6 +15,29 @@ use std::ptr::{self, NonNull}; use std::sync::Arc; use std::u32; +/// We stop lying about what this daat is +/// TODO: +#[derive(Copy, Clone)] +pub union FunctionExtraData { + /// Wasm function, it has a real VMContext: + pub vmctx: *mut VMContext, + /// Host functions can have custom environments + pub host_env: *mut std::ffi::c_void, +} + +impl std::fmt::Debug for FunctionExtraData { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "FunctionExtarData union") + } +} + +impl std::cmp::PartialEq for FunctionExtraData { + fn eq(&self, rhs: &Self) -> bool { + // TODO + false + } +} + /// An imported function. #[derive(Debug, Copy, Clone)] #[repr(C)] @@ -22,8 +45,12 @@ pub struct VMFunctionImport { /// A pointer to the imported function body. pub body: *const VMFunctionBody, - /// A pointer to the `VMContext` that owns the function. - pub vmctx: *mut VMContext, + /// A pointer to the `VMContext` that owns the function or host data. + pub extra_data: FunctionExtraData, + + /// temporary hack + /// Only used by host env + pub function_ptr: usize, } #[cfg(test)] @@ -46,7 +73,7 @@ mod test_vmfunction_import { usize::from(offsets.vmfunction_import_body()) ); assert_eq!( - offset_of!(VMFunctionImport, vmctx), + offset_of!(VMFunctionImport, extra_data), usize::from(offsets.vmfunction_import_vmctx()) ); } @@ -729,7 +756,7 @@ pub struct VMCallerCheckedAnyfunc { /// Function signature id. pub type_index: VMSharedSignatureIndex, /// Function `VMContext`. - pub vmctx: *mut VMContext, + pub vmctx: FunctionExtraData, // If more elements are added here, remember to add offset_of tests below! } @@ -768,7 +795,9 @@ impl Default for VMCallerCheckedAnyfunc { Self { func_ptr: ptr::null_mut(), type_index: Default::default(), - vmctx: ptr::null_mut(), + vmctx: FunctionExtraData { + vmctx: ptr::null_mut(), + }, } } } diff --git a/lib/vm/src/vmoffsets.rs b/lib/vm/src/vmoffsets.rs index b18408165d3..66406d0035f 100644 --- a/lib/vm/src/vmoffsets.rs +++ b/lib/vm/src/vmoffsets.rs @@ -109,7 +109,7 @@ impl VMOffsets { /// /// [`VMFunctionImport`]: crate::vmcontext::VMFunctionImport pub fn size_of_vmfunction_import(&self) -> u8 { - 2 * self.pointer_size + 3 * self.pointer_size } } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 74a0fab3819..d0733055f68 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -51,7 +51,25 @@ pub enum WasiError { #[derive(Debug, Clone)] pub struct WasiEnv { state: Arc>, - memory: Arc, + memory: *mut Memory, +} + +impl wasmer::WasmerPostInstantiate for WasiEnv { + fn finish(&mut self, instance: &wasmer::Instance) { + dbg!("in Wasi::Finish"); + let memory = instance.exports.get_memory("memory").unwrap(); + unsafe { + let heap_ptr = Box::into_raw(Box::new(memory.clone())); + self.memory = heap_ptr; + } + } + + fn free(&mut self) { + unsafe { + Box::from_raw(self.memory); + self.memory = std::ptr::null_mut(); + } + } } /// Wrapper type around `Memory` used to delay initialization of the memory. @@ -140,7 +158,7 @@ impl WasiEnv { pub fn new(state: WasiState) -> Self { Self { state: Arc::new(Mutex::new(state)), - memory: Arc::new(WasiMemory::new()), + memory: std::ptr::null_mut(), } } @@ -154,9 +172,9 @@ impl WasiEnv { } /// Set the memory - pub fn set_memory(&mut self, memory: Memory) -> bool { + /*pub fn set_memory(&mut self, memory: Memory) -> bool { self.memory.set_memory(memory) - } + }*/ /// Get the WASI state pub fn state(&self) -> MutexGuard { @@ -170,7 +188,8 @@ impl WasiEnv { /// Get a reference to the memory pub fn memory(&self) -> &Memory { - self.memory.get_memory().expect("The expected Memory is not attached to the `WasiEnv`. Did you forgot to call wasi_env.set_memory(...)?") + dbg!("Getting memory", &self.memory); + unsafe { &*self.memory } } pub(crate) fn get_memory_and_wasi_state( diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 3c25dacfef9..866a68dabe8 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -84,7 +84,7 @@ impl<'a> WasiTest<'a> { let imports = self.get_imports(store, &module, env.clone())?; let instance = Instance::new(&module, &imports)?; let memory: &Memory = instance.exports.get("memory")?; - env.set_memory(memory.clone()); + //env.set_memory(memory.clone()); let start = instance.exports.get_function("_start")?; // TODO: handle errors here when the error fix gets shipped From ed1202181e42a7ff7a8158cbc45f637ab1eda231 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 20 Oct 2020 12:21:16 -0700 Subject: [PATCH 02/39] Clean up code a bit --- lib/api/src/externals/function.rs | 20 +++++++++------- lib/api/src/instance.rs | 11 ++++----- lib/api/src/module.rs | 15 +++--------- lib/api/src/native.rs | 4 ++-- lib/api/src/types.rs | 3 ++- lib/engine/src/artifact.rs | 32 +++++++++++-------------- lib/engine/src/resolver.rs | 8 +++++-- lib/vm/src/export.rs | 2 +- lib/vm/src/imports.rs | 12 ++++++++++ lib/vm/src/instance.rs | 40 +++++++++++++++++++++++++++++-- lib/vm/src/vmcontext.rs | 4 ---- lib/vm/src/vmoffsets.rs | 2 +- lib/wasi/src/lib.rs | 1 - 13 files changed, 96 insertions(+), 58 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index ac0b5f26b4b..9a373c6b7e0 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -96,7 +96,7 @@ impl Function { address, kind: VMFunctionKind::Dynamic, vmctx, - function_ptr: 0, + function_ptr: None, signature: ty.clone(), }, } @@ -126,7 +126,7 @@ impl Function { pub fn new_with_env(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self where F: Fn(&mut Env, &[Val]) -> Result, RuntimeError> + 'static, - Env: Sized + 'static, + Env: Sized + crate::WasmerPostInstantiate + 'static, { let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv { env: RefCell::new(env), @@ -140,6 +140,9 @@ impl Function { let vmctx = FunctionExtraData { host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _, }; + // TODO: look into removing transmute by changing API type signatures + let function_ptr = Some(unsafe { std::mem::transmute::(Env::finish) }); + //dbg!(function_ptr); Self { store: store.clone(), @@ -148,8 +151,7 @@ impl Function { address, kind: VMFunctionKind::Dynamic, vmctx, - // TODO: - function_ptr: 0, + function_ptr, signature: ty.clone(), }, } @@ -193,8 +195,9 @@ impl Function { address, vmctx, signature, - // TODO: - function_ptr: 0, + // 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, }, } @@ -241,8 +244,9 @@ impl Function { let vmctx = FunctionExtraData { host_env: Box::into_raw(box_env) as *mut _, }; - let function_ptr = Env::finish as usize; - dbg!(function_ptr); + // TODO: look into removing transmute by changing API type signatures + let function_ptr = Some(unsafe { std::mem::transmute::(Env::finish) }); + //dbg!(function_ptr as usize); let signature = function.ty(); Self { diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index 61f51a43ae1..c9dd1c6216b 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -73,7 +73,7 @@ impl Instance { pub fn new(module: &Module, resolver: &dyn Resolver) -> Result { let store = module.store(); - let (handle, thunks) = module.instantiate(resolver)?; + let handle = module.instantiate(resolver)?; let exports = module .exports() @@ -91,11 +91,10 @@ impl Instance { exports, }; - for (func, env) in thunks.iter() { - dbg!(func, env); - unsafe { - func(*env, (&instance) as *const _ as *const _); - } + unsafe { + instance + .handle + .initialize_host_envs(&instance as *const _ as *const _); } Ok(instance) diff --git a/lib/api/src/module.rs b/lib/api/src/module.rs index 74b361a8d3f..714991cba58 100644 --- a/lib/api/src/module.rs +++ b/lib/api/src/module.rs @@ -261,18 +261,9 @@ impl Module { pub(crate) fn instantiate( &self, resolver: &dyn Resolver, - ) -> Result< - ( - InstanceHandle, - Vec<( - fn(*mut std::ffi::c_void, *const std::ffi::c_void), - *mut std::ffi::c_void, - )>, - ), - InstantiationError, - > { + ) -> Result { unsafe { - let (instance_handle, thunks) = + let instance_handle = self.artifact .instantiate(self.store.tunables(), resolver, Box::new(()))?; @@ -283,7 +274,7 @@ impl Module { // instance tables. self.artifact.finish_instantiation(&instance_handle)?; - Ok((instance_handle, thunks)) + Ok(instance_handle) } } diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index 9957e23bb63..5a02ac8e3e0 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -70,7 +70,7 @@ where vmctx: other.vmctx, signature, // TODO: - function_ptr: 0, + function_ptr: None, kind: other.arg_kind, } } @@ -91,7 +91,7 @@ where vmctx: other.vmctx, signature, // TODO: - function_ptr: 0, + function_ptr: None, kind: other.arg_kind, }, } diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index cea1336d60f..07b0ea1f7ce 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -77,7 +77,8 @@ impl ValFuncRef for Val { address: item.func_ptr, signature, // TODO: - function_ptr: 0, + // 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, diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index 5719fa6d21e..215e8bc265a 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -86,16 +86,7 @@ pub trait Artifact: Send + Sync + Upcastable { tunables: &dyn Tunables, resolver: &dyn Resolver, host_state: Box, - ) -> Result< - ( - InstanceHandle, - Vec<( - fn(*mut std::ffi::c_void, *const std::ffi::c_void), - *mut std::ffi::c_void, - )>, - ), - InstantiationError, - > { + ) -> Result { self.preinstantiate()?; let module = self.module(); @@ -110,13 +101,17 @@ pub trait Artifact: Send + Sync + Upcastable { let mut thunks = vec![]; // ------------ - for func in imports.functions.values() { - unsafe { - let finish: fn(*mut std::ffi::c_void, instance: *const std::ffi::c_void) = - std::mem::transmute(func.function_ptr); - dbg!(func.extra_data.host_env); - thunks.push((finish, func.extra_data.host_env)); - } + for (func_init, func) in imports + .host_function_env_initializers + .values() + .cloned() + .zip(imports.functions.values()) + { + let host_env = unsafe { + //dbg!(func.extra_data.host_env); + func.extra_data.host_env + }; + thunks.push((func_init, host_env)); } // ------------ @@ -144,9 +139,10 @@ pub trait Artifact: Send + Sync + Upcastable { imports, self.signatures().clone(), host_state, + thunks, ) .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))?; - Ok((handle, thunks)) + Ok(handle) } /// Finishes the instantiation of a just created `InstanceHandle`. diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index 0e27426f60c..6ef8650d7a3 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -125,6 +125,9 @@ pub fn resolve_imports( _table_styles: &PrimaryMap, ) -> Result { let mut function_imports = PrimaryMap::with_capacity(module.num_imported_functions); + // TODO: account for imported functions without env / from other Wasm instances + let mut host_function_env_initializers = + PrimaryMap::with_capacity(module.num_imported_functions); let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables); let mut memory_imports = PrimaryMap::with_capacity(module.num_imported_memories); let mut global_imports = PrimaryMap::with_capacity(module.num_imported_globals); @@ -168,9 +171,9 @@ pub fn resolve_imports( function_imports.push(VMFunctionImport { body: address, extra_data: f.vmctx, - // TODO: - function_ptr: f.function_ptr, }); + + host_function_env_initializers.push(f.function_ptr); } Export::Table(ref t) => { table_imports.push(VMTableImport { @@ -224,6 +227,7 @@ pub fn resolve_imports( Ok(Imports::new( function_imports, + host_function_env_initializers, table_imports, memory_imports, global_imports, diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 23672aa8f17..fde459e447c 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -32,7 +32,7 @@ pub struct ExportFunction { /// Pointer to the containing `VMContext`. pub vmctx: crate::vmcontext::FunctionExtraData, /// temp code to set vmctx for host functions - pub function_ptr: usize, + pub function_ptr: Option, /// The function type, used for compatibility checking. pub signature: FunctionType, /// The function kind (it defines how it's the signature that provided `address` have) diff --git a/lib/vm/src/imports.rs b/lib/vm/src/imports.rs index fb5da509907..80c7ce19cf7 100644 --- a/lib/vm/src/imports.rs +++ b/lib/vm/src/imports.rs @@ -11,6 +11,12 @@ pub struct Imports { /// Resolved addresses for imported functions. pub functions: BoxedSlice, + /// Initializers for host function environments. This is split out from `functions` + /// because the generated code never needs to touch this and the extra wasted + /// space may affect Wasm runtime performance due to increased cache pressure. + pub host_function_env_initializers: + BoxedSlice>, + /// Resolved addresses for imported tables. pub tables: BoxedSlice, @@ -25,12 +31,17 @@ impl Imports { /// Construct a new `Imports` instance. pub fn new( function_imports: PrimaryMap, + host_function_env_initializers: PrimaryMap< + FunctionIndex, + Option, + >, table_imports: PrimaryMap, memory_imports: PrimaryMap, global_imports: PrimaryMap, ) -> Self { Self { functions: function_imports.into_boxed_slice(), + host_function_env_initializers: host_function_env_initializers.into_boxed_slice(), tables: table_imports.into_boxed_slice(), memories: memory_imports.into_boxed_slice(), globals: global_imports.into_boxed_slice(), @@ -41,6 +52,7 @@ impl Imports { pub fn none() -> Self { Self { functions: PrimaryMap::new().into_boxed_slice(), + host_function_env_initializers: PrimaryMap::new().into_boxed_slice(), tables: PrimaryMap::new().into_boxed_slice(), memories: PrimaryMap::new().into_boxed_slice(), globals: PrimaryMap::new().into_boxed_slice(), diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 055d57e2cfc..b77a5b6df62 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -100,6 +100,17 @@ pub(crate) struct Instance { /// Handler run when `SIGBUS`, `SIGFPE`, `SIGILL`, or `SIGSEGV` are caught by the instance thread. pub(crate) signal_handler: Cell>>, + /// TODO: document this + /// Functions to initialize the host environments in the imports. + /// Do we want to drain this? There's probably no reason to keep this memory + /// around once we've used it. + /// + /// Be sure to test with serialize/deserialize and imported functions from other Wasm modules. + import_initializers: Vec<( + Option, + *mut std::ffi::c_void, + )>, + /// Additional context used by compiled wasm code. This field is last, and /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). @@ -141,6 +152,14 @@ impl Instance { unsafe { &*self.imported_functions_ptr().add(index) } } + /// TODO: document this + fn imported_function_env_initializer( + &self, + index: FunctionIndex, + ) -> Option { + self.import_initializers[index.as_u32() as usize].0 + } + /// Return a pointer to the `VMFunctionImport`s. fn imported_functions_ptr(&self) -> *mut VMFunctionImport { unsafe { self.vmctx_plus_offset(self.offsets.vmctx_imported_functions_begin()) } @@ -298,11 +317,12 @@ impl Instance { crate::vmcontext::FunctionExtraData { vmctx: self.vmctx_ptr(), }, - 0, + None, ) } else { let import = self.imported_function(*index); - (import.body, import.extra_data, import.function_ptr) + let initializer = self.imported_function_env_initializer(*index); + (import.body, import.extra_data, initializer) }; let signature = self.module.signatures[*sig_index].clone(); ExportFunction { @@ -815,6 +835,10 @@ impl InstanceHandle { imports: Imports, vmshared_signatures: BoxedSlice, host_state: Box, + import_initializers: Vec<( + Option, + *mut std::ffi::c_void, + )>, ) -> Result { // TODO: investigate `vmctx_tables` and `vmctx_memories`: both of these // appear to be dropped in this function which may cause memory problems @@ -859,6 +883,7 @@ impl InstanceHandle { passive_data, host_state, signal_handler: Cell::new(None), + import_initializers, vmctx: VMContext {}, }; let layout = instance.alloc_layout(); @@ -1076,6 +1101,17 @@ impl InstanceHandle { unsafe { &*(self.instance as *const Instance) } } + /// TODO: document this + /// Initializes the host environments. + pub unsafe fn initialize_host_envs(&self, instance_ptr: *const std::ffi::c_void) { + for (func, env) in self.instance().import_initializers.iter() { + if let Some(f) = func { + dbg!(f, env); + f(*env, instance_ptr); + } + } + } + /// Deallocates memory associated with this instance. /// /// # Safety diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index d1de6b3110b..49a75c59869 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -47,10 +47,6 @@ pub struct VMFunctionImport { /// A pointer to the `VMContext` that owns the function or host data. pub extra_data: FunctionExtraData, - - /// temporary hack - /// Only used by host env - pub function_ptr: usize, } #[cfg(test)] diff --git a/lib/vm/src/vmoffsets.rs b/lib/vm/src/vmoffsets.rs index 66406d0035f..b18408165d3 100644 --- a/lib/vm/src/vmoffsets.rs +++ b/lib/vm/src/vmoffsets.rs @@ -109,7 +109,7 @@ impl VMOffsets { /// /// [`VMFunctionImport`]: crate::vmcontext::VMFunctionImport pub fn size_of_vmfunction_import(&self) -> u8 { - 3 * self.pointer_size + 2 * self.pointer_size } } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index d0733055f68..70197795944 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -188,7 +188,6 @@ impl WasiEnv { /// Get a reference to the memory pub fn memory(&self) -> &Memory { - dbg!("Getting memory", &self.memory); unsafe { &*self.memory } } From 103ea035361c64c174e56ee1e77aebf606ce13d4 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 20 Oct 2020 15:40:51 -0700 Subject: [PATCH 03/39] Rename trait, get tests running --- examples/wasi.rs | 3 --- lib/api/src/externals/function.rs | 4 +-- lib/api/src/lib.rs | 2 +- lib/wasi/src/lib.rs | 2 +- tests/compilers/imports.rs | 42 ++++++++++++++++++++++++----- tests/compilers/native_functions.rs | 24 +++++++++++++++++ 6 files changed, 64 insertions(+), 13 deletions(-) diff --git a/examples/wasi.rs b/examples/wasi.rs index c9c779b7450..2a10b815f60 100644 --- a/examples/wasi.rs +++ b/examples/wasi.rs @@ -51,9 +51,6 @@ fn main() -> Result<(), Box> { 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()); - println!("Call WASI `_start` function..."); // And we just call the `_start` function! let start = instance.exports.get_function("_start")?; diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 9a373c6b7e0..4a4081f9b11 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -126,7 +126,7 @@ impl Function { pub fn new_with_env(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self where F: Fn(&mut Env, &[Val]) -> Result, RuntimeError> + 'static, - Env: Sized + crate::WasmerPostInstantiate + 'static, + Env: Sized + crate::WasmerEnv + 'static, { let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv { env: RefCell::new(env), @@ -230,7 +230,7 @@ impl Function { F: HostFunction, Args: WasmTypeList, Rets: WasmTypeList, - Env: Sized + crate::WasmerPostInstantiate + 'static, + Env: Sized + crate::WasmerEnv + 'static, { let function = inner::Function::::new(func); let address = function.address(); diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index ce4d8204a83..122ea2daec1 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -124,7 +124,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); // TODO: rename everything, all names are throw-away names /// Prototype trait for finishing envs. -pub trait WasmerPostInstantiate { +pub trait WasmerEnv { /// The function that Wasmer will call on your type to let it finish /// instantiating. fn finish(&mut self, instance: &Instance); diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 70197795944..b50a4cde56d 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -54,7 +54,7 @@ pub struct WasiEnv { memory: *mut Memory, } -impl wasmer::WasmerPostInstantiate for WasiEnv { +impl wasmer::WasmerEnv for WasiEnv { fn finish(&mut self, instance: &wasmer::Instance) { dbg!("in Wasi::Finish"); let memory = instance.exports.get_memory("memory").unwrap(); diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index b73501f4151..db43d2a9d3a 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -86,7 +86,22 @@ fn dynamic_function_with_env() -> Result<()> { let store = get_store(false); let module = get_module(&store)?; - let env: Arc = Arc::new(AtomicUsize::new(0)); + #[derive(Clone)] + struct Env(Arc); + + impl std::ops::Deref for Env { + type Target = Arc; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl WasmerEnv for Env { + fn finish(&mut self, _instance: &Instance) {} + fn free(&mut self) {} + } + + let env: Env = Env(Arc::new(AtomicUsize::new(0))); Instance::new( &module, &imports! { @@ -203,25 +218,40 @@ fn static_function_with_env() -> Result<()> { let store = get_store(false); let module = get_module(&store)?; - let env: Arc = Arc::new(AtomicUsize::new(0)); + #[derive(Clone)] + struct Env(Arc); + + impl std::ops::Deref for Env { + type Target = Arc; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl WasmerEnv for Env { + fn finish(&mut self, _instance: &Instance) {} + fn free(&mut self) {} + } + + let env: Env = Env(Arc::new(AtomicUsize::new(0))); Instance::new( &module, &imports! { "host" => { - "0" => Function::new_native_with_env(&store, env.clone(), |env: &mut Arc| { + "0" => Function::new_native_with_env(&store, env.clone(), |env: &mut Env| { assert_eq!(env.fetch_add(1, SeqCst), 0); }), - "1" => Function::new_native_with_env(&store, env.clone(), |env: &mut Arc, x: i32| -> i32 { + "1" => Function::new_native_with_env(&store, env.clone(), |env: &mut Env, x: i32| -> i32 { assert_eq!(x, 0); assert_eq!(env.fetch_add(1, SeqCst), 1); 1 }), - "2" => Function::new_native_with_env(&store, env.clone(), |env: &mut Arc, x: i32, y: i64| { + "2" => Function::new_native_with_env(&store, env.clone(), |env: &mut Env, x: i32, y: i64| { assert_eq!(x, 2); assert_eq!(y, 3); assert_eq!(env.fetch_add(1, SeqCst), 2); }), - "3" => Function::new_native_with_env(&store, env.clone(), |env: &mut Arc, a: i32, b: i64, c: i32, d: f32, e: f64| { + "3" => Function::new_native_with_env(&store, env.clone(), |env: &mut Env, a: i32, b: i64, c: i32, d: f32, e: f64| { assert_eq!(a, 100); assert_eq!(b, 200); assert_eq!(c, 300); diff --git a/tests/compilers/native_functions.rs b/tests/compilers/native_functions.rs index 66b3fada8f1..ed2e623a265 100644 --- a/tests/compilers/native_functions.rs +++ b/tests/compilers/native_functions.rs @@ -108,6 +108,18 @@ fn static_host_function_with_env() -> anyhow::Result<()> { #[derive(Clone)] struct Env(Rc>); + impl std::ops::Deref for Env { + type Target = Rc>; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl WasmerEnv for Env { + fn finish(&mut self, _instance: &Instance) {} + fn free(&mut self) {} + } + // Native static host function that returns a tuple. { let env = Env(Rc::new(RefCell::new(100))); @@ -175,6 +187,18 @@ fn dynamic_host_function_with_env() -> anyhow::Result<()> { #[derive(Clone)] struct Env(Rc>); + impl std::ops::Deref for Env { + type Target = Rc>; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl WasmerEnv for Env { + fn finish(&mut self, _instance: &Instance) {} + fn free(&mut self) {} + } + let env = Env(Rc::new(RefCell::new(100))); let f = Function::new_with_env( &store, From b78447f8a4f74079d222b6b1a6eb7abfa977fef2 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 20 Oct 2020 15:49:36 -0700 Subject: [PATCH 04/39] Fix up merge, use new union --- lib/api/src/externals/function.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 683ca81b6f2..c0bff213658 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -385,7 +385,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, } From d64908dc8302636c84af49f41d2fe93cbfa3fe84 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 20 Oct 2020 18:03:22 -0700 Subject: [PATCH 05/39] Fix package tests --- lib/api/src/externals/function.rs | 12 ++++++++++-- lib/api/tests/externals.rs | 9 +++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index c0bff213658..7f367fac355 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -108,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]); @@ -214,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 { diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index 49fdc6f0772..18ea8bf41e6 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -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![])); @@ -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( From 46204d6357d7e8499098a7c0b6f064830e23cbaf Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 21 Oct 2020 11:56:57 -0700 Subject: [PATCH 06/39] Fix up more tests --- lib/api/src/lib.rs | 9 ++ lib/c-api/src/deprecated/import/mod.rs | 5 + lib/c-api/src/deprecated/import/wasi.rs | 7 +- .../src/wasm_c_api/externals/function.rs | 15 ++- lib/c-api/src/wasm_c_api/wasi/mod.rs | 13 ++- lib/c-api/tests/wasm_c_api/test-wasi.c | 1 - lib/cli/src/commands/wasmer_create_exe_main.c | 4 - lib/deprecated/runtime-core/Cargo.lock | 104 +++++++++++------- lib/deprecated/runtime-core/src/module.rs | 8 +- lib/deprecated/runtime-core/src/typed_func.rs | 5 + lib/deprecated/runtime-core/src/vm.rs | 6 + lib/deprecated/runtime/Cargo.lock | 104 +++++++++++------- 12 files changed, 178 insertions(+), 103 deletions(-) diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 122ea2daec1..dfdcd95d9d5 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -132,3 +132,12 @@ pub trait WasmerEnv { /// Frees memory written to `self` so it can be dropped without any memory leaks. fn free(&mut self); } + +impl WasmerEnv for &'static mut T { + fn finish(&mut self, instance: &Instance) { + (*self).finish(instance) + } + fn free(&mut self) { + (*self).free() + } +} diff --git a/lib/c-api/src/deprecated/import/mod.rs b/lib/c-api/src/deprecated/import/mod.rs index 09eb562c075..1c3bf0bf442 100644 --- a/lib/c-api/src/deprecated/import/mod.rs +++ b/lib/c-api/src/deprecated/import/mod.rs @@ -639,6 +639,11 @@ pub(crate) struct LegacyEnv { pub(crate) instance_ptr: Option>, } +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 diff --git a/lib/c-api/src/deprecated/import/wasi.rs b/lib/c-api/src/deprecated/import/wasi.rs index 77196a60e20..aa94f523dab 100644 --- a/lib/c-api/src/deprecated/import/wasi.rs +++ b/lib/c-api/src/deprecated/import/wasi.rs @@ -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)] @@ -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 let import_object_inner: Box = Box::new( wasi::generate_import_object_from_env(store, wasi_env, wasi::WasiVersion::Latest), ); diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs index 6f6319365b3..dac751ddf20 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -92,8 +92,17 @@ pub unsafe extern "C" fn wasm_func_new_with_env( // TODO: handle null pointers? let func_sig = ft.sig(); let num_rets = func_sig.results().len(); + + #[repr(transparent)] + struct WrapperEnv(*mut c_void); + + impl wasmer::WasmerEnv for WrapperEnv { + fn finish(&mut self, _instance: &wasmer::Instance) {} + fn free(&mut self) {} + } + let inner_callback = - move |env: &mut *mut c_void, args: &[Val]| -> Result, RuntimeError> { + move |env: &mut WrapperEnv, args: &[Val]| -> Result, RuntimeError> { let processed_args: wasm_val_vec_t = args .into_iter() .map(TryInto::try_into) @@ -110,7 +119,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( ] .into(); - let _traps = callback(*env, &processed_args, &mut results); + let _traps = callback(env.0, &processed_args, &mut results); // TODO: do something with `traps` let processed_results = results @@ -124,7 +133,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( Ok(processed_results) }; - let function = Function::new_with_env(&store.inner, &func_sig, env, inner_callback); + let function = Function::new_with_env(&store.inner, &func_sig, WrapperEnv(env), inner_callback); Some(Box::new(wasm_func_t { instance: None, diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index 68516c66a12..a5c8beddd8f 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -174,21 +174,28 @@ pub extern "C" fn wasi_env_new(mut config: Box) -> Option>) {} +// Dead code: deprecate or remove #[no_mangle] -pub extern "C" fn wasi_env_set_instance(env: &mut wasi_env_t, instance: &wasm_instance_t) -> bool { +pub extern "C" fn wasi_env_set_instance( + _env: &mut wasi_env_t, + _instance: &wasm_instance_t, +) -> bool { + /* let memory = if let Ok(memory) = instance.inner.exports.get_memory("memory") { memory } else { return false; }; env.inner.set_memory(memory.clone()); + */ true } +// Dead code: deprecate or remove #[no_mangle] -pub extern "C" fn wasi_env_set_memory(env: &mut wasi_env_t, memory: &wasm_memory_t) { - env.inner.set_memory(memory.inner.clone()); +pub extern "C" fn wasi_env_set_memory(_env: &mut wasi_env_t, _memory: &wasm_memory_t) { + //env.inner.set_memory(memory.inner.clone()); } #[no_mangle] diff --git a/lib/c-api/tests/wasm_c_api/test-wasi.c b/lib/c-api/tests/wasm_c_api/test-wasi.c index 1c7c244db91..60f89185c2f 100644 --- a/lib/c-api/tests/wasm_c_api/test-wasi.c +++ b/lib/c-api/tests/wasm_c_api/test-wasi.c @@ -103,7 +103,6 @@ int main(int argc, const char* argv[]) { } fprintf(stderr, "found %zu exports\n", exports.size); - wasi_env_set_instance(wasi_env, instance); wasm_func_t* run_func = wasi_get_start_function(instance); if (run_func == NULL) { printf("> Error accessing export!\n"); diff --git a/lib/cli/src/commands/wasmer_create_exe_main.c b/lib/cli/src/commands/wasmer_create_exe_main.c index 6624c31866c..73300da587a 100644 --- a/lib/cli/src/commands/wasmer_create_exe_main.c +++ b/lib/cli/src/commands/wasmer_create_exe_main.c @@ -159,10 +159,6 @@ int main(int argc, char* argv[]) { print_wasmer_error(); return -1; } - - #ifdef WASI - wasi_env_set_instance(wasi_env, instance); - #endif #ifdef WASI own wasm_func_t* start_function = wasi_get_start_function(instance); diff --git a/lib/deprecated/runtime-core/Cargo.lock b/lib/deprecated/runtime-core/Cargo.lock index 6ab9c79044c..a49b103f64f 100644 --- a/lib/deprecated/runtime-core/Cargo.lock +++ b/lib/deprecated/runtime-core/Cargo.lock @@ -107,9 +107,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cloudabi" -version = "0.0.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" dependencies = [ "bitflags", ] @@ -455,8 +455,9 @@ dependencies = [ [[package]] name = "inkwell" -version = "0.1.0" -source = "git+https://github.com/theDan64/inkwell?rev=fdf895777e937c974204e879cf1102cf7a727c42#fdf895777e937c974204e879cf1102cf7a727c42" +version = "0.1.0-llvm10sample" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079c12273d96e41481454a37ad968e607e1ce51b39b9facd3a802a12df6e9dc" dependencies = [ "either", "inkwell_internals", @@ -470,13 +471,23 @@ dependencies = [ [[package]] name = "inkwell_internals" version = "0.2.0" -source = "git+https://github.com/theDan64/inkwell?rev=fdf895777e937c974204e879cf1102cf7a727c42#fdf895777e937c974204e879cf1102cf7a727c42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22cf4eda09069b48204cce4b7cd9a25311da813780e95a038524f2210fab44e" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "instant" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" +dependencies = [ + "cfg-if", +] + [[package]] name = "itertools" version = "0.9.0" @@ -528,9 +539,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" dependencies = [ "scopeguard", ] @@ -642,22 +653,24 @@ checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" [[package]] name = "parking_lot" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" dependencies = [ + "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" dependencies = [ "cfg-if", "cloudabi", + "instant", "libc", "redox_syscall", "smallvec", @@ -1094,24 +1107,15 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasmer-types" -version = "1.0.0-alpha.1" -dependencies = [ - "cranelift-entity", - "serde", -] - [[package]] name = "wasmer" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "cfg-if", "indexmap", "more-asserts", "target-lexicon", "thiserror", - "wasmer-types", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-compiler-llvm", @@ -1119,6 +1123,7 @@ dependencies = [ "wasmer-engine", "wasmer-engine-jit", "wasmer-engine-native", + "wasmer-types", "wasmer-vm", "wat", "winapi", @@ -1126,7 +1131,7 @@ dependencies = [ [[package]] name = "wasmer-cache" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "blake3", "hex", @@ -1137,7 +1142,7 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "enumset", "raw-cpuid", @@ -1153,7 +1158,7 @@ dependencies = [ [[package]] name = "wasmer-compiler-cranelift" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "cranelift-codegen", "cranelift-frontend", @@ -1162,14 +1167,14 @@ dependencies = [ "rayon", "serde", "tracing", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", ] [[package]] name = "wasmer-compiler-llvm" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "byteorder", "cc", @@ -1184,14 +1189,14 @@ dependencies = [ "semver", "smallvec", "target-lexicon", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", ] [[package]] name = "wasmer-compiler-singlepass" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "byteorder", "dynasm", @@ -1201,14 +1206,14 @@ dependencies = [ "rayon", "serde", "smallvec", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", ] [[package]] name = "wasmer-engine" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "backtrace", "bincode", @@ -1219,55 +1224,54 @@ dependencies = [ "serde_bytes", "target-lexicon", "thiserror", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", - "winapi", ] [[package]] name = "wasmer-engine-jit" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "bincode", "cfg-if", "region", "serde", "serde_bytes", - "wasmer-types", "wasmer-compiler", "wasmer-engine", + "wasmer-types", "wasmer-vm", "winapi", ] [[package]] name = "wasmer-engine-native" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "bincode", "cfg-if", "leb128", "libloading", "serde", - "serde_bytes", "tempfile", "tracing", - "wasmer-types", "wasmer-compiler", "wasmer-engine", "wasmer-object", + "wasmer-types", "wasmer-vm", + "which", ] [[package]] name = "wasmer-object" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "object 0.19.0", "thiserror", - "wasmer-types", "wasmer-compiler", + "wasmer-types", ] [[package]] @@ -1276,7 +1280,6 @@ version = "0.18.0" dependencies = [ "blake3", "lazy_static", - "wasmer-types", "wasmer", "wasmer-cache", "wasmer-compiler", @@ -1285,12 +1288,21 @@ dependencies = [ "wasmer-compiler-singlepass", "wasmer-engine", "wasmer-engine-jit", + "wasmer-types", "wasmer-vm", ] +[[package]] +name = "wasmer-types" +version = "1.0.0-alpha4" +dependencies = [ + "cranelift-entity", + "serde", +] + [[package]] name = "wasmer-vm" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "backtrace", "cc", @@ -1330,6 +1342,16 @@ dependencies = [ "wast", ] +[[package]] +name = "which" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" +dependencies = [ + "libc", + "thiserror", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/lib/deprecated/runtime-core/src/module.rs b/lib/deprecated/runtime-core/src/module.rs index ac9b606d12d..7ef483dcb85 100644 --- a/lib/deprecated/runtime-core/src/module.rs +++ b/lib/deprecated/runtime-core/src/module.rs @@ -102,14 +102,14 @@ impl Module { // Properly drop the empty `vm::Ctx` // created by the host function. unsafe { - ptr::drop_in_place::(function.vmctx as _); + ptr::drop_in_place::(function.vmctx.host_env as _); } // Update the pointer to `VMContext`, // which is actually a `vm::Ctx` // pointer, to fallback on the // environment hack. - function.vmctx = pre_instance.vmctx_ptr() as _; + function.vmctx.host_env = pre_instance.vmctx_ptr() as _; } // `function` is a dynamic host function // constructed with @@ -147,13 +147,13 @@ impl Module { new::wasmer_vm::VMDynamicFunctionContext< VMDynamicFunctionWithEnv, >, - > = unsafe { Box::from_raw(function.vmctx as *mut _) }; + > = unsafe { Box::from_raw(function.vmctx.host_env as *mut _) }; // Replace the environment by ours. vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx(); // … without anyone noticing… - function.vmctx = Box::into_raw(vmctx) as _; + function.vmctx.host_env = Box::into_raw(vmctx) as _; } } diff --git a/lib/deprecated/runtime-core/src/typed_func.rs b/lib/deprecated/runtime-core/src/typed_func.rs index a1b8d74685e..c9b549f1093 100644 --- a/lib/deprecated/runtime-core/src/typed_func.rs +++ b/lib/deprecated/runtime-core/src/typed_func.rs @@ -236,6 +236,11 @@ pub(crate) struct DynamicCtx { pub(crate) vmctx: Rc>, } +impl new::wasmer::WasmerEnv for DynamicCtx { + fn finish(&mut self, _instance: &new::wasmer::Instance) {} + fn free(&mut self) {} +} + impl DynamicFunc { /// Create a new `DynamicFunc`. pub fn new(signature: &FuncSig, func: F) -> Self diff --git a/lib/deprecated/runtime-core/src/vm.rs b/lib/deprecated/runtime-core/src/vm.rs index 8b129e3c647..a07aecf6ea8 100644 --- a/lib/deprecated/runtime-core/src/vm.rs +++ b/lib/deprecated/runtime-core/src/vm.rs @@ -1,4 +1,5 @@ use crate::module::ModuleInfo; +use crate::new; use std::{ffi::c_void, ptr}; /// The context of the currently running WebAssembly instance. @@ -38,6 +39,11 @@ pub struct Ctx { pub data_finalizer: Option, } +impl new::wasmer::WasmerEnv for Ctx { + fn finish(&mut self, _instance: &new::wasmer::Instance) {} + fn free(&mut self) {} +} + impl Ctx { pub(crate) unsafe fn new_uninit() -> Self { Self { diff --git a/lib/deprecated/runtime/Cargo.lock b/lib/deprecated/runtime/Cargo.lock index 161e55b4649..3cb70a56205 100644 --- a/lib/deprecated/runtime/Cargo.lock +++ b/lib/deprecated/runtime/Cargo.lock @@ -107,9 +107,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cloudabi" -version = "0.0.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467" dependencies = [ "bitflags", ] @@ -455,8 +455,9 @@ dependencies = [ [[package]] name = "inkwell" -version = "0.1.0" -source = "git+https://github.com/theDan64/inkwell?rev=fdf895777e937c974204e879cf1102cf7a727c42#fdf895777e937c974204e879cf1102cf7a727c42" +version = "0.1.0-llvm10sample" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e079c12273d96e41481454a37ad968e607e1ce51b39b9facd3a802a12df6e9dc" dependencies = [ "either", "inkwell_internals", @@ -470,13 +471,23 @@ dependencies = [ [[package]] name = "inkwell_internals" version = "0.2.0" -source = "git+https://github.com/theDan64/inkwell?rev=fdf895777e937c974204e879cf1102cf7a727c42#fdf895777e937c974204e879cf1102cf7a727c42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22cf4eda09069b48204cce4b7cd9a25311da813780e95a038524f2210fab44e" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "instant" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63312a18f7ea8760cdd0a7c5aac1a619752a246b833545e3e36d1f81f7cd9e66" +dependencies = [ + "cfg-if", +] + [[package]] name = "itertools" version = "0.9.0" @@ -528,9 +539,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c" dependencies = [ "scopeguard", ] @@ -642,22 +653,24 @@ checksum = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" [[package]] name = "parking_lot" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733" dependencies = [ + "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" dependencies = [ "cfg-if", "cloudabi", + "instant", "libc", "redox_syscall", "smallvec", @@ -1094,24 +1107,15 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -[[package]] -name = "wasmer-types" -version = "1.0.0-alpha.1" -dependencies = [ - "cranelift-entity", - "serde", -] - [[package]] name = "wasmer" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "cfg-if", "indexmap", "more-asserts", "target-lexicon", "thiserror", - "wasmer-types", "wasmer-compiler", "wasmer-compiler-cranelift", "wasmer-compiler-llvm", @@ -1119,6 +1123,7 @@ dependencies = [ "wasmer-engine", "wasmer-engine-jit", "wasmer-engine-native", + "wasmer-types", "wasmer-vm", "wat", "winapi", @@ -1126,7 +1131,7 @@ dependencies = [ [[package]] name = "wasmer-cache" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "blake3", "hex", @@ -1137,7 +1142,7 @@ dependencies = [ [[package]] name = "wasmer-compiler" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "enumset", "raw-cpuid", @@ -1153,7 +1158,7 @@ dependencies = [ [[package]] name = "wasmer-compiler-cranelift" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "cranelift-codegen", "cranelift-frontend", @@ -1162,14 +1167,14 @@ dependencies = [ "rayon", "serde", "tracing", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", ] [[package]] name = "wasmer-compiler-llvm" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "byteorder", "cc", @@ -1184,14 +1189,14 @@ dependencies = [ "semver", "smallvec", "target-lexicon", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", ] [[package]] name = "wasmer-compiler-singlepass" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "byteorder", "dynasm", @@ -1201,14 +1206,14 @@ dependencies = [ "rayon", "serde", "smallvec", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", ] [[package]] name = "wasmer-engine" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "backtrace", "bincode", @@ -1219,55 +1224,54 @@ dependencies = [ "serde_bytes", "target-lexicon", "thiserror", - "wasmer-types", "wasmer-compiler", + "wasmer-types", "wasmer-vm", - "winapi", ] [[package]] name = "wasmer-engine-jit" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "bincode", "cfg-if", "region", "serde", "serde_bytes", - "wasmer-types", "wasmer-compiler", "wasmer-engine", + "wasmer-types", "wasmer-vm", "winapi", ] [[package]] name = "wasmer-engine-native" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "bincode", "cfg-if", "leb128", "libloading", "serde", - "serde_bytes", "tempfile", "tracing", - "wasmer-types", "wasmer-compiler", "wasmer-engine", "wasmer-object", + "wasmer-types", "wasmer-vm", + "which", ] [[package]] name = "wasmer-object" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "object 0.19.0", "thiserror", - "wasmer-types", "wasmer-compiler", + "wasmer-types", ] [[package]] @@ -1283,7 +1287,6 @@ version = "0.18.0" dependencies = [ "blake3", "lazy_static", - "wasmer-types", "wasmer", "wasmer-cache", "wasmer-compiler", @@ -1292,12 +1295,21 @@ dependencies = [ "wasmer-compiler-singlepass", "wasmer-engine", "wasmer-engine-jit", + "wasmer-types", "wasmer-vm", ] +[[package]] +name = "wasmer-types" +version = "1.0.0-alpha4" +dependencies = [ + "cranelift-entity", + "serde", +] + [[package]] name = "wasmer-vm" -version = "1.0.0-alpha.1" +version = "1.0.0-alpha4" dependencies = [ "backtrace", "cc", @@ -1337,6 +1349,16 @@ dependencies = [ "wast", ] +[[package]] +name = "which" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87c14ef7e1b8b8ecfc75d5eca37949410046e66f15d185c01d70824f1f8111ef" +dependencies = [ + "libc", + "thiserror", +] + [[package]] name = "winapi" version = "0.3.9" From 1b7188769cb9da333a05334d09c37bc0a823a89d Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 22 Oct 2020 12:00:44 -0700 Subject: [PATCH 07/39] Remove VMContext port to union, split into #1753 --- lib/api/src/externals/function.rs | 22 +++++++-------------- lib/api/src/native.rs | 21 ++++++++------------ lib/api/src/types.rs | 4 +--- lib/engine/src/artifact.rs | 5 +---- lib/engine/src/resolver.rs | 2 +- lib/vm/src/export.rs | 2 +- lib/vm/src/instance.rs | 31 +++++++++-------------------- lib/vm/src/lib.rs | 8 ++++---- lib/vm/src/trap/traphandlers.rs | 14 ++++++------- lib/vm/src/vmcontext.rs | 33 ++++--------------------------- 10 files changed, 43 insertions(+), 99 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 7f367fac355..91fb329f611 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -11,8 +11,8 @@ use std::cmp::max; use std::fmt; use wasmer_vm::{ raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction, - FunctionExtraData, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, - VMFunctionKind, VMTrampoline, + VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, + VMTrampoline, }; /// A function defined in the Wasm module @@ -85,9 +85,7 @@ 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 = FunctionExtraData { - host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _, - }; + let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext; Self { store: store.clone(), @@ -142,9 +140,7 @@ 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 = FunctionExtraData { - host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _, - }; + let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext; // TODO: look into removing transmute by changing API type signatures let function_ptr = Some(unsafe { std::mem::transmute::(Env::finish) }); //dbg!(function_ptr); @@ -189,9 +185,7 @@ impl Function { { let function = inner::Function::::new(func); let address = function.address() as *const VMFunctionBody; - let vmctx = FunctionExtraData { - host_env: std::ptr::null_mut() as *mut _, - }; + let vmctx = std::ptr::null_mut() as *mut VMContext; let signature = function.ty(); Self { @@ -252,9 +246,7 @@ 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 = FunctionExtraData { - host_env: Box::into_raw(box_env) as *mut _, - }; + let vmctx = Box::into_raw(box_env) as *mut VMContext; // TODO: look into removing transmute by changing API type signatures let function_ptr = Some(unsafe { std::mem::transmute::(Env::finish) }); //dbg!(function_ptr as usize); @@ -393,7 +385,7 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { - has_env: !unsafe { wasmer_export.vmctx.host_env.is_null() }, + has_env: !wasmer_export.vmctx.is_null(), }), exported: wasmer_export, } diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index f1ccd044e65..2a68c3abbbb 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -17,8 +17,7 @@ use crate::{FromToNativeWasmType, Function, FunctionType, RuntimeError, Store, W use std::panic::{catch_unwind, AssertUnwindSafe}; use wasmer_types::NativeWasmType; use wasmer_vm::{ - ExportFunction, FunctionExtraData, VMContext, VMDynamicFunctionContext, VMFunctionBody, - VMFunctionKind, + ExportFunction, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, }; /// A WebAssembly function that can be called natively @@ -27,7 +26,7 @@ pub struct NativeFunc<'a, Args = (), Rets = ()> { definition: FunctionDefinition, store: Store, address: *const VMFunctionBody, - vmctx: FunctionExtraData, + vmctx: *mut VMContext, arg_kind: VMFunctionKind, // exported: ExportFunction, _phantom: PhantomData<(&'a (), Args, Rets)>, @@ -43,7 +42,7 @@ where pub(crate) fn new( store: Store, address: *const VMFunctionBody, - vmctx: FunctionExtraData, + vmctx: *mut VMContext, arg_kind: VMFunctionKind, definition: FunctionDefinition, ) -> Self { @@ -170,7 +169,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( FunctionExtraData, $( $x, )*) -> Rets::CStruct>(self.address); + let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address); // We always pass the vmctx f( self.vmctx, $( $x, )* ) })).map_err(|e| RuntimeError::new(format!("{:?}", e)))?; @@ -180,16 +179,12 @@ macro_rules! impl_native_traits { let params_list = [ $( $x.to_native().to_value() ),* ]; let results = if !has_env { type VMContextWithoutEnv = VMDynamicFunctionContext; - unsafe { - let ctx = self.vmctx.host_env as *mut VMContextWithoutEnv; - (*ctx).ctx.call(¶ms_list)? - } + let ctx = self.vmctx as *mut VMContextWithoutEnv; + unsafe { (*ctx).ctx.call(¶ms_list)? } } else { type VMContextWithEnv = VMDynamicFunctionContext>; - unsafe { - let ctx = self.vmctx.host_env as *mut VMContextWithEnv; - (*ctx).ctx.call(¶ms_list)? - } + let ctx = self.vmctx as *mut VMContextWithEnv; + unsafe { (*ctx).ctx.call(¶ms_list)? } }; let mut rets_list_array = Rets::empty_array(); let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128; diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index 479175786e7..f55bfc42a81 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -56,9 +56,7 @@ impl ValFuncRef for Val { Self::ExternRef(ExternRef::Null) => wasmer_vm::VMCallerCheckedAnyfunc { func_ptr: ptr::null(), type_index: wasmer_vm::VMSharedSignatureIndex::default(), - vmctx: wasmer_vm::FunctionExtraData { - host_env: ptr::null_mut(), - }, + vmctx: ptr::null_mut(), }, Self::FuncRef(f) => f.checked_anyfunc(), _ => return Err(RuntimeError::new("val is not funcref")), diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index 076dd5b27ca..e9e764ca4ab 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -112,10 +112,7 @@ pub trait Artifact: Send + Sync + Upcastable { .cloned() .zip(imports.functions.values()) { - let host_env = unsafe { - //dbg!(func.extra_data.host_env); - func.extra_data.host_env - }; + let host_env = func.vmctx as _; thunks.push((func_init, host_env)); } // ------------ diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index 6ef8650d7a3..a73a906eebd 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -170,7 +170,7 @@ pub fn resolve_imports( }; function_imports.push(VMFunctionImport { body: address, - extra_data: f.vmctx, + vmctx: f.vmctx, }); host_function_env_initializers.push(f.function_ptr); diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 00c7340c3a1..3935f360d4d 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -30,7 +30,7 @@ pub struct ExportFunction { /// The address of the native-code function. pub address: *const VMFunctionBody, /// Pointer to the containing `VMContext`. - pub vmctx: crate::vmcontext::FunctionExtraData, + pub vmctx: *mut VMContext, /// temp code to set vmctx for host functions pub function_ptr: Option, /// The function type, used for compatibility checking. diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 8e5fb8e584f..737b7c72f45 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -317,15 +317,13 @@ impl Instance { if let Some(def_index) = self.module.local_func_index(*index) { ( self.functions[def_index].0 as *const _, - crate::vmcontext::FunctionExtraData { - vmctx: self.vmctx_ptr(), - }, + self.vmctx_ptr(), None, ) } else { let import = self.imported_function(*index); let initializer = self.imported_function_env_initializer(*index); - (import.body, import.extra_data, initializer) + (import.body, import.vmctx, initializer) }; let call_trampoline = Some(self.function_call_trampolines[*sig_index]); let signature = self.module.signatures[*sig_index].clone(); @@ -404,27 +402,21 @@ impl Instance { .get(local_index) .expect("function index is out of bounds") .0; - ( - body as *const _, - crate::FunctionExtraData { - vmctx: self.vmctx_ptr(), - }, - ) + (body as *const _, self.vmctx_ptr()) } None => { assert_lt!(start_index.index(), self.module.num_imported_functions); let import = self.imported_function(start_index); - (import.body, import.extra_data) + (import.body, import.vmctx) } }; // Make the call. unsafe { catch_traps(callee_extra_data, || { - mem::transmute::< - *const VMFunctionBody, - unsafe extern "C" fn(crate::FunctionExtraData), - >(callee_address)(callee_extra_data) + mem::transmute::<*const VMFunctionBody, unsafe extern "C" fn(*mut VMContext)>( + callee_address, + )(callee_extra_data) }) } } @@ -594,15 +586,10 @@ impl Instance { let type_index = self.signature_id(sig); let (func_ptr, vmctx) = if let Some(def_index) = self.module.local_func_index(index) { - ( - self.functions[def_index].0 as *const _, - crate::FunctionExtraData { - vmctx: self.vmctx_ptr(), - }, - ) + (self.functions[def_index].0 as *const _, self.vmctx_ptr()) } else { let import = self.imported_function(index); - (import.body, import.extra_data) + (import.body, import.vmctx) }; VMCallerCheckedAnyfunc { func_ptr, diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index b9e9e39e153..f8e649f591f 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -48,10 +48,10 @@ pub use crate::sig_registry::SignatureRegistry; pub use crate::table::{LinearTable, Table, TableStyle}; pub use crate::trap::*; pub use crate::vmcontext::{ - FunctionExtraData, VMBuiltinFunctionIndex, VMCallerCheckedAnyfunc, VMContext, - VMDynamicFunctionContext, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, - VMGlobalImport, VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, - VMTableImport, VMTrampoline, + VMBuiltinFunctionIndex, VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, + VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalDefinition, VMGlobalImport, + VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, + VMTrampoline, }; pub use crate::vmoffsets::{TargetSharedSignatureIndex, VMOffsets}; diff --git a/lib/vm/src/trap/traphandlers.rs b/lib/vm/src/trap/traphandlers.rs index a09b13bf537..613e8ec1035 100644 --- a/lib/vm/src/trap/traphandlers.rs +++ b/lib/vm/src/trap/traphandlers.rs @@ -429,13 +429,13 @@ impl Trap { /// Wildly unsafe because it calls raw function pointers and reads/writes raw /// function pointers. pub unsafe fn wasmer_call_trampoline( - vmctx: crate::FunctionExtraData, + vmctx: *mut VMContext, trampoline: VMTrampoline, callee: *const VMFunctionBody, values_vec: *mut u8, ) -> Result<(), Trap> { catch_traps(vmctx, || { - mem::transmute::<_, extern "C" fn(crate::FunctionExtraData, *const VMFunctionBody, *mut u8)>( + mem::transmute::<_, extern "C" fn(*mut VMContext, *const VMFunctionBody, *mut u8)>( trampoline, )(vmctx, callee, values_vec) }) @@ -447,7 +447,7 @@ pub unsafe fn wasmer_call_trampoline( /// # Safety /// /// Highly unsafe since `closure` won't have any destructors run. -pub unsafe fn catch_traps(vmctx: crate::FunctionExtraData, mut closure: F) -> Result<(), Trap> +pub unsafe fn catch_traps(vmctx: *mut VMContext, mut closure: F) -> Result<(), Trap> where F: FnMut(), { @@ -481,7 +481,7 @@ where /// /// Check [`catch_traps`]. pub unsafe fn catch_traps_with_result( - vmctx: crate::FunctionExtraData, + vmctx: *mut VMContext, mut closure: F, ) -> Result where @@ -501,7 +501,7 @@ pub struct CallThreadState { jmp_buf: Cell<*const u8>, reset_guard_page: Cell, prev: Option<*const CallThreadState>, - vmctx: crate::FunctionExtraData, + vmctx: *mut VMContext, handling_trap: Cell, } @@ -518,7 +518,7 @@ enum UnwindReason { } impl CallThreadState { - fn new(vmctx: crate::FunctionExtraData) -> Self { + fn new(vmctx: *mut VMContext) -> Self { Self { unwind: Cell::new(UnwindReason::None), vmctx, @@ -561,7 +561,7 @@ impl CallThreadState { fn any_instance(&self, func: impl Fn(&InstanceHandle) -> bool) -> bool { unsafe { - if func(&InstanceHandle::from_vmctx(self.vmctx.vmctx)) { + if func(&InstanceHandle::from_vmctx(self.vmctx)) { return true; } match self.prev { diff --git a/lib/vm/src/vmcontext.rs b/lib/vm/src/vmcontext.rs index 49a75c59869..9ca9051dd55 100644 --- a/lib/vm/src/vmcontext.rs +++ b/lib/vm/src/vmcontext.rs @@ -15,29 +15,6 @@ use std::ptr::{self, NonNull}; use std::sync::Arc; use std::u32; -/// We stop lying about what this daat is -/// TODO: -#[derive(Copy, Clone)] -pub union FunctionExtraData { - /// Wasm function, it has a real VMContext: - pub vmctx: *mut VMContext, - /// Host functions can have custom environments - pub host_env: *mut std::ffi::c_void, -} - -impl std::fmt::Debug for FunctionExtraData { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "FunctionExtarData union") - } -} - -impl std::cmp::PartialEq for FunctionExtraData { - fn eq(&self, rhs: &Self) -> bool { - // TODO - false - } -} - /// An imported function. #[derive(Debug, Copy, Clone)] #[repr(C)] @@ -46,7 +23,7 @@ pub struct VMFunctionImport { pub body: *const VMFunctionBody, /// A pointer to the `VMContext` that owns the function or host data. - pub extra_data: FunctionExtraData, + pub vmctx: *mut VMContext, } #[cfg(test)] @@ -69,7 +46,7 @@ mod test_vmfunction_import { usize::from(offsets.vmfunction_import_body()) ); assert_eq!( - offset_of!(VMFunctionImport, extra_data), + offset_of!(VMFunctionImport, vmctx), usize::from(offsets.vmfunction_import_vmctx()) ); } @@ -752,7 +729,7 @@ pub struct VMCallerCheckedAnyfunc { /// Function signature id. pub type_index: VMSharedSignatureIndex, /// Function `VMContext`. - pub vmctx: FunctionExtraData, + pub vmctx: *mut VMContext, // If more elements are added here, remember to add offset_of tests below! } @@ -791,9 +768,7 @@ impl Default for VMCallerCheckedAnyfunc { Self { func_ptr: ptr::null_mut(), type_index: Default::default(), - vmctx: FunctionExtraData { - vmctx: ptr::null_mut(), - }, + vmctx: ptr::null_mut(), } } } From f3b7f42da2662131ccf49ba40f360477d362ca4b Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 22 Oct 2020 13:37:22 -0700 Subject: [PATCH 08/39] Remove union logic from deprecated crate too --- lib/deprecated/runtime-core/src/module.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/deprecated/runtime-core/src/module.rs b/lib/deprecated/runtime-core/src/module.rs index 7ef483dcb85..ac9b606d12d 100644 --- a/lib/deprecated/runtime-core/src/module.rs +++ b/lib/deprecated/runtime-core/src/module.rs @@ -102,14 +102,14 @@ impl Module { // Properly drop the empty `vm::Ctx` // created by the host function. unsafe { - ptr::drop_in_place::(function.vmctx.host_env as _); + ptr::drop_in_place::(function.vmctx as _); } // Update the pointer to `VMContext`, // which is actually a `vm::Ctx` // pointer, to fallback on the // environment hack. - function.vmctx.host_env = pre_instance.vmctx_ptr() as _; + function.vmctx = pre_instance.vmctx_ptr() as _; } // `function` is a dynamic host function // constructed with @@ -147,13 +147,13 @@ impl Module { new::wasmer_vm::VMDynamicFunctionContext< VMDynamicFunctionWithEnv, >, - > = unsafe { Box::from_raw(function.vmctx.host_env as *mut _) }; + > = unsafe { Box::from_raw(function.vmctx as *mut _) }; // Replace the environment by ours. vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx(); // … without anyone noticing… - function.vmctx.host_env = Box::into_raw(vmctx) as _; + function.vmctx = Box::into_raw(vmctx) as _; } } From c5b94c50504acc9ec50b968828f89d63c957b016 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 22 Oct 2020 16:14:26 -0700 Subject: [PATCH 09/39] Add first draft of `WasmerEnv` derive macro --- Cargo.lock | 11 ++++ Cargo.toml | 1 + lib/derive/Cargo.toml | 18 +++++++ lib/derive/src/lib.rs | 117 ++++++++++++++++++++++++++++++++++++++++ lib/derive/src/parse.rs | 60 +++++++++++++++++++++ 5 files changed, 207 insertions(+) create mode 100644 lib/derive/Cargo.toml create mode 100644 lib/derive/src/lib.rs create mode 100644 lib/derive/src/parse.rs diff --git a/Cargo.lock b/Cargo.lock index 76e9d096e8b..0474826de46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2310,6 +2310,17 @@ dependencies = [ "wasmer-vm", ] +[[package]] +name = "wasmer-derive" +version = "1.0.0-alpha4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", + "wasmer", +] + [[package]] name = "wasmer-emscripten" version = "1.0.0-alpha4" diff --git a/Cargo.toml b/Cargo.toml index d57dc5679b5..45e83b0c3a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ members = [ "lib/compiler-cranelift", "lib/compiler-singlepass", "lib/compiler-llvm", + "lib/derive", "lib/emscripten", "lib/engine", "lib/engine-jit", diff --git a/lib/derive/Cargo.toml b/lib/derive/Cargo.toml new file mode 100644 index 00000000000..f35a49cd9d4 --- /dev/null +++ b/lib/derive/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "wasmer-derive" +version = "1.0.0-alpha4" +description = "Wasmer derive macros" +authors = ["Wasmer Engineering Team "] +repository = "https://github.com/wasmerio/wasmer" +license = "MIT" +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1", features = ["full"] } +quote = "1" +proc-macro2 = "1" +proc-macro-error = "1.0.0" +wasmer = { path = "../api", version = "1.0.0-alpha4" } diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs new file mode 100644 index 00000000000..75709d4d652 --- /dev/null +++ b/lib/derive/src/lib.rs @@ -0,0 +1,117 @@ +extern crate proc_macro; + +use proc_macro2::{Span, TokenStream}; +use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy}; +use quote::{format_ident, quote, quote_spanned}; +use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *}; + +mod parse; + +use crate::parse::{ExportAttr, WasmerAttr}; + +#[proc_macro_derive(WasmerEnv, attributes(wasmer))] +#[proc_macro_error] +pub fn derive_wasmer_env(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let input: DeriveInput = syn::parse(input).unwrap(); + let gen = impl_wasmer_env(&input); + gen.into() +} + +fn impl_wasmer_env_for_struct( + name: &Ident, + data: &DataStruct, + _attrs: &[Attribute], +) -> TokenStream { + let impl_inner = derive_struct_fields(data); + quote! { + impl ::wasmer::WasmerEnv for #name { + #impl_inner + } + } +} + +fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { + use syn::Data::*; + let struct_name = &input.ident; + + set_dummy(quote! { + impl ::wasmer::WasmerEnv for #struct_name { + fn finish(&mut self, instance: &::wasmer::Instance) { + } + fn free(&mut self) { + } + } + }); + + match &input.data { + Data::Struct(ds) => impl_wasmer_env_for_struct(struct_name, ds, &input.attrs), + _ => todo!(), + } + /*match input.data { + Struct(ds /*DataStruct { + fields: syn::Fields::Named(ref fields), + .. + }*/) => , + Enum(ref e) => impl_wasmer_env_for_enum(struct_name, &e.variants, &input.attrs), + _ => abort_call_site!("structopt only supports non-tuple structs and enums"), + }*/ +} + +fn derive_struct_fields(data: &DataStruct) -> TokenStream { + let mut finish = vec![]; + let mut free = vec![]; + let mut assign_tokens = vec![]; + let mut touched_fields = vec![]; + match data.fields { + Fields::Named(ref fields) => { + for f in fields.named.iter() { + let name = f.ident.as_ref().unwrap(); + touched_fields.push(name.clone()); + let mut wasmer_attr = None; + for attr in &f.attrs { + // if / filter + let tokens = attr.tokens.clone(); + wasmer_attr = Some(syn::parse2(tokens).unwrap()); + break; + } + + if let Some(wasmer_attr) = wasmer_attr { + match wasmer_attr { + WasmerAttr::Export { identifier, ty } => match ty { + ExportAttr::Function {} => todo!(), + ExportAttr::Memory {} => { + let finish_tokens = quote_spanned! {f.span()=> + let #name = instance.exports.get_memory(#identifier).unwrap(); + let #name = Box::into_raw(Box::new(#name.clone())); + }; + finish.push(finish_tokens); + let free_tokens = quote_spanned! {f.span()=> + let _ = Box::from_raw(self.#name); + self.#name = ::std::ptr::null_mut(); + }; + free.push(free_tokens); + } + }, + } + assign_tokens.push(quote! { + self.#name = #name; + }); + } + } + } + _ => todo!(), + } + + quote! { + fn finish(&mut self, instance: &::wasmer::Instance) { + #(#finish)* + #(#assign_tokens)* + } + + fn free(&mut self) { + unsafe { + #(#free)* + } + } + } +} diff --git a/lib/derive/src/parse.rs b/lib/derive/src/parse.rs new file mode 100644 index 00000000000..e92d94f09e6 --- /dev/null +++ b/lib/derive/src/parse.rs @@ -0,0 +1,60 @@ +use proc_macro2::Span; +use proc_macro_error::{abort, ResultExt}; +use syn::{ + parenthesized, + parse::{Parse, ParseStream}, + token, Expr, Ident, LitStr, Token, +}; + +pub enum WasmerAttr { + Export { identifier: LitStr, ty: ExportAttr }, +} + +pub enum ExportAttr { + // TODO: + Function {}, + Memory {}, +} + +struct ExportExpr { + name: LitStr, +} + +impl Parse for ExportExpr { + fn parse(input: ParseStream<'_>) -> syn::Result { + Ok(Self { + name: input.parse::()?, + }) + } +} + +// allows us to handle parens more cleanly +struct WasmerAttrInner(WasmerAttr); + +impl Parse for WasmerAttrInner { + fn parse(input: ParseStream<'_>) -> syn::Result { + let ident: Ident = input.parse()?; + let ident_str = ident.to_string(); + let out = match ident_str.as_str() { + "export" => { + let export_expr; + let _: token::Paren = parenthesized!(export_expr in input); + + WasmerAttr::Export { + identifier: export_expr.parse::()?.name, + ty: ExportAttr::Memory {}, + } + } + _ => return Err(input.error(format!("Unexpected identifier {}", ident_str))), + }; + Ok(WasmerAttrInner(out)) + } +} + +impl Parse for WasmerAttr { + fn parse(input: ParseStream<'_>) -> syn::Result { + let attr_inner; + parenthesized!(attr_inner in input); + Ok(attr_inner.parse::()?.0) + } +} From a7abee6fb75a129ec6ff0e55eee6c314b8a3bfa8 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Fri, 23 Oct 2020 12:50:36 -0700 Subject: [PATCH 10/39] Add lazy abstraction, improve macro, use macro internally --- Cargo.lock | 1 + lib/api/Cargo.toml | 1 + lib/api/src/lib.rs | 94 ++++++++++++++++++++++++++++++++++++++ lib/api/tests/externals.rs | 12 +---- lib/derive/Cargo.toml | 2 + lib/derive/src/lib.rs | 84 ++++++++++++++++++++++++++++------ lib/wasi/src/lib.rs | 92 +++++-------------------------------- 7 files changed, 183 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0474826de46..7ea7499a025 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2155,6 +2155,7 @@ dependencies = [ "wasmer-compiler-cranelift", "wasmer-compiler-llvm", "wasmer-compiler-singlepass", + "wasmer-derive", "wasmer-engine", "wasmer-engine-jit", "wasmer-engine-native", diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index a66269bee53..d2e05994790 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -16,6 +16,7 @@ wasmer-compiler-singlepass = { path = "../compiler-singlepass", version = "1.0.0 wasmer-compiler-cranelift = { path = "../compiler-cranelift", version = "1.0.0-alpha4", optional = true } wasmer-compiler-llvm = { path = "../compiler-llvm", version = "1.0.0-alpha4", optional = true } wasmer-compiler = { path = "../compiler", version = "1.0.0-alpha4" } +wasmer-derive = { path = "../derive", version = "1.0.0-alpha4" } wasmer-engine = { path = "../engine", version = "1.0.0-alpha4" } wasmer-engine-jit = { path = "../engine-jit", version = "1.0.0-alpha4", optional = true } wasmer-engine-native = { path = "../engine-native", version = "1.0.0-alpha4", optional = true } diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index dfdcd95d9d5..59c86e0cf61 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -36,6 +36,8 @@ mod tunables; mod types; mod utils; +pub use wasmer_derive::WasmerEnv; + pub mod internals { //! We use the internals module for exporting types that are only //! intended to use in internal crates such as the compatibility crate @@ -141,3 +143,95 @@ impl WasmerEnv for &'static mut T { (*self).free() } } + +// TODO: iterate on names +// TODO: do we want to use mutex/atomics here? like old WASI solution +/// Lazily init an item +pub struct InitAfterInstance { + /// The data to be initialized + data: std::mem::MaybeUninit, + /// Whether or not the data has been initialized + initialized: bool, +} + +impl InitAfterInstance { + /// Creates an unitialized value. + pub fn new() -> Self { + Self { + data: std::mem::MaybeUninit::uninit(), + initialized: false, + } + } + + /// # Safety + /// - The data must be initialized first + pub unsafe fn get_unchecked(&self) -> &T { + &*self.data.as_ptr() + } + + /// Get the inner data. + pub fn get_ref(&self) -> Option<&T> { + if !self.initialized { + None + } else { + Some(unsafe { self.get_unchecked() }) + } + } + + /// TOOD: review + pub fn initialize(&mut self, value: T) -> bool { + if self.initialized { + return false; + } + unsafe { + self.data.as_mut_ptr().write(value); + } + self.initialized = true; + true + } +} + +impl std::fmt::Debug for InitAfterInstance { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("InitAfterInstance") + .field("data", &self.get_ref()) + .finish() + } +} + +impl Clone for InitAfterInstance { + fn clone(&self) -> Self { + if let Some(inner) = self.get_ref() { + Self { + data: std::mem::MaybeUninit::new(inner.clone()), + initialized: true, + } + } else { + Self { + data: std::mem::MaybeUninit::uninit(), + initialized: false, + } + } + } +} + +impl Drop for InitAfterInstance { + fn drop(&mut self) { + if self.initialized { + unsafe { + let ptr = self.data.as_mut_ptr(); + std::ptr::drop_in_place(ptr); + }; + } + } +} + +impl Default for InitAfterInstance { + fn default() -> Self { + Self::new() + } +} + +unsafe impl Send for InitAfterInstance {} +// I thought we could opt out of sync..., look into this +// unsafe impl !Sync for InitWithInstance {} diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index 18ea8bf41e6..67ed7aba34b 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -208,12 +208,8 @@ fn function_new() -> Result<()> { #[test] fn function_new_env() -> Result<()> { let store = Store::default(); - #[derive(Clone)] + #[derive(Clone, WasmerEnv)] 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| {}); @@ -275,13 +271,9 @@ fn function_new_dynamic() -> Result<()> { #[test] fn function_new_dynamic_env() -> Result<()> { let store = Store::default(); - #[derive(Clone)] + #[derive(Clone, WasmerEnv)] 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( diff --git a/lib/derive/Cargo.toml b/lib/derive/Cargo.toml index f35a49cd9d4..28fa35ac953 100644 --- a/lib/derive/Cargo.toml +++ b/lib/derive/Cargo.toml @@ -15,4 +15,6 @@ syn = { version = "1", features = ["full"] } quote = "1" proc-macro2 = "1" proc-macro-error = "1.0.0" + +[dev-dependencies] wasmer = { path = "../api", version = "1.0.0-alpha4" } diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 75709d4d652..454f01f1e91 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -22,10 +22,14 @@ fn impl_wasmer_env_for_struct( data: &DataStruct, _attrs: &[Attribute], ) -> TokenStream { - let impl_inner = derive_struct_fields(data); + let (trait_methods, helper_methods) = derive_struct_fields(data); quote! { impl ::wasmer::WasmerEnv for #name { - #impl_inner + #trait_methods + } + + impl #name { + #helper_methods } } } @@ -57,15 +61,17 @@ fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { }*/ } -fn derive_struct_fields(data: &DataStruct) -> TokenStream { +fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { let mut finish = vec![]; let mut free = vec![]; - let mut assign_tokens = vec![]; + let mut helpers = vec![]; + //let mut assign_tokens = vec![]; let mut touched_fields = vec![]; match data.fields { Fields::Named(ref fields) => { for f in fields.named.iter() { let name = f.ident.as_ref().unwrap(); + let top_level_ty: &Type = &f.ty; touched_fields.push(name.clone()); let mut wasmer_attr = None; for attr in &f.attrs { @@ -76,36 +82,82 @@ fn derive_struct_fields(data: &DataStruct) -> TokenStream { } if let Some(wasmer_attr) = wasmer_attr { + let inner_type = match top_level_ty { + Type::Path(TypePath { + path: Path { segments, .. }, + .. + }) => { + if let Some(PathSegment { ident, arguments }) = segments.last() { + let ident_str = ident.to_string(); + if ident != "InitAfterInstance" { + // TODO: + panic!( + "Only the `InitAfterInstance` type is supported right now" + ); + } + if let PathArguments::AngleBracketed( + AngleBracketedGenericArguments { args, .. }, + ) = arguments + { + // TODO: proper error handling + assert_eq!(args.len(), 1); + if let GenericArgument::Type(Type::Path(TypePath { + path: Path { segments, .. }, + .. + })) = &args[0] + { + if let PathSegment { + ident, + .. + } = segments.last().expect("there must be at least one segment; TODO: error handling") { + ident + } else { + panic!("unknown type found inside `InitAfterInstance`"); + } + } else { + panic!("unrecognized type in first generic position on `InitAfterInstance`"); + } + } else { + panic!("Expected a generic parameter on `InitAfterInstance`"); + } + } else { + panic!("Wrong type of type found"); + } + } + _ => todo!("Unrecognized/unsupported type"), + }; + let name_ref_str = format!("{}_ref", name); + let name_ref = syn::Ident::new(&name_ref_str, name.span()); + let helper_tokens = quote_spanned! {f.span()=> + pub fn #name_ref(&self) -> &#inner_type { + unsafe { self.#name.get_unchecked() } + } + }; + helpers.push(helper_tokens); match wasmer_attr { WasmerAttr::Export { identifier, ty } => match ty { ExportAttr::Function {} => todo!(), ExportAttr::Memory {} => { let finish_tokens = quote_spanned! {f.span()=> let #name = instance.exports.get_memory(#identifier).unwrap(); - let #name = Box::into_raw(Box::new(#name.clone())); + self.#name.initialize(#name.clone()); }; finish.push(finish_tokens); let free_tokens = quote_spanned! {f.span()=> - let _ = Box::from_raw(self.#name); - self.#name = ::std::ptr::null_mut(); }; free.push(free_tokens); } }, } - assign_tokens.push(quote! { - self.#name = #name; - }); } } } _ => todo!(), } - quote! { + let trait_methods = quote! { fn finish(&mut self, instance: &::wasmer::Instance) { #(#finish)* - #(#assign_tokens)* } fn free(&mut self) { @@ -113,5 +165,11 @@ fn derive_struct_fields(data: &DataStruct) -> TokenStream { #(#free)* } } - } + }; + + let helper_methods = quote! { + #(#helpers)* + }; + + (trait_methods, helper_methods) } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index b50a4cde56d..dbe9300a2e0 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -29,7 +29,9 @@ pub use crate::syscalls::types; pub use crate::utils::{get_wasi_version, is_wasi_module, WasiVersion}; use thiserror::Error; -use wasmer::{imports, Function, ImportObject, Memory, Module, Store}; +use wasmer::{ + imports, Function, ImportObject, InitAfterInstance, Memory, Module, Store, WasmerEnv, +}; use std::cell::UnsafeCell; use std::fmt; @@ -48,29 +50,22 @@ pub enum WasiError { } /// The environment provided to the WASI imports. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, WasmerEnv)] pub struct WasiEnv { state: Arc>, - memory: *mut Memory, + #[wasmer(export("memory"))] + memory: InitAfterInstance, } - +/* impl wasmer::WasmerEnv for WasiEnv { fn finish(&mut self, instance: &wasmer::Instance) { dbg!("in Wasi::Finish"); let memory = instance.exports.get_memory("memory").unwrap(); - unsafe { - let heap_ptr = Box::into_raw(Box::new(memory.clone())); - self.memory = heap_ptr; - } + self.memory.initialize(memory.clone()); } - fn free(&mut self) { - unsafe { - Box::from_raw(self.memory); - self.memory = std::ptr::null_mut(); - } - } -} + fn free(&mut self) {} +}*/ /// Wrapper type around `Memory` used to delay initialization of the memory. /// @@ -91,74 +86,11 @@ impl fmt::Debug for WasiMemory { } } -impl WasiMemory { - fn new() -> Self { - Self { - initialized: AtomicBool::new(false), - memory: UnsafeCell::new(MaybeUninit::zeroed()), - mutate_lock: Mutex::new(()), - } - } - - /// Initialize the memory, making it safe to read from. - /// - /// Returns whether or not the set was successful. If the set failed then - /// the memory has already been initialized. - fn set_memory(&self, memory: Memory) -> bool { - // synchronize it - let _guard = self.mutate_lock.lock(); - if self.initialized.load(Ordering::Acquire) { - return false; - } - - unsafe { - let ptr = self.memory.get(); - let mem_inner: &mut MaybeUninit = &mut *ptr; - mem_inner.as_mut_ptr().write(memory); - } - self.initialized.store(true, Ordering::Release); - - true - } - - /// Returns `None` if the memory has not been initialized yet. - /// Otherwise returns the memory that was used to initialize it. - fn get_memory(&self) -> Option<&Memory> { - // Based on normal usage, `Relaxed` is fine... - // TODO: investigate if it's possible to use the API in a way where `Relaxed` - // is not fine - if self.initialized.load(Ordering::Relaxed) { - unsafe { - let maybe_mem = self.memory.get(); - Some(&*(*maybe_mem).as_ptr()) - } - } else { - None - } - } -} - -impl Drop for WasiMemory { - fn drop(&mut self) { - if self.initialized.load(Ordering::Acquire) { - unsafe { - // We want to get the internal value in memory, so we need to consume - // the `UnsafeCell` and assume the `MapbeInit` is initialized, but because - // we only have a `&mut self` we can't do this directly, so we swap the data - // out so we can drop it (via `assume_init`). - let mut maybe_uninit = UnsafeCell::new(MaybeUninit::zeroed()); - std::mem::swap(&mut self.memory, &mut maybe_uninit); - maybe_uninit.into_inner().assume_init(); - } - } - } -} - impl WasiEnv { pub fn new(state: WasiState) -> Self { Self { state: Arc::new(Mutex::new(state)), - memory: std::ptr::null_mut(), + memory: InitAfterInstance::new(), } } @@ -188,7 +120,7 @@ impl WasiEnv { /// Get a reference to the memory pub fn memory(&self) -> &Memory { - unsafe { &*self.memory } + self.memory_ref() } pub(crate) fn get_memory_and_wasi_state( From cfa87b272d53efb979baa689e54c29ee6067d04c Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 26 Oct 2020 14:56:02 -0700 Subject: [PATCH 11/39] Add misc changes, update from feedback --- lib/api/src/externals/function.rs | 5 +- lib/api/src/lib.rs | 42 +++++++++++++- lib/derive/src/lib.rs | 92 ++++++++++++++++--------------- lib/vm/src/export.rs | 7 ++- 4 files changed, 97 insertions(+), 49 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 91fb329f611..6b285bcdca2 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -5,6 +5,7 @@ use crate::types::Val; use crate::FunctionType; use crate::NativeFunc; use crate::RuntimeError; +use crate::WasmerEnv; pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; use std::cell::RefCell; use std::cmp::max; @@ -129,7 +130,7 @@ impl Function { pub fn new_with_env(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self where F: Fn(&mut Env, &[Val]) -> Result, RuntimeError> + 'static, - Env: Sized + crate::WasmerEnv + 'static, + Env: Sized + WasmerEnv + 'static, { let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv { env: RefCell::new(env), @@ -235,7 +236,7 @@ impl Function { F: HostFunction, Args: WasmTypeList, Rets: WasmTypeList, - Env: Sized + crate::WasmerEnv + 'static, + Env: Sized + WasmerEnv + 'static, { let function = inner::Function::::new(func); let address = function.address(); diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 59c86e0cf61..2028095093b 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -126,12 +126,52 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); // TODO: rename everything, all names are throw-away names /// Prototype trait for finishing envs. +/// # Examples +/// +/// This trait can be derived like so: +/// +/// ``` +/// # use wasmer::{WasmerEnv, InitAfterInstance, Memory}; +/// +/// #[derive(WasmerEnv)] +/// pub struct MyEnvWithNoInstanceData { +/// non_instance_data: u8, +/// } +/// +/// #[derive(WasmerEnv)] +/// pub struct MyEnvWithInstanceData { +/// non_instance_data: u8, +/// #[wasmer(export("memory"))] +/// memory: InitAfterInstance, +/// } +/// +/// ``` +/// +/// This trait can also be implemented manually: +/// ``` +/// # use wasmer::{WasmerEnv, InitAfterInstance, Memory, Instance}; +/// pub struct MyEnv { +/// memory: InitAfterInstance, +/// } +/// +/// impl WasmerEnv for MyEnv { +/// fn finish(&mut self, instance: &Instance) { +/// let memory = instance.exports.get_memory("memory").unwrap(); +/// self.memory.initialize(memory.clone()); +/// } +/// fn free(&mut self) {} +/// } +/// ``` pub trait WasmerEnv { /// The function that Wasmer will call on your type to let it finish - /// instantiating. + /// setting up the environment with data from the `Instance`. + /// + /// This function is called after `Instance` is created but before it is + /// returned to the user via `Instance::new`. fn finish(&mut self, instance: &Instance); /// Frees memory written to `self` so it can be dropped without any memory leaks. + // TODO: review, this is unused by the macro currently, do we want to do anything with this? fn free(&mut self); } diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 454f01f1e91..3e0165dd75b 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -2,7 +2,7 @@ extern crate proc_macro; use proc_macro2::{Span, TokenStream}; use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy}; -use quote::{format_ident, quote, quote_spanned}; +use quote::{format_ident, quote, quote_spanned, ToTokens}; use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *}; mod parse; @@ -72,6 +72,7 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { for f in fields.named.iter() { let name = f.ident.as_ref().unwrap(); let top_level_ty: &Type = &f.ty; + dbg!(top_level_ty); touched_fields.push(name.clone()); let mut wasmer_attr = None; for attr in &f.attrs { @@ -82,50 +83,7 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { } if let Some(wasmer_attr) = wasmer_attr { - let inner_type = match top_level_ty { - Type::Path(TypePath { - path: Path { segments, .. }, - .. - }) => { - if let Some(PathSegment { ident, arguments }) = segments.last() { - let ident_str = ident.to_string(); - if ident != "InitAfterInstance" { - // TODO: - panic!( - "Only the `InitAfterInstance` type is supported right now" - ); - } - if let PathArguments::AngleBracketed( - AngleBracketedGenericArguments { args, .. }, - ) = arguments - { - // TODO: proper error handling - assert_eq!(args.len(), 1); - if let GenericArgument::Type(Type::Path(TypePath { - path: Path { segments, .. }, - .. - })) = &args[0] - { - if let PathSegment { - ident, - .. - } = segments.last().expect("there must be at least one segment; TODO: error handling") { - ident - } else { - panic!("unknown type found inside `InitAfterInstance`"); - } - } else { - panic!("unrecognized type in first generic position on `InitAfterInstance`"); - } - } else { - panic!("Expected a generic parameter on `InitAfterInstance`"); - } - } else { - panic!("Wrong type of type found"); - } - } - _ => todo!("Unrecognized/unsupported type"), - }; + let inner_type = get_identifier(top_level_ty); let name_ref_str = format!("{}_ref", name); let name_ref = syn::Ident::new(&name_ref_str, name.span()); let helper_tokens = quote_spanned! {f.span()=> @@ -173,3 +131,47 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { (trait_methods, helper_methods) } + +// TODO: name this something that makes sense +fn get_identifier(ty: &Type) -> TokenStream { + match ty { + Type::Path(TypePath { + path: Path { segments, .. }, + .. + }) => { + if let Some(PathSegment { ident, arguments }) = segments.last() { + let ident_str = ident.to_string(); + if ident != "InitAfterInstance" { + // TODO: + panic!("Only the `InitAfterInstance` type is supported right now"); + } + if let PathArguments::AngleBracketed(AngleBracketedGenericArguments { + args, .. + }) = arguments + { + // TODO: proper error handling + assert_eq!(args.len(), 1); + if let GenericArgument::Type(Type::Path(TypePath { + path: Path { segments, .. }, + .. + })) = &args[0] + { + segments + .last() + .expect("there must be at least one segment; TODO: error handling") + .to_token_stream() + } else { + panic!( + "unrecognized type in first generic position on `InitAfterInstance`" + ); + } + } else { + panic!("Expected a generic parameter on `InitAfterInstance`"); + } + } else { + panic!("Wrong type of type found"); + } + } + _ => todo!("Unrecognized/unsupported type"), + } +} diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 3935f360d4d..4b276eb9168 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -31,7 +31,12 @@ pub struct ExportFunction { pub address: *const VMFunctionBody, /// Pointer to the containing `VMContext`. pub vmctx: *mut VMContext, - /// temp code to set vmctx for host functions + /// Function pointer to `WasmerEnv::finish(&mut self, instance: &Instance)`. + /// + /// This function is called to finish setting up the environment after + /// we create the `api::Instance`. + // META: if you have a better idea of how to get this function to where it + // needs to be, please let me know. pub function_ptr: Option, /// The function type, used for compatibility checking. pub signature: FunctionType, From 1dd6d8d3eb4f2633e1f05acce50803302f8a3498 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 27 Oct 2020 17:10:32 -0700 Subject: [PATCH 12/39] Add modified attribute to get `NativeFunc` working --- lib/derive/src/lib.rs | 15 ++++++++++++--- lib/derive/src/parse.rs | 35 +++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 3e0165dd75b..237f12fde40 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -94,10 +94,19 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { helpers.push(helper_tokens); match wasmer_attr { WasmerAttr::Export { identifier, ty } => match ty { - ExportAttr::Function {} => todo!(), - ExportAttr::Memory {} => { + ExportAttr::NativeFunc {} => { let finish_tokens = quote_spanned! {f.span()=> - let #name = instance.exports.get_memory(#identifier).unwrap(); + let #name: #inner_type = instance.exports.get_native_function(#identifier).unwrap(); + self.#name.initialize(#name); + }; + finish.push(finish_tokens); + let free_tokens = quote_spanned! {f.span()=> + }; + free.push(free_tokens); + } + ExportAttr::EverythingElse {} => { + let finish_tokens = quote_spanned! {f.span()=> + let #name: &#inner_type = instance.exports.get(#identifier).unwrap(); self.#name.initialize(#name.clone()); }; finish.push(finish_tokens); diff --git a/lib/derive/src/parse.rs b/lib/derive/src/parse.rs index e92d94f09e6..477c42ab1f0 100644 --- a/lib/derive/src/parse.rs +++ b/lib/derive/src/parse.rs @@ -11,20 +11,38 @@ pub enum WasmerAttr { } pub enum ExportAttr { - // TODO: - Function {}, - Memory {}, + NativeFunc, + EverythingElse, } struct ExportExpr { name: LitStr, + ty: ExportAttr, } impl Parse for ExportExpr { fn parse(input: ParseStream<'_>) -> syn::Result { - Ok(Self { - name: input.parse::()?, - }) + if input.peek(LitStr) { + Ok(Self { + name: input.parse::()?, + ty: ExportAttr::EverythingElse, + }) + } else { + let ident: Ident = input.parse()?; + let ident_str = ident.to_string(); + + if ident_str.as_str() == "native_func" { + let inner; + let _ = parenthesized!(inner in input); + let name = inner.parse::()?; + Ok(Self { + name, + ty: ExportAttr::NativeFunc, + }) + } else { + panic!("Todo abort here"); + } + } } } @@ -40,9 +58,10 @@ impl Parse for WasmerAttrInner { let export_expr; let _: token::Paren = parenthesized!(export_expr in input); + let expr = export_expr.parse::()?; WasmerAttr::Export { - identifier: export_expr.parse::()?.name, - ty: ExportAttr::Memory {}, + identifier: expr.name, + ty: expr.ty, } } _ => return Err(input.error(format!("Unexpected identifier {}", ident_str))), From 82330018c2d2363efe7a6a2a3ad9f976244cca41 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 27 Oct 2020 18:02:52 -0700 Subject: [PATCH 13/39] Add support for generics and lifetimes for WasmerEnv derive --- lib/derive/src/lib.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 237f12fde40..579c33dd930 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -20,15 +20,18 @@ pub fn derive_wasmer_env(input: proc_macro::TokenStream) -> proc_macro::TokenStr fn impl_wasmer_env_for_struct( name: &Ident, data: &DataStruct, + generics: &Generics, _attrs: &[Attribute], ) -> TokenStream { let (trait_methods, helper_methods) = derive_struct_fields(data); + let lifetimes_and_generics = generics.params.clone(); + let where_clause = generics.where_clause.clone(); quote! { - impl ::wasmer::WasmerEnv for #name { + impl < #lifetimes_and_generics > ::wasmer::WasmerEnv for #name < #lifetimes_and_generics > #where_clause{ #trait_methods } - impl #name { + impl < #lifetimes_and_generics > #name < #lifetimes_and_generics > #where_clause { #helper_methods } } @@ -48,7 +51,7 @@ fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { }); match &input.data { - Data::Struct(ds) => impl_wasmer_env_for_struct(struct_name, ds, &input.attrs), + Data::Struct(ds) => impl_wasmer_env_for_struct(struct_name, ds, &input.generics, &input.attrs), _ => todo!(), } /*match input.data { From 8b87526d9dd8387f48f5c7c9a844a233d17fd152 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 28 Oct 2020 13:32:27 -0700 Subject: [PATCH 14/39] Create single interface to get exports from Instance.exports This adds a method that takes generic arguments as well so that NativeFunc can also be `got` even though it has generic parameters --- lib/api/src/exports.rs | 42 ++++++++++++++++++++ lib/api/src/native.rs | 11 ++++++ lib/derive/src/lib.rs | 55 ++++++++++++++------------ lib/derive/src/parse.rs | 87 ++++++++++++++++++++++++++++++++--------- 4 files changed, 152 insertions(+), 43 deletions(-) diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index 744605a2476..7f53591f4fe 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -150,6 +150,19 @@ impl Exports { .map_err(|_| ExportError::IncompatibleType) } + /// Hack to get this working with nativefunc too + pub fn get_with_generics<'a, T, Args, Rets>(&'a self, name: &str) -> Result + where + Args: WasmTypeList, + Rets: WasmTypeList, + T: ExportableWithGenerics<'a, Args, Rets>, + { + match self.map.get(name) { + None => Err(ExportError::Missing(name.to_string())), + Some(extern_) => T::get_self_from_extern_with_generics(extern_), + } + } + /// Get an export as an `Extern`. pub fn get_extern(&self, name: &str) -> Option<&Extern> { self.map.get(name) @@ -282,3 +295,32 @@ pub trait Exportable<'a>: Sized { /// [`Instance`]: crate::Instance fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>; } + +/// Hack to make macros work well +pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized { + /// Get it with generics + fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result; + /*where + Args: WasmTypeList, + Rets: WasmTypeList;*/ +} + +impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T { + fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result { + T::get_self_from_extern(_extern).map(|i| i.clone()) + } +} + +/* +impl<'a, Args, Rets> ExportableWithGenerics<'a> for T { + fn get_self_from_extern_with_generics( + _extern: &'a Extern, + ) -> Result<&'a Self, ExportError> + where + Args: WasmTypeList, + Rets: WasmTypeList, + { + T::get_self_from_extern(_extern) + } +} +*/ diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index 4c0c6b5daa1..ed8a2f7ca4f 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -201,6 +201,17 @@ macro_rules! impl_native_traits { } } + + impl<'a, $( $x, )* Rets> crate::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for NativeFunc<( $( $x ),* ), Rets> + where + $( $x: FromToNativeWasmType, )* + Rets: WasmTypeList, + { + fn get_self_from_extern_with_generics(_extern: &crate::externals::Extern) -> Result { + use crate::exports::Exportable; + crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::exports::ExportError::IncompatibleType) + } + } }; } diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 579c33dd930..cf4b47b33ce 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -51,7 +51,9 @@ fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { }); match &input.data { - Data::Struct(ds) => impl_wasmer_env_for_struct(struct_name, ds, &input.generics, &input.attrs), + Data::Struct(ds) => { + impl_wasmer_env_for_struct(struct_name, ds, &input.generics, &input.attrs) + } _ => todo!(), } /*match input.data { @@ -74,8 +76,9 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { Fields::Named(ref fields) => { for f in fields.named.iter() { let name = f.ident.as_ref().unwrap(); + let name_str = name.to_string(); let top_level_ty: &Type = &f.ty; - dbg!(top_level_ty); + //dbg!(top_level_ty); touched_fields.push(name.clone()); let mut wasmer_attr = None; for attr in &f.attrs { @@ -96,28 +99,32 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { }; helpers.push(helper_tokens); match wasmer_attr { - WasmerAttr::Export { identifier, ty } => match ty { - ExportAttr::NativeFunc {} => { - let finish_tokens = quote_spanned! {f.span()=> - let #name: #inner_type = instance.exports.get_native_function(#identifier).unwrap(); - self.#name.initialize(#name); - }; - finish.push(finish_tokens); - let free_tokens = quote_spanned! {f.span()=> - }; - free.push(free_tokens); - } - ExportAttr::EverythingElse {} => { - let finish_tokens = quote_spanned! {f.span()=> - let #name: &#inner_type = instance.exports.get(#identifier).unwrap(); - self.#name.initialize(#name.clone()); - }; - finish.push(finish_tokens); - let free_tokens = quote_spanned! {f.span()=> - }; - free.push(free_tokens); - } - }, + WasmerAttr::Export { identifier, .. } => { + let item_name = + identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span())); + /*match ty { + ExportAttr::NativeFunc {} => { + let finish_tokens = quote_spanned! {f.span()=> + let #name: #inner_type = instance.exports.get_native_function(#item_name).unwrap(); + self.#name.initialize(#name); + }; + finish.push(finish_tokens); + let free_tokens = quote_spanned! {f.span()=> + }; + free.push(free_tokens); + } + ExportAttr::EverythingElse {} => {*/ + let finish_tokens = quote_spanned! {f.span()=> + let #name: #inner_type = instance.exports.get_with_generics(#item_name).unwrap(); + self.#name.initialize(#name); + }; + finish.push(finish_tokens); + let free_tokens = quote_spanned! {f.span()=> + }; + free.push(free_tokens); + //} + //} + } } } } diff --git a/lib/derive/src/parse.rs b/lib/derive/src/parse.rs index 477c42ab1f0..216d0640586 100644 --- a/lib/derive/src/parse.rs +++ b/lib/derive/src/parse.rs @@ -7,7 +7,12 @@ use syn::{ }; pub enum WasmerAttr { - Export { identifier: LitStr, ty: ExportAttr }, + Export { + /// The identifier is an override, otherwise we use the field name as the name + /// to lookup in `instance.exports`. + identifier: Option, + ty: ExportAttr, + }, } pub enum ExportAttr { @@ -16,33 +21,71 @@ pub enum ExportAttr { } struct ExportExpr { - name: LitStr, + name: Option, ty: ExportAttr, } +struct ExportOptions { + name: Option, +} +impl Parse for ExportOptions { + fn parse(input: ParseStream<'_>) -> syn::Result { + let ident = input.parse::()?; + let _ = input.parse::()?; + let ident_str = ident.to_string(); + let mut name = None; + + match ident_str.as_str() { + "name" => { + name = Some(input.parse::()?); + } + _ => { + // TODO: better handle errors here + panic!("Unrecognized argument in export options"); + } + } + + Ok(ExportOptions { name }) + } +} + +// parsing either: +// Inner | NativeFunc +// +// Inner: +// - Nothing +// - `name = "name"` impl Parse for ExportExpr { fn parse(input: ParseStream<'_>) -> syn::Result { - if input.peek(LitStr) { - Ok(Self { - name: input.parse::()?, - ty: ExportAttr::EverythingElse, - }) - } else { + let name; + let ty; + /* + // check for native_func( + if input.peek(Ident) && input.peek2(token::Paren) { let ident: Ident = input.parse()?; let ident_str = ident.to_string(); - if ident_str.as_str() == "native_func" { let inner; let _ = parenthesized!(inner in input); - let name = inner.parse::()?; - Ok(Self { - name, - ty: ExportAttr::NativeFunc, - }) + let options = inner.parse::()?; + name = options.name; + ty = ExportAttr::NativeFunc; } else { - panic!("Todo abort here"); + panic!("Unrecognized attribute `{}` followed by `(`. Expected `native_func`", + &ident_str); } + } + + // check for inner attribute + else */ if input.peek(Ident) { + let options = input.parse::()?; + name = options.name; + ty = ExportAttr::EverythingElse; + } else { + name = None; + ty = ExportAttr::EverythingElse; } + Ok(Self { name, ty }) } } @@ -56,12 +99,18 @@ impl Parse for WasmerAttrInner { let out = match ident_str.as_str() { "export" => { let export_expr; - let _: token::Paren = parenthesized!(export_expr in input); + let (name, ty) = if input.peek(token::Paren) { + let _: token::Paren = parenthesized!(export_expr in input); + + let expr = export_expr.parse::()?; + (expr.name, expr.ty) + } else { + (None, ExportAttr::EverythingElse) + }; - let expr = export_expr.parse::()?; WasmerAttr::Export { - identifier: expr.name, - ty: expr.ty, + identifier: name, + ty, } } _ => return Err(input.error(format!("Unexpected identifier {}", ident_str))), From be3ab95688585cbf681bc68e065a97205fcc8faf Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 28 Oct 2020 17:39:37 -0700 Subject: [PATCH 15/39] Add error handling to host init logic --- lib/api/src/externals/function.rs | 8 +++-- lib/api/src/instance.rs | 35 +++++++++++++++++++- lib/api/src/lib.rs | 25 +++++++++++--- lib/api/src/native.rs | 1 + lib/c-api/wasmer_wasm.h | 4 +-- lib/derive/src/lib.rs | 55 ++++++++++++++++--------------- lib/derive/src/parse.rs | 43 ++++-------------------- lib/vm/src/export.rs | 5 ++- lib/vm/src/imports.rs | 15 +++++++-- lib/vm/src/instance.rs | 15 +++++++-- lib/wasi/src/lib.rs | 40 +--------------------- 11 files changed, 127 insertions(+), 119 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 495361af5f1..65e944e6ecc 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -143,7 +143,9 @@ impl Function { let address = std::ptr::null() as *const VMFunctionBody; let vmctx = Box::into_raw(Box::new(dynamic_ctx)) as *mut VMContext; // TODO: look into removing transmute by changing API type signatures - let function_ptr = Some(unsafe { std::mem::transmute::(Env::finish) }); + let function_ptr = Some(unsafe { + std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish) + }); //dbg!(function_ptr); Self { @@ -249,7 +251,9 @@ impl Function { let box_env = Box::new(env); let vmctx = Box::into_raw(box_env) as *mut VMContext; // TODO: look into removing transmute by changing API type signatures - let function_ptr = Some(unsafe { std::mem::transmute::(Env::finish) }); + let function_ptr = Some(unsafe { + std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish) + }); //dbg!(function_ptr as usize); let signature = function.ty(); diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index c9dd1c6216b..700544d680b 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -2,8 +2,9 @@ use crate::exports::Exports; use crate::externals::Extern; use crate::module::Module; use crate::store::Store; -use crate::InstantiationError; +use crate::{HostEnvInitError, LinkError, RuntimeError}; use std::fmt; +use thiserror::Error; use wasmer_engine::Resolver; use wasmer_vm::{InstanceHandle, VMContext}; @@ -36,6 +37,38 @@ mod send_test { } } +/// An error while instantiating a module. +/// +/// This is not a common WebAssembly error, however +/// we need to differentiate from a `LinkError` (an error +/// that happens while linking, on instantiation), a +/// Trap that occurs when calling the WebAssembly module +/// start function, and an error when initializing the user's +/// host environments. +#[derive(Error, Debug)] +pub enum InstantiationError { + /// A linking ocurred during instantiation. + #[error(transparent)] + Link(LinkError), + + /// A runtime error occured while invoking the start function + #[error(transparent)] + Start(RuntimeError), + + /// Error occurred when initializing the host environment. + #[error(transparent)] + HostEnvInitialization(HostEnvInitError), +} + +impl From for InstantiationError { + fn from(other: wasmer_engine::InstantiationError) -> Self { + match other { + wasmer_engine::InstantiationError::Link(e) => Self::Link(e), + wasmer_engine::InstantiationError::Start(e) => Self::Start(e), + } + } +} + impl Instance { /// Creates a new `Instance` from a WebAssembly [`Module`] and a /// set of imports resolved by the [`Resolver`]. diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 0090dc4f7bd..d8d6bc1cef4 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -56,7 +56,7 @@ pub use crate::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList, }; pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace}; -pub use crate::instance::Instance; +pub use crate::instance::{Instance, InstantiationError}; pub use crate::module::Module; pub use crate::native::NativeFunc; pub use crate::ptr::{Array, Item, WasmPtr}; @@ -76,8 +76,8 @@ pub use wasmer_compiler::{ }; pub use wasmer_compiler::{CpuFeature, Features, Target}; pub use wasmer_engine::{ - ChainableNamedResolver, DeserializeError, Engine, FrameInfo, InstantiationError, LinkError, - NamedResolver, NamedResolverChain, Resolver, RuntimeError, SerializeError, + ChainableNamedResolver, DeserializeError, Engine, FrameInfo, LinkError, NamedResolver, + NamedResolverChain, Resolver, RuntimeError, SerializeError, }; pub use wasmer_types::{ Atomically, Bytes, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType, @@ -129,6 +129,21 @@ 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 +use thiserror::Error; +/// An error while initializing the user supplied host env with the `WasmerEnv` trait. +#[derive(Error, Debug)] +#[error("Host env initialization error: {0}")] +pub enum HostEnvInitError { + /// An error occurred when accessing an export + Export(ExportError), +} + +impl From for HostEnvInitError { + fn from(other: ExportError) -> Self { + Self::Export(other) + } +} + /// Prototype trait for finishing envs. /// # Examples /// @@ -172,7 +187,7 @@ pub trait WasmerEnv { /// /// This function is called after `Instance` is created but before it is /// returned to the user via `Instance::new`. - fn finish(&mut self, instance: &Instance); + fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError>; /// Frees memory written to `self` so it can be dropped without any memory leaks. // TODO: review, this is unused by the macro currently, do we want to do anything with this? @@ -180,7 +195,7 @@ pub trait WasmerEnv { } impl WasmerEnv for &'static mut T { - fn finish(&mut self, instance: &Instance) { + fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { (*self).finish(instance) } fn free(&mut self) { diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index ed8a2f7ca4f..b8f6c291d72 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -202,6 +202,7 @@ macro_rules! impl_native_traits { } } + #[allow(unused_parens)] impl<'a, $( $x, )* Rets> crate::exports::ExportableWithGenerics<'a, ($( $x ),*), Rets> for NativeFunc<( $( $x ),* ), Rets> where $( $x: FromToNativeWasmType, )* diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index abbc036be47..eb61710af86 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -131,11 +131,11 @@ intptr_t wasi_env_read_stdout(wasi_env_t *env, char *buffer, uintptr_t buffer_le #endif #if defined(WASMER_WASI_ENABLED) -bool wasi_env_set_instance(wasi_env_t *env, const wasm_instance_t *instance); +bool wasi_env_set_instance(wasi_env_t *_env, const wasm_instance_t *_instance); #endif #if defined(WASMER_WASI_ENABLED) -void wasi_env_set_memory(wasi_env_t *env, const wasm_memory_t *memory); +void wasi_env_set_memory(wasi_env_t *_env, const wasm_memory_t *_memory); #endif #if defined(WASMER_WASI_ENABLED) diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index cf4b47b33ce..c3ac6e11842 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -2,12 +2,12 @@ extern crate proc_macro; use proc_macro2::{Span, TokenStream}; use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy}; -use quote::{format_ident, quote, quote_spanned, ToTokens}; -use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *}; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{spanned::Spanned, token::Comma, *}; mod parse; -use crate::parse::{ExportAttr, WasmerAttr}; +use crate::parse::WasmerAttr; #[proc_macro_derive(WasmerEnv, attributes(wasmer))] #[proc_macro_error] @@ -84,8 +84,10 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { for attr in &f.attrs { // if / filter let tokens = attr.tokens.clone(); - wasmer_attr = Some(syn::parse2(tokens).unwrap()); - break; + if let Ok(attr) = syn::parse2(tokens) { + wasmer_attr = Some(attr); + break; + } } if let Some(wasmer_attr) = wasmer_attr { @@ -103,26 +105,26 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { let item_name = identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span())); /*match ty { - ExportAttr::NativeFunc {} => { - let finish_tokens = quote_spanned! {f.span()=> - let #name: #inner_type = instance.exports.get_native_function(#item_name).unwrap(); - self.#name.initialize(#name); - }; - finish.push(finish_tokens); - let free_tokens = quote_spanned! {f.span()=> - }; - free.push(free_tokens); - } - ExportAttr::EverythingElse {} => {*/ - let finish_tokens = quote_spanned! {f.span()=> - let #name: #inner_type = instance.exports.get_with_generics(#item_name).unwrap(); - self.#name.initialize(#name); - }; - finish.push(finish_tokens); - let free_tokens = quote_spanned! {f.span()=> - }; - free.push(free_tokens); - //} + ExportAttr::NativeFunc {} => { + let finish_tokens = quote_spanned! {f.span()=> + let #name: #inner_type = instance.exports.get_native_function(#item_name).unwrap(); + self.#name.initialize(#name); + }; + finish.push(finish_tokens); + let free_tokens = quote_spanned! {f.span()=> + }; + free.push(free_tokens); + } + ExportAttr::EverythingElse {} => {*/ + let finish_tokens = quote_spanned! {f.span()=> + let #name: #inner_type = instance.exports.get_with_generics(#item_name)?; + self.#name.initialize(#name); + }; + finish.push(finish_tokens); + let free_tokens = quote_spanned! {f.span()=> + }; + free.push(free_tokens); + //} //} } } @@ -133,8 +135,9 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { } let trait_methods = quote! { - fn finish(&mut self, instance: &::wasmer::Instance) { + fn finish(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> { #(#finish)* + Ok(()) } fn free(&mut self) { diff --git a/lib/derive/src/parse.rs b/lib/derive/src/parse.rs index 216d0640586..35be70ff285 100644 --- a/lib/derive/src/parse.rs +++ b/lib/derive/src/parse.rs @@ -11,18 +11,11 @@ pub enum WasmerAttr { /// The identifier is an override, otherwise we use the field name as the name /// to lookup in `instance.exports`. identifier: Option, - ty: ExportAttr, }, } -pub enum ExportAttr { - NativeFunc, - EverythingElse, -} - struct ExportExpr { name: Option, - ty: ExportAttr, } struct ExportOptions { @@ -58,34 +51,13 @@ impl Parse for ExportOptions { impl Parse for ExportExpr { fn parse(input: ParseStream<'_>) -> syn::Result { let name; - let ty; - /* - // check for native_func( - if input.peek(Ident) && input.peek2(token::Paren) { - let ident: Ident = input.parse()?; - let ident_str = ident.to_string(); - if ident_str.as_str() == "native_func" { - let inner; - let _ = parenthesized!(inner in input); - let options = inner.parse::()?; - name = options.name; - ty = ExportAttr::NativeFunc; - } else { - panic!("Unrecognized attribute `{}` followed by `(`. Expected `native_func`", - &ident_str); - } - } - - // check for inner attribute - else */ if input.peek(Ident) { + if input.peek(Ident) { let options = input.parse::()?; name = options.name; - ty = ExportAttr::EverythingElse; } else { name = None; - ty = ExportAttr::EverythingElse; } - Ok(Self { name, ty }) + Ok(Self { name }) } } @@ -99,19 +71,16 @@ impl Parse for WasmerAttrInner { let out = match ident_str.as_str() { "export" => { let export_expr; - let (name, ty) = if input.peek(token::Paren) { + let name = if input.peek(token::Paren) { let _: token::Paren = parenthesized!(export_expr in input); let expr = export_expr.parse::()?; - (expr.name, expr.ty) + expr.name } else { - (None, ExportAttr::EverythingElse) + None }; - WasmerAttr::Export { - identifier: name, - ty, - } + WasmerAttr::Export { identifier: name } } _ => return Err(input.error(format!("Unexpected identifier {}", ident_str))), }; diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 4b276eb9168..09800bf4102 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -37,7 +37,10 @@ pub struct ExportFunction { /// we create the `api::Instance`. // META: if you have a better idea of how to get this function to where it // needs to be, please let me know. - pub function_ptr: Option, + pub function_ptr: Option< + // TODO: review the return value here... + fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, + >, /// The function type, used for compatibility checking. pub signature: FunctionType, /// The function kind (it defines how it's the signature that provided `address` have) diff --git a/lib/vm/src/imports.rs b/lib/vm/src/imports.rs index 80c7ce19cf7..510830e43e2 100644 --- a/lib/vm/src/imports.rs +++ b/lib/vm/src/imports.rs @@ -14,8 +14,12 @@ pub struct Imports { /// Initializers for host function environments. This is split out from `functions` /// because the generated code never needs to touch this and the extra wasted /// space may affect Wasm runtime performance due to increased cache pressure. - pub host_function_env_initializers: - BoxedSlice>, + pub host_function_env_initializers: BoxedSlice< + FunctionIndex, + Option< + fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, + >, + >, /// Resolved addresses for imported tables. pub tables: BoxedSlice, @@ -33,7 +37,12 @@ impl Imports { function_imports: PrimaryMap, host_function_env_initializers: PrimaryMap< FunctionIndex, - Option, + Option< + fn( + *mut std::ffi::c_void, + *const std::ffi::c_void, + ) -> Result<(), *mut std::ffi::c_void>, + >, >, table_imports: PrimaryMap, memory_imports: PrimaryMap, diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 90c25592af3..edaf6930f10 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -110,7 +110,9 @@ pub(crate) struct Instance { /// /// Be sure to test with serialize/deserialize and imported functions from other Wasm modules. import_initializers: Vec<( - Option, + Option< + fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, + >, *mut std::ffi::c_void, )>, @@ -159,7 +161,9 @@ impl Instance { fn imported_function_env_initializer( &self, index: FunctionIndex, - ) -> Option { + ) -> Option< + fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, + > { self.import_initializers[index.as_u32() as usize].0 } @@ -907,7 +911,12 @@ impl InstanceHandle { vmshared_signatures: BoxedSlice, host_state: Box, import_initializers: Vec<( - Option, + Option< + fn( + *mut std::ffi::c_void, + *const std::ffi::c_void, + ) -> Result<(), *mut std::ffi::c_void>, + >, *mut std::ffi::c_void, )>, ) -> Result { diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 61b8549e9c3..b8f4105bd94 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -33,10 +33,6 @@ use wasmer::{ imports, Function, ImportObject, InitAfterInstance, Memory, Module, Store, WasmerEnv, }; -use std::cell::UnsafeCell; -use std::fmt; -use std::mem::MaybeUninit; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex, MutexGuard}; /// This is returned in `RuntimeError`. @@ -53,38 +49,9 @@ pub enum WasiError { #[derive(Debug, Clone, WasmerEnv)] pub struct WasiEnv { state: Arc>, - #[wasmer(export("memory"))] + #[wasmer(export)] memory: InitAfterInstance, } -/* -impl wasmer::WasmerEnv for WasiEnv { - fn finish(&mut self, instance: &wasmer::Instance) { - dbg!("in Wasi::Finish"); - let memory = instance.exports.get_memory("memory").unwrap(); - self.memory.initialize(memory.clone()); - } - - fn free(&mut self) {} -}*/ - -/// Wrapper type around `Memory` used to delay initialization of the memory. -/// -/// The `initialized` field is used to indicate if it's safe to read `memory` as `Memory`. -/// -/// The `mutate_lock` is used to prevent access from multiple threads during initialization. -struct WasiMemory { - initialized: AtomicBool, - memory: UnsafeCell>, - mutate_lock: Mutex<()>, -} - -impl fmt::Debug for WasiMemory { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("WasiMemory") - .field("initialized", &self.initialized) - .finish() - } -} impl WasiEnv { pub fn new(state: WasiState) -> Self { @@ -103,11 +70,6 @@ impl WasiEnv { )) } - /// Set the memory - /*pub fn set_memory(&mut self, memory: Memory) -> bool { - self.memory.set_memory(memory) - }*/ - /// Get the WASI state pub fn state(&self) -> MutexGuard { self.state.lock().unwrap() From 83008a7771a9c8692c9975d1a315caffb4e4f175 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 29 Oct 2020 11:13:51 -0700 Subject: [PATCH 16/39] Fix up error handling code, get tests passing --- lib/api/src/instance.rs | 8 +++- lib/api/src/lib.rs | 24 +++++----- lib/derive/src/lib.rs | 10 ++--- lib/derive/tests/basic.rs | 70 +++++++++++++++++++++++++++++ lib/vm/src/instance.rs | 23 ++++++++-- lib/wasi/src/lib.rs | 8 ++-- tests/compilers/imports.rs | 8 +++- tests/compilers/native_functions.rs | 8 +++- tests/compilers/traps.rs | 4 +- 9 files changed, 131 insertions(+), 32 deletions(-) create mode 100644 lib/derive/tests/basic.rs diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index 700544d680b..ca002e7e785 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -69,6 +69,12 @@ impl From for InstantiationError { } } +impl From for InstantiationError { + fn from(other: HostEnvInitError) -> Self { + Self::HostEnvInitialization(other) + } +} + impl Instance { /// Creates a new `Instance` from a WebAssembly [`Module`] and a /// set of imports resolved by the [`Resolver`]. @@ -127,7 +133,7 @@ impl Instance { unsafe { instance .handle - .initialize_host_envs(&instance as *const _ as *const _); + .initialize_host_envs::(&instance as *const _ as *const _)?; } Ok(instance) diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index d8d6bc1cef4..854b91c7918 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -150,7 +150,7 @@ impl From for HostEnvInitError { /// This trait can be derived like so: /// /// ``` -/// # use wasmer::{WasmerEnv, InitAfterInstance, Memory}; +/// # use wasmer::{WasmerEnv, LazyInit, Memory}; /// /// #[derive(WasmerEnv)] /// pub struct MyEnvWithNoInstanceData { @@ -161,16 +161,16 @@ impl From for HostEnvInitError { /// pub struct MyEnvWithInstanceData { /// non_instance_data: u8, /// #[wasmer(export("memory"))] -/// memory: InitAfterInstance, +/// memory: LazyInit, /// } /// /// ``` /// /// This trait can also be implemented manually: /// ``` -/// # use wasmer::{WasmerEnv, InitAfterInstance, Memory, Instance}; +/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance}; /// pub struct MyEnv { -/// memory: InitAfterInstance, +/// memory: LazyInit, /// } /// /// impl WasmerEnv for MyEnv { @@ -206,14 +206,14 @@ impl WasmerEnv for &'static mut T { // TODO: iterate on names // TODO: do we want to use mutex/atomics here? like old WASI solution /// Lazily init an item -pub struct InitAfterInstance { +pub struct LazyInit { /// The data to be initialized data: std::mem::MaybeUninit, /// Whether or not the data has been initialized initialized: bool, } -impl InitAfterInstance { +impl LazyInit { /// Creates an unitialized value. pub fn new() -> Self { Self { @@ -250,15 +250,15 @@ impl InitAfterInstance { } } -impl std::fmt::Debug for InitAfterInstance { +impl std::fmt::Debug for LazyInit { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("InitAfterInstance") + f.debug_struct("LazyInit") .field("data", &self.get_ref()) .finish() } } -impl Clone for InitAfterInstance { +impl Clone for LazyInit { fn clone(&self) -> Self { if let Some(inner) = self.get_ref() { Self { @@ -274,7 +274,7 @@ impl Clone for InitAfterInstance { } } -impl Drop for InitAfterInstance { +impl Drop for LazyInit { fn drop(&mut self) { if self.initialized { unsafe { @@ -285,12 +285,12 @@ impl Drop for InitAfterInstance { } } -impl Default for InitAfterInstance { +impl Default for LazyInit { fn default() -> Self { Self::new() } } -unsafe impl Send for InitAfterInstance {} +unsafe impl Send for LazyInit {} // I thought we could opt out of sync..., look into this // unsafe impl !Sync for InitWithInstance {} diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index c3ac6e11842..cce734db534 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -163,9 +163,9 @@ fn get_identifier(ty: &Type) -> TokenStream { }) => { if let Some(PathSegment { ident, arguments }) = segments.last() { let ident_str = ident.to_string(); - if ident != "InitAfterInstance" { + if ident != "LazyInit" { // TODO: - panic!("Only the `InitAfterInstance` type is supported right now"); + panic!("Only the `LazyInit` type is supported right now"); } if let PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. @@ -183,12 +183,10 @@ fn get_identifier(ty: &Type) -> TokenStream { .expect("there must be at least one segment; TODO: error handling") .to_token_stream() } else { - panic!( - "unrecognized type in first generic position on `InitAfterInstance`" - ); + panic!("unrecognized type in first generic position on `LazyInit`"); } } else { - panic!("Expected a generic parameter on `InitAfterInstance`"); + panic!("Expected a generic parameter on `LazyInit`"); } } else { panic!("Wrong type of type found"); diff --git a/lib/derive/tests/basic.rs b/lib/derive/tests/basic.rs new file mode 100644 index 00000000000..267545d9b65 --- /dev/null +++ b/lib/derive/tests/basic.rs @@ -0,0 +1,70 @@ +use wasmer::{Function, Global, LazyInit, Memory, NativeFunc, Table, WasmerEnv}; + +#[derive(WasmerEnv)] +struct MyEnv { + num: u32, + nums: Vec, +} + +fn impls_wasmer_env() -> bool { + true +} + +#[test] +fn test_derive() { + let _my_env = MyEnv { + num: 3, + nums: vec![1, 2, 3], + }; + assert!(impls_wasmer_env::()); +} + +#[derive(WasmerEnv)] +struct MyEnvWithMemory { + num: u32, + nums: Vec, + #[wasmer(export)] + memory: LazyInit, +} + +#[derive(WasmerEnv)] +struct MyEnvWithFuncs { + num: u32, + nums: Vec, + #[wasmer(export)] + memory: LazyInit, + #[wasmer(export)] + sum: LazyInit>, +} + +#[derive(WasmerEnv)] +struct MyEnvWithEverything { + num: u32, + nums: Vec, + #[wasmer(export)] + memory: LazyInit, + #[wasmer(export)] + sum: LazyInit>, + #[wasmer(export)] + multiply: LazyInit, + #[wasmer(export)] + counter: LazyInit, + #[wasmer(export)] + functions: LazyInit, +} + +#[derive(WasmerEnv)] +struct MyEnvWithLifetime<'a> { + name: &'a str, + #[wasmer(export(name = "memory"))] + memory: LazyInit, +} + +#[test] +fn test_derive_with_attribute() { + //use wasmer::WasmerEnv; + assert!(impls_wasmer_env::()); + assert!(impls_wasmer_env::()); + assert!(impls_wasmer_env::()); + assert!(impls_wasmer_env::()); +} diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index edaf6930f10..53dfaa62808 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -1148,15 +1148,32 @@ impl InstanceHandle { unsafe { &*(self.instance as *const Instance) } } - /// TODO: document this /// Initializes the host environments. - pub unsafe fn initialize_host_envs(&self, instance_ptr: *const std::ffi::c_void) { + /// + /// # Safety + /// - This function should only be called once (TODO: we can enforce this by draining the vec...) + /// - This function must be called with the correct `Err` type parameter: the error type is not + /// visible to code in `wasmer_vm`, so it's the caller's responsibility to ensure these + /// functions are called with the correct type. + pub unsafe fn initialize_host_envs( + &self, + instance_ptr: *const std::ffi::c_void, + ) -> Result<(), Err> { for (func, env) in self.instance().import_initializers.iter() { if let Some(f) = func { + // transmute our function pointer into one with the correct error type + let f = std::mem::transmute::< + &fn( + *mut std::ffi::c_void, + *const std::ffi::c_void, + ) -> Result<(), *mut std::ffi::c_void>, + &fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), Err>, + >(f); dbg!(f, env); - f(*env, instance_ptr); + f(*env, instance_ptr)?; } } + Ok(()) } /// Deallocates memory associated with this instance. diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index b8f4105bd94..a5c9663445b 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -29,9 +29,7 @@ pub use crate::syscalls::types; pub use crate::utils::{get_wasi_version, is_wasi_module, WasiVersion}; use thiserror::Error; -use wasmer::{ - imports, Function, ImportObject, InitAfterInstance, Memory, Module, Store, WasmerEnv, -}; +use wasmer::{imports, Function, ImportObject, LazyInit, Memory, Module, Store, WasmerEnv}; use std::sync::{Arc, Mutex, MutexGuard}; @@ -50,14 +48,14 @@ pub enum WasiError { pub struct WasiEnv { state: Arc>, #[wasmer(export)] - memory: InitAfterInstance, + memory: LazyInit, } impl WasiEnv { pub fn new(state: WasiState) -> Self { Self { state: Arc::new(Mutex::new(state)), - memory: InitAfterInstance::new(), + memory: LazyInit::new(), } } diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index db43d2a9d3a..76289c8a815 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -97,7 +97,9 @@ fn dynamic_function_with_env() -> Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) {} + fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + Ok(()) + } fn free(&mut self) {} } @@ -229,7 +231,9 @@ fn static_function_with_env() -> Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) {} + fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + Ok(()) + } fn free(&mut self) {} } diff --git a/tests/compilers/native_functions.rs b/tests/compilers/native_functions.rs index ed2e623a265..ec372920c0a 100644 --- a/tests/compilers/native_functions.rs +++ b/tests/compilers/native_functions.rs @@ -116,7 +116,9 @@ fn static_host_function_with_env() -> anyhow::Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) {} + fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + Ok(()) + } fn free(&mut self) {} } @@ -195,7 +197,9 @@ fn dynamic_host_function_with_env() -> anyhow::Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) {} + fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + Ok(()) + } fn free(&mut self) {} } diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index e84d98a9aea..2f8a7bc2c7e 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -288,7 +288,9 @@ fn trap_start_function_import() -> Result<()> { .err() .unwrap(); match err { - InstantiationError::Link(_) => panic!("It should be a start error"), + InstantiationError::Link(_) | InstantiationError::HostEnvInitialization(_) => { + panic!("It should be a start error") + } InstantiationError::Start(err) => { assert_eq!(err.message(), "user trap"); } From 78f958b52ccad301f02d8faf879fe7e847ff5479 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 29 Oct 2020 13:07:04 -0700 Subject: [PATCH 17/39] Clean up misc code --- lib/api/src/exports.rs | 25 +++++-------------- lib/c-api/src/deprecated/import/mod.rs | 9 ++----- .../src/wasm_c_api/externals/function.rs | 4 ++- lib/cli/src/commands/run/wasi.rs | 2 -- lib/deprecated/runtime-core/Cargo.lock | 11 ++++++++ lib/deprecated/runtime-core/src/error.rs | 4 +-- lib/deprecated/runtime-core/src/typed_func.rs | 8 ++---- lib/deprecated/runtime-core/src/vm.rs | 9 ++----- lib/vm/src/instance.rs | 1 - tests/lib/wast/src/wasi_wast.rs | 2 -- 10 files changed, 28 insertions(+), 47 deletions(-) diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index 7f53591f4fe..b402143a763 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -296,31 +296,18 @@ pub trait Exportable<'a>: Sized { fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>; } -/// Hack to make macros work well +/// A trait for accessing exports (like [`Exportable`]) but it takes generic +/// `Args` and `Rets` parameters so that `NativeFunc` can be accessed directly +/// as well. pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized { - /// Get it with generics + /// Get an export with the given generics. fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result; - /*where - Args: WasmTypeList, - Rets: WasmTypeList;*/ } +/// We implement it for all concrete [`Exportable`] types (that are `Clone`) +/// with empty `Args` and `Rets`. impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T { fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result { T::get_self_from_extern(_extern).map(|i| i.clone()) } } - -/* -impl<'a, Args, Rets> ExportableWithGenerics<'a> for T { - fn get_self_from_extern_with_generics( - _extern: &'a Extern, - ) -> Result<&'a Self, ExportError> - where - Args: WasmTypeList, - Rets: WasmTypeList, - { - T::get_self_from_extern(_extern) - } -} -*/ diff --git a/lib/c-api/src/deprecated/import/mod.rs b/lib/c-api/src/deprecated/import/mod.rs index 1c3bf0bf442..5dd2cf7f571 100644 --- a/lib/c-api/src/deprecated/import/mod.rs +++ b/lib/c-api/src/deprecated/import/mod.rs @@ -21,7 +21,7 @@ use std::collections::HashMap; use wasmer::{ ChainableNamedResolver, Exports, Extern, Function, FunctionType, Global, ImportObject, ImportObjectIterator, ImportType, Memory, Module, NamedResolver, RuntimeError, Table, Val, - ValType, + ValType, WasmerEnv, }; #[repr(C)] @@ -634,16 +634,11 @@ pub unsafe extern "C" fn wasmer_import_func_params_arity( } /// struct used to pass in context to functions (which must be back-patched) -#[derive(Debug, Default)] +#[derive(Debug, Default, WasmerEnv)] pub(crate) struct LegacyEnv { pub(crate) instance_ptr: Option>, } -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 diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs index 93e14fb0eda..b694ceb3503 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -98,7 +98,9 @@ pub unsafe extern "C" fn wasm_func_new_with_env( struct WrapperEnv(*mut c_void); impl wasmer::WasmerEnv for WrapperEnv { - fn finish(&mut self, _instance: &wasmer::Instance) {} + fn finish(&mut self, _instance: &wasmer::Instance) -> Result<(), wasmer::HostEnvInitError> { + Ok(()) + } fn free(&mut self) {} } diff --git a/lib/cli/src/commands/run/wasi.rs b/lib/cli/src/commands/run/wasi.rs index d74dbd3f63a..8d9f7314708 100644 --- a/lib/cli/src/commands/run/wasi.rs +++ b/lib/cli/src/commands/run/wasi.rs @@ -58,8 +58,6 @@ impl Wasi { let import_object = wasi_env.import_object(&module)?; let instance = Instance::new(&module, &import_object)?; - //wasi_env.set_memory(instance.exports.get_memory("memory")?.clone()); - let start = instance.exports.get_function("_start")?; let result = start.call(&[]); diff --git a/lib/deprecated/runtime-core/Cargo.lock b/lib/deprecated/runtime-core/Cargo.lock index a49b103f64f..7fdc5e1a095 100644 --- a/lib/deprecated/runtime-core/Cargo.lock +++ b/lib/deprecated/runtime-core/Cargo.lock @@ -1120,6 +1120,7 @@ dependencies = [ "wasmer-compiler-cranelift", "wasmer-compiler-llvm", "wasmer-compiler-singlepass", + "wasmer-derive", "wasmer-engine", "wasmer-engine-jit", "wasmer-engine-native", @@ -1211,6 +1212,16 @@ dependencies = [ "wasmer-vm", ] +[[package]] +name = "wasmer-derive" +version = "1.0.0-alpha4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "wasmer-engine" version = "1.0.0-alpha4" diff --git a/lib/deprecated/runtime-core/src/error.rs b/lib/deprecated/runtime-core/src/error.rs index a8cba4efa9b..b90f65b946a 100644 --- a/lib/deprecated/runtime-core/src/error.rs +++ b/lib/deprecated/runtime-core/src/error.rs @@ -1,3 +1,3 @@ -pub use crate::new::wasmer::{ExportError, MemoryError}; +pub use crate::new::wasmer::{ExportError, InstantiationError, MemoryError}; pub use crate::new::wasmer_compiler::CompileError; -pub use crate::new::wasmer_engine::{InstantiationError, LinkError, RuntimeError}; +pub use crate::new::wasmer_engine::{LinkError, RuntimeError}; diff --git a/lib/deprecated/runtime-core/src/typed_func.rs b/lib/deprecated/runtime-core/src/typed_func.rs index c9b549f1093..b814b94c103 100644 --- a/lib/deprecated/runtime-core/src/typed_func.rs +++ b/lib/deprecated/runtime-core/src/typed_func.rs @@ -6,7 +6,7 @@ use crate::{ }; use std::marker::PhantomData; -pub use new::wasmer::{HostFunction, WasmTypeList}; +pub use new::wasmer::{HostFunction, WasmTypeList, WasmerEnv}; /// Represents a function that can be used by WebAssembly. #[derive(Clone)] @@ -232,15 +232,11 @@ use std::{ /// Initially, it holds an empty `vm::Ctx`, but it is replaced by the /// `vm::Ctx` from `instance::PreInstance` in /// `module::Module::instantiate`. +#[derive(WasmerEnv)] pub(crate) struct DynamicCtx { pub(crate) vmctx: Rc>, } -impl new::wasmer::WasmerEnv for DynamicCtx { - fn finish(&mut self, _instance: &new::wasmer::Instance) {} - fn free(&mut self) {} -} - impl DynamicFunc { /// Create a new `DynamicFunc`. pub fn new(signature: &FuncSig, func: F) -> Self diff --git a/lib/deprecated/runtime-core/src/vm.rs b/lib/deprecated/runtime-core/src/vm.rs index a07aecf6ea8..0f47e48589b 100644 --- a/lib/deprecated/runtime-core/src/vm.rs +++ b/lib/deprecated/runtime-core/src/vm.rs @@ -1,5 +1,5 @@ use crate::module::ModuleInfo; -use crate::new; +use crate::new::wasmer::WasmerEnv; use std::{ffi::c_void, ptr}; /// The context of the currently running WebAssembly instance. @@ -14,7 +14,7 @@ use std::{ffi::c_void, ptr}; /// it may someday be pinned to a register (especially /// on arm, which has a ton of registers) to reduce /// register shuffling. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, WasmerEnv)] #[repr(C)] pub struct Ctx { /// A pointer to the `ModuleInfo` of this instance. @@ -39,11 +39,6 @@ pub struct Ctx { pub data_finalizer: Option, } -impl new::wasmer::WasmerEnv for Ctx { - fn finish(&mut self, _instance: &new::wasmer::Instance) {} - fn free(&mut self) {} -} - impl Ctx { pub(crate) unsafe fn new_uninit() -> Self { Self { diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 53dfaa62808..3326741d005 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -1169,7 +1169,6 @@ impl InstanceHandle { ) -> Result<(), *mut std::ffi::c_void>, &fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), Err>, >(f); - dbg!(f, env); f(*env, instance_ptr)?; } } diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 866a68dabe8..800249e16d1 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -83,8 +83,6 @@ impl<'a> WasiTest<'a> { let (mut env, _tempdirs) = self.create_wasi_env()?; let imports = self.get_imports(store, &module, env.clone())?; let instance = Instance::new(&module, &imports)?; - let memory: &Memory = instance.exports.get("memory")?; - //env.set_memory(memory.clone()); let start = instance.exports.get_function("_start")?; // TODO: handle errors here when the error fix gets shipped From a25288a0aeee3e488a116bc517f0b73a2d62aa08 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 29 Oct 2020 15:09:24 -0700 Subject: [PATCH 18/39] Improve error messages on `WasmerEnv` macro, clean up code, add tests --- Cargo.lock | 165 ++++++++++++++++++ lib/api/src/lib.rs | 2 +- lib/derive/Cargo.toml | 1 + lib/derive/src/lib.rs | 54 +++--- lib/derive/src/parse.rs | 22 +-- lib/derive/tests/basic.rs | 5 +- .../tests/compile-fail/bad-attribute.rs | 11 ++ .../tests/compile-fail/bad-export-arg.rs | 17 ++ lib/derive/tests/compile-fail/no-lazy-init.rs | 11 ++ lib/derive/tests/compiletest.rs | 46 +++++ 10 files changed, 286 insertions(+), 48 deletions(-) create mode 100644 lib/derive/tests/compile-fail/bad-attribute.rs create mode 100644 lib/derive/tests/compile-fail/bad-export-arg.rs create mode 100644 lib/derive/tests/compile-fail/no-lazy-init.rs create mode 100644 lib/derive/tests/compiletest.rs diff --git a/Cargo.lock b/Cargo.lock index 7ea7499a025..fdd942ca8c5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -100,6 +100,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + [[package]] name = "bincode" version = "1.3.1" @@ -140,6 +146,17 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + [[package]] name = "blake3" version = "0.3.6" @@ -309,6 +326,27 @@ dependencies = [ "winapi", ] +[[package]] +name = "compiletest_rs" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" +dependencies = [ + "diff", + "filetime", + "getopts", + "libc", + "log", + "miow", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tester", + "winapi", +] + [[package]] name = "constant_time_eq" version = "0.1.5" @@ -552,6 +590,12 @@ dependencies = [ "syn", ] +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + [[package]] name = "digest" version = "0.9.0" @@ -561,6 +605,27 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "distance" version = "0.4.0" @@ -674,6 +739,18 @@ dependencies = [ "log", ] +[[package]] +name = "filetime" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "fnv" version = "1.0.7" @@ -706,6 +783,15 @@ dependencies = [ "version_check 0.9.2", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.1.15" @@ -1100,6 +1186,16 @@ dependencies = [ "autocfg 1.0.1", ] +[[package]] +name = "miow" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" +dependencies = [ + "socket2", + "winapi", +] + [[package]] name = "more-asserts" version = "0.2.1" @@ -1560,6 +1656,17 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_users" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + [[package]] name = "ref_thread_local" version = "0.0.0" @@ -1625,6 +1732,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "rust-argon2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + [[package]] name = "rustc-demangle" version = "0.1.16" @@ -1646,6 +1765,18 @@ dependencies = [ "semver", ] +[[package]] +name = "rustfix" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" +dependencies = [ + "anyhow", + "log", + "serde", + "serde_json", +] + [[package]] name = "ryu" version = "1.0.5" @@ -1794,6 +1925,18 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +[[package]] +name = "socket2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1873,6 +2016,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "term" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" +dependencies = [ + "dirs", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.0" @@ -1890,6 +2043,17 @@ dependencies = [ "target-lexicon", ] +[[package]] +name = "tester" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" +dependencies = [ + "getopts", + "libc", + "term", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -2315,6 +2479,7 @@ dependencies = [ name = "wasmer-derive" version = "1.0.0-alpha4" dependencies = [ + "compiletest_rs", "proc-macro-error", "proc-macro2", "quote", diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 854b91c7918..52e8081505b 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -160,7 +160,7 @@ impl From for HostEnvInitError { /// #[derive(WasmerEnv)] /// pub struct MyEnvWithInstanceData { /// non_instance_data: u8, -/// #[wasmer(export("memory"))] +/// #[wasmer(export)] /// memory: LazyInit, /// } /// diff --git a/lib/derive/Cargo.toml b/lib/derive/Cargo.toml index 28fa35ac953..d2c0e74fd7b 100644 --- a/lib/derive/Cargo.toml +++ b/lib/derive/Cargo.toml @@ -18,3 +18,4 @@ proc-macro-error = "1.0.0" [dev-dependencies] wasmer = { path = "../api", version = "1.0.0-alpha4" } +compiletest_rs = "0.5" diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index cce734db534..cbc267a6122 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -1,16 +1,16 @@ extern crate proc_macro; -use proc_macro2::{Span, TokenStream}; -use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy}; +use proc_macro2::{TokenStream}; +use proc_macro_error::{abort, proc_macro_error, set_dummy}; use quote::{quote, quote_spanned, ToTokens}; -use syn::{spanned::Spanned, token::Comma, *}; +use syn::{spanned::Spanned, *}; mod parse; use crate::parse::WasmerAttr; -#[proc_macro_derive(WasmerEnv, attributes(wasmer))] #[proc_macro_error] +#[proc_macro_derive(WasmerEnv, attributes(wasmer))] pub fn derive_wasmer_env(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input: DeriveInput = syn::parse(input).unwrap(); let gen = impl_wasmer_env(&input); @@ -43,7 +43,8 @@ fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { set_dummy(quote! { impl ::wasmer::WasmerEnv for #struct_name { - fn finish(&mut self, instance: &::wasmer::Instance) { + fn finish(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> { + Ok(()) } fn free(&mut self) { } @@ -78,15 +79,21 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { let name = f.ident.as_ref().unwrap(); let name_str = name.to_string(); let top_level_ty: &Type = &f.ty; - //dbg!(top_level_ty); touched_fields.push(name.clone()); let mut wasmer_attr = None; for attr in &f.attrs { // if / filter - let tokens = attr.tokens.clone(); - if let Ok(attr) = syn::parse2(tokens) { - wasmer_attr = Some(attr); - break; + if attr.path.is_ident(&Ident::new("wasmer", attr.span())) { + let tokens = attr.tokens.clone(); + match syn::parse2(tokens) { + Ok(attr) => { + wasmer_attr = Some(attr); + break; + } + Err(e) => { + abort!(attr, "Failed to parse `wasmer` attribute: {}", e); + } + } } } @@ -104,18 +111,6 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { WasmerAttr::Export { identifier, .. } => { let item_name = identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span())); - /*match ty { - ExportAttr::NativeFunc {} => { - let finish_tokens = quote_spanned! {f.span()=> - let #name: #inner_type = instance.exports.get_native_function(#item_name).unwrap(); - self.#name.initialize(#name); - }; - finish.push(finish_tokens); - let free_tokens = quote_spanned! {f.span()=> - }; - free.push(free_tokens); - } - ExportAttr::EverythingElse {} => {*/ let finish_tokens = quote_spanned! {f.span()=> let #name: #inner_type = instance.exports.get_with_generics(#item_name)?; self.#name.initialize(#name); @@ -124,14 +119,12 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { let free_tokens = quote_spanned! {f.span()=> }; free.push(free_tokens); - //} - //} } } } } } - _ => todo!(), + _ => abort!(data.fields, "Only named fields are supported by `WasmerEnv` right now"), } let trait_methods = quote! { @@ -164,8 +157,7 @@ fn get_identifier(ty: &Type) -> TokenStream { if let Some(PathSegment { ident, arguments }) = segments.last() { let ident_str = ident.to_string(); if ident != "LazyInit" { - // TODO: - panic!("Only the `LazyInit` type is supported right now"); + abort!(ident, "WasmerEnv derive expects all `exports` to be wrapped in `LazyInit`"); } if let PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. @@ -183,15 +175,15 @@ fn get_identifier(ty: &Type) -> TokenStream { .expect("there must be at least one segment; TODO: error handling") .to_token_stream() } else { - panic!("unrecognized type in first generic position on `LazyInit`"); + abort!(&args[0], "unrecognized type in first generic position on `LazyInit`"); } } else { - panic!("Expected a generic parameter on `LazyInit`"); + abort!(arguments, "Expected a generic parameter on `LazyInit`"); } } else { - panic!("Wrong type of type found"); + abort!(segments, "Unknown type found"); } } - _ => todo!("Unrecognized/unsupported type"), + _ => abort!(ty, "Unrecognized/unsupported type"), } } diff --git a/lib/derive/src/parse.rs b/lib/derive/src/parse.rs index 35be70ff285..a324c2cb02c 100644 --- a/lib/derive/src/parse.rs +++ b/lib/derive/src/parse.rs @@ -1,9 +1,8 @@ -use proc_macro2::Span; -use proc_macro_error::{abort, ResultExt}; +use proc_macro_error::abort; use syn::{ parenthesized, parse::{Parse, ParseStream}, - token, Expr, Ident, LitStr, Token, + token, Ident, LitStr, Token, }; pub enum WasmerAttr { @@ -26,15 +25,14 @@ impl Parse for ExportOptions { let ident = input.parse::()?; let _ = input.parse::()?; let ident_str = ident.to_string(); - let mut name = None; + let name; match ident_str.as_str() { "name" => { name = Some(input.parse::()?); } - _ => { - // TODO: better handle errors here - panic!("Unrecognized argument in export options"); + otherwise => { + abort!(ident, "Unrecognized argument in export options: expected `name` found `{}`", otherwise); } } @@ -42,12 +40,6 @@ impl Parse for ExportOptions { } } -// parsing either: -// Inner | NativeFunc -// -// Inner: -// - Nothing -// - `name = "name"` impl Parse for ExportExpr { fn parse(input: ParseStream<'_>) -> syn::Result { let name; @@ -82,7 +74,9 @@ impl Parse for WasmerAttrInner { WasmerAttr::Export { identifier: name } } - _ => return Err(input.error(format!("Unexpected identifier {}", ident_str))), + otherwise => { + abort!(ident, "Unexpected identifier `{}`. Expected `export`.", otherwise) + } }; Ok(WasmerAttrInner(out)) } diff --git a/lib/derive/tests/basic.rs b/lib/derive/tests/basic.rs index 267545d9b65..e9fc8b95dbc 100644 --- a/lib/derive/tests/basic.rs +++ b/lib/derive/tests/basic.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use wasmer::{Function, Global, LazyInit, Memory, NativeFunc, Table, WasmerEnv}; #[derive(WasmerEnv)] @@ -62,9 +64,8 @@ struct MyEnvWithLifetime<'a> { #[test] fn test_derive_with_attribute() { - //use wasmer::WasmerEnv; assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); -} +} \ No newline at end of file diff --git a/lib/derive/tests/compile-fail/bad-attribute.rs b/lib/derive/tests/compile-fail/bad-attribute.rs new file mode 100644 index 00000000000..9da62cbac08 --- /dev/null +++ b/lib/derive/tests/compile-fail/bad-attribute.rs @@ -0,0 +1,11 @@ +extern crate wasmer; + +use wasmer::{LazyInit, WasmerEnv, Memory}; + +#[derive(WasmerEnv)] +struct BadAttribute { + #[wasmer(extraport)] //~ Unexpected identifier `extraport`. Expected `export`. + memory: LazyInit, +} + +fn main() {} \ No newline at end of file diff --git a/lib/derive/tests/compile-fail/bad-export-arg.rs b/lib/derive/tests/compile-fail/bad-export-arg.rs new file mode 100644 index 00000000000..1e133dfb91b --- /dev/null +++ b/lib/derive/tests/compile-fail/bad-export-arg.rs @@ -0,0 +1,17 @@ +extern crate wasmer; + +use wasmer::{LazyInit, WasmerEnv, Memory}; + +#[derive(WasmerEnv)] +struct BadExportArg { + #[wasmer(export(this_is_not_a_real_argument="hello, world"))] //~ Unrecognized argument in export options: expected `name` found `this_is_not_a_real_argument + memory: LazyInit, +} + +#[derive(WasmerEnv)] +struct BadExportArgRawString { + #[wasmer(export("hello"))] //~ Failed to parse `wasmer` attribute: unexpected token + memory: LazyInit, +} + +fn main() {} \ No newline at end of file diff --git a/lib/derive/tests/compile-fail/no-lazy-init.rs b/lib/derive/tests/compile-fail/no-lazy-init.rs new file mode 100644 index 00000000000..fba410bb71f --- /dev/null +++ b/lib/derive/tests/compile-fail/no-lazy-init.rs @@ -0,0 +1,11 @@ +extern crate wasmer; + +use wasmer::{LazyInit, WasmerEnv, Memory}; + +#[derive(WasmerEnv)] +struct ExportNotWrappedInLazyInit { + #[wasmer(export)] //~ WasmerEnv derive expects all `exports` to be wrapped in `LazyInit` + memory: Memory, +} + +fn main() {} \ No newline at end of file diff --git a/lib/derive/tests/compiletest.rs b/lib/derive/tests/compiletest.rs new file mode 100644 index 00000000000..8f66078ac0e --- /dev/null +++ b/lib/derive/tests/compiletest.rs @@ -0,0 +1,46 @@ +// file is a modified version of https://github.com/AltSysrq/proptest/blob/proptest-derive/proptest-derive/tests/compiletest.rs + +// Original copyright and license: +// Copyright 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Modifications copyright 2020 Wasmer +// Licensed under the MIT license + +extern crate compiletest_rs as ct; + +use std::env; + +fn run_mode(src: &'static str, mode: &'static str) { + let mut config = ct::Config::default(); + + config.mode = mode.parse().expect("invalid mode"); + config.target_rustcflags = Some("-L ../../target/debug/deps".to_owned()); + if let Ok(name) = env::var("TESTNAME") { + config.filter = Some(name); + } + config.src_base = format!("tests/{}", src).into(); + + // hack to make this work on OSX: we probably don't need it though + /*if std::env::var("DYLD_LIBRARY_PATH").is_err() { + let val = std::env::var("DYLD_FALLBACK_LIBRARY_PATH").unwrap(); + std::env::set_var("DYLD_LIBRARY_PATH", val); + } + config.link_deps();*/ + + // Uncomment this if you have the "multiple crates named `wasmer` issue". Massively slows + // down test iteration though... + //config.clean_rmeta(); + + ct::run_tests(&config); +} + +#[test] +fn compile_test() { + run_mode("compile-fail", "compile-fail"); +} \ No newline at end of file From 52191a0e9a882f3e97f9ad8ef4ff70541faf2e89 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 29 Oct 2020 15:16:41 -0700 Subject: [PATCH 19/39] Clean up and fix test --- lib/derive/src/lib.rs | 17 +++++++++++++---- lib/derive/src/parse.rs | 14 ++++++++++---- lib/derive/tests/basic.rs | 2 +- lib/derive/tests/compile-fail/no-lazy-init.rs | 4 ++-- lib/derive/tests/compiletest.rs | 8 +++++--- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index cbc267a6122..ec0e788547b 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -1,6 +1,6 @@ extern crate proc_macro; -use proc_macro2::{TokenStream}; +use proc_macro2::TokenStream; use proc_macro_error::{abort, proc_macro_error, set_dummy}; use quote::{quote, quote_spanned, ToTokens}; use syn::{spanned::Spanned, *}; @@ -124,7 +124,10 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { } } } - _ => abort!(data.fields, "Only named fields are supported by `WasmerEnv` right now"), + _ => abort!( + data.fields, + "Only named fields are supported by `WasmerEnv` right now" + ), } let trait_methods = quote! { @@ -157,7 +160,10 @@ fn get_identifier(ty: &Type) -> TokenStream { if let Some(PathSegment { ident, arguments }) = segments.last() { let ident_str = ident.to_string(); if ident != "LazyInit" { - abort!(ident, "WasmerEnv derive expects all `exports` to be wrapped in `LazyInit`"); + abort!( + ident, + "WasmerEnv derive expects all `exports` to be wrapped in `LazyInit`" + ); } if let PathArguments::AngleBracketed(AngleBracketedGenericArguments { args, .. @@ -175,7 +181,10 @@ fn get_identifier(ty: &Type) -> TokenStream { .expect("there must be at least one segment; TODO: error handling") .to_token_stream() } else { - abort!(&args[0], "unrecognized type in first generic position on `LazyInit`"); + abort!( + &args[0], + "unrecognized type in first generic position on `LazyInit`" + ); } } else { abort!(arguments, "Expected a generic parameter on `LazyInit`"); diff --git a/lib/derive/src/parse.rs b/lib/derive/src/parse.rs index a324c2cb02c..20208e8261d 100644 --- a/lib/derive/src/parse.rs +++ b/lib/derive/src/parse.rs @@ -32,7 +32,11 @@ impl Parse for ExportOptions { name = Some(input.parse::()?); } otherwise => { - abort!(ident, "Unrecognized argument in export options: expected `name` found `{}`", otherwise); + abort!( + ident, + "Unrecognized argument in export options: expected `name` found `{}`", + otherwise + ); } } @@ -74,9 +78,11 @@ impl Parse for WasmerAttrInner { WasmerAttr::Export { identifier: name } } - otherwise => { - abort!(ident, "Unexpected identifier `{}`. Expected `export`.", otherwise) - } + otherwise => abort!( + ident, + "Unexpected identifier `{}`. Expected `export`.", + otherwise + ), }; Ok(WasmerAttrInner(out)) } diff --git a/lib/derive/tests/basic.rs b/lib/derive/tests/basic.rs index e9fc8b95dbc..ae89d47cadb 100644 --- a/lib/derive/tests/basic.rs +++ b/lib/derive/tests/basic.rs @@ -68,4 +68,4 @@ fn test_derive_with_attribute() { assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); -} \ No newline at end of file +} diff --git a/lib/derive/tests/compile-fail/no-lazy-init.rs b/lib/derive/tests/compile-fail/no-lazy-init.rs index fba410bb71f..56ba024e286 100644 --- a/lib/derive/tests/compile-fail/no-lazy-init.rs +++ b/lib/derive/tests/compile-fail/no-lazy-init.rs @@ -4,8 +4,8 @@ use wasmer::{LazyInit, WasmerEnv, Memory}; #[derive(WasmerEnv)] struct ExportNotWrappedInLazyInit { - #[wasmer(export)] //~ WasmerEnv derive expects all `exports` to be wrapped in `LazyInit` - memory: Memory, + #[wasmer(export)] + memory: Memory, //~ WasmerEnv derive expects all `exports` to be wrapped in `LazyInit` } fn main() {} \ No newline at end of file diff --git a/lib/derive/tests/compiletest.rs b/lib/derive/tests/compiletest.rs index 8f66078ac0e..3bebac1aa6d 100644 --- a/lib/derive/tests/compiletest.rs +++ b/lib/derive/tests/compiletest.rs @@ -1,4 +1,4 @@ -// file is a modified version of https://github.com/AltSysrq/proptest/blob/proptest-derive/proptest-derive/tests/compiletest.rs +// file is a modified version of https://github.com/AltSysrq/proptest/blob/proptest-derive/proptest-derive/tests/compiletest.rs // Original copyright and license: // Copyright 2018 The proptest developers @@ -35,12 +35,14 @@ fn run_mode(src: &'static str, mode: &'static str) { // Uncomment this if you have the "multiple crates named `wasmer` issue". Massively slows // down test iteration though... - //config.clean_rmeta(); + config.clean_rmeta(); ct::run_tests(&config); } #[test] +#[ignore] // ignored by default because it needs to essentially run `cargo clean` to work correctly + // and that's really, really slow fn compile_test() { run_mode("compile-fail", "compile-fail"); -} \ No newline at end of file +} From 1c9fc1f0d4137c2c10abd171c013e0adc0090ae8 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Thu, 29 Oct 2020 15:45:23 -0700 Subject: [PATCH 20/39] Fix up doc tests in api --- lib/api/src/externals/function.rs | 16 ++++------------ lib/api/src/lib.rs | 10 ++++++---- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 65e944e6ecc..9dcbf6f865d 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -107,16 +107,13 @@ impl Function { /// # Example /// /// ``` - /// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv, Instance}; + /// # use wasmer::{Function, FunctionType, Type, Store, Value, WasmerEnv}; /// # let store = Store::default(); /// # + /// #[derive(WasmerEnv)] /// 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]); @@ -146,7 +143,6 @@ impl Function { let function_ptr = Some(unsafe { std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish) }); - //dbg!(function_ptr); Self { store: store.clone(), @@ -215,16 +211,13 @@ impl Function { /// # Example /// /// ``` - /// # use wasmer::{Store, Function, WasmerEnv, Instance}; + /// # use wasmer::{Store, Function, WasmerEnv}; /// # let store = Store::default(); /// # + /// #[derive(WasmerEnv)] /// 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 { @@ -254,7 +247,6 @@ impl Function { let function_ptr = Some(unsafe { std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish) }); - //dbg!(function_ptr as usize); let signature = function.ty(); Self { diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 52e8081505b..7bf193bcf7a 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -150,7 +150,7 @@ impl From for HostEnvInitError { /// This trait can be derived like so: /// /// ``` -/// # use wasmer::{WasmerEnv, LazyInit, Memory}; +/// # use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc}; /// /// #[derive(WasmerEnv)] /// pub struct MyEnvWithNoInstanceData { @@ -162,21 +162,24 @@ impl From for HostEnvInitError { /// non_instance_data: u8, /// #[wasmer(export)] /// memory: LazyInit, +/// #[wasmer(export(name = "real_name"))] +/// func: LazyInit>, /// } /// /// ``` /// /// This trait can also be implemented manually: /// ``` -/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance}; +/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError}; /// pub struct MyEnv { /// memory: LazyInit, /// } /// /// impl WasmerEnv for MyEnv { -/// fn finish(&mut self, instance: &Instance) { +/// fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { /// let memory = instance.exports.get_memory("memory").unwrap(); /// self.memory.initialize(memory.clone()); +/// Ok(()) /// } /// fn free(&mut self) {} /// } @@ -203,7 +206,6 @@ impl WasmerEnv for &'static mut T { } } -// TODO: iterate on names // TODO: do we want to use mutex/atomics here? like old WASI solution /// Lazily init an item pub struct LazyInit { From a19705ae11c3fdd318785c0488cce68b85d0a414 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 16 Nov 2020 16:36:58 -0800 Subject: [PATCH 21/39] Remove free method, call finalizers in C API --- Cargo.lock | 33 ++++++++++++------- examples/imports_function_env.rs | 6 ++-- lib/api/src/lib.rs | 8 ----- .../src/wasm_c_api/externals/function.rs | 29 ++++++++++++---- lib/c-api/src/wasm_c_api/instance.rs | 6 ++++ lib/derive/Cargo.toml | 2 +- lib/derive/src/lib.rs | 14 -------- lib/engine/src/artifact.rs | 2 +- lib/vm/src/instance.rs | 7 ++-- tests/compilers/imports.rs | 2 -- tests/compilers/native_functions.rs | 2 -- tests/lib/wast/src/wasi_wast.rs | 4 +-- 12 files changed, 61 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a224f657a66..13a4d86d7fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -378,7 +378,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c478836e029dcef17fb47c89023448c64f781a046e0300e257ad8225ae59afab" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -505,7 +504,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils", + "crossbeam-utils 0.8.0", ] [[package]] @@ -516,7 +515,7 @@ checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" dependencies = [ "cfg-if 1.0.0", "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-utils 0.8.0", ] [[package]] @@ -527,12 +526,23 @@ checksum = "ec0f606a85340376eef0d6d8fec399e6d4a544d648386c6645eb6d0653b27d9f" dependencies = [ "cfg-if 1.0.0", "const_fn", - "crossbeam-utils", + "crossbeam-utils 0.8.0", "lazy_static", "memoffset", "scopeguard", ] +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if 0.1.10", + "lazy_static", +] + [[package]] name = "crossbeam-utils" version = "0.8.0" @@ -649,7 +659,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "dirs-sys", ] @@ -780,10 +790,11 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi", +] [[package]] name = "float-cmp" @@ -1767,7 +1778,7 @@ checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" dependencies = [ "crossbeam-channel", "crossbeam-deque", - "crossbeam-utils", + "crossbeam-utils 0.8.0", "lazy_static", "num_cpus", ] @@ -1793,7 +1804,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom", + "getrandom 0.1.15", "redox_syscall", "rust-argon2", ] @@ -1872,7 +1883,7 @@ dependencies = [ "base64", "blake2b_simd", "constant_time_eq", - "crossbeam-utils", + "crossbeam-utils 0.7.2", ] [[package]] @@ -2083,7 +2094,7 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi", @@ -2653,7 +2664,7 @@ dependencies = [ [[package]] name = "wasmer-derive" -version = "1.0.0-alpha4" +version = "1.0.0-alpha5" dependencies = [ "compiletest_rs", "proc-macro-error", diff --git a/examples/imports_function_env.rs b/examples/imports_function_env.rs index 88caf3c6ef7..88778dba467 100644 --- a/examples/imports_function_env.rs +++ b/examples/imports_function_env.rs @@ -21,7 +21,7 @@ use std::cell::RefCell; use std::sync::Arc; -use wasmer::{imports, wat2wasm, Function, Instance, Module, Store}; +use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, WasmerEnv}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_jit::JIT; @@ -68,7 +68,9 @@ fn main() -> Result<(), Box> { // // This struct may have been anything. The only constraint is it must be // possible to know the size of the `Env` at compile time (i.e it has to - // implement the `Sized` trait). + // implement the `Sized` trait) and that it implement the `WasmerEnv` trait. + // We derive a default implementation of `WasmerEnv` here. + #[derive(WasmerEnv)] struct Env { counter: Arc>, } diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 9d7cc828f47..9877c4da97c 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -191,7 +191,6 @@ impl From for HostEnvInitError { /// self.memory.initialize(memory.clone()); /// Ok(()) /// } -/// fn free(&mut self) {} /// } /// ``` pub trait WasmerEnv { @@ -201,19 +200,12 @@ pub trait WasmerEnv { /// This function is called after `Instance` is created but before it is /// returned to the user via `Instance::new`. fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError>; - - /// Frees memory written to `self` so it can be dropped without any memory leaks. - // TODO: review, this is unused by the macro currently, do we want to do anything with this? - fn free(&mut self); } impl WasmerEnv for &'static mut T { fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { (*self).finish(instance) } - fn free(&mut self) { - (*self).free() - } } // TODO: do we want to use mutex/atomics here? like old WASI solution diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs index fe6f58b41fe..feea15ababd 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -29,7 +29,7 @@ pub type wasm_func_callback_with_env_t = unsafe extern "C" fn( ) -> *mut wasm_trap_t; #[allow(non_camel_case_types)] -pub type wasm_env_finalizer_t = unsafe extern "C" fn(c_void); +pub type wasm_env_finalizer_t = unsafe extern "C" fn(*mut c_void); #[no_mangle] pub unsafe extern "C" fn wasm_func_new( @@ -92,7 +92,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( function_type: Option<&wasm_functype_t>, callback: Option, env: *mut c_void, - finalizer: wasm_env_finalizer_t, + finalizer: Option, ) -> Option> { let store = store?; let function_type = function_type?; @@ -101,14 +101,24 @@ pub unsafe extern "C" fn wasm_func_new_with_env( let func_sig = &function_type.inner().function_type; let num_rets = func_sig.results().len(); - #[repr(transparent)] - struct WrapperEnv(*mut c_void); + #[repr(C)] + struct WrapperEnv { + env: *mut c_void, + finalizer: Option, + }; + + impl Drop for WrapperEnv { + fn drop(&mut self) { + if let Some(finalizer) = self.finalizer { + unsafe { (finalizer)(self.env as _) } + } + } + } impl wasmer::WasmerEnv for WrapperEnv { fn finish(&mut self, _instance: &wasmer::Instance) -> Result<(), wasmer::HostEnvInitError> { Ok(()) } - fn free(&mut self) {} } let inner_callback = @@ -129,7 +139,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( ] .into(); - let trap = callback(env.0, &processed_args, &mut results); + let trap = callback(env.env, &processed_args, &mut results); if !trap.is_null() { let trap: Box = Box::from_raw(trap); @@ -148,7 +158,12 @@ pub unsafe extern "C" fn wasm_func_new_with_env( Ok(processed_results) }; - let function = Function::new_with_env(&store.inner, &func_sig, WrapperEnv(env), inner_callback); + let function = Function::new_with_env( + &store.inner, + &func_sig, + WrapperEnv { env, finalizer }, + inner_callback, + ); Some(Box::new(wasm_func_t { instance: None, diff --git a/lib/c-api/src/wasm_c_api/instance.rs b/lib/c-api/src/wasm_c_api/instance.rs index 84437b04f13..d15b658c735 100644 --- a/lib/c-api/src/wasm_c_api/instance.rs +++ b/lib/c-api/src/wasm_c_api/instance.rs @@ -49,6 +49,12 @@ pub unsafe extern "C" fn wasm_instance_new( return None; } + + Err(InstantiationError::HostEnvInitialization(error)) => { + crate::error::update_last_error(error); + + return None; + } }; Some(Box::new(wasm_instance_t { inner: instance })) diff --git a/lib/derive/Cargo.toml b/lib/derive/Cargo.toml index d2c0e74fd7b..c0a03f55291 100644 --- a/lib/derive/Cargo.toml +++ b/lib/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "wasmer-derive" -version = "1.0.0-alpha4" +version = "1.0.0-alpha5" description = "Wasmer derive macros" authors = ["Wasmer Engineering Team "] repository = "https://github.com/wasmerio/wasmer" diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index ec0e788547b..0f9329e535c 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -38,7 +38,6 @@ fn impl_wasmer_env_for_struct( } fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { - use syn::Data::*; let struct_name = &input.ident; set_dummy(quote! { @@ -46,8 +45,6 @@ fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { fn finish(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> { Ok(()) } - fn free(&mut self) { - } } }); @@ -69,7 +66,6 @@ fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { let mut finish = vec![]; - let mut free = vec![]; let mut helpers = vec![]; //let mut assign_tokens = vec![]; let mut touched_fields = vec![]; @@ -116,9 +112,6 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { self.#name.initialize(#name); }; finish.push(finish_tokens); - let free_tokens = quote_spanned! {f.span()=> - }; - free.push(free_tokens); } } } @@ -135,12 +128,6 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { #(#finish)* Ok(()) } - - fn free(&mut self) { - unsafe { - #(#free)* - } - } }; let helper_methods = quote! { @@ -158,7 +145,6 @@ fn get_identifier(ty: &Type) -> TokenStream { .. }) => { if let Some(PathSegment { ident, arguments }) = segments.last() { - let ident_str = ident.to_string(); if ident != "LazyInit" { abort!( ident, diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index acb63447366..40bca8abc99 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -113,7 +113,7 @@ pub trait Artifact: Send + Sync + Upcastable { .cloned() .zip(imports.functions.values()) { - let host_env = func.vmctx as _; + let host_env = func.environment.host_env; thunks.push((func_init, host_env)); } // ------------ diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 28b55f9f038..ddfb8804fdb 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -327,13 +327,12 @@ impl Instance { VMFunctionEnvironment { vmctx: self.vmctx_ptr(), }, - self.vmctx_ptr(), None, ) } else { let import = self.imported_function(*index); let initializer = self.imported_function_env_initializer(*index); - (import.body, import.vmctx, initializer) + (import.body, import.environment, initializer) }; let call_trampoline = Some(self.function_call_trampolines[*sig_index]); let signature = self.module.signatures[*sig_index].clone(); @@ -405,7 +404,7 @@ impl Instance { None => return Ok(()), }; - let (callee_address, callee_extra_data) = match self.module.local_func_index(start_index) { + let (callee_address, callee_vmctx) = match self.module.local_func_index(start_index) { Some(local_index) => { let body = self .functions @@ -431,7 +430,7 @@ impl Instance { catch_traps(callee_vmctx, || { mem::transmute::<*const VMFunctionBody, unsafe extern "C" fn(VMFunctionEnvironment)>( callee_address, - )(callee_extra_data) + )(callee_vmctx) }) } } diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index 76289c8a815..0aee4c15258 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -100,7 +100,6 @@ fn dynamic_function_with_env() -> Result<()> { fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } - fn free(&mut self) {} } let env: Env = Env(Arc::new(AtomicUsize::new(0))); @@ -234,7 +233,6 @@ fn static_function_with_env() -> Result<()> { fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } - fn free(&mut self) {} } let env: Env = Env(Arc::new(AtomicUsize::new(0))); diff --git a/tests/compilers/native_functions.rs b/tests/compilers/native_functions.rs index ec372920c0a..56d419516f0 100644 --- a/tests/compilers/native_functions.rs +++ b/tests/compilers/native_functions.rs @@ -119,7 +119,6 @@ fn static_host_function_with_env() -> anyhow::Result<()> { fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } - fn free(&mut self) {} } // Native static host function that returns a tuple. @@ -200,7 +199,6 @@ fn dynamic_host_function_with_env() -> anyhow::Result<()> { fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } - fn free(&mut self) {} } let env = Env(Rc::new(RefCell::new(100))); diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 800249e16d1..adfd91c0dad 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use std::fs::File; use std::io::{self, Read, Seek, Write}; use std::path::PathBuf; -use wasmer::{ImportObject, Instance, Memory, Module, Store}; +use wasmer::{ImportObject, Instance, Module, Store}; use wasmer_wasi::types::{__wasi_filesize_t, __wasi_timestamp_t}; use wasmer_wasi::{ generate_import_object_from_env, get_wasi_version, WasiEnv, WasiFile, WasiFsError, WasiState, @@ -80,7 +80,7 @@ impl<'a> WasiTest<'a> { out }; let module = Module::new(&store, &wasm_bytes)?; - let (mut env, _tempdirs) = self.create_wasi_env()?; + let (env, _tempdirs) = self.create_wasi_env()?; let imports = self.get_imports(store, &module, env.clone())?; let instance = Instance::new(&module, &imports)?; From 75707106d9ebec56503711b67129ae76d488ffbb Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 16 Nov 2020 17:04:08 -0800 Subject: [PATCH 22/39] Add test initializing and calling host function manually --- lib/api/tests/externals.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index d7dd0cca105..b3a67bfd1a3 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -377,3 +377,33 @@ fn function_outlives_instance() -> Result<()> { Ok(()) } + +#[test] +fn manually_call_function() -> Result<()> { + let store = Store::default(); + #[derive(WasmerEnv)] + struct MyEnv { + val: u32, + memory: LazyInit, + } + + fn host_function(env: &mut MyEnv, arg1: u32, arg2: u32) -> u32 { + env.val + arg1 + arg2 + } + + let mut env = MyEnv { + val: 5, + memory: LazyInit::new(), + }; + + let result = host_function(&mut env, 7, 9); + assert_eq!(result, 21); + + let memory = Memory::new(&store, MemoryType::new(0, None, false))?; + env.memory.initialize(memory); + + let result = host_function(&mut env, 1, 2); + assert_eq!(result, 8); + + Ok(()) +} From 655ac093a2db3e563a4a7ec0ef9b867ee1767495 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 17 Nov 2020 11:19:42 -0800 Subject: [PATCH 23/39] Fix up helpers generated by WasmerEnv; add `unchecked` variant --- lib/api/tests/externals.rs | 2 +- lib/c-api/wasmer_wasm.h | 3 --- lib/derive/src/lib.rs | 18 ++++++++++++++++-- lib/wasi/src/lib.rs | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/api/tests/externals.rs b/lib/api/tests/externals.rs index b3a67bfd1a3..5addf44e4db 100644 --- a/lib/api/tests/externals.rs +++ b/lib/api/tests/externals.rs @@ -379,7 +379,7 @@ fn function_outlives_instance() -> Result<()> { } #[test] -fn manually_call_function() -> Result<()> { +fn manually_generate_wasmer_env() -> Result<()> { let store = Store::default(); #[derive(WasmerEnv)] struct MyEnv { diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 4bc65f62d46..44323f020d4 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -29,9 +29,6 @@ # define DEPRECATED(message) __declspec(deprecated(message)) #endif -// The `jit` feature has been enabled for this build. -#define WASMER_JIT_ENABLED - // The `compiler` feature has been enabled for this build. #define WASMER_COMPILER_ENABLED diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 0f9329e535c..f0e59bf3f77 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -97,9 +97,23 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { let inner_type = get_identifier(top_level_ty); let name_ref_str = format!("{}_ref", name); let name_ref = syn::Ident::new(&name_ref_str, name.span()); + let name_ref_unchecked_str = format!("{}_ref_unchecked", name); + let name_ref_unchecked = syn::Ident::new(&name_ref_unchecked_str, name.span()); let helper_tokens = quote_spanned! {f.span()=> - pub fn #name_ref(&self) -> &#inner_type { - unsafe { self.#name.get_unchecked() } + /// Get access to the underlying data. + /// + /// If `WasmerEnv::finish` has been called, this function will never + /// return `None` unless the underlying data has been mutated manually. + pub fn #name_ref(&self) -> Option<&#inner_type> { + self.#name.get_ref() + } + /// Gets the item without checking if it's been initialized. + /// + /// # Safety + /// `WasmerEnv::finish` must have been called on this function or + /// this type manually initialized. + pub unsafe fn #name_ref_unchecked(&self) -> &#inner_type { + self.#name.get_unchecked() } }; helpers.push(helper_tokens); diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index a5c9663445b..282a09a6ecd 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -80,7 +80,7 @@ impl WasiEnv { /// Get a reference to the memory pub fn memory(&self) -> &Memory { - self.memory_ref() + self.memory_ref().unwrap() } pub(crate) fn get_memory_and_wasi_state( From 619afb5b10c5dbf74d136f472a05155dacb973d3 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 17 Nov 2020 11:56:09 -0800 Subject: [PATCH 24/39] Add support for tuple structs and unit structs in derive(WasmerEnv) --- lib/derive/src/lib.rs | 130 +++++++++++++++++++++----------------- lib/derive/src/parse.rs | 8 ++- lib/derive/tests/basic.rs | 16 +++++ 3 files changed, 96 insertions(+), 58 deletions(-) diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index f0e59bf3f77..f8f88eff7d1 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -69,72 +69,88 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { let mut helpers = vec![]; //let mut assign_tokens = vec![]; let mut touched_fields = vec![]; - match data.fields { - Fields::Named(ref fields) => { - for f in fields.named.iter() { - let name = f.ident.as_ref().unwrap(); - let name_str = name.to_string(); - let top_level_ty: &Type = &f.ty; - touched_fields.push(name.clone()); - let mut wasmer_attr = None; - for attr in &f.attrs { - // if / filter - if attr.path.is_ident(&Ident::new("wasmer", attr.span())) { - let tokens = attr.tokens.clone(); - match syn::parse2(tokens) { - Ok(attr) => { - wasmer_attr = Some(attr); - break; - } - Err(e) => { - abort!(attr, "Failed to parse `wasmer` attribute: {}", e); - } - } + let fields: Vec = match &data.fields { + Fields::Named(ref fields) => fields.named.iter().cloned().collect(), + Fields::Unit => vec![], + Fields::Unnamed(fields) => fields.unnamed.iter().cloned().collect(), + }; + for (field_num, f) in fields.into_iter().enumerate() { + let name = f.ident.clone(); + let top_level_ty: &Type = &f.ty; + touched_fields.push(name.clone()); + let mut wasmer_attr = None; + for attr in &f.attrs { + // if / filter + if attr.path.is_ident(&Ident::new("wasmer", attr.span())) { + let tokens = attr.tokens.clone(); + match syn::parse2(tokens) { + Ok(attr) => { + wasmer_attr = Some(attr); + break; + } + Err(e) => { + abort!(attr, "Failed to parse `wasmer` attribute: {}", e); } } + } + } - if let Some(wasmer_attr) = wasmer_attr { - let inner_type = get_identifier(top_level_ty); - let name_ref_str = format!("{}_ref", name); - let name_ref = syn::Ident::new(&name_ref_str, name.span()); - let name_ref_unchecked_str = format!("{}_ref_unchecked", name); - let name_ref_unchecked = syn::Ident::new(&name_ref_unchecked_str, name.span()); - let helper_tokens = quote_spanned! {f.span()=> - /// Get access to the underlying data. - /// - /// If `WasmerEnv::finish` has been called, this function will never - /// return `None` unless the underlying data has been mutated manually. - pub fn #name_ref(&self) -> Option<&#inner_type> { - self.#name.get_ref() + if let Some(wasmer_attr) = wasmer_attr { + let inner_type = get_identifier(top_level_ty); + if let Some(name) = &name { + let name_ref_str = format!("{}_ref", name); + let name_ref = syn::Ident::new(&name_ref_str, name.span()); + let name_ref_unchecked_str = format!("{}_ref_unchecked", name); + let name_ref_unchecked = syn::Ident::new(&name_ref_unchecked_str, name.span()); + let helper_tokens = quote_spanned! {f.span()=> + /// Get access to the underlying data. + /// + /// If `WasmerEnv::finish` has been called, this function will never + /// return `None` unless the underlying data has been mutated manually. + pub fn #name_ref(&self) -> Option<&#inner_type> { + self.#name.get_ref() + } + /// Gets the item without checking if it's been initialized. + /// + /// # Safety + /// `WasmerEnv::finish` must have been called on this function or + /// this type manually initialized. + pub unsafe fn #name_ref_unchecked(&self) -> &#inner_type { + self.#name.get_unchecked() + } + }; + helpers.push(helper_tokens); + } + match wasmer_attr { + WasmerAttr::Export { identifier, span } => { + let finish_tokens = if let Some(name) = name { + let name_str = name.to_string(); + let item_name = + identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span())); + quote_spanned! {f.span()=> + let #name: #inner_type = instance.exports.get_with_generics(#item_name)?; + self.#name.initialize(#name); } - /// Gets the item without checking if it's been initialized. - /// - /// # Safety - /// `WasmerEnv::finish` must have been called on this function or - /// this type manually initialized. - pub unsafe fn #name_ref_unchecked(&self) -> &#inner_type { - self.#name.get_unchecked() + } else { + if let Some(identifier) = identifier { + let local_var = + Ident::new(&format!("field_{}", field_num), identifier.span()); + quote_spanned! {f.span()=> + let #local_var: #inner_type = instance.exports.get_with_generics(#identifier)?; + self.#field_num.initialize(#local_var); + } + } else { + abort!( + span, + "Expected `name` field on export attribute because field does not have a name. For example: `#[wasmer(export(name = \"wasm_ident\"))]`.", + ); } }; - helpers.push(helper_tokens); - match wasmer_attr { - WasmerAttr::Export { identifier, .. } => { - let item_name = - identifier.unwrap_or_else(|| LitStr::new(&name_str, name.span())); - let finish_tokens = quote_spanned! {f.span()=> - let #name: #inner_type = instance.exports.get_with_generics(#item_name)?; - self.#name.initialize(#name); - }; - finish.push(finish_tokens); - } - } + + finish.push(finish_tokens); } } } - _ => abort!( - data.fields, - "Only named fields are supported by `WasmerEnv` right now" - ), } let trait_methods = quote! { diff --git a/lib/derive/src/parse.rs b/lib/derive/src/parse.rs index 20208e8261d..bf2728b82f4 100644 --- a/lib/derive/src/parse.rs +++ b/lib/derive/src/parse.rs @@ -1,3 +1,4 @@ +use proc_macro2::Span; use proc_macro_error::abort; use syn::{ parenthesized, @@ -10,6 +11,7 @@ pub enum WasmerAttr { /// The identifier is an override, otherwise we use the field name as the name /// to lookup in `instance.exports`. identifier: Option, + span: Span, }, } @@ -64,6 +66,7 @@ impl Parse for WasmerAttrInner { fn parse(input: ParseStream<'_>) -> syn::Result { let ident: Ident = input.parse()?; let ident_str = ident.to_string(); + let span = ident.span(); let out = match ident_str.as_str() { "export" => { let export_expr; @@ -76,7 +79,10 @@ impl Parse for WasmerAttrInner { None }; - WasmerAttr::Export { identifier: name } + WasmerAttr::Export { + identifier: name, + span, + } } otherwise => abort!( ident, diff --git a/lib/derive/tests/basic.rs b/lib/derive/tests/basic.rs index ae89d47cadb..e87c236cdea 100644 --- a/lib/derive/tests/basic.rs +++ b/lib/derive/tests/basic.rs @@ -62,10 +62,26 @@ struct MyEnvWithLifetime<'a> { memory: LazyInit, } +#[derive(WasmerEnv)] +struct MyUnitStruct; + +#[derive(WasmerEnv)] +struct MyTupleStruct(u32); + +#[derive(WasmerEnv)] +struct MyTupleStruct2(u32, u32); + +#[derive(WasmerEnv)] +struct MyTupleStructWithAttribute(#[wasmer(export(name = "memory"))] LazyInit, u32); + #[test] fn test_derive_with_attribute() { assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); assert!(impls_wasmer_env::()); + assert!(impls_wasmer_env::()); + assert!(impls_wasmer_env::()); + assert!(impls_wasmer_env::()); + assert!(impls_wasmer_env::()); } From 38b296e36fac7048f95d5fdbb0215507f0b2192c Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 17 Nov 2020 15:30:21 -0800 Subject: [PATCH 25/39] Move `WasmerEnv` into its own mod, implement it for stdlib types --- lib/api/src/env.rs | 202 +++++++++++++++++++++++++++++++++++++++++++++ lib/api/src/lib.rs | 166 +------------------------------------ 2 files changed, 204 insertions(+), 164 deletions(-) create mode 100644 lib/api/src/env.rs diff --git a/lib/api/src/env.rs b/lib/api/src/env.rs new file mode 100644 index 00000000000..a7f7ea4f370 --- /dev/null +++ b/lib/api/src/env.rs @@ -0,0 +1,202 @@ +use crate::{ExportError, Instance}; +use thiserror::Error; + +/// An error while initializing the user supplied host env with the `WasmerEnv` trait. +#[derive(Error, Debug)] +#[error("Host env initialization error: {0}")] +pub enum HostEnvInitError { + /// An error occurred when accessing an export + Export(ExportError), +} + +impl From for HostEnvInitError { + fn from(other: ExportError) -> Self { + Self::Export(other) + } +} + +/// Prototype trait for finishing envs. +/// # Examples +/// +/// This trait can be derived like so: +/// +/// ``` +/// # use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc}; +/// +/// #[derive(WasmerEnv)] +/// pub struct MyEnvWithNoInstanceData { +/// non_instance_data: u8, +/// } +/// +/// #[derive(WasmerEnv)] +/// pub struct MyEnvWithInstanceData { +/// non_instance_data: u8, +/// #[wasmer(export)] +/// memory: LazyInit, +/// #[wasmer(export(name = "real_name"))] +/// func: LazyInit>, +/// } +/// +/// ``` +/// +/// This trait can also be implemented manually: +/// ``` +/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError}; +/// pub struct MyEnv { +/// memory: LazyInit, +/// } +/// +/// impl WasmerEnv for MyEnv { +/// fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { +/// let memory = instance.exports.get_memory("memory").unwrap(); +/// self.memory.initialize(memory.clone()); +/// Ok(()) +/// } +/// } +/// ``` +pub trait WasmerEnv { + /// The function that Wasmer will call on your type to let it finish + /// setting up the environment with data from the `Instance`. + /// + /// This function is called after `Instance` is created but before it is + /// returned to the user via `Instance::new`. + fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError>; +} + +macro_rules! impl_wasmer_env { + ($name:ty) => { + impl WasmerEnv for $name { + fn finish( + &mut self, + _instance: &crate::Instance, + ) -> Result<(), crate::HostEnvInitError> { + Ok(()) + } + } + }; +} + +impl_wasmer_env!(u8); +impl_wasmer_env!(i8); +impl_wasmer_env!(u16); +impl_wasmer_env!(i16); +impl_wasmer_env!(u32); +impl_wasmer_env!(i32); +impl_wasmer_env!(u64); +impl_wasmer_env!(i64); +impl_wasmer_env!(u128); +impl_wasmer_env!(i128); +impl_wasmer_env!(f32); +impl_wasmer_env!(f64); +impl_wasmer_env!(usize); +impl_wasmer_env!(isize); +impl_wasmer_env!(char); +impl_wasmer_env!(bool); +impl_wasmer_env!(String); +impl_wasmer_env!(::std::sync::atomic::AtomicBool); +impl_wasmer_env!(::std::sync::atomic::AtomicI8); +impl_wasmer_env!(::std::sync::atomic::AtomicU8); +impl_wasmer_env!(::std::sync::atomic::AtomicI16); +impl_wasmer_env!(::std::sync::atomic::AtomicU16); +impl_wasmer_env!(::std::sync::atomic::AtomicI32); +impl_wasmer_env!(::std::sync::atomic::AtomicU32); +impl_wasmer_env!(::std::sync::atomic::AtomicI64); +impl_wasmer_env!(::std::sync::atomic::AtomicUsize); +impl_wasmer_env!(::std::sync::atomic::AtomicIsize); + +impl WasmerEnv for &'static mut T { + fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { + (*self).finish(instance) + } +} + +// TODO: do we want to use mutex/atomics here? like old WASI solution +/// Lazily init an item +pub struct LazyInit { + /// The data to be initialized + data: std::mem::MaybeUninit, + /// Whether or not the data has been initialized + initialized: bool, +} + +impl LazyInit { + /// Creates an unitialized value. + pub fn new() -> Self { + Self { + data: std::mem::MaybeUninit::uninit(), + initialized: false, + } + } + + /// # Safety + /// - The data must be initialized first + pub unsafe fn get_unchecked(&self) -> &T { + &*self.data.as_ptr() + } + + /// Get the inner data. + pub fn get_ref(&self) -> Option<&T> { + if !self.initialized { + None + } else { + Some(unsafe { self.get_unchecked() }) + } + } + + /// TOOD: review + pub fn initialize(&mut self, value: T) -> bool { + if self.initialized { + return false; + } + unsafe { + self.data.as_mut_ptr().write(value); + } + self.initialized = true; + true + } +} + +impl std::fmt::Debug for LazyInit { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.debug_struct("LazyInit") + .field("data", &self.get_ref()) + .finish() + } +} + +impl Clone for LazyInit { + fn clone(&self) -> Self { + if let Some(inner) = self.get_ref() { + Self { + data: std::mem::MaybeUninit::new(inner.clone()), + initialized: true, + } + } else { + Self { + data: std::mem::MaybeUninit::uninit(), + initialized: false, + } + } + } +} + +impl Drop for LazyInit { + fn drop(&mut self) { + if self.initialized { + unsafe { + let ptr = self.data.as_mut_ptr(); + std::ptr::drop_in_place(ptr); + }; + } + } +} + +impl Default for LazyInit { + fn default() -> Self { + Self::new() + } +} + +unsafe impl Send for LazyInit {} +// I thought we could opt out of sync..., look into this +// unsafe impl !Sync for InitWithInstance {} diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 9877c4da97c..596aa8bd7d8 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -28,6 +28,7 @@ ) )] +mod env; mod exports; mod externals; mod import_object; @@ -51,6 +52,7 @@ pub mod internals { pub use crate::externals::{WithEnv, WithoutEnv}; } +pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv}; pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator}; pub use crate::externals::{ Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, Table, WasmTypeList, @@ -134,167 +136,3 @@ 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 - -use thiserror::Error; -/// An error while initializing the user supplied host env with the `WasmerEnv` trait. -#[derive(Error, Debug)] -#[error("Host env initialization error: {0}")] -pub enum HostEnvInitError { - /// An error occurred when accessing an export - Export(ExportError), -} - -impl From for HostEnvInitError { - fn from(other: ExportError) -> Self { - Self::Export(other) - } -} - -/// Prototype trait for finishing envs. -/// # Examples -/// -/// This trait can be derived like so: -/// -/// ``` -/// # use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc}; -/// -/// #[derive(WasmerEnv)] -/// pub struct MyEnvWithNoInstanceData { -/// non_instance_data: u8, -/// } -/// -/// #[derive(WasmerEnv)] -/// pub struct MyEnvWithInstanceData { -/// non_instance_data: u8, -/// #[wasmer(export)] -/// memory: LazyInit, -/// #[wasmer(export(name = "real_name"))] -/// func: LazyInit>, -/// } -/// -/// ``` -/// -/// This trait can also be implemented manually: -/// ``` -/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError}; -/// pub struct MyEnv { -/// memory: LazyInit, -/// } -/// -/// impl WasmerEnv for MyEnv { -/// fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { -/// let memory = instance.exports.get_memory("memory").unwrap(); -/// self.memory.initialize(memory.clone()); -/// Ok(()) -/// } -/// } -/// ``` -pub trait WasmerEnv { - /// The function that Wasmer will call on your type to let it finish - /// setting up the environment with data from the `Instance`. - /// - /// This function is called after `Instance` is created but before it is - /// returned to the user via `Instance::new`. - fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError>; -} - -impl WasmerEnv for &'static mut T { - fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { - (*self).finish(instance) - } -} - -// TODO: do we want to use mutex/atomics here? like old WASI solution -/// Lazily init an item -pub struct LazyInit { - /// The data to be initialized - data: std::mem::MaybeUninit, - /// Whether or not the data has been initialized - initialized: bool, -} - -impl LazyInit { - /// Creates an unitialized value. - pub fn new() -> Self { - Self { - data: std::mem::MaybeUninit::uninit(), - initialized: false, - } - } - - /// # Safety - /// - The data must be initialized first - pub unsafe fn get_unchecked(&self) -> &T { - &*self.data.as_ptr() - } - - /// Get the inner data. - pub fn get_ref(&self) -> Option<&T> { - if !self.initialized { - None - } else { - Some(unsafe { self.get_unchecked() }) - } - } - - /// TOOD: review - pub fn initialize(&mut self, value: T) -> bool { - if self.initialized { - return false; - } - unsafe { - self.data.as_mut_ptr().write(value); - } - self.initialized = true; - true - } -} - -impl std::fmt::Debug for LazyInit { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("LazyInit") - .field("data", &self.get_ref()) - .finish() - } -} - -impl Clone for LazyInit { - fn clone(&self) -> Self { - if let Some(inner) = self.get_ref() { - Self { - data: std::mem::MaybeUninit::new(inner.clone()), - initialized: true, - } - } else { - Self { - data: std::mem::MaybeUninit::uninit(), - initialized: false, - } - } - } -} - -impl Drop for LazyInit { - fn drop(&mut self) { - if self.initialized { - unsafe { - let ptr = self.data.as_mut_ptr(); - std::ptr::drop_in_place(ptr); - }; - } - } -} - -impl Default for LazyInit { - fn default() -> Self { - Self::new() - } -} - -unsafe impl Send for LazyInit {} -// I thought we could opt out of sync..., look into this -// unsafe impl !Sync for InitWithInstance {} From 2b0464a4b254fb800bef9166ef4e3a551045d670 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 17 Nov 2020 16:19:00 -0800 Subject: [PATCH 26/39] Port wasmer-emscripten to use `WasmerEnv` --- Cargo.lock | 1 + Cargo.toml | 5 +- lib/api/src/env.rs | 2 +- lib/cli/Cargo.toml | 2 +- lib/cli/src/commands/run.rs | 5 +- lib/emscripten/src/emscripten_target.rs | 241 ++++++++++---- lib/emscripten/src/env/mod.rs | 13 +- lib/emscripten/src/jmp.rs | 3 +- lib/emscripten/src/lib.rs | 414 +++++++++--------------- lib/emscripten/src/memory.rs | 6 +- lib/emscripten/src/utils.rs | 3 +- 11 files changed, 353 insertions(+), 342 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13a4d86d7fc..ed92b39f6cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2879,6 +2879,7 @@ dependencies = [ "wasmer-compiler-cranelift", "wasmer-compiler-llvm", "wasmer-compiler-singlepass", + "wasmer-emscripten", "wasmer-engine", "wasmer-engine-dummy", "wasmer-engine-jit", diff --git a/Cargo.toml b/Cargo.toml index ea6780cec84..143fde2a92c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ wasmer-compiler = { version = "1.0.0-alpha5", path = "lib/compiler" } wasmer-compiler-cranelift = { version = "1.0.0-alpha5", path = "lib/compiler-cranelift", optional = true } wasmer-compiler-singlepass = { version = "1.0.0-alpha5", path = "lib/compiler-singlepass", optional = true } wasmer-compiler-llvm = { version = "1.0.0-alpha5", path = "lib/compiler-llvm", optional = true } +wasmer-emscripten = { version = "1.0.0-alpha5", path = "lib/emscripten", optional = true } wasmer-engine = { version = "1.0.0-alpha5", path = "lib/engine" } wasmer-engine-jit = { version = "1.0.0-alpha5", path = "lib/engine-jit", optional = true } wasmer-engine-native = { version = "1.0.0-alpha5", path = "lib/engine-native", optional = true } @@ -79,7 +80,7 @@ default = [ "object-file", "cache", "wasi", - # "emscripten", + "emscripten", ] engine = [] jit = [ @@ -97,7 +98,7 @@ object-file = [ cache = ["wasmer-cache"] wast = ["wasmer-wast"] wasi = ["wasmer-wasi"] -# emscripten = ["wasmer-emscripten"] +emscripten = ["wasmer-emscripten"] wat = ["wasmer/wat"] compiler = [ "wasmer/compiler", diff --git a/lib/api/src/env.rs b/lib/api/src/env.rs index a7f7ea4f370..6373d05598b 100644 --- a/lib/api/src/env.rs +++ b/lib/api/src/env.rs @@ -143,7 +143,7 @@ impl LazyInit { } } - /// TOOD: review + /// Sets a value and marks the data as initialized. pub fn initialize(&mut self, value: T) -> bool { if self.initialized { return false; diff --git a/lib/cli/Cargo.toml b/lib/cli/Cargo.toml index ccdc773ffa8..b734ca0ccb6 100644 --- a/lib/cli/Cargo.toml +++ b/lib/cli/Cargo.toml @@ -58,7 +58,7 @@ default = [ "object-file", "cache", "wasi", - # "emscripten", + "emscripten", ] engine = [] jit = [ diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index b3422d3ce88..c3a1d98a752 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -116,7 +116,7 @@ impl Run { if is_emscripten_module(&module) { let mut emscripten_globals = EmscriptenGlobals::new(module.store(), &module) .map_err(|e| anyhow!("{}", e))?; - let mut em_env = EmEnv::new(); + let mut em_env = EmEnv::new(&emscripten_globals.data, Default::default()); let import_object = generate_emscripten_env(module.store(), &mut emscripten_globals, &mut em_env); let mut instance = Instance::new(&module, &import_object) @@ -132,8 +132,7 @@ impl Run { self.path.to_str().unwrap() }, self.args.iter().map(|arg| arg.as_str()).collect(), - None, //run.em_entrypoint.clone(), - vec![], //mapped_dirs, + None, //run.em_entrypoint.clone(), )?; return Ok(()); } diff --git a/lib/emscripten/src/emscripten_target.rs b/lib/emscripten/src/emscripten_target.rs index 2458cc8f21b..fd3eba13834 100644 --- a/lib/emscripten/src/emscripten_target.rs +++ b/lib/emscripten/src/emscripten_target.rs @@ -138,32 +138,32 @@ pub fn _getnameinfo( // Macro definitions macro_rules! invoke { - ($ctx: ident, $name:ident, $( $arg:ident ),*) => {{ - let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed"); - let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*); + ($ctx: ident, $name:ident, $name_ref:ident, $( $arg:ident ),*) => {{ + let sp = get_emscripten_data($ctx).stack_save_ref().expect("stack_save is None").call().expect("stack_save call failed"); + let result = get_emscripten_data($ctx).$name_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*); match result { Ok(v) => v, Err(_e) => { - get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed"); + get_emscripten_data($ctx).stack_restore_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed"); // TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error // JS version is: if (e !== e+0 && e !== 'longjmp') throw e; - get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed"); + get_emscripten_data($ctx).set_threw_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed"); 0 as _ } } }}; } macro_rules! invoke_no_return { - ($ctx: ident, $name:ident, $( $arg:ident ),*) => {{ - let sp = get_emscripten_data($ctx).stack_save.as_ref().expect("stack_save is None").call().expect("stack_save call failed"); - let result = get_emscripten_data($ctx).$name.as_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*); + ($ctx: ident, $name:ident, $name_ref:ident, $( $arg:ident ),*) => {{ + let sp = get_emscripten_data($ctx).stack_save_ref().expect("stack_save is None").call().expect("stack_save call failed"); + let result = get_emscripten_data($ctx).$name_ref().expect(concat!("Dynamic call is None: ", stringify!($name))).call($($arg),*); match result { Ok(v) => v, Err(_e) => { - get_emscripten_data($ctx).stack_restore.as_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed"); + get_emscripten_data($ctx).stack_restore_ref().expect("stack_restore is None").call(sp).expect("stack_restore call failed"); // TODO: We should check if _e != "longjmp" and if that's the case, re-throw the error // JS version is: if (e !== e+0 && e !== 'longjmp') throw e; - get_emscripten_data($ctx).set_threw.as_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed"); + get_emscripten_data($ctx).set_threw_ref().expect("set_threw is None").call(1, 0).expect("set_threw call failed"); } } }}; @@ -172,56 +172,83 @@ macro_rules! invoke_no_return { // Invoke functions pub fn invoke_i(ctx: &mut EmEnv, index: i32) -> i32 { debug!("emscripten::invoke_i"); - invoke!(ctx, dyn_call_i, index) + invoke!(ctx, dyn_call_i, dyn_call_i_ref, index) } pub fn invoke_ii(ctx: &mut EmEnv, index: i32, a1: i32) -> i32 { debug!("emscripten::invoke_ii"); - invoke!(ctx, dyn_call_ii, index, a1) + invoke!(ctx, dyn_call_ii, dyn_call_ii_ref, index, a1) } pub fn invoke_iii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) -> i32 { debug!("emscripten::invoke_iii"); - invoke!(ctx, dyn_call_iii, index, a1, a2) + invoke!(ctx, dyn_call_iii, dyn_call_iii_ref, index, a1, a2) } pub fn invoke_iiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 { debug!("emscripten::invoke_iiii"); - invoke!(ctx, dyn_call_iiii, index, a1, a2, a3) + invoke!(ctx, dyn_call_iiii, dyn_call_iiii_ref, index, a1, a2, a3) } pub fn invoke_iifi(ctx: &mut EmEnv, index: i32, a1: i32, a2: f64, a3: i32) -> i32 { debug!("emscripten::invoke_iifi"); - invoke!(ctx, dyn_call_iifi, index, a1, a2, a3) + invoke!(ctx, dyn_call_iifi, dyn_call_iifi_ref, index, a1, a2, a3) } pub fn invoke_v(ctx: &mut EmEnv, index: i32) { debug!("emscripten::invoke_v"); - invoke_no_return!(ctx, dyn_call_v, index); + invoke_no_return!(ctx, dyn_call_v, dyn_call_v_ref, index); } pub fn invoke_vi(ctx: &mut EmEnv, index: i32, a1: i32) { debug!("emscripten::invoke_vi"); - invoke_no_return!(ctx, dyn_call_vi, index, a1); + invoke_no_return!(ctx, dyn_call_vi, dyn_call_vi_ref, index, a1); } pub fn invoke_vii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) { debug!("emscripten::invoke_vii"); - invoke_no_return!(ctx, dyn_call_vii, index, a1, a2); + invoke_no_return!(ctx, dyn_call_vii, dyn_call_vii_ref, index, a1, a2); } pub fn invoke_viii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) { debug!("emscripten::invoke_viii"); - invoke_no_return!(ctx, dyn_call_viii, index, a1, a2, a3); + invoke_no_return!(ctx, dyn_call_viii, dyn_call_viii_ref, index, a1, a2, a3); } pub fn invoke_viiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) { debug!("emscripten::invoke_viiii"); - invoke_no_return!(ctx, dyn_call_viiii, index, a1, a2, a3, a4); + invoke_no_return!( + ctx, + dyn_call_viiii, + dyn_call_viiii_ref, + index, + a1, + a2, + a3, + a4 + ); } pub fn invoke_dii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) -> f64 { debug!("emscripten::invoke_dii"); - invoke!(ctx, dyn_call_dii, index, a1, a2) + invoke!(ctx, dyn_call_dii, dyn_call_dii_ref, index, a1, a2) } pub fn invoke_diiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> f64 { debug!("emscripten::invoke_diiii"); - invoke!(ctx, dyn_call_diiii, index, a1, a2, a3, a4) + invoke!( + ctx, + dyn_call_diiii, + dyn_call_diiii_ref, + index, + a1, + a2, + a3, + a4 + ) } pub fn invoke_iiiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 { debug!("emscripten::invoke_iiiii"); - invoke!(ctx, dyn_call_iiiii, index, a1, a2, a3, a4) + invoke!( + ctx, + dyn_call_iiiii, + dyn_call_iiiii_ref, + index, + a1, + a2, + a3, + a4 + ) } pub fn invoke_iiiiii( ctx: &mut EmEnv, @@ -233,7 +260,17 @@ pub fn invoke_iiiiii( a5: i32, ) -> i32 { debug!("emscripten::invoke_iiiiii"); - invoke!(ctx, dyn_call_iiiiii, index, a1, a2, a3, a4, a5) + invoke!( + ctx, + dyn_call_iiiiii, + dyn_call_iiiiii_ref, + index, + a1, + a2, + a3, + a4, + a5 + ) } pub fn invoke_iiiiiii( ctx: &mut EmEnv, @@ -246,7 +283,18 @@ pub fn invoke_iiiiiii( a6: i32, ) -> i32 { debug!("emscripten::invoke_iiiiiii"); - invoke!(ctx, dyn_call_iiiiiii, index, a1, a2, a3, a4, a5, a6) + invoke!( + ctx, + dyn_call_iiiiiii, + dyn_call_iiiiiii_ref, + index, + a1, + a2, + a3, + a4, + a5, + a6 + ) } pub fn invoke_iiiiiiii( ctx: &mut EmEnv, @@ -260,7 +308,19 @@ pub fn invoke_iiiiiiii( a7: i32, ) -> i32 { debug!("emscripten::invoke_iiiiiiii"); - invoke!(ctx, dyn_call_iiiiiiii, index, a1, a2, a3, a4, a5, a6, a7) + invoke!( + ctx, + dyn_call_iiiiiiii, + dyn_call_iiiiiiii_ref, + index, + a1, + a2, + a3, + a4, + a5, + a6, + a7 + ) } pub fn invoke_iiiiiiiii( ctx: &mut EmEnv, @@ -278,6 +338,7 @@ pub fn invoke_iiiiiiiii( invoke!( ctx, dyn_call_iiiiiiiii, + dyn_call_iiiiiiiii_ref, index, a1, a2, @@ -306,6 +367,7 @@ pub fn invoke_iiiiiiiiii( invoke!( ctx, dyn_call_iiiiiiiiii, + dyn_call_iiiiiiiiii_ref, index, a1, a2, @@ -336,6 +398,7 @@ pub fn invoke_iiiiiiiiiii( invoke!( ctx, dyn_call_iiiiiiiiiii, + dyn_call_iiiiiiiiiii_ref, index, a1, a2, @@ -351,11 +414,21 @@ pub fn invoke_iiiiiiiiiii( } pub fn invoke_vd(ctx: &mut EmEnv, index: i32, a1: f64) { debug!("emscripten::invoke_vd"); - invoke_no_return!(ctx, dyn_call_vd, index, a1) + invoke_no_return!(ctx, dyn_call_vd, dyn_call_vd_ref, index, a1) } pub fn invoke_viiiii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) { debug!("emscripten::invoke_viiiii"); - invoke_no_return!(ctx, dyn_call_viiiii, index, a1, a2, a3, a4, a5) + invoke_no_return!( + ctx, + dyn_call_viiiii, + dyn_call_viiiii_ref, + index, + a1, + a2, + a3, + a4, + a5 + ) } pub fn invoke_viiiiii( ctx: &mut EmEnv, @@ -368,7 +441,18 @@ pub fn invoke_viiiiii( a6: i32, ) { debug!("emscripten::invoke_viiiiii"); - invoke_no_return!(ctx, dyn_call_viiiiii, index, a1, a2, a3, a4, a5, a6) + invoke_no_return!( + ctx, + dyn_call_viiiiii, + dyn_call_viiiiii_ref, + index, + a1, + a2, + a3, + a4, + a5, + a6 + ) } pub fn invoke_viiiiiii( ctx: &mut EmEnv, @@ -382,7 +466,19 @@ pub fn invoke_viiiiiii( a7: i32, ) { debug!("emscripten::invoke_viiiiiii"); - invoke_no_return!(ctx, dyn_call_viiiiiii, index, a1, a2, a3, a4, a5, a6, a7) + invoke_no_return!( + ctx, + dyn_call_viiiiiii, + dyn_call_viiiiiii_ref, + index, + a1, + a2, + a3, + a4, + a5, + a6, + a7 + ) } pub fn invoke_viiiiiiii( ctx: &mut EmEnv, @@ -400,6 +496,7 @@ pub fn invoke_viiiiiiii( invoke_no_return!( ctx, dyn_call_viiiiiiii, + dyn_call_viiiiiiii_ref, index, a1, a2, @@ -428,6 +525,7 @@ pub fn invoke_viiiiiiiii( invoke_no_return!( ctx, dyn_call_viiiiiiiii, + dyn_call_viiiiiiiii_ref, index, a1, a2, @@ -458,6 +556,7 @@ pub fn invoke_viiiiiiiiii( invoke_no_return!( ctx, dyn_call_viiiiiiiiii, + dyn_call_viiiiiiiiii_ref, index, a1, a2, @@ -474,17 +573,17 @@ pub fn invoke_viiiiiiiiii( pub fn invoke_iij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 { debug!("emscripten::invoke_iij"); - invoke!(ctx, dyn_call_iij, index, a1, a2, a3) + invoke!(ctx, dyn_call_iij, dyn_call_iij_ref, index, a1, a2, a3) } pub fn invoke_iji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 { debug!("emscripten::invoke_iji"); - invoke!(ctx, dyn_call_iji, index, a1, a2, a3) + invoke!(ctx, dyn_call_iji, dyn_call_iji_ref, index, a1, a2, a3) } pub fn invoke_iiji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 { debug!("emscripten::invoke_iiji"); - invoke!(ctx, dyn_call_iiji, index, a1, a2, a3, a4) + invoke!(ctx, dyn_call_iiji, dyn_call_iiji_ref, index, a1, a2, a3, a4) } pub fn invoke_iiijj( @@ -498,11 +597,22 @@ pub fn invoke_iiijj( a6: i32, ) -> i32 { debug!("emscripten::invoke_iiijj"); - invoke!(ctx, dyn_call_iiijj, index, a1, a2, a3, a4, a5, a6) + invoke!( + ctx, + dyn_call_iiijj, + dyn_call_iiijj_ref, + index, + a1, + a2, + a3, + a4, + a5, + a6 + ) } pub fn invoke_j(ctx: &mut EmEnv, index: i32) -> i32 { debug!("emscripten::invoke_j"); - if let Some(dyn_call_j) = &get_emscripten_data(ctx).dyn_call_j { + if let Some(dyn_call_j) = get_emscripten_data(ctx).dyn_call_j_ref() { dyn_call_j.call(index).unwrap() } else { panic!("dyn_call_j is set to None"); @@ -510,7 +620,7 @@ pub fn invoke_j(ctx: &mut EmEnv, index: i32) -> i32 { } pub fn invoke_ji(ctx: &mut EmEnv, index: i32, a1: i32) -> i32 { debug!("emscripten::invoke_ji"); - if let Some(dyn_call_ji) = &get_emscripten_data(ctx).dyn_call_ji { + if let Some(dyn_call_ji) = get_emscripten_data(ctx).dyn_call_ji_ref() { dyn_call_ji.call(index, a1).unwrap() } else { panic!("dyn_call_ji is set to None"); @@ -518,7 +628,7 @@ pub fn invoke_ji(ctx: &mut EmEnv, index: i32, a1: i32) -> i32 { } pub fn invoke_jii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) -> i32 { debug!("emscripten::invoke_jii"); - if let Some(dyn_call_jii) = &get_emscripten_data(ctx).dyn_call_jii { + if let Some(dyn_call_jii) = get_emscripten_data(ctx).dyn_call_jii_ref() { dyn_call_jii.call(index, a1, a2).unwrap() } else { panic!("dyn_call_jii is set to None"); @@ -527,7 +637,7 @@ pub fn invoke_jii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) -> i32 { pub fn invoke_jij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 { debug!("emscripten::invoke_jij"); - if let Some(dyn_call_jij) = &get_emscripten_data(ctx).dyn_call_jij { + if let Some(dyn_call_jij) = get_emscripten_data(ctx).dyn_call_jij_ref() { dyn_call_jij.call(index, a1, a2, a3).unwrap() } else { panic!("dyn_call_jij is set to None"); @@ -535,7 +645,7 @@ pub fn invoke_jij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) -> i32 } pub fn invoke_jjj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) -> i32 { debug!("emscripten::invoke_jjj"); - if let Some(dyn_call_jjj) = &get_emscripten_data(ctx).dyn_call_jjj { + if let Some(dyn_call_jjj) = get_emscripten_data(ctx).dyn_call_jjj_ref() { dyn_call_jjj.call(index, a1, a2, a3, a4).unwrap() } else { panic!("dyn_call_jjj is set to None"); @@ -543,7 +653,7 @@ pub fn invoke_jjj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i3 } pub fn invoke_viiij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) { debug!("emscripten::invoke_viiij"); - if let Some(dyn_call_viiij) = &get_emscripten_data(ctx).dyn_call_viiij { + if let Some(dyn_call_viiij) = get_emscripten_data(ctx).dyn_call_viiij_ref() { dyn_call_viiij.call(index, a1, a2, a3, a4, a5).unwrap(); } else { panic!("dyn_call_viiij is set to None"); @@ -563,7 +673,7 @@ pub fn invoke_viiijiiii( a9: i32, ) { debug!("emscripten::invoke_viiijiiii"); - if let Some(dyn_call_viiijiiii) = &get_emscripten_data(ctx).dyn_call_viiijiiii { + if let Some(dyn_call_viiijiiii) = get_emscripten_data(ctx).dyn_call_viiijiiii_ref() { dyn_call_viiijiiii .call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9) .unwrap(); @@ -587,7 +697,7 @@ pub fn invoke_viiijiiiiii( a11: i32, ) { debug!("emscripten::invoke_viiijiiiiii"); - if let Some(dyn_call_viiijiiiiii) = &get_emscripten_data(ctx).dyn_call_viiijiiiiii { + if let Some(dyn_call_viiijiiiiii) = get_emscripten_data(ctx).dyn_call_viiijiiiiii_ref() { dyn_call_viiijiiiiii .call(index, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) .unwrap(); @@ -597,7 +707,7 @@ pub fn invoke_viiijiiiiii( } pub fn invoke_viij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) { debug!("emscripten::invoke_viij"); - if let Some(dyn_call_viij) = &get_emscripten_data(ctx).dyn_call_viij { + if let Some(dyn_call_viij) = get_emscripten_data(ctx).dyn_call_viij_ref() { dyn_call_viij.call(index, a1, a2, a3, a4).unwrap(); } else { panic!("dyn_call_viij is set to None"); @@ -605,7 +715,7 @@ pub fn invoke_viij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i } pub fn invoke_viiji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) { debug!("emscripten::invoke_viiji"); - if let Some(dyn_call_viiji) = &get_emscripten_data(ctx).dyn_call_viiji { + if let Some(dyn_call_viiji) = get_emscripten_data(ctx).dyn_call_viiji_ref() { dyn_call_viiji.call(index, a1, a2, a3, a4, a5).unwrap(); } else { panic!("dyn_call_viiji is set to None"); @@ -623,7 +733,7 @@ pub fn invoke_viijiii( a7: i32, ) { debug!("emscripten::invoke_viijiii"); - if let Some(dyn_call_viijiii) = &get_emscripten_data(ctx).dyn_call_viijiii { + if let Some(dyn_call_viijiii) = get_emscripten_data(ctx).dyn_call_viijiii_ref() { dyn_call_viijiii .call(index, a1, a2, a3, a4, a5, a6, a7) .unwrap(); @@ -642,7 +752,7 @@ pub fn invoke_viijj( a6: i32, ) { debug!("emscripten::invoke_viijj"); - if let Some(dyn_call_viijj) = &get_emscripten_data(ctx).dyn_call_viijj { + if let Some(dyn_call_viijj) = get_emscripten_data(ctx).dyn_call_viijj_ref() { dyn_call_viijj.call(index, a1, a2, a3, a4, a5, a6).unwrap(); } else { panic!("dyn_call_viijj is set to None"); @@ -650,7 +760,7 @@ pub fn invoke_viijj( } pub fn invoke_vj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) { debug!("emscripten::invoke_vj"); - if let Some(dyn_call_vj) = &get_emscripten_data(ctx).dyn_call_vj { + if let Some(dyn_call_vj) = get_emscripten_data(ctx).dyn_call_vj_ref() { dyn_call_vj.call(index, a1, a2).unwrap(); } else { panic!("dyn_call_vj is set to None"); @@ -658,11 +768,21 @@ pub fn invoke_vj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32) { } pub fn invoke_vjji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) { debug!("emscripten::invoke_vjji"); - invoke_no_return!(ctx, dyn_call_vjji, index, a1, a2, a3, a4, a5) + invoke_no_return!( + ctx, + dyn_call_vjji, + dyn_call_vjji_ref, + index, + a1, + a2, + a3, + a4, + a5 + ) } pub fn invoke_vij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) { debug!("emscripten::invoke_vij"); - if let Some(dyn_call_vij) = &get_emscripten_data(ctx).dyn_call_vij { + if let Some(dyn_call_vij) = get_emscripten_data(ctx).dyn_call_vij_ref() { dyn_call_vij.call(index, a1, a2, a3).unwrap(); } else { panic!("dyn_call_vij is set to None"); @@ -670,7 +790,7 @@ pub fn invoke_vij(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32) { } pub fn invoke_viji(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32) { debug!("emscripten::invoke_viji"); - if let Some(dyn_call_viji) = &get_emscripten_data(ctx).dyn_call_viji { + if let Some(dyn_call_viji) = get_emscripten_data(ctx).dyn_call_viji_ref() { dyn_call_viji.call(index, a1, a2, a3, a4).unwrap() } else { panic!("dyn_call_viji is set to None"); @@ -687,7 +807,7 @@ pub fn invoke_vijiii( a6: i32, ) { debug!("emscripten::invoke_vijiii"); - if let Some(dyn_call_vijiii) = &get_emscripten_data(ctx).dyn_call_vijiii { + if let Some(dyn_call_vijiii) = get_emscripten_data(ctx).dyn_call_vijiii_ref() { dyn_call_vijiii.call(index, a1, a2, a3, a4, a5, a6).unwrap() } else { panic!("dyn_call_vijiii is set to None"); @@ -695,7 +815,7 @@ pub fn invoke_vijiii( } pub fn invoke_vijj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i32, a5: i32) { debug!("emscripten::invoke_vijj"); - if let Some(dyn_call_vijj) = &get_emscripten_data(ctx).dyn_call_vijj { + if let Some(dyn_call_vijj) = get_emscripten_data(ctx).dyn_call_vijj_ref() { dyn_call_vijj.call(index, a1, a2, a3, a4, a5).unwrap() } else { panic!("dyn_call_vijj is set to None"); @@ -703,15 +823,25 @@ pub fn invoke_vijj(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: i32, a4: i } pub fn invoke_vidd(ctx: &mut EmEnv, index: i32, a1: i32, a2: f64, a3: f64) { debug!("emscripten::invoke_viid"); - invoke_no_return!(ctx, dyn_call_vidd, index, a1, a2, a3); + invoke_no_return!(ctx, dyn_call_vidd, dyn_call_vidd_ref, index, a1, a2, a3); } pub fn invoke_viid(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: f64) { debug!("emscripten::invoke_viid"); - invoke_no_return!(ctx, dyn_call_viid, index, a1, a2, a3); + invoke_no_return!(ctx, dyn_call_viid, dyn_call_viid_ref, index, a1, a2, a3); } pub fn invoke_viidii(ctx: &mut EmEnv, index: i32, a1: i32, a2: i32, a3: f64, a4: i32, a5: i32) { debug!("emscripten::invoke_viidii"); - invoke_no_return!(ctx, dyn_call_viidii, index, a1, a2, a3, a4, a5); + invoke_no_return!( + ctx, + dyn_call_viidii, + dyn_call_viidii_ref, + index, + a1, + a2, + a3, + a4, + a5 + ); } pub fn invoke_viidddddddd( ctx: &mut EmEnv, @@ -731,6 +861,7 @@ pub fn invoke_viidddddddd( invoke_no_return!( ctx, dyn_call_viidddddddd, + dyn_call_viidddddddd_ref, index, a1, a2, diff --git a/lib/emscripten/src/env/mod.rs b/lib/emscripten/src/env/mod.rs index ad04d8dc729..52208fb3c3c 100644 --- a/lib/emscripten/src/env/mod.rs +++ b/lib/emscripten/src/env/mod.rs @@ -19,14 +19,14 @@ use crate::{ }; use std::os::raw::c_int; +use std::sync::MutexGuard; use crate::EmEnv; use wasmer::ValueType; pub fn call_malloc(ctx: &mut EmEnv, size: u32) -> u32 { get_emscripten_data(ctx) - .malloc - .as_ref() + .malloc_ref() .unwrap() .call(size) .unwrap() @@ -38,7 +38,7 @@ pub fn call_malloc_with_cast(ctx: &mut EmEnv, size: u32) -> WasmPtr } pub fn call_memalign(ctx: &mut EmEnv, alignment: u32, size: u32) -> u32 { - if let Some(memalign) = &get_emscripten_data(ctx).memalign { + if let Some(memalign) = &get_emscripten_data(ctx).memalign_ref() { memalign.call(alignment, size).unwrap() } else { panic!("Memalign is set to None"); @@ -47,15 +47,14 @@ pub fn call_memalign(ctx: &mut EmEnv, alignment: u32, size: u32) -> u32 { pub fn call_memset(ctx: &mut EmEnv, pointer: u32, value: u32, size: u32) -> u32 { get_emscripten_data(ctx) - .memset - .as_ref() + .memset_ref() .unwrap() .call(pointer, value, size) .unwrap() } -pub(crate) fn get_emscripten_data<'a>(ctx: &'a mut EmEnv) -> &'a mut EmscriptenData<'static> { - unsafe { &mut **ctx.data } +pub(crate) fn get_emscripten_data(ctx: &EmEnv) -> MutexGuard { + ctx.data.lock().unwrap() } pub fn _getpagesize(_ctx: &mut EmEnv) -> u32 { diff --git a/lib/emscripten/src/jmp.rs b/lib/emscripten/src/jmp.rs index def2346d473..cef02fb8045 100644 --- a/lib/emscripten/src/jmp.rs +++ b/lib/emscripten/src/jmp.rs @@ -62,8 +62,7 @@ impl Error for LongJumpRet {} pub fn _longjmp(ctx: &mut EmEnv, env_addr: i32, val: c_int) { let val = if val == 0 { 1 } else { val }; get_emscripten_data(ctx) - .set_threw - .as_ref() + .set_threw_ref() .expect("set_threw is None") .call(env_addr, val) .expect("set_threw failed to call"); diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 4f33c657262..60fbcfd3b33 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -16,13 +16,13 @@ extern crate log; use lazy_static::lazy_static; use std::cell::UnsafeCell; use std::collections::HashMap; +use std::f64; use std::path::PathBuf; -use std::sync::Arc; -use std::{f64, ffi::c_void}; +use std::sync::{Arc, Mutex}; use wasmer::{ imports, namespace, Exports, ExternRef, Function, FunctionType, Global, ImportObject, Instance, - Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType, Val, - ValType, + LazyInit, Memory, MemoryType, Module, NativeFunc, Pages, RuntimeError, Store, Table, TableType, + Val, ValType, WasmerEnv, }; #[cfg(unix)] @@ -73,15 +73,22 @@ pub use self::utils::{ /// The environment provided to the Emscripten imports. pub struct EmEnv { memory: Arc>, - data: *mut *mut EmscriptenData<'static>, + data: Arc>, +} + +impl WasmerEnv for EmEnv { + fn finish(&mut self, instance: &Instance) -> Result<(), wasmer::HostEnvInitError> { + let mut ed = self.data.lock().unwrap(); + ed.finish(instance)?; + Ok(()) + } } impl EmEnv { - pub fn new() -> Self { + pub fn new(data: &EmscriptenGlobalsData, mapped_dirs: HashMap) -> Self { Self { memory: Arc::new(None), - // TODO: clean this up - data: Box::into_raw(Box::new(std::ptr::null_mut())), + data: Arc::new(Mutex::new(EmscriptenData::new(data.clone(), mapped_dirs))), } } @@ -92,10 +99,6 @@ impl EmEnv { } } - pub fn set_data(&mut self, data: *mut c_void) { - unsafe { *self.data = data as _ }; - } - /// Get a reference to the memory pub fn memory(&self, _mem_idx: u32) -> &Memory { (*self.memory).as_ref().unwrap() @@ -119,279 +122,158 @@ lazy_static! { const GLOBAL_BASE: u32 = 1024; const STATIC_BASE: u32 = GLOBAL_BASE; -pub struct EmscriptenData<'a> { - pub globals: &'a EmscriptenGlobalsData, - - pub malloc: Option>, - pub free: Option>, - pub memalign: Option>, - pub memset: Option>, - pub stack_alloc: Option>, +#[derive(WasmerEnv, Default)] +pub struct EmscriptenData { + pub globals: EmscriptenGlobalsData, + + #[wasmer(export)] + pub malloc: LazyInit>, + #[wasmer(export)] + pub free: LazyInit>, + #[wasmer(export)] + pub memalign: LazyInit>, + #[wasmer(export)] + pub memset: LazyInit>, + #[wasmer(export)] + pub stack_alloc: LazyInit>, pub jumps: Vec>, pub opened_dirs: HashMap>, - pub dyn_call_i: Option>, - pub dyn_call_ii: Option>, - pub dyn_call_iii: Option>, - pub dyn_call_iiii: Option>, - pub dyn_call_iifi: Option>, - pub dyn_call_v: Option>, - pub dyn_call_vi: Option>, - pub dyn_call_vii: Option>, - pub dyn_call_viii: Option>, - pub dyn_call_viiii: Option>, + #[wasmer(export)] + pub dyn_call_i: LazyInit>, + #[wasmer(export)] + pub dyn_call_ii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iifi: LazyInit>, + #[wasmer(export)] + pub dyn_call_v: LazyInit>, + #[wasmer(export)] + pub dyn_call_vi: LazyInit>, + #[wasmer(export)] + pub dyn_call_vii: LazyInit>, + #[wasmer(export)] + pub dyn_call_viii: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiii: LazyInit>, // round 2 - pub dyn_call_dii: Option>, - pub dyn_call_diiii: Option>, - pub dyn_call_iiiii: Option>, - pub dyn_call_iiiiii: Option>, - pub dyn_call_iiiiiii: Option>, - pub dyn_call_iiiiiiii: Option>, - pub dyn_call_iiiiiiiii: Option>, + #[wasmer(export)] + pub dyn_call_dii: LazyInit>, + #[wasmer(export)] + pub dyn_call_diiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiiiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiiiiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiiiiiiii: + LazyInit>, + #[wasmer(export)] pub dyn_call_iiiiiiiiii: - Option>, + LazyInit>, + #[wasmer(export)] pub dyn_call_iiiiiiiiiii: - Option>, - pub dyn_call_vd: Option>, - pub dyn_call_viiiii: Option>, - pub dyn_call_viiiiii: Option>, - pub dyn_call_viiiiiii: Option>, - pub dyn_call_viiiiiiii: Option>, - pub dyn_call_viiiiiiiii: Option>, + LazyInit>, + #[wasmer(export)] + pub dyn_call_vd: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiiiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiiiiiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiiiiiiii: + LazyInit>, + #[wasmer(export)] pub dyn_call_viiiiiiiiii: - Option>, - pub dyn_call_iij: Option>, - pub dyn_call_iji: Option>, - pub dyn_call_iiji: Option>, - pub dyn_call_iiijj: Option>, - pub dyn_call_j: Option>, - pub dyn_call_ji: Option>, - pub dyn_call_jii: Option>, - pub dyn_call_jij: Option>, - pub dyn_call_jjj: Option>, - pub dyn_call_viiij: Option>, - pub dyn_call_viiijiiii: Option>, + LazyInit>, + #[wasmer(export)] + pub dyn_call_iij: LazyInit>, + #[wasmer(export)] + pub dyn_call_iji: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiji: LazyInit>, + #[wasmer(export)] + pub dyn_call_iiijj: LazyInit>, + #[wasmer(export)] + pub dyn_call_j: LazyInit>, + #[wasmer(export)] + pub dyn_call_ji: LazyInit>, + #[wasmer(export)] + pub dyn_call_jii: LazyInit>, + #[wasmer(export)] + pub dyn_call_jij: LazyInit>, + #[wasmer(export)] + pub dyn_call_jjj: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiij: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiijiiii: + LazyInit>, + #[wasmer(export)] pub dyn_call_viiijiiiiii: - Option>, - pub dyn_call_viij: Option>, - pub dyn_call_viiji: Option>, - pub dyn_call_viijiii: Option>, - pub dyn_call_viijj: Option>, - pub dyn_call_vj: Option>, - pub dyn_call_vjji: Option>, - pub dyn_call_vij: Option>, - pub dyn_call_viji: Option>, - pub dyn_call_vijiii: Option>, - pub dyn_call_vijj: Option>, - pub dyn_call_viid: Option>, - pub dyn_call_vidd: Option>, - pub dyn_call_viidii: Option>, + LazyInit>, + #[wasmer(export)] + pub dyn_call_viij: LazyInit>, + #[wasmer(export)] + pub dyn_call_viiji: LazyInit>, + #[wasmer(export)] + pub dyn_call_viijiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_viijj: LazyInit>, + #[wasmer(export)] + pub dyn_call_vj: LazyInit>, + #[wasmer(export)] + pub dyn_call_vjji: LazyInit>, + #[wasmer(export)] + pub dyn_call_vij: LazyInit>, + #[wasmer(export)] + pub dyn_call_viji: LazyInit>, + #[wasmer(export)] + pub dyn_call_vijiii: LazyInit>, + #[wasmer(export)] + pub dyn_call_vijj: LazyInit>, + #[wasmer(export)] + pub dyn_call_viid: LazyInit>, + #[wasmer(export)] + pub dyn_call_vidd: LazyInit>, + #[wasmer(export)] + pub dyn_call_viidii: LazyInit>, + #[wasmer(export)] pub dyn_call_viidddddddd: - Option>, + LazyInit>, pub temp_ret_0: i32, - pub stack_save: Option>, - pub stack_restore: Option>, - pub set_threw: Option>, + #[wasmer(export)] + pub stack_save: LazyInit>, + #[wasmer(export)] + pub stack_restore: LazyInit>, + #[wasmer(export)] + pub set_threw: LazyInit>, pub mapped_dirs: HashMap, } -impl<'a> EmscriptenData<'a> { +impl EmscriptenData { pub fn new( - instance: &'a mut Instance, - globals: &'a EmscriptenGlobalsData, + globals: EmscriptenGlobalsData, mapped_dirs: HashMap, - ) -> EmscriptenData<'a> { - let malloc = instance - .exports - .get_native_function("_malloc") - .or(instance.exports.get_native_function("malloc")) - .ok(); - let free = instance - .exports - .get_native_function("_free") - .or(instance.exports.get_native_function("free")) - .ok(); - let memalign = instance - .exports - .get_native_function("_memalign") - .or(instance.exports.get_native_function("memalign")) - .ok(); - let memset = instance - .exports - .get_native_function("_memset") - .or(instance.exports.get_native_function("memset")) - .ok(); - let stack_alloc = instance.exports.get_native_function("stackAlloc").ok(); - - let dyn_call_i = instance.exports.get_native_function("dynCall_i").ok(); - let dyn_call_ii = instance.exports.get_native_function("dynCall_ii").ok(); - let dyn_call_iii = instance.exports.get_native_function("dynCall_iii").ok(); - let dyn_call_iiii = instance.exports.get_native_function("dynCall_iiii").ok(); - let dyn_call_iifi = instance.exports.get_native_function("dynCall_iifi").ok(); - let dyn_call_v = instance.exports.get_native_function("dynCall_v").ok(); - let dyn_call_vi = instance.exports.get_native_function("dynCall_vi").ok(); - let dyn_call_vii = instance.exports.get_native_function("dynCall_vii").ok(); - let dyn_call_viii = instance.exports.get_native_function("dynCall_viii").ok(); - let dyn_call_viiii = instance.exports.get_native_function("dynCall_viiii").ok(); - - // round 2 - let dyn_call_dii = instance.exports.get_native_function("dynCall_dii").ok(); - let dyn_call_diiii = instance.exports.get_native_function("dynCall_diiii").ok(); - let dyn_call_iiiii = instance.exports.get_native_function("dynCall_iiiii").ok(); - let dyn_call_iiiiii = instance.exports.get_native_function("dynCall_iiiiii").ok(); - let dyn_call_iiiiiii = instance.exports.get_native_function("dynCall_iiiiiii").ok(); - let dyn_call_iiiiiiii = instance - .exports - .get_native_function("dynCall_iiiiiiii") - .ok(); - let dyn_call_iiiiiiiii = instance - .exports - .get_native_function("dynCall_iiiiiiiii") - .ok(); - let dyn_call_iiiiiiiiii = instance - .exports - .get_native_function("dynCall_iiiiiiiiii") - .ok(); - let dyn_call_iiiiiiiiiii = instance - .exports - .get_native_function("dynCall_iiiiiiiiiii") - .ok(); - let dyn_call_vd = instance.exports.get_native_function("dynCall_vd").ok(); - let dyn_call_viiiii = instance.exports.get_native_function("dynCall_viiiii").ok(); - let dyn_call_viiiiii = instance.exports.get_native_function("dynCall_viiiiii").ok(); - let dyn_call_viiiiiii = instance - .exports - .get_native_function("dynCall_viiiiiii") - .ok(); - let dyn_call_viiiiiiii = instance - .exports - .get_native_function("dynCall_viiiiiiii") - .ok(); - let dyn_call_viiiiiiiii = instance - .exports - .get_native_function("dynCall_viiiiiiiii") - .ok(); - let dyn_call_viiiiiiiiii = instance - .exports - .get_native_function("dynCall_viiiiiiiiii") - .ok(); - let dyn_call_iij = instance.exports.get_native_function("dynCall_iij").ok(); - let dyn_call_iji = instance.exports.get_native_function("dynCall_iji").ok(); - let dyn_call_iiji = instance.exports.get_native_function("dynCall_iiji").ok(); - let dyn_call_iiijj = instance.exports.get_native_function("dynCall_iiijj").ok(); - let dyn_call_j = instance.exports.get_native_function("dynCall_j").ok(); - let dyn_call_ji = instance.exports.get_native_function("dynCall_ji").ok(); - let dyn_call_jii = instance.exports.get_native_function("dynCall_jii").ok(); - let dyn_call_jij = instance.exports.get_native_function("dynCall_jij").ok(); - let dyn_call_jjj = instance.exports.get_native_function("dynCall_jjj").ok(); - let dyn_call_viiij = instance.exports.get_native_function("dynCall_viiij").ok(); - let dyn_call_viiijiiii = instance - .exports - .get_native_function("dynCall_viiijiiii") - .ok(); - let dyn_call_viiijiiiiii = instance - .exports - .get_native_function("dynCall_viiijiiiiii") - .ok(); - let dyn_call_viij = instance.exports.get_native_function("dynCall_viij").ok(); - let dyn_call_viiji = instance.exports.get_native_function("dynCall_viiji").ok(); - let dyn_call_viijiii = instance.exports.get_native_function("dynCall_viijiii").ok(); - let dyn_call_viijj = instance.exports.get_native_function("dynCall_viijj").ok(); - let dyn_call_vj = instance.exports.get_native_function("dynCall_vj").ok(); - let dyn_call_vjji = instance.exports.get_native_function("dynCall_vjji").ok(); - let dyn_call_vij = instance.exports.get_native_function("dynCall_vij").ok(); - let dyn_call_viji = instance.exports.get_native_function("dynCall_viji").ok(); - let dyn_call_vijiii = instance.exports.get_native_function("dynCall_vijiii").ok(); - let dyn_call_vijj = instance.exports.get_native_function("dynCall_vijj").ok(); - let dyn_call_viid = instance.exports.get_native_function("dynCall_viid").ok(); - let dyn_call_vidd = instance.exports.get_native_function("dynCall_vidd").ok(); - let dyn_call_viidii = instance.exports.get_native_function("dynCall_viidii").ok(); - let dyn_call_viidddddddd = instance - .exports - .get_native_function("dynCall_viidddddddd") - .ok(); - - let stack_save = instance.exports.get_native_function("stackSave").ok(); - let stack_restore = instance.exports.get_native_function("stackRestore").ok(); - let set_threw = instance - .exports - .get_native_function("_setThrew") - .or(instance.exports.get_native_function("setThrew")) - .ok(); - + ) -> EmscriptenData { EmscriptenData { globals, - - malloc, - free, - memalign, - memset, - stack_alloc, - jumps: Vec::new(), - opened_dirs: HashMap::new(), - - dyn_call_i, - dyn_call_ii, - dyn_call_iii, - dyn_call_iiii, - dyn_call_iifi, - dyn_call_v, - dyn_call_vi, - dyn_call_vii, - dyn_call_viii, - dyn_call_viiii, - - // round 2 - dyn_call_dii, - dyn_call_diiii, - dyn_call_iiiii, - dyn_call_iiiiii, - dyn_call_iiiiiii, - dyn_call_iiiiiiii, - dyn_call_iiiiiiiii, - dyn_call_iiiiiiiiii, - dyn_call_iiiiiiiiiii, - dyn_call_vd, - dyn_call_viiiii, - dyn_call_viiiiii, - dyn_call_viiiiiii, - dyn_call_viiiiiiii, - dyn_call_viiiiiiiii, - dyn_call_viiiiiiiiii, - dyn_call_iij, - dyn_call_iji, - dyn_call_iiji, - dyn_call_iiijj, - dyn_call_j, - dyn_call_ji, - dyn_call_jii, - dyn_call_jij, - dyn_call_jjj, - dyn_call_viiij, - dyn_call_viiijiiii, - dyn_call_viiijiiiiii, - dyn_call_viij, - dyn_call_viiji, - dyn_call_viijiii, - dyn_call_viijj, - dyn_call_vj, - dyn_call_vjji, - dyn_call_vij, - dyn_call_viji, - dyn_call_vijiii, - dyn_call_vijj, - dyn_call_viid, - dyn_call_vidd, - dyn_call_viidii, - dyn_call_viidddddddd, temp_ret_0: 0, - - stack_save, - stack_restore, - set_threw, mapped_dirs, + ..Default::default() } } } @@ -473,11 +355,8 @@ pub fn run_emscripten_instance( path: &str, args: Vec<&str>, entrypoint: Option, - mapped_dirs: Vec<(String, PathBuf)>, ) -> Result<(), RuntimeError> { - let mut data = EmscriptenData::new(instance, &globals.data, mapped_dirs.into_iter().collect()); env.set_memory(globals.memory.clone()); - env.set_data(&mut data as *mut _ as *mut c_void); set_up_emscripten(instance)?; // println!("running emscripten instance"); @@ -533,6 +412,7 @@ pub fn emscripten_set_up_memory( Ok(()) } +#[derive(Debug, Clone, Default)] pub struct EmscriptenGlobalsData { abort: u64, // Env namespace diff --git a/lib/emscripten/src/memory.rs b/lib/emscripten/src/memory.rs index 066cb166965..70505019f25 100644 --- a/lib/emscripten/src/memory.rs +++ b/lib/emscripten/src/memory.rs @@ -73,8 +73,10 @@ pub fn sbrk(ctx: &mut EmEnv, increment: i32) -> i32 { debug!("emscripten::sbrk"); // let old_dynamic_top = 0; // let new_dynamic_top = 0; - let globals = get_emscripten_data(ctx).globals; - let dynamictop_ptr = (globals.dynamictop_ptr) as usize; + let dynamictop_ptr = { + let globals = &get_emscripten_data(ctx).globals; + (globals.dynamictop_ptr) as usize + }; let old_dynamic_top = ctx.memory(0).view::()[dynamictop_ptr].get() as i32; let new_dynamic_top: i32 = old_dynamic_top + increment; let total_memory = _emscripten_get_heap_size(ctx) as i32; diff --git a/lib/emscripten/src/utils.rs b/lib/emscripten/src/utils.rs index c3d24f03940..aa734cc0be0 100644 --- a/lib/emscripten/src/utils.rs +++ b/lib/emscripten/src/utils.rs @@ -124,8 +124,7 @@ pub unsafe fn copy_cstr_into_wasm(ctx: &mut EmEnv, cstr: *const c_char) -> u32 { pub unsafe fn allocate_on_stack<'a, T: Copy>(ctx: &'a mut EmEnv, count: u32) -> (u32, &'a mut [T]) { let offset = get_emscripten_data(ctx) - .stack_alloc - .as_ref() + .stack_alloc_ref() .unwrap() .call(count * (size_of::() as u32)) .unwrap(); From 6aab77e503e8bd011911526733858dce37112dd5 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 17 Nov 2020 16:25:07 -0800 Subject: [PATCH 27/39] Add default impl for `WasmerEnv::finish` remove macro --- lib/api/src/env.rs | 72 +++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/lib/api/src/env.rs b/lib/api/src/env.rs index 6373d05598b..e489597870e 100644 --- a/lib/api/src/env.rs +++ b/lib/api/src/env.rs @@ -60,49 +60,38 @@ pub trait WasmerEnv { /// /// This function is called after `Instance` is created but before it is /// returned to the user via `Instance::new`. - fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError>; -} - -macro_rules! impl_wasmer_env { - ($name:ty) => { - impl WasmerEnv for $name { - fn finish( - &mut self, - _instance: &crate::Instance, - ) -> Result<(), crate::HostEnvInitError> { - Ok(()) - } - } - }; + fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { + Ok(()) + } } -impl_wasmer_env!(u8); -impl_wasmer_env!(i8); -impl_wasmer_env!(u16); -impl_wasmer_env!(i16); -impl_wasmer_env!(u32); -impl_wasmer_env!(i32); -impl_wasmer_env!(u64); -impl_wasmer_env!(i64); -impl_wasmer_env!(u128); -impl_wasmer_env!(i128); -impl_wasmer_env!(f32); -impl_wasmer_env!(f64); -impl_wasmer_env!(usize); -impl_wasmer_env!(isize); -impl_wasmer_env!(char); -impl_wasmer_env!(bool); -impl_wasmer_env!(String); -impl_wasmer_env!(::std::sync::atomic::AtomicBool); -impl_wasmer_env!(::std::sync::atomic::AtomicI8); -impl_wasmer_env!(::std::sync::atomic::AtomicU8); -impl_wasmer_env!(::std::sync::atomic::AtomicI16); -impl_wasmer_env!(::std::sync::atomic::AtomicU16); -impl_wasmer_env!(::std::sync::atomic::AtomicI32); -impl_wasmer_env!(::std::sync::atomic::AtomicU32); -impl_wasmer_env!(::std::sync::atomic::AtomicI64); -impl_wasmer_env!(::std::sync::atomic::AtomicUsize); -impl_wasmer_env!(::std::sync::atomic::AtomicIsize); +impl WasmerEnv for u8 {} +impl WasmerEnv for i8 {} +impl WasmerEnv for u16 {} +impl WasmerEnv for i16 {} +impl WasmerEnv for u32 {} +impl WasmerEnv for i32 {} +impl WasmerEnv for u64 {} +impl WasmerEnv for i64 {} +impl WasmerEnv for u128 {} +impl WasmerEnv for i128 {} +impl WasmerEnv for f32 {} +impl WasmerEnv for f64 {} +impl WasmerEnv for usize {} +impl WasmerEnv for isize {} +impl WasmerEnv for char {} +impl WasmerEnv for bool {} +impl WasmerEnv for String {} +impl WasmerEnv for ::std::sync::atomic::AtomicBool {} +impl WasmerEnv for ::std::sync::atomic::AtomicI8 {} +impl WasmerEnv for ::std::sync::atomic::AtomicU8 {} +impl WasmerEnv for ::std::sync::atomic::AtomicI16 {} +impl WasmerEnv for ::std::sync::atomic::AtomicU16 {} +impl WasmerEnv for ::std::sync::atomic::AtomicI32 {} +impl WasmerEnv for ::std::sync::atomic::AtomicU32 {} +impl WasmerEnv for ::std::sync::atomic::AtomicI64 {} +impl WasmerEnv for ::std::sync::atomic::AtomicUsize {} +impl WasmerEnv for ::std::sync::atomic::AtomicIsize {} impl WasmerEnv for &'static mut T { fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { @@ -110,7 +99,6 @@ impl WasmerEnv for &'static mut T { } } -// TODO: do we want to use mutex/atomics here? like old WASI solution /// Lazily init an item pub struct LazyInit { /// The data to be initialized From 3580f165e8af206e6089e266af425689951a08fc Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Tue, 17 Nov 2020 17:14:11 -0800 Subject: [PATCH 28/39] Rename `WasmerEnv::finish` to `WasmerEnv::init_with_instance` --- lib/api/src/env.rs | 8 ++++---- lib/api/src/externals/function.rs | 8 ++++++-- lib/c-api/src/wasm_c_api/externals/function.rs | 5 ++++- lib/c-api/wasmer_wasm.h | 3 +++ lib/derive/src/lib.rs | 4 ++-- lib/emscripten/src/lib.rs | 4 ++-- tests/compilers/imports.rs | 4 ++-- tests/compilers/native_functions.rs | 4 ++-- 8 files changed, 25 insertions(+), 15 deletions(-) diff --git a/lib/api/src/env.rs b/lib/api/src/env.rs index e489597870e..43ef59005e1 100644 --- a/lib/api/src/env.rs +++ b/lib/api/src/env.rs @@ -47,7 +47,7 @@ impl From for HostEnvInitError { /// } /// /// impl WasmerEnv for MyEnv { -/// fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { +/// fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { /// let memory = instance.exports.get_memory("memory").unwrap(); /// self.memory.initialize(memory.clone()); /// Ok(()) @@ -60,7 +60,7 @@ pub trait WasmerEnv { /// /// This function is called after `Instance` is created but before it is /// returned to the user via `Instance::new`. - fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { + fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } } @@ -94,8 +94,8 @@ impl WasmerEnv for ::std::sync::atomic::AtomicUsize {} impl WasmerEnv for ::std::sync::atomic::AtomicIsize {} impl WasmerEnv for &'static mut T { - fn finish(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { - (*self).finish(instance) + fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { + (*self).init_with_instance(instance) } } diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index a86753b81bb..87db2f6d58f 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -145,7 +145,9 @@ impl Function { }; // TODO: look into removing transmute by changing API type signatures let function_ptr = Some(unsafe { - std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish) + std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>( + Env::init_with_instance, + ) }); Self { @@ -253,7 +255,9 @@ impl Function { }; // TODO: look into removing transmute by changing API type signatures let function_ptr = Some(unsafe { - std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>(Env::finish) + std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>( + Env::init_with_instance, + ) }); let signature = function.ty(); diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs index feea15ababd..7e40e988da6 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -116,7 +116,10 @@ pub unsafe extern "C" fn wasm_func_new_with_env( } impl wasmer::WasmerEnv for WrapperEnv { - fn finish(&mut self, _instance: &wasmer::Instance) -> Result<(), wasmer::HostEnvInitError> { + fn init_with_instance( + &mut self, + _instance: &wasmer::Instance, + ) -> Result<(), wasmer::HostEnvInitError> { Ok(()) } } diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 44323f020d4..4bc65f62d46 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -29,6 +29,9 @@ # define DEPRECATED(message) __declspec(deprecated(message)) #endif +// The `jit` feature has been enabled for this build. +#define WASMER_JIT_ENABLED + // The `compiler` feature has been enabled for this build. #define WASMER_COMPILER_ENABLED diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index f8f88eff7d1..923c9f2f089 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -42,7 +42,7 @@ fn impl_wasmer_env(input: &DeriveInput) -> TokenStream { set_dummy(quote! { impl ::wasmer::WasmerEnv for #struct_name { - fn finish(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> { + fn init_with_instance(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> { Ok(()) } } @@ -154,7 +154,7 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { } let trait_methods = quote! { - fn finish(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> { + fn init_with_instance(&mut self, instance: &::wasmer::Instance) -> Result<(), ::wasmer::HostEnvInitError> { #(#finish)* Ok(()) } diff --git a/lib/emscripten/src/lib.rs b/lib/emscripten/src/lib.rs index 60fbcfd3b33..b68db93e1d2 100644 --- a/lib/emscripten/src/lib.rs +++ b/lib/emscripten/src/lib.rs @@ -77,9 +77,9 @@ pub struct EmEnv { } impl WasmerEnv for EmEnv { - fn finish(&mut self, instance: &Instance) -> Result<(), wasmer::HostEnvInitError> { + fn init_with_instance(&mut self, instance: &Instance) -> Result<(), wasmer::HostEnvInitError> { let mut ed = self.data.lock().unwrap(); - ed.finish(instance)?; + ed.init_with_instance(instance)?; Ok(()) } } diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index 0aee4c15258..c446ff5200f 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -97,7 +97,7 @@ fn dynamic_function_with_env() -> Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } } @@ -230,7 +230,7 @@ fn static_function_with_env() -> Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } } diff --git a/tests/compilers/native_functions.rs b/tests/compilers/native_functions.rs index 56d419516f0..910f215de53 100644 --- a/tests/compilers/native_functions.rs +++ b/tests/compilers/native_functions.rs @@ -116,7 +116,7 @@ fn static_host_function_with_env() -> anyhow::Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } } @@ -196,7 +196,7 @@ fn dynamic_host_function_with_env() -> anyhow::Result<()> { } impl WasmerEnv for Env { - fn finish(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { + fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { Ok(()) } } From 7131caa8d9ee806dd2fd7df4ab5e77365c8d4ff0 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 18 Nov 2020 11:31:57 -0800 Subject: [PATCH 29/39] Implement `WasmerEnv` for `dyn Any` --- lib/api/src/env.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/api/src/env.rs b/lib/api/src/env.rs index 43ef59005e1..8d03c981961 100644 --- a/lib/api/src/env.rs +++ b/lib/api/src/env.rs @@ -92,6 +92,12 @@ impl WasmerEnv for ::std::sync::atomic::AtomicU32 {} impl WasmerEnv for ::std::sync::atomic::AtomicI64 {} impl WasmerEnv for ::std::sync::atomic::AtomicUsize {} impl WasmerEnv for ::std::sync::atomic::AtomicIsize {} +impl WasmerEnv for dyn ::std::any::Any {} +impl WasmerEnv for Box { + fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { + (&mut **self).init_with_instance(instance) + } +} impl WasmerEnv for &'static mut T { fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> { From 15e88a11957f3b0d9e7e56e3284b323bac9e96a7 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 18 Nov 2020 12:12:24 -0800 Subject: [PATCH 30/39] Clean up error message in proc macro, improve docs on WasmerEnv --- lib/api/src/env.rs | 16 ++++++++++++++-- lib/derive/src/lib.rs | 8 ++++---- lib/derive/tests/compile-fail/no-lazy-init.rs | 4 ++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/api/src/env.rs b/lib/api/src/env.rs index 8d03c981961..53c37d6d2ea 100644 --- a/lib/api/src/env.rs +++ b/lib/api/src/env.rs @@ -15,13 +15,20 @@ impl From for HostEnvInitError { } } -/// Prototype trait for finishing envs. +/// Trait for initializing the environments passed to host functions after +/// instantiation but before execution. +/// +/// This is useful for filling an environment with data that can only be accesed +/// after instantiation. For example, exported items such as memories and +/// functions which don't exist prior to instantiation can be accessed here so +/// that host functions can use them. +/// /// # Examples /// /// This trait can be derived like so: /// /// ``` -/// # use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc}; +/// use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc}; /// /// #[derive(WasmerEnv)] /// pub struct MyEnvWithNoInstanceData { @@ -39,6 +46,11 @@ impl From for HostEnvInitError { /// /// ``` /// +/// When deriving `WasmerEnv`, you must wrap your types to be initialized in +/// [`LazyInit`]. The derive macro will also generate helper methods of the form +/// `_ref` and `_ref_unchecked` for easy access to the +/// data. +/// /// This trait can also be implemented manually: /// ``` /// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError}; diff --git a/lib/derive/src/lib.rs b/lib/derive/src/lib.rs index 923c9f2f089..ea9c617751b 100644 --- a/lib/derive/src/lib.rs +++ b/lib/derive/src/lib.rs @@ -141,9 +141,9 @@ fn derive_struct_fields(data: &DataStruct) -> (TokenStream, TokenStream) { } } else { abort!( - span, - "Expected `name` field on export attribute because field does not have a name. For example: `#[wasmer(export(name = \"wasm_ident\"))]`.", - ); + span, + "Expected `name` field on export attribute because field does not have a name. For example: `#[wasmer(export(name = \"wasm_ident\"))]`.", + ); } }; @@ -178,7 +178,7 @@ fn get_identifier(ty: &Type) -> TokenStream { if ident != "LazyInit" { abort!( ident, - "WasmerEnv derive expects all `exports` to be wrapped in `LazyInit`" + "WasmerEnv derive expects all `export`s to be wrapped in `LazyInit`" ); } if let PathArguments::AngleBracketed(AngleBracketedGenericArguments { diff --git a/lib/derive/tests/compile-fail/no-lazy-init.rs b/lib/derive/tests/compile-fail/no-lazy-init.rs index 56ba024e286..90f919005c0 100644 --- a/lib/derive/tests/compile-fail/no-lazy-init.rs +++ b/lib/derive/tests/compile-fail/no-lazy-init.rs @@ -5,7 +5,7 @@ use wasmer::{LazyInit, WasmerEnv, Memory}; #[derive(WasmerEnv)] struct ExportNotWrappedInLazyInit { #[wasmer(export)] - memory: Memory, //~ WasmerEnv derive expects all `exports` to be wrapped in `LazyInit` + memory: Memory, //~ WasmerEnv derive expects all `export`s to be wrapped in `LazyInit` } -fn main() {} \ No newline at end of file +fn main() {} From 85169f699604b0a0348b5a5d352088ae640af23d Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 18 Nov 2020 14:23:40 -0800 Subject: [PATCH 31/39] Add misc clean ups and corrections --- lib/api/src/instance.rs | 2 +- .../src/wasm_c_api/externals/function.rs | 10 +--- lib/engine/src/artifact.rs | 18 +++--- lib/vm/src/export.rs | 2 +- lib/vm/src/instance.rs | 56 +++++++++---------- 5 files changed, 38 insertions(+), 50 deletions(-) diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index ca002e7e785..590ae2886b7 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -124,7 +124,7 @@ impl Instance { }) .collect::(); - let instance = Self { + let mut instance = Self { handle, module: module.clone(), exports, diff --git a/lib/c-api/src/wasm_c_api/externals/function.rs b/lib/c-api/src/wasm_c_api/externals/function.rs index 7e40e988da6..bd70b3fc650 100644 --- a/lib/c-api/src/wasm_c_api/externals/function.rs +++ b/lib/c-api/src/wasm_c_api/externals/function.rs @@ -101,6 +101,7 @@ pub unsafe extern "C" fn wasm_func_new_with_env( let func_sig = &function_type.inner().function_type; let num_rets = func_sig.results().len(); + #[derive(wasmer::WasmerEnv)] #[repr(C)] struct WrapperEnv { env: *mut c_void, @@ -115,15 +116,6 @@ pub unsafe extern "C" fn wasm_func_new_with_env( } } - impl wasmer::WasmerEnv for WrapperEnv { - fn init_with_instance( - &mut self, - _instance: &wasmer::Instance, - ) -> Result<(), wasmer::HostEnvInitError> { - Ok(()) - } - } - let inner_callback = move |env: &mut WrapperEnv, args: &[Val]| -> Result, RuntimeError> { let processed_args: wasm_val_vec_t = args diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index 40bca8abc99..1e1b5da1060 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -105,18 +105,18 @@ pub trait Artifact: Send + Sync + Upcastable { ) .map_err(InstantiationError::Link)?; - let mut thunks = vec![]; - // ------------ - for (func_init, func) in imports + // Get the `WasmerEnv::init_with_instance` function pointers and the pointers + // to the envs to call it on. + let import_initializers: Vec<(_, _)> = imports .host_function_env_initializers .values() .cloned() .zip(imports.functions.values()) - { - let host_env = func.environment.host_env; - thunks.push((func_init, host_env)); - } - // ------------ + .map(|(func_init, func)| { + let host_env = func.environment.host_env; + (func_init, host_env) + }) + .collect(); // Get pointers to where metadata about local memories should live in VM memory. let memory_definition_locations = @@ -151,7 +151,7 @@ pub trait Artifact: Send + Sync + Upcastable { imports, self.signatures().clone(), host_state, - thunks, + import_initializers, ) .map_err(|trap| InstantiationError::Start(RuntimeError::from_trap(trap)))?; Ok(handle) diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index d12ab6579b7..f6ea9305b72 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -31,7 +31,7 @@ pub struct ExportFunction { pub address: *const VMFunctionBody, /// Pointer to the containing `VMContext`. pub vmctx: VMFunctionEnvironment, - /// Function pointer to `WasmerEnv::finish(&mut self, instance: &Instance)`. + /// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`. /// /// This function is called to finish setting up the environment after /// we create the `api::Instance`. diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index ddfb8804fdb..1eb8b026471 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -63,6 +63,13 @@ cfg_if::cfg_if! { } } +/// This type holds thunks (delayed computations) for initializing the imported +/// function's environments with the [`Instance`]. +pub(crate) type ImportInitializerThunks = Vec<( + Option Result<(), *mut std::ffi::c_void>>, + *mut std::ffi::c_void, +)>; + /// A WebAssembly instance. /// /// This is repr(C) to ensure that the vmctx field is last. @@ -104,19 +111,13 @@ pub(crate) struct Instance { /// Handler run when `SIGBUS`, `SIGFPE`, `SIGILL`, or `SIGSEGV` are caught by the instance thread. pub(crate) signal_handler: Cell>>, - /// TODO: document this - /// Functions to initialize the host environments in the imports. - /// Do we want to drain this? There's probably no reason to keep this memory - /// around once we've used it. + /// Functions to initialize the host environments in the imports and pointers + /// to the environments. + /// These function pointers all come from `WasmerEnv::init_with_instance`. /// + /// TODO: /// Be sure to test with serialize/deserialize and imported functions from other Wasm modules. - import_initializers: Vec<( - Option< - fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, - >, - *mut std::ffi::c_void, - )>, - + import_initializers: ImportInitializerThunks, /// Additional context used by compiled wasm code. This field is last, and /// represents a dynamically-sized array that extends beyond the nominal /// end of the struct (similar to a flexible array member). @@ -923,15 +924,7 @@ impl InstanceHandle { imports: Imports, vmshared_signatures: BoxedSlice, host_state: Box, - import_initializers: Vec<( - Option< - fn( - *mut std::ffi::c_void, - *const std::ffi::c_void, - ) -> Result<(), *mut std::ffi::c_void>, - >, - *mut std::ffi::c_void, - )>, + import_initializers: ImportInitializerThunks, ) -> Result { let instance_ptr = instance_ptr.cast::().as_ptr(); @@ -1164,27 +1157,30 @@ impl InstanceHandle { /// Initializes the host environments. /// /// # Safety - /// - This function should only be called once (TODO: we can enforce this by draining the vec...) /// - This function must be called with the correct `Err` type parameter: the error type is not /// visible to code in `wasmer_vm`, so it's the caller's responsibility to ensure these /// functions are called with the correct type. pub unsafe fn initialize_host_envs( - &self, + &mut self, instance_ptr: *const std::ffi::c_void, ) -> Result<(), Err> { - for (func, env) in self.instance().import_initializers.iter() { - if let Some(f) = func { + use std::ffi; + let instance = &mut *self.instance; + for (func, env) in instance.import_initializers.drain(..) { + if let Some(ref f) = func { // transmute our function pointer into one with the correct error type let f = std::mem::transmute::< - &fn( - *mut std::ffi::c_void, - *const std::ffi::c_void, - ) -> Result<(), *mut std::ffi::c_void>, - &fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), Err>, + &fn(*mut ffi::c_void, *const ffi::c_void) -> Result<(), *mut ffi::c_void>, + &fn(*mut ffi::c_void, *const ffi::c_void) -> Result<(), Err>, >(f); - f(*env, instance_ptr)?; + f(env, instance_ptr)?; } } + // free memory + instance.import_initializers.shrink_to_fit(); + // TODO: remove, just here to double check my work + assert_eq!(instance.import_initializers.capacity(), 0); + assert_eq!(instance.import_initializers.len(), 0); Ok(()) } From 37d0c364e629c9a2e2063f3d84170ef2e34976c1 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 18 Nov 2020 15:21:59 -0800 Subject: [PATCH 32/39] Clean up code, reduce memory usage, improve correctness --- lib/engine/src/artifact.rs | 37 +++++++++---------- lib/engine/src/resolver.rs | 1 - lib/vm/src/export.rs | 6 ++-- lib/vm/src/imports.rs | 55 ++++++++++++++++++++--------- lib/vm/src/instance.rs | 24 ++++++------- tests/compilers/imports.rs | 16 ++------- tests/compilers/native_functions.rs | 16 ++------- 7 files changed, 71 insertions(+), 84 deletions(-) diff --git a/lib/engine/src/artifact.rs b/lib/engine/src/artifact.rs index 1e1b5da1060..43ff9506c06 100644 --- a/lib/engine/src/artifact.rs +++ b/lib/engine/src/artifact.rs @@ -96,27 +96,22 @@ pub trait Artifact: Send + Sync + Upcastable { let module = self.module(); let (instance_ptr, offsets) = InstanceHandle::allocate_instance(&module); - let imports = resolve_imports( - &module, - resolver, - &self.finished_dynamic_function_trampolines(), - self.memory_styles(), - self.table_styles(), - ) - .map_err(InstantiationError::Link)?; - - // Get the `WasmerEnv::init_with_instance` function pointers and the pointers - // to the envs to call it on. - let import_initializers: Vec<(_, _)> = imports - .host_function_env_initializers - .values() - .cloned() - .zip(imports.functions.values()) - .map(|(func_init, func)| { - let host_env = func.environment.host_env; - (func_init, host_env) - }) - .collect(); + let (imports, import_initializers) = { + let mut imports = resolve_imports( + &module, + resolver, + &self.finished_dynamic_function_trampolines(), + self.memory_styles(), + self.table_styles(), + ) + .map_err(InstantiationError::Link)?; + + // Get the `WasmerEnv::init_with_instance` function pointers and the pointers + // to the envs to call it on. + let import_initializers: Vec<(_, _)> = imports.get_import_initializers(); + + (imports, import_initializers) + }; // Get pointers to where metadata about local memories should live in VM memory. let memory_definition_locations = diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index cdb65741297..59de18d5f0d 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -125,7 +125,6 @@ pub fn resolve_imports( _table_styles: &PrimaryMap, ) -> Result { let mut function_imports = PrimaryMap::with_capacity(module.num_imported_functions); - // TODO: account for imported functions without env / from other Wasm instances let mut host_function_env_initializers = PrimaryMap::with_capacity(module.num_imported_functions); let mut table_imports = PrimaryMap::with_capacity(module.num_imported_tables); diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index f6ea9305b72..eb8956733ee 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -2,6 +2,7 @@ // Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md use crate::global::Global; +use crate::instance::ImportInitializerFuncPtr; use crate::memory::{Memory, MemoryStyle}; use crate::table::{Table, TableStyle}; use crate::vmcontext::{VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, VMTrampoline}; @@ -37,10 +38,7 @@ pub struct ExportFunction { /// we create the `api::Instance`. // META: if you have a better idea of how to get this function to where it // needs to be, please let me know. - pub function_ptr: Option< - // TODO: review the return value here... - fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, - >, + pub function_ptr: Option, /// The function type, used for compatibility checking. pub signature: FunctionType, /// The function kind (specifies the calling convention for the function). diff --git a/lib/vm/src/imports.rs b/lib/vm/src/imports.rs index 510830e43e2..af1b4bf4c02 100644 --- a/lib/vm/src/imports.rs +++ b/lib/vm/src/imports.rs @@ -1,6 +1,7 @@ // This file contains code from external sources. // Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md +use crate::instance::{ImportInitializerFuncPtr, ImportInitializerThunks}; use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport}; use wasmer_types::entity::{BoxedSlice, PrimaryMap}; use wasmer_types::{FunctionIndex, GlobalIndex, MemoryIndex, TableIndex}; @@ -14,12 +15,10 @@ pub struct Imports { /// Initializers for host function environments. This is split out from `functions` /// because the generated code never needs to touch this and the extra wasted /// space may affect Wasm runtime performance due to increased cache pressure. - pub host_function_env_initializers: BoxedSlice< - FunctionIndex, - Option< - fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, - >, - >, + /// + /// We make it optional so that we can free the data after use. + pub host_function_env_initializers: + Option>>, /// Resolved addresses for imported tables. pub tables: BoxedSlice, @@ -35,22 +34,14 @@ impl Imports { /// Construct a new `Imports` instance. pub fn new( function_imports: PrimaryMap, - host_function_env_initializers: PrimaryMap< - FunctionIndex, - Option< - fn( - *mut std::ffi::c_void, - *const std::ffi::c_void, - ) -> Result<(), *mut std::ffi::c_void>, - >, - >, + host_function_env_initializers: PrimaryMap>, table_imports: PrimaryMap, memory_imports: PrimaryMap, global_imports: PrimaryMap, ) -> Self { Self { functions: function_imports.into_boxed_slice(), - host_function_env_initializers: host_function_env_initializers.into_boxed_slice(), + host_function_env_initializers: Some(host_function_env_initializers.into_boxed_slice()), tables: table_imports.into_boxed_slice(), memories: memory_imports.into_boxed_slice(), globals: global_imports.into_boxed_slice(), @@ -61,10 +52,40 @@ impl Imports { pub fn none() -> Self { Self { functions: PrimaryMap::new().into_boxed_slice(), - host_function_env_initializers: PrimaryMap::new().into_boxed_slice(), + host_function_env_initializers: Some(PrimaryMap::new().into_boxed_slice()), tables: PrimaryMap::new().into_boxed_slice(), memories: PrimaryMap::new().into_boxed_slice(), globals: PrimaryMap::new().into_boxed_slice(), } } + + /// Get the `WasmerEnv::init_with_instance` function pointers and the pointers + /// to the envs to call it on. + /// + /// This function can only be called once, it deletes the data it returns after + /// returning it to ensure that it's not called more than once. + pub fn get_import_initializers(&mut self) -> ImportInitializerThunks { + let result = if let Some(inner) = &self.host_function_env_initializers { + inner + .values() + .cloned() + .zip(self.functions.values()) + .map(|(func_init, func)| { + let host_env = if func_init.is_some() { + // this access is correct because we know that only functions with + // host envs have a value in `func_init`. + unsafe { func.environment.host_env } + } else { + std::ptr::null_mut() + }; + (func_init, host_env) + }) + .collect() + } else { + vec![] + }; + // ensure we only call these functions once and free this now useless memory. + self.host_function_env_initializers = None; + result + } } diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 1eb8b026471..7955b71ede0 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -63,12 +63,15 @@ cfg_if::cfg_if! { } } +/// The function pointer to call with data and an [`Instance`] pointer to +/// finish initializing the host env. +pub(crate) type ImportInitializerFuncPtr = + fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>; + /// This type holds thunks (delayed computations) for initializing the imported /// function's environments with the [`Instance`]. -pub(crate) type ImportInitializerThunks = Vec<( - Option Result<(), *mut std::ffi::c_void>>, - *mut std::ffi::c_void, -)>; +pub(crate) type ImportInitializerThunks = + Vec<(Option, *mut std::ffi::c_void)>; /// A WebAssembly instance. /// @@ -159,13 +162,11 @@ impl Instance { unsafe { &*self.imported_functions_ptr().add(index) } } - /// TODO: document this + /// Get the import initializer func at the given index if it exists. fn imported_function_env_initializer( &self, index: FunctionIndex, - ) -> Option< - fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>, - > { + ) -> Option { self.import_initializers[index.as_u32() as usize].0 } @@ -1170,17 +1171,14 @@ impl InstanceHandle { if let Some(ref f) = func { // transmute our function pointer into one with the correct error type let f = std::mem::transmute::< - &fn(*mut ffi::c_void, *const ffi::c_void) -> Result<(), *mut ffi::c_void>, + &ImportInitializerFuncPtr, &fn(*mut ffi::c_void, *const ffi::c_void) -> Result<(), Err>, >(f); f(env, instance_ptr)?; } } - // free memory + // free memory now that it's empty. instance.import_initializers.shrink_to_fit(); - // TODO: remove, just here to double check my work - assert_eq!(instance.import_initializers.capacity(), 0); - assert_eq!(instance.import_initializers.len(), 0); Ok(()) } diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index c446ff5200f..610284b31a4 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -86,7 +86,7 @@ fn dynamic_function_with_env() -> Result<()> { let store = get_store(false); let module = get_module(&store)?; - #[derive(Clone)] + #[derive(WasmerEnv, Clone)] struct Env(Arc); impl std::ops::Deref for Env { @@ -96,12 +96,6 @@ fn dynamic_function_with_env() -> Result<()> { } } - impl WasmerEnv for Env { - fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { - Ok(()) - } - } - let env: Env = Env(Arc::new(AtomicUsize::new(0))); Instance::new( &module, @@ -219,7 +213,7 @@ fn static_function_with_env() -> Result<()> { let store = get_store(false); let module = get_module(&store)?; - #[derive(Clone)] + #[derive(WasmerEnv, Clone)] struct Env(Arc); impl std::ops::Deref for Env { @@ -229,12 +223,6 @@ fn static_function_with_env() -> Result<()> { } } - impl WasmerEnv for Env { - fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { - Ok(()) - } - } - let env: Env = Env(Arc::new(AtomicUsize::new(0))); Instance::new( &module, diff --git a/tests/compilers/native_functions.rs b/tests/compilers/native_functions.rs index 910f215de53..b93a47df53a 100644 --- a/tests/compilers/native_functions.rs +++ b/tests/compilers/native_functions.rs @@ -105,7 +105,7 @@ fn static_host_function_with_env() -> anyhow::Result<()> { Ok((d * 4.0, c * 3.0, b * 2, a * 1)) } - #[derive(Clone)] + #[derive(WasmerEnv, Clone)] struct Env(Rc>); impl std::ops::Deref for Env { @@ -115,12 +115,6 @@ fn static_host_function_with_env() -> anyhow::Result<()> { } } - impl WasmerEnv for Env { - fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { - Ok(()) - } - } - // Native static host function that returns a tuple. { let env = Env(Rc::new(RefCell::new(100))); @@ -185,7 +179,7 @@ fn dynamic_host_function_without_env() -> anyhow::Result<()> { fn dynamic_host_function_with_env() -> anyhow::Result<()> { let store = get_store(false); - #[derive(Clone)] + #[derive(WasmerEnv, Clone)] struct Env(Rc>); impl std::ops::Deref for Env { @@ -195,12 +189,6 @@ fn dynamic_host_function_with_env() -> anyhow::Result<()> { } } - impl WasmerEnv for Env { - fn init_with_instance(&mut self, _instance: &Instance) -> Result<(), HostEnvInitError> { - Ok(()) - } - } - let env = Env(Rc::new(RefCell::new(100))); let f = Function::new_with_env( &store, From 7013163829d32dfdcf5b4d1c9e2ec1faa5bfa916 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 25 Nov 2020 10:59:04 -0800 Subject: [PATCH 33/39] WIP attempt to make an Export wrapper type I can't figure out how we can ever use the non-wrapped type though --- lib/api/src/exports.rs | 8 +-- lib/api/src/externals/function.rs | 109 ++++++++++++++++-------------- lib/api/src/externals/global.rs | 4 +- lib/api/src/externals/memory.rs | 4 +- lib/api/src/externals/mod.rs | 4 +- lib/api/src/externals/table.rs | 4 +- lib/api/src/import_object.rs | 18 ++--- lib/api/src/native.rs | 43 +++++++++--- lib/api/src/types.rs | 18 ++--- lib/c-api/wasmer_wasm.h | 3 - lib/engine/src/resolver.rs | 40 +++++------ lib/vm/src/export.rs | 59 ++++++++++++++-- lib/vm/src/instance.rs | 11 ++- 13 files changed, 204 insertions(+), 121 deletions(-) diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index 4bfa11074dd..9c25aed8e24 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -7,7 +7,7 @@ use std::fmt; use std::iter::{ExactSizeIterator, FromIterator}; use std::sync::Arc; use thiserror::Error; -use wasmer_vm::Export; +use wasmer_vm::EngineExport; /// The `ExportError` can happen when trying to get a specific /// export [`Extern`] from the [`Instance`] exports. @@ -264,11 +264,11 @@ impl FromIterator<(String, Extern)> for Exports { } impl LikeNamespace for Exports { - fn get_namespace_export(&self, name: &str) -> Option { + fn get_namespace_export(&self, name: &str) -> Option { self.map.get(name).map(|is_export| is_export.to_export()) } - fn get_namespace_exports(&self) -> Vec<(String, Export)> { + fn get_namespace_exports(&self) -> Vec<(String, EngineExport)> { self.map .iter() .map(|(k, v)| (k.clone(), v.to_export())) @@ -284,7 +284,7 @@ pub trait Exportable<'a>: Sized { /// can be used while instantiating the [`Module`]. /// /// [`Module`]: crate::Module - fn to_export(&self) -> Export; + fn to_export(&self) -> EngineExport; /// Implementation of how to get the export corresponding to the implementing type /// from an [`Instance`] by name. diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index fe17f68e2ac..71c168aa132 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -13,9 +13,9 @@ pub use inner::{UnsafeMutableEnv, WithUnsafeMutableEnv}; use std::cmp::max; use std::fmt; use wasmer_vm::{ - raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction, - VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, - VMFunctionKind, VMTrampoline, + raise_user_trap, resume_panic, wasmer_call_trampoline, EngineExport, EngineExportFunction, + ExportFunction, VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMFunctionBody, + VMFunctionEnvironment, VMFunctionKind, VMTrampoline, }; /// A function defined in the Wasm module @@ -56,7 +56,7 @@ pub enum FunctionDefinition { pub struct Function { pub(crate) store: Store, pub(crate) definition: FunctionDefinition, - pub(crate) exported: ExportFunction, + pub(crate) exported: EngineExportFunction, } impl Function { @@ -95,13 +95,15 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }), - exported: ExportFunction { - address, - kind: VMFunctionKind::Dynamic, - vmctx, + exported: EngineExportFunction { function_ptr: None, - signature: ty.clone(), - call_trampoline: None, + function: ExportFunction { + address, + kind: VMFunctionKind::Dynamic, + vmctx, + signature: ty.clone(), + call_trampoline: None, + }, }, } } @@ -155,13 +157,15 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), - exported: ExportFunction { - address, - kind: VMFunctionKind::Dynamic, - vmctx, + exported: EngineExportFunction { function_ptr, - signature: ty.clone(), - call_trampoline: None, + function: ExportFunction { + address, + kind: VMFunctionKind::Dynamic, + vmctx, + signature: ty.clone(), + call_trampoline: None, + }, }, } } @@ -200,15 +204,18 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }), - exported: ExportFunction { - address, - vmctx, - signature, + + exported: EngineExportFunction { // 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, + function: ExportFunction { + address, + vmctx, + signature, + kind: VMFunctionKind::Static, + call_trampoline: None, + }, }, } } @@ -266,13 +273,15 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), - exported: ExportFunction { - address, - kind: VMFunctionKind::Static, - vmctx, + exported: EngineExportFunction { function_ptr, - signature, - call_trampoline: None, + function: ExportFunction { + address, + kind: VMFunctionKind::Static, + vmctx, + signature, + call_trampoline: None, + }, }, } } @@ -313,13 +322,15 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), - exported: ExportFunction { - address, - kind: VMFunctionKind::Static, - vmctx, + exported: EngineExportFunction { function_ptr, - signature, - call_trampoline: None, + function: ExportFunction { + address, + kind: VMFunctionKind::Static, + vmctx, + signature, + call_trampoline: None, + }, }, } } @@ -342,7 +353,7 @@ impl Function { /// assert_eq!(f.ty().results(), vec![Type::I32]); /// ``` pub fn ty(&self) -> &FunctionType { - &self.exported.signature + &self.exported.function.signature } /// Returns the [`Store`] where the `Function` belongs. @@ -399,9 +410,9 @@ impl Function { // Call the trampoline. if let Err(error) = unsafe { wasmer_call_trampoline( - self.exported.vmctx, + self.exported.function.vmctx, func.trampoline, - self.exported.address, + self.exported.function.address, values_vec.as_mut_ptr() as *mut u8, ) } { @@ -501,8 +512,8 @@ impl Function { Ok(results.into_boxed_slice()) } - pub(crate) fn from_export(store: &Store, wasmer_export: ExportFunction) -> Self { - if let Some(trampoline) = wasmer_export.call_trampoline { + pub(crate) fn from_export(store: &Store, wasmer_export: EngineExportFunction) -> Self { + if let Some(trampoline) = wasmer_export.function.call_trampoline { Self { store: store.clone(), definition: FunctionDefinition::Wasm(WasmFunctionDefinition { trampoline }), @@ -512,7 +523,7 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { - has_env: !wasmer_export.vmctx.is_null(), + has_env: !wasmer_export.function.vmctx.is_null(), }), exported: wasmer_export, } @@ -523,11 +534,11 @@ impl Function { let vmsignature = self .store .engine() - .register_signature(&self.exported.signature); + .register_signature(&self.exported.function.signature); VMCallerCheckedAnyfunc { - func_ptr: self.exported.address, + func_ptr: self.exported.function.address, type_index: vmsignature, - vmctx: self.exported.vmctx, + vmctx: self.exported.function.vmctx, } } @@ -613,7 +624,7 @@ impl Function { { // type check { - let expected = self.exported.signature.params(); + let expected = self.exported.function.signature.params(); let given = Args::wasm_types(); if expected != given { @@ -626,7 +637,7 @@ impl Function { } { - let expected = self.exported.signature.results(); + let expected = self.exported.function.signature.results(); let given = Rets::wasm_types(); if expected != given { @@ -641,16 +652,16 @@ impl Function { Ok(NativeFunc::new( self.store.clone(), - self.exported.address, - self.exported.vmctx, - self.exported.kind, + self.exported.function.address, + self.exported.function.vmctx, + self.exported.function.kind, self.definition.clone(), )) } } impl<'a> Exportable<'a> for Function { - fn to_export(&self) -> Export { + fn to_export(&self) -> EngineExport { self.exported.clone().into() } diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index a306b9a94e5..e1e865d825b 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -7,7 +7,7 @@ use crate::Mutability; use crate::RuntimeError; use std::fmt; use std::sync::Arc; -use wasmer_vm::{Export, ExportGlobal, Global as RuntimeGlobal}; +use wasmer_vm::{EngineExport, ExportGlobal, Global as RuntimeGlobal}; /// A WebAssembly `global` instance. /// @@ -215,7 +215,7 @@ impl fmt::Debug for Global { } impl<'a> Exportable<'a> for Global { - fn to_export(&self) -> Export { + fn to_export(&self) -> EngineExport { ExportGlobal { from: self.global.clone(), } diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index 32583c82fef..e260ae721c3 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -6,7 +6,7 @@ use std::convert::TryInto; use std::slice; use std::sync::Arc; use wasmer_types::{Pages, ValueType}; -use wasmer_vm::{Export, ExportMemory, Memory as RuntimeMemory, MemoryError}; +use wasmer_vm::{EngineExport, ExportMemory, Memory as RuntimeMemory, MemoryError}; /// A WebAssembly `memory` instance. /// @@ -245,7 +245,7 @@ impl Memory { } impl<'a> Exportable<'a> for Memory { - fn to_export(&self) -> Export { + fn to_export(&self) -> EngineExport { ExportMemory { from: self.memory.clone(), } diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index c9521870059..bd4164a0dc6 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -17,7 +17,7 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{Store, StoreObject}; use crate::ExternType; use std::fmt; -use wasmer_vm::Export; +use wasmer_vm::{EngineExport, Export}; /// An `Extern` is the runtime representation of an entity that /// can be imported or exported. @@ -58,7 +58,7 @@ impl Extern { } impl<'a> Exportable<'a> for Extern { - fn to_export(&self) -> Export { + fn to_export(&self) -> EngineExport { match self { Self::Function(f) => f.to_export(), Self::Global(g) => g.to_export(), diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 4bcbf257584..e5cc2cb4a75 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -5,7 +5,7 @@ use crate::types::{Val, ValFuncRef}; use crate::RuntimeError; use crate::TableType; use std::sync::Arc; -use wasmer_vm::{Export, ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc}; +use wasmer_vm::{EngineExport, ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc}; /// A WebAssembly `table` instance. /// @@ -153,7 +153,7 @@ impl Table { } impl<'a> Exportable<'a> for Table { - fn to_export(&self) -> Export { + fn to_export(&self) -> EngineExport { ExportTable { from: self.table.clone(), } diff --git a/lib/api/src/import_object.rs b/lib/api/src/import_object.rs index bf499fcc953..949e412d1c8 100644 --- a/lib/api/src/import_object.rs +++ b/lib/api/src/import_object.rs @@ -7,16 +7,16 @@ use std::collections::{hash_map::Entry, HashMap}; use std::fmt; use std::sync::{Arc, Mutex}; use wasmer_engine::NamedResolver; -use wasmer_vm::Export; +use wasmer_vm::EngineExport; /// The `LikeNamespace` trait represents objects that act as a namespace for imports. /// For example, an `Instance` or `Namespace` could be /// considered namespaces that could provide imports to an instance. pub trait LikeNamespace { /// Gets an export by name. - fn get_namespace_export(&self, name: &str) -> Option; + fn get_namespace_export(&self, name: &str) -> Option; /// Gets all exports in the namespace. - fn get_namespace_exports(&self) -> Vec<(String, Export)>; + fn get_namespace_exports(&self) -> Vec<(String, EngineExport)>; } /// All of the import data used when instantiating. @@ -59,7 +59,7 @@ impl ImportObject { /// let mut import_object = ImportObject::new(); /// import_object.get_export("module", "name"); /// ``` - pub fn get_export(&self, module: &str, name: &str) -> Option { + pub fn get_export(&self, module: &str, name: &str) -> Option { let guard = self.map.lock().unwrap(); let map_ref = guard.borrow(); if map_ref.contains_key(module) { @@ -102,7 +102,7 @@ impl ImportObject { } } - fn get_objects(&self) -> VecDeque<((String, String), Export)> { + fn get_objects(&self) -> VecDeque<((String, String), EngineExport)> { let mut out = VecDeque::new(); let guard = self.map.lock().unwrap(); let map = guard.borrow(); @@ -116,18 +116,18 @@ impl ImportObject { } impl NamedResolver for ImportObject { - fn resolve_by_name(&self, module: &str, name: &str) -> Option { + fn resolve_by_name(&self, module: &str, name: &str) -> Option { self.get_export(module, name) } } /// Iterator for an `ImportObject`'s exports. pub struct ImportObjectIterator { - elements: VecDeque<((String, String), Export)>, + elements: VecDeque<((String, String), EngineExport)>, } impl Iterator for ImportObjectIterator { - type Item = ((String, String), Export); + type Item = ((String, String), EngineExport); fn next(&mut self) -> Option { self.elements.pop_front() } @@ -135,7 +135,7 @@ impl Iterator for ImportObjectIterator { impl IntoIterator for ImportObject { type IntoIter = ImportObjectIterator; - type Item = ((String, String), Export); + type Item = ((String, String), EngineExport); fn into_iter(self) -> Self::IntoIter { ImportObjectIterator { diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index 8e82e41e2b2..9edf4acb1c1 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -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, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, + EngineExportFunction, ExportFunction, VMDynamicFunctionContext, VMFunctionBody, + VMFunctionEnvironment, VMFunctionKind, }; /// A WebAssembly function that can be called natively @@ -28,7 +29,7 @@ pub struct NativeFunc { address: *const VMFunctionBody, vmctx: VMFunctionEnvironment, arg_kind: VMFunctionKind, - // exported: ExportFunction, + // exported: EngineExportFunction, _phantom: PhantomData<(Args, Rets)>, } @@ -57,6 +58,7 @@ where } } +/* impl From<&NativeFunc> for ExportFunction where Args: WasmTypeList, @@ -68,12 +70,31 @@ where address: other.address, vmctx: other.vmctx, signature, - // TODO: - function_ptr: None, kind: other.arg_kind, call_trampoline: None, } } +}*/ + +impl From<&NativeFunc> for EngineExportFunction +where + Args: WasmTypeList, + Rets: WasmTypeList, +{ + fn from(other: &NativeFunc) -> Self { + let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); + Self { + // TODO: + function_ptr: None, + function: ExportFunction { + address: other.address, + vmctx: other.vmctx, + signature, + kind: other.arg_kind, + call_trampoline: None, + }, + } + } } impl From> for Function @@ -86,14 +107,16 @@ where Self { store: other.store, definition: other.definition, - exported: ExportFunction { - address: other.address, - vmctx: other.vmctx, - signature, + exported: EngineExportFunction { // TODO: function_ptr: None, - kind: other.arg_kind, - call_trampoline: None, + function: ExportFunction { + address: other.address, + vmctx: other.vmctx, + signature, + kind: other.arg_kind, + call_trampoline: None, + }, }, } } diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index 5839b8f7723..52ff99ffba6 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -73,17 +73,19 @@ impl ValFuncRef for Val { .engine() .lookup_signature(item.type_index) .expect("Signature not found in store"); - let export = wasmer_vm::ExportFunction { - address: item.func_ptr, - signature, + let export = wasmer_vm::EngineExportFunction { // 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, - vmctx: item.vmctx, - call_trampoline: None, + function: wasmer_vm::ExportFunction { + address: item.func_ptr, + signature, + // All functions in tables are already Static (as dynamic functions + // are converted to use the trampolines with static signatures). + kind: wasmer_vm::VMFunctionKind::Static, + vmctx: item.vmctx, + call_trampoline: None, + }, }; let f = Function::from_export(store, export); Self::FuncRef(f) diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index ab3600f690e..3310984e901 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -29,9 +29,6 @@ # define DEPRECATED(message) __declspec(deprecated(message)) #endif -// The `jit` feature has been enabled for this build. -#define WASMER_JIT_ENABLED - // The `compiler` feature has been enabled for this build. #define WASMER_COMPILER_ENABLED diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index 59de18d5f0d..da1845eb409 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -7,7 +7,7 @@ use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, TableIndex}; use wasmer_vm::{ - Export, FunctionBodyPtr, Imports, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody, + EngineExport, FunctionBodyPtr, Imports, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport, VMTableImport, }; @@ -32,7 +32,7 @@ pub trait Resolver { /// (import "" "" (func (param i32) (result i32))) /// ) /// ``` - fn resolve(&self, _index: u32, module: &str, field: &str) -> Option; + fn resolve(&self, _index: u32, module: &str, field: &str) -> Option; } /// Import resolver connects imports with available exported values. @@ -45,26 +45,26 @@ pub trait NamedResolver { /// /// It receives the `module` and `field` names and return the [`Export`] in /// case it's found. - fn resolve_by_name(&self, module: &str, field: &str) -> Option; + fn resolve_by_name(&self, module: &str, field: &str) -> Option; } // All NamedResolvers should extend `Resolver`. impl Resolver for T { /// By default this method will be calling [`NamedResolver::resolve_by_name`], /// dismissing the provided `index`. - fn resolve(&self, _index: u32, module: &str, field: &str) -> Option { + fn resolve(&self, _index: u32, module: &str, field: &str) -> Option { self.resolve_by_name(module, field) } } impl NamedResolver for &T { - fn resolve_by_name(&self, module: &str, field: &str) -> Option { + fn resolve_by_name(&self, module: &str, field: &str) -> Option { (**self).resolve_by_name(module, field) } } impl NamedResolver for Box { - fn resolve_by_name(&self, module: &str, field: &str) -> Option { + fn resolve_by_name(&self, module: &str, field: &str) -> Option { (**self).resolve_by_name(module, field) } } @@ -73,7 +73,7 @@ impl NamedResolver for Box { pub struct NullResolver {} impl Resolver for NullResolver { - fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option { + fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option { None } } @@ -101,12 +101,12 @@ fn get_extern_from_import(module: &ModuleInfo, import_index: &ImportIndex) -> Ex } /// Get an `ExternType` given an export (and Engine signatures in case is a function). -fn get_extern_from_export(_module: &ModuleInfo, export: &Export) -> ExternType { +fn get_extern_from_export(_module: &ModuleInfo, export: &EngineExport) -> ExternType { match export { - Export::Function(ref f) => ExternType::Function(f.signature.clone()), - Export::Table(ref t) => ExternType::Table(*t.ty()), - Export::Memory(ref m) => ExternType::Memory(*m.ty()), - Export::Global(ref g) => { + EngineExport::Function(ref f) => ExternType::Function(f.function.signature.clone()), + EngineExport::Table(ref t) => ExternType::Table(*t.ty()), + EngineExport::Memory(ref m) => ExternType::Memory(*m.ty()), + EngineExport::Global(ref g) => { let global = g.from.ty(); ExternType::Global(*global) } @@ -153,8 +153,8 @@ pub fn resolve_imports( )); } match resolved { - Export::Function(ref f) => { - let address = match f.kind { + EngineExport::Function(ref f) => { + let address = match f.function.kind { VMFunctionKind::Dynamic => { // If this is a dynamic imported function, // the address of the function is the address of the @@ -165,22 +165,22 @@ pub fn resolve_imports( // TODO: We should check that the f.vmctx actually matches // the shape of `VMDynamicFunctionImportContext` } - VMFunctionKind::Static => f.address, + VMFunctionKind::Static => f.function.address, }; function_imports.push(VMFunctionImport { body: address, - environment: f.vmctx, + environment: f.function.vmctx, }); host_function_env_initializers.push(f.function_ptr); } - Export::Table(ref t) => { + EngineExport::Table(ref t) => { table_imports.push(VMTableImport { definition: t.from.vmtable(), from: t.from.clone(), }); } - Export::Memory(ref m) => { + EngineExport::Memory(ref m) => { match import_index { ImportIndex::Memory(index) => { // Sanity-check: Ensure that the imported memory has at least @@ -215,7 +215,7 @@ pub fn resolve_imports( }); } - Export::Global(ref g) => { + EngineExport::Global(ref g) => { global_imports.push(VMGlobalImport { definition: g.from.vmglobal(), from: g.from.clone(), @@ -303,7 +303,7 @@ where A: NamedResolver, B: NamedResolver, { - fn resolve_by_name(&self, module: &str, field: &str) -> Option { + fn resolve_by_name(&self, module: &str, field: &str) -> Option { self.a .resolve_by_name(module, field) .or_else(|| self.b.resolve_by_name(module, field)) diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index eb8956733ee..4eb9f818a30 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -9,6 +9,22 @@ use crate::vmcontext::{VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, VM use std::sync::Arc; use wasmer_types::{FunctionType, MemoryType, TableType}; +/// The value of an export passed from one instance to another. +#[derive(Debug, Clone)] +pub enum EngineExport { + /// A function export value. + Function(EngineExportFunction), + + /// A table export value. + Table(ExportTable), + + /// A memory export value. + Memory(ExportMemory), + + /// A global export value. + Global(ExportGlobal), +} + /// The value of an export passed from one instance to another. #[derive(Debug, Clone)] pub enum Export { @@ -25,6 +41,18 @@ pub enum Export { Global(ExportGlobal), } +/// TODO: +#[derive(Debug, Clone, PartialEq)] +pub struct EngineExportFunction { + /// TODO: + pub function: ExportFunction, + /// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`. + /// + /// This function is called to finish setting up the environment after + /// we create the `api::Instance`. + pub function_ptr: Option, +} + /// A function export value. #[derive(Debug, Clone, PartialEq)] pub struct ExportFunction { @@ -32,13 +60,6 @@ pub struct ExportFunction { pub address: *const VMFunctionBody, /// Pointer to the containing `VMContext`. pub vmctx: VMFunctionEnvironment, - /// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`. - /// - /// This function is called to finish setting up the environment after - /// we create the `api::Instance`. - // META: if you have a better idea of how to get this function to where it - // needs to be, please let me know. - pub function_ptr: Option, /// The function type, used for compatibility checking. pub signature: FunctionType, /// The function kind (specifies the calling convention for the function). @@ -56,6 +77,12 @@ unsafe impl Send for ExportFunction {} /// The members of an ExportFunction are immutable after construction. unsafe impl Sync for ExportFunction {} +impl From for EngineExport { + fn from(func: EngineExportFunction) -> Self { + Self::Function(func) + } +} + impl From for Export { fn from(func: ExportFunction) -> Self { Self::Function(func) @@ -103,6 +130,12 @@ impl From for Export { } } +impl From for EngineExport { + fn from(table: ExportTable) -> Self { + Self::Table(table) + } +} + /// A memory export value. #[derive(Debug, Clone)] pub struct ExportMemory { @@ -144,6 +177,12 @@ impl From for Export { } } +impl From for EngineExport { + fn from(memory: ExportMemory) -> Self { + Self::Memory(memory) + } +} + /// A global export value. #[derive(Debug, Clone)] pub struct ExportGlobal { @@ -174,3 +213,9 @@ impl From for Export { Self::Global(global) } } + +impl From for EngineExport { + fn from(global: ExportGlobal) -> Self { + Self::Global(global) + } +} diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 0b350617e4b..e4fa6718734 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -4,7 +4,7 @@ //! An `Instance` contains all the runtime state used by execution of a //! wasm module (except its callstack and register state). An //! `InstanceHandle` is a reference-counting handle for an `Instance`. -use crate::export::Export; +use crate::export::{EngineExport, Export}; use crate::global::Global; use crate::imports::Imports; use crate::memory::{Memory, MemoryError}; @@ -16,7 +16,7 @@ use crate::vmcontext::{ VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, }; -use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable}; +use crate::{EngineExportFunction, ExportFunction, ExportGlobal, ExportMemory, ExportTable}; use crate::{FunctionBodyPtr, ModuleInfo, VMOffsets}; use memoffset::offset_of; use more_asserts::assert_lt; @@ -315,6 +315,7 @@ impl Instance { } /// Lookup an export with the given export declaration. + // TODO: maybe EngineExport pub fn lookup_by_declaration(&self, export: &ExportIndex) -> Export { match export { ExportIndex::Function(index) => { @@ -335,6 +336,9 @@ impl Instance { }; let call_trampoline = Some(self.function_call_trampolines[*sig_index]); let signature = self.module.signatures[*sig_index].clone(); + /*EngineExportFunction { + function_ptr, + function: */ ExportFunction { address, // Any function received is already static at this point as: @@ -344,9 +348,9 @@ impl Instance { kind: VMFunctionKind::Static, signature, vmctx, - function_ptr, call_trampoline, } + //} .into() } ExportIndex::Table(index) => { @@ -1170,6 +1174,7 @@ impl InstanceHandle { use std::ffi; let instance = &mut *self.instance; for (func, env) in instance.import_initializers.drain(..) { + dbg!(func, env); if let Some(ref f) = func { // transmute our function pointer into one with the correct error type let f = std::mem::transmute::< From 40eec3fbd662190bb34127af2ccf59458d93648d Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 25 Nov 2020 14:19:29 -0800 Subject: [PATCH 34/39] Address feedback: misc clean ups --- lib/api/src/instance.rs | 8 ++++++++ lib/c-api/src/wasm_c_api/wasi/mod.rs | 13 ++++++++----- lib/c-api/wasmer_wasm.h | 12 ++++++++++-- lib/vm/src/instance.rs | 1 + lib/wasi/src/lib.rs | 3 ++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index c011be3703b..3b2932b8266 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -130,6 +130,14 @@ impl Instance { exports, }; + // # Safety + // `initialize_host_envs` should be called after instantiation but before + // returning an `Instance` to the user. We set up the host environments + // via `WasmerEnv::init_with_instance`. + // + // This usage is correct because we pass a valid pointer to `instance` and the + // correct error type returned by `WasmerEnv::init_with_instance` as a generic + // parameter. unsafe { instance .handle diff --git a/lib/c-api/src/wasm_c_api/wasi/mod.rs b/lib/c-api/src/wasm_c_api/wasi/mod.rs index a5c8beddd8f..5998cc72ada 100644 --- a/lib/c-api/src/wasm_c_api/wasi/mod.rs +++ b/lib/c-api/src/wasm_c_api/wasi/mod.rs @@ -174,12 +174,12 @@ pub extern "C" fn wasi_env_new(mut config: Box) -> Option>) {} +/// This function is deprecated. You may safely remove all calls to it and everything +/// will continue to work. // Dead code: deprecate or remove +#[allow(unused_variables)] #[no_mangle] -pub extern "C" fn wasi_env_set_instance( - _env: &mut wasi_env_t, - _instance: &wasm_instance_t, -) -> bool { +pub extern "C" fn wasi_env_set_instance(env: &mut wasi_env_t, instance: &wasm_instance_t) -> bool { /* let memory = if let Ok(memory) = instance.inner.exports.get_memory("memory") { memory @@ -192,9 +192,12 @@ pub extern "C" fn wasi_env_set_instance( true } +/// This function is deprecated. You may safely remove all calls to it and everything +/// will continue to work. // Dead code: deprecate or remove +#[allow(unused_variables)] #[no_mangle] -pub extern "C" fn wasi_env_set_memory(_env: &mut wasi_env_t, _memory: &wasm_memory_t) { +pub extern "C" fn wasi_env_set_memory(env: &mut wasi_env_t, memory: &wasm_memory_t) { //env.inner.set_memory(memory.inner.clone()); } diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index ab3600f690e..c3079de7c25 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -145,11 +145,19 @@ intptr_t wasi_env_read_stdout(wasi_env_t *env, char *buffer, uintptr_t buffer_le #endif #if defined(WASMER_WASI_ENABLED) -bool wasi_env_set_instance(wasi_env_t *_env, const wasm_instance_t *_instance); +/** + * This function is deprecated. You may safely remove all calls to it and everything + * will continue to work. + */ +bool wasi_env_set_instance(wasi_env_t *env, const wasm_instance_t *instance); #endif #if defined(WASMER_WASI_ENABLED) -void wasi_env_set_memory(wasi_env_t *_env, const wasm_memory_t *_memory); +/** + * This function is deprecated. You may safely remove all calls to it and everything + * will continue to work. + */ +void wasi_env_set_memory(wasi_env_t *env, const wasm_memory_t *memory); #endif #if defined(WASMER_WASI_ENABLED) diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index 0b350617e4b..5bc89318667 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -1163,6 +1163,7 @@ impl InstanceHandle { /// - This function must be called with the correct `Err` type parameter: the error type is not /// visible to code in `wasmer_vm`, so it's the caller's responsibility to ensure these /// functions are called with the correct type. + /// - `instance_ptr` must point to a valid `wasmer::Instance`. pub unsafe fn initialize_host_envs( &mut self, instance_ptr: *const std::ffi::c_void, diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index f8378e748bc..4c590a14aac 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -82,7 +82,8 @@ impl WasiEnv { /// Get a reference to the memory pub fn memory(&self) -> &Memory { - self.memory_ref().unwrap() + self.memory_ref() + .expect("Memory should be set on `WasiEnv` first") } pub(crate) fn get_memory_and_wasi_state( From 8669e92ed420a50da4f9983c61686b845bdb0479 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Wed, 25 Nov 2020 16:44:21 -0800 Subject: [PATCH 35/39] Move `EngineExport` to engine --- lib/api/src/exports.rs | 2 +- lib/api/src/externals/function.rs | 6 ++-- lib/api/src/externals/global.rs | 3 +- lib/api/src/externals/memory.rs | 3 +- lib/api/src/externals/mod.rs | 12 +++---- lib/api/src/externals/table.rs | 3 +- lib/api/src/import_object.rs | 40 ++++++++++++----------- lib/api/src/instance.rs | 2 +- lib/api/src/lib.rs | 4 +-- lib/api/src/native.rs | 4 +-- lib/api/src/types.rs | 2 +- lib/c-api/src/ordered_resolver.rs | 6 ++-- lib/engine/src/lib.rs | 2 ++ lib/engine/src/resolver.rs | 4 +-- lib/vm/src/export.rs | 53 ------------------------------- lib/vm/src/instance.rs | 9 +++--- lib/vm/src/lib.rs | 2 +- 17 files changed, 56 insertions(+), 101 deletions(-) diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index 9c25aed8e24..963a36e013c 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -7,7 +7,7 @@ use std::fmt; use std::iter::{ExactSizeIterator, FromIterator}; use std::sync::Arc; use thiserror::Error; -use wasmer_vm::EngineExport; +use wasmer_engine::EngineExport; /// The `ExportError` can happen when trying to get a specific /// export [`Extern`] from the [`Instance`] exports. diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 71c168aa132..01cfa433fdd 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -12,10 +12,10 @@ pub use inner::{UnsafeMutableEnv, WithUnsafeMutableEnv}; use std::cmp::max; use std::fmt; +use wasmer_engine::{EngineExport, EngineExportFunction}; use wasmer_vm::{ - raise_user_trap, resume_panic, wasmer_call_trampoline, EngineExport, EngineExportFunction, - ExportFunction, VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMFunctionBody, - VMFunctionEnvironment, VMFunctionKind, VMTrampoline, + raise_user_trap, resume_panic, wasmer_call_trampoline, ExportFunction, VMCallerCheckedAnyfunc, + VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, VMTrampoline, }; /// A function defined in the Wasm module diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index e1e865d825b..98f97f2fa6a 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -7,7 +7,8 @@ use crate::Mutability; use crate::RuntimeError; use std::fmt; use std::sync::Arc; -use wasmer_vm::{EngineExport, ExportGlobal, Global as RuntimeGlobal}; +use wasmer_engine::EngineExport; +use wasmer_vm::{ExportGlobal, Global as RuntimeGlobal}; /// A WebAssembly `global` instance. /// diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index e260ae721c3..d6e0eef2507 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -5,8 +5,9 @@ use crate::{MemoryType, MemoryView}; use std::convert::TryInto; use std::slice; use std::sync::Arc; +use wasmer_engine::EngineExport; use wasmer_types::{Pages, ValueType}; -use wasmer_vm::{EngineExport, ExportMemory, Memory as RuntimeMemory, MemoryError}; +use wasmer_vm::{ExportMemory, Memory as RuntimeMemory, MemoryError}; /// A WebAssembly `memory` instance. /// diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index bd4164a0dc6..49357dda347 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -17,7 +17,7 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{Store, StoreObject}; use crate::ExternType; use std::fmt; -use wasmer_vm::{EngineExport, Export}; +use wasmer_engine::EngineExport; /// An `Extern` is the runtime representation of an entity that /// can be imported or exported. @@ -47,12 +47,12 @@ impl Extern { } /// Create an `Extern` from an `Export`. - pub fn from_export(store: &Store, export: Export) -> Self { + pub fn from_export(store: &Store, export: EngineExport) -> Self { match export { - Export::Function(f) => Self::Function(Function::from_export(store, f)), - Export::Memory(m) => Self::Memory(Memory::from_export(store, m)), - Export::Global(g) => Self::Global(Global::from_export(store, g)), - Export::Table(t) => Self::Table(Table::from_export(store, t)), + EngineExport::Function(f) => Self::Function(Function::from_export(store, f)), + EngineExport::Memory(m) => Self::Memory(Memory::from_export(store, m)), + EngineExport::Global(g) => Self::Global(Global::from_export(store, g)), + EngineExport::Table(t) => Self::Table(Table::from_export(store, t)), } } } diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index e5cc2cb4a75..0669ea8a3de 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -5,7 +5,8 @@ use crate::types::{Val, ValFuncRef}; use crate::RuntimeError; use crate::TableType; use std::sync::Arc; -use wasmer_vm::{EngineExport, ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc}; +use wasmer_engine::EngineExport; +use wasmer_vm::{ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc}; /// A WebAssembly `table` instance. /// diff --git a/lib/api/src/import_object.rs b/lib/api/src/import_object.rs index 949e412d1c8..e22181950e9 100644 --- a/lib/api/src/import_object.rs +++ b/lib/api/src/import_object.rs @@ -6,8 +6,7 @@ use std::collections::VecDeque; use std::collections::{hash_map::Entry, HashMap}; use std::fmt; use std::sync::{Arc, Mutex}; -use wasmer_engine::NamedResolver; -use wasmer_vm::EngineExport; +use wasmer_engine::{EngineExport, NamedResolver}; /// The `LikeNamespace` trait represents objects that act as a namespace for imports. /// For example, an `Instance` or `Namespace` could be @@ -265,7 +264,6 @@ mod test { use crate::{Global, Store, Val}; use wasmer_engine::ChainableNamedResolver; use wasmer_types::Type; - use wasmer_vm::Export; #[test] fn chaining_works() { @@ -319,11 +317,13 @@ mod test { let resolver = imports1.chain_front(imports2); let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap(); - assert!(if let Export::Global(happy_dog_global) = happy_dog_entry { - happy_dog_global.from.ty().ty == Type::I64 - } else { - false - }); + assert!( + if let EngineExport::Global(happy_dog_global) = happy_dog_entry { + happy_dog_global.from.ty().ty == Type::I64 + } else { + false + } + ); // now test it in reverse let store = Store::default(); @@ -345,11 +345,13 @@ mod test { let resolver = imports1.chain_back(imports2); let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap(); - assert!(if let Export::Global(happy_dog_global) = happy_dog_entry { - happy_dog_global.from.ty().ty == Type::I32 - } else { - false - }); + assert!( + if let EngineExport::Global(happy_dog_global) = happy_dog_entry { + happy_dog_global.from.ty().ty == Type::I32 + } else { + false + } + ); } #[test] @@ -365,11 +367,13 @@ mod test { let happy_dog_entry = imports1.resolve_by_name("dog", "happy").unwrap(); - assert!(if let Export::Global(happy_dog_global) = happy_dog_entry { - happy_dog_global.from.ty().ty == Type::I32 - } else { - false - }); + assert!( + if let EngineExport::Global(happy_dog_global) = happy_dog_entry { + happy_dog_global.from.ty().ty == Type::I32 + } else { + false + } + ); } #[test] diff --git a/lib/api/src/instance.rs b/lib/api/src/instance.rs index c011be3703b..db2395ffac4 100644 --- a/lib/api/src/instance.rs +++ b/lib/api/src/instance.rs @@ -119,7 +119,7 @@ impl Instance { .map(|export| { let name = export.name().to_string(); let export = handle.lookup(&name).expect("export"); - let extern_ = Extern::from_export(store, export); + let extern_ = Extern::from_export(store, export.into()); (name, extern_) }) .collect::(); diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index f4cfb70f903..b003d56750c 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -80,8 +80,8 @@ pub use wasmer_compiler::{ }; pub use wasmer_compiler::{CpuFeature, Features, Target}; pub use wasmer_engine::{ - ChainableNamedResolver, DeserializeError, Engine, FrameInfo, LinkError, NamedResolver, - NamedResolverChain, Resolver, RuntimeError, SerializeError, + ChainableNamedResolver, DeserializeError, Engine, EngineExport, FrameInfo, LinkError, + NamedResolver, NamedResolverChain, Resolver, RuntimeError, SerializeError, }; pub use wasmer_types::{ Atomically, Bytes, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType, diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index 9edf4acb1c1..e4181597172 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -15,10 +15,10 @@ use crate::externals::function::{ }; use crate::{FromToNativeWasmType, Function, FunctionType, RuntimeError, Store, WasmTypeList}; use std::panic::{catch_unwind, AssertUnwindSafe}; +use wasmer_engine::EngineExportFunction; use wasmer_types::NativeWasmType; use wasmer_vm::{ - EngineExportFunction, ExportFunction, VMDynamicFunctionContext, VMFunctionBody, - VMFunctionEnvironment, VMFunctionKind, + ExportFunction, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, }; /// A WebAssembly function that can be called natively diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index 52ff99ffba6..3c97d63ec4f 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -73,7 +73,7 @@ impl ValFuncRef for Val { .engine() .lookup_signature(item.type_index) .expect("Signature not found in store"); - let export = wasmer_vm::EngineExportFunction { + let export = wasmer_engine::EngineExportFunction { // TODO: // figure out if we ever need a value here: need testing with complicated import patterns function_ptr: None, diff --git a/lib/c-api/src/ordered_resolver.rs b/lib/c-api/src/ordered_resolver.rs index 857714f1275..ca2bda0e2fe 100644 --- a/lib/c-api/src/ordered_resolver.rs +++ b/lib/c-api/src/ordered_resolver.rs @@ -1,11 +1,11 @@ //! Ordered Resolvers are a custom kind of [`Resolver`] that retrieves -//! `Export`s based on the index of the import, and not the module or name. +//! `EngineExport`s based on the index of the import, and not the module or name. //! //! This resolver is used in the Wasm-C-API as the imports are provided //! by index and not by module and name. use std::iter::FromIterator; -use wasmer::{Export, Exportable, Extern, Resolver}; +use wasmer::{EngineExport, Exportable, Extern, Resolver}; /// An `OrderedResolver` stores all the `externs` provided to an Instance /// in a Vec, so we can retrieve them later based on index. @@ -16,7 +16,7 @@ pub struct OrderedResolver { } impl Resolver for OrderedResolver { - fn resolve(&self, index: u32, _module: &str, _name: &str) -> Option { + fn resolve(&self, index: u32, _module: &str, _name: &str) -> Option { self.externs .get(index as usize) .map(|extern_| extern_.to_export()) diff --git a/lib/engine/src/lib.rs b/lib/engine/src/lib.rs index 66327e3a227..bad34615e83 100644 --- a/lib/engine/src/lib.rs +++ b/lib/engine/src/lib.rs @@ -23,6 +23,7 @@ mod artifact; mod engine; mod error; +mod export; mod resolver; mod serialize; mod trap; @@ -33,6 +34,7 @@ pub use crate::engine::{Engine, EngineId}; pub use crate::error::{ DeserializeError, ImportError, InstantiationError, LinkError, SerializeError, }; +pub use crate::export::{EngineExport, EngineExportFunction}; pub use crate::resolver::{ resolve_imports, ChainableNamedResolver, NamedResolver, NamedResolverChain, NullResolver, Resolver, diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index da1845eb409..5f21d68c46f 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -1,13 +1,13 @@ //! Define the `Resolver` trait, allowing custom resolution for external //! references. -use crate::{ImportError, LinkError}; +use crate::{EngineExport, ImportError, LinkError}; use more_asserts::assert_ge; use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, TableIndex}; use wasmer_vm::{ - EngineExport, FunctionBodyPtr, Imports, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody, + FunctionBodyPtr, Imports, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport, VMTableImport, }; diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 4eb9f818a30..86b09befbb5 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -2,29 +2,12 @@ // Attributions: https://github.com/wasmerio/wasmer/blob/master/ATTRIBUTIONS.md use crate::global::Global; -use crate::instance::ImportInitializerFuncPtr; use crate::memory::{Memory, MemoryStyle}; use crate::table::{Table, TableStyle}; use crate::vmcontext::{VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, VMTrampoline}; use std::sync::Arc; use wasmer_types::{FunctionType, MemoryType, TableType}; -/// The value of an export passed from one instance to another. -#[derive(Debug, Clone)] -pub enum EngineExport { - /// A function export value. - Function(EngineExportFunction), - - /// A table export value. - Table(ExportTable), - - /// A memory export value. - Memory(ExportMemory), - - /// A global export value. - Global(ExportGlobal), -} - /// The value of an export passed from one instance to another. #[derive(Debug, Clone)] pub enum Export { @@ -41,18 +24,6 @@ pub enum Export { Global(ExportGlobal), } -/// TODO: -#[derive(Debug, Clone, PartialEq)] -pub struct EngineExportFunction { - /// TODO: - pub function: ExportFunction, - /// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`. - /// - /// This function is called to finish setting up the environment after - /// we create the `api::Instance`. - pub function_ptr: Option, -} - /// A function export value. #[derive(Debug, Clone, PartialEq)] pub struct ExportFunction { @@ -77,12 +48,6 @@ unsafe impl Send for ExportFunction {} /// The members of an ExportFunction are immutable after construction. unsafe impl Sync for ExportFunction {} -impl From for EngineExport { - fn from(func: EngineExportFunction) -> Self { - Self::Function(func) - } -} - impl From for Export { fn from(func: ExportFunction) -> Self { Self::Function(func) @@ -130,12 +95,6 @@ impl From for Export { } } -impl From for EngineExport { - fn from(table: ExportTable) -> Self { - Self::Table(table) - } -} - /// A memory export value. #[derive(Debug, Clone)] pub struct ExportMemory { @@ -177,12 +136,6 @@ impl From for Export { } } -impl From for EngineExport { - fn from(memory: ExportMemory) -> Self { - Self::Memory(memory) - } -} - /// A global export value. #[derive(Debug, Clone)] pub struct ExportGlobal { @@ -213,9 +166,3 @@ impl From for Export { Self::Global(global) } } - -impl From for EngineExport { - fn from(global: ExportGlobal) -> Self { - Self::Global(global) - } -} diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index e4fa6718734..b1ead9bafd0 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -4,7 +4,7 @@ //! An `Instance` contains all the runtime state used by execution of a //! wasm module (except its callstack and register state). An //! `InstanceHandle` is a reference-counting handle for an `Instance`. -use crate::export::{EngineExport, Export}; +use crate::export::Export; use crate::global::Global; use crate::imports::Imports; use crate::memory::{Memory, MemoryError}; @@ -16,7 +16,7 @@ use crate::vmcontext::{ VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, }; -use crate::{EngineExportFunction, ExportFunction, ExportGlobal, ExportMemory, ExportTable}; +use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable}; use crate::{FunctionBodyPtr, ModuleInfo, VMOffsets}; use memoffset::offset_of; use more_asserts::assert_lt; @@ -65,7 +65,7 @@ cfg_if::cfg_if! { /// The function pointer to call with data and an [`Instance`] pointer to /// finish initializing the host env. -pub(crate) type ImportInitializerFuncPtr = +pub type ImportInitializerFuncPtr = fn(*mut std::ffi::c_void, *const std::ffi::c_void) -> Result<(), *mut std::ffi::c_void>; /// This type holds thunks (delayed computations) for initializing the imported @@ -320,7 +320,7 @@ impl Instance { match export { ExportIndex::Function(index) => { let sig_index = &self.module.functions[*index]; - let (address, vmctx, function_ptr) = + let (address, vmctx, _function_ptr) = if let Some(def_index) = self.module.local_func_index(*index) { ( self.functions[def_index].0 as *const _, @@ -1174,7 +1174,6 @@ impl InstanceHandle { use std::ffi; let instance = &mut *self.instance; for (func, env) in instance.import_initializers.drain(..) { - dbg!(func, env); if let Some(ref f) = func { // transmute our function pointer into one with the correct error type let f = std::mem::transmute::< diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index 6a1af9f9afa..ecbadeca794 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -39,7 +39,7 @@ pub mod libcalls; pub use crate::export::*; pub use crate::global::*; pub use crate::imports::Imports; -pub use crate::instance::InstanceHandle; +pub use crate::instance::{ImportInitializerFuncPtr, InstanceHandle}; pub use crate::memory::{LinearMemory, Memory, MemoryError, MemoryStyle}; pub use crate::mmap::Mmap; pub use crate::module::{ExportsIterator, ImportsIterator, ModuleInfo}; From 9e0cfcebbba694b2766942b88ef55568228f8aff Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 30 Nov 2020 11:38:14 -0800 Subject: [PATCH 36/39] Rename vm::Export to vm::VMExport --- lib/api/src/externals/function.rs | 15 ++++---- lib/api/src/externals/global.rs | 6 +-- lib/api/src/externals/memory.rs | 6 +-- lib/api/src/externals/table.rs | 6 +-- lib/api/src/lib.rs | 2 +- lib/api/src/native.rs | 9 +++-- lib/api/src/types.rs | 2 +- lib/vm/src/export.rs | 64 +++++++++++++++---------------- lib/vm/src/instance.rs | 20 +++++----- 9 files changed, 66 insertions(+), 64 deletions(-) diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 01cfa433fdd..8995d279d40 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -14,8 +14,9 @@ use std::cmp::max; use std::fmt; use wasmer_engine::{EngineExport, EngineExportFunction}; use wasmer_vm::{ - raise_user_trap, resume_panic, wasmer_call_trampoline, ExportFunction, VMCallerCheckedAnyfunc, - VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, VMTrampoline, + raise_user_trap, resume_panic, wasmer_call_trampoline, VMCallerCheckedAnyfunc, + VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMFunctionEnvironment, + VMFunctionKind, VMTrampoline, }; /// A function defined in the Wasm module @@ -97,7 +98,7 @@ impl Function { definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }), exported: EngineExportFunction { function_ptr: None, - function: ExportFunction { + function: VMExportFunction { address, kind: VMFunctionKind::Dynamic, vmctx, @@ -159,7 +160,7 @@ impl Function { definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), exported: EngineExportFunction { function_ptr, - function: ExportFunction { + function: VMExportFunction { address, kind: VMFunctionKind::Dynamic, vmctx, @@ -209,7 +210,7 @@ impl Function { // 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, - function: ExportFunction { + function: VMExportFunction { address, vmctx, signature, @@ -275,7 +276,7 @@ impl Function { definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), exported: EngineExportFunction { function_ptr, - function: ExportFunction { + function: VMExportFunction { address, kind: VMFunctionKind::Static, vmctx, @@ -324,7 +325,7 @@ impl Function { definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), exported: EngineExportFunction { function_ptr, - function: ExportFunction { + function: VMExportFunction { address, kind: VMFunctionKind::Static, vmctx, diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index 98f97f2fa6a..deb33a4355a 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -8,7 +8,7 @@ use crate::RuntimeError; use std::fmt; use std::sync::Arc; use wasmer_engine::EngineExport; -use wasmer_vm::{ExportGlobal, Global as RuntimeGlobal}; +use wasmer_vm::{Global as RuntimeGlobal, VMExportGlobal}; /// A WebAssembly `global` instance. /// @@ -181,7 +181,7 @@ impl Global { Ok(()) } - pub(crate) fn from_export(store: &Store, wasmer_export: ExportGlobal) -> Self { + pub(crate) fn from_export(store: &Store, wasmer_export: VMExportGlobal) -> Self { Self { store: store.clone(), global: wasmer_export.from, @@ -217,7 +217,7 @@ impl fmt::Debug for Global { impl<'a> Exportable<'a> for Global { fn to_export(&self) -> EngineExport { - ExportGlobal { + VMExportGlobal { from: self.global.clone(), } .into() diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index d6e0eef2507..c10ceaf765b 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -7,7 +7,7 @@ use std::slice; use std::sync::Arc; use wasmer_engine::EngineExport; use wasmer_types::{Pages, ValueType}; -use wasmer_vm::{ExportMemory, Memory as RuntimeMemory, MemoryError}; +use wasmer_vm::{Memory as RuntimeMemory, MemoryError, VMExportMemory}; /// A WebAssembly `memory` instance. /// @@ -221,7 +221,7 @@ impl Memory { unsafe { MemoryView::new(base as _, length as u32) } } - pub(crate) fn from_export(store: &Store, wasmer_export: ExportMemory) -> Self { + pub(crate) fn from_export(store: &Store, wasmer_export: VMExportMemory) -> Self { Self { store: store.clone(), memory: wasmer_export.from, @@ -247,7 +247,7 @@ impl Memory { impl<'a> Exportable<'a> for Memory { fn to_export(&self) -> EngineExport { - ExportMemory { + VMExportMemory { from: self.memory.clone(), } .into() diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 0669ea8a3de..5330ac9d07a 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -6,7 +6,7 @@ use crate::RuntimeError; use crate::TableType; use std::sync::Arc; use wasmer_engine::EngineExport; -use wasmer_vm::{ExportTable, Table as RuntimeTable, VMCallerCheckedAnyfunc}; +use wasmer_vm::{Table as RuntimeTable, VMCallerCheckedAnyfunc, VMExportTable}; /// A WebAssembly `table` instance. /// @@ -140,7 +140,7 @@ impl Table { Ok(()) } - pub(crate) fn from_export(store: &Store, wasmer_export: ExportTable) -> Self { + pub(crate) fn from_export(store: &Store, wasmer_export: VMExportTable) -> Self { Self { store: store.clone(), table: wasmer_export.from, @@ -155,7 +155,7 @@ impl Table { impl<'a> Exportable<'a> for Table { fn to_export(&self) -> EngineExport { - ExportTable { + VMExportTable { from: self.table.clone(), } .into() diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index b003d56750c..25dc8d1402a 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -89,7 +89,7 @@ pub use wasmer_types::{ }; // TODO: should those be moved into wasmer::vm as well? -pub use wasmer_vm::{raise_user_trap, Export, MemoryError}; +pub use wasmer_vm::{raise_user_trap, MemoryError, VMExport}; pub mod vm { //! We use the vm module for re-exporting wasmer-vm types diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index e4181597172..cad5242010d 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -18,7 +18,8 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; use wasmer_engine::EngineExportFunction; use wasmer_types::NativeWasmType; use wasmer_vm::{ - ExportFunction, VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind, + VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMFunctionEnvironment, + VMFunctionKind, }; /// A WebAssembly function that can be called natively @@ -59,7 +60,7 @@ where } /* -impl From<&NativeFunc> for ExportFunction +impl From<&NativeFunc> for VMExportFunction where Args: WasmTypeList, Rets: WasmTypeList, @@ -86,7 +87,7 @@ where Self { // TODO: function_ptr: None, - function: ExportFunction { + function: VMExportFunction { address: other.address, vmctx: other.vmctx, signature, @@ -110,7 +111,7 @@ where exported: EngineExportFunction { // TODO: function_ptr: None, - function: ExportFunction { + function: VMExportFunction { address: other.address, vmctx: other.vmctx, signature, diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index 3c97d63ec4f..3c9d4a90e4f 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -77,7 +77,7 @@ impl ValFuncRef for Val { // TODO: // figure out if we ever need a value here: need testing with complicated import patterns function_ptr: None, - function: wasmer_vm::ExportFunction { + function: wasmer_vm::VMExportFunction { address: item.func_ptr, signature, // All functions in tables are already Static (as dynamic functions diff --git a/lib/vm/src/export.rs b/lib/vm/src/export.rs index 86b09befbb5..083210093bc 100644 --- a/lib/vm/src/export.rs +++ b/lib/vm/src/export.rs @@ -10,23 +10,23 @@ use wasmer_types::{FunctionType, MemoryType, TableType}; /// The value of an export passed from one instance to another. #[derive(Debug, Clone)] -pub enum Export { +pub enum VMExport { /// A function export value. - Function(ExportFunction), + Function(VMExportFunction), /// A table export value. - Table(ExportTable), + Table(VMExportTable), /// A memory export value. - Memory(ExportMemory), + Memory(VMExportMemory), /// A global export value. - Global(ExportGlobal), + Global(VMExportGlobal), } /// A function export value. #[derive(Debug, Clone, PartialEq)] -pub struct ExportFunction { +pub struct VMExportFunction { /// The address of the native-code function. pub address: *const VMFunctionBody, /// Pointer to the containing `VMContext`. @@ -43,20 +43,20 @@ pub struct ExportFunction { /// # Safety /// There is no non-threadsafe logic directly in this type. Calling the function /// may not be threadsafe. -unsafe impl Send for ExportFunction {} +unsafe impl Send for VMExportFunction {} /// # Safety -/// The members of an ExportFunction are immutable after construction. -unsafe impl Sync for ExportFunction {} +/// The members of an VMExportFunction are immutable after construction. +unsafe impl Sync for VMExportFunction {} -impl From for Export { - fn from(func: ExportFunction) -> Self { +impl From for VMExport { + fn from(func: VMExportFunction) -> Self { Self::Function(func) } } /// A table export value. #[derive(Debug, Clone)] -pub struct ExportTable { +pub struct VMExportTable { /// Pointer to the containing `Table`. pub from: Arc, } @@ -65,14 +65,14 @@ pub struct ExportTable { /// This is correct because there is no non-threadsafe logic directly in this type; /// correct use of the raw table from multiple threads via `definition` requires `unsafe` /// and is the responsibilty of the user of this type. -unsafe impl Send for ExportTable {} +unsafe impl Send for VMExportTable {} /// # Safety /// This is correct because the values directly in `definition` should be considered immutable /// and the type is both `Send` and `Clone` (thus marking it `Sync` adds no new behavior, it /// only makes this type easier to use) -unsafe impl Sync for ExportTable {} +unsafe impl Sync for VMExportTable {} -impl ExportTable { +impl VMExportTable { /// Get the table type for this exported table pub fn ty(&self) -> &TableType { self.from.ty() @@ -83,21 +83,21 @@ impl ExportTable { self.from.style() } - /// Returns whether or not the two `ExportTable`s refer to the same Memory. + /// Returns whether or not the two `VMExportTable`s refer to the same Memory. pub fn same(&self, other: &Self) -> bool { Arc::ptr_eq(&self.from, &other.from) } } -impl From for Export { - fn from(table: ExportTable) -> Self { +impl From for VMExport { + fn from(table: VMExportTable) -> Self { Self::Table(table) } } /// A memory export value. #[derive(Debug, Clone)] -pub struct ExportMemory { +pub struct VMExportMemory { /// Pointer to the containing `Memory`. pub from: Arc, } @@ -106,14 +106,14 @@ pub struct ExportMemory { /// This is correct because there is no non-threadsafe logic directly in this type; /// correct use of the raw memory from multiple threads via `definition` requires `unsafe` /// and is the responsibilty of the user of this type. -unsafe impl Send for ExportMemory {} +unsafe impl Send for VMExportMemory {} /// # Safety /// This is correct because the values directly in `definition` should be considered immutable /// and the type is both `Send` and `Clone` (thus marking it `Sync` adds no new behavior, it /// only makes this type easier to use) -unsafe impl Sync for ExportMemory {} +unsafe impl Sync for VMExportMemory {} -impl ExportMemory { +impl VMExportMemory { /// Get the type for this exported memory pub fn ty(&self) -> &MemoryType { self.from.ty() @@ -124,21 +124,21 @@ impl ExportMemory { self.from.style() } - /// Returns whether or not the two `ExportMemory`s refer to the same Memory. + /// Returns whether or not the two `VMExportMemory`s refer to the same Memory. pub fn same(&self, other: &Self) -> bool { Arc::ptr_eq(&self.from, &other.from) } } -impl From for Export { - fn from(memory: ExportMemory) -> Self { +impl From for VMExport { + fn from(memory: VMExportMemory) -> Self { Self::Memory(memory) } } /// A global export value. #[derive(Debug, Clone)] -pub struct ExportGlobal { +pub struct VMExportGlobal { /// The global declaration, used for compatibility checking. pub from: Arc, } @@ -147,22 +147,22 @@ pub struct ExportGlobal { /// This is correct because there is no non-threadsafe logic directly in this type; /// correct use of the raw global from multiple threads via `definition` requires `unsafe` /// and is the responsibilty of the user of this type. -unsafe impl Send for ExportGlobal {} +unsafe impl Send for VMExportGlobal {} /// # Safety /// This is correct because the values directly in `definition` should be considered immutable /// from the perspective of users of this type and the type is both `Send` and `Clone` (thus /// marking it `Sync` adds no new behavior, it only makes this type easier to use) -unsafe impl Sync for ExportGlobal {} +unsafe impl Sync for VMExportGlobal {} -impl ExportGlobal { - /// Returns whether or not the two `ExportGlobal`s refer to the same Global. +impl VMExportGlobal { + /// Returns whether or not the two `VMExportGlobal`s refer to the same Global. pub fn same(&self, other: &Self) -> bool { Arc::ptr_eq(&self.from, &other.from) } } -impl From for Export { - fn from(global: ExportGlobal) -> Self { +impl From for VMExport { + fn from(global: VMExportGlobal) -> Self { Self::Global(global) } } diff --git a/lib/vm/src/instance.rs b/lib/vm/src/instance.rs index b1ead9bafd0..20225624544 100644 --- a/lib/vm/src/instance.rs +++ b/lib/vm/src/instance.rs @@ -4,7 +4,7 @@ //! An `Instance` contains all the runtime state used by execution of a //! wasm module (except its callstack and register state). An //! `InstanceHandle` is a reference-counting handle for an `Instance`. -use crate::export::Export; +use crate::export::VMExport; use crate::global::Global; use crate::imports::Imports; use crate::memory::{Memory, MemoryError}; @@ -16,8 +16,8 @@ use crate::vmcontext::{ VMMemoryDefinition, VMMemoryImport, VMSharedSignatureIndex, VMTableDefinition, VMTableImport, VMTrampoline, }; -use crate::{ExportFunction, ExportGlobal, ExportMemory, ExportTable}; use crate::{FunctionBodyPtr, ModuleInfo, VMOffsets}; +use crate::{VMExportFunction, VMExportGlobal, VMExportMemory, VMExportTable}; use memoffset::offset_of; use more_asserts::assert_lt; use std::alloc::{self, Layout}; @@ -308,7 +308,7 @@ impl Instance { } /// Lookup an export with the given name. - pub fn lookup(&self, field: &str) -> Option { + pub fn lookup(&self, field: &str) -> Option { let export = self.module.exports.get(field)?; Some(self.lookup_by_declaration(&export)) @@ -316,7 +316,7 @@ impl Instance { /// Lookup an export with the given export declaration. // TODO: maybe EngineExport - pub fn lookup_by_declaration(&self, export: &ExportIndex) -> Export { + pub fn lookup_by_declaration(&self, export: &ExportIndex) -> VMExport { match export { ExportIndex::Function(index) => { let sig_index = &self.module.functions[*index]; @@ -339,7 +339,7 @@ impl Instance { /*EngineExportFunction { function_ptr, function: */ - ExportFunction { + VMExportFunction { address, // Any function received is already static at this point as: // 1. All locally defined functions in the Wasm have a static signature. @@ -360,7 +360,7 @@ impl Instance { let import = self.imported_table(*index); import.from.clone() }; - ExportTable { from }.into() + VMExportTable { from }.into() } ExportIndex::Memory(index) => { let from = if let Some(def_index) = self.module.local_memory_index(*index) { @@ -369,7 +369,7 @@ impl Instance { let import = self.imported_memory(*index); import.from.clone() }; - ExportMemory { from }.into() + VMExportMemory { from }.into() } ExportIndex::Global(index) => { let from = { @@ -380,7 +380,7 @@ impl Instance { import.from.clone() } }; - ExportGlobal { from }.into() + VMExportGlobal { from }.into() } } } @@ -1072,12 +1072,12 @@ impl InstanceHandle { } /// Lookup an export with the given name. - pub fn lookup(&self, field: &str) -> Option { + pub fn lookup(&self, field: &str) -> Option { self.instance().lookup(field) } /// Lookup an export with the given export declaration. - pub fn lookup_by_declaration(&self, export: &ExportIndex) -> Export { + pub fn lookup_by_declaration(&self, export: &ExportIndex) -> VMExport { self.instance().lookup_by_declaration(export) } From 03410c15a1a3c2e1db0dcfa1ae610919f72bc00e Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 30 Nov 2020 12:32:53 -0800 Subject: [PATCH 37/39] Rename `EngineExport` to `Export` --- lib/api/src/exports.rs | 8 +-- lib/api/src/externals/function.rs | 70 +++++++++---------- lib/api/src/externals/global.rs | 14 ++-- lib/api/src/externals/memory.rs | 14 ++-- lib/api/src/externals/mod.rs | 14 ++-- lib/api/src/externals/table.rs | 14 ++-- lib/api/src/import_object.rs | 54 +++++++------- lib/api/src/lib.rs | 4 +- lib/api/src/native.rs | 16 ++--- lib/api/src/types.rs | 6 +- lib/c-api/src/ordered_resolver.rs | 4 +- lib/deprecated/runtime-core/src/export.rs | 2 +- lib/deprecated/runtime-core/src/global.rs | 2 +- lib/deprecated/runtime-core/src/import.rs | 4 +- lib/deprecated/runtime-core/src/instance.rs | 8 +-- lib/deprecated/runtime-core/src/memory.rs | 4 +- lib/deprecated/runtime-core/src/module.rs | 16 +++-- lib/deprecated/runtime-core/src/table.rs | 2 +- lib/deprecated/runtime-core/src/typed_func.rs | 4 +- lib/engine/src/lib.rs | 2 +- lib/engine/src/resolver.rs | 58 +++++++-------- 21 files changed, 162 insertions(+), 158 deletions(-) diff --git a/lib/api/src/exports.rs b/lib/api/src/exports.rs index 963a36e013c..1f1ecfbda72 100644 --- a/lib/api/src/exports.rs +++ b/lib/api/src/exports.rs @@ -7,7 +7,7 @@ use std::fmt; use std::iter::{ExactSizeIterator, FromIterator}; use std::sync::Arc; use thiserror::Error; -use wasmer_engine::EngineExport; +use wasmer_engine::Export; /// The `ExportError` can happen when trying to get a specific /// export [`Extern`] from the [`Instance`] exports. @@ -264,11 +264,11 @@ impl FromIterator<(String, Extern)> for Exports { } impl LikeNamespace for Exports { - fn get_namespace_export(&self, name: &str) -> Option { + fn get_namespace_export(&self, name: &str) -> Option { self.map.get(name).map(|is_export| is_export.to_export()) } - fn get_namespace_exports(&self) -> Vec<(String, EngineExport)> { + fn get_namespace_exports(&self) -> Vec<(String, Export)> { self.map .iter() .map(|(k, v)| (k.clone(), v.to_export())) @@ -284,7 +284,7 @@ pub trait Exportable<'a>: Sized { /// can be used while instantiating the [`Module`]. /// /// [`Module`]: crate::Module - fn to_export(&self) -> EngineExport; + fn to_export(&self) -> Export; /// Implementation of how to get the export corresponding to the implementing type /// from an [`Instance`] by name. diff --git a/lib/api/src/externals/function.rs b/lib/api/src/externals/function.rs index 8995d279d40..82425853a6d 100644 --- a/lib/api/src/externals/function.rs +++ b/lib/api/src/externals/function.rs @@ -12,7 +12,7 @@ pub use inner::{UnsafeMutableEnv, WithUnsafeMutableEnv}; use std::cmp::max; use std::fmt; -use wasmer_engine::{EngineExport, EngineExportFunction}; +use wasmer_engine::{Export, ExportFunction}; use wasmer_vm::{ raise_user_trap, resume_panic, wasmer_call_trampoline, VMCallerCheckedAnyfunc, VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMFunctionEnvironment, @@ -57,7 +57,7 @@ pub enum FunctionDefinition { pub struct Function { pub(crate) store: Store, pub(crate) definition: FunctionDefinition, - pub(crate) exported: EngineExportFunction, + pub(crate) exported: ExportFunction, } impl Function { @@ -96,9 +96,9 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }), - exported: EngineExportFunction { - function_ptr: None, - function: VMExportFunction { + exported: ExportFunction { + import_init_function_ptr: None, + vm_function: VMExportFunction { address, kind: VMFunctionKind::Dynamic, vmctx, @@ -149,7 +149,7 @@ impl Function { host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _, }; // TODO: look into removing transmute by changing API type signatures - let function_ptr = Some(unsafe { + let import_init_function_ptr = Some(unsafe { std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>( Env::init_with_instance, ) @@ -158,9 +158,9 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), - exported: EngineExportFunction { - function_ptr, - function: VMExportFunction { + exported: ExportFunction { + import_init_function_ptr, + vm_function: VMExportFunction { address, kind: VMFunctionKind::Dynamic, vmctx, @@ -206,11 +206,11 @@ impl Function { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }), - exported: EngineExportFunction { + exported: ExportFunction { // 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, - function: VMExportFunction { + import_init_function_ptr: None, + vm_function: VMExportFunction { address, vmctx, signature, @@ -264,7 +264,7 @@ impl Function { host_env: Box::into_raw(box_env) as *mut _, }; // TODO: look into removing transmute by changing API type signatures - let function_ptr = Some(unsafe { + let import_init_function_ptr = Some(unsafe { std::mem::transmute:: Result<(), _>, fn(_, _) -> Result<(), _>>( Env::init_with_instance, ) @@ -274,9 +274,9 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), - exported: EngineExportFunction { - function_ptr, - function: VMExportFunction { + exported: ExportFunction { + import_init_function_ptr, + vm_function: VMExportFunction { address, kind: VMFunctionKind::Static, vmctx, @@ -315,7 +315,7 @@ impl Function { }; let signature = function.ty(); // TODO: look into removing transmute by changing API type signatures - let function_ptr = Some(std::mem::transmute::< + let import_init_function_ptr = Some(std::mem::transmute::< fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>, >(Env::init_with_instance)); @@ -323,9 +323,9 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), - exported: EngineExportFunction { - function_ptr, - function: VMExportFunction { + exported: ExportFunction { + import_init_function_ptr, + vm_function: VMExportFunction { address, kind: VMFunctionKind::Static, vmctx, @@ -354,7 +354,7 @@ impl Function { /// assert_eq!(f.ty().results(), vec![Type::I32]); /// ``` pub fn ty(&self) -> &FunctionType { - &self.exported.function.signature + &self.exported.vm_function.signature } /// Returns the [`Store`] where the `Function` belongs. @@ -411,9 +411,9 @@ impl Function { // Call the trampoline. if let Err(error) = unsafe { wasmer_call_trampoline( - self.exported.function.vmctx, + self.exported.vm_function.vmctx, func.trampoline, - self.exported.function.address, + self.exported.vm_function.address, values_vec.as_mut_ptr() as *mut u8, ) } { @@ -513,8 +513,8 @@ impl Function { Ok(results.into_boxed_slice()) } - pub(crate) fn from_export(store: &Store, wasmer_export: EngineExportFunction) -> Self { - if let Some(trampoline) = wasmer_export.function.call_trampoline { + pub(crate) fn from_export(store: &Store, wasmer_export: ExportFunction) -> Self { + if let Some(trampoline) = wasmer_export.vm_function.call_trampoline { Self { store: store.clone(), definition: FunctionDefinition::Wasm(WasmFunctionDefinition { trampoline }), @@ -524,7 +524,7 @@ impl Function { Self { store: store.clone(), definition: FunctionDefinition::Host(HostFunctionDefinition { - has_env: !wasmer_export.function.vmctx.is_null(), + has_env: !wasmer_export.vm_function.vmctx.is_null(), }), exported: wasmer_export, } @@ -535,11 +535,11 @@ impl Function { let vmsignature = self .store .engine() - .register_signature(&self.exported.function.signature); + .register_signature(&self.exported.vm_function.signature); VMCallerCheckedAnyfunc { - func_ptr: self.exported.function.address, + func_ptr: self.exported.vm_function.address, type_index: vmsignature, - vmctx: self.exported.function.vmctx, + vmctx: self.exported.vm_function.vmctx, } } @@ -625,7 +625,7 @@ impl Function { { // type check { - let expected = self.exported.function.signature.params(); + let expected = self.exported.vm_function.signature.params(); let given = Args::wasm_types(); if expected != given { @@ -638,7 +638,7 @@ impl Function { } { - let expected = self.exported.function.signature.results(); + let expected = self.exported.vm_function.signature.results(); let given = Rets::wasm_types(); if expected != given { @@ -653,16 +653,16 @@ impl Function { Ok(NativeFunc::new( self.store.clone(), - self.exported.function.address, - self.exported.function.vmctx, - self.exported.function.kind, + self.exported.vm_function.address, + self.exported.vm_function.vmctx, + self.exported.vm_function.kind, self.definition.clone(), )) } } impl<'a> Exportable<'a> for Function { - fn to_export(&self) -> EngineExport { + fn to_export(&self) -> Export { self.exported.clone().into() } diff --git a/lib/api/src/externals/global.rs b/lib/api/src/externals/global.rs index deb33a4355a..9c0a73e7c57 100644 --- a/lib/api/src/externals/global.rs +++ b/lib/api/src/externals/global.rs @@ -7,7 +7,7 @@ use crate::Mutability; use crate::RuntimeError; use std::fmt; use std::sync::Arc; -use wasmer_engine::EngineExport; +use wasmer_engine::{Export, ExportGlobal}; use wasmer_vm::{Global as RuntimeGlobal, VMExportGlobal}; /// A WebAssembly `global` instance. @@ -181,10 +181,10 @@ impl Global { Ok(()) } - pub(crate) fn from_export(store: &Store, wasmer_export: VMExportGlobal) -> Self { + pub(crate) fn from_export(store: &Store, wasmer_export: ExportGlobal) -> Self { Self { store: store.clone(), - global: wasmer_export.from, + global: wasmer_export.vm_global.from, } } @@ -216,9 +216,11 @@ impl fmt::Debug for Global { } impl<'a> Exportable<'a> for Global { - fn to_export(&self) -> EngineExport { - VMExportGlobal { - from: self.global.clone(), + fn to_export(&self) -> Export { + ExportGlobal { + vm_global: VMExportGlobal { + from: self.global.clone(), + }, } .into() } diff --git a/lib/api/src/externals/memory.rs b/lib/api/src/externals/memory.rs index c10ceaf765b..08d7744934b 100644 --- a/lib/api/src/externals/memory.rs +++ b/lib/api/src/externals/memory.rs @@ -5,7 +5,7 @@ use crate::{MemoryType, MemoryView}; use std::convert::TryInto; use std::slice; use std::sync::Arc; -use wasmer_engine::EngineExport; +use wasmer_engine::{Export, ExportMemory}; use wasmer_types::{Pages, ValueType}; use wasmer_vm::{Memory as RuntimeMemory, MemoryError, VMExportMemory}; @@ -221,10 +221,10 @@ impl Memory { unsafe { MemoryView::new(base as _, length as u32) } } - pub(crate) fn from_export(store: &Store, wasmer_export: VMExportMemory) -> Self { + pub(crate) fn from_export(store: &Store, wasmer_export: ExportMemory) -> Self { Self { store: store.clone(), - memory: wasmer_export.from, + memory: wasmer_export.vm_memory.from, } } @@ -246,9 +246,11 @@ impl Memory { } impl<'a> Exportable<'a> for Memory { - fn to_export(&self) -> EngineExport { - VMExportMemory { - from: self.memory.clone(), + fn to_export(&self) -> Export { + ExportMemory { + vm_memory: VMExportMemory { + from: self.memory.clone(), + }, } .into() } diff --git a/lib/api/src/externals/mod.rs b/lib/api/src/externals/mod.rs index 49357dda347..ccdf974ab6f 100644 --- a/lib/api/src/externals/mod.rs +++ b/lib/api/src/externals/mod.rs @@ -17,7 +17,7 @@ use crate::exports::{ExportError, Exportable}; use crate::store::{Store, StoreObject}; use crate::ExternType; use std::fmt; -use wasmer_engine::EngineExport; +use wasmer_engine::Export; /// An `Extern` is the runtime representation of an entity that /// can be imported or exported. @@ -47,18 +47,18 @@ impl Extern { } /// Create an `Extern` from an `Export`. - pub fn from_export(store: &Store, export: EngineExport) -> Self { + pub fn from_export(store: &Store, export: Export) -> Self { match export { - EngineExport::Function(f) => Self::Function(Function::from_export(store, f)), - EngineExport::Memory(m) => Self::Memory(Memory::from_export(store, m)), - EngineExport::Global(g) => Self::Global(Global::from_export(store, g)), - EngineExport::Table(t) => Self::Table(Table::from_export(store, t)), + Export::Function(f) => Self::Function(Function::from_export(store, f)), + Export::Memory(m) => Self::Memory(Memory::from_export(store, m)), + Export::Global(g) => Self::Global(Global::from_export(store, g)), + Export::Table(t) => Self::Table(Table::from_export(store, t)), } } } impl<'a> Exportable<'a> for Extern { - fn to_export(&self) -> EngineExport { + fn to_export(&self) -> Export { match self { Self::Function(f) => f.to_export(), Self::Global(g) => g.to_export(), diff --git a/lib/api/src/externals/table.rs b/lib/api/src/externals/table.rs index 5330ac9d07a..ad2db9a0cfb 100644 --- a/lib/api/src/externals/table.rs +++ b/lib/api/src/externals/table.rs @@ -5,7 +5,7 @@ use crate::types::{Val, ValFuncRef}; use crate::RuntimeError; use crate::TableType; use std::sync::Arc; -use wasmer_engine::EngineExport; +use wasmer_engine::{Export, ExportTable}; use wasmer_vm::{Table as RuntimeTable, VMCallerCheckedAnyfunc, VMExportTable}; /// A WebAssembly `table` instance. @@ -140,10 +140,10 @@ impl Table { Ok(()) } - pub(crate) fn from_export(store: &Store, wasmer_export: VMExportTable) -> Self { + pub(crate) fn from_export(store: &Store, wasmer_export: ExportTable) -> Self { Self { store: store.clone(), - table: wasmer_export.from, + table: wasmer_export.vm_table.from, } } @@ -154,9 +154,11 @@ impl Table { } impl<'a> Exportable<'a> for Table { - fn to_export(&self) -> EngineExport { - VMExportTable { - from: self.table.clone(), + fn to_export(&self) -> Export { + ExportTable { + vm_table: VMExportTable { + from: self.table.clone(), + }, } .into() } diff --git a/lib/api/src/import_object.rs b/lib/api/src/import_object.rs index e22181950e9..b38f4aa8d2b 100644 --- a/lib/api/src/import_object.rs +++ b/lib/api/src/import_object.rs @@ -6,16 +6,16 @@ use std::collections::VecDeque; use std::collections::{hash_map::Entry, HashMap}; use std::fmt; use std::sync::{Arc, Mutex}; -use wasmer_engine::{EngineExport, NamedResolver}; +use wasmer_engine::{Export, NamedResolver}; /// The `LikeNamespace` trait represents objects that act as a namespace for imports. /// For example, an `Instance` or `Namespace` could be /// considered namespaces that could provide imports to an instance. pub trait LikeNamespace { /// Gets an export by name. - fn get_namespace_export(&self, name: &str) -> Option; + fn get_namespace_export(&self, name: &str) -> Option; /// Gets all exports in the namespace. - fn get_namespace_exports(&self) -> Vec<(String, EngineExport)>; + fn get_namespace_exports(&self) -> Vec<(String, Export)>; } /// All of the import data used when instantiating. @@ -58,7 +58,7 @@ impl ImportObject { /// let mut import_object = ImportObject::new(); /// import_object.get_export("module", "name"); /// ``` - pub fn get_export(&self, module: &str, name: &str) -> Option { + pub fn get_export(&self, module: &str, name: &str) -> Option { let guard = self.map.lock().unwrap(); let map_ref = guard.borrow(); if map_ref.contains_key(module) { @@ -101,7 +101,7 @@ impl ImportObject { } } - fn get_objects(&self) -> VecDeque<((String, String), EngineExport)> { + fn get_objects(&self) -> VecDeque<((String, String), Export)> { let mut out = VecDeque::new(); let guard = self.map.lock().unwrap(); let map = guard.borrow(); @@ -115,18 +115,18 @@ impl ImportObject { } impl NamedResolver for ImportObject { - fn resolve_by_name(&self, module: &str, name: &str) -> Option { + fn resolve_by_name(&self, module: &str, name: &str) -> Option { self.get_export(module, name) } } /// Iterator for an `ImportObject`'s exports. pub struct ImportObjectIterator { - elements: VecDeque<((String, String), EngineExport)>, + elements: VecDeque<((String, String), Export)>, } impl Iterator for ImportObjectIterator { - type Item = ((String, String), EngineExport); + type Item = ((String, String), Export); fn next(&mut self) -> Option { self.elements.pop_front() } @@ -134,7 +134,7 @@ impl Iterator for ImportObjectIterator { impl IntoIterator for ImportObject { type IntoIter = ImportObjectIterator; - type Item = ((String, String), EngineExport); + type Item = ((String, String), Export); fn into_iter(self) -> Self::IntoIter { ImportObjectIterator { @@ -317,13 +317,11 @@ mod test { let resolver = imports1.chain_front(imports2); let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap(); - assert!( - if let EngineExport::Global(happy_dog_global) = happy_dog_entry { - happy_dog_global.from.ty().ty == Type::I64 - } else { - false - } - ); + assert!(if let Export::Global(happy_dog_global) = happy_dog_entry { + happy_dog_global.vm_global.from.ty().ty == Type::I64 + } else { + false + }); // now test it in reverse let store = Store::default(); @@ -345,13 +343,11 @@ mod test { let resolver = imports1.chain_back(imports2); let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap(); - assert!( - if let EngineExport::Global(happy_dog_global) = happy_dog_entry { - happy_dog_global.from.ty().ty == Type::I32 - } else { - false - } - ); + assert!(if let Export::Global(happy_dog_global) = happy_dog_entry { + happy_dog_global.vm_global.from.ty().ty == Type::I32 + } else { + false + }); } #[test] @@ -367,13 +363,11 @@ mod test { let happy_dog_entry = imports1.resolve_by_name("dog", "happy").unwrap(); - assert!( - if let EngineExport::Global(happy_dog_global) = happy_dog_entry { - happy_dog_global.from.ty().ty == Type::I32 - } else { - false - } - ); + assert!(if let Export::Global(happy_dog_global) = happy_dog_entry { + happy_dog_global.vm_global.from.ty().ty == Type::I32 + } else { + false + }); } #[test] diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 25dc8d1402a..52c20ea7fea 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -80,8 +80,8 @@ pub use wasmer_compiler::{ }; pub use wasmer_compiler::{CpuFeature, Features, Target}; pub use wasmer_engine::{ - ChainableNamedResolver, DeserializeError, Engine, EngineExport, FrameInfo, LinkError, - NamedResolver, NamedResolverChain, Resolver, RuntimeError, SerializeError, + ChainableNamedResolver, DeserializeError, Engine, Export, FrameInfo, LinkError, NamedResolver, + NamedResolverChain, Resolver, RuntimeError, SerializeError, }; pub use wasmer_types::{ Atomically, Bytes, GlobalInit, LocalFunctionIndex, MemoryView, Pages, ValueType, diff --git a/lib/api/src/native.rs b/lib/api/src/native.rs index cad5242010d..77a8179cd12 100644 --- a/lib/api/src/native.rs +++ b/lib/api/src/native.rs @@ -15,7 +15,7 @@ use crate::externals::function::{ }; use crate::{FromToNativeWasmType, Function, FunctionType, RuntimeError, Store, WasmTypeList}; use std::panic::{catch_unwind, AssertUnwindSafe}; -use wasmer_engine::EngineExportFunction; +use wasmer_engine::ExportFunction; use wasmer_types::NativeWasmType; use wasmer_vm::{ VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMFunctionEnvironment, @@ -30,7 +30,7 @@ pub struct NativeFunc { address: *const VMFunctionBody, vmctx: VMFunctionEnvironment, arg_kind: VMFunctionKind, - // exported: EngineExportFunction, + // exported: ExportFunction, _phantom: PhantomData<(Args, Rets)>, } @@ -77,7 +77,7 @@ where } }*/ -impl From<&NativeFunc> for EngineExportFunction +impl From<&NativeFunc> for ExportFunction where Args: WasmTypeList, Rets: WasmTypeList, @@ -86,8 +86,8 @@ where let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types()); Self { // TODO: - function_ptr: None, - function: VMExportFunction { + import_init_function_ptr: None, + vm_function: VMExportFunction { address: other.address, vmctx: other.vmctx, signature, @@ -108,10 +108,10 @@ where Self { store: other.store, definition: other.definition, - exported: EngineExportFunction { + exported: ExportFunction { // TODO: - function_ptr: None, - function: VMExportFunction { + import_init_function_ptr: None, + vm_function: VMExportFunction { address: other.address, vmctx: other.vmctx, signature, diff --git a/lib/api/src/types.rs b/lib/api/src/types.rs index 3c9d4a90e4f..d986e89b713 100644 --- a/lib/api/src/types.rs +++ b/lib/api/src/types.rs @@ -73,11 +73,11 @@ impl ValFuncRef for Val { .engine() .lookup_signature(item.type_index) .expect("Signature not found in store"); - let export = wasmer_engine::EngineExportFunction { + let export = wasmer_engine::ExportFunction { // TODO: // figure out if we ever need a value here: need testing with complicated import patterns - function_ptr: None, - function: wasmer_vm::VMExportFunction { + import_init_function_ptr: None, + vm_function: wasmer_vm::VMExportFunction { address: item.func_ptr, signature, // All functions in tables are already Static (as dynamic functions diff --git a/lib/c-api/src/ordered_resolver.rs b/lib/c-api/src/ordered_resolver.rs index ca2bda0e2fe..d35ac43fbf2 100644 --- a/lib/c-api/src/ordered_resolver.rs +++ b/lib/c-api/src/ordered_resolver.rs @@ -5,7 +5,7 @@ //! by index and not by module and name. use std::iter::FromIterator; -use wasmer::{EngineExport, Exportable, Extern, Resolver}; +use wasmer::{Export, Exportable, Extern, Resolver}; /// An `OrderedResolver` stores all the `externs` provided to an Instance /// in a Vec, so we can retrieve them later based on index. @@ -16,7 +16,7 @@ pub struct OrderedResolver { } impl Resolver for OrderedResolver { - fn resolve(&self, index: u32, _module: &str, _name: &str) -> Option { + fn resolve(&self, index: u32, _module: &str, _name: &str) -> Option { self.externs .get(index as usize) .map(|extern_| extern_.to_export()) diff --git a/lib/deprecated/runtime-core/src/export.rs b/lib/deprecated/runtime-core/src/export.rs index 359822b8d55..ddf6d8da6d1 100644 --- a/lib/deprecated/runtime-core/src/export.rs +++ b/lib/deprecated/runtime-core/src/export.rs @@ -1,4 +1,4 @@ pub use crate::new::{ + wasmer::Export as RuntimeExport, wasmer::{Exportable, Extern as Export}, - wasmer_vm::Export as RuntimeExport, }; diff --git a/lib/deprecated/runtime-core/src/global.rs b/lib/deprecated/runtime-core/src/global.rs index bf2aa45fc70..0f66a9918e1 100644 --- a/lib/deprecated/runtime-core/src/global.rs +++ b/lib/deprecated/runtime-core/src/global.rs @@ -87,7 +87,7 @@ impl From<&new::wasmer::Global> for Global { } impl<'a> new::wasmer::Exportable<'a> for Global { - fn to_export(&self) -> new::wasmer_vm::Export { + fn to_export(&self) -> new::wasmer::Export { self.new_global.to_export() } diff --git a/lib/deprecated/runtime-core/src/import.rs b/lib/deprecated/runtime-core/src/import.rs index b9af6e6c542..1c2dc88782d 100644 --- a/lib/deprecated/runtime-core/src/import.rs +++ b/lib/deprecated/runtime-core/src/import.rs @@ -30,11 +30,11 @@ impl Namespace { } impl LikeNamespace for Namespace { - fn get_namespace_export(&self, name: &str) -> Option { + fn get_namespace_export(&self, name: &str) -> Option { self.exports.new_exports.get_namespace_export(name) } - fn get_namespace_exports(&self) -> Vec<(String, new::wasmer_vm::Export)> { + fn get_namespace_exports(&self) -> Vec<(String, new::wasmer::Export)> { self.exports.new_exports.get_namespace_exports() } } diff --git a/lib/deprecated/runtime-core/src/instance.rs b/lib/deprecated/runtime-core/src/instance.rs index 8bc6bd4f567..7cf42b30936 100644 --- a/lib/deprecated/runtime-core/src/instance.rs +++ b/lib/deprecated/runtime-core/src/instance.rs @@ -222,11 +222,11 @@ impl Instance { } impl LikeNamespace for Instance { - fn get_namespace_export(&self, name: &str) -> Option { + fn get_namespace_export(&self, name: &str) -> Option { self.exports.new_exports.get_namespace_export(name) } - fn get_namespace_exports(&self) -> Vec<(String, new::wasmer_vm::Export)> { + fn get_namespace_exports(&self) -> Vec<(String, new::wasmer::Export)> { self.exports.new_exports.get_namespace_exports() } } @@ -256,11 +256,11 @@ impl Exports { } impl LikeNamespace for Exports { - fn get_namespace_export(&self, name: &str) -> Option { + fn get_namespace_export(&self, name: &str) -> Option { self.new_exports.get_namespace_export(name) } - fn get_namespace_exports(&self) -> Vec<(String, new::wasmer_vm::Export)> { + fn get_namespace_exports(&self) -> Vec<(String, new::wasmer::Export)> { self.new_exports.get_namespace_exports() } } diff --git a/lib/deprecated/runtime-core/src/memory.rs b/lib/deprecated/runtime-core/src/memory.rs index 5f0937da712..69074f400f1 100644 --- a/lib/deprecated/runtime-core/src/memory.rs +++ b/lib/deprecated/runtime-core/src/memory.rs @@ -9,8 +9,8 @@ pub mod ptr { pub use crate::new::wasmer::{Array, Item, WasmPtr}; } -pub use new::wasmer_types::MemoryType as MemoryDescriptor; pub use new::wasmer::{Atomically, MemoryView}; +pub use new::wasmer_types::MemoryType as MemoryDescriptor; pub use new::wasmer_vm::MemoryStyle as MemoryType; /// A Wasm linear memory. @@ -108,7 +108,7 @@ impl From<&new::wasmer::Memory> for Memory { } impl<'a> new::wasmer::Exportable<'a> for Memory { - fn to_export(&self) -> new::wasmer_vm::Export { + fn to_export(&self) -> new::wasmer::Export { self.new_memory.to_export() } diff --git a/lib/deprecated/runtime-core/src/module.rs b/lib/deprecated/runtime-core/src/module.rs index 7ef483dcb85..c7600d7224f 100644 --- a/lib/deprecated/runtime-core/src/module.rs +++ b/lib/deprecated/runtime-core/src/module.rs @@ -8,7 +8,7 @@ use crate::{ types::{FuncSig, Value}, vm, }; -use new::wasmer_vm::Export; +use new::wasmer::Export; use std::{ cell::RefCell, collections::HashMap, @@ -98,18 +98,20 @@ impl Module { // `function` is a static host function // constructed with // `new::wasmer::Function::new_env`. - if !function.address.is_null() { + if !function.vm_function.address.is_null() { // Properly drop the empty `vm::Ctx` // created by the host function. unsafe { - ptr::drop_in_place::(function.vmctx.host_env as _); + ptr::drop_in_place::( + function.vm_function.vmctx.host_env as _, + ); } // Update the pointer to `VMContext`, // which is actually a `vm::Ctx` // pointer, to fallback on the // environment hack. - function.vmctx.host_env = pre_instance.vmctx_ptr() as _; + function.vm_function.vmctx.host_env = pre_instance.vmctx_ptr() as _; } // `function` is a dynamic host function // constructed with @@ -147,13 +149,15 @@ impl Module { new::wasmer_vm::VMDynamicFunctionContext< VMDynamicFunctionWithEnv, >, - > = unsafe { Box::from_raw(function.vmctx.host_env as *mut _) }; + > = unsafe { + Box::from_raw(function.vm_function.vmctx.host_env as *mut _) + }; // Replace the environment by ours. vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx(); // … without anyone noticing… - function.vmctx.host_env = Box::into_raw(vmctx) as _; + function.vm_function.vmctx.host_env = Box::into_raw(vmctx) as _; } } diff --git a/lib/deprecated/runtime-core/src/table.rs b/lib/deprecated/runtime-core/src/table.rs index ece88e5fb07..9b2c60d1d34 100644 --- a/lib/deprecated/runtime-core/src/table.rs +++ b/lib/deprecated/runtime-core/src/table.rs @@ -70,7 +70,7 @@ impl From<&new::wasmer::Table> for Table { } impl<'a> new::wasmer::Exportable<'a> for Table { - fn to_export(&self) -> new::wasmer_vm::Export { + fn to_export(&self) -> new::wasmer::Export { self.new_table.to_export() } diff --git a/lib/deprecated/runtime-core/src/typed_func.rs b/lib/deprecated/runtime-core/src/typed_func.rs index c44996cb310..0bfe47d61a5 100644 --- a/lib/deprecated/runtime-core/src/typed_func.rs +++ b/lib/deprecated/runtime-core/src/typed_func.rs @@ -201,7 +201,7 @@ where Args: WasmTypeList, Rets: WasmTypeList, { - fn to_export(&self) -> new::wasmer_vm::Export { + fn to_export(&self) -> new::wasmer::Export { self.new_function.to_export() } @@ -312,7 +312,7 @@ impl From<&new::wasmer::Function> for DynamicFunc { } impl<'a> new::wasmer::Exportable<'a> for DynamicFunc { - fn to_export(&self) -> new::wasmer_vm::Export { + fn to_export(&self) -> new::wasmer::Export { self.new_function.to_export() } diff --git a/lib/engine/src/lib.rs b/lib/engine/src/lib.rs index bad34615e83..557b1b039d2 100644 --- a/lib/engine/src/lib.rs +++ b/lib/engine/src/lib.rs @@ -34,7 +34,7 @@ pub use crate::engine::{Engine, EngineId}; pub use crate::error::{ DeserializeError, ImportError, InstantiationError, LinkError, SerializeError, }; -pub use crate::export::{EngineExport, EngineExportFunction}; +pub use crate::export::{Export, ExportFunction, ExportGlobal, ExportMemory, ExportTable}; pub use crate::resolver::{ resolve_imports, ChainableNamedResolver, NamedResolver, NamedResolverChain, NullResolver, Resolver, diff --git a/lib/engine/src/resolver.rs b/lib/engine/src/resolver.rs index 5f21d68c46f..7a0105e14e5 100644 --- a/lib/engine/src/resolver.rs +++ b/lib/engine/src/resolver.rs @@ -1,7 +1,7 @@ //! Define the `Resolver` trait, allowing custom resolution for external //! references. -use crate::{EngineExport, ImportError, LinkError}; +use crate::{Export, ImportError, LinkError}; use more_asserts::assert_ge; use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap}; use wasmer_types::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, TableIndex}; @@ -32,7 +32,7 @@ pub trait Resolver { /// (import "" "" (func (param i32) (result i32))) /// ) /// ``` - fn resolve(&self, _index: u32, module: &str, field: &str) -> Option; + fn resolve(&self, _index: u32, module: &str, field: &str) -> Option; } /// Import resolver connects imports with available exported values. @@ -45,26 +45,26 @@ pub trait NamedResolver { /// /// It receives the `module` and `field` names and return the [`Export`] in /// case it's found. - fn resolve_by_name(&self, module: &str, field: &str) -> Option; + fn resolve_by_name(&self, module: &str, field: &str) -> Option; } // All NamedResolvers should extend `Resolver`. impl Resolver for T { /// By default this method will be calling [`NamedResolver::resolve_by_name`], /// dismissing the provided `index`. - fn resolve(&self, _index: u32, module: &str, field: &str) -> Option { + fn resolve(&self, _index: u32, module: &str, field: &str) -> Option { self.resolve_by_name(module, field) } } impl NamedResolver for &T { - fn resolve_by_name(&self, module: &str, field: &str) -> Option { + fn resolve_by_name(&self, module: &str, field: &str) -> Option { (**self).resolve_by_name(module, field) } } impl NamedResolver for Box { - fn resolve_by_name(&self, module: &str, field: &str) -> Option { + fn resolve_by_name(&self, module: &str, field: &str) -> Option { (**self).resolve_by_name(module, field) } } @@ -73,7 +73,7 @@ impl NamedResolver for Box { pub struct NullResolver {} impl Resolver for NullResolver { - fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option { + fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option { None } } @@ -101,13 +101,13 @@ fn get_extern_from_import(module: &ModuleInfo, import_index: &ImportIndex) -> Ex } /// Get an `ExternType` given an export (and Engine signatures in case is a function). -fn get_extern_from_export(_module: &ModuleInfo, export: &EngineExport) -> ExternType { +fn get_extern_from_export(_module: &ModuleInfo, export: &Export) -> ExternType { match export { - EngineExport::Function(ref f) => ExternType::Function(f.function.signature.clone()), - EngineExport::Table(ref t) => ExternType::Table(*t.ty()), - EngineExport::Memory(ref m) => ExternType::Memory(*m.ty()), - EngineExport::Global(ref g) => { - let global = g.from.ty(); + Export::Function(ref f) => ExternType::Function(f.vm_function.signature.clone()), + Export::Table(ref t) => ExternType::Table(*t.vm_table.ty()), + Export::Memory(ref m) => ExternType::Memory(*m.vm_memory.ty()), + Export::Global(ref g) => { + let global = g.vm_global.from.ty(); ExternType::Global(*global) } } @@ -153,8 +153,8 @@ pub fn resolve_imports( )); } match resolved { - EngineExport::Function(ref f) => { - let address = match f.function.kind { + Export::Function(ref f) => { + let address = match f.vm_function.kind { VMFunctionKind::Dynamic => { // If this is a dynamic imported function, // the address of the function is the address of the @@ -165,27 +165,27 @@ pub fn resolve_imports( // TODO: We should check that the f.vmctx actually matches // the shape of `VMDynamicFunctionImportContext` } - VMFunctionKind::Static => f.function.address, + VMFunctionKind::Static => f.vm_function.address, }; function_imports.push(VMFunctionImport { body: address, - environment: f.function.vmctx, + environment: f.vm_function.vmctx, }); - host_function_env_initializers.push(f.function_ptr); + host_function_env_initializers.push(f.import_init_function_ptr); } - EngineExport::Table(ref t) => { + Export::Table(ref t) => { table_imports.push(VMTableImport { - definition: t.from.vmtable(), - from: t.from.clone(), + definition: t.vm_table.from.vmtable(), + from: t.vm_table.from.clone(), }); } - EngineExport::Memory(ref m) => { + Export::Memory(ref m) => { match import_index { ImportIndex::Memory(index) => { // Sanity-check: Ensure that the imported memory has at least // guard-page protections the importing module expects it to have. - let export_memory_style = m.style(); + let export_memory_style = m.vm_memory.style(); let import_memory_style = &memory_styles[*index]; if let ( MemoryStyle::Static { bound, .. }, @@ -210,15 +210,15 @@ pub fn resolve_imports( } memory_imports.push(VMMemoryImport { - definition: m.from.vmmemory(), - from: m.from.clone(), + definition: m.vm_memory.from.vmmemory(), + from: m.vm_memory.from.clone(), }); } - EngineExport::Global(ref g) => { + Export::Global(ref g) => { global_imports.push(VMGlobalImport { - definition: g.from.vmglobal(), - from: g.from.clone(), + definition: g.vm_global.from.vmglobal(), + from: g.vm_global.from.clone(), }); } } @@ -303,7 +303,7 @@ where A: NamedResolver, B: NamedResolver, { - fn resolve_by_name(&self, module: &str, field: &str) -> Option { + fn resolve_by_name(&self, module: &str, field: &str) -> Option { self.a .resolve_by_name(module, field) .or_else(|| self.b.resolve_by_name(module, field)) From 2c9ca4a74d2264c001c096d0dd06f34c8fa10a61 Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 30 Nov 2020 13:50:40 -0800 Subject: [PATCH 38/39] Add engine::export --- lib/engine/src/export.rs | 103 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 lib/engine/src/export.rs diff --git a/lib/engine/src/export.rs b/lib/engine/src/export.rs new file mode 100644 index 00000000000..8f972c3f79f --- /dev/null +++ b/lib/engine/src/export.rs @@ -0,0 +1,103 @@ +use wasmer_vm::{ + ImportInitializerFuncPtr, VMExport, VMExportFunction, VMExportGlobal, VMExportMemory, + VMExportTable, +}; + +/// The value of an export passed from one instance to another. +#[derive(Debug, Clone)] +pub enum Export { + /// A function export value. + Function(ExportFunction), + + /// A table export value. + Table(ExportTable), + + /// A memory export value. + Memory(ExportMemory), + + /// A global export value. + Global(ExportGlobal), +} + +impl From for VMExport { + fn from(other: Export) -> Self { + match other { + Export::Function(ExportFunction { vm_function, .. }) => VMExport::Function(vm_function), + Export::Memory(ExportMemory { vm_memory }) => VMExport::Memory(vm_memory), + Export::Table(ExportTable { vm_table }) => VMExport::Table(vm_table), + Export::Global(ExportGlobal { vm_global }) => VMExport::Global(vm_global), + } + } +} + +impl From for Export { + fn from(other: VMExport) -> Self { + match other { + VMExport::Function(vm_function) => Export::Function(ExportFunction { + vm_function, + import_init_function_ptr: None, + }), + VMExport::Memory(vm_memory) => Export::Memory(ExportMemory { vm_memory }), + VMExport::Table(vm_table) => Export::Table(ExportTable { vm_table }), + VMExport::Global(vm_global) => Export::Global(ExportGlobal { vm_global }), + } + } +} + +/// A function export value with an extra function pointer to initialize +/// host environments. +#[derive(Debug, Clone, PartialEq)] +pub struct ExportFunction { + /// The VM function, containing most of the data. + pub vm_function: VMExportFunction, + /// Function pointer to `WasmerEnv::init_with_instance(&mut self, instance: &Instance)`. + /// + /// This function is called to finish setting up the environment after + /// we create the `api::Instance`. + pub import_init_function_ptr: Option, +} + +impl From for Export { + fn from(func: ExportFunction) -> Self { + Self::Function(func) + } +} + +/// A table export value. +#[derive(Debug, Clone)] +pub struct ExportTable { + /// The VM table, containing info about the table. + pub vm_table: VMExportTable, +} + +impl From for Export { + fn from(table: ExportTable) -> Self { + Self::Table(table) + } +} + +/// A memory export value. +#[derive(Debug, Clone)] +pub struct ExportMemory { + /// The VM memory, containing info about the table. + pub vm_memory: VMExportMemory, +} + +impl From for Export { + fn from(memory: ExportMemory) -> Self { + Self::Memory(memory) + } +} + +/// A global export value. +#[derive(Debug, Clone)] +pub struct ExportGlobal { + /// The VM global, containing info about the global. + pub vm_global: VMExportGlobal, +} + +impl From for Export { + fn from(global: ExportGlobal) -> Self { + Self::Global(global) + } +} From e96022034f7ecbc3d8693cd2c69b66920ac8828b Mon Sep 17 00:00:00 2001 From: Mark McCaskey Date: Mon, 30 Nov 2020 16:54:32 -0800 Subject: [PATCH 39/39] Update changelog with info about `WasmerEnv` --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ea497fe669..d04379168c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### Changed +- [#1739](https://github.com/wasmerio/wasmer/pull/1739) Environments passed to host function- must now implement the `WasmerEnv` trait. You can implement it on your existing type with `#[derive(WasmerEnv)]`. - [#1838](https://github.com/wasmerio/wasmer/pull/1838) Deprecate `WasiEnv::state_mut`: prefer `WasiEnv::state` instead. - [#1663](https://github.com/wasmerio/wasmer/pull/1663) Function environments passed to host functions now must be passed by `&` instead of `&mut`. This is a breaking change. This change fixes a race condition when a host function is called from multiple threads. If you need mutability in your environment, consider using `std::sync::Mutex` or other synchronization primitives. - [#1830](https://github.com/wasmerio/wasmer/pull/1830) Minimum supported Rust version bumped to 1.47.0