/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 | } |