wasm/execution/
mod.rs

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