Skip to content

Commit

Permalink
Try #1663:
Browse files Browse the repository at this point in the history
  • Loading branch information
bors[bot] authored Nov 20, 2020
2 parents 875ac93 + a95c445 commit 67bac73
Show file tree
Hide file tree
Showing 48 changed files with 799 additions and 717 deletions.
4 changes: 2 additions & 2 deletions examples/imports_function_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}

// Create the functions
fn get_counter(env: &mut Env) -> i32 {
fn get_counter(env: &Env) -> i32 {
*env.counter.borrow()
}
fn add_to_counter(env: &mut Env, add: i32) -> i32 {
fn add_to_counter(env: &Env, add: i32) -> i32 {
let mut counter_ref = env.counter.borrow_mut();

*counter_ref += add;
Expand Down
2 changes: 2 additions & 0 deletions lib/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ llvm = [
"wasmer-compiler-llvm",
"compiler",
]
# enables internal features used by the deprecated API.
deprecated = []
default-compiler = []
default-engine = []

Expand Down
126 changes: 116 additions & 10 deletions lib/api/src/externals/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use crate::FunctionType;
use crate::NativeFunc;
use crate::RuntimeError;
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
use std::cell::RefCell;
#[cfg(feature = "deprecated")]
pub use inner::{LegacyEnv, WithLegacyEnv};

use std::cmp::max;
use std::fmt;
use wasmer_vm::{
Expand Down Expand Up @@ -125,11 +127,11 @@ impl Function {
#[allow(clippy::cast_ptr_alignment)]
pub fn new_with_env<F, Env>(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self
where
F: Fn(&mut Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static,
F: Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static,
Env: Sized + 'static,
{
let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv {
env: RefCell::new(env),
env: Box::new(env),
func: Box::new(func),
function_type: ty.clone(),
});
Expand Down Expand Up @@ -214,7 +216,7 @@ impl Function {
/// };
/// let env = Env { multiplier: 2 };
///
/// fn sum_and_multiply(env: &mut Env, a: i32, b: i32) -> i32 {
/// fn sum_and_multiply(env: &Env, a: i32, b: i32) -> i32 {
/// (a + b) * env.multiplier
/// }
///
Expand Down Expand Up @@ -254,6 +256,47 @@ impl Function {
}
}

/// Function used by the deprecated API to call a function with a `&mut` Env.
///
/// This is not a stable API and may be broken at any time.
///
/// # Safety
/// - This function is only safe to use from the deprecated API.
#[doc(hidden)]
#[cfg(feature = "deprecated")]
pub unsafe fn new_native_with_env_legacy<F, Args, Rets, Env>(
store: &Store,
env: Env,
func: F,
) -> Self
where
F: HostFunction<Args, Rets, WithLegacyEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: LegacyEnv + 'static,
{
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address();

let box_env = Box::new(env);
let vmctx = VMFunctionEnvironment {
host_env: Box::into_raw(box_env) as *mut _,
};
let signature = function.ty();

Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Static,
vmctx,
signature,
call_trampoline: None,
},
}
}

/// Returns the [`FunctionType`] of the `Function`.
///
/// # Example
Expand Down Expand Up @@ -628,18 +671,16 @@ where
{
function_type: FunctionType,
#[allow(clippy::type_complexity)]
func: Box<dyn Fn(&mut Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>,
env: RefCell<Env>,
func: Box<dyn Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>,
env: Box<Env>,
}

impl<Env> VMDynamicFunction for VMDynamicFunctionWithEnv<Env>
where
Env: Sized + 'static,
{
fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError> {
// TODO: the `&mut *self.env.as_ptr()` is likely invoking some "mild"
// undefined behavior due to how it's used in the static fn call
unsafe { (*self.func)(&mut *self.env.as_ptr(), &args) }
(*self.func)(&*self.env, &args)
}
fn function_type(&self) -> &FunctionType {
&self.function_type
Expand Down Expand Up @@ -979,6 +1020,14 @@ mod inner {
fn function_body_ptr(self) -> *const VMFunctionBody;
}

/// Marker trait to limit what the hidden APIs needed for the deprecated API
/// can be used on.
///
/// Marks an environment as being passed by `&mut`.
#[cfg(feature = "deprecated")]
#[doc(hidden)]
pub unsafe trait LegacyEnv: Sized {}

/// Empty trait to specify the kind of `HostFunction`: With or
/// without an environment.
///
Expand All @@ -994,6 +1043,18 @@ mod inner {

impl HostFunctionKind for WithEnv {}

/// An empty struct to help Rust typing to determine
/// when a `HostFunction` does have an environment.
///
/// This environment is passed by `&mut` and exists soley for the deprecated
/// API.
#[cfg(feature = "deprecated")]
#[doc(hidden)]
pub struct WithLegacyEnv;

#[cfg(feature = "deprecated")]
impl HostFunctionKind for WithLegacyEnv {}

/// An empty struct to help Rust typing to determine
/// when a `HostFunction` does not have an environment.
pub struct WithoutEnv;
Expand Down Expand Up @@ -1187,6 +1248,52 @@ mod inner {
Rets: WasmTypeList,
RetsAsResult: IntoResult<Rets>,
Env: Sized,
Func: Fn(&Env, $( $x , )*) -> RetsAsResult + Send + 'static,
{
#[allow(non_snake_case)]
fn function_body_ptr(self) -> *const VMFunctionBody {
/// This is a function that wraps the real host
/// function. Its address will be used inside the
/// runtime.
extern fn func_wrapper<$( $x, )* Rets, RetsAsResult, Env, Func>( env: &Env, $( $x: $x::Native, )* ) -> Rets::CStruct
where
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
RetsAsResult: IntoResult<Rets>,
Env: Sized,
Func: Fn(&Env, $( $x ),* ) -> RetsAsResult + 'static
{
let func: &Func = unsafe { &*(&() as *const () as *const Func) };

let result = panic::catch_unwind(AssertUnwindSafe(|| {
func(env, $( FromToNativeWasmType::from_native($x) ),* ).into_result()
}));

match result {
Ok(Ok(result)) => return result.into_c_struct(),
Ok(Err(trap)) => unsafe { raise_user_trap(Box::new(trap)) },
Err(panic) => unsafe { resume_panic(panic) },
}
}

func_wrapper::< $( $x, )* Rets, RetsAsResult, Env, Self > as *const VMFunctionBody
}
}

// Implement `HostFunction` for a function that has the same arity than the tuple.
// This specific function has an environment.
#[doc(hidden)]
#[cfg(feature = "deprecated")]
#[allow(unused_parens)]
impl< $( $x, )* Rets, RetsAsResult, Env, Func >
HostFunction<( $( $x ),* ), Rets, WithLegacyEnv, Env>
for
Func
where
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
RetsAsResult: IntoResult<Rets>,
Env: LegacyEnv,
Func: Fn(&mut Env, $( $x , )*) -> RetsAsResult + Send + 'static,
{
#[allow(non_snake_case)]
Expand Down Expand Up @@ -1218,7 +1325,6 @@ mod inner {
func_wrapper::< $( $x, )* Rets, RetsAsResult, Env, Self > as *const VMFunctionBody
}
}

};
}

Expand Down
3 changes: 3 additions & 0 deletions lib/api/src/externals/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ mod table;
pub use self::function::{
FromToNativeWasmType, Function, HostFunction, WasmTypeList, WithEnv, WithoutEnv,
};

#[cfg(feature = "deprecated")]
pub use self::function::{LegacyEnv, WithLegacyEnv};
pub use self::global::Global;
pub use self::memory::Memory;
pub use self::table::Table;
Expand Down
2 changes: 2 additions & 0 deletions lib/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ pub mod internals {
//! `wasmer-vm`. Please don't use any of this types directly, as
//! they might change frequently or be removed in the future.
#[cfg(feature = "deprecated")]
pub use crate::externals::{LegacyEnv, WithLegacyEnv};
pub use crate::externals::{WithEnv, WithoutEnv};
}

Expand Down
20 changes: 10 additions & 10 deletions lib/api/tests/externals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,33 +211,33 @@ fn function_new_env() -> Result<()> {
#[derive(Clone)]
struct MyEnv {};
let my_env = MyEnv {};
let function = Function::new_native_with_env(&store, my_env.clone(), |_env: &mut MyEnv| {});
let function = Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| {});
assert_eq!(function.ty().clone(), FunctionType::new(vec![], vec![]));
let function =
Function::new_native_with_env(&store, my_env.clone(), |_env: &mut MyEnv, _a: i32| {});
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv, _a: i32| {});
assert_eq!(
function.ty().clone(),
FunctionType::new(vec![Type::I32], vec![])
);
let function = Function::new_native_with_env(
&store,
my_env.clone(),
|_env: &mut MyEnv, _a: i32, _b: i64, _c: f32, _d: f64| {},
|_env: &MyEnv, _a: i32, _b: i64, _c: f32, _d: f64| {},
);
assert_eq!(
function.ty().clone(),
FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![])
);
let function =
Function::new_native_with_env(&store, my_env.clone(), |_env: &mut MyEnv| -> i32 { 1 });
Function::new_native_with_env(&store, my_env.clone(), |_env: &MyEnv| -> i32 { 1 });
assert_eq!(
function.ty().clone(),
FunctionType::new(vec![], vec![Type::I32])
);
let function = Function::new_native_with_env(
&store,
my_env.clone(),
|_env: &mut MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
|_env: &MyEnv| -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) },
);
assert_eq!(
function.ty().clone(),
Expand Down Expand Up @@ -279,39 +279,39 @@ fn function_new_dynamic_env() -> Result<()> {
&store,
&function_type,
my_env.clone(),
|_env: &mut MyEnv, _values: &[Value]| unimplemented!(),
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty().clone(), function_type);
let function_type = FunctionType::new(vec![Type::I32], vec![]);
let function = Function::new_with_env(
&store,
&function_type,
my_env.clone(),
|_env: &mut MyEnv, _values: &[Value]| unimplemented!(),
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty().clone(), function_type);
let function_type = FunctionType::new(vec![Type::I32, Type::I64, Type::F32, Type::F64], vec![]);
let function = Function::new_with_env(
&store,
&function_type,
my_env.clone(),
|_env: &mut MyEnv, _values: &[Value]| unimplemented!(),
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty().clone(), function_type);
let function_type = FunctionType::new(vec![], vec![Type::I32]);
let function = Function::new_with_env(
&store,
&function_type,
my_env.clone(),
|_env: &mut MyEnv, _values: &[Value]| unimplemented!(),
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty().clone(), function_type);
let function_type = FunctionType::new(vec![], vec![Type::I32, Type::I64, Type::F32, Type::F64]);
let function = Function::new_with_env(
&store,
&function_type,
my_env.clone(),
|_env: &mut MyEnv, _values: &[Value]| unimplemented!(),
|_env: &MyEnv, _values: &[Value]| unimplemented!(),
);
assert_eq!(function.ty().clone(), function_type);
Ok(())
Expand Down
Loading

0 comments on commit 67bac73

Please sign in to comment.