wasmer/entities/function/
inner.rs

1use std::pin::Pin;
2
3use wasmer_types::{FunctionType, RawValue};
4
5#[cfg(feature = "experimental-async")]
6use crate::{AsStoreAsync, AsyncFunctionEnvMut, entities::function::async_host::AsyncHostFunction};
7use crate::{
8    AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, FunctionEnv, FunctionEnvMut,
9    HostFunction, StoreMut, StoreRef, TypedFunction, Value, WasmTypeList, WithEnv, WithoutEnv,
10    error::RuntimeError,
11    macros::backend::{gen_rt_ty, match_rt},
12    vm::{VMExtern, VMExternFunction, VMFuncRef},
13};
14
15/// A WebAssembly `function` instance.
16///
17/// A function instance is the runtime representation of a function.
18/// It effectively is a closure of the original function (defined in either
19/// the host or the WebAssembly module) over the runtime `Instance` of its
20/// originating `Module`.
21///
22/// The module instance is used to resolve references to other definitions
23/// during execution of the function.
24///
25/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#function-instances>
26///
27/// # Panics
28/// - Closures (functions with captured environments) are not currently supported
29///   with native functions. Attempting to create a native `Function` with one will
30///   result in a panic.
31///   [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
32gen_rt_ty! {
33    #[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
34    #[derive(Debug, Clone, PartialEq, Eq)]
35    pub(crate) BackendFunction(entities::function::Function);
36}
37
38impl BackendFunction {
39    /// Creates a new host `Function` (dynamic) with the provided signature.
40    ///
41    /// If you know the signature of the host function at compile time,
42    /// consider using [`Self::new_typed`] for less runtime overhead.
43    #[inline]
44    pub fn new<FT, F>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
45    where
46        FT: Into<FunctionType>,
47        F: Fn(&[Value]) -> Result<Vec<Value>, RuntimeError> + 'static + Send + Sync,
48    {
49        let env = FunctionEnv::new(&mut store.as_store_mut(), ());
50        let wrapped_func = move |_env: FunctionEnvMut<()>,
51                                 args: &[Value]|
52              -> Result<Vec<Value>, RuntimeError> { func(args) };
53        Self::new_with_env(store, &env, ty, wrapped_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 [`Self::new_typed_with_env`] for less runtime overhead.
60    ///
61    /// Takes a [`FunctionEnv`] that is passed into func. If that is not required,
62    /// [`Self::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    #[inline]
94    pub fn new_with_env<FT, F, T: Send + 'static>(
95        store: &mut impl AsStoreMut,
96        env: &FunctionEnv<T>,
97        ty: FT,
98        func: F,
99    ) -> Self
100    where
101        FT: Into<FunctionType>,
102        F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
103            + 'static
104            + Send
105            + Sync,
106    {
107        match &store.as_store_mut().inner.store {
108            #[cfg(feature = "sys")]
109            crate::BackendStore::Sys(_) => Self::Sys(
110                crate::backend::sys::entities::function::Function::new_with_env(
111                    store, env, ty, func,
112                ),
113            ),
114            #[cfg(feature = "wamr")]
115            crate::BackendStore::Wamr(_) => Self::Wamr(
116                crate::backend::wamr::entities::function::Function::new_with_env(
117                    store, env, ty, func,
118                ),
119            ),
120            #[cfg(feature = "wasmi")]
121            crate::BackendStore::Wasmi(_) => Self::Wasmi(
122                crate::backend::wasmi::entities::function::Function::new_with_env(
123                    store, env, ty, func,
124                ),
125            ),
126            #[cfg(feature = "v8")]
127            crate::BackendStore::V8(_) => Self::V8(
128                crate::backend::v8::entities::function::Function::new_with_env(
129                    store, env, ty, func,
130                ),
131            ),
132            #[cfg(feature = "js")]
133            crate::BackendStore::Js(_) => Self::Js(
134                crate::backend::js::entities::function::Function::new_with_env(
135                    store, env, ty, func,
136                ),
137            ),
138            #[cfg(feature = "jsc")]
139            crate::BackendStore::Jsc(_) => Self::Jsc(
140                crate::backend::jsc::entities::function::Function::new_with_env(
141                    store, env, ty, func,
142                ),
143            ),
144        }
145    }
146
147    /// Creates a new host `Function` from a native function.
148    #[inline]
149    pub fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
150    where
151        F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
152        Args: WasmTypeList,
153        Rets: WasmTypeList,
154    {
155        match &store.as_store_mut().inner.store {
156            #[cfg(feature = "sys")]
157            crate::BackendStore::Sys(_) => {
158                Self::Sys(crate::backend::sys::entities::function::Function::new_typed(store, func))
159            }
160            #[cfg(feature = "wamr")]
161            crate::BackendStore::Wamr(_) => Self::Wamr(
162                crate::backend::wamr::entities::function::Function::new_typed(store, func),
163            ),
164
165            #[cfg(feature = "wasmi")]
166            crate::BackendStore::Wasmi(_) => Self::Wasmi(
167                crate::backend::wasmi::entities::function::Function::new_typed(store, func),
168            ),
169            #[cfg(feature = "v8")]
170            crate::BackendStore::V8(_) => Self::V8(
171                crate::backend::v8::entities::function::Function::new_typed(store, func),
172            ),
173            #[cfg(feature = "js")]
174            crate::BackendStore::Js(_) => Self::Js(
175                crate::backend::js::entities::function::Function::new_typed(store, func),
176            ),
177
178            #[cfg(feature = "jsc")]
179            crate::BackendStore::Jsc(_) => {
180                Self::Jsc(crate::backend::jsc::entities::function::Function::new_typed(store, func))
181            }
182        }
183    }
184
185    /// Creates a new host `Function` with an environment from a typed function.
186    ///
187    /// The function signature is automatically retrieved using the
188    /// Rust typing system.
189    ///
190    /// # Example
191    ///
192    /// ```
193    /// # use wasmer::{Store, Function, FunctionEnv, FunctionEnvMut};
194    /// # let mut store = Store::default();
195    /// # let env = FunctionEnv::new(&mut store, ());
196    /// #
197    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
198    ///     a + b
199    /// }
200    ///
201    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
202    /// ```
203    #[inline]
204    pub fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
205        store: &mut impl AsStoreMut,
206        env: &FunctionEnv<T>,
207        func: F,
208    ) -> Self
209    where
210        F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
211        Args: WasmTypeList,
212        Rets: WasmTypeList,
213    {
214        match &store.as_store_mut().inner.store {
215            #[cfg(feature = "sys")]
216            crate::BackendStore::Sys(s) => Self::Sys(
217                crate::backend::sys::entities::function::Function::new_typed_with_env(
218                    store, env, func,
219                ),
220            ),
221            #[cfg(feature = "wamr")]
222            crate::BackendStore::Wamr(s) => Self::Wamr(
223                crate::backend::wamr::entities::function::Function::new_typed_with_env(
224                    store, env, func,
225                ),
226            ),
227
228            #[cfg(feature = "wasmi")]
229            crate::BackendStore::Wasmi(s) => Self::Wasmi(
230                crate::backend::wasmi::entities::function::Function::new_typed_with_env(
231                    store, env, func,
232                ),
233            ),
234            #[cfg(feature = "v8")]
235            crate::BackendStore::V8(s) => Self::V8(
236                crate::backend::v8::entities::function::Function::new_typed_with_env(
237                    store, env, func,
238                ),
239            ),
240            #[cfg(feature = "js")]
241            crate::BackendStore::Js(s) => Self::Js(
242                crate::backend::js::entities::function::Function::new_typed_with_env(
243                    store, env, func,
244                ),
245            ),
246            #[cfg(feature = "jsc")]
247            crate::BackendStore::Jsc(s) => Self::Jsc(
248                crate::backend::jsc::entities::function::Function::new_typed_with_env(
249                    store, env, func,
250                ),
251            ),
252        }
253    }
254
255    /// Creates a new async host `Function` (dynamic) with the provided
256    /// signature.
257    ///
258    /// If you know the signature of the host function at compile time,
259    /// consider using [`Self::new_typed_async`] for less runtime overhead.
260    ///
261    /// The provided closure returns a future that resolves to the function results.
262    /// When invoked synchronously
263    /// (via [`Function::call`](crate::Function::call)) the future will run to
264    /// completion immediately, provided it doesn't suspend. When invoked through
265    /// [`Function::call_async`](crate::Function::call_async), the future may suspend
266    /// and resume as needed.
267    #[inline]
268    #[cfg(feature = "experimental-async")]
269    pub fn new_async<FT, F, Fut>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
270    where
271        FT: Into<FunctionType>,
272        F: Fn(&[Value]) -> Fut + 'static,
273        Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
274    {
275        match &store.as_store_mut().inner.store {
276            #[cfg(feature = "sys")]
277            crate::BackendStore::Sys(_) => Self::Sys(
278                crate::backend::sys::entities::function::Function::new_async(store, ty, func),
279            ),
280            #[cfg(feature = "wamr")]
281            crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"),
282            #[cfg(feature = "wasmi")]
283            crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"),
284            #[cfg(feature = "v8")]
285            crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
286            #[cfg(feature = "js")]
287            crate::BackendStore::Js(_) => unsupported_async_backend("js"),
288            #[cfg(feature = "jsc")]
289            crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"),
290        }
291    }
292
293    /// Creates a new async host `Function` (dynamic) with the provided
294    /// signature and environment.
295    ///
296    /// If you know the signature of the host function at compile time,
297    /// consider using [`Self::new_typed_with_env_async`] for less runtime overhead.
298    ///
299    /// Takes an [`AsyncFunctionEnvMut`] that is passed into func. If
300    /// that is not required, [`Self::new_async`] might be an option as well.
301    #[inline]
302    #[cfg(feature = "experimental-async")]
303    pub fn new_with_env_async<FT, F, Fut, T: 'static>(
304        store: &mut impl AsStoreMut,
305        env: &FunctionEnv<T>,
306        ty: FT,
307        func: F,
308    ) -> Self
309    where
310        FT: Into<FunctionType>,
311        F: Fn(AsyncFunctionEnvMut<T>, &[Value]) -> Fut + 'static,
312        Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
313    {
314        match &store.as_store_mut().inner.store {
315            #[cfg(feature = "sys")]
316            crate::BackendStore::Sys(_) => Self::Sys(
317                crate::backend::sys::entities::function::Function::new_with_env_async(
318                    store, env, ty, func,
319                ),
320            ),
321            #[cfg(feature = "wamr")]
322            crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"),
323            #[cfg(feature = "wasmi")]
324            crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"),
325            #[cfg(feature = "v8")]
326            crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
327            #[cfg(feature = "js")]
328            crate::BackendStore::Js(_) => unsupported_async_backend("js"),
329            #[cfg(feature = "jsc")]
330            crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"),
331        }
332    }
333
334    /// Creates a new async host `Function` from a native typed function.
335    ///
336    /// The future can return either the raw result tuple or any type that implements
337    /// [`IntoResult`](crate::IntoResult) for the result tuple (e.g. `Result<Rets, E>`).
338    #[inline]
339    #[cfg(feature = "experimental-async")]
340    pub fn new_typed_async<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
341    where
342        F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static,
343        Args: WasmTypeList + 'static,
344        Rets: WasmTypeList + 'static,
345    {
346        match &store.as_store_mut().inner.store {
347            #[cfg(feature = "sys")]
348            crate::BackendStore::Sys(_) => Self::Sys(
349                crate::backend::sys::entities::function::Function::new_typed_async(store, func),
350            ),
351            #[cfg(feature = "wamr")]
352            crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"),
353            #[cfg(feature = "wasmi")]
354            crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"),
355            #[cfg(feature = "v8")]
356            crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
357            #[cfg(feature = "js")]
358            crate::BackendStore::Js(_) => unsupported_async_backend("js"),
359            #[cfg(feature = "jsc")]
360            crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"),
361        }
362    }
363
364    /// Creates a new async host `Function` with an environment from a typed function.
365    #[inline]
366    #[cfg(feature = "experimental-async")]
367    pub fn new_typed_with_env_async<T: 'static, F, Args, Rets>(
368        store: &mut impl AsStoreMut,
369        env: &FunctionEnv<T>,
370        func: F,
371    ) -> Self
372    where
373        F: AsyncHostFunction<T, Args, Rets, WithEnv> + 'static,
374        Args: WasmTypeList + 'static,
375        Rets: WasmTypeList + 'static,
376    {
377        match &store.as_store_mut().inner.store {
378            #[cfg(feature = "sys")]
379            crate::BackendStore::Sys(_) => Self::Sys(
380                crate::backend::sys::entities::function::Function::new_typed_with_env_async(
381                    store, env, func,
382                ),
383            ),
384            #[cfg(feature = "wamr")]
385            crate::BackendStore::Wamr(_) => unsupported_async_backend("wamr"),
386            #[cfg(feature = "wasmi")]
387            crate::BackendStore::Wasmi(_) => unsupported_async_backend("wasmi"),
388            #[cfg(feature = "v8")]
389            crate::BackendStore::V8(_) => unsupported_async_backend("v8"),
390            #[cfg(feature = "js")]
391            crate::BackendStore::Js(_) => unsupported_async_backend("js"),
392            #[cfg(feature = "jsc")]
393            crate::BackendStore::Jsc(_) => unsupported_async_backend("jsc"),
394        }
395    }
396
397    /// Returns the [`FunctionType`] of the `Function`.
398    ///
399    /// # Example
400    ///
401    /// ```
402    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
403    /// # let mut store = Store::default();
404    /// # let env = FunctionEnv::new(&mut store, ());
405    /// #
406    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
407    ///     a + b
408    /// }
409    ///
410    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
411    ///
412    /// assert_eq!(f.ty(&mut store).params(), vec![Type::I32, Type::I32]);
413    /// assert_eq!(f.ty(&mut store).results(), vec![Type::I32]);
414    /// ```
415    #[inline]
416    pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
417        match_rt!(on self => f {
418            f.ty(store)
419        })
420    }
421
422    /// Returns the number of parameters that this function takes.
423    ///
424    /// # Example
425    ///
426    /// ```
427    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
428    /// # let mut store = Store::default();
429    /// # let env = FunctionEnv::new(&mut store, ());
430    /// #
431    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
432    ///     a + b
433    /// }
434    ///
435    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
436    ///
437    /// assert_eq!(f.param_arity(&mut store), 2);
438    /// ```
439    #[inline]
440    pub fn param_arity(&self, store: &impl AsStoreRef) -> usize {
441        self.ty(store).params().len()
442    }
443
444    /// Returns the number of results this function produces.
445    ///
446    /// # Example
447    ///
448    /// ```
449    /// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
450    /// # let mut store = Store::default();
451    /// # let env = FunctionEnv::new(&mut store, ());
452    /// #
453    /// fn sum(_env: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
454    ///     a + b
455    /// }
456    ///
457    /// let f = Function::new_typed_with_env(&mut store, &env, sum);
458    ///
459    /// assert_eq!(f.result_arity(&mut store), 1);
460    /// ```
461    #[inline]
462    pub fn result_arity(&self, store: &impl AsStoreRef) -> usize {
463        self.ty(store).params().len()
464    }
465
466    /// Call the `Function` function.
467    ///
468    /// Depending on where the Function is defined, it will call it.
469    /// 1. If the function is defined inside a WebAssembly, it will call the trampoline
470    ///    for the function signature.
471    /// 2. If the function is defined in the host (in a native way), it will
472    ///    call the trampoline.
473    ///
474    /// # Examples
475    ///
476    /// ```
477    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
478    /// # use wasmer::FunctionEnv;
479    /// # let mut store = Store::default();
480    /// # let env = FunctionEnv::new(&mut store, ());
481    /// # let wasm_bytes = wat2wasm(r#"
482    /// # (module
483    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
484    /// #     local.get $x
485    /// #     local.get $y
486    /// #     i32.add
487    /// #   ))
488    /// # "#.as_bytes()).unwrap();
489    /// # let module = Module::new(&store, wasm_bytes).unwrap();
490    /// # let import_object = imports! {};
491    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
492    /// #
493    /// let sum = instance.exports.get_function("sum").unwrap();
494    ///
495    /// assert_eq!(sum.call(&mut store, &[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
496    /// ```
497    #[inline]
498    pub fn call(
499        &self,
500        store: &mut impl AsStoreMut,
501        params: &[Value],
502    ) -> Result<Box<[Value]>, RuntimeError> {
503        match_rt!(on self => f {
504            f.call(store, params)
505        })
506    }
507
508    #[doc(hidden)]
509    #[allow(missing_docs)]
510    #[inline]
511    pub fn call_raw(
512        &self,
513        store: &mut impl AsStoreMut,
514        params: Vec<RawValue>,
515    ) -> Result<Box<[Value]>, RuntimeError> {
516        match_rt!(on self => f {
517            f.call_raw(store, params)
518        })
519    }
520
521    #[cfg(feature = "experimental-async")]
522    #[allow(clippy::type_complexity)]
523    pub fn call_async(
524        &self,
525        store: &impl AsStoreAsync,
526        params: Vec<Value>,
527    ) -> Pin<Box<dyn Future<Output = Result<Box<[Value]>, RuntimeError>> + 'static>> {
528        match self {
529            #[cfg(feature = "sys")]
530            Self::Sys(f) => f.call_async(store, params),
531            #[cfg(feature = "wamr")]
532            Self::Wamr(_) => unsupported_async_future(),
533            #[cfg(feature = "wasmi")]
534            Self::Wasmi(_) => unsupported_async_future(),
535            #[cfg(feature = "v8")]
536            Self::V8(_) => unsupported_async_future(),
537            #[cfg(feature = "js")]
538            Self::Js(_) => unsupported_async_future(),
539            #[cfg(feature = "jsc")]
540            Self::Jsc(_) => unsupported_async_future(),
541        }
542    }
543
544    #[inline]
545    pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
546        match self {
547            #[cfg(feature = "sys")]
548            Self::Sys(f) => VMFuncRef::Sys(f.vm_funcref(store)),
549            #[cfg(feature = "wamr")]
550            Self::Wamr(f) => VMFuncRef::Wamr(f.vm_funcref(store)),
551            #[cfg(feature = "wasmi")]
552            Self::Wasmi(f) => VMFuncRef::Wasmi(f.vm_funcref(store)),
553            #[cfg(feature = "v8")]
554            Self::V8(f) => VMFuncRef::V8(f.vm_funcref(store)),
555            #[cfg(feature = "js")]
556            Self::Js(f) => VMFuncRef::Js(f.vm_funcref(store)),
557            #[cfg(feature = "jsc")]
558            Self::Jsc(f) => VMFuncRef::Jsc(f.vm_funcref(store)),
559        }
560    }
561
562    #[inline]
563    pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
564        match &store.as_store_mut().inner.store {
565            #[cfg(feature = "sys")]
566            crate::BackendStore::Sys(s) => Self::Sys(unsafe {
567                crate::backend::sys::entities::function::Function::from_vm_funcref(
568                    store,
569                    funcref.unwrap_sys(),
570                )
571            }),
572            #[cfg(feature = "wamr")]
573            crate::BackendStore::Wamr(s) => Self::Wamr(unsafe {
574                crate::backend::wamr::entities::function::Function::from_vm_funcref(
575                    store,
576                    funcref.unwrap_wamr(),
577                )
578            }),
579            #[cfg(feature = "wasmi")]
580            crate::BackendStore::Wasmi(s) => Self::Wasmi(unsafe {
581                crate::backend::wasmi::entities::function::Function::from_vm_funcref(
582                    store,
583                    funcref.unwrap_wasmi(),
584                )
585            }),
586            #[cfg(feature = "v8")]
587            crate::BackendStore::V8(s) => Self::V8(unsafe {
588                crate::backend::v8::entities::function::Function::from_vm_funcref(
589                    store,
590                    funcref.unwrap_v_8(),
591                )
592            }),
593            #[cfg(feature = "js")]
594            crate::BackendStore::Js(s) => Self::Js(unsafe {
595                crate::backend::js::entities::function::Function::from_vm_funcref(
596                    store,
597                    funcref.unwrap_js(),
598                )
599            }),
600            #[cfg(feature = "jsc")]
601            crate::BackendStore::Jsc(s) => Self::Jsc(unsafe {
602                crate::backend::jsc::entities::function::Function::from_vm_funcref(
603                    store,
604                    funcref.unwrap_jsc(),
605                )
606            }),
607        }
608    }
609
610    /// Transform this WebAssembly function into a typed function.
611    /// See [`TypedFunction`] to learn more.
612    ///
613    /// # Examples
614    ///
615    /// ```
616    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
617    /// # use wasmer::FunctionEnv;
618    /// # let mut store = Store::default();
619    /// # let env = FunctionEnv::new(&mut store, ());
620    /// # let wasm_bytes = wat2wasm(r#"
621    /// # (module
622    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
623    /// #     local.get $x
624    /// #     local.get $y
625    /// #     i32.add
626    /// #   ))
627    /// # "#.as_bytes()).unwrap();
628    /// # let module = Module::new(&store, wasm_bytes).unwrap();
629    /// # let import_object = imports! {};
630    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
631    /// #
632    /// let sum = instance.exports.get_function("sum").unwrap();
633    /// let sum_typed: TypedFunction<(i32, i32), i32> = sum.typed(&mut store).unwrap();
634    ///
635    /// assert_eq!(sum_typed.call(&mut store, 1, 2).unwrap(), 3);
636    /// ```
637    ///
638    /// # Errors
639    ///
640    /// If the `Args` generic parameter does not match the exported function
641    /// an error will be raised:
642    ///
643    /// ```should_panic
644    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
645    /// # use wasmer::FunctionEnv;
646    /// # let mut store = Store::default();
647    /// # let env = FunctionEnv::new(&mut store, ());
648    /// # let wasm_bytes = wat2wasm(r#"
649    /// # (module
650    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
651    /// #     local.get $x
652    /// #     local.get $y
653    /// #     i32.add
654    /// #   ))
655    /// # "#.as_bytes()).unwrap();
656    /// # let module = Module::new(&store, wasm_bytes).unwrap();
657    /// # let import_object = imports! {};
658    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
659    /// #
660    /// let sum = instance.exports.get_function("sum").unwrap();
661    ///
662    /// // This results in an error: `RuntimeError`
663    /// let sum_typed : TypedFunction<(i64, i64), i32> = sum.typed(&mut store).unwrap();
664    /// ```
665    ///
666    /// If the `Rets` generic parameter does not match the exported function
667    /// an error will be raised:
668    ///
669    /// ```should_panic
670    /// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, TypedFunction, Value};
671    /// # use wasmer::FunctionEnv;
672    /// # let mut store = Store::default();
673    /// # let env = FunctionEnv::new(&mut store, ());
674    /// # let wasm_bytes = wat2wasm(r#"
675    /// # (module
676    /// #   (func (export "sum") (param $x i32) (param $y i32) (result i32)
677    /// #     local.get $x
678    /// #     local.get $y
679    /// #     i32.add
680    /// #   ))
681    /// # "#.as_bytes()).unwrap();
682    /// # let module = Module::new(&store, wasm_bytes).unwrap();
683    /// # let import_object = imports! {};
684    /// # let instance = Instance::new(&mut store, &module, &import_object).unwrap();
685    /// #
686    /// let sum = instance.exports.get_function("sum").unwrap();
687    ///
688    /// // This results in an error: `RuntimeError`
689    /// let sum_typed: TypedFunction<(i32, i32), i64> = sum.typed(&mut store).unwrap();
690    /// ```
691    #[inline]
692    pub fn typed<Args, Rets>(
693        &self,
694        store: &impl AsStoreRef,
695    ) -> Result<TypedFunction<Args, Rets>, RuntimeError>
696    where
697        Args: WasmTypeList,
698        Rets: WasmTypeList,
699    {
700        let ty = self.ty(store);
701
702        // type check
703        {
704            let expected = ty.params();
705            let given = Args::wasm_types();
706
707            if expected != given {
708                return Err(RuntimeError::new(format!(
709                    "given types (`{given:?}`) for the function arguments don't match the actual types (`{expected:?}`)",
710                )));
711            }
712        }
713
714        {
715            let expected = ty.results();
716            let given = Rets::wasm_types();
717
718            if expected != given {
719                // todo: error result types don't match
720                return Err(RuntimeError::new(format!(
721                    "given types (`{given:?}`) for the function results don't match the actual types (`{expected:?}`)",
722                )));
723            }
724        }
725
726        Ok(TypedFunction::new(store, super::Function(self.clone())))
727    }
728
729    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
730        match &store.as_store_mut().inner.store {
731            #[cfg(feature = "sys")]
732            crate::BackendStore::Sys(_) => Self::Sys(
733                crate::backend::sys::entities::function::Function::from_vm_extern(store, vm_extern),
734            ),
735            #[cfg(feature = "wamr")]
736            crate::BackendStore::Wamr(_) => Self::Wamr(
737                crate::backend::wamr::entities::function::Function::from_vm_extern(
738                    store, vm_extern,
739                ),
740            ),
741            #[cfg(feature = "wasmi")]
742            crate::BackendStore::Wasmi(_) => Self::Wasmi(
743                crate::backend::wasmi::entities::function::Function::from_vm_extern(
744                    store, vm_extern,
745                ),
746            ),
747            #[cfg(feature = "v8")]
748            crate::BackendStore::V8(_) => Self::V8(
749                crate::backend::v8::entities::function::Function::from_vm_extern(store, vm_extern),
750            ),
751            #[cfg(feature = "js")]
752            crate::BackendStore::Js(_) => Self::Js(
753                crate::backend::js::entities::function::Function::from_vm_extern(store, vm_extern),
754            ),
755            #[cfg(feature = "jsc")]
756            crate::BackendStore::Jsc(_) => Self::Jsc(
757                crate::backend::jsc::entities::function::Function::from_vm_extern(store, vm_extern),
758            ),
759        }
760    }
761
762    /// Checks whether this `Function` can be used with the given store.
763    #[inline]
764    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
765        match_rt!(on self => f {
766            f.is_from_store(store)
767        })
768    }
769
770    #[inline]
771    pub(crate) fn to_vm_extern(&self) -> VMExtern {
772        match_rt!(on self => f {
773            f.to_vm_extern()
774        })
775    }
776}
777
778#[cold]
779fn unsupported_async_backend(backend: &str) -> ! {
780    panic!(
781        "async host functions are only supported with the `sys` backend (attempted on {backend})"
782    )
783}
784
785#[allow(clippy::type_complexity)]
786pub(super) fn unsupported_async_future<'a>()
787-> Pin<Box<dyn Future<Output = Result<Box<[Value]>, RuntimeError>> + 'a>> {
788    Box::pin(async {
789        Err(RuntimeError::new(
790            "async calls are only supported with the `sys` backend",
791        ))
792    })
793}
794
795impl<'a> Exportable<'a> for BackendFunction {
796    fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
797        match _extern {
798            Extern::Function(func) => Ok(&func.0),
799            _ => Err(ExportError::IncompatibleType),
800        }
801    }
802}