/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, H = EmptyHookSet> |
35 | | where |
36 | | H: HookSet + core::fmt::Debug, |
37 | | { |
38 | | pub hook_set: H, |
39 | | pub store: Store<'b>, |
40 | | } |
41 | | |
42 | | impl Default for RuntimeInstance<'_, EmptyHookSet> { |
43 | 0 | fn default() -> Self { |
44 | 0 | Self::new() |
45 | 0 | } |
46 | | } |
47 | | |
48 | | impl<'b> RuntimeInstance<'b, EmptyHookSet> { |
49 | 9 | pub fn new() -> Self { |
50 | 9 | Self::new_with_hooks(EmptyHookSet) |
51 | 9 | } |
52 | | |
53 | 272 | pub fn new_with_default_module(validation_info: &'_ ValidationInfo<'b>) -> CustomResult<Self> { |
54 | 272 | let mut instance = Self::new_with_hooks(EmptyHookSet); |
55 | 272 | instance.add_module(DEFAULT_MODULE, validation_info)?0 ; |
56 | 272 | Ok(instance) |
57 | 272 | } |
58 | | |
59 | 92 | pub fn new_named( |
60 | 92 | module_name: &str, |
61 | 92 | validation_info: &'_ ValidationInfo<'b>, |
62 | 92 | // store: &mut Store, |
63 | 92 | ) -> CustomResult<Self> { |
64 | 92 | let mut instance = Self::new_with_hooks(EmptyHookSet); |
65 | 92 | instance.add_module(module_name, validation_info)?0 ; |
66 | 92 | Ok(instance) |
67 | 92 | } |
68 | | } |
69 | | |
70 | | impl<'b, H> RuntimeInstance<'b, H> |
71 | | where |
72 | | H: HookSet + core::fmt::Debug, |
73 | | { |
74 | 1.62k | pub fn add_module( |
75 | 1.62k | &mut self, |
76 | 1.62k | module_name: &str, |
77 | 1.62k | validation_info: &'_ ValidationInfo<'b>, |
78 | 1.62k | ) -> CustomResult<()> { |
79 | 1.62k | self.store.add_module(module_name, validation_info) |
80 | 1.62k | } |
81 | | |
82 | 373 | pub fn new_with_hooks( |
83 | 373 | hook_set: H, |
84 | 373 | // store: &mut Store, |
85 | 373 | ) -> Self { |
86 | 373 | RuntimeInstance { |
87 | 373 | hook_set, |
88 | 373 | store: Store::default(), |
89 | 373 | } |
90 | 373 | } |
91 | | |
92 | 258 | pub fn get_function_by_name( |
93 | 258 | &self, |
94 | 258 | module_name: &str, |
95 | 258 | function_name: &str, |
96 | 258 | ) -> Result<FunctionRef, RuntimeError> { |
97 | 258 | FunctionRef::new_from_name(module_name, function_name, &self.store) |
98 | 258 | .map_err(|_| RuntimeError::FunctionNotFound0 ) |
99 | 258 | } |
100 | | |
101 | 1.32k | pub fn get_function_by_index( |
102 | 1.32k | &self, |
103 | 1.32k | module_addr: usize, |
104 | 1.32k | function_idx: usize, |
105 | 1.32k | ) -> Result<FunctionRef, RuntimeError> { |
106 | 1.32k | let module_inst = self |
107 | 1.32k | .store |
108 | 1.32k | .modules |
109 | 1.32k | .get(module_addr) |
110 | 1.32k | .ok_or(RuntimeError::ModuleNotFound)?0 ; |
111 | 1.32k | let func_addr = *module_inst |
112 | 1.32k | .func_addrs |
113 | 1.32k | .get(function_idx) |
114 | 1.32k | .ok_or(RuntimeError::FunctionNotFound)?0 ; |
115 | | |
116 | 1.32k | Ok(FunctionRef { func_addr }) |
117 | 1.32k | } |
118 | | |
119 | | /// Invokes a function with the given parameters of type `Param`, and return types of type `Returns`. |
120 | 6.84k | pub fn invoke_typed<Params: InteropValueList, Returns: InteropValueList>( |
121 | 6.84k | &mut self, |
122 | 6.84k | function_ref: &FunctionRef, |
123 | 6.84k | params: Params, |
124 | 6.84k | // store: &mut Store, |
125 | 6.84k | ) -> Result<Returns, RuntimeError> { |
126 | 6.84k | let FunctionRef { func_addr } = *function_ref; |
127 | 6.84k | self.store |
128 | 6.84k | .invoke(func_addr, params.into_values()) |
129 | 6.84k | .map(|values| Returns::from_values(values.into_iter())6.18k ) |
130 | 6.84k | } |
131 | | |
132 | | /// Invokes a function with the given parameters. The return types depend on the function signature. |
133 | 23.4k | pub fn invoke( |
134 | 23.4k | &mut self, |
135 | 23.4k | function_ref: &FunctionRef, |
136 | 23.4k | params: Vec<Value>, |
137 | 23.4k | ) -> Result<Vec<Value>, RuntimeError> { |
138 | 23.4k | let FunctionRef { func_addr } = *function_ref; |
139 | 23.4k | self.store.invoke(func_addr, params) |
140 | 23.4k | } |
141 | | |
142 | | /// Adds a host function under module namespace `module_name` with name `name`. |
143 | | /// roughly similar to `func_alloc` in <https://webassembly.github.io/spec/core/appendix/embedding.html#functions> |
144 | | /// except the host function is made visible to other modules through these names. |
145 | 10 | pub fn add_host_function_typed<Params: InteropValueList, Returns: InteropValueList>( |
146 | 10 | &mut self, |
147 | 10 | module_name: &str, |
148 | 10 | name: &str, |
149 | 10 | host_func: fn(Vec<Value>) -> Vec<Value>, |
150 | 10 | ) -> Result<FunctionRef, Error> { |
151 | 10 | let host_func_ty = FuncType { |
152 | 10 | params: ResultType { |
153 | 10 | valtypes: Vec::from(Params::TYS), |
154 | 10 | }, |
155 | 10 | returns: ResultType { |
156 | 10 | valtypes: Vec::from(Returns::TYS), |
157 | 10 | }, |
158 | 10 | }; |
159 | 10 | self.add_host_function(module_name, name, host_func_ty, host_func) |
160 | 10 | } |
161 | | |
162 | 10 | pub fn add_host_function( |
163 | 10 | &mut self, |
164 | 10 | module_name: &str, |
165 | 10 | name: &str, |
166 | 10 | host_func_ty: FuncType, |
167 | 10 | host_func: fn(Vec<Value>) -> Vec<Value>, |
168 | 10 | ) -> Result<FunctionRef, Error> { |
169 | 10 | let func_addr = self.store.alloc_host_func(host_func_ty, host_func); |
170 | 10 | self.store.registry.register( |
171 | 10 | module_name.to_owned().into(), |
172 | 10 | name.to_owned().into(), |
173 | 10 | store::ExternVal::Func(func_addr), |
174 | 10 | )?0 ; |
175 | 10 | Ok(FunctionRef { func_addr }) |
176 | 10 | } |
177 | | } |
178 | | |
179 | | /// Helper function to quickly construct host functions without worrying about wasm to Rust |
180 | | /// type conversion. |
181 | | /// # Example |
182 | | /// ``` |
183 | | /// use wasm::{validate, RuntimeInstance, host_function_wrapper, Value}; |
184 | | /// fn my_wrapped_host_func(params: Vec<Value>) -> Vec<Value> { |
185 | | /// host_function_wrapper(params, |(x, y): (u32, i32)| -> u32 { |
186 | | /// x + (y as u32) |
187 | | /// }) |
188 | | /// } |
189 | | /// fn main() { |
190 | | /// let mut instance = RuntimeInstance::new(); |
191 | | /// let foo_bar = instance.add_host_function_typed::<(u32,i32),u32>("foo", "bar", my_wrapped_host_func).unwrap(); |
192 | | /// } |
193 | | /// ``` |
194 | 1 | pub fn host_function_wrapper<Params: InteropValueList, Results: InteropValueList>( |
195 | 1 | params: Vec<Value>, |
196 | 1 | f: impl FnOnce(Params) -> Results, |
197 | 1 | ) -> Vec<Value> { |
198 | 1 | let params = Params::from_values(params.into_iter()); |
199 | 1 | let results = f(params); |
200 | 1 | results.into_values() |
201 | 1 | } |