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
13#[cfg(feature = "experimental-async")]
14pub(crate) mod async_host;
15#[cfg(feature = "experimental-async")]
16pub use async_host::{AsyncFunctionEnv, AsyncHostFunction};
17
18use std::{future::Future, pin::Pin};
19
20use wasmer_types::{FunctionType, RawValue};
21
22#[cfg(feature = "experimental-async")]
23use crate::AsStoreAsync;
24use crate::{
25    AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, TypedFunction,
26    Value, WasmTypeList,
27    error::RuntimeError,
28    vm::{VMExtern, VMExternFunction, VMFuncRef},
29};
30
31/// A WebAssembly `function` instance.
32///
33/// A function instance is the runtime representation of a function.
34/// It effectively is a closure of the original function (defined in either
35/// the host or the WebAssembly module) over the runtime [`crate::Instance`] of its
36/// originating [`crate::Module`].
37///
38/// The module instance is used to resolve references to other definitions
39/// during execution of the function.
40///
41/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
42///
43/// # Panics
44/// - Closures (functions with captured environments) are not currently supported
45///   with native functions. Attempting to create a native `Function` with one will
46///   result in a panic.
47///   [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
48#[derive(Debug, Clone, PartialEq, Eq)]
49#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
50pub struct Function(pub(crate) BackendFunction);
51
52impl Function {
53    /// Creates a new host `Function` (dynamic) with the provided signature.
54    ///
55    /// If you know the signature of the host function at compile time,
56    /// consider using [`Function::new_typed`] for less runtime overhead.
57    pub fn new<FT, F>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
58    where
59        FT: Into<FunctionType>,
60        F: Fn(&[Value]) -> Result<Vec<Value>, RuntimeError> + 'static + Send + Sync,
61    {
62        Self(BackendFunction::new(store, ty, func))
63    }
64
65    /// Creates a new host `Function` (dynamic) with the provided signature.
66    ///
67    /// If you know the signature of the host function at compile time,
68    /// consider using [`Function::new_typed_with_env`] for less runtime overhead.
69    ///
70    /// Takes a [`FunctionEnv`] that is passed into func. If that is not required,
71    /// [`Function::new`] might be an option as well.
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
77    /// # let mut store = Store::default();
78    /// # let env = FunctionEnv::new(&mut store, ());
79    /// #
80    /// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
81    ///
82    /// let f = Function::new_with_env(&mut store, &env, &signature, |_env, args| {
83    ///     let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
84    ///     Ok(vec![Value::I32(sum)])
85    /// });
86    /// ```
87    ///
88    /// With constant signature:
89    ///
90    /// ```
91    /// # use wasmer::{Function, FunctionEnv, FunctionType, Type, Store, Value};
92    /// # let mut store = Store::default();
93    /// # let env = FunctionEnv::new(&mut store, ());
94    /// #
95    /// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
96    ///
97    /// let f = Function::new_with_env(&mut store, &env, I32_I32_TO_I32, |_env, args| {
98    ///     let sum = args[0].unwrap_i32() + args[1].unwrap_i32();
99    ///     Ok(vec![Value::I32(sum)])
100    /// });
101    /// ```
102    pub fn new_with_env<FT, F, T: Send + 'static>(
103        store: &mut impl AsStoreMut,
104        env: &FunctionEnv<T>,
105        ty: FT,
106        func: F,
107    ) -> Self
108    where
109        FT: Into<FunctionType>,
110        F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
111            + 'static
112            + Send
113            + Sync,
114    {
115        Self(BackendFunction::new_with_env(store, env, ty, func))
116    }
117
118    /// Creates a new host `Function` from a native function.
119    pub fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
120    where
121        F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
122        Args: WasmTypeList,
123        Rets: WasmTypeList,
124    {
125        Self(BackendFunction::new_typed(store, func))
126    }
127
128    /// Creates a new host `Function` with an environment from a typed function.
129    ///
130    /// The function signature is automatically retrieved using the
131    /// Rust typing system.
132    ///
133    /// # Example
134    ///
135    /// ```
136    /// # use wasmer::{Store, Function, FunctionEnv, FunctionEnvMut};
137    /// # let mut store = Store::default();
138    /// # let env = FunctionEnv::new(&mut store, ());
139    /// #
140    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
141    ///     a + b
142    /// }
143    ///
144    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
145    /// ```
146    pub fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
147        store: &mut impl AsStoreMut,
148        env: &FunctionEnv<T>,
149        func: F,
150    ) -> Self
151    where
152        F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
153        Args: WasmTypeList,
154        Rets: WasmTypeList,
155    {
156        Self(BackendFunction::new_typed_with_env(store, env, func))
157    }
158
159    /// Creates a new async host `Function` (dynamic) with the provided
160    /// signature.
161    ///
162    /// If you know the signature of the host function at compile time,
163    /// consider using [`Self::new_typed_async`] for less runtime overhead.
164    ///
165    /// The provided closure returns a future that resolves to the function results.
166    /// When invoked synchronously (via [`Function::call`]) the future will run to
167    /// completion immediately, provided it doesn't suspend. When invoked through
168    /// [`Function::call_async`], the future may suspend and resume as needed.
169    #[cfg(feature = "experimental-async")]
170    pub fn new_async<FT, F, Fut>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
171    where
172        FT: Into<FunctionType>,
173        F: Fn(&[Value]) -> Fut + 'static,
174        Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
175    {
176        Self(BackendFunction::new_async(store, ty, func))
177    }
178
179    /// Creates a new async host `Function` (dynamic) with the provided
180    /// signature and environment.
181    ///
182    /// If you know the signature of the host function at compile time,
183    /// consider using [`Self::new_typed_with_env_async`] for less runtime overhead.
184    ///
185    /// Takes an [`AsyncFunctionEnvMut`] that is passed into func. If
186    /// that is not required, [`Self::new_async`] might be an option as well.
187    #[cfg(feature = "experimental-async")]
188    pub fn new_with_env_async<FT, F, Fut, T: 'static>(
189        store: &mut impl AsStoreMut,
190        env: &FunctionEnv<T>,
191        ty: FT,
192        func: F,
193    ) -> Self
194    where
195        FT: Into<FunctionType>,
196        F: Fn(AsyncFunctionEnvMut<T>, &[Value]) -> Fut + 'static,
197        Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
198    {
199        Self(BackendFunction::new_with_env_async(store, env, ty, func))
200    }
201
202    /// Creates a new async host `Function` from a native typed function.
203    ///
204    /// The future can return either the raw result tuple or any type that implements
205    /// [`IntoResult`](crate::IntoResult) for the result tuple (e.g. `Result<Rets, E>`).
206    #[cfg(feature = "experimental-async")]
207    pub fn new_typed_async<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
208    where
209        Rets: WasmTypeList + 'static,
210        Args: WasmTypeList + 'static,
211        F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static,
212    {
213        Self(BackendFunction::new_typed_async(store, func))
214    }
215
216    /// Creates a new async host `Function` with an environment from a typed function.
217    #[cfg(feature = "experimental-async")]
218    pub fn new_typed_with_env_async<T: 'static, F, Args, Rets>(
219        store: &mut impl AsStoreMut,
220        env: &FunctionEnv<T>,
221        func: F,
222    ) -> Self
223    where
224        Rets: WasmTypeList + 'static,
225        Args: WasmTypeList + 'static,
226        F: AsyncHostFunction<T, Args, Rets, WithEnv> + 'static,
227    {
228        Self(BackendFunction::new_typed_with_env_async(store, env, func))
229    }
230
231    /// Returns the [`FunctionType`] of the `Function`.
232    ///
233    /// # Example
234    ///
235    /// ```
236    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
237    /// # let mut store = Store::default();
238    /// # let env = FunctionEnv::new(&mut store, ());
239    /// #
240    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
241    ///     a + b
242    /// }
243    ///
244    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
245    ///
246    /// assert_eq!(f.ty(&mut store).params(), vec![Type::I32, Type::I32]);
247    /// assert_eq!(f.ty(&mut store).results(), vec![Type::I32]);
248    /// ```
249    pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
250        self.0.ty(store)
251    }
252
253    /// Returns the number of parameters that this function takes.
254    ///
255    /// # Example
256    ///
257    /// ```
258    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
259    /// # let mut store = Store::default();
260    /// # let env = FunctionEnv::new(&mut store, ());
261    /// #
262    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
263    ///     a + b
264    /// }
265    ///
266    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
267    ///
268    /// assert_eq!(f.param_arity(&mut store), 2);
269    /// ```
270    pub fn param_arity(&self, store: &impl AsStoreRef) -> usize {
271        self.ty(store).params().len()
272    }
273
274    /// Returns the number of results this function produces.
275    ///
276    /// # Example
277    ///
278    /// ```
279    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
280    /// # let mut store = Store::default();
281    /// # let env = FunctionEnv::new(&mut store, ());
282    /// #
283    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
284    ///     a + b
285    /// }
286    ///
287    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
288    ///
289    /// assert_eq!(f.result_arity(&mut store), 1);
290    /// ```
291    pub fn result_arity(&self, store: &impl AsStoreRef) -> usize {
292        self.ty(store).results().len()
293    }
294
295    /// Call the function.
296    ///
297    /// Depending on where the Function is defined, it will call it.
298    /// 1. If the function is defined inside a WebAssembly, it will call the trampoline
299    ///    for the function signature.
300    /// 2. If the function is defined in the host (in a native way), it will
301    ///    call the trampoline.
302    ///
303    /// # Examples
304    ///
305    /// ```
306    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
307    /// # use wasmer::FunctionEnv;
308    /// # let mut store = Store::default();
309    /// # let env = FunctionEnv::new(&mut store, ());
310    /// # let wasm_bytes = wat2wasm(r#"
311    /// # (module
312    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
313    /// #     local.get $x
314    /// #     local.get $y
315    /// #     i32.add
316    /// #   ))
317    /// # "#.as_bytes()).unwrap();
318    /// # let module = Module::new(&store, wasm_bytes).unwrap();
319    /// # let import_object = imports! {};
320    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
321    /// #
322    /// let sum = instance.exports.get_function("sum").unwrap();
323    ///
324    /// assert_eq!(sum.call(&mut store, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
325    /// ```
326    pub fn call(
327        &self,
328        store: &mut impl AsStoreMut,
329        params: &[Value],
330    ) -> Result<Box<[Value]>, RuntimeError> {
331        self.0.call(store, params)
332    }
333
334    /// Calls the function asynchronously.
335    ///
336    /// The returned future drives execution of the WebAssembly function on a
337    /// coroutine stack. Host functions created with [`Function::new_async`] may
338    /// suspend execution by awaiting futures, and their completion will resume
339    /// the Wasm instance according to the JSPI proposal.
340    #[must_use = "This function spawns a future that must be awaited to produce results"]
341    #[cfg(feature = "experimental-async")]
342    pub fn call_async(
343        &self,
344        store: &impl AsStoreAsync,
345        params: Vec<Value>,
346    ) -> impl Future<Output = Result<Box<[Value]>, RuntimeError>> + 'static {
347        self.0.call_async(store, params)
348    }
349
350    #[doc(hidden)]
351    #[allow(missing_docs)]
352    pub fn call_raw(
353        &self,
354        store: &mut impl AsStoreMut,
355        params: Vec<RawValue>,
356    ) -> Result<Box<[Value]>, RuntimeError> {
357        self.0.call_raw(store, params)
358    }
359
360    pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
361        self.0.vm_funcref(store)
362    }
363
364    pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
365        unsafe { Self(BackendFunction::from_vm_funcref(store, funcref)) }
366    }
367
368    /// Transform this WebAssembly function into a typed function.
369    /// See [`TypedFunction`] to learn more.
370    ///
371    /// # Examples
372    ///
373    /// ```
374    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
375    /// # use wasmer::FunctionEnv;
376    /// # let mut store = Store::default();
377    /// # let env = FunctionEnv::new(&mut store, ());
378    /// # let wasm_bytes = wat2wasm(r#"
379    /// # (module
380    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
381    /// #     local.get $x
382    /// #     local.get $y
383    /// #     i32.add
384    /// #   ))
385    /// # "#.as_bytes()).unwrap();
386    /// # let module = Module::new(&store, wasm_bytes).unwrap();
387    /// # let import_object = imports! {};
388    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
389    /// #
390    /// let sum = instance.exports.get_function("sum").unwrap();
391    /// let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&mut store).unwrap();
392    ///
393    /// assert_eq!(sum_typed.call(&mut store, 1, 2).unwrap(), 3);
394    /// ```
395    ///
396    /// # Errors
397    ///
398    /// If the `Args` generic parameter does not match the exported function
399    /// an error will be raised:
400    ///
401    /// ```should_panic
402    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
403    /// # use wasmer::FunctionEnv;
404    /// # let mut store = Store::default();
405    /// # let env = FunctionEnv::new(&mut store, ());
406    /// # let wasm_bytes = wat2wasm(r#"
407    /// # (module
408    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
409    /// #     local.get $x
410    /// #     local.get $y
411    /// #     i32.add
412    /// #   ))
413    /// # "#.as_bytes()).unwrap();
414    /// # let module = Module::new(&store, wasm_bytes).unwrap();
415    /// # let import_object = imports! {};
416    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
417    /// #
418    /// let sum = instance.exports.get_function("sum").unwrap();
419    ///
420    /// // This results in an error: `RuntimeError`
421    /// let sum_typed : TypedFunction<(i64, i64), i32> = sum.typed(&mut store).unwrap();
422    /// ```
423    ///
424    /// If the `Rets` generic parameter does not match the exported function
425    /// an error will be raised:
426    ///
427    /// ```should_panic
428    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
429    /// # use wasmer::FunctionEnv;
430    /// # let mut store = Store::default();
431    /// # let env = FunctionEnv::new(&mut store, ());
432    /// # let wasm_bytes = wat2wasm(r#"
433    /// # (module
434    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
435    /// #     local.get $x
436    /// #     local.get $y
437    /// #     i32.add
438    /// #   ))
439    /// # "#.as_bytes()).unwrap();
440    /// # let module = Module::new(&store, wasm_bytes).unwrap();
441    /// # let import_object = imports! {};
442    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
443    /// #
444    /// let sum = instance.exports.get_function("sum").unwrap();
445    ///
446    /// // This results in an error: `RuntimeError`
447    /// let sum_typed: TypedFunction<(i32, i32), i64> = sum.typed(&mut store).unwrap();
448    /// ```
449    pub fn typed<Args, Rets>(
450        &self,
451        store: &impl AsStoreRef,
452    ) -> Result<TypedFunction<Args, Rets>, RuntimeError>
453    where
454        Args: WasmTypeList,
455        Rets: WasmTypeList,
456    {
457        self.0.typed(store)
458    }
459
460    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
461        Self(BackendFunction::from_vm_extern(store, vm_extern))
462    }
463
464    /// Checks whether this `Function` can be used with the given store.
465    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
466        self.0.is_from_store(store)
467    }
468
469    pub(crate) fn to_vm_extern(&self) -> VMExtern {
470        self.0.to_vm_extern()
471    }
472}
473
474impl<'a> Exportable<'a> for Function {
475    fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
476        match _extern {
477            Extern::Function(func) => Ok(func),
478            _ => Err(ExportError::IncompatibleType),
479        }
480    }
481}