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}