diff --git a/lib/deprecated/runtime-core/src/instance.rs b/lib/deprecated/runtime-core/src/instance.rs index b80ca0e00..eda66b89d 100644 --- a/lib/deprecated/runtime-core/src/instance.rs +++ b/lib/deprecated/runtime-core/src/instance.rs @@ -2,22 +2,29 @@ use crate::{ error::ExportError, export::Exportable, import::LikeNamespace, module::Module, new, structures::TypedIndex, types::Value, vm, }; -use std::error::Error; +use std::{ + cell::{Ref, RefCell}, + error::Error, +}; #[derive(Debug)] pub(crate) struct PreInstance { - pub(crate) vmctx: vm::Ctx, + pub(crate) vmctx: RefCell, } impl PreInstance { pub(crate) fn new() -> Self { Self { - vmctx: vm::Ctx::new(), + vmctx: RefCell::new(vm::Ctx::new()), } } + pub(crate) fn vmctx(&self) -> RefCell { + self.vmctx.clone() + } + pub(crate) fn vmctx_ptr(&self) -> *mut vm::Ctx { - &self.vmctx as *const _ as *mut _ + self.vmctx.as_ptr() } } @@ -71,12 +78,12 @@ impl Instance { Module::new(self.new_instance.module().clone()) } - pub fn context(&self) -> &vm::Ctx { - &self.pre_instance.vmctx + pub fn context(&self) -> Ref { + self.pre_instance.vmctx.borrow() } pub fn context_mut(&mut self) -> &mut vm::Ctx { - &mut self.pre_instance.vmctx + self.pre_instance.vmctx.get_mut() } } diff --git a/lib/deprecated/runtime-core/src/lib.rs b/lib/deprecated/runtime-core/src/lib.rs index eeadcbadb..81284830a 100644 --- a/lib/deprecated/runtime-core/src/lib.rs +++ b/lib/deprecated/runtime-core/src/lib.rs @@ -38,7 +38,7 @@ pub use functional_api::{ pub mod prelude { pub use crate::import::{namespace, ImportObject, Namespace}; - pub use crate::typed_func::Func; + pub use crate::typed_func::{DynamicFunc, Func}; pub use crate::types::{FuncIndex, GlobalIndex, MemoryIndex, TableIndex, Type, Value}; } diff --git a/lib/deprecated/runtime-core/src/module.rs b/lib/deprecated/runtime-core/src/module.rs index 05b44172b..ffb6cf3b7 100644 --- a/lib/deprecated/runtime-core/src/module.rs +++ b/lib/deprecated/runtime-core/src/module.rs @@ -1,12 +1,15 @@ use crate::{ cache::Artifact, - error::InstantiationError, + error::{InstantiationError, RuntimeError}, import::{ImportObject, Namespace}, instance::{Instance, PreInstance}, - new, vm, + new, + types::{FuncSig, Value}, + vm, }; use new::wasmer_runtime::Export; use std::{ + cell::RefCell, collections::HashMap, convert::{AsRef, Infallible}, ptr, @@ -52,28 +55,74 @@ impl Module { Export::Function(mut function) => { // That's an ugly hack. Go your way :-]. { - // An empty `vm::Ctx` was created in - // `Func` as a host function - // environment. The internals of - // `new::wasmer::externals::Function` - // passes the environment inside the - // `VMContext` pointer. That's another - // hack. This empty `vm::Ctx` must be - // replaced by another `vm::Ctx` value - // owned by `Instance`, because that's the - // only way to update this structure - // correctly for compatibility - // purposes. Before doing this operation, - // we must drop the empty `vm::Ctx` first. - unsafe { - ptr::drop_in_place::(function.vmctx as _); - } + // That's a static host function + // constructed with + // `new::wasmer::Function::new_env`. + if !function.address.is_null() { + // An empty `vm::Ctx` was created in + // `Func` as a host function + // environment. The internals of + // `new::wasmer::externals::Function` + // passes the environment inside the + // `VMContext` pointer. That's another + // hack. This empty `vm::Ctx` must be + // replaced by another `vm::Ctx` value + // owned by `Instance`, because that's the + // only way to update this structure + // correctly for compatibility + // purposes. Before doing this operation, + // we must drop the empty `vm::Ctx` first. + unsafe { + ptr::drop_in_place::(function.vmctx as _); + } - // And now we can 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 _; + // And now we can 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 _; + } + // That's a dynamic host function + // constructed with + // `new::wasmer::Function::new_dynamic_env`. + else { + // `new::wasmer::VMDynamicFunctionWithEnv` + // is private to `new::wasmer`. Let's + // replicate it, and hope the layout + // is the same! + struct VMDynamicFunctionWithEnv + where + Env: Sized + 'static, + { + #[allow(unused)] + function_type: FuncSig, + #[allow(unused)] + func: Box< + dyn Fn( + &mut Env, + &[Value], + ) + -> Result, RuntimeError> + + 'static, + >, + env: RefCell, + } + + // Get back the `vmctx` as it is + // stored by + // `new::wasmer::Function::new_dynamic_env`. + let vmctx: Box< + new::wasmer_runtime::VMDynamicFunctionContext< + VMDynamicFunctionWithEnv, + >, + > = unsafe { Box::from_raw(function.vmctx as *mut _) }; + + // Replace the environment by ours. + vmctx.ctx.env.swap(&pre_instance.vmctx()); + + // … without anyone noticing… + function.vmctx = 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 2d5b5a48d..71e294ffd 100644 --- a/lib/deprecated/runtime-core/src/typed_func.rs +++ b/lib/deprecated/runtime-core/src/typed_func.rs @@ -2,7 +2,7 @@ use crate::{ error::{ExportError, RuntimeError}, get_global_store, new::{self, wasm_common::NativeWasmType}, - types::{FuncDescriptor, Type, Value}, + types::{FuncDescriptor, FuncSig, Type, Value}, vm, }; use std::marker::PhantomData; @@ -204,3 +204,73 @@ where } } } + +#[derive(Clone)] +pub struct DynamicFunc { + new_function: new::wasmer::Function, +} + +impl DynamicFunc { + pub fn new(signature: &FuncSig, func: F) -> Self + where + F: Fn(&mut vm::Ctx, &[Value]) -> Result, RuntimeError> + 'static, + { + // Create an empty `vm::Ctx`, that is going to be overwritten by `Instance::new`. + let ctx = vm::Ctx::new(); + + Self { + new_function: new::wasmer::Function::new_dynamic_env( + get_global_store(), + signature, + ctx, + func, + ), + } + } + + pub fn signature(&self) -> &FuncDescriptor { + self.new_function.ty() + } + + pub fn params(&self) -> &[Type] { + self.signature().params() + } + + pub fn returns(&self) -> &[Type] { + self.signature().results() + } + + pub fn dyn_call(&self, params: &[Value]) -> Result, RuntimeError> { + self.new_function.call(params) + } +} + +impl From for new::wasmer::Extern { + fn from(dynamic_func: DynamicFunc) -> Self { + new::wasmer::Extern::Function(dynamic_func.new_function) + } +} + +impl From<&new::wasmer::Function> for DynamicFunc { + fn from(new_function: &new::wasmer::Function) -> Self { + Self { + new_function: new_function.clone(), + } + } +} + +impl<'a> new::wasmer::Exportable<'a> for DynamicFunc { + fn to_export(&self) -> new::wasmer_runtime::Export { + self.new_function.to_export() + } + + fn get_self_from_extern(r#extern: &'a new::wasmer::Extern) -> Result<&'a Self, ExportError> { + match r#extern { + new::wasmer::Extern::Function(dynamic_func) => Ok( + // It's not ideal to call `Box::leak` here, but it would introduce too much changes in the `new::wasmer` API to support `Cow` or similar. + Box::leak(Box::::new(dynamic_func.into())), + ), + _ => Err(ExportError::IncompatibleType), + } + } +} diff --git a/lib/deprecated/runtime/src/lib.rs b/lib/deprecated/runtime/src/lib.rs index 35f399b49..59bcc83e5 100644 --- a/lib/deprecated/runtime/src/lib.rs +++ b/lib/deprecated/runtime/src/lib.rs @@ -8,7 +8,7 @@ pub use wasmer_runtime_core::memory::ptr::{Array, Item, WasmPtr}; pub use wasmer_runtime_core::memory::Memory; pub use wasmer_runtime_core::module::Module; pub use wasmer_runtime_core::table::Table; -pub use wasmer_runtime_core::typed_func::Func; +pub use wasmer_runtime_core::typed_func::{DynamicFunc, Func}; pub use wasmer_runtime_core::types; pub use wasmer_runtime_core::vm::Ctx; pub use wasmer_runtime_core::{