Skip to content

Commit

Permalink
Improved Function API
Browse files Browse the repository at this point in the history
  • Loading branch information
syrusakbary committed Jul 22, 2020
1 parent 7386382 commit b06f021
Show file tree
Hide file tree
Showing 16 changed files with 701 additions and 662 deletions.
4 changes: 2 additions & 2 deletions benches/static_and_dynamic_functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub fn run_basic_static_function(store: &Store, compiler_name: &str, c: &mut Cri
let module = Module::new(&store, BASIC_WAT).unwrap();
let import_object = imports! {
"env" => {
"multiply" => Function::new(&store, |a: i32, b: i32| a * b),
"multiply" => Function::new_native(&store, |a: i32, b: i32| a * b),
},
};
let instance = Instance::new(&module, &import_object).unwrap();
Expand Down Expand Up @@ -97,7 +97,7 @@ pub fn run_basic_dynamic_function(store: &Store, compiler_name: &str, c: &mut Cr
let module = Module::new(&store, BASIC_WAT).unwrap();
let import_object = imports! {
"env" => {
"multiply" => Function::new(&store, |a: i32, b: i32| a * b),
"multiply" => Function::new_native(&store, |a: i32, b: i32| a * b),
},
};
let instance = Instance::new(&module, &import_object).unwrap();
Expand Down
209 changes: 126 additions & 83 deletions lib/api/src/externals/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,85 +56,23 @@ pub struct Function {
}

impl Function {
/// Creates a new host `Function` that is:
/// Creates a new host `Function` (dynamic) with the provided signature.
///
/// 1. Static/Monomorphic, i.e. all inputs and outputs have a
/// unique _statically declared type_. The outputs can be
/// wrapped in a `Result`.
/// 2. Independent, i.e. the function _does not_ receive an
/// environment argument.
pub fn new<F, Args, Rets, Env>(store: &Store, func: F) -> Self
where
F: HostFunction<Args, Rets, WithoutEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: Sized + 'static,
{
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address() as *const VMFunctionBody;
let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext;
let signature = function.ty();

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

/// Creates a new host `Function` that is:
/// # Example
///
/// 1. Static/Monomorphic, i.e. all inputs and outputs have a
/// unique statically declared type. The outputs can be wrapped
/// in a `Result`.
/// 2. Dependent, i.e. the function _does_ receive an environment
/// argument (given by `env`).
pub fn new_env<F, Args, Rets, Env>(store: &Store, env: Env, func: F) -> Self
where
F: HostFunction<Args, Rets, WithEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: Sized + 'static,
{
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address();

// TODO: We need to refactor the Function context.
// Right now is structured as it's always a `VMContext`. However, only
// Wasm-defined functions have a `VMContext`.
// 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 signature = function.ty();

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

/// Creates a new host `Function` that is:
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # let store = Store::default();
///
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
///
/// 1. Dynamic/Polymorphic, i.e. all inputs are received in a
/// slice of `Val` (the set of all Wasm values), and all
/// outputs are stored in a vector of `Val`, wrapped in a
/// `Result`.
/// 2. Independent, i.e. the function _does not_ receive an
/// environment argument.
/// let f = Function::new(&store, &signature, |args| {
/// let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
/// Ok(vec![Value::I32(sum)])
/// });
/// ```
#[allow(clippy::cast_ptr_alignment)]
pub fn new_dynamic<F>(store: &Store, ty: &FunctionType, func: F) -> Self
pub fn new<F>(store: &Store, ty: &FunctionType, func: F) -> Self
where
F: Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static,
{
Expand All @@ -160,16 +98,28 @@ impl Function {
}
}

/// Creates a new host `Function` that is:
/// Creates a new host `Function` (dynamic) with the provided signature and environment.
///
/// 1. Dynamic/Polymorphic, i.e. all inputs are received in a
/// slice of `Val` (the set of all Wasm values), and all
/// outputs are stored in a vector of `Val`, wrapped in a
/// `Result`.
/// 2. Dependent, i.e. the function _does_ receive an environment
/// argument (given by `env`).
/// # Example
///
/// ```
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
/// # let store = Store::default();
///
/// struct Env {
/// multiplier: i32,
/// };
/// let env = Env { multiplier: 2 };
///
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
///
/// let f = Function::new_with_env(&store, &signature, env, |env, args| {
/// let result = env.multiplier * (args[0].unwrap_i32() + args[1].unwrap_i32());
/// Ok(vec![Value::I32(result)])
/// });
/// ```
#[allow(clippy::cast_ptr_alignment)]
pub fn new_dynamic_env<F, Env>(store: &Store, ty: &FunctionType, env: Env, func: F) -> Self
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,
Env: Sized + 'static,
Expand Down Expand Up @@ -197,6 +147,99 @@ impl Function {
}
}

/// Creates a new host `Function` from a native function.
///
/// The function signature is automatically retrieved using the
/// Rust typing system.
///
/// # Example
///
/// ```
/// # use wasmer::{Store, Function};
/// # let store = Store::default();
///
/// fn sum(a: i32, b: i32) -> i32 {
/// a + b
/// }
///
/// let f = Function::new_native(&store, sum);
/// ```
pub fn new_native<F, Args, Rets, Env>(store: &Store, func: F) -> Self
where
F: HostFunction<Args, Rets, WithoutEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: Sized + 'static,
{
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address() as *const VMFunctionBody;
let vmctx = std::ptr::null_mut() as *mut _ as *mut VMContext;
let signature = function.ty();

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

/// Creates a new host `Function` from a native function and a provided environment.
///
/// The function signature is automatically retrieved using the
/// Rust typing system.
///
/// # Example
///
/// ```
/// # use wasmer::{Store, Function};
/// # let store = Store::default();
///
/// struct Env {
/// multiplier: i32,
/// };
/// let env = Env { multiplier: 2 };
///
/// fn sum_and_multiply(env: &mut Env, a: i32, b: i32) -> i32 {
/// (a + b) * env.multiplier
/// }
///
/// let f = Function::new_native_with_env(&store, env, sum_and_multiply);
/// ```
pub fn new_native_with_env<F, Args, Rets, Env>(store: &Store, env: Env, func: F) -> Self
where
F: HostFunction<Args, Rets, WithEnv, Env>,
Args: WasmTypeList,
Rets: WasmTypeList,
Env: Sized + 'static,
{
let function = inner::Function::<Args, Rets>::new(func);
let address = function.address();

// TODO: We need to refactor the Function context.
// Right now is structured as it's always a `VMContext`. However, only
// Wasm-defined functions have a `VMContext`.
// 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 signature = function.ty();

Self {
store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction {
address,
kind: VMFunctionKind::Static,
vmctx,
signature,
},
}
}
/// Returns the [`FunctionType`] of the `Function`.
pub fn ty(&self) -> &FunctionType {
&self.exported.signature
Expand Down
24 changes: 12 additions & 12 deletions lib/api/src/import_object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pub trait LikeNamespace {
/// let mut import_object = ImportObject::new();
/// let mut env = Exports::new();
///
/// env.insert("foo", Function::new(foo));
/// env.insert("foo", Function::new_native(foo));
/// import_object.register("env", env);
///
/// fn foo(n: i32) -> i32 {
Expand Down Expand Up @@ -160,7 +160,7 @@ impl IntoIterator for ImportObject {
///
/// let import_object = imports! {
/// "env" => {
/// "foo" => Function::new(&store, foo)
/// "foo" => Function::new_native(&store, foo)
/// },
/// };
///
Expand Down Expand Up @@ -336,42 +336,42 @@ mod test {

let _ = imports! {
"env" => {
"func" => Function::new(&store, func),
"func" => Function::new_native(&store, func),
},
};
let _ = imports! {
"env" => {
"func" => Function::new(&store, func),
"func" => Function::new_native(&store, func),
}
};
let _ = imports! {
"env" => {
"func" => Function::new(&store, func),
"func" => Function::new_native(&store, func),
},
"abc" => {
"def" => Function::new(&store, func),
"def" => Function::new_native(&store, func),
}
};
let _ = imports! {
"env" => {
"func" => Function::new(&store, func)
"func" => Function::new_native(&store, func)
},
};
let _ = imports! {
"env" => {
"func" => Function::new(&store, func)
"func" => Function::new_native(&store, func)
}
};
let _ = imports! {
"env" => {
"func1" => Function::new(&store, func),
"func2" => Function::new(&store, func)
"func1" => Function::new_native(&store, func),
"func2" => Function::new_native(&store, func)
}
};
let _ = imports! {
"env" => {
"func1" => Function::new(&store, func),
"func2" => Function::new(&store, func),
"func1" => Function::new_native(&store, func),
"func2" => Function::new_native(&store, func),
}
};
}
Expand Down
Loading

0 comments on commit b06f021

Please sign in to comment.