wasmer/entities/function/
mod.rs

1//! Defines the [`Function`] and [`HostFunction`] types and useful traits and data types to
2//! interact with them.
3
4pub(crate) mod inner;
5pub use inner::*;
6
7pub(crate) mod host;
8pub use host::*;
9
10pub(crate) mod env;
11pub use env::*;
12
13use wasmer_types::{FunctionType, RawValue};
14
15use crate::{
16    AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, TypedFunction,
17    Value, WasmTypeList,
18    error::RuntimeError,
19    vm::{VMExtern, VMExternFunction, VMFuncRef},
20};
21
22/// A WebAssembly `function` instance.
23///
24/// A function instance is the runtime representation of a function.
25/// It effectively is a closure of the original function (defined in either
26/// the host or the WebAssembly module) over the runtime [`crate::Instance`] of its
27/// originating [`crate::Module`].
28///
29/// The module instance is used to resolve references to other definitions
30/// during execution of the function.
31///
32/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
33///
34/// # Panics
35/// - Closures (functions with captured environments) are not currently supported
36///   with native functions. Attempting to create a native `Function` with one will
37///   result in a panic.
38///   [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
39#[derive(Debug, Clone, PartialEq, Eq)]
40#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
41pub struct Function(pub(crate) BackendFunction);
42
43impl Function {
44    /// Creates a new host `Function` (dynamic) with the provided signature.
45    ///
46    /// If you know the signature of the host function at compile time,
47    /// consider using [`Function::new_typed`] for less runtime overhead.
48    pub fn new<FT, F>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
49    where
50        FT: Into<FunctionType>,
51        F: Fn(&[Value]) -> Result<Vec<Value>, RuntimeError> + 'static + Send + Sync,
52    {
53        Self(BackendFunction::new(store, ty, func))
54    }
55
56    /// Creates a new host `Function` (dynamic) with the provided signature.
57    ///
58    /// If you know the signature of the host function at compile time,
59    /// consider using [`Function::new_typed_with_env`] for less runtime overhead.
60    ///
61    /// Takes a [`FunctionEnv`] that is passed into func. If that is not required,
62    /// [`Function::new`] might be an option as well.
63    ///
64    /// # Examples
65    ///
66    /// ```
67    /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
68    /// # let mut store = Store::default();
69    /// # let env = FunctionEnv::new(&mut store, ());
70    /// #
71    /// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
72    ///
73    /// let f = Function::new_with_env(&mut store, &env, &signature, |_env, args| {
74    ///     let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
75    ///     Ok(vec![Value::I32(sum)])
76    /// });
77    /// ```
78    ///
79    /// With constant signature:
80    ///
81    /// ```
82    /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
83    /// # let mut store = Store::default();
84    /// # let env = FunctionEnv::new(&mut store, ());
85    /// #
86    /// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
87    ///
88    /// let f = Function::new_with_env(&mut store, &env, I32_I32_TO_I32, |_env, args| {
89    ///     let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
90    ///     Ok(vec![Value::I32(sum)])
91    /// });
92    /// ```
93    pub fn new_with_env<FT, F, T: Send + 'static>(
94        store: &mut impl AsStoreMut,
95        env: &FunctionEnv<T>,
96        ty: FT,
97        func: F,
98    ) -> Self
99    where
100        FT: Into<FunctionType>,
101        F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
102            + 'static
103            + Send
104            + Sync,
105    {
106        Self(BackendFunction::new_with_env(store, env, ty, func))
107    }
108
109    /// Creates a new host `Function` from a native function.
110    pub fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
111    where
112        F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
113        Args: WasmTypeList,
114        Rets: WasmTypeList,
115    {
116        Self(BackendFunction::new_typed(store, func))
117    }
118
119    /// Creates a new host `Function` with an environment from a typed function.
120    ///
121    /// The function signature is automatically retrieved using the
122    /// Rust typing system.
123    ///
124    /// # Example
125    ///
126    /// ```
127    /// # use wasmer::{Store, Function, FunctionEnv, FunctionEnvMut};
128    /// # let mut store = Store::default();
129    /// # let env = FunctionEnv::new(&mut store, ());
130    /// #
131    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
132    ///     a + b
133    /// }
134    ///
135    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
136    /// ```
137    pub fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
138        store: &mut impl AsStoreMut,
139        env: &FunctionEnv<T>,
140        func: F,
141    ) -> Self
142    where
143        F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
144        Args: WasmTypeList,
145        Rets: WasmTypeList,
146    {
147        Self(BackendFunction::new_typed_with_env(store, env, func))
148    }
149
150    /// Returns the [`FunctionType`] of the `Function`.
151    ///
152    /// # Example
153    ///
154    /// ```
155    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
156    /// # let mut store = Store::default();
157    /// # let env = FunctionEnv::new(&mut store, ());
158    /// #
159    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
160    ///     a + b
161    /// }
162    ///
163    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
164    ///
165    /// assert_eq!(f.ty(&mut store).params(), vec![Type::I32, Type::I32]);
166    /// assert_eq!(f.ty(&mut store).results(), vec![Type::I32]);
167    /// ```
168    pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
169        self.0.ty(store)
170    }
171
172    /// Returns the number of parameters that this function takes.
173    ///
174    /// # Example
175    ///
176    /// ```
177    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
178    /// # let mut store = Store::default();
179    /// # let env = FunctionEnv::new(&mut store, ());
180    /// #
181    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
182    ///     a + b
183    /// }
184    ///
185    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
186    ///
187    /// assert_eq!(f.param_arity(&mut store), 2);
188    /// ```
189    pub fn param_arity(&self, store: &impl AsStoreRef) -> usize {
190        self.ty(store).params().len()
191    }
192
193    /// Returns the number of results this function produces.
194    ///
195    /// # Example
196    ///
197    /// ```
198    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
199    /// # let mut store = Store::default();
200    /// # let env = FunctionEnv::new(&mut store, ());
201    /// #
202    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
203    ///     a + b
204    /// }
205    ///
206    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
207    ///
208    /// assert_eq!(f.result_arity(&mut store), 1);
209    /// ```
210    pub fn result_arity(&self, store: &impl AsStoreRef) -> usize {
211        self.ty(store).results().len()
212    }
213
214    /// Call the function.
215    ///
216    /// Depending on where the Function is defined, it will call it.
217    /// 1. If the function is defined inside a WebAssembly, it will call the trampoline
218    ///    for the function signature.
219    /// 2. If the function is defined in the host (in a native way), it will
220    ///    call the trampoline.
221    ///
222    /// # Examples
223    ///
224    /// ```
225    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
226    /// # use wasmer::FunctionEnv;
227    /// # let mut store = Store::default();
228    /// # let env = FunctionEnv::new(&mut store, ());
229    /// # let wasm_bytes = wat2wasm(r#"
230    /// # (module
231    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
232    /// #     local.get $x
233    /// #     local.get $y
234    /// #     i32.add
235    /// #   ))
236    /// # "#.as_bytes()).unwrap();
237    /// # let module = Module::new(&store, wasm_bytes).unwrap();
238    /// # let import_object = imports! {};
239    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
240    /// #
241    /// let sum = instance.exports.get_function("sum").unwrap();
242    ///
243    /// assert_eq!(sum.call(&mut store, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
244    /// ```
245    pub fn call(
246        &self,
247        store: &mut impl AsStoreMut,
248        params: &[Value],
249    ) -> Result<Box<[Value]>, RuntimeError> {
250        self.0.call(store, params)
251    }
252
253    #[doc(hidden)]
254    #[allow(missing_docs)]
255    pub fn call_raw(
256        &self,
257        store: &mut impl AsStoreMut,
258        params: Vec<RawValue>,
259    ) -> Result<Box<[Value]>, RuntimeError> {
260        self.0.call_raw(store, params)
261    }
262
263    pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
264        self.0.vm_funcref(store)
265    }
266
267    pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
268        unsafe { Self(BackendFunction::from_vm_funcref(store, funcref)) }
269    }
270
271    /// Transform this WebAssembly function into a typed function.
272    /// See [`TypedFunction`] to learn more.
273    ///
274    /// # Examples
275    ///
276    /// ```
277    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
278    /// # use wasmer::FunctionEnv;
279    /// # let mut store = Store::default();
280    /// # let env = FunctionEnv::new(&mut store, ());
281    /// # let wasm_bytes = wat2wasm(r#"
282    /// # (module
283    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
284    /// #     local.get $x
285    /// #     local.get $y
286    /// #     i32.add
287    /// #   ))
288    /// # "#.as_bytes()).unwrap();
289    /// # let module = Module::new(&store, wasm_bytes).unwrap();
290    /// # let import_object = imports! {};
291    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
292    /// #
293    /// let sum = instance.exports.get_function("sum").unwrap();
294    /// let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&mut store).unwrap();
295    ///
296    /// assert_eq!(sum_typed.call(&mut store, 1, 2).unwrap(), 3);
297    /// ```
298    ///
299    /// # Errors
300    ///
301    /// If the `Args` generic parameter does not match the exported function
302    /// an error will be raised:
303    ///
304    /// ```should_panic
305    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
306    /// # use wasmer::FunctionEnv;
307    /// # let mut store = Store::default();
308    /// # let env = FunctionEnv::new(&mut store, ());
309    /// # let wasm_bytes = wat2wasm(r#"
310    /// # (module
311    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
312    /// #     local.get $x
313    /// #     local.get $y
314    /// #     i32.add
315    /// #   ))
316    /// # "#.as_bytes()).unwrap();
317    /// # let module = Module::new(&store, wasm_bytes).unwrap();
318    /// # let import_object = imports! {};
319    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
320    /// #
321    /// let sum = instance.exports.get_function("sum").unwrap();
322    ///
323    /// // This results in an error: `RuntimeError`
324    /// let sum_typed : TypedFunction<(i64, i64), i32> = sum.typed(&mut store).unwrap();
325    /// ```
326    ///
327    /// If the `Rets` generic parameter does not match the exported function
328    /// an error will be raised:
329    ///
330    /// ```should_panic
331    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
332    /// # use wasmer::FunctionEnv;
333    /// # let mut store = Store::default();
334    /// # let env = FunctionEnv::new(&mut store, ());
335    /// # let wasm_bytes = wat2wasm(r#"
336    /// # (module
337    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
338    /// #     local.get $x
339    /// #     local.get $y
340    /// #     i32.add
341    /// #   ))
342    /// # "#.as_bytes()).unwrap();
343    /// # let module = Module::new(&store, wasm_bytes).unwrap();
344    /// # let import_object = imports! {};
345    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
346    /// #
347    /// let sum = instance.exports.get_function("sum").unwrap();
348    ///
349    /// // This results in an error: `RuntimeError`
350    /// let sum_typed: TypedFunction<(i32, i32), i64> = sum.typed(&mut store).unwrap();
351    /// ```
352    pub fn typed<Args, Rets>(
353        &self,
354        store: &impl AsStoreRef,
355    ) -> Result<TypedFunction<Args, Rets>, RuntimeError>
356    where
357        Args: WasmTypeList,
358        Rets: WasmTypeList,
359    {
360        self.0.typed(store)
361    }
362
363    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
364        Self(BackendFunction::from_vm_extern(store, vm_extern))
365    }
366
367    /// Checks whether this `Function` can be used with the given store.
368    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
369        self.0.is_from_store(store)
370    }
371
372    pub(crate) fn to_vm_extern(&self) -> VMExtern {
373        self.0.to_vm_extern()
374    }
375}
376
377impl<'a> Exportable<'a> for Function {
378    fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
379        match _extern {
380            Extern::Function(func) => Ok(func),
381            _ => Err(ExportError::IncompatibleType),
382        }
383    }
384}