Coverage Report

Created: 2024-05-16 12:16

/__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, &params, 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, &params, 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, &params, 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
}