wasm/execution/
mod.rs

1use alloc::vec::Vec;
2
3use const_interpreter_loop::run_const_span;
4use function_ref::FunctionRef;
5use interpreter_loop::run;
6use locals::Locals;
7use value_stack::Stack;
8
9use crate::execution::assert_validated::UnwrapValidatedExt;
10use crate::execution::hooks::{EmptyHookSet, HookSet};
11use crate::execution::store::Store;
12use crate::execution::value::Value;
13use crate::value::InteropValueList;
14use crate::{Result as CustomResult, RuntimeError, ValType, ValidationInfo};
15
16pub(crate) mod assert_validated;
17pub mod const_interpreter_loop;
18pub mod function_ref;
19pub mod hooks;
20mod interpreter_loop;
21pub(crate) mod linear_memory;
22pub(crate) mod locals;
23pub mod store;
24pub mod value;
25pub mod value_stack;
26
27/// The default module name if a [RuntimeInstance] was created using [RuntimeInstance::new].
28pub const DEFAULT_MODULE: &str = "__interpreter_default__";
29
30#[derive(Debug)]
31pub struct RuntimeInstance<'b, H = EmptyHookSet>
32where
33    H: HookSet + core::fmt::Debug,
34{
35    pub hook_set: H,
36    pub store: Option<Store<'b>>,
37}
38
39impl<'b> RuntimeInstance<'b, EmptyHookSet> {
40    pub fn new(validation_info: &'_ ValidationInfo<'b>) -> CustomResult<Self> {
41        Self::new_with_hooks(DEFAULT_MODULE, validation_info, EmptyHookSet)
42    }
43
44    pub fn new_named(
45        module_name: &str,
46        validation_info: &'_ ValidationInfo<'b>,
47        // store: &mut Store,
48    ) -> CustomResult<Self> {
49        Self::new_with_hooks(module_name, validation_info, EmptyHookSet)
50    }
51}
52
53impl<'b, H> RuntimeInstance<'b, H>
54where
55    H: HookSet + core::fmt::Debug,
56{
57    pub fn add_module(
58        &mut self,
59        module_name: &str,
60        validation_info: &'_ ValidationInfo<'b>,
61    ) -> CustomResult<()> {
62        match self.store {
63            // TODO fix error
64            None => return Err(crate::Error::RuntimeError(RuntimeError::ModuleNotFound)),
65            Some(ref mut store) => {
66                store.add_module(module_name, validation_info)?;
67            }
68        };
69        Ok(())
70    }
71
72    pub fn new_with_hooks(
73        module_name: &str,
74        validation_info: &'_ ValidationInfo<'b>,
75        hook_set: H,
76        // store: &mut Store,
77    ) -> CustomResult<Self> {
78        trace!("Starting instantiation of bytecode");
79
80        let store = Some(Store::default());
81
82        let mut instance = RuntimeInstance { hook_set, store };
83        instance.add_module(module_name, validation_info)?;
84
85        Ok(instance)
86    }
87
88    pub fn get_function_by_name(
89        &self,
90        module_name: &str,
91        function_name: &str,
92    ) -> Result<FunctionRef, RuntimeError> {
93        // TODO fix error
94        let store = self.store.as_ref().ok_or(RuntimeError::ModuleNotFound)?;
95        if !store.module_names.contains_key(module_name) {
96            return Err(RuntimeError::ModuleNotFound);
97        };
98        FunctionRef::new_from_name(module_name, function_name, 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        // TODO fix error
108        let store = self.store.as_ref().ok_or(RuntimeError::ModuleNotFound)?;
109
110        let module_inst = store
111            .modules
112            .get(module_addr)
113            .ok_or(RuntimeError::ModuleNotFound)?;
114        let func_addr = *module_inst
115            .func_addrs
116            .get(function_idx)
117            .ok_or(RuntimeError::FunctionNotFound)?;
118
119        Ok(FunctionRef { func_addr })
120    }
121
122    pub fn invoke<Param: InteropValueList, Returns: InteropValueList>(
123        &mut self,
124        function_ref: &FunctionRef,
125        params: Param,
126        // store: &mut Store,
127    ) -> Result<Returns, RuntimeError> {
128        // TODO fix error
129        let store = self.store.as_ref().ok_or(RuntimeError::ModuleNotFound)?;
130
131        let FunctionRef { func_addr } = *function_ref;
132        let func_inst = store
133            .functions
134            .get(func_addr)
135            .ok_or(RuntimeError::FunctionNotFound)?;
136
137        let module_addr = func_inst.module_addr;
138
139        // TODO handle this bad linear search that is unavoidable
140        let (func_idx, _) = store.modules[module_addr]
141            .func_addrs
142            .iter()
143            .enumerate()
144            .find(|&(_idx, addr)| *addr == func_addr)
145            .ok_or(RuntimeError::FunctionNotFound)?;
146
147        let func_ty = func_inst.ty();
148
149        // Check correct function parameters and return types
150        if func_ty.params.valtypes != Param::TYS {
151            panic!("Invalid `Param` generics");
152        }
153        if func_ty.returns.valtypes != Returns::TYS {
154            panic!(
155                "Invalid `Returns` generics, expected {:?}",
156                func_ty.returns.valtypes
157            );
158        }
159
160        // Prepare a new stack with the locals for the entry function
161        let mut stack = Stack::new();
162        let locals = Locals::new(
163            params.into_values().into_iter(),
164            func_inst.locals.iter().cloned(),
165        );
166
167        // setting `usize::MAX` as return address for the outermost function ensures that we
168        // observably fail upon errornoeusly continuing execution after that function returns.
169        stack.push_stackframe(
170            module_addr,
171            func_idx,
172            &func_ty,
173            locals,
174            usize::MAX,
175            usize::MAX,
176        )?;
177
178        let mut current_module_idx = module_addr;
179
180        // Run the interpreter
181        run(
182            &mut current_module_idx,
183            &mut stack,
184            EmptyHookSet,
185            self.store.as_mut().unwrap_validated(),
186        )?;
187
188        // Pop return values from stack
189        let return_values = Returns::TYS
190            .iter()
191            .rev()
192            .map(|ty| stack.pop_value(*ty))
193            .collect::<Vec<Value>>();
194
195        // Values are reversed because they were popped from stack one-by-one. Now reverse them back
196        let reversed_values = return_values.into_iter().rev();
197        let ret: Returns = Returns::from_values(reversed_values);
198        debug!("Successfully invoked function");
199        Ok(ret)
200    }
201
202    /// Invokes a function with the given parameters, and return types which are not known at compile time.
203    pub fn invoke_dynamic(
204        &mut self,
205        function_ref: &FunctionRef,
206        params: Vec<Value>,
207        ret_types: &[ValType],
208        // store: &mut Store,
209    ) -> Result<Vec<Value>, RuntimeError> {
210        // TODO fix error
211        let store = self.store.as_ref().ok_or(RuntimeError::ModuleNotFound)?;
212
213        let FunctionRef { func_addr } = *function_ref;
214        let func_inst = store
215            .functions
216            .get(func_addr)
217            .ok_or(RuntimeError::FunctionNotFound)?;
218
219        let module_addr = func_inst.module_addr;
220
221        // TODO handle this bad linear search that is unavoidable
222        let (func_idx, _) = store.modules[module_addr]
223            .func_addrs
224            .iter()
225            .enumerate()
226            .find(|&(_idx, addr)| *addr == func_addr)
227            .ok_or(RuntimeError::FunctionNotFound)?;
228
229        let func_ty = func_inst.ty();
230
231        // Verify that the given parameters match the function parameters
232        let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
233
234        if func_ty.params.valtypes != param_types {
235            panic!("Invalid parameters for function");
236        }
237
238        // Verify that the given return types match the function return types
239        if func_ty.returns.valtypes != ret_types {
240            panic!("Invalid return types for function");
241        }
242
243        // Prepare a new stack with the locals for the entry function
244        let mut stack = Stack::new();
245        let locals = Locals::new(params.into_iter(), func_inst.locals.iter().cloned());
246        stack.push_stackframe(module_addr, func_idx, &func_ty, locals, 0, 0)?;
247
248        let mut currrent_module_idx = module_addr;
249
250        // Run the interpreter
251        run(
252            &mut currrent_module_idx,
253            &mut stack,
254            EmptyHookSet,
255            self.store.as_mut().unwrap_validated(),
256        )?;
257
258        // Pop return values from stack
259        let return_values = func_ty
260            .returns
261            .valtypes
262            .iter()
263            .rev()
264            .map(|ty| stack.pop_value(*ty))
265            .collect::<Vec<Value>>();
266
267        // Values are reversed because they were popped from stack one-by-one. Now reverse them back
268        let reversed_values = return_values.into_iter().rev();
269        let ret = reversed_values.collect();
270        debug!("Successfully invoked function");
271        Ok(ret)
272    }
273
274    /// Get the indicies of a module and function by their names.
275    ///
276    /// # Arguments
277    /// - `module_name`: The module in which to find the function.
278    /// - `function_name`: The name of the function to find inside the module. The function must be a local function and
279    ///   not an import.
280    ///
281    /// # Returns
282    /// - `Ok((module_idx, func_idx))`, where `module_idx` is the internal index of the module inside the
283    ///   [RuntimeInstance], and `func_idx` is the internal index of the function inside the module.
284    /// - `Err(RuntimeError::ModuleNotFound)`, if the module is not found.
285    /// - `Err(RuntimeError::FunctionNotFound`, if the function is not found within the module.
286    ///
287    pub fn invoke_dynamic_unchecked_return_ty(
288        &mut self,
289        function_ref: &FunctionRef,
290        params: Vec<Value>,
291    ) -> Result<Vec<Value>, RuntimeError> {
292        // TODO fix error
293        let store = self.store.as_ref().ok_or(RuntimeError::ModuleNotFound)?;
294
295        let FunctionRef { func_addr } = *function_ref;
296        let func_inst = store
297            .functions
298            .get(func_addr)
299            .ok_or(RuntimeError::FunctionNotFound)?;
300
301        let module_addr = func_inst.module_addr;
302
303        // TODO handle this bad linear search that is unavoidable
304        let (func_idx, _) = store.modules[module_addr]
305            .func_addrs
306            .iter()
307            .enumerate()
308            .find(|&(_idx, addr)| *addr == func_addr)
309            .ok_or(RuntimeError::FunctionNotFound)?;
310        let func_ty = func_inst.ty();
311
312        // Verify that the given parameters match the function parameters
313        let param_types = params.iter().map(|v| v.to_ty()).collect::<Vec<_>>();
314
315        if func_ty.params.valtypes != param_types {
316            panic!("Invalid parameters for function");
317        }
318
319        // Prepare a new stack with the locals for the entry function
320        let mut stack = Stack::new();
321        let locals = Locals::new(params.into_iter(), func_inst.locals.iter().cloned());
322        stack.push_stackframe(module_addr, func_idx, &func_ty, locals, 0, 0)?;
323
324        let mut currrent_module_idx = module_addr;
325
326        // Run the interpreter
327        run(
328            &mut currrent_module_idx,
329            &mut stack,
330            EmptyHookSet,
331            self.store.as_mut().unwrap_validated(),
332        )?;
333
334        // Pop return values from stack
335        let return_values = func_ty
336            .returns
337            .valtypes
338            .iter()
339            .rev()
340            .map(|ty| stack.pop_value(*ty))
341            .collect::<Vec<Value>>();
342
343        // Values are reversed because they were popped from stack one-by-one. Now reverse them back
344        let reversed_values = return_values.into_iter().rev();
345        let ret = reversed_values.collect();
346        debug!("Successfully invoked function");
347        Ok(ret)
348    }
349}