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
27pub 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 ) -> 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 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 ) -> 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 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 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 ) -> Result<Returns, RuntimeError> {
128 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 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 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 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 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(
182 &mut current_module_idx,
183 &mut stack,
184 EmptyHookSet,
185 self.store.as_mut().unwrap_validated(),
186 )?;
187
188 let return_values = Returns::TYS
190 .iter()
191 .rev()
192 .map(|ty| stack.pop_value(*ty))
193 .collect::<Vec<Value>>();
194
195 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 pub fn invoke_dynamic(
204 &mut self,
205 function_ref: &FunctionRef,
206 params: Vec<Value>,
207 ret_types: &[ValType],
208 ) -> Result<Vec<Value>, RuntimeError> {
210 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 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 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 if func_ty.returns.valtypes != ret_types {
240 panic!("Invalid return types for function");
241 }
242
243 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(
252 &mut currrent_module_idx,
253 &mut stack,
254 EmptyHookSet,
255 self.store.as_mut().unwrap_validated(),
256 )?;
257
258 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 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 pub fn invoke_dynamic_unchecked_return_ty(
288 &mut self,
289 function_ref: &FunctionRef,
290 params: Vec<Value>,
291 ) -> Result<Vec<Value>, RuntimeError> {
292 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 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 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 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(
328 &mut currrent_module_idx,
329 &mut stack,
330 EmptyHookSet,
331 self.store.as_mut().unwrap_validated(),
332 )?;
333
334 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 let reversed_values = return_values.into_iter().rev();
345 let ret = reversed_values.collect();
346 debug!("Successfully invoked function");
347 Ok(ret)
348 }
349}