mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-16 17:18:57 +00:00
Experimental: clone host envs during construction
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2826,7 +2826,6 @@ dependencies = [
|
||||
"wasmer-compiler-cranelift",
|
||||
"wasmer-compiler-llvm",
|
||||
"wasmer-compiler-singlepass",
|
||||
"wasmer-emscripten",
|
||||
"wasmer-engine",
|
||||
"wasmer-engine-dummy",
|
||||
"wasmer-engine-jit",
|
||||
|
||||
@@ -15,7 +15,7 @@ wasmer-compiler = { version = "1.0.0-beta1", path = "lib/compiler" }
|
||||
wasmer-compiler-cranelift = { version = "1.0.0-beta1", path = "lib/compiler-cranelift", optional = true }
|
||||
wasmer-compiler-singlepass = { version = "1.0.0-beta1", path = "lib/compiler-singlepass", optional = true }
|
||||
wasmer-compiler-llvm = { version = "1.0.0-beta1", path = "lib/compiler-llvm", optional = true }
|
||||
wasmer-emscripten = { version = "1.0.0-beta1", path = "lib/emscripten", optional = true }
|
||||
#wasmer-emscripten = { version = "1.0.0-beta1", path = "lib/emscripten", optional = true }
|
||||
wasmer-engine = { version = "1.0.0-beta1", path = "lib/engine" }
|
||||
wasmer-engine-jit = { version = "1.0.0-beta1", path = "lib/engine-jit", optional = true }
|
||||
wasmer-engine-native = { version = "1.0.0-beta1", path = "lib/engine-native", optional = true }
|
||||
@@ -38,7 +38,7 @@ members = [
|
||||
"lib/compiler-singlepass",
|
||||
"lib/compiler-llvm",
|
||||
"lib/derive",
|
||||
"lib/emscripten",
|
||||
# "lib/emscripten",
|
||||
"lib/engine",
|
||||
"lib/engine-jit",
|
||||
"lib/engine-native",
|
||||
@@ -81,7 +81,7 @@ default = [
|
||||
"object-file",
|
||||
"cache",
|
||||
"wasi",
|
||||
"emscripten",
|
||||
# "emscripten",
|
||||
"middlewares",
|
||||
]
|
||||
engine = []
|
||||
@@ -100,7 +100,7 @@ object-file = [
|
||||
cache = ["wasmer-cache"]
|
||||
wast = ["wasmer-wast"]
|
||||
wasi = ["wasmer-wasi"]
|
||||
emscripten = ["wasmer-emscripten"]
|
||||
#emscripten = ["wasmer-emscripten"]
|
||||
wat = ["wasmer/wat"]
|
||||
compiler = [
|
||||
"wasmer/compiler",
|
||||
|
||||
@@ -70,7 +70,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// possible to know the size of the `Env` at compile time (i.e it has to
|
||||
// implement the `Sized` trait) and that it implement the `WasmerEnv` trait.
|
||||
// We derive a default implementation of `WasmerEnv` here.
|
||||
#[derive(WasmerEnv)]
|
||||
#[derive(WasmerEnv, Clone)]
|
||||
struct Env {
|
||||
counter: Arc<RefCell<i32>>,
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ impl From<ExportError> for HostEnvInitError {
|
||||
/// ```
|
||||
/// use wasmer::{WasmerEnv, LazyInit, Memory, NativeFunc};
|
||||
///
|
||||
/// #[derive(WasmerEnv)]
|
||||
/// #[derive(WasmerEnv, Clone)]
|
||||
/// pub struct MyEnvWithNoInstanceData {
|
||||
/// non_instance_data: u8,
|
||||
/// }
|
||||
///
|
||||
/// #[derive(WasmerEnv)]
|
||||
/// #[derive(WasmerEnv, Clone)]
|
||||
/// pub struct MyEnvWithInstanceData {
|
||||
/// non_instance_data: u8,
|
||||
/// #[wasmer(export)]
|
||||
@@ -54,6 +54,7 @@ impl From<ExportError> for HostEnvInitError {
|
||||
/// This trait can also be implemented manually:
|
||||
/// ```
|
||||
/// # use wasmer::{WasmerEnv, LazyInit, Memory, Instance, HostEnvInitError};
|
||||
/// #[derive(Clone)]
|
||||
/// pub struct MyEnv {
|
||||
/// memory: LazyInit<Memory>,
|
||||
/// }
|
||||
@@ -66,7 +67,7 @@ impl From<ExportError> for HostEnvInitError {
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub trait WasmerEnv {
|
||||
pub trait WasmerEnv: Clone {
|
||||
/// The function that Wasmer will call on your type to let it finish
|
||||
/// setting up the environment with data from the `Instance`.
|
||||
///
|
||||
@@ -94,28 +95,29 @@ 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 dyn ::std::any::Any {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicBool {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicI8 {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicU8 {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicI16 {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicU16 {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicI32 {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicU32 {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicI64 {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicUsize {}
|
||||
impl<'a> WasmerEnv for &'a ::std::sync::atomic::AtomicIsize {}
|
||||
//impl WasmerEnv for dyn ::std::any::Any + Clone {}
|
||||
impl<T: WasmerEnv> WasmerEnv for Box<T> {
|
||||
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
|
||||
(&mut **self).init_with_instance(instance)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: WasmerEnv> WasmerEnv for &'static mut T {
|
||||
/*impl<T: WasmerEnv> WasmerEnv for &'static T {
|
||||
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
|
||||
T::init_with_instance()
|
||||
(*self).init_with_instance(instance)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/// Lazily init an item
|
||||
pub struct LazyInit<T: Sized> {
|
||||
|
||||
73
lib/api/src/externals/function.rs
vendored
73
lib/api/src/externals/function.rs
vendored
@@ -13,7 +13,7 @@ pub use inner::{UnsafeMutableEnv, WithUnsafeMutableEnv};
|
||||
use std::cmp::max;
|
||||
use std::fmt;
|
||||
use std::sync::Arc;
|
||||
use wasmer_engine::{Export, ExportFunction};
|
||||
use wasmer_engine::{Export, ExportFunction, ExportFunctionMetadata};
|
||||
use wasmer_vm::{
|
||||
raise_user_trap, resume_panic, wasmer_call_trampoline, VMCallerCheckedAnyfunc,
|
||||
VMDynamicFunctionContext, VMExportFunction, VMFunctionBody, VMFunctionEnvironment,
|
||||
@@ -97,22 +97,32 @@ 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 = VMFunctionEnvironment {
|
||||
host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _,
|
||||
let host_env = Box::into_raw(Box::new(dynamic_ctx)) as *mut _;
|
||||
let vmctx = VMFunctionEnvironment { host_env };
|
||||
let host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void = |ptr| {
|
||||
let duped_env = unsafe {
|
||||
let ptr: *mut VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv> = ptr as _;
|
||||
let item: &VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv> = &*ptr;
|
||||
item.clone()
|
||||
};
|
||||
let host_env_drop_fn: Option<fn(*mut std::ffi::c_void)> =
|
||||
Some(|ptr: *mut std::ffi::c_void| {
|
||||
Box::into_raw(Box::new(duped_env)) as _
|
||||
};
|
||||
let host_env_drop_fn: fn(*mut std::ffi::c_void) = |ptr: *mut std::ffi::c_void| {
|
||||
unsafe {
|
||||
Box::from_raw(ptr as *mut VMDynamicFunctionContext<VMDynamicFunctionWithoutEnv>)
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
Self {
|
||||
store: store.clone(),
|
||||
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: false }),
|
||||
exported: ExportFunction {
|
||||
metadata: Some(Arc::new(ExportFunctionMetadata {
|
||||
host_env,
|
||||
import_init_function_ptr: None,
|
||||
host_env_clone_fn,
|
||||
host_env_drop_fn,
|
||||
})),
|
||||
vm_function: Arc::new(VMExportFunction {
|
||||
address,
|
||||
kind: VMFunctionKind::Dynamic,
|
||||
@@ -162,9 +172,8 @@ 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 = VMFunctionEnvironment {
|
||||
host_env: Box::into_raw(Box::new(dynamic_ctx)) as *mut _,
|
||||
};
|
||||
let host_env = Box::into_raw(Box::new(dynamic_ctx)) as *mut _;
|
||||
let vmctx = VMFunctionEnvironment { host_env };
|
||||
let import_init_function_ptr: fn(_, _) -> Result<(), _> =
|
||||
|ptr: *mut std::ffi::c_void, instance: *const std::ffi::c_void| {
|
||||
let ptr = ptr as *mut VMDynamicFunctionContext<VMDynamicFunctionWithEnv<Env>>;
|
||||
@@ -180,21 +189,30 @@ impl Function {
|
||||
import_init_function_ptr,
|
||||
)
|
||||
});
|
||||
let host_env_drop_fn: Option<fn(*mut std::ffi::c_void)> =
|
||||
Some(|ptr: *mut std::ffi::c_void| {
|
||||
unsafe {
|
||||
Box::from_raw(
|
||||
ptr as *mut VMDynamicFunctionContext<VMDynamicFunctionWithEnv<Env>>,
|
||||
)
|
||||
let host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void = |ptr| {
|
||||
let duped_env = unsafe {
|
||||
let ptr: *mut VMDynamicFunctionContext<VMDynamicFunctionWithEnv<Env>> = ptr as _;
|
||||
let item: &VMDynamicFunctionContext<VMDynamicFunctionWithEnv<Env>> = &*ptr;
|
||||
item.clone()
|
||||
};
|
||||
Box::into_raw(Box::new(duped_env)) as _
|
||||
};
|
||||
let host_env_drop_fn: fn(*mut std::ffi::c_void) = |ptr: *mut std::ffi::c_void| {
|
||||
unsafe {
|
||||
Box::from_raw(ptr as *mut VMDynamicFunctionContext<VMDynamicFunctionWithEnv<Env>>)
|
||||
};
|
||||
};
|
||||
});
|
||||
|
||||
Self {
|
||||
store: store.clone(),
|
||||
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
|
||||
exported: ExportFunction {
|
||||
metadata: Some(Arc::new(ExportFunctionMetadata {
|
||||
host_env,
|
||||
import_init_function_ptr,
|
||||
host_env_clone_fn,
|
||||
host_env_drop_fn,
|
||||
})),
|
||||
vm_function: Arc::new(VMExportFunction {
|
||||
address,
|
||||
kind: VMFunctionKind::Dynamic,
|
||||
@@ -248,8 +266,7 @@ impl Function {
|
||||
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
|
||||
import_init_function_ptr: None,
|
||||
host_env_drop_fn: None,
|
||||
metadata: None,
|
||||
vm_function: Arc::new(VMExportFunction {
|
||||
address,
|
||||
vmctx,
|
||||
@@ -304,13 +321,19 @@ 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 = VMFunctionEnvironment {
|
||||
host_env: Box::into_raw(box_env) as *mut _,
|
||||
let host_env = Box::into_raw(box_env) as *mut _;
|
||||
let vmctx = VMFunctionEnvironment { host_env };
|
||||
let host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void = |ptr| {
|
||||
let duped_env = unsafe {
|
||||
let ptr: *mut Env = ptr as _;
|
||||
let item: &Env = &*ptr;
|
||||
item.clone()
|
||||
};
|
||||
let host_env_drop_fn: Option<fn(*mut std::ffi::c_void)> =
|
||||
Some(|ptr: *mut std::ffi::c_void| {
|
||||
Box::into_raw(Box::new(duped_env)) as _
|
||||
};
|
||||
let host_env_drop_fn: fn(*mut std::ffi::c_void) = |ptr: *mut std::ffi::c_void| {
|
||||
unsafe { Box::from_raw(ptr as *mut Env) };
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: look into removing transmute by changing API type signatures
|
||||
let import_init_function_ptr = Some(unsafe {
|
||||
@@ -324,8 +347,12 @@ impl Function {
|
||||
store: store.clone(),
|
||||
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
|
||||
exported: ExportFunction {
|
||||
metadata: Some(Arc::new(ExportFunctionMetadata {
|
||||
host_env,
|
||||
import_init_function_ptr,
|
||||
host_env_clone_fn,
|
||||
host_env_drop_fn,
|
||||
})),
|
||||
vm_function: Arc::new(VMExportFunction {
|
||||
address,
|
||||
kind: VMFunctionKind::Static,
|
||||
|
||||
@@ -88,8 +88,7 @@ where
|
||||
let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
|
||||
Self {
|
||||
// TODO:
|
||||
import_init_function_ptr: None,
|
||||
host_env_drop_fn: None,
|
||||
metadata: None,
|
||||
vm_function: Arc::new(VMExportFunction {
|
||||
address: other.address,
|
||||
vmctx: other.vmctx,
|
||||
@@ -114,8 +113,7 @@ where
|
||||
definition: other.definition,
|
||||
exported: ExportFunction {
|
||||
// TODO:
|
||||
import_init_function_ptr: None,
|
||||
host_env_drop_fn: None,
|
||||
metadata: None,
|
||||
vm_function: Arc::new(VMExportFunction {
|
||||
address: other.address,
|
||||
vmctx: other.vmctx,
|
||||
|
||||
@@ -76,8 +76,7 @@ impl ValFuncRef for Val {
|
||||
let export = wasmer_engine::ExportFunction {
|
||||
// TODO:
|
||||
// figure out if we ever need a value here: need testing with complicated import patterns
|
||||
import_init_function_ptr: None,
|
||||
host_env_drop_fn: None,
|
||||
metadata: None,
|
||||
vm_function: std::sync::Arc::new(wasmer_vm::VMExportFunction {
|
||||
address: item.func_ptr,
|
||||
signature,
|
||||
|
||||
@@ -122,7 +122,7 @@ lazy_static! {
|
||||
const GLOBAL_BASE: u32 = 1024;
|
||||
const STATIC_BASE: u32 = GLOBAL_BASE;
|
||||
|
||||
#[derive(WasmerEnv, Default)]
|
||||
#[derive(WasmerEnv, Clone, Default)]
|
||||
pub struct EmscriptenData {
|
||||
pub globals: EmscriptenGlobalsData,
|
||||
|
||||
|
||||
@@ -37,8 +37,7 @@ impl From<VMExport> for Export {
|
||||
match other {
|
||||
VMExport::Function(vm_function) => Export::Function(ExportFunction {
|
||||
vm_function,
|
||||
import_init_function_ptr: None,
|
||||
host_env_drop_fn: None,
|
||||
metadata: None,
|
||||
}),
|
||||
VMExport::Memory(vm_memory) => Export::Memory(ExportMemory { vm_memory }),
|
||||
VMExport::Table(vm_table) => Export::Table(ExportTable { vm_table }),
|
||||
@@ -47,19 +46,41 @@ impl From<VMExport> for Export {
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: rename, etc.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct ExportFunctionMetadata {
|
||||
/// duplicated here so we can free it....
|
||||
/// TODO: refactor all this stuff so it's less of a nightmare.
|
||||
pub host_env: *mut std::ffi::c_void,
|
||||
/// 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`.
|
||||
// This one is optional for now because dynamic host envs need the rest
|
||||
// of this without the init fn
|
||||
pub import_init_function_ptr: Option<ImportInitializerFuncPtr>,
|
||||
/// TODO:
|
||||
pub host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void,
|
||||
/// The destructor to free the host environment.
|
||||
pub host_env_drop_fn: fn(*mut std::ffi::c_void),
|
||||
}
|
||||
|
||||
impl Drop for ExportFunctionMetadata {
|
||||
fn drop(&mut self) {
|
||||
if !self.host_env.is_null() {
|
||||
(self.host_env_drop_fn)(self.host_env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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: Arc<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<ImportInitializerFuncPtr>,
|
||||
/// The destructor to free the host environment.
|
||||
pub host_env_drop_fn: Option<fn(*mut std::ffi::c_void)>,
|
||||
/// TODO:
|
||||
pub metadata: Option<Arc<ExportFunctionMetadata>>,
|
||||
}
|
||||
|
||||
impl From<ExportFunction> for Export {
|
||||
|
||||
@@ -34,7 +34,9 @@ pub use crate::engine::{Engine, EngineId};
|
||||
pub use crate::error::{
|
||||
DeserializeError, ImportError, InstantiationError, LinkError, SerializeError,
|
||||
};
|
||||
pub use crate::export::{Export, ExportFunction, ExportGlobal, ExportMemory, ExportTable};
|
||||
pub use crate::export::{
|
||||
Export, ExportFunction, ExportFunctionMetadata, ExportGlobal, ExportMemory, ExportTable,
|
||||
};
|
||||
pub use crate::resolver::{
|
||||
resolve_imports, ChainableNamedResolver, NamedResolver, NamedResolverChain, NullResolver,
|
||||
Resolver,
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
//! Define the `Resolver` trait, allowing custom resolution for external
|
||||
//! references.
|
||||
|
||||
use crate::{Export, ImportError, LinkError};
|
||||
use crate::{Export, ExportFunctionMetadata, ImportError, LinkError};
|
||||
use more_asserts::assert_ge;
|
||||
use std::sync::Arc;
|
||||
use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
|
||||
use wasmer_types::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, TableIndex};
|
||||
|
||||
use wasmer_vm::{
|
||||
FunctionBodyPtr, ImportEnv, Imports, MemoryStyle, ModuleInfo, TableStyle,
|
||||
VMDynamicFunctionContext, VMFunctionBody, VMFunctionImport, VMFunctionKind, VMGlobalImport,
|
||||
VMMemoryImport, VMTableImport,
|
||||
FunctionBodyPtr, ImportEnv, Imports, MemoryStyle, ModuleInfo, TableStyle, VMFunctionBody,
|
||||
VMFunctionEnvironment, VMFunctionImport, VMFunctionKind, VMGlobalImport, VMMemoryImport,
|
||||
VMTableImport,
|
||||
};
|
||||
|
||||
/// Import resolver connects imports with available exported values.
|
||||
@@ -179,16 +178,42 @@ pub fn resolve_imports(
|
||||
f.vm_function.address
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: add lots of documentation for this really strange
|
||||
// looking code.
|
||||
// Also, keep eyes open for refactor opportunities to clean
|
||||
// this all up.
|
||||
let env = if let Some(ExportFunctionMetadata {
|
||||
host_env_clone_fn: clone,
|
||||
..
|
||||
}) = f.metadata.as_ref().map(|x| &**x)
|
||||
{
|
||||
// TODO: maybe start adding asserts in all these
|
||||
// unsafe blocks to prevent future changes from
|
||||
// horribly breaking things.
|
||||
unsafe {
|
||||
assert!(!f.vm_function.vmctx.host_env.is_null());
|
||||
(clone)(f.vm_function.vmctx.host_env)
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
assert!(f.vm_function.vmctx.host_env.is_null());
|
||||
f.vm_function.vmctx.host_env
|
||||
}
|
||||
};
|
||||
|
||||
function_imports.push(VMFunctionImport {
|
||||
body: address,
|
||||
environment: f.vm_function.vmctx,
|
||||
environment: VMFunctionEnvironment { host_env: env },
|
||||
});
|
||||
|
||||
host_function_env_initializers.push(Arc::new(ImportEnv {
|
||||
env: unsafe { f.vm_function.vmctx.host_env },
|
||||
initializer: f.import_init_function_ptr,
|
||||
destructor: f.host_env_drop_fn,
|
||||
}));
|
||||
host_function_env_initializers.push(ImportEnv {
|
||||
env,
|
||||
// TODO: consider just passing metadata directly
|
||||
initializer: f.metadata.as_ref().and_then(|m| m.import_init_function_ptr),
|
||||
clone: f.metadata.as_ref().map(|m| m.host_env_clone_fn),
|
||||
destructor: f.metadata.as_ref().map(|m| m.host_env_drop_fn),
|
||||
});
|
||||
}
|
||||
Export::Table(ref t) => {
|
||||
table_imports.push(VMTableImport {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
use crate::instance::ImportEnv;
|
||||
use crate::vmcontext::{VMFunctionImport, VMGlobalImport, VMMemoryImport, VMTableImport};
|
||||
use std::sync::Arc;
|
||||
use wasmer_types::entity::{BoxedSlice, PrimaryMap};
|
||||
use wasmer_types::{FunctionIndex, GlobalIndex, MemoryIndex, TableIndex};
|
||||
|
||||
@@ -18,7 +17,7 @@ pub struct Imports {
|
||||
/// space may affect Wasm runtime performance due to increased cache pressure.
|
||||
///
|
||||
/// We make it optional so that we can free the data after use.
|
||||
pub host_function_env_initializers: Option<BoxedSlice<FunctionIndex, Arc<ImportEnv>>>,
|
||||
pub host_function_env_initializers: Option<BoxedSlice<FunctionIndex, ImportEnv>>,
|
||||
|
||||
/// Resolved addresses for imported tables.
|
||||
pub tables: BoxedSlice<TableIndex, VMTableImport>,
|
||||
@@ -34,7 +33,7 @@ impl Imports {
|
||||
/// Construct a new `Imports` instance.
|
||||
pub fn new(
|
||||
function_imports: PrimaryMap<FunctionIndex, VMFunctionImport>,
|
||||
host_function_env_initializers: PrimaryMap<FunctionIndex, Arc<ImportEnv>>,
|
||||
host_function_env_initializers: PrimaryMap<FunctionIndex, ImportEnv>,
|
||||
table_imports: PrimaryMap<TableIndex, VMTableImport>,
|
||||
memory_imports: PrimaryMap<MemoryIndex, VMMemoryImport>,
|
||||
global_imports: PrimaryMap<GlobalIndex, VMGlobalImport>,
|
||||
@@ -64,7 +63,7 @@ impl Imports {
|
||||
///
|
||||
/// 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) -> BoxedSlice<FunctionIndex, Arc<ImportEnv>> {
|
||||
pub fn get_import_initializers(&mut self) -> BoxedSlice<FunctionIndex, ImportEnv> {
|
||||
self.host_function_env_initializers
|
||||
.take()
|
||||
.unwrap_or_else(|| PrimaryMap::new().into_boxed_slice())
|
||||
|
||||
@@ -45,11 +45,6 @@ use wasmer_types::{
|
||||
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
|
||||
/// function's environments with the [`Instance`].
|
||||
pub(crate) type ImportInitializerThunks =
|
||||
Vec<(Option<ImportInitializerFuncPtr>, *mut std::ffi::c_void)>;
|
||||
|
||||
/// A WebAssembly instance.
|
||||
///
|
||||
/// The type is dynamically-sized. Indeed, the `vmctx` field can
|
||||
@@ -101,7 +96,7 @@ pub(crate) struct Instance {
|
||||
/// TODO: Be sure to test with serialize/deserialize and imported
|
||||
/// functions from other Wasm modules.
|
||||
/// TODO: update this comment
|
||||
import_envs: BoxedSlice<FunctionIndex, Arc<ImportEnv>>,
|
||||
import_envs: BoxedSlice<FunctionIndex, ImportEnv>,
|
||||
|
||||
/// Additional context used by compiled WebAssembly code. This
|
||||
/// field is last, and represents a dynamically-sized array that
|
||||
@@ -118,11 +113,29 @@ pub struct ImportEnv {
|
||||
/// TODO:
|
||||
pub env: *mut std::ffi::c_void,
|
||||
/// TODO:
|
||||
pub clone: Option<fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void>,
|
||||
/// TODO:
|
||||
pub initializer: Option<ImportInitializerFuncPtr>,
|
||||
/// TODO:
|
||||
pub destructor: Option<fn(*mut std::ffi::c_void)>,
|
||||
}
|
||||
|
||||
impl Clone for ImportEnv {
|
||||
fn clone(&self) -> Self {
|
||||
let env = if let Some(clone) = self.clone {
|
||||
(clone)(self.env)
|
||||
} else {
|
||||
self.env
|
||||
};
|
||||
Self {
|
||||
env,
|
||||
clone: self.clone.clone(),
|
||||
initializer: self.initializer.clone(),
|
||||
destructor: self.destructor.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ImportEnv {
|
||||
fn drop(&mut self) {
|
||||
if let Some(destructor) = self.destructor {
|
||||
@@ -1029,7 +1042,7 @@ impl InstanceHandle {
|
||||
imports: Imports,
|
||||
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||
host_state: Box<dyn Any>,
|
||||
import_envs: BoxedSlice<FunctionIndex, Arc<ImportEnv>>,
|
||||
import_envs: BoxedSlice<FunctionIndex, ImportEnv>,
|
||||
) -> Result<Self, Trap> {
|
||||
// `NonNull<u8>` here actually means `NonNull<Instance>`. See
|
||||
// `Self::allocate_instance` to understand why.
|
||||
@@ -1435,7 +1448,7 @@ impl InstanceHandle {
|
||||
|
||||
for ImportEnv {
|
||||
env, initializer, ..
|
||||
} in instance_ref.import_envs.values().map(|v| &**v)
|
||||
} in instance_ref.import_envs.values_mut()
|
||||
{
|
||||
if let Some(ref f) = initializer {
|
||||
// transmute our function pointer into one with the correct error type
|
||||
@@ -1444,7 +1457,7 @@ impl InstanceHandle {
|
||||
&fn(*mut ffi::c_void, *const ffi::c_void) -> Result<(), Err>,
|
||||
>(f);
|
||||
f(*env, instance_ptr)?;
|
||||
//*initializer = None;
|
||||
*initializer = None;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -343,3 +343,52 @@ fn dynamic_function_with_env_wasmer_env_init_works() -> Result<()> {
|
||||
f.call()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multi_use_host_fn_manages_memory_correctly() -> Result<()> {
|
||||
let store = get_store(false);
|
||||
let module = get_module2(&store)?;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone)]
|
||||
struct Env {
|
||||
memory: LazyInit<Memory>,
|
||||
};
|
||||
|
||||
impl WasmerEnv for Env {
|
||||
fn init_with_instance(&mut self, instance: &Instance) -> Result<(), HostEnvInitError> {
|
||||
dbg!("Initing the env!");
|
||||
let memory = instance.exports.get_memory("memory")?.clone();
|
||||
self.memory.initialize(memory);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
let env: Env = Env {
|
||||
memory: LazyInit::default(),
|
||||
};
|
||||
fn host_fn(env: &Env) {
|
||||
dbg!(env as *const _);
|
||||
assert!(env.memory.get_ref().is_some());
|
||||
println!("Hello, world!");
|
||||
}
|
||||
|
||||
let imports = imports! {
|
||||
"host" => {
|
||||
"fn" => Function::new_native_with_env(&store, env.clone(), host_fn),
|
||||
},
|
||||
};
|
||||
let instance1 = Instance::new(&module, &imports)?;
|
||||
let instance2 = Instance::new(&module, &imports)?;
|
||||
{
|
||||
let f1: NativeFunc<(), ()> = instance1.exports.get_native_function("main")?;
|
||||
f1.call()?;
|
||||
}
|
||||
drop(instance1);
|
||||
{
|
||||
let f2: NativeFunc<(), ()> = instance2.exports.get_native_function("main")?;
|
||||
f2.call()?;
|
||||
}
|
||||
drop(instance2);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user