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