From d8eedb20eadbb5a351e17ec802895627f7cd49ec Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Jan 2021 11:10:50 -0800 Subject: [PATCH 1/6] Update wasm-smith to export modules/instances If they exist, they're candidates for export! --- crates/wasm-smith/src/lib.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs index a7d40167da..078d94435f 100644 --- a/crates/wasm-smith/src/lib.rs +++ b/crates/wasm-smith/src/lib.rs @@ -1396,6 +1396,20 @@ where }); } + if self.instances.len() > 0 { + choices.push(|u, m| { + let idx = u.int_in_range(0..=m.instances.len() - 1)?; + Ok(Export::Instance(idx as u32)) + }); + } + + if self.modules.len() > 0 { + choices.push(|u, m| { + let idx = u.int_in_range(0..=m.modules.len() - 1)?; + Ok(Export::Module(idx as u32)) + }); + } + if choices.is_empty() { return Ok(()); } From d98b4f73a90c4a9a8984ee44206374268cea80e8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Jan 2021 11:11:11 -0800 Subject: [PATCH 2/6] Write out `test.wat` on fuzz failures I almost always do this anyway so it's nice to have it already done. --- fuzz/fuzz_targets/validate-valid-module.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fuzz/fuzz_targets/validate-valid-module.rs b/fuzz/fuzz_targets/validate-valid-module.rs index f1c6292e26..1767821937 100755 --- a/fuzz/fuzz_targets/validate-valid-module.rs +++ b/fuzz/fuzz_targets/validate-valid-module.rs @@ -21,7 +21,10 @@ fuzz_target!(|m: ConfiguredModule| { ..wasmparser::WasmFeatures::default() }); if let Err(e) = validator.validate_all(&bytes) { - std::fs::write("test.wasm", bytes).unwrap(); + std::fs::write("test.wasm", &bytes).unwrap(); + if let Ok(wat) = wasmprinter::print_bytes(&bytes) { + std::fs::write("test.wat", wat).unwrap(); + } panic!("Invalid module: {}", e); } }); From 8731edc9c5e40b84d4b16c99ffbab636457ad6d6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Jan 2021 11:21:26 -0800 Subject: [PATCH 3/6] Account for implicit instance imports in wasm-smith This updates the indexing of the instance index space in wasm-smith to account for the fact that imports from a two-level namespace implicitly generate an instance import. Additionally the encoding of instance arguments is updated to not have a 2-level namespace, but just a single-level namespace. --- crates/wasm-encoder/src/instances.rs | 13 +--- crates/wasm-smith/src/encode.rs | 7 ++- crates/wasm-smith/src/lib.rs | 88 ++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/crates/wasm-encoder/src/instances.rs b/crates/wasm-encoder/src/instances.rs index 12725bd8e4..a0ca142be1 100644 --- a/crates/wasm-encoder/src/instances.rs +++ b/crates/wasm-encoder/src/instances.rs @@ -42,7 +42,7 @@ impl InstanceSection { /// arguments to the instantiation. pub fn instantiate<'a, I>(&mut self, module: u32, args: I) -> &mut Self where - I: IntoIterator, Export)>, + I: IntoIterator, I::IntoIter: ExactSizeIterator, { let args = args.into_iter(); @@ -51,17 +51,8 @@ impl InstanceSection { self.bytes.extend(encoders::u32(module)); self.bytes .extend(encoders::u32(u32::try_from(args.len()).unwrap())); - for (name, field, export) in args { + for (name, export) in args { self.bytes.extend(encoders::str(name)); - match field { - Some(field) => { - self.bytes.push(0x01); - self.bytes.extend(encoders::str(field)); - } - None => { - self.bytes.push(0x00); - } - } export.encode(&mut self.bytes); } self.num_added += 1; diff --git a/crates/wasm-smith/src/encode.rs b/crates/wasm-smith/src/encode.rs index b5ddc7b8d1..299e642188 100644 --- a/crates/wasm-smith/src/encode.rs +++ b/crates/wasm-smith/src/encode.rs @@ -119,9 +119,10 @@ where for instance in list { section.instantiate( instance.module, - instance.args.iter().map(|(name, field, export)| { - (name.as_str(), field.as_deref(), translate_export(export)) - }), + instance + .args + .iter() + .map(|(name, export)| (name.as_str(), translate_export(export))), ); } module.section(§ion); diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs index 078d94435f..01817212e7 100644 --- a/crates/wasm-smith/src/lib.rs +++ b/crates/wasm-smith/src/lib.rs @@ -119,6 +119,10 @@ where /// second-level import names that have been generated so far. import_names: HashMap>>, + /// Where within the `instances` array each implicit instance's type is + /// defined. + implicit_instance_types: HashMap, + /// Indices into `initializers` which are types. The pair `(i, j)` means /// that `initializers[i]` is a type section, and we are referring to the /// `j`th type within that type section. @@ -252,7 +256,7 @@ struct FuncType { results: Vec, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] struct InstanceType { exports: indexmap::IndexMap, } @@ -260,6 +264,7 @@ struct InstanceType { #[derive(Clone, Debug)] struct ModuleType { imports: Vec<(String, Option, EntityType)>, + import_types: indexmap::IndexMap, /// The list of exports can be found in the `InstanceType` indirection here, /// and this struct layout is used to ease the instantiation process where /// we record an instance's signature. @@ -341,7 +346,7 @@ enum Alias { #[derive(Clone, Debug)] struct Instance { module: u32, - args: Vec<(String, Option, Export)>, + args: Vec<(String, Export)>, } #[derive(Copy, Clone, Debug)] @@ -814,16 +819,33 @@ where ) -> Result> { let exports = self.arbitrary_instance_type(u, entities)?; let mut imports = Vec::new(); + let mut import_types = indexmap::IndexMap::new(); let mut names = HashMap::new(); if !entities.max_reached(&self.config) { arbitrary_loop(u, 0, self.config.max_imports(), |u| { let (module, name) = unique_import_strings(1_000, &mut names, true, u)?; let ty = self.arbitrary_entity_type(u, entities)?; + if let Some(name) = &name { + let ity = import_types.entry(module.clone()).or_insert_with(|| { + EntityType::Instance(u32::max_value(), Default::default()) + }); + let ity = match ity { + EntityType::Instance(_, ty) => Rc::get_mut(ty).unwrap(), + _ => unreachable!(), + }; + ity.exports.insert(name.clone(), ty.clone()); + } else { + import_types.insert(module.clone(), ty.clone()); + } imports.push((module, name, ty)); Ok(!entities.max_reached(&self.config)) })?; } - Ok(Rc::new(ModuleType { imports, exports })) + Ok(Rc::new(ModuleType { + imports, + import_types, + exports, + })) } fn arbitrary_instance_type( @@ -983,15 +1005,36 @@ where return Ok(false); } - let (module, name) = unique_import_strings( - 1_000, - &mut self.import_names, - self.config.module_linking_enabled() || self.depth > 0, - u, - )?; + // Generate an arbitrary module/name pair to name this import. Note + // that if module-linking is enabled and `name` is present, then we + // might be implicitly generating an instance. If that's the case + // then we need to record the type of this instance. + let module_linking = self.config.module_linking_enabled() || self.depth > 0; + let (module, name) = + unique_import_strings(1_000, &mut self.import_names, module_linking, u)?; + if module_linking + && name.is_some() + && self.import_names[&module].as_ref().unwrap().len() == 1 + { + // first time this is imported, generate a new type + self.implicit_instance_types + .insert(module.clone(), self.instances.len()); + self.instances.push(Rc::new(InstanceType::default())); + } let f = u.choose(&choices)?; let ty = f(u, self)?; + if let Some(name) = &name { + if module_linking { + let idx = self.implicit_instance_types[&module]; + let instance_ty = &mut self.instances[idx]; + Rc::get_mut(instance_ty) + .unwrap() // shouldn't be aliased yet + .exports + .insert(name.clone(), ty.clone()); + } + } + self.num_imports += 1; imports.push((module, name, ty)); Ok(true) @@ -1105,9 +1148,8 @@ where args: choice .args .iter() - .map(|(name, field, candidates)| { - u.choose(candidates) - .map(|e| (name.clone(), field.clone(), e.clone())) + .map(|(name, candidates)| { + u.choose(candidates).map(|e| (name.clone(), e.clone())) }) .collect::>>()?, }); @@ -1135,7 +1177,8 @@ where // After we've generated the `module`, we create `ty` which is its // own type signature of itself. let mut imports = Vec::with_capacity(module.num_imports); - for (module, name, ty) in module + let mut import_types = indexmap::IndexMap::with_capacity(module.num_imports); + for (name, field, ty) in module .initial_sections .iter() .filter_map(|section| match section { @@ -1144,7 +1187,17 @@ where }) .flat_map(|a| a) { - imports.push((module.clone(), name.clone(), ty.clone())); + if field.is_none() { + // If the field is none then `ty` matches the import type + // exactly + import_types.insert(name.clone(), ty.clone()); + } else if import_types.get(name).is_none() { + // otherwise if we haven't already recorded the implicit + // type of `name` then we do so here + let ty = module.instances[module.implicit_instance_types[name]].clone(); + import_types.insert(name.clone(), EntityType::Instance(u32::max_value(), ty)); + } + imports.push((name.clone(), field.clone(), ty.clone())); } let mut exports = indexmap::IndexMap::with_capacity(module.exports.len()); for (name, export) in module.exports.iter() { @@ -1153,6 +1206,7 @@ where } let ty = Rc::new(ModuleType { imports, + import_types, exports: Rc::new(InstanceType { exports }), }); @@ -2061,7 +2115,7 @@ struct Instantiation { /// (global $g2 (mut i32) (i32.const 42)) /// ) /// ``` - args: Vec<(String, Option, Vec)>, + args: Vec<(String, Vec)>, } impl AvailableInstantiations { @@ -2069,7 +2123,7 @@ impl AvailableInstantiations { self.choices.clear(); 'outer: for (i, ty) in module.modules.iter().enumerate() { let mut args = Vec::new(); - for (name, field, import) in ty.imports.iter() { + for (name, import) in ty.import_types.iter() { let candidates = module.subtypes(import); // If nothing in our module up to this point can satisfy this // import then we can't instantiate this module. That means we @@ -2077,7 +2131,7 @@ impl AvailableInstantiations { if candidates.is_empty() { continue 'outer; } - args.push((name.clone(), field.clone(), candidates)); + args.push((name.clone(), candidates)); } self.choices.push(Instantiation { From 0c2796beaffc05d72944f260cf559ec7852c6548 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Jan 2021 12:13:06 -0800 Subject: [PATCH 4/6] Update wasm-smith to generate outer aliases This commit fixes a TODO tto update wasm-smith to generate modules with outer aliases for types/modules. --- crates/wasm-encoder/src/aliases.rs | 10 +- crates/wasm-smith/src/encode.rs | 8 +- crates/wasm-smith/src/lib.rs | 142 ++++++++++++++++++++--------- 3 files changed, 108 insertions(+), 52 deletions(-) diff --git a/crates/wasm-encoder/src/aliases.rs b/crates/wasm-encoder/src/aliases.rs index 4ccb8b375c..472f50d174 100644 --- a/crates/wasm-encoder/src/aliases.rs +++ b/crates/wasm-encoder/src/aliases.rs @@ -50,18 +50,20 @@ impl AliasSection { self } - /// Define an alias that references a parent's type. - pub fn parent_type(&mut self, ty: u32) -> &mut Self { + /// Define an alias that references an outer module's type. + pub fn outer_type(&mut self, depth: u32, ty: u32) -> &mut Self { self.bytes.push(0x01); + self.bytes.extend(encoders::u32(depth)); self.bytes.push(0x07); self.bytes.extend(encoders::u32(ty)); self.num_added += 1; self } - /// Define an alias that references a parent's module. - pub fn parent_module(&mut self, module: u32) -> &mut Self { + /// Define an alias that references an outer module's module. + pub fn outer_module(&mut self, depth: u32, module: u32) -> &mut Self { self.bytes.push(0x01); + self.bytes.extend(encoders::u32(depth)); self.bytes.push(ItemKind::Module as u8); self.bytes.extend(encoders::u32(module)); self.num_added += 1; diff --git a/crates/wasm-smith/src/encode.rs b/crates/wasm-smith/src/encode.rs index 299e642188..633d3c540b 100644 --- a/crates/wasm-smith/src/encode.rs +++ b/crates/wasm-smith/src/encode.rs @@ -103,11 +103,11 @@ where } => { section.instance_export(*instance, translate_item_kind(kind), name); } - Alias::ParentType(ty) => { - section.parent_type(*ty); + Alias::OuterType { depth, index } => { + section.outer_type(*depth, *index); } - Alias::ParentModule(m) => { - section.parent_module(*m); + Alias::OuterModule { depth, index } => { + section.outer_module(*depth, *index); } } } diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs index 01817212e7..9e0bd8e095 100644 --- a/crates/wasm-smith/src/lib.rs +++ b/crates/wasm-smith/src/lib.rs @@ -94,9 +94,11 @@ where C: Config, { config: C, - depth: usize, valtypes: Vec, + /// Parent modules, if any (used for module linking) + parents: Vec, + /// The initial sections of this wasm module, including types and imports. /// This is stored as a list-of-lists where each `InitialSection` represents /// a whole section, so this `initial_sections` list represents a list of @@ -126,12 +128,9 @@ where /// Indices into `initializers` which are types. The pair `(i, j)` means /// that `initializers[i]` is a type section, and we are referring to the /// `j`th type within that type section. - types: Vec<(usize, usize)>, + types: Vec, /// Indices within `types` that are function types. func_types: Vec, - /// Map from function signature to indices that have that function - /// signature. - func_map: HashMap, Vec>, /// Indices within `types` that are module types. module_types: Vec, /// Indices within `types` that are instance types. @@ -337,10 +336,14 @@ enum Alias { kind: ItemKind, name: String, }, - #[allow(dead_code)] // TODO: not constructed yet - ParentType(u32), - #[allow(dead_code)] // TODO: not constructed yet - ParentModule(u32), + OuterType { + depth: u32, + index: u32, + }, + OuterModule { + depth: u32, + index: u32, + }, } #[derive(Clone, Debug)] @@ -717,7 +720,7 @@ where choices.push(|u, m, _, _| m.arbitrary_imports(0, u)); } if self.modules.len() < self.config.max_modules() - && self.depth < self.config.max_nesting_depth() + && self.parents.len() < self.config.max_nesting_depth() { choices.push(|u, m, _, _| m.arbitrary_modules(u)); } @@ -757,23 +760,15 @@ where self.initial_sections.push(InitialSection::Type(Vec::new())); arbitrary_loop(u, min, self.config.max_types() - self.types.len(), |u| { let ty = self.arbitrary_type(u)?; - let list = match &ty { - Type::Func(f) => { - self.func_map - .entry(f.clone()) - .or_insert(Vec::new()) - .push(self.types.len() as u32); - &mut self.func_types - } - Type::Module(_) => &mut self.module_types, - Type::Instance(_) => &mut self.instance_types, - }; - list.push(self.types.len() as u32); + self.record_type(&ty); let types = match self.initial_sections.last_mut().unwrap() { InitialSection::Type(list) => list, _ => unreachable!(), }; - self.types.push((section_idx, types.len())); + self.types.push(LocalType::Defined { + section: section_idx, + nth: types.len(), + }); types.push(ty); Ok(true) })?; @@ -787,6 +782,15 @@ where Ok(()) } + fn record_type(&mut self, ty: &Type) { + let list = match &ty { + Type::Func(_) => &mut self.func_types, + Type::Module(_) => &mut self.module_types, + Type::Instance(_) => &mut self.instance_types, + }; + list.push(self.types.len() as u32); + } + fn arbitrary_type(&mut self, u: &mut Unstructured) -> Result { if !self.config.module_linking_enabled() { return Ok(Type::Func(self.arbitrary_func_type(u)?)); @@ -1009,7 +1013,7 @@ where // that if module-linking is enabled and `name` is present, then we // might be implicitly generating an instance. If that's the case // then we need to record the type of this instance. - let module_linking = self.config.module_linking_enabled() || self.depth > 0; + let module_linking = self.config.module_linking_enabled() || self.parents.len() > 0; let (module, name) = unique_import_strings(1_000, &mut self.import_names, module_linking, u)?; if module_linking @@ -1116,8 +1120,15 @@ where } } } - Alias::ParentType(_) => unimplemented!(), - Alias::ParentModule(_) => unimplemented!(), + Alias::OuterType { depth, index } => { + let ty = self.parents[*depth as usize].types[*index as usize].clone(); + self.record_type(&ty); + self.types.push(LocalType::Aliased(ty)); + } + Alias::OuterModule { depth, index } => { + let ty = self.parents[*depth as usize].modules[*index as usize].clone(); + self.modules.push(ty); + } } available.update(self); self.num_aliases += 1; @@ -1170,7 +1181,14 @@ where let mut modules = Vec::new(); arbitrary_loop(u, 0, self.config.max_modules(), |u| { let mut module = ConfiguredModule::::default(); - module.depth = self.depth + 1; + module.parents = self.parents.clone(); + let parent = Parent { + types: (0..self.types.len()) + .map(|i| self.ty(i as u32).clone()) + .collect(), + modules: self.modules.clone(), + }; + module.parents.insert(0, parent); module.config = self.config.clone(); module.build(u, false)?; @@ -1242,6 +1260,18 @@ where } } + fn ty(&self, idx: u32) -> &Type { + match &self.types[idx as usize] { + LocalType::Defined { section, nth } => { + if let InitialSection::Type(list) = &self.initial_sections[*section] { + return &list[*nth]; + } + panic!("looked up a type with the wrong index") + } + LocalType::Aliased(ty) => ty, + } + } + fn func_types<'a>(&'a self) -> impl Iterator + 'a { self.func_types .iter() @@ -1250,31 +1280,22 @@ where } fn func_type(&self, idx: u32) -> &Rc { - let (i, j) = self.types[idx as usize]; - if let InitialSection::Type(list) = &self.initial_sections[i] { - if let Type::Func(f) = &list[j] { - return f; - } + if let Type::Func(f) = self.ty(idx) { + return f; } panic!("looked up a function type with the wrong index") } fn instance_type(&self, idx: u32) -> &Rc { - let (i, j) = self.types[idx as usize]; - if let InitialSection::Type(list) = &self.initial_sections[i] { - if let Type::Instance(f) = &list[j] { - return f; - } + if let Type::Instance(f) = self.ty(idx) { + return f; } panic!("looked up an instance type with the wrong index") } fn module_type(&self, idx: u32) -> &Rc { - let (i, j) = self.types[idx as usize]; - if let InitialSection::Type(list) = &self.initial_sections[i] { - if let Type::Module(f) = &list[j] { - return f; - } + if let Type::Module(f) = self.ty(idx) { + return f; } panic!("looked up an instance type with the wrong index") } @@ -1980,6 +2001,7 @@ fn arbitrary_vec_u8(u: &mut Unstructured) -> Result> { struct AvailableAliases { aliases: Vec, instances_added: usize, + parents_processed: bool, } impl AvailableAliases { @@ -2041,6 +2063,26 @@ impl AvailableAliases { } } + // Then add in our all parent's alias candidates, if there are any + // parents. + if !self.parents_processed { + for (i, parent) in module.parents.iter().enumerate() { + for j in 0..parent.types.len() { + self.aliases.push(Alias::OuterType { + depth: i as u32, + index: j as u32, + }); + } + for j in 0..parent.modules.len() { + self.aliases.push(Alias::OuterModule { + depth: i as u32, + index: j as u32, + }); + } + } + self.parents_processed = true; + } + // And afterwards we need to discard alias candidates that create items // which, if created, would exceed our maximum limits. self.aliases.retain(|alias| match alias { @@ -2068,8 +2110,8 @@ impl AvailableAliases { kind: ItemKind::Module, .. } => module.modules.len() < module.config.max_modules(), - Alias::ParentType(_) => module.types.len() < module.config.max_types(), - Alias::ParentModule(_) => module.modules.len() < module.config.max_modules(), + Alias::OuterType { .. } => module.types.len() < module.config.max_types(), + Alias::OuterModule { .. } => module.modules.len() < module.config.max_modules(), }); } } @@ -2164,3 +2206,15 @@ impl Entities { || self.instances >= config.max_instances() } } + +#[derive(Clone, Debug)] +enum LocalType { + Defined { section: usize, nth: usize }, + Aliased(Type), +} + +#[derive(Debug, Clone)] +struct Parent { + types: Vec, + modules: Vec>, +} From 7ab3a269b623fff762d242517ad0004d2f3831f8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Jan 2021 12:27:19 -0800 Subject: [PATCH 5/6] Fix tests --- crates/wasm-encoder/src/aliases.rs | 2 +- crates/wasm-encoder/src/instances.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/wasm-encoder/src/aliases.rs b/crates/wasm-encoder/src/aliases.rs index 472f50d174..f729c5118d 100644 --- a/crates/wasm-encoder/src/aliases.rs +++ b/crates/wasm-encoder/src/aliases.rs @@ -13,7 +13,7 @@ use super::*; /// use wasm_encoder::{Module, AliasSection, ItemKind}; /// /// let mut aliases = AliasSection::new(); -/// aliases.parent_type(2); +/// aliases.outer_type(0, 2); /// aliases.instance_export(0, ItemKind::Function, "foo"); /// /// let mut module = Module::new(); diff --git a/crates/wasm-encoder/src/instances.rs b/crates/wasm-encoder/src/instances.rs index a0ca142be1..af9bc63a7a 100644 --- a/crates/wasm-encoder/src/instances.rs +++ b/crates/wasm-encoder/src/instances.rs @@ -14,9 +14,9 @@ use super::*; /// /// let mut instances = InstanceSection::new(); /// instances.instantiate(0, vec![ -/// ("x", None, Export::Function(0)), -/// ("", Some("y"), Export::Module(2)), -/// ("foo", None, Export::Global(0)), +/// ("x", Export::Function(0)), +/// ("", Export::Module(2)), +/// ("foo", Export::Global(0)), /// ]); /// /// let mut module = Module::new(); From 2759413b64856d645493ce632c912aeec9689f26 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 11 Jan 2021 14:23:22 -0800 Subject: [PATCH 6/6] Address review comments --- crates/wasm-smith/src/lib.rs | 59 +++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs index 9e0bd8e095..39f20c5da9 100644 --- a/crates/wasm-smith/src/lib.rs +++ b/crates/wasm-smith/src/lib.rs @@ -96,8 +96,8 @@ where config: C, valtypes: Vec, - /// Parent modules, if any (used for module linking) - parents: Vec, + /// Outer modules, if any (used for module linking) + outers: Vec, /// The initial sections of this wasm module, including types and imports. /// This is stored as a list-of-lists where each `InitialSection` represents @@ -125,9 +125,8 @@ where /// defined. implicit_instance_types: HashMap, - /// Indices into `initializers` which are types. The pair `(i, j)` means - /// that `initializers[i]` is a type section, and we are referring to the - /// `j`th type within that type section. + /// All types locally defined in this module (available in the type index + /// space). types: Vec, /// Indices within `types` that are function types. func_types: Vec, @@ -720,7 +719,7 @@ where choices.push(|u, m, _, _| m.arbitrary_imports(0, u)); } if self.modules.len() < self.config.max_modules() - && self.parents.len() < self.config.max_nesting_depth() + && self.outers.len() < self.config.max_nesting_depth() { choices.push(|u, m, _, _| m.arbitrary_modules(u)); } @@ -1013,14 +1012,15 @@ where // that if module-linking is enabled and `name` is present, then we // might be implicitly generating an instance. If that's the case // then we need to record the type of this instance. - let module_linking = self.config.module_linking_enabled() || self.parents.len() > 0; + let module_linking = self.config.module_linking_enabled() || self.outers.len() > 0; let (module, name) = unique_import_strings(1_000, &mut self.import_names, module_linking, u)?; if module_linking && name.is_some() && self.import_names[&module].as_ref().unwrap().len() == 1 { - // first time this is imported, generate a new type + // This is the first time this module name is imported from, so + // generate a new instance type. self.implicit_instance_types .insert(module.clone(), self.instances.len()); self.instances.push(Rc::new(InstanceType::default())); @@ -1033,7 +1033,7 @@ where let idx = self.implicit_instance_types[&module]; let instance_ty = &mut self.instances[idx]; Rc::get_mut(instance_ty) - .unwrap() // shouldn't be aliased yet + .expect("shouldn't be aliased yet") .exports .insert(name.clone(), ty.clone()); } @@ -1121,12 +1121,12 @@ where } } Alias::OuterType { depth, index } => { - let ty = self.parents[*depth as usize].types[*index as usize].clone(); + let ty = self.outers[*depth as usize].types[*index as usize].clone(); self.record_type(&ty); self.types.push(LocalType::Aliased(ty)); } Alias::OuterModule { depth, index } => { - let ty = self.parents[*depth as usize].modules[*index as usize].clone(); + let ty = self.outers[*depth as usize].modules[*index as usize].clone(); self.modules.push(ty); } } @@ -1181,14 +1181,14 @@ where let mut modules = Vec::new(); arbitrary_loop(u, 0, self.config.max_modules(), |u| { let mut module = ConfiguredModule::::default(); - module.parents = self.parents.clone(); - let parent = Parent { + module.outers = self.outers.clone(); + let parent = Outer { types: (0..self.types.len()) .map(|i| self.ty(i as u32).clone()) .collect(), modules: self.modules.clone(), }; - module.parents.insert(0, parent); + module.outers.insert(0, parent); module.config = self.config.clone(); module.build(u, false)?; @@ -1207,11 +1207,11 @@ where { if field.is_none() { // If the field is none then `ty` matches the import type - // exactly + // exactly. import_types.insert(name.clone(), ty.clone()); } else if import_types.get(name).is_none() { - // otherwise if we haven't already recorded the implicit - // type of `name` then we do so here + // Otherwise if we haven't already recorded the implicit + // type of `name` then we do so here. let ty = module.instances[module.implicit_instance_types[name]].clone(); import_types.insert(name.clone(), EntityType::Instance(u32::max_value(), ty)); } @@ -2001,7 +2001,7 @@ fn arbitrary_vec_u8(u: &mut Unstructured) -> Result> { struct AvailableAliases { aliases: Vec, instances_added: usize, - parents_processed: bool, + outers_processed: bool, } impl AvailableAliases { @@ -2064,9 +2064,9 @@ impl AvailableAliases { } // Then add in our all parent's alias candidates, if there are any - // parents. - if !self.parents_processed { - for (i, parent) in module.parents.iter().enumerate() { + // outers. + if !self.outers_processed { + for (i, parent) in module.outers.iter().enumerate() { for j in 0..parent.types.len() { self.aliases.push(Alias::OuterType { depth: i as u32, @@ -2080,7 +2080,7 @@ impl AvailableAliases { }); } } - self.parents_processed = true; + self.outers_processed = true; } // And afterwards we need to discard alias candidates that create items @@ -2209,12 +2209,23 @@ impl Entities { #[derive(Clone, Debug)] enum LocalType { - Defined { section: usize, nth: usize }, + /// A type that's locally defined in a module via a type section. + Defined { + /// The section (index within `ConfiguredModule::initializers` that this + /// type is defined. + section: usize, + /// Which element within the section definition this type corresponds + /// to. + nth: usize, + }, + + /// A type that's aliased from another outer module to be defined in a + /// module. The type's definition is copied inline here. Aliased(Type), } #[derive(Debug, Clone)] -struct Parent { +struct Outer { types: Vec, modules: Vec>, }