wasmtime_wizer/
info.rs

1use std::convert::TryFrom;
2use std::ops::Range;
3
4/// Info that we keep track of on a per module-within-a-module-linking-bundle
5/// basis.
6///
7/// These are created during our `parse` pass and then used throughout
8/// our later passes.
9#[derive(Default)]
10pub struct ModuleContext<'a> {
11    /// The raw sections from the original Wasm input.
12    raw_sections: Vec<wasm_encoder::RawSection<'a>>,
13
14    /// Imports made by this module.
15    imports: Vec<wasmparser::Import<'a>>,
16
17    /// A map from global indices to each global's type for all defined,
18    /// imported, and aliased globals.
19    globals: Vec<wasmparser::GlobalType>,
20
21    /// The index within the global index space where defined globals (as
22    /// opposed to imported or aliased) begin.
23    ///
24    /// If this is `None`, then there are no locally defined globals.
25    defined_globals_index: Option<u32>,
26
27    /// This module's exports.
28    ///
29    /// This is used later on, in the rewrite phase, when we are inserting state
30    /// instance imports.
31    ///
32    /// Note that this does *not* include the `__wizer_thing_N` exports that
33    /// this instrumentation pass adds.
34    exports: Vec<wasmparser::Export<'a>>,
35
36    /// Maps from function index to the function's type index for all functions
37    /// defined and imported in this module.
38    functions: Vec<u32>,
39
40    /// Maps from table index to the table's type for all tables defined,
41    /// imported, and aliased in this module.
42    tables: Vec<wasmparser::TableType>,
43
44    /// Maps from memory index to the memory's type for all memories defined,
45    /// imported, and aliased in this module.
46    memories: Vec<wasmparser::MemoryType>,
47
48    /// The index within the memory index space where defined memories (as
49    /// opposed to imported or aliased) begin.
50    ///
51    /// If this is `None`, then there are no locally defined memories.
52    defined_memories_index: Option<u32>,
53
54    /// Export names of defined globals injected by the instrumentation pass.
55    ///
56    /// Note that this only tracks defined mutable globals, not all globals.
57    pub(crate) defined_global_exports: Option<Vec<(u32, String)>>,
58
59    /// Export names of defined memories injected by the instrumentation pass.
60    pub(crate) defined_memory_exports: Option<Vec<String>>,
61}
62
63impl<'a> ModuleContext<'a> {
64    /// Add a new raw section to this module info during parsing.
65    pub(crate) fn add_raw_section(&mut self, id: u8, range: Range<usize>, full_wasm: &'a [u8]) {
66        self.raw_sections.push(wasm_encoder::RawSection {
67            id,
68            data: &full_wasm[range.start..range.end],
69        })
70    }
71
72    /// Push a new imported memory into this module's memory index space.
73    pub(crate) fn push_imported_memory(&mut self, memory_type: wasmparser::MemoryType) {
74        assert!(self.defined_memories_index.is_none());
75        self.memories.push(memory_type);
76    }
77
78    /// Push a new defined memory into this module's memory index space.
79    pub(crate) fn push_defined_memory(&mut self, memory_type: wasmparser::MemoryType) {
80        if self.defined_memories_index.is_none() {
81            self.defined_memories_index = Some(u32::try_from(self.memories.len()).unwrap());
82        }
83        self.memories.push(memory_type);
84    }
85
86    /// Push a new imported global into this module's global index space.
87    pub(crate) fn push_imported_global(&mut self, global_type: wasmparser::GlobalType) {
88        assert!(self.defined_globals_index.is_none());
89        self.globals.push(global_type);
90    }
91
92    /// Push a new defined global into this module's global index space.
93    pub(crate) fn push_defined_global(&mut self, global_type: wasmparser::GlobalType) {
94        if self.defined_globals_index.is_none() {
95            self.defined_globals_index = Some(u32::try_from(self.globals.len()).unwrap());
96        }
97        self.globals.push(global_type);
98    }
99
100    /// Push a new function into this module's function index space.
101    pub(crate) fn push_function(&mut self, func_type: u32) {
102        self.functions.push(func_type);
103    }
104
105    /// Push a new table into this module's table index space.
106    pub(crate) fn push_table(&mut self, table_type: wasmparser::TableType) {
107        self.tables.push(table_type);
108    }
109
110    /// Push a new import into this module.
111    pub(crate) fn push_import(&mut self, import: wasmparser::Import<'a>) {
112        self.imports.push(import);
113
114        // Add the import to the appropriate index space for our current module.
115        match import.ty {
116            wasmparser::TypeRef::Memory(ty) => {
117                self.push_imported_memory(ty);
118            }
119            wasmparser::TypeRef::Global(ty) => {
120                self.push_imported_global(ty);
121            }
122            wasmparser::TypeRef::Func(ty_idx) => {
123                self.push_function(ty_idx);
124            }
125            wasmparser::TypeRef::Table(ty) => {
126                self.push_table(ty);
127            }
128            wasmparser::TypeRef::Tag(_) => {
129                unreachable!("exceptions are unsupported; checked in validation")
130            }
131            wasmparser::TypeRef::FuncExact(_) => {
132                unreachable!("custom-descriptors are unsupported; checked in validation")
133            }
134        }
135    }
136
137    /// Push an export into this module.
138    pub(crate) fn push_export(&mut self, export: wasmparser::Export<'a>) {
139        self.exports.push(export);
140    }
141
142    /// The number of defined memories in this module.
143    pub(crate) fn defined_memories_len(&self) -> usize {
144        self.defined_memories_index.map_or(0, |n| {
145            let n = usize::try_from(n).unwrap();
146            assert!(self.memories.len() > n);
147            self.memories.len() - n
148        })
149    }
150
151    /// Iterate over the defined memories in this module.
152    pub(crate) fn defined_memories(
153        &self,
154    ) -> impl Iterator<Item = (u32, wasmparser::MemoryType)> + '_ {
155        self.memories
156            .iter()
157            .copied()
158            .enumerate()
159            .skip(
160                self.defined_memories_index
161                    .map_or(self.memories.len(), |i| usize::try_from(i).unwrap()),
162            )
163            .map(|(i, m)| (u32::try_from(i).unwrap(), m))
164    }
165
166    /// Iterate over the defined globals in this module.
167    pub(crate) fn defined_globals(
168        &self,
169    ) -> impl Iterator<Item = (u32, wasmparser::GlobalType, Option<&str>)> + '_ {
170        let mut defined_global_exports = self
171            .defined_global_exports
172            .as_ref()
173            .map(|v| v.as_slice())
174            .unwrap_or(&[])
175            .iter()
176            .peekable();
177
178        self.globals
179            .iter()
180            .copied()
181            .enumerate()
182            .skip(
183                self.defined_globals_index
184                    .map_or(self.globals.len(), |i| usize::try_from(i).unwrap()),
185            )
186            .map(move |(i, g)| {
187                let i = u32::try_from(i).unwrap();
188                let name = defined_global_exports
189                    .next_if(|(j, _)| *j == i)
190                    .map(|(_, name)| name.as_str());
191                (i, g, name)
192            })
193    }
194
195    /// Get a slice of this module's original raw sections.
196    pub(crate) fn raw_sections(&self) -> &[wasm_encoder::RawSection<'a>] {
197        &self.raw_sections
198    }
199
200    /// Get a slice of this module's imports.
201    pub(crate) fn imports(&self) -> &[wasmparser::Import<'a>] {
202        &self.imports
203    }
204
205    /// Get a slice of this module's exports.
206    pub(crate) fn exports(&self) -> &[wasmparser::Export<'a>] {
207        &self.exports
208    }
209
210    pub(crate) fn has_wasi_initialize(&self) -> bool {
211        self.exports.iter().any(|e| e.name == "_initialize")
212    }
213}