Coverage Report

Created: 2025-06-23 13:53

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