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