xref: /wasmtime-44.0.1/crates/wizer/src/info.rs (revision 54826c0e)
1 use std::convert::TryFrom;
2 use 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)]
10 pub 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 
63 impl<'a> ModuleContext<'a> {
64     /// Add a new raw section to this module info during parsing.
add_raw_section(&mut self, id: u8, range: Range<usize>, full_wasm: &'a [u8])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.
push_imported_memory(&mut self, memory_type: wasmparser::MemoryType)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.
push_defined_memory(&mut self, memory_type: wasmparser::MemoryType)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.
push_imported_global(&mut self, global_type: wasmparser::GlobalType)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.
push_defined_global(&mut self, global_type: wasmparser::GlobalType)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.
push_function(&mut self, func_type: u32)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.
push_table(&mut self, table_type: wasmparser::TableType)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.
push_import(&mut self, import: wasmparser::Import<'a>)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.
push_export(&mut self, export: wasmparser::Export<'a>)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.
defined_memories_len(&self) -> usize143     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.
defined_memories( &self, ) -> impl Iterator<Item = (u32, wasmparser::MemoryType)> + '_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.
defined_globals( &self, ) -> impl Iterator<Item = (u32, wasmparser::GlobalType, Option<&str>)> + '_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.
raw_sections(&self) -> &[wasm_encoder::RawSection<'a>]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.
imports(&self) -> &[wasmparser::Import<'a>]201     pub(crate) fn imports(&self) -> &[wasmparser::Import<'a>] {
202         &self.imports
203     }
204 
205     /// Get a slice of this module's exports.
exports(&self) -> &[wasmparser::Export<'a>]206     pub(crate) fn exports(&self) -> &[wasmparser::Export<'a>] {
207         &self.exports
208     }
209 
has_wasi_initialize(&self) -> bool210     pub(crate) fn has_wasi_initialize(&self) -> bool {
211         self.exports.iter().any(|e| e.name == "_initialize")
212     }
213 }
214