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