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