near_vm_types/
module.rs

1// This file contains code from external sources.
2// Attributions: https://github.com/wasmerio/wasmer/blob/2.3.0/ATTRIBUTIONS.md
3
4//! Data structure for representing WebAssembly modules in a
5//! `wasmer::Module`.
6
7use crate::entity::{EntityRef, PrimaryMap};
8use crate::{
9    CustomSectionIndex, DataIndex, ElemIndex, ExportIndex, FunctionIndex, FunctionType,
10    GlobalIndex, GlobalInit, GlobalType, ImportIndex, LocalFunctionIndex, LocalGlobalIndex,
11    LocalMemoryIndex, LocalTableIndex, MemoryIndex, MemoryType, OwnedTableInitializer,
12    SignatureIndex, TableIndex, TableType,
13};
14use indexmap::IndexMap;
15use std::collections::BTreeMap;
16use std::fmt;
17use std::sync::Arc;
18use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
19
20#[derive(Debug, Clone, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
21pub struct ModuleId {
22    id: usize,
23}
24
25impl ModuleId {
26    pub fn id(&self) -> String {
27        format!("{}", &self.id)
28    }
29}
30
31impl Default for ModuleId {
32    fn default() -> Self {
33        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
34        Self { id: NEXT_ID.fetch_add(1, SeqCst) }
35    }
36}
37
38/// The counts of imported entities in a WebAssembly module.
39#[derive(
40    Debug, Copy, Clone, Default, PartialEq, Eq, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
41)]
42pub struct ImportCounts {
43    /// Number of imported functions in the module.
44    pub functions: u32,
45
46    /// Number of imported tables in the module.
47    pub tables: u32,
48
49    /// Number of imported memories in the module.
50    pub memories: u32,
51
52    /// Number of imported globals in the module.
53    pub globals: u32,
54}
55
56impl ImportCounts {
57    fn make_local<R: EntityRef, I: EntityRef>(idx: I, imports: u32) -> Result<R, I> {
58        EntityRef::index(idx).checked_sub(imports as _).map(R::new).ok_or(idx)
59    }
60
61    /// Convert the `FunctionIndex` to a `LocalFunctionIndex`.
62    pub fn local_function_index(
63        &self,
64        idx: FunctionIndex,
65    ) -> Result<LocalFunctionIndex, FunctionIndex> {
66        Self::make_local(idx, self.functions)
67    }
68
69    /// Convert the `TableIndex` to a `LocalTableIndex`.
70    pub fn local_table_index(&self, idx: TableIndex) -> Result<LocalTableIndex, TableIndex> {
71        Self::make_local(idx, self.tables)
72    }
73
74    /// Convert the `MemoryIndex` to a `LocalMemoryIndex`.
75    pub fn local_memory_index(&self, idx: MemoryIndex) -> Result<LocalMemoryIndex, MemoryIndex> {
76        Self::make_local(idx, self.memories)
77    }
78
79    /// Convert the `GlobalIndex` to a `LocalGlobalIndex`.
80    pub fn local_global_index(&self, idx: GlobalIndex) -> Result<LocalGlobalIndex, GlobalIndex> {
81        Self::make_local(idx, self.globals)
82    }
83
84    fn make_index<R: EntityRef, I: EntityRef>(idx: I, imports: u32) -> R {
85        let imports = imports as usize;
86        R::new(idx.index() + imports)
87    }
88
89    /// Convert the `LocalFunctionIndex` to a `FunctionIndex`.
90    pub fn function_index(&self, idx: LocalFunctionIndex) -> FunctionIndex {
91        Self::make_index(idx, self.functions)
92    }
93
94    /// Convert the `LocalTableIndex` to a `TableIndex`.
95    pub fn table_index(&self, idx: LocalTableIndex) -> TableIndex {
96        Self::make_index(idx, self.tables)
97    }
98
99    /// Convert the `LocalMemoryIndex` to a `MemoryIndex`.
100    pub fn memory_index(&self, idx: LocalMemoryIndex) -> MemoryIndex {
101        Self::make_index(idx, self.memories)
102    }
103
104    /// Convert the `LocalGlobalIndex` to a `GlobalIndex`.
105    pub fn global_index(&self, idx: LocalGlobalIndex) -> GlobalIndex {
106        Self::make_index(idx, self.globals)
107    }
108}
109
110/// A translated WebAssembly module, excluding the function bodies and
111/// memory initializers.
112#[derive(Debug, Clone, Default, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
113pub struct ModuleInfo {
114    /// A unique identifier (within this process) for this module.
115    ///
116    /// We skip serialization/deserialization of this field, as it
117    /// should be computed by the process.
118    #[rkyv(with = rkyv::with::Skip)]
119    pub id: ModuleId,
120
121    /// The name of this wasm module, often found in the wasm file.
122    pub name: Option<String>,
123
124    /// Imported entities with the (module, field, index_of_the_import)
125    ///
126    /// Keeping the `index_of_the_import` is important, as there can be
127    /// two same references to the same import, and we don't want to confuse
128    /// them.
129    pub imports: IndexMap<(String, String, u32), ImportIndex>,
130
131    /// Exported entities.
132    pub exports: IndexMap<String, ExportIndex>,
133
134    /// The module "start" function, if present.
135    pub start_function: Option<FunctionIndex>,
136
137    /// WebAssembly table initializers.
138    pub table_initializers: Vec<OwnedTableInitializer>,
139
140    /// WebAssembly passive elements.
141    pub passive_elements: BTreeMap<ElemIndex, Box<[FunctionIndex]>>,
142
143    /// WebAssembly passive data segments.
144    pub passive_data: BTreeMap<DataIndex, Arc<[u8]>>,
145
146    /// WebAssembly global initializers.
147    pub global_initializers: PrimaryMap<LocalGlobalIndex, GlobalInit>,
148
149    /// WebAssembly function names.
150    pub function_names: BTreeMap<FunctionIndex, String>,
151
152    /// WebAssembly function signatures.
153    pub signatures: PrimaryMap<SignatureIndex, FunctionType>,
154
155    /// WebAssembly functions (imported and local).
156    pub functions: PrimaryMap<FunctionIndex, SignatureIndex>,
157
158    /// WebAssembly tables (imported and local).
159    pub tables: PrimaryMap<TableIndex, TableType>,
160
161    /// WebAssembly linear memories (imported and local).
162    pub memories: PrimaryMap<MemoryIndex, MemoryType>,
163
164    /// WebAssembly global variables (imported and local).
165    pub globals: PrimaryMap<GlobalIndex, GlobalType>,
166
167    /// Custom sections in the module.
168    pub custom_sections: IndexMap<String, CustomSectionIndex>,
169
170    /// The data for each CustomSection in the module.
171    pub custom_sections_data: PrimaryMap<CustomSectionIndex, Arc<[u8]>>,
172
173    /// The counts of imported entities.
174    pub import_counts: ImportCounts,
175}
176
177// For test serialization correctness, everything except module id should be same
178impl PartialEq for ModuleInfo {
179    fn eq(&self, other: &Self) -> bool {
180        self.name == other.name
181            && self.imports == other.imports
182            && self.exports == other.exports
183            && self.start_function == other.start_function
184            && self.table_initializers == other.table_initializers
185            && self.passive_elements == other.passive_elements
186            && self.passive_data == other.passive_data
187            && self.global_initializers == other.global_initializers
188            && self.function_names == other.function_names
189            && self.signatures == other.signatures
190            && self.functions == other.functions
191            && self.tables == other.tables
192            && self.memories == other.memories
193            && self.globals == other.globals
194            && self.custom_sections == other.custom_sections
195            && self.custom_sections_data == other.custom_sections_data
196            && self.import_counts == other.import_counts
197    }
198}
199
200impl Eq for ModuleInfo {}
201
202impl ModuleInfo {
203    /// Allocates the module data structures.
204    pub fn new() -> Self {
205        Default::default()
206    }
207
208    /// Get the given passive element, if it exists.
209    pub fn get_passive_element(&self, index: ElemIndex) -> Option<&[FunctionIndex]> {
210        self.passive_elements.get(&index).map(|es| &**es)
211    }
212
213    /// Get the exported signatures of the module
214    pub fn exported_signatures(&self) -> Vec<FunctionType> {
215        self.exports
216            .iter()
217            .filter_map(|(_name, export_index)| match export_index {
218                ExportIndex::Function(i) => {
219                    let signature = self.functions.get(*i).unwrap();
220                    let func_type = self.signatures.get(*signature).unwrap();
221                    Some(func_type.clone())
222                }
223                _ => None,
224            })
225            .collect::<Vec<FunctionType>>()
226    }
227
228    /// Get the custom sections of the module given a `name`.
229    pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Arc<[u8]>> + 'a {
230        self.custom_sections.iter().filter_map(move |(section_name, section_index)| {
231            if name != section_name {
232                return None;
233            }
234            Some(self.custom_sections_data[*section_index].clone())
235        })
236    }
237
238    /// Convert a `LocalFunctionIndex` into a `FunctionIndex`.
239    pub fn func_index(&self, local_func: LocalFunctionIndex) -> FunctionIndex {
240        self.import_counts.function_index(local_func)
241    }
242
243    /// Convert a `FunctionIndex` into a `LocalFunctionIndex`. Returns None if the
244    /// index is an imported function.
245    pub fn local_func_index(&self, func: FunctionIndex) -> Option<LocalFunctionIndex> {
246        self.import_counts.local_function_index(func).ok()
247    }
248
249    /// Test whether the given function index is for an imported function.
250    pub fn is_imported_function(&self, index: FunctionIndex) -> bool {
251        self.local_func_index(index).is_none()
252    }
253
254    /// Convert a `LocalTableIndex` into a `TableIndex`.
255    pub fn table_index(&self, local_table: LocalTableIndex) -> TableIndex {
256        self.import_counts.table_index(local_table)
257    }
258
259    /// Convert a `TableIndex` into a `LocalTableIndex`. Returns None if the
260    /// index is an imported table.
261    pub fn local_table_index(&self, table: TableIndex) -> Option<LocalTableIndex> {
262        self.import_counts.local_table_index(table).ok()
263    }
264
265    /// Test whether the given table index is for an imported table.
266    pub fn is_imported_table(&self, index: TableIndex) -> bool {
267        self.local_table_index(index).is_none()
268    }
269
270    /// Convert a `LocalMemoryIndex` into a `MemoryIndex`.
271    pub fn memory_index(&self, local_memory: LocalMemoryIndex) -> MemoryIndex {
272        self.import_counts.memory_index(local_memory)
273    }
274
275    /// Convert a `MemoryIndex` into a `LocalMemoryIndex`. Returns None if the
276    /// index is an imported memory.
277    pub fn local_memory_index(&self, memory: MemoryIndex) -> Option<LocalMemoryIndex> {
278        self.import_counts.local_memory_index(memory).ok()
279    }
280
281    /// Test whether the given memory index is for an imported memory.
282    pub fn is_imported_memory(&self, index: MemoryIndex) -> bool {
283        self.local_memory_index(index).is_none()
284    }
285
286    /// Convert a `LocalGlobalIndex` into a `GlobalIndex`.
287    pub fn global_index(&self, local_global: LocalGlobalIndex) -> GlobalIndex {
288        self.import_counts.global_index(local_global)
289    }
290
291    /// Convert a `GlobalIndex` into a `LocalGlobalIndex`. Returns None if the
292    /// index is an imported global.
293    pub fn local_global_index(&self, global: GlobalIndex) -> Option<LocalGlobalIndex> {
294        self.import_counts.local_global_index(global).ok()
295    }
296
297    /// Test whether the given global index is for an imported global.
298    pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
299        self.local_global_index(index).is_none()
300    }
301
302    /// Get the Module name
303    pub fn name(&self) -> String {
304        match self.name {
305            Some(ref name) => name.to_string(),
306            None => "<module>".to_string(),
307        }
308    }
309
310    /// Get the imported function types of the module.
311    pub fn imported_function_types<'a>(&'a self) -> impl Iterator<Item = FunctionType> + 'a {
312        self.functions
313            .values()
314            .take(self.import_counts.functions as usize)
315            .map(move |sig_index| self.signatures[*sig_index].clone())
316    }
317}
318
319impl fmt::Display for ModuleInfo {
320    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321        write!(f, "{}", self.name())
322    }
323}