/__w/smoldot/smoldot/repo/lib/src/executor/vm/interpreter.rs
Line | Count | Source (jump to first uncovered line) |
1 | | // Smoldot |
2 | | // Copyright (C) 2019-2022 Parity Technologies (UK) Ltd. |
3 | | // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 |
4 | | |
5 | | // This program is free software: you can redistribute it and/or modify |
6 | | // it under the terms of the GNU General Public License as published by |
7 | | // the Free Software Foundation, either version 3 of the License, or |
8 | | // (at your option) any later version. |
9 | | |
10 | | // This program is distributed in the hope that it will be useful, |
11 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | // GNU General Public License for more details. |
14 | | |
15 | | // You should have received a copy of the GNU General Public License |
16 | | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | |
18 | | //! Implements the API documented [in the parent module](..). |
19 | | |
20 | | use super::{ |
21 | | ExecOutcome, GlobalValueErr, HeapPages, NewErr, OutOfBoundsError, RunErr, Signature, StartErr, |
22 | | Trap, ValueType, WasmValue, |
23 | | }; |
24 | | |
25 | | use alloc::{borrow::ToOwned as _, string::ToString as _, sync::Arc, vec::Vec}; |
26 | | use core::fmt; |
27 | | |
28 | | pub use wasmi::CompilationMode; |
29 | | |
30 | | /// See [`super::VirtualMachinePrototype`]. |
31 | | pub struct InterpreterPrototype { |
32 | | /// Base components that can be used to recreate a prototype later if desired. |
33 | | base_components: BaseComponents, |
34 | | |
35 | | // TODO: doc |
36 | | store: wasmi::Store<()>, |
37 | | |
38 | | /// An instance of the module. |
39 | | instance: wasmi::Instance, |
40 | | |
41 | | /// Memory of the module instantiation. |
42 | | memory: wasmi::Memory, |
43 | | } |
44 | | |
45 | | struct BaseComponents { |
46 | | module: Arc<wasmi::Module>, |
47 | | |
48 | | /// For each import of the module, either `None` if not a function, or `Some` containing the |
49 | | /// `usize` of that function. |
50 | | resolved_imports: Vec<Option<usize>>, |
51 | | } |
52 | | |
53 | | impl InterpreterPrototype { |
54 | | /// See [`super::VirtualMachinePrototype::new`]. |
55 | 141 | pub fn new( |
56 | 141 | module_bytes: &[u8], |
57 | 141 | compilation_mode: CompilationMode, |
58 | 141 | symbols: &mut dyn FnMut(&str, &str, &Signature) -> Result<usize, ()>, |
59 | 141 | ) -> Result<Self, NewErr> { |
60 | 141 | let engine = { |
61 | 141 | let mut config = wasmi::Config::default(); |
62 | 141 | |
63 | 141 | // Disable all the post-MVP wasm features. |
64 | 141 | config.wasm_sign_extension(false); |
65 | 141 | config.wasm_reference_types(false); |
66 | 141 | config.wasm_bulk_memory(false); |
67 | 141 | config.wasm_multi_value(false); |
68 | 141 | config.wasm_extended_const(false); |
69 | 141 | config.wasm_mutable_global(false); |
70 | 141 | config.wasm_saturating_float_to_int(false); |
71 | 141 | config.wasm_tail_call(false); |
72 | 141 | config.compilation_mode(compilation_mode); |
73 | 141 | |
74 | 141 | wasmi::Engine::new(&config) |
75 | | }; |
76 | | |
77 | 141 | let module128 = wasmi::Module::new(&engine, module_bytes) |
78 | 141 | .map_err(|err| NewErr::InvalidWasm(err.to_string())13 )?13 ; _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype3new0Ba_ Line | Count | Source | 78 | 13 | .map_err(|err| NewErr::InvalidWasm(err.to_string()))?; |
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype3new0Ba_ |
79 | | |
80 | 128 | let mut resolved_imports = Vec::with_capacity(module.imports().len()); |
81 | 2.34k | for import in module.imports()128 { |
82 | 2.34k | match import.ty() { |
83 | 2.23k | wasmi::ExternType::Func(func_type) => { |
84 | 2.23k | // Note that if `Signature::try_from` fails, a `UnresolvedFunctionImport` is |
85 | 2.23k | // also returned. This is because it is not possible for the function to |
86 | 2.23k | // resolve anyway if its signature can't be represented. |
87 | 2.23k | let function_index = |
88 | 2.23k | match Signature::try_from(func_type) |
89 | 2.23k | .ok() |
90 | 2.23k | .and_then(|conv_signature| { |
91 | 2.23k | symbols(import.module(), import.name(), &conv_signature).ok() |
92 | 2.23k | }) { _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype3news_0Ba_ Line | Count | Source | 90 | 410 | .and_then(|conv_signature| { | 91 | 410 | symbols(import.module(), import.name(), &conv_signature).ok() | 92 | 410 | }) { |
_RNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype3news_0Ba_ Line | Count | Source | 90 | 1.82k | .and_then(|conv_signature| { | 91 | 1.82k | symbols(import.module(), import.name(), &conv_signature).ok() | 92 | 1.82k | }) { |
|
93 | 2.23k | Some(i) => i, |
94 | | None => { |
95 | 5 | return Err(NewErr::UnresolvedFunctionImport { |
96 | 5 | module_name: import.module().to_owned(), |
97 | 5 | function: import.name().to_owned(), |
98 | 5 | }) |
99 | | } |
100 | | }; |
101 | | |
102 | 2.23k | resolved_imports.push(Some(function_index)); |
103 | | } |
104 | 101 | wasmi::ExternType::Memory(_) => resolved_imports.push(None), |
105 | | wasmi::ExternType::Global(_) | wasmi::ExternType::Table(_) => { |
106 | 1 | return Err(NewErr::ImportTypeNotSupported) |
107 | | } |
108 | | } |
109 | | } |
110 | | |
111 | 122 | Self::from_base_components(BaseComponents { |
112 | 122 | module: Arc::new(module), |
113 | 122 | resolved_imports, |
114 | 122 | }) |
115 | 141 | } _RNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype3new Line | Count | Source | 55 | 78 | pub fn new( | 56 | 78 | module_bytes: &[u8], | 57 | 78 | compilation_mode: CompilationMode, | 58 | 78 | symbols: &mut dyn FnMut(&str, &str, &Signature) -> Result<usize, ()>, | 59 | 78 | ) -> Result<Self, NewErr> { | 60 | 78 | let engine = { | 61 | 78 | let mut config = wasmi::Config::default(); | 62 | 78 | | 63 | 78 | // Disable all the post-MVP wasm features. | 64 | 78 | config.wasm_sign_extension(false); | 65 | 78 | config.wasm_reference_types(false); | 66 | 78 | config.wasm_bulk_memory(false); | 67 | 78 | config.wasm_multi_value(false); | 68 | 78 | config.wasm_extended_const(false); | 69 | 78 | config.wasm_mutable_global(false); | 70 | 78 | config.wasm_saturating_float_to_int(false); | 71 | 78 | config.wasm_tail_call(false); | 72 | 78 | config.compilation_mode(compilation_mode); | 73 | 78 | | 74 | 78 | wasmi::Engine::new(&config) | 75 | | }; | 76 | | | 77 | 78 | let module65 = wasmi::Module::new(&engine, module_bytes) | 78 | 78 | .map_err(|err| NewErr::InvalidWasm(err.to_string()))?13 ; | 79 | | | 80 | 65 | let mut resolved_imports = Vec::with_capacity(module.imports().len()); | 81 | 450 | for import in module.imports()65 { | 82 | 450 | match import.ty() { | 83 | 411 | wasmi::ExternType::Func(func_type) => { | 84 | 406 | // Note that if `Signature::try_from` fails, a `UnresolvedFunctionImport` is | 85 | 406 | // also returned. This is because it is not possible for the function to | 86 | 406 | // resolve anyway if its signature can't be represented. | 87 | 406 | let function_index = | 88 | 411 | match Signature::try_from(func_type) | 89 | 411 | .ok() | 90 | 411 | .and_then(|conv_signature| { | 91 | | symbols(import.module(), import.name(), &conv_signature).ok() | 92 | 411 | }) { | 93 | 406 | Some(i) => i, | 94 | | None => { | 95 | 5 | return Err(NewErr::UnresolvedFunctionImport { | 96 | 5 | module_name: import.module().to_owned(), | 97 | 5 | function: import.name().to_owned(), | 98 | 5 | }) | 99 | | } | 100 | | }; | 101 | | | 102 | 406 | resolved_imports.push(Some(function_index)); | 103 | | } | 104 | 38 | wasmi::ExternType::Memory(_) => resolved_imports.push(None), | 105 | | wasmi::ExternType::Global(_) | wasmi::ExternType::Table(_) => { | 106 | 1 | return Err(NewErr::ImportTypeNotSupported) | 107 | | } | 108 | | } | 109 | | } | 110 | | | 111 | 59 | Self::from_base_components(BaseComponents { | 112 | 59 | module: Arc::new(module), | 113 | 59 | resolved_imports, | 114 | 59 | }) | 115 | 78 | } |
_RNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype3new Line | Count | Source | 55 | 63 | pub fn new( | 56 | 63 | module_bytes: &[u8], | 57 | 63 | compilation_mode: CompilationMode, | 58 | 63 | symbols: &mut dyn FnMut(&str, &str, &Signature) -> Result<usize, ()>, | 59 | 63 | ) -> Result<Self, NewErr> { | 60 | 63 | let engine = { | 61 | 63 | let mut config = wasmi::Config::default(); | 62 | 63 | | 63 | 63 | // Disable all the post-MVP wasm features. | 64 | 63 | config.wasm_sign_extension(false); | 65 | 63 | config.wasm_reference_types(false); | 66 | 63 | config.wasm_bulk_memory(false); | 67 | 63 | config.wasm_multi_value(false); | 68 | 63 | config.wasm_extended_const(false); | 69 | 63 | config.wasm_mutable_global(false); | 70 | 63 | config.wasm_saturating_float_to_int(false); | 71 | 63 | config.wasm_tail_call(false); | 72 | 63 | config.compilation_mode(compilation_mode); | 73 | 63 | | 74 | 63 | wasmi::Engine::new(&config) | 75 | | }; | 76 | | | 77 | 63 | let module = wasmi::Module::new(&engine, module_bytes) | 78 | 63 | .map_err(|err| NewErr::InvalidWasm(err.to_string()))?0 ; | 79 | | | 80 | 63 | let mut resolved_imports = Vec::with_capacity(module.imports().len()); | 81 | 1.89k | for import in module.imports()63 { | 82 | 1.89k | match import.ty() { | 83 | 1.82k | wasmi::ExternType::Func(func_type) => { | 84 | 1.82k | // Note that if `Signature::try_from` fails, a `UnresolvedFunctionImport` is | 85 | 1.82k | // also returned. This is because it is not possible for the function to | 86 | 1.82k | // resolve anyway if its signature can't be represented. | 87 | 1.82k | let function_index = | 88 | 1.82k | match Signature::try_from(func_type) | 89 | 1.82k | .ok() | 90 | 1.82k | .and_then(|conv_signature| { | 91 | | symbols(import.module(), import.name(), &conv_signature).ok() | 92 | 1.82k | }) { | 93 | 1.82k | Some(i) => i, | 94 | | None => { | 95 | 0 | return Err(NewErr::UnresolvedFunctionImport { | 96 | 0 | module_name: import.module().to_owned(), | 97 | 0 | function: import.name().to_owned(), | 98 | 0 | }) | 99 | | } | 100 | | }; | 101 | | | 102 | 1.82k | resolved_imports.push(Some(function_index)); | 103 | | } | 104 | 63 | wasmi::ExternType::Memory(_) => resolved_imports.push(None), | 105 | | wasmi::ExternType::Global(_) | wasmi::ExternType::Table(_) => { | 106 | 0 | return Err(NewErr::ImportTypeNotSupported) | 107 | | } | 108 | | } | 109 | | } | 110 | | | 111 | 63 | Self::from_base_components(BaseComponents { | 112 | 63 | module: Arc::new(module), | 113 | 63 | resolved_imports, | 114 | 63 | }) | 115 | 63 | } |
|
116 | | |
117 | 263 | fn from_base_components(base_components: BaseComponents) -> Result<Self, NewErr> { |
118 | 263 | let mut store = wasmi::Store::new(base_components.module.engine(), ()); |
119 | 263 | |
120 | 263 | let mut linker = wasmi::Linker::<()>::new(base_components.module.engine()); |
121 | 263 | let mut import_memory = None; |
122 | | |
123 | 6.55k | for (module_import, resolved_function) in base_components |
124 | 263 | .module |
125 | 263 | .imports() |
126 | 263 | .zip(base_components.resolved_imports.iter()) |
127 | | { |
128 | 6.55k | match module_import.ty() { |
129 | 6.32k | wasmi::ExternType::Func(func_type) => { |
130 | 6.32k | let function_index = resolved_function.unwrap(); |
131 | 6.32k | |
132 | 6.32k | let func = wasmi::Func::new( |
133 | 6.32k | &mut store, |
134 | 6.32k | func_type.clone(), |
135 | 30.0k | move |_caller, parameters, _ret| { |
136 | 30.0k | Err(wasmi::Error::host(InterruptedTrap { |
137 | 30.0k | function_index, |
138 | 30.0k | parameters: parameters |
139 | 30.0k | .iter() |
140 | 30.3k | .map(|v| WasmValue::try_from(v).unwrap()) _RNCNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB6_20InterpreterPrototype20from_base_components00Bc_ Line | Count | Source | 140 | 29.5k | .map(|v| WasmValue::try_from(v).unwrap()) |
_RNCNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB6_20InterpreterPrototype20from_base_components00Bc_ Line | Count | Source | 140 | 798 | .map(|v| WasmValue::try_from(v).unwrap()) |
|
141 | 30.0k | .collect(), |
142 | 30.0k | })) |
143 | 30.0k | }, _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_components0Ba_ Line | Count | Source | 135 | 29.1k | move |_caller, parameters, _ret| { | 136 | 29.1k | Err(wasmi::Error::host(InterruptedTrap { | 137 | 29.1k | function_index, | 138 | 29.1k | parameters: parameters | 139 | 29.1k | .iter() | 140 | 29.1k | .map(|v| WasmValue::try_from(v).unwrap()) | 141 | 29.1k | .collect(), | 142 | 29.1k | })) | 143 | 29.1k | }, |
_RNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_components0Ba_ Line | Count | Source | 135 | 924 | move |_caller, parameters, _ret| { | 136 | 924 | Err(wasmi::Error::host(InterruptedTrap { | 137 | 924 | function_index, | 138 | 924 | parameters: parameters | 139 | 924 | .iter() | 140 | 924 | .map(|v| WasmValue::try_from(v).unwrap()) | 141 | 924 | .collect(), | 142 | 924 | })) | 143 | 924 | }, |
|
144 | 6.32k | ); |
145 | 6.32k | |
146 | 6.32k | // `define` returns an error in case of duplicate definition. Since we |
147 | 6.32k | // enumerate over the imports, this can't happen. |
148 | 6.32k | linker |
149 | 6.32k | .define(module_import.module(), module_import.name(), func) |
150 | 6.32k | .unwrap(); |
151 | 6.32k | } |
152 | 237 | wasmi::ExternType::Memory(memory_type) => { |
153 | 237 | if module_import.module() != "env" || module_import.name() != "memory" { |
154 | 1 | return Err(NewErr::MemoryNotNamedMemory); |
155 | 236 | } |
156 | 236 | |
157 | 236 | // Considering that the memory can only be "env":"memory", and that each |
158 | 236 | // import has a unique name, this block can't be reached more than once. |
159 | 236 | debug_assert!(import_memory.is_none()); |
160 | | |
161 | 236 | let memory = wasmi::Memory::new(&mut store, *memory_type) |
162 | 236 | .map_err(|_| NewErr::CouldntAllocateMemory0 )?0 ; Unexecuted instantiation: _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_componentss_0Ba_ Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_componentss_0Ba_ |
163 | 236 | import_memory = Some(memory); |
164 | 236 | |
165 | 236 | // `define` returns an error in case of duplicate definition. Since we |
166 | 236 | // enumerate over the imports, this can't happen. |
167 | 236 | linker |
168 | 236 | .define(module_import.module(), module_import.name(), memory) |
169 | 236 | .unwrap(); |
170 | | } |
171 | | wasmi::ExternType::Global(_) | wasmi::ExternType::Table(_) => { |
172 | 0 | unreachable!() |
173 | | } |
174 | | } |
175 | | } |
176 | | |
177 | 262 | let instance259 = linker |
178 | 262 | .instantiate(&mut store, &base_components.module) |
179 | 262 | .map_err(|err| NewErr::Instantiation(err.to_string())1 )?1 _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_componentss0_0Ba_ Line | Count | Source | 179 | 1 | .map_err(|err| NewErr::Instantiation(err.to_string()))? |
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_componentss0_0Ba_ |
180 | 261 | .ensure_no_start(&mut store) |
181 | 261 | .map_err(|_| NewErr::StartFunctionNotSupported2 )?2 ; _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_componentss1_0Ba_ Line | Count | Source | 181 | 2 | .map_err(|_| NewErr::StartFunctionNotSupported)?; |
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype20from_base_componentss1_0Ba_ |
182 | | |
183 | 259 | let exported_memory258 = match instance.get_export(&store, "memory") { |
184 | 22 | Some(wasmi::Extern::Memory(m)) => Some(m), |
185 | 236 | None => None, |
186 | 1 | Some(_) => return Err(NewErr::MemoryIsntMemory), |
187 | | }; |
188 | | |
189 | 257 | let memory = if let Some(wasmi::Extern::Memory(import_memory235 )) = |
190 | 258 | linker.get(&store, "env", "memory") |
191 | | { |
192 | 235 | if exported_memory.is_some() { |
193 | 0 | return Err(NewErr::TwoMemories); |
194 | 235 | } |
195 | 235 | |
196 | 235 | import_memory |
197 | 23 | } else if let Some(mem22 ) = exported_memory { |
198 | 22 | mem |
199 | | } else { |
200 | 1 | return Err(NewErr::NoMemory); |
201 | | }; |
202 | | |
203 | 257 | Ok(InterpreterPrototype { |
204 | 257 | base_components, |
205 | 257 | store, |
206 | 257 | instance, |
207 | 257 | memory, |
208 | 257 | }) |
209 | 263 | } _RNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype20from_base_components Line | Count | Source | 117 | 74 | fn from_base_components(base_components: BaseComponents) -> Result<Self, NewErr> { | 118 | 74 | let mut store = wasmi::Store::new(base_components.module.engine(), ()); | 119 | 74 | | 120 | 74 | let mut linker = wasmi::Linker::<()>::new(base_components.module.engine()); | 121 | 74 | let mut import_memory = None; | 122 | | | 123 | 887 | for (module_import, resolved_function) in base_components | 124 | 74 | .module | 125 | 74 | .imports() | 126 | 74 | .zip(base_components.resolved_imports.iter()) | 127 | | { | 128 | 887 | match module_import.ty() { | 129 | 839 | wasmi::ExternType::Func(func_type) => { | 130 | 839 | let function_index = resolved_function.unwrap(); | 131 | 839 | | 132 | 839 | let func = wasmi::Func::new( | 133 | 839 | &mut store, | 134 | 839 | func_type.clone(), | 135 | 839 | move |_caller, parameters, _ret| { | 136 | | Err(wasmi::Error::host(InterruptedTrap { | 137 | | function_index, | 138 | | parameters: parameters | 139 | | .iter() | 140 | | .map(|v| WasmValue::try_from(v).unwrap()) | 141 | | .collect(), | 142 | | })) | 143 | 839 | }, | 144 | 839 | ); | 145 | 839 | | 146 | 839 | // `define` returns an error in case of duplicate definition. Since we | 147 | 839 | // enumerate over the imports, this can't happen. | 148 | 839 | linker | 149 | 839 | .define(module_import.module(), module_import.name(), func) | 150 | 839 | .unwrap(); | 151 | 839 | } | 152 | 48 | wasmi::ExternType::Memory(memory_type) => { | 153 | 48 | if module_import.module() != "env" || module_import.name() != "memory" { | 154 | 1 | return Err(NewErr::MemoryNotNamedMemory); | 155 | 47 | } | 156 | 47 | | 157 | 47 | // Considering that the memory can only be "env":"memory", and that each | 158 | 47 | // import has a unique name, this block can't be reached more than once. | 159 | 47 | debug_assert!(import_memory.is_none()); | 160 | | | 161 | 47 | let memory = wasmi::Memory::new(&mut store, *memory_type) | 162 | 47 | .map_err(|_| NewErr::CouldntAllocateMemory)?0 ; | 163 | 47 | import_memory = Some(memory); | 164 | 47 | | 165 | 47 | // `define` returns an error in case of duplicate definition. Since we | 166 | 47 | // enumerate over the imports, this can't happen. | 167 | 47 | linker | 168 | 47 | .define(module_import.module(), module_import.name(), memory) | 169 | 47 | .unwrap(); | 170 | | } | 171 | | wasmi::ExternType::Global(_) | wasmi::ExternType::Table(_) => { | 172 | 0 | unreachable!() | 173 | | } | 174 | | } | 175 | | } | 176 | | | 177 | 73 | let instance70 = linker | 178 | 73 | .instantiate(&mut store, &base_components.module) | 179 | 73 | .map_err(|err| NewErr::Instantiation(err.to_string()))?1 | 180 | 72 | .ensure_no_start(&mut store) | 181 | 72 | .map_err(|_| NewErr::StartFunctionNotSupported)?2 ; | 182 | | | 183 | 70 | let exported_memory69 = match instance.get_export(&store, "memory") { | 184 | 22 | Some(wasmi::Extern::Memory(m)) => Some(m), | 185 | 47 | None => None, | 186 | 1 | Some(_) => return Err(NewErr::MemoryIsntMemory), | 187 | | }; | 188 | | | 189 | 68 | let memory = if let Some(wasmi::Extern::Memory(import_memory46 )) = | 190 | 69 | linker.get(&store, "env", "memory") | 191 | | { | 192 | 46 | if exported_memory.is_some() { | 193 | 0 | return Err(NewErr::TwoMemories); | 194 | 46 | } | 195 | 46 | | 196 | 46 | import_memory | 197 | 23 | } else if let Some(mem22 ) = exported_memory { | 198 | 22 | mem | 199 | | } else { | 200 | 1 | return Err(NewErr::NoMemory); | 201 | | }; | 202 | | | 203 | 68 | Ok(InterpreterPrototype { | 204 | 68 | base_components, | 205 | 68 | store, | 206 | 68 | instance, | 207 | 68 | memory, | 208 | 68 | }) | 209 | 74 | } |
_RNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype20from_base_components Line | Count | Source | 117 | 189 | fn from_base_components(base_components: BaseComponents) -> Result<Self, NewErr> { | 118 | 189 | let mut store = wasmi::Store::new(base_components.module.engine(), ()); | 119 | 189 | | 120 | 189 | let mut linker = wasmi::Linker::<()>::new(base_components.module.engine()); | 121 | 189 | let mut import_memory = None; | 122 | | | 123 | 5.67k | for (module_import, resolved_function) in base_components | 124 | 189 | .module | 125 | 189 | .imports() | 126 | 189 | .zip(base_components.resolved_imports.iter()) | 127 | | { | 128 | 5.67k | match module_import.ty() { | 129 | 5.48k | wasmi::ExternType::Func(func_type) => { | 130 | 5.48k | let function_index = resolved_function.unwrap(); | 131 | 5.48k | | 132 | 5.48k | let func = wasmi::Func::new( | 133 | 5.48k | &mut store, | 134 | 5.48k | func_type.clone(), | 135 | 5.48k | move |_caller, parameters, _ret| { | 136 | | Err(wasmi::Error::host(InterruptedTrap { | 137 | | function_index, | 138 | | parameters: parameters | 139 | | .iter() | 140 | | .map(|v| WasmValue::try_from(v).unwrap()) | 141 | | .collect(), | 142 | | })) | 143 | 5.48k | }, | 144 | 5.48k | ); | 145 | 5.48k | | 146 | 5.48k | // `define` returns an error in case of duplicate definition. Since we | 147 | 5.48k | // enumerate over the imports, this can't happen. | 148 | 5.48k | linker | 149 | 5.48k | .define(module_import.module(), module_import.name(), func) | 150 | 5.48k | .unwrap(); | 151 | 5.48k | } | 152 | 189 | wasmi::ExternType::Memory(memory_type) => { | 153 | 189 | if module_import.module() != "env" || module_import.name() != "memory" { | 154 | 0 | return Err(NewErr::MemoryNotNamedMemory); | 155 | 189 | } | 156 | 189 | | 157 | 189 | // Considering that the memory can only be "env":"memory", and that each | 158 | 189 | // import has a unique name, this block can't be reached more than once. | 159 | 189 | debug_assert!(import_memory.is_none()); | 160 | | | 161 | 189 | let memory = wasmi::Memory::new(&mut store, *memory_type) | 162 | 189 | .map_err(|_| NewErr::CouldntAllocateMemory)?0 ; | 163 | 189 | import_memory = Some(memory); | 164 | 189 | | 165 | 189 | // `define` returns an error in case of duplicate definition. Since we | 166 | 189 | // enumerate over the imports, this can't happen. | 167 | 189 | linker | 168 | 189 | .define(module_import.module(), module_import.name(), memory) | 169 | 189 | .unwrap(); | 170 | | } | 171 | | wasmi::ExternType::Global(_) | wasmi::ExternType::Table(_) => { | 172 | 0 | unreachable!() | 173 | | } | 174 | | } | 175 | | } | 176 | | | 177 | 189 | let instance = linker | 178 | 189 | .instantiate(&mut store, &base_components.module) | 179 | 189 | .map_err(|err| NewErr::Instantiation(err.to_string()))?0 | 180 | 189 | .ensure_no_start(&mut store) | 181 | 189 | .map_err(|_| NewErr::StartFunctionNotSupported)?0 ; | 182 | | | 183 | 189 | let exported_memory = match instance.get_export(&store, "memory") { | 184 | 0 | Some(wasmi::Extern::Memory(m)) => Some(m), | 185 | 189 | None => None, | 186 | 0 | Some(_) => return Err(NewErr::MemoryIsntMemory), | 187 | | }; | 188 | | | 189 | 189 | let memory = if let Some(wasmi::Extern::Memory(import_memory)) = | 190 | 189 | linker.get(&store, "env", "memory") | 191 | | { | 192 | 189 | if exported_memory.is_some() { | 193 | 0 | return Err(NewErr::TwoMemories); | 194 | 189 | } | 195 | 189 | | 196 | 189 | import_memory | 197 | 0 | } else if let Some(mem) = exported_memory { | 198 | 0 | mem | 199 | | } else { | 200 | 0 | return Err(NewErr::NoMemory); | 201 | | }; | 202 | | | 203 | 189 | Ok(InterpreterPrototype { | 204 | 189 | base_components, | 205 | 189 | store, | 206 | 189 | instance, | 207 | 189 | memory, | 208 | 189 | }) | 209 | 189 | } |
|
210 | | |
211 | | /// See [`super::VirtualMachinePrototype::global_value`]. |
212 | 100 | pub fn global_value(&self, name: &str) -> Result<u32, GlobalValueErr> { |
213 | 100 | let value97 = self |
214 | 100 | .instance |
215 | 100 | .get_global(&self.store, name) |
216 | 100 | .ok_or(GlobalValueErr::NotFound)?3 |
217 | 97 | .get(&self.store); |
218 | 97 | |
219 | 97 | match value { |
220 | 96 | wasmi::Val::I32(v) => Ok(u32::from_ne_bytes(v.to_ne_bytes())), |
221 | 1 | _ => Err(GlobalValueErr::Invalid), |
222 | | } |
223 | 100 | } _RNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype12global_value Line | Count | Source | 212 | 37 | pub fn global_value(&self, name: &str) -> Result<u32, GlobalValueErr> { | 213 | 37 | let value34 = self | 214 | 37 | .instance | 215 | 37 | .get_global(&self.store, name) | 216 | 37 | .ok_or(GlobalValueErr::NotFound)?3 | 217 | 34 | .get(&self.store); | 218 | 34 | | 219 | 34 | match value { | 220 | 33 | wasmi::Val::I32(v) => Ok(u32::from_ne_bytes(v.to_ne_bytes())), | 221 | 1 | _ => Err(GlobalValueErr::Invalid), | 222 | | } | 223 | 37 | } |
_RNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype12global_value Line | Count | Source | 212 | 63 | pub fn global_value(&self, name: &str) -> Result<u32, GlobalValueErr> { | 213 | 63 | let value = self | 214 | 63 | .instance | 215 | 63 | .get_global(&self.store, name) | 216 | 63 | .ok_or(GlobalValueErr::NotFound)?0 | 217 | 63 | .get(&self.store); | 218 | 63 | | 219 | 63 | match value { | 220 | 63 | wasmi::Val::I32(v) => Ok(u32::from_ne_bytes(v.to_ne_bytes())), | 221 | 0 | _ => Err(GlobalValueErr::Invalid), | 222 | | } | 223 | 63 | } |
|
224 | | |
225 | | /// See [`super::VirtualMachinePrototype::memory_max_pages`]. |
226 | 95 | pub fn memory_max_pages(&self) -> Option<HeapPages> { |
227 | 95 | self.memory |
228 | 95 | .ty(&self.store) |
229 | 95 | .maximum_pages() |
230 | 95 | .map(|p| HeapPages(u32::from(p))2 ) _RNCNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype16memory_max_pages0Ba_ Line | Count | Source | 230 | 2 | .map(|p| HeapPages(u32::from(p))) |
Unexecuted instantiation: _RNCNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototype16memory_max_pages0Ba_ |
231 | 95 | } _RNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype16memory_max_pages Line | Count | Source | 226 | 32 | pub fn memory_max_pages(&self) -> Option<HeapPages> { | 227 | 32 | self.memory | 228 | 32 | .ty(&self.store) | 229 | 32 | .maximum_pages() | 230 | 32 | .map(|p| HeapPages(u32::from(p))) | 231 | 32 | } |
_RNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype16memory_max_pages Line | Count | Source | 226 | 63 | pub fn memory_max_pages(&self) -> Option<HeapPages> { | 227 | 63 | self.memory | 228 | 63 | .ty(&self.store) | 229 | 63 | .maximum_pages() | 230 | 63 | .map(|p| HeapPages(u32::from(p))) | 231 | 63 | } |
|
232 | | |
233 | | /// See [`super::VirtualMachinePrototype::prepare`]. |
234 | 174 | pub fn prepare(self) -> Prepare { |
235 | 174 | Prepare { inner: self } |
236 | 174 | } _RNvMNtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype7prepare Line | Count | Source | 234 | 48 | pub fn prepare(self) -> Prepare { | 235 | 48 | Prepare { inner: self } | 236 | 48 | } |
_RNvMNtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB2_20InterpreterPrototype7prepare Line | Count | Source | 234 | 126 | pub fn prepare(self) -> Prepare { | 235 | 126 | Prepare { inner: self } | 236 | 126 | } |
|
237 | | } |
238 | | |
239 | | impl Clone for InterpreterPrototype { |
240 | 0 | fn clone(&self) -> Self { |
241 | 0 | // `from_base_components` is deterministic: either it errors all the time or it never |
242 | 0 | // errors. Since we've called it before and it didn't error, we know that it will also |
243 | 0 | // not error. |
244 | 0 | // The only exception is `NewErr::CouldntAllocateMemory`, but lack of memory is always an |
245 | 0 | // acceptable reason to panic. |
246 | 0 | InterpreterPrototype::from_base_components(BaseComponents { |
247 | 0 | module: self.base_components.module.clone(), |
248 | 0 | resolved_imports: self.base_components.resolved_imports.clone(), |
249 | 0 | }) |
250 | 0 | .unwrap() |
251 | 0 | } Unexecuted instantiation: _RNvXs_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototypeNtNtCsaYZPK01V26L_4core5clone5Clone5clone Unexecuted instantiation: _RNvXs_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB4_20InterpreterPrototypeNtNtCsaYZPK01V26L_4core5clone5Clone5clone |
252 | | } |
253 | | |
254 | | impl fmt::Debug for InterpreterPrototype { |
255 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
256 | 0 | f.debug_tuple("InterpreterPrototype").finish() |
257 | 0 | } Unexecuted instantiation: _RNvXs0_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_20InterpreterPrototypeNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt Unexecuted instantiation: _RNvXs0_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_20InterpreterPrototypeNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt |
258 | | } |
259 | | |
260 | | /// See [`super::Prepare`]. |
261 | | pub struct Prepare { |
262 | | inner: InterpreterPrototype, |
263 | | } |
264 | | |
265 | | impl Prepare { |
266 | | /// See [`super::Prepare::into_prototype`]. |
267 | 1 | pub fn into_prototype(self) -> InterpreterPrototype { |
268 | 1 | // Since creation has succeeded in the past, there is no reason for it to fail now. |
269 | 1 | InterpreterPrototype::from_base_components(self.inner.base_components).unwrap() |
270 | 1 | } _RNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_7Prepare14into_prototype Line | Count | Source | 267 | 1 | pub fn into_prototype(self) -> InterpreterPrototype { | 268 | 1 | // Since creation has succeeded in the past, there is no reason for it to fail now. | 269 | 1 | InterpreterPrototype::from_base_components(self.inner.base_components).unwrap() | 270 | 1 | } |
Unexecuted instantiation: _RNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_7Prepare14into_prototype |
271 | | |
272 | | /// See [`super::Prepare::memory_size`]. |
273 | 316 | pub fn memory_size(&self) -> HeapPages { |
274 | 316 | HeapPages(u32::from( |
275 | 316 | self.inner.memory.current_pages(&self.inner.store), |
276 | 316 | )) |
277 | 316 | } _RNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_7Prepare11memory_size Line | Count | Source | 273 | 64 | pub fn memory_size(&self) -> HeapPages { | 274 | 64 | HeapPages(u32::from( | 275 | 64 | self.inner.memory.current_pages(&self.inner.store), | 276 | 64 | )) | 277 | 64 | } |
_RNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_7Prepare11memory_size Line | Count | Source | 273 | 252 | pub fn memory_size(&self) -> HeapPages { | 274 | 252 | HeapPages(u32::from( | 275 | 252 | self.inner.memory.current_pages(&self.inner.store), | 276 | 252 | )) | 277 | 252 | } |
|
278 | | |
279 | | /// See [`super::Prepare::read_memory`]. |
280 | 4 | pub fn read_memory( |
281 | 4 | &'_ self, |
282 | 4 | offset: u32, |
283 | 4 | size: u32, |
284 | 4 | ) -> Result<impl AsRef<[u8]> + '_, OutOfBoundsError> { |
285 | 4 | let offset = usize::try_from(offset).map_err(|_| OutOfBoundsError0 )?0 ; Unexecuted instantiation: _RNCNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_7Prepare11read_memory0Bd_ Unexecuted instantiation: _RNCNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_7Prepare11read_memory0Bd_ |
286 | | |
287 | 4 | let max = offset |
288 | 4 | .checked_add(size.try_into().map_err(|_| OutOfBoundsError0 )?0 ) Unexecuted instantiation: _RNCNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_7Prepare11read_memorys_0Bd_ Unexecuted instantiation: _RNCNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_7Prepare11read_memorys_0Bd_ |
289 | 4 | .ok_or(OutOfBoundsError)?0 ; |
290 | | |
291 | | struct AccessOffset<T> { |
292 | | access: T, |
293 | | offset: usize, |
294 | | max: usize, |
295 | | } |
296 | | |
297 | | impl<T: AsRef<[u8]>> AsRef<[u8]> for AccessOffset<T> { |
298 | 4 | fn as_ref(&self) -> &[u8] { |
299 | 4 | &self.access.as_ref()[self.offset..self.max] |
300 | 4 | } _RNvXNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB8_7Prepare11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1J_E6as_refBe_ Line | Count | Source | 298 | 4 | fn as_ref(&self) -> &[u8] { | 299 | 4 | &self.access.as_ref()[self.offset..self.max] | 300 | 4 | } |
Unexecuted instantiation: _RNvXNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB8_7Prepare11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1K_E6as_refBe_ |
301 | | } |
302 | | |
303 | 4 | let access = self.inner.memory.data(&self.inner.store); |
304 | 4 | if max > access.as_ref().len() { |
305 | 0 | return Err(OutOfBoundsError); |
306 | 4 | } |
307 | 4 | |
308 | 4 | Ok(AccessOffset { |
309 | 4 | access, |
310 | 4 | offset, |
311 | 4 | max, |
312 | 4 | }) |
313 | 4 | } _RNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_7Prepare11read_memory Line | Count | Source | 280 | 4 | pub fn read_memory( | 281 | 4 | &'_ self, | 282 | 4 | offset: u32, | 283 | 4 | size: u32, | 284 | 4 | ) -> Result<impl AsRef<[u8]> + '_, OutOfBoundsError> { | 285 | 4 | let offset = usize::try_from(offset).map_err(|_| OutOfBoundsError)?0 ; | 286 | | | 287 | 4 | let max = offset | 288 | 4 | .checked_add(size.try_into().map_err(|_| OutOfBoundsError)?0 ) | 289 | 4 | .ok_or(OutOfBoundsError)?0 ; | 290 | | | 291 | | struct AccessOffset<T> { | 292 | | access: T, | 293 | | offset: usize, | 294 | | max: usize, | 295 | | } | 296 | | | 297 | | impl<T: AsRef<[u8]>> AsRef<[u8]> for AccessOffset<T> { | 298 | | fn as_ref(&self) -> &[u8] { | 299 | | &self.access.as_ref()[self.offset..self.max] | 300 | | } | 301 | | } | 302 | | | 303 | 4 | let access = self.inner.memory.data(&self.inner.store); | 304 | 4 | if max > access.as_ref().len() { | 305 | 0 | return Err(OutOfBoundsError); | 306 | 4 | } | 307 | 4 | | 308 | 4 | Ok(AccessOffset { | 309 | 4 | access, | 310 | 4 | offset, | 311 | 4 | max, | 312 | 4 | }) | 313 | 4 | } |
Unexecuted instantiation: _RNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_7Prepare11read_memory |
314 | | |
315 | | /// See [`super::Prepare::write_memory`]. |
316 | 209 | pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> { |
317 | 209 | let memory_slice = self.inner.memory.data_mut(&mut self.inner.store); |
318 | | |
319 | 209 | let start = usize::try_from(offset).map_err(|_| OutOfBoundsError0 )?0 ; Unexecuted instantiation: _RNCNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_7Prepare12write_memory0Bd_ Unexecuted instantiation: _RNCNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_7Prepare12write_memory0Bd_ |
320 | 209 | let end = start.checked_add(value.len()).ok_or(OutOfBoundsError)?0 ; |
321 | | |
322 | 209 | if end > memory_slice.len() { |
323 | 0 | return Err(OutOfBoundsError); |
324 | 209 | } |
325 | 209 | |
326 | 209 | if !value.is_empty() { |
327 | 204 | memory_slice[start..end].copy_from_slice(value); |
328 | 204 | }5 |
329 | | |
330 | 209 | Ok(()) |
331 | 209 | } _RNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_7Prepare12write_memory Line | Count | Source | 316 | 83 | pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> { | 317 | 83 | let memory_slice = self.inner.memory.data_mut(&mut self.inner.store); | 318 | | | 319 | 83 | let start = usize::try_from(offset).map_err(|_| OutOfBoundsError)?0 ; | 320 | 83 | let end = start.checked_add(value.len()).ok_or(OutOfBoundsError)?0 ; | 321 | | | 322 | 83 | if end > memory_slice.len() { | 323 | 0 | return Err(OutOfBoundsError); | 324 | 83 | } | 325 | 83 | | 326 | 83 | if !value.is_empty() { | 327 | 78 | memory_slice[start..end].copy_from_slice(value); | 328 | 78 | }5 | 329 | | | 330 | 83 | Ok(()) | 331 | 83 | } |
_RNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_7Prepare12write_memory Line | Count | Source | 316 | 126 | pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> { | 317 | 126 | let memory_slice = self.inner.memory.data_mut(&mut self.inner.store); | 318 | | | 319 | 126 | let start = usize::try_from(offset).map_err(|_| OutOfBoundsError)?0 ; | 320 | 126 | let end = start.checked_add(value.len()).ok_or(OutOfBoundsError)?0 ; | 321 | | | 322 | 126 | if end > memory_slice.len() { | 323 | 0 | return Err(OutOfBoundsError); | 324 | 126 | } | 325 | 126 | | 326 | 126 | if !value.is_empty() { | 327 | 126 | memory_slice[start..end].copy_from_slice(value); | 328 | 126 | }0 | 329 | | | 330 | 126 | Ok(()) | 331 | 126 | } |
|
332 | | |
333 | | /// See [`super::Prepare::write_memory`]. |
334 | 165 | pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> { |
335 | 165 | self.inner |
336 | 165 | .memory |
337 | 165 | .grow( |
338 | 165 | &mut self.inner.store, |
339 | 165 | wasmi::core::Pages::new(additional.0).ok_or(OutOfBoundsError)?0 , |
340 | | ) |
341 | 165 | .map_err(|_| OutOfBoundsError0 )?0 ; Unexecuted instantiation: _RNCNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_7Prepare11grow_memory0Bd_ Unexecuted instantiation: _RNCNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_7Prepare11grow_memory0Bd_ |
342 | 165 | Ok(()) |
343 | 165 | } _RNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_7Prepare11grow_memory Line | Count | Source | 334 | 39 | pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> { | 335 | 39 | self.inner | 336 | 39 | .memory | 337 | 39 | .grow( | 338 | 39 | &mut self.inner.store, | 339 | 39 | wasmi::core::Pages::new(additional.0).ok_or(OutOfBoundsError)?0 , | 340 | | ) | 341 | 39 | .map_err(|_| OutOfBoundsError)?0 ; | 342 | 39 | Ok(()) | 343 | 39 | } |
_RNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_7Prepare11grow_memory Line | Count | Source | 334 | 126 | pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> { | 335 | 126 | self.inner | 336 | 126 | .memory | 337 | 126 | .grow( | 338 | 126 | &mut self.inner.store, | 339 | 126 | wasmi::core::Pages::new(additional.0).ok_or(OutOfBoundsError)?0 , | 340 | | ) | 341 | 126 | .map_err(|_| OutOfBoundsError)?0 ; | 342 | 126 | Ok(()) | 343 | 126 | } |
|
344 | | |
345 | | /// See [`super::Prepare::start`]. |
346 | 172 | pub fn start( |
347 | 172 | self, |
348 | 172 | function_name: &str, |
349 | 172 | params: &[WasmValue], |
350 | 172 | ) -> Result<Interpreter, (StartErr, InterpreterPrototype)> { |
351 | 172 | let func_to_call166 = match self |
352 | 172 | .inner |
353 | 172 | .instance |
354 | 172 | .get_export(&self.inner.store, function_name) |
355 | | { |
356 | 169 | Some(wasmi::Extern::Func(function)) => { |
357 | | // Try to convert the signature of the function to call, in order to make sure |
358 | | // that the type of parameters and return value are supported. |
359 | 169 | let Ok(signature168 ) = Signature::try_from(function.ty(&self.inner.store)) else { |
360 | 1 | return Err((StartErr::SignatureNotSupported, self.inner)); |
361 | | }; |
362 | | |
363 | | // Check whether the types of the parameters are correct. |
364 | | // This is necessary to do manually because for API purposes the call immediately |
365 | | //starts, while in the internal implementation it doesn't actually. |
366 | 168 | if params.len() != signature.parameters().len() { |
367 | 2 | return Err((StartErr::InvalidParameters, self.inner)); |
368 | 166 | } |
369 | 314 | for (obtained, expected) in params.iter().zip(signature.parameters())166 { |
370 | 314 | if obtained.ty() != *expected { |
371 | 0 | return Err((StartErr::InvalidParameters, self.inner)); |
372 | 314 | } |
373 | | } |
374 | | |
375 | 166 | function |
376 | | } |
377 | 1 | Some(_) => return Err((StartErr::NotAFunction, self.inner)), |
378 | 2 | None => return Err((StartErr::FunctionNotFound, self.inner)), |
379 | | }; |
380 | | |
381 | 166 | let dummy_output_value = { |
382 | 166 | let func_to_call_ty = func_to_call.ty(&self.inner.store); |
383 | 166 | let list = func_to_call_ty.results(); |
384 | 166 | // We don't support more than one return value. This is enforced by verifying the |
385 | 166 | // function signature above. |
386 | 166 | debug_assert!(list.len() <= 1); |
387 | 166 | list.first().map(|item| match *item164 { |
388 | 8 | wasmi::core::ValType::I32 => wasmi::Val::I32(0), |
389 | 156 | wasmi::core::ValType::I64 => wasmi::Val::I64(0), |
390 | 0 | wasmi::core::ValType::F32 => wasmi::Val::F32(0.0f32.into()), |
391 | 0 | wasmi::core::ValType::F64 => wasmi::Val::F64(0.0.into()), |
392 | 0 | _ => unreachable!(), |
393 | 166 | }164 ) _RNCNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_7Prepare5start0Bd_ Line | Count | Source | 387 | 38 | list.first().map(|item| match *item { | 388 | 8 | wasmi::core::ValType::I32 => wasmi::Val::I32(0), | 389 | 30 | wasmi::core::ValType::I64 => wasmi::Val::I64(0), | 390 | 0 | wasmi::core::ValType::F32 => wasmi::Val::F32(0.0f32.into()), | 391 | 0 | wasmi::core::ValType::F64 => wasmi::Val::F64(0.0.into()), | 392 | 0 | _ => unreachable!(), | 393 | 38 | }) |
_RNCNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_7Prepare5start0Bd_ Line | Count | Source | 387 | 126 | list.first().map(|item| match *item { | 388 | 0 | wasmi::core::ValType::I32 => wasmi::Val::I32(0), | 389 | 126 | wasmi::core::ValType::I64 => wasmi::Val::I64(0), | 390 | 0 | wasmi::core::ValType::F32 => wasmi::Val::F32(0.0f32.into()), | 391 | 0 | wasmi::core::ValType::F64 => wasmi::Val::F64(0.0.into()), | 392 | 0 | _ => unreachable!(), | 393 | 126 | }) |
|
394 | 166 | }; |
395 | 166 | |
396 | 166 | Ok(Interpreter { |
397 | 166 | base_components: self.inner.base_components, |
398 | 166 | store: self.inner.store, |
399 | 166 | memory: self.inner.memory, |
400 | 166 | dummy_output_value, |
401 | 166 | execution: Some(Execution::NotStarted( |
402 | 166 | func_to_call, |
403 | 166 | params |
404 | 166 | .iter() |
405 | 314 | .map(|v| wasmi::Val::from(*v)) _RNCNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_7Prepare5starts_0Bd_ Line | Count | Source | 405 | 62 | .map(|v| wasmi::Val::from(*v)) |
_RNCNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_7Prepare5starts_0Bd_ Line | Count | Source | 405 | 252 | .map(|v| wasmi::Val::from(*v)) |
|
406 | 166 | .collect::<Vec<_>>(), |
407 | 166 | )), |
408 | 166 | }) |
409 | 172 | } _RNvMs1_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_7Prepare5start Line | Count | Source | 346 | 46 | pub fn start( | 347 | 46 | self, | 348 | 46 | function_name: &str, | 349 | 46 | params: &[WasmValue], | 350 | 46 | ) -> Result<Interpreter, (StartErr, InterpreterPrototype)> { | 351 | 46 | let func_to_call40 = match self | 352 | 46 | .inner | 353 | 46 | .instance | 354 | 46 | .get_export(&self.inner.store, function_name) | 355 | | { | 356 | 43 | Some(wasmi::Extern::Func(function)) => { | 357 | | // Try to convert the signature of the function to call, in order to make sure | 358 | | // that the type of parameters and return value are supported. | 359 | 43 | let Ok(signature42 ) = Signature::try_from(function.ty(&self.inner.store)) else { | 360 | 1 | return Err((StartErr::SignatureNotSupported, self.inner)); | 361 | | }; | 362 | | | 363 | | // Check whether the types of the parameters are correct. | 364 | | // This is necessary to do manually because for API purposes the call immediately | 365 | | //starts, while in the internal implementation it doesn't actually. | 366 | 42 | if params.len() != signature.parameters().len() { | 367 | 2 | return Err((StartErr::InvalidParameters, self.inner)); | 368 | 40 | } | 369 | 62 | for (obtained, expected) in params.iter().zip(signature.parameters())40 { | 370 | 62 | if obtained.ty() != *expected { | 371 | 0 | return Err((StartErr::InvalidParameters, self.inner)); | 372 | 62 | } | 373 | | } | 374 | | | 375 | 40 | function | 376 | | } | 377 | 1 | Some(_) => return Err((StartErr::NotAFunction, self.inner)), | 378 | 2 | None => return Err((StartErr::FunctionNotFound, self.inner)), | 379 | | }; | 380 | | | 381 | 40 | let dummy_output_value = { | 382 | 40 | let func_to_call_ty = func_to_call.ty(&self.inner.store); | 383 | 40 | let list = func_to_call_ty.results(); | 384 | 40 | // We don't support more than one return value. This is enforced by verifying the | 385 | 40 | // function signature above. | 386 | 40 | debug_assert!(list.len() <= 1); | 387 | 40 | list.first().map(|item| match *item { | 388 | | wasmi::core::ValType::I32 => wasmi::Val::I32(0), | 389 | | wasmi::core::ValType::I64 => wasmi::Val::I64(0), | 390 | | wasmi::core::ValType::F32 => wasmi::Val::F32(0.0f32.into()), | 391 | | wasmi::core::ValType::F64 => wasmi::Val::F64(0.0.into()), | 392 | | _ => unreachable!(), | 393 | 40 | }) | 394 | 40 | }; | 395 | 40 | | 396 | 40 | Ok(Interpreter { | 397 | 40 | base_components: self.inner.base_components, | 398 | 40 | store: self.inner.store, | 399 | 40 | memory: self.inner.memory, | 400 | 40 | dummy_output_value, | 401 | 40 | execution: Some(Execution::NotStarted( | 402 | 40 | func_to_call, | 403 | 40 | params | 404 | 40 | .iter() | 405 | 40 | .map(|v| wasmi::Val::from(*v)) | 406 | 40 | .collect::<Vec<_>>(), | 407 | 40 | )), | 408 | 40 | }) | 409 | 46 | } |
_RNvMs1_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_7Prepare5start Line | Count | Source | 346 | 126 | pub fn start( | 347 | 126 | self, | 348 | 126 | function_name: &str, | 349 | 126 | params: &[WasmValue], | 350 | 126 | ) -> Result<Interpreter, (StartErr, InterpreterPrototype)> { | 351 | 126 | let func_to_call = match self | 352 | 126 | .inner | 353 | 126 | .instance | 354 | 126 | .get_export(&self.inner.store, function_name) | 355 | | { | 356 | 126 | Some(wasmi::Extern::Func(function)) => { | 357 | | // Try to convert the signature of the function to call, in order to make sure | 358 | | // that the type of parameters and return value are supported. | 359 | 126 | let Ok(signature) = Signature::try_from(function.ty(&self.inner.store)) else { | 360 | 0 | return Err((StartErr::SignatureNotSupported, self.inner)); | 361 | | }; | 362 | | | 363 | | // Check whether the types of the parameters are correct. | 364 | | // This is necessary to do manually because for API purposes the call immediately | 365 | | //starts, while in the internal implementation it doesn't actually. | 366 | 126 | if params.len() != signature.parameters().len() { | 367 | 0 | return Err((StartErr::InvalidParameters, self.inner)); | 368 | 126 | } | 369 | 252 | for (obtained, expected) in params.iter().zip(signature.parameters())126 { | 370 | 252 | if obtained.ty() != *expected { | 371 | 0 | return Err((StartErr::InvalidParameters, self.inner)); | 372 | 252 | } | 373 | | } | 374 | | | 375 | 126 | function | 376 | | } | 377 | 0 | Some(_) => return Err((StartErr::NotAFunction, self.inner)), | 378 | 0 | None => return Err((StartErr::FunctionNotFound, self.inner)), | 379 | | }; | 380 | | | 381 | 126 | let dummy_output_value = { | 382 | 126 | let func_to_call_ty = func_to_call.ty(&self.inner.store); | 383 | 126 | let list = func_to_call_ty.results(); | 384 | 126 | // We don't support more than one return value. This is enforced by verifying the | 385 | 126 | // function signature above. | 386 | 126 | debug_assert!(list.len() <= 1); | 387 | 126 | list.first().map(|item| match *item { | 388 | | wasmi::core::ValType::I32 => wasmi::Val::I32(0), | 389 | | wasmi::core::ValType::I64 => wasmi::Val::I64(0), | 390 | | wasmi::core::ValType::F32 => wasmi::Val::F32(0.0f32.into()), | 391 | | wasmi::core::ValType::F64 => wasmi::Val::F64(0.0.into()), | 392 | | _ => unreachable!(), | 393 | 126 | }) | 394 | 126 | }; | 395 | 126 | | 396 | 126 | Ok(Interpreter { | 397 | 126 | base_components: self.inner.base_components, | 398 | 126 | store: self.inner.store, | 399 | 126 | memory: self.inner.memory, | 400 | 126 | dummy_output_value, | 401 | 126 | execution: Some(Execution::NotStarted( | 402 | 126 | func_to_call, | 403 | 126 | params | 404 | 126 | .iter() | 405 | 126 | .map(|v| wasmi::Val::from(*v)) | 406 | 126 | .collect::<Vec<_>>(), | 407 | 126 | )), | 408 | 126 | }) | 409 | 126 | } |
|
410 | | } |
411 | | |
412 | | impl fmt::Debug for Prepare { |
413 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
414 | 0 | f.debug_tuple("Prepare").finish() |
415 | 0 | } Unexecuted instantiation: _RNvXs2_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_7PrepareNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt Unexecuted instantiation: _RNvXs2_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_7PrepareNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt |
416 | | } |
417 | | |
418 | | /// This dummy struct is meant to be converted to a `wasmi::core::Trap` and then back, similar to |
419 | | /// `std::any::Any`. |
420 | | #[derive(Debug, Clone)] |
421 | | struct InterruptedTrap { |
422 | | function_index: usize, |
423 | | parameters: Vec<WasmValue>, |
424 | | } |
425 | | |
426 | | impl fmt::Display for InterruptedTrap { |
427 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
428 | 0 | write!(f, "Interrupted") |
429 | 0 | } Unexecuted instantiation: _RNvXs3_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_15InterruptedTrapNtNtCsaYZPK01V26L_4core3fmt7Display3fmt Unexecuted instantiation: _RNvXs3_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_15InterruptedTrapNtNtCsaYZPK01V26L_4core3fmt7Display3fmt |
430 | | } |
431 | | |
432 | | impl wasmi::core::HostError for InterruptedTrap {} |
433 | | |
434 | | /// See [`super::VirtualMachine`]. |
435 | | pub struct Interpreter { |
436 | | /// Base components that can be used to recreate a prototype later if desired. |
437 | | base_components: BaseComponents, |
438 | | |
439 | | // TODO: doc |
440 | | store: wasmi::Store<()>, |
441 | | |
442 | | /// Memory of the module instantiation. |
443 | | memory: wasmi::Memory, |
444 | | |
445 | | /// Execution context of this virtual machine. This notably holds the program counter, state |
446 | | /// of the stack, and so on. |
447 | | /// |
448 | | /// This field is an `Option` because we need to be able to temporarily extract it. |
449 | | /// If `None`, the state machine is in a poisoned state and cannot run any code anymore. |
450 | | execution: Option<Execution>, |
451 | | |
452 | | /// Where the return value of the execution will be stored. |
453 | | /// While this could be regenerated every time `run` is called, it is instead kept in the |
454 | | /// `Interpreter` struct for convenience. |
455 | | dummy_output_value: Option<wasmi::Val>, |
456 | | } |
457 | | |
458 | | enum Execution { |
459 | | NotStarted(wasmi::Func, Vec<wasmi::Val>), |
460 | | Started(wasmi::ResumableInvocation), |
461 | | } |
462 | | |
463 | | impl Interpreter { |
464 | | /// See [`super::VirtualMachine::run`]. |
465 | 30.2k | pub fn run(&mut self, value: Option<WasmValue>) -> Result<ExecOutcome, RunErr> { |
466 | 30.2k | let outputs_storage_ptr = if let Some(output_storage30.2k ) = self.dummy_output_value.as_mut() { |
467 | 30.2k | &mut core::array::from_mut(output_storage)[..] |
468 | | } else { |
469 | 1 | &mut [] |
470 | | }; |
471 | | |
472 | 30.2k | let result30.2k = match self.execution.take() { |
473 | 162 | Some(Execution::NotStarted(func, params)) => { |
474 | 162 | if let Some(value1 ) = value.as_ref() { |
475 | 1 | return Err(RunErr::BadValueTy { |
476 | 1 | expected: None, |
477 | 1 | obtained: Some(value.ty()), |
478 | 1 | }); |
479 | 161 | } |
480 | 161 | |
481 | 161 | func.call_resumable(&mut self.store, ¶ms, outputs_storage_ptr) |
482 | | } |
483 | 30.0k | Some(Execution::Started(func)) => { |
484 | 30.0k | let expected = { |
485 | 30.0k | let func_type = func.host_func().ty(&self.store); |
486 | 30.0k | // We don't support functions with more than one result type. This should have |
487 | 30.0k | // been checked at initialization. |
488 | 30.0k | debug_assert!(func_type.results().len() <= 1); |
489 | 30.0k | func_type |
490 | 30.0k | .results() |
491 | 30.0k | .iter() |
492 | 30.0k | .next() |
493 | 30.0k | .map(|r| ValueType::try_from(*r).unwrap()14.9k ) _RNCNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_11Interpreter3run0Bd_ Line | Count | Source | 493 | 14.3k | .map(|r| ValueType::try_from(*r).unwrap()) |
_RNCNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_11Interpreter3run0Bd_ Line | Count | Source | 493 | 588 | .map(|r| ValueType::try_from(*r).unwrap()) |
|
494 | 30.0k | }; |
495 | 30.0k | let obtained = value.as_ref().map(|v| v.ty()14.9k ); _RNCNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_11Interpreter3runs_0Bd_ Line | Count | Source | 495 | 14.3k | let obtained = value.as_ref().map(|v| v.ty()); |
_RNCNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_11Interpreter3runs_0Bd_ Line | Count | Source | 495 | 588 | let obtained = value.as_ref().map(|v| v.ty()); |
|
496 | 30.0k | if expected != obtained { |
497 | 1 | return Err(RunErr::BadValueTy { expected, obtained }); |
498 | 30.0k | } |
499 | 30.0k | |
500 | 30.0k | let value = value.map(wasmi::Val::from); |
501 | 30.0k | let inputs = match value.as_ref() { |
502 | 14.9k | Some(v) => &core::array::from_ref(v)[..], |
503 | 15.1k | None => &[], |
504 | | }; |
505 | | |
506 | 30.0k | func.resume(&mut self.store, inputs, outputs_storage_ptr) |
507 | | } |
508 | 0 | None => return Err(RunErr::Poisoned), |
509 | | }; |
510 | | |
511 | 30.2k | match result { |
512 | | Ok(wasmi::ResumableCall::Finished) => { |
513 | | // Because we have checked the signature of the function, we know that this |
514 | | // conversion can never fail. |
515 | 157 | let return_value = self |
516 | 157 | .dummy_output_value |
517 | 157 | .clone() |
518 | 157 | .map(|r| WasmValue::try_from(r).unwrap()156 ); _RNCNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_11Interpreter3runs0_0Bd_ Line | Count | Source | 518 | 30 | .map(|r| WasmValue::try_from(r).unwrap()); |
_RNCNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_11Interpreter3runs0_0Bd_ Line | Count | Source | 518 | 126 | .map(|r| WasmValue::try_from(r).unwrap()); |
|
519 | 157 | Ok(ExecOutcome::Finished { |
520 | 157 | return_value: Ok(return_value), |
521 | 157 | }) |
522 | | } |
523 | 30.0k | Ok(wasmi::ResumableCall::Resumable(next)) => { |
524 | 30.0k | let trap = next.host_error().downcast_ref::<InterruptedTrap>().unwrap(); |
525 | 30.0k | let outcome = ExecOutcome::Interrupted { |
526 | 30.0k | id: trap.function_index, |
527 | 30.0k | params: trap.parameters.clone(), |
528 | 30.0k | }; |
529 | 30.0k | |
530 | 30.0k | self.execution = Some(Execution::Started(next)); |
531 | 30.0k | Ok(outcome) |
532 | | } |
533 | 1 | Err(err) => Ok(ExecOutcome::Finished { |
534 | 1 | return_value: Err(Trap(err.to_string())), |
535 | 1 | }), |
536 | | } |
537 | 30.2k | } _RNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_11Interpreter3run Line | Count | Source | 465 | 29.1k | pub fn run(&mut self, value: Option<WasmValue>) -> Result<ExecOutcome, RunErr> { | 466 | 29.1k | let outputs_storage_ptr = if let Some(output_storage29.1k ) = self.dummy_output_value.as_mut() { | 467 | 29.1k | &mut core::array::from_mut(output_storage)[..] | 468 | | } else { | 469 | 1 | &mut [] | 470 | | }; | 471 | | | 472 | 29.1k | let result29.1k = match self.execution.take() { | 473 | 36 | Some(Execution::NotStarted(func, params)) => { | 474 | 36 | if let Some(value1 ) = value.as_ref() { | 475 | 1 | return Err(RunErr::BadValueTy { | 476 | 1 | expected: None, | 477 | 1 | obtained: Some(value.ty()), | 478 | 1 | }); | 479 | 35 | } | 480 | 35 | | 481 | 35 | func.call_resumable(&mut self.store, ¶ms, outputs_storage_ptr) | 482 | | } | 483 | 29.1k | Some(Execution::Started(func)) => { | 484 | 29.1k | let expected = { | 485 | 29.1k | let func_type = func.host_func().ty(&self.store); | 486 | 29.1k | // We don't support functions with more than one result type. This should have | 487 | 29.1k | // been checked at initialization. | 488 | 29.1k | debug_assert!(func_type.results().len() <= 1); | 489 | 29.1k | func_type | 490 | 29.1k | .results() | 491 | 29.1k | .iter() | 492 | 29.1k | .next() | 493 | 29.1k | .map(|r| ValueType::try_from(*r).unwrap()) | 494 | 29.1k | }; | 495 | 29.1k | let obtained = value.as_ref().map(|v| v.ty()); | 496 | 29.1k | if expected != obtained { | 497 | 1 | return Err(RunErr::BadValueTy { expected, obtained }); | 498 | 29.1k | } | 499 | 29.1k | | 500 | 29.1k | let value = value.map(wasmi::Val::from); | 501 | 29.1k | let inputs = match value.as_ref() { | 502 | 14.3k | Some(v) => &core::array::from_ref(v)[..], | 503 | 14.7k | None => &[], | 504 | | }; | 505 | | | 506 | 29.1k | func.resume(&mut self.store, inputs, outputs_storage_ptr) | 507 | | } | 508 | 0 | None => return Err(RunErr::Poisoned), | 509 | | }; | 510 | | | 511 | 29.1k | match result { | 512 | | Ok(wasmi::ResumableCall::Finished) => { | 513 | | // Because we have checked the signature of the function, we know that this | 514 | | // conversion can never fail. | 515 | 31 | let return_value = self | 516 | 31 | .dummy_output_value | 517 | 31 | .clone() | 518 | 31 | .map(|r| WasmValue::try_from(r).unwrap()); | 519 | 31 | Ok(ExecOutcome::Finished { | 520 | 31 | return_value: Ok(return_value), | 521 | 31 | }) | 522 | | } | 523 | 29.1k | Ok(wasmi::ResumableCall::Resumable(next)) => { | 524 | 29.1k | let trap = next.host_error().downcast_ref::<InterruptedTrap>().unwrap(); | 525 | 29.1k | let outcome = ExecOutcome::Interrupted { | 526 | 29.1k | id: trap.function_index, | 527 | 29.1k | params: trap.parameters.clone(), | 528 | 29.1k | }; | 529 | 29.1k | | 530 | 29.1k | self.execution = Some(Execution::Started(next)); | 531 | 29.1k | Ok(outcome) | 532 | | } | 533 | 1 | Err(err) => Ok(ExecOutcome::Finished { | 534 | 1 | return_value: Err(Trap(err.to_string())), | 535 | 1 | }), | 536 | | } | 537 | 29.1k | } |
_RNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_11Interpreter3run Line | Count | Source | 465 | 1.05k | pub fn run(&mut self, value: Option<WasmValue>) -> Result<ExecOutcome, RunErr> { | 466 | 1.05k | let outputs_storage_ptr = if let Some(output_storage) = self.dummy_output_value.as_mut() { | 467 | 1.05k | &mut core::array::from_mut(output_storage)[..] | 468 | | } else { | 469 | 0 | &mut [] | 470 | | }; | 471 | | | 472 | 1.05k | let result = match self.execution.take() { | 473 | 126 | Some(Execution::NotStarted(func, params)) => { | 474 | 126 | if let Some(value0 ) = value.as_ref() { | 475 | 0 | return Err(RunErr::BadValueTy { | 476 | 0 | expected: None, | 477 | 0 | obtained: Some(value.ty()), | 478 | 0 | }); | 479 | 126 | } | 480 | 126 | | 481 | 126 | func.call_resumable(&mut self.store, ¶ms, outputs_storage_ptr) | 482 | | } | 483 | 924 | Some(Execution::Started(func)) => { | 484 | 924 | let expected = { | 485 | 924 | let func_type = func.host_func().ty(&self.store); | 486 | 924 | // We don't support functions with more than one result type. This should have | 487 | 924 | // been checked at initialization. | 488 | 924 | debug_assert!(func_type.results().len() <= 1); | 489 | 924 | func_type | 490 | 924 | .results() | 491 | 924 | .iter() | 492 | 924 | .next() | 493 | 924 | .map(|r| ValueType::try_from(*r).unwrap()) | 494 | 924 | }; | 495 | 924 | let obtained = value.as_ref().map(|v| v.ty()); | 496 | 924 | if expected != obtained { | 497 | 0 | return Err(RunErr::BadValueTy { expected, obtained }); | 498 | 924 | } | 499 | 924 | | 500 | 924 | let value = value.map(wasmi::Val::from); | 501 | 924 | let inputs = match value.as_ref() { | 502 | 588 | Some(v) => &core::array::from_ref(v)[..], | 503 | 336 | None => &[], | 504 | | }; | 505 | | | 506 | 924 | func.resume(&mut self.store, inputs, outputs_storage_ptr) | 507 | | } | 508 | 0 | None => return Err(RunErr::Poisoned), | 509 | | }; | 510 | | | 511 | 1.05k | match result { | 512 | | Ok(wasmi::ResumableCall::Finished) => { | 513 | | // Because we have checked the signature of the function, we know that this | 514 | | // conversion can never fail. | 515 | 126 | let return_value = self | 516 | 126 | .dummy_output_value | 517 | 126 | .clone() | 518 | 126 | .map(|r| WasmValue::try_from(r).unwrap()); | 519 | 126 | Ok(ExecOutcome::Finished { | 520 | 126 | return_value: Ok(return_value), | 521 | 126 | }) | 522 | | } | 523 | 924 | Ok(wasmi::ResumableCall::Resumable(next)) => { | 524 | 924 | let trap = next.host_error().downcast_ref::<InterruptedTrap>().unwrap(); | 525 | 924 | let outcome = ExecOutcome::Interrupted { | 526 | 924 | id: trap.function_index, | 527 | 924 | params: trap.parameters.clone(), | 528 | 924 | }; | 529 | 924 | | 530 | 924 | self.execution = Some(Execution::Started(next)); | 531 | 924 | Ok(outcome) | 532 | | } | 533 | 0 | Err(err) => Ok(ExecOutcome::Finished { | 534 | 0 | return_value: Err(Trap(err.to_string())), | 535 | 0 | }), | 536 | | } | 537 | 1.05k | } |
|
538 | | |
539 | | /// See [`super::VirtualMachine::memory_size`]. |
540 | 73.5k | pub fn memory_size(&self) -> HeapPages { |
541 | 73.5k | HeapPages(u32::from(self.memory.current_pages(&self.store))) |
542 | 73.5k | } _RNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_11Interpreter11memory_size Line | Count | Source | 540 | 71.5k | pub fn memory_size(&self) -> HeapPages { | 541 | 71.5k | HeapPages(u32::from(self.memory.current_pages(&self.store))) | 542 | 71.5k | } |
_RNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_11Interpreter11memory_size Line | Count | Source | 540 | 1.97k | pub fn memory_size(&self) -> HeapPages { | 541 | 1.97k | HeapPages(u32::from(self.memory.current_pages(&self.store))) | 542 | 1.97k | } |
|
543 | | |
544 | | /// See [`super::VirtualMachine::read_memory`]. |
545 | 34.1k | pub fn read_memory( |
546 | 34.1k | &'_ self, |
547 | 34.1k | offset: u32, |
548 | 34.1k | size: u32, |
549 | 34.1k | ) -> Result<impl AsRef<[u8]> + '_, OutOfBoundsError> { |
550 | 34.1k | let offset = usize::try_from(offset).map_err(|_| OutOfBoundsError0 )?0 ; Unexecuted instantiation: _RNCNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_11Interpreter11read_memory0Bd_ Unexecuted instantiation: _RNCNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_11Interpreter11read_memory0Bd_ |
551 | | |
552 | 34.1k | let max = offset |
553 | 34.1k | .checked_add(size.try_into().map_err(|_| OutOfBoundsError0 )?0 ) Unexecuted instantiation: _RNCNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_11Interpreter11read_memorys_0Bd_ Unexecuted instantiation: _RNCNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_11Interpreter11read_memorys_0Bd_ |
554 | 34.1k | .ok_or(OutOfBoundsError)?0 ; |
555 | | |
556 | | struct AccessOffset<T> { |
557 | | access: T, |
558 | | offset: usize, |
559 | | max: usize, |
560 | | } |
561 | | |
562 | | impl<T: AsRef<[u8]>> AsRef<[u8]> for AccessOffset<T> { |
563 | 34.5k | fn as_ref(&self) -> &[u8] { |
564 | 34.5k | &self.access.as_ref()[self.offset..self.max] |
565 | 34.5k | } _RNvXNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB8_11Interpreter11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1O_E6as_refBe_ Line | Count | Source | 563 | 33.6k | fn as_ref(&self) -> &[u8] { | 564 | 33.6k | &self.access.as_ref()[self.offset..self.max] | 565 | 33.6k | } |
Unexecuted instantiation: _RNvXNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB8_11Interpreter11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1P_E6as_refCsDDUKWWCHAU_18smoldot_light_wasm _RNvXNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB8_11Interpreter11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1P_E6as_refBe_ Line | Count | Source | 563 | 882 | fn as_ref(&self) -> &[u8] { | 564 | 882 | &self.access.as_ref()[self.offset..self.max] | 565 | 882 | } |
Unexecuted instantiation: _RNvXNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB8_11Interpreter11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1P_E6as_refCsiLzmwikkc22_14json_rpc_basic Unexecuted instantiation: _RNvXNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB8_11Interpreter11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1P_E6as_refCsiUjFBJteJ7x_17smoldot_full_node Unexecuted instantiation: _RNvXNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB8_11Interpreter11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1P_E6as_refCscDgN54JpMGG_6author Unexecuted instantiation: _RNvXNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB8_11Interpreter11read_memoryINtB2_12AccessOffsetRShEINtNtCsaYZPK01V26L_4core7convert5AsRefB1P_E6as_refCsibGXYHQB8Ea_25json_rpc_general_requests |
566 | | } |
567 | | |
568 | 34.1k | let access = self.memory.data(&self.store); |
569 | 34.1k | if max > access.as_ref().len() { |
570 | 0 | return Err(OutOfBoundsError); |
571 | 34.1k | } |
572 | 34.1k | |
573 | 34.1k | Ok(AccessOffset { |
574 | 34.1k | access, |
575 | 34.1k | offset, |
576 | 34.1k | max, |
577 | 34.1k | }) |
578 | 34.1k | } _RNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_11Interpreter11read_memory Line | Count | Source | 545 | 33.2k | pub fn read_memory( | 546 | 33.2k | &'_ self, | 547 | 33.2k | offset: u32, | 548 | 33.2k | size: u32, | 549 | 33.2k | ) -> Result<impl AsRef<[u8]> + '_, OutOfBoundsError> { | 550 | 33.2k | let offset = usize::try_from(offset).map_err(|_| OutOfBoundsError)?0 ; | 551 | | | 552 | 33.2k | let max = offset | 553 | 33.2k | .checked_add(size.try_into().map_err(|_| OutOfBoundsError)?0 ) | 554 | 33.2k | .ok_or(OutOfBoundsError)?0 ; | 555 | | | 556 | | struct AccessOffset<T> { | 557 | | access: T, | 558 | | offset: usize, | 559 | | max: usize, | 560 | | } | 561 | | | 562 | | impl<T: AsRef<[u8]>> AsRef<[u8]> for AccessOffset<T> { | 563 | | fn as_ref(&self) -> &[u8] { | 564 | | &self.access.as_ref()[self.offset..self.max] | 565 | | } | 566 | | } | 567 | | | 568 | 33.2k | let access = self.memory.data(&self.store); | 569 | 33.2k | if max > access.as_ref().len() { | 570 | 0 | return Err(OutOfBoundsError); | 571 | 33.2k | } | 572 | 33.2k | | 573 | 33.2k | Ok(AccessOffset { | 574 | 33.2k | access, | 575 | 33.2k | offset, | 576 | 33.2k | max, | 577 | 33.2k | }) | 578 | 33.2k | } |
_RNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_11Interpreter11read_memory Line | Count | Source | 545 | 882 | pub fn read_memory( | 546 | 882 | &'_ self, | 547 | 882 | offset: u32, | 548 | 882 | size: u32, | 549 | 882 | ) -> Result<impl AsRef<[u8]> + '_, OutOfBoundsError> { | 550 | 882 | let offset = usize::try_from(offset).map_err(|_| OutOfBoundsError)?0 ; | 551 | | | 552 | 882 | let max = offset | 553 | 882 | .checked_add(size.try_into().map_err(|_| OutOfBoundsError)?0 ) | 554 | 882 | .ok_or(OutOfBoundsError)?0 ; | 555 | | | 556 | | struct AccessOffset<T> { | 557 | | access: T, | 558 | | offset: usize, | 559 | | max: usize, | 560 | | } | 561 | | | 562 | | impl<T: AsRef<[u8]>> AsRef<[u8]> for AccessOffset<T> { | 563 | | fn as_ref(&self) -> &[u8] { | 564 | | &self.access.as_ref()[self.offset..self.max] | 565 | | } | 566 | | } | 567 | | | 568 | 882 | let access = self.memory.data(&self.store); | 569 | 882 | if max > access.as_ref().len() { | 570 | 0 | return Err(OutOfBoundsError); | 571 | 882 | } | 572 | 882 | | 573 | 882 | Ok(AccessOffset { | 574 | 882 | access, | 575 | 882 | offset, | 576 | 882 | max, | 577 | 882 | }) | 578 | 882 | } |
|
579 | | |
580 | | /// See [`super::VirtualMachine::write_memory`]. |
581 | 35.1k | pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> { |
582 | 35.1k | let memory_slice = self.memory.data_mut(&mut self.store); |
583 | | |
584 | 35.1k | let start = usize::try_from(offset).map_err(|_| OutOfBoundsError0 )?0 ; Unexecuted instantiation: _RNCNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_11Interpreter12write_memory0Bd_ Unexecuted instantiation: _RNCNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_11Interpreter12write_memory0Bd_ |
585 | 35.1k | let end = start.checked_add(value.len()).ok_or(OutOfBoundsError)?0 ; |
586 | | |
587 | 35.1k | if end > memory_slice.len() { |
588 | 0 | return Err(OutOfBoundsError); |
589 | 35.1k | } |
590 | 35.1k | |
591 | 35.1k | if !value.is_empty() { |
592 | 35.1k | memory_slice[start..end].copy_from_slice(value); |
593 | 35.1k | }1 |
594 | | |
595 | 35.1k | Ok(()) |
596 | 35.1k | } _RNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_11Interpreter12write_memory Line | Count | Source | 581 | 33.9k | pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> { | 582 | 33.9k | let memory_slice = self.memory.data_mut(&mut self.store); | 583 | | | 584 | 33.9k | let start = usize::try_from(offset).map_err(|_| OutOfBoundsError)?0 ; | 585 | 33.9k | let end = start.checked_add(value.len()).ok_or(OutOfBoundsError)?0 ; | 586 | | | 587 | 33.9k | if end > memory_slice.len() { | 588 | 0 | return Err(OutOfBoundsError); | 589 | 33.9k | } | 590 | 33.9k | | 591 | 33.9k | if !value.is_empty() { | 592 | 33.9k | memory_slice[start..end].copy_from_slice(value); | 593 | 33.9k | }1 | 594 | | | 595 | 33.9k | Ok(()) | 596 | 33.9k | } |
_RNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_11Interpreter12write_memory Line | Count | Source | 581 | 1.21k | pub fn write_memory(&mut self, offset: u32, value: &[u8]) -> Result<(), OutOfBoundsError> { | 582 | 1.21k | let memory_slice = self.memory.data_mut(&mut self.store); | 583 | | | 584 | 1.21k | let start = usize::try_from(offset).map_err(|_| OutOfBoundsError)?0 ; | 585 | 1.21k | let end = start.checked_add(value.len()).ok_or(OutOfBoundsError)?0 ; | 586 | | | 587 | 1.21k | if end > memory_slice.len() { | 588 | 0 | return Err(OutOfBoundsError); | 589 | 1.21k | } | 590 | 1.21k | | 591 | 1.21k | if !value.is_empty() { | 592 | 1.21k | memory_slice[start..end].copy_from_slice(value); | 593 | 1.21k | }0 | 594 | | | 595 | 1.21k | Ok(()) | 596 | 1.21k | } |
|
597 | | |
598 | | /// See [`super::VirtualMachine::write_memory`]. |
599 | 41 | pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> { |
600 | 41 | self.memory |
601 | 41 | .grow( |
602 | 41 | &mut self.store, |
603 | 41 | wasmi::core::Pages::new(additional.0).ok_or(OutOfBoundsError)?0 , |
604 | | ) |
605 | 41 | .map_err(|_| OutOfBoundsError2 )?2 ; _RNCNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB7_11Interpreter11grow_memory0Bd_ Line | Count | Source | 605 | 2 | .map_err(|_| OutOfBoundsError)?; |
Unexecuted instantiation: _RNCNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB7_11Interpreter11grow_memory0Bd_ |
606 | 39 | Ok(()) |
607 | 41 | } _RNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_11Interpreter11grow_memory Line | Count | Source | 599 | 41 | pub fn grow_memory(&mut self, additional: HeapPages) -> Result<(), OutOfBoundsError> { | 600 | 41 | self.memory | 601 | 41 | .grow( | 602 | 41 | &mut self.store, | 603 | 41 | wasmi::core::Pages::new(additional.0).ok_or(OutOfBoundsError)?0 , | 604 | | ) | 605 | 41 | .map_err(|_| OutOfBoundsError)?2 ; | 606 | 39 | Ok(()) | 607 | 41 | } |
Unexecuted instantiation: _RNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_11Interpreter11grow_memory |
608 | | |
609 | | /// See [`super::VirtualMachine::into_prototype`]. |
610 | 140 | pub fn into_prototype(self) -> InterpreterPrototype { |
611 | 140 | // Since creation has succeeded in the past, there is no reason for it to fail now. |
612 | 140 | InterpreterPrototype::from_base_components(self.base_components).unwrap() |
613 | 140 | } _RNvMs5_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_11Interpreter14into_prototype Line | Count | Source | 610 | 14 | pub fn into_prototype(self) -> InterpreterPrototype { | 611 | 14 | // Since creation has succeeded in the past, there is no reason for it to fail now. | 612 | 14 | InterpreterPrototype::from_base_components(self.base_components).unwrap() | 613 | 14 | } |
_RNvMs5_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_11Interpreter14into_prototype Line | Count | Source | 610 | 126 | pub fn into_prototype(self) -> InterpreterPrototype { | 611 | 126 | // Since creation has succeeded in the past, there is no reason for it to fail now. | 612 | 126 | InterpreterPrototype::from_base_components(self.base_components).unwrap() | 613 | 126 | } |
|
614 | | } |
615 | | |
616 | | // TODO: `wasmi::ResumableInvocation` doesn't implement `Sync`, see <https://github.com/paritytech/wasmi/issues/869> |
617 | | // while it's not 100% clear whether or not it should implement `Sync`, none of the `&self`-taking functions of `Interpreter` access this field, and it is thus safe to Sync-ify Interpreter |
618 | | unsafe impl Sync for Interpreter {} |
619 | | |
620 | | impl fmt::Debug for Interpreter { |
621 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
622 | 0 | f.debug_tuple("Interpreter").finish() |
623 | 0 | } Unexecuted instantiation: _RNvXs7_NtNtNtCsN16ciHI6Qf_7smoldot8executor2vm11interpreterNtB5_11InterpreterNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt Unexecuted instantiation: _RNvXs7_NtNtNtCseuYC0Zibziv_7smoldot8executor2vm11interpreterNtB5_11InterpreterNtNtCsaYZPK01V26L_4core3fmt5Debug3fmt |
624 | | } |