Coverage Report

Created: 2025-08-28 07:14

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