wasm/execution/
mod.rs

1use crate::Error;
2
3use alloc::borrow::ToOwned;
4use alloc::vec::Vec;
5
6use const_interpreter_loop::run_const_span;
7use function_ref::FunctionRef;
8use value_stack::Stack;
9
10use crate::core::reader::types::{FuncType, ResultType};
11use crate::execution::assert_validated::UnwrapValidatedExt;
12use crate::execution::hooks::{EmptyHookSet, HookSet};
13use crate::execution::store::Store;
14use crate::execution::value::Value;
15use crate::value::InteropValueList;
16use crate::{Result as CustomResult, RuntimeError, ValidationInfo};
17
18pub(crate) mod assert_validated;
19pub mod const_interpreter_loop;
20pub mod function_ref;
21pub mod hooks;
22mod interpreter_loop;
23pub(crate) mod linear_memory;
24pub(crate) mod locals;
25pub mod registry;
26pub mod store;
27pub mod value;
28pub mod value_stack;
29
30/// The default module name if a [RuntimeInstance] was created using [RuntimeInstance::new].
31pub const DEFAULT_MODULE: &str = "__interpreter_default__";
32
33#[derive(Debug)]
34pub struct RuntimeInstance<'b, T = (), H = EmptyHookSet>
35where
36    H: HookSet + core::fmt::Debug,
37{
38    pub hook_set: H,
39    pub store: Store<'b, T>,
40}
41
42impl<T: Default> Default for RuntimeInstance<'_, T, EmptyHookSet> {
43    fn default() -> Self {
44        Self::new(T::default())
45    }
46}
47
48impl<'b, T> RuntimeInstance<'b, T, EmptyHookSet> {
49    pub fn new(user_data: T) -> Self {
50        Self::new_with_hooks(user_data, EmptyHookSet)
51    }
52
53    pub fn new_with_default_module(
54        user_data: T,
55        validation_info: &'_ ValidationInfo<'b>,
56    ) -> CustomResult<Self> {
57        let mut instance = Self::new_with_hooks(user_data, EmptyHookSet);
58        instance.add_module(DEFAULT_MODULE, validation_info)?;
59        Ok(instance)
60    }
61
62    pub fn new_named(
63        user_data: T,
64        module_name: &str,
65        validation_info: &'_ ValidationInfo<'b>,
66        // store: &mut Store,
67    ) -> CustomResult<Self> {
68        let mut instance = Self::new_with_hooks(user_data, EmptyHookSet);
69        instance.add_module(module_name, validation_info)?;
70        Ok(instance)
71    }
72}
73
74impl<'b, T, H> RuntimeInstance<'b, T, H>
75where
76    H: HookSet + core::fmt::Debug,
77{
78    pub fn add_module(
79        &mut self,
80        module_name: &str,
81        validation_info: &'_ ValidationInfo<'b>,
82    ) -> CustomResult<()> {
83        self.store.add_module(module_name, validation_info)
84    }
85
86    pub fn new_with_hooks(user_data: T, hook_set: H) -> Self {
87        RuntimeInstance {
88            hook_set,
89            store: Store::new(user_data),
90        }
91    }
92
93    pub fn get_function_by_name(
94        &self,
95        module_name: &str,
96        function_name: &str,
97    ) -> Result<FunctionRef, RuntimeError> {
98        FunctionRef::new_from_name(module_name, function_name, &self.store)
99            .map_err(|_| RuntimeError::FunctionNotFound)
100    }
101
102    pub fn get_function_by_index(
103        &self,
104        module_addr: usize,
105        function_idx: usize,
106    ) -> Result<FunctionRef, RuntimeError> {
107        let module_inst = self
108            .store
109            .modules
110            .get(module_addr)
111            .ok_or(RuntimeError::ModuleNotFound)?;
112        let func_addr = *module_inst
113            .func_addrs
114            .get(function_idx)
115            .ok_or(RuntimeError::FunctionNotFound)?;
116
117        Ok(FunctionRef { func_addr })
118    }
119
120    /// Invokes a function with the given parameters of type `Param`, and return types of type `Returns`.
121    pub fn invoke_typed<Params: InteropValueList, Returns: InteropValueList>(
122        &mut self,
123        function_ref: &FunctionRef,
124        params: Params,
125        // store: &mut Store,
126    ) -> Result<Returns, RuntimeError> {
127        let FunctionRef { func_addr } = *function_ref;
128        self.store
129            .invoke(func_addr, params.into_values())
130            .map(|values| Returns::from_values(values.into_iter()))
131    }
132
133    /// Invokes a function with the given parameters. The return types depend on the function signature.
134    pub fn invoke(
135        &mut self,
136        function_ref: &FunctionRef,
137        params: Vec<Value>,
138    ) -> Result<Vec<Value>, RuntimeError> {
139        let FunctionRef { func_addr } = *function_ref;
140        self.store.invoke(func_addr, params)
141    }
142
143    /// Adds a host function under module namespace `module_name` with name `name`.
144    /// roughly similar to `func_alloc` in <https://webassembly.github.io/spec/core/appendix/embedding.html#functions>
145    /// except the host function is made visible to other modules through these names.
146    pub fn add_host_function_typed<Params: InteropValueList, Returns: InteropValueList>(
147        &mut self,
148        module_name: &str,
149        name: &str,
150        host_func: fn(&mut T, Vec<Value>) -> Vec<Value>,
151    ) -> Result<FunctionRef, Error> {
152        let host_func_ty = FuncType {
153            params: ResultType {
154                valtypes: Vec::from(Params::TYS),
155            },
156            returns: ResultType {
157                valtypes: Vec::from(Returns::TYS),
158            },
159        };
160        self.add_host_function(module_name, name, host_func_ty, host_func)
161    }
162
163    pub fn add_host_function(
164        &mut self,
165        module_name: &str,
166        name: &str,
167        host_func_ty: FuncType,
168        host_func: fn(&mut T, Vec<Value>) -> Vec<Value>,
169    ) -> Result<FunctionRef, Error> {
170        let func_addr = self.store.alloc_host_func(host_func_ty, host_func);
171        self.store.registry.register(
172            module_name.to_owned().into(),
173            name.to_owned().into(),
174            store::ExternVal::Func(func_addr),
175        )?;
176        Ok(FunctionRef { func_addr })
177    }
178
179    pub fn user_data(&self) -> &T {
180        &self.store.user_data
181    }
182
183    pub fn user_data_mut(&mut self) -> &mut T {
184        &mut self.store.user_data
185    }
186}
187
188/// Helper function to quickly construct host functions without worrying about wasm to Rust
189/// type conversion. For user data, simply move the mutable reference into the passed closure.
190/// # Example
191/// ```
192/// use wasm::{validate, RuntimeInstance, host_function_wrapper, Value};
193/// fn my_wrapped_host_func(user_data: &mut (), params: Vec<Value>) -> Vec<Value> {
194///     host_function_wrapper(params, |(x, y): (u32, i32)| -> u32 {
195///         let _user_data = user_data;
196///         x + (y as u32)
197///  })
198/// }
199/// fn main() {
200///     let mut instance = RuntimeInstance::new(());
201///     let foo_bar = instance.add_host_function_typed::<(u32,i32),u32>("foo", "bar", my_wrapped_host_func).unwrap();
202/// }
203/// ```
204pub fn host_function_wrapper<Params: InteropValueList, Results: InteropValueList>(
205    params: Vec<Value>,
206    f: impl FnOnce(Params) -> Results,
207) -> Vec<Value> {
208    let params = Params::from_values(params.into_iter());
209    let results = f(params);
210    results.into_values()
211}