Experimental: clone host envs during construction

This commit is contained in:
Mark McCaskey
2020-12-04 16:04:03 -08:00
parent 1eaea6ecf1
commit e43d9d2732
14 changed files with 231 additions and 97 deletions

1
Cargo.lock generated
View File

@@ -2826,7 +2826,6 @@ dependencies = [
"wasmer-compiler-cranelift",
"wasmer-compiler-llvm",
"wasmer-compiler-singlepass",
"wasmer-emscripten",
"wasmer-engine",
"wasmer-engine-dummy",
"wasmer-engine-jit",

View File

@@ -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",

View File

@@ -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>>,
}

View File

@@ -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> {

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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())

View File

@@ -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;
}
}

View File

@@ -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(())
}