diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index 064be25741..0ebef3a498 100644 --- a/crates/dump/src/lib.rs +++ b/crates/dump/src/lib.rs @@ -29,15 +29,21 @@ struct Dump<'a> { #[derive(Default)] struct Indices { - funcs: u32, - globals: u32, - tables: u32, - memories: u32, - tags: u32, + // Core module indexes + core_types: u32, + core_funcs: u32, + core_globals: u32, + core_tables: u32, + core_memories: u32, + core_tags: u32, + core_modules: u32, + core_instances: u32, + + // Component indexes types: u32, - instances: u32, + funcs: u32, components: u32, - modules: u32, + instances: u32, values: u32, } @@ -45,9 +51,7 @@ enum ComponentTypeKind { Func, Component, Instance, - Module, - Value, - Type, + DefinedType, } const NBYTES: usize = 4; @@ -87,40 +91,44 @@ impl<'a> Dump<'a> { self.print(range.end)?; } Payload::TypeSection(s) => self.section(s, "type", |me, end, t| { - write!(me.state, "[type {}] {:?}", inc(&mut i.types), t)?; + write!(me.state, "[type {}] {:?}", inc(&mut i.core_types), t)?; me.print(end) })?, Payload::ImportSection(s) => self.section(s, "import", |me, end, imp| { write!(me.state, "import ")?; match imp.ty { - TypeRef::Func(_) => write!(me.state, "[func {}]", inc(&mut i.funcs))?, + TypeRef::Func(_) => write!(me.state, "[func {}]", inc(&mut i.core_funcs))?, TypeRef::Memory(_) => { - write!(me.state, "[memory {}]", inc(&mut i.memories))? + write!(me.state, "[memory {}]", inc(&mut i.core_memories))? + } + TypeRef::Tag(_) => write!(me.state, "[tag {}]", inc(&mut i.core_tags))?, + TypeRef::Table(_) => { + write!(me.state, "[table {}]", inc(&mut i.core_tables))? + } + TypeRef::Global(_) => { + write!(me.state, "[global {}]", inc(&mut i.core_globals))? } - TypeRef::Tag(_) => write!(me.state, "[tag {}]", inc(&mut i.tags))?, - TypeRef::Table(_) => write!(me.state, "[table {}]", inc(&mut i.tables))?, - TypeRef::Global(_) => write!(me.state, "[global {}]", inc(&mut i.globals))?, } write!(me.state, " {:?}", imp)?; me.print(end) })?, Payload::FunctionSection(s) => { - let mut cnt = i.funcs; + let mut cnt = i.core_funcs; self.section(s, "func", |me, end, f| { write!(me.state, "[func {}] type {:?}", inc(&mut cnt), f)?; me.print(end) })? } Payload::TableSection(s) => self.section(s, "table", |me, end, t| { - write!(me.state, "[table {}] {:?}", inc(&mut i.tables), t)?; + write!(me.state, "[table {}] {:?}", inc(&mut i.core_tables), t)?; me.print(end) })?, Payload::MemorySection(s) => self.section(s, "memory", |me, end, m| { - write!(me.state, "[memory {}] {:?}", inc(&mut i.memories), m)?; + write!(me.state, "[memory {}] {:?}", inc(&mut i.core_memories), m)?; me.print(end) })?, Payload::TagSection(s) => self.section(s, "tag", |me, end, m| { - write!(me.state, "[tag {}] {:?}", inc(&mut i.tags), m)?; + write!(me.state, "[tag {}] {:?}", inc(&mut i.core_tags), m)?; me.print(end) })?, Payload::ExportSection(s) => self.section(s, "export", |me, end, e| { @@ -128,7 +136,7 @@ impl<'a> Dump<'a> { me.print(end) })?, Payload::GlobalSection(s) => self.section(s, "global", |me, _end, g| { - write!(me.state, "[global {}] {:?}", inc(&mut i.globals), g.ty)?; + write!(me.state, "[global {}] {:?}", inc(&mut i.core_globals), g.ty)?; me.print(g.init_expr.get_binary_reader().original_position())?; me.print_ops(g.init_expr.get_operators_reader()) })?, @@ -192,7 +200,7 @@ impl<'a> Dump<'a> { for _ in 0..NBYTES { write!(me.dst, "---")?; } - write!(me.dst, "-| ... {} bytes of data\n", i.data.len())?; + writeln!(me.dst, "-| ... {} bytes of data", i.data.len())?; me.cur = end; Ok(()) })?, @@ -205,10 +213,10 @@ impl<'a> Dump<'a> { } Payload::CodeSectionEntry(body) => { - write!( + writeln!( self.dst, - "============== func {} ====================\n", - inc(&mut i.funcs), + "============== func {} ====================", + inc(&mut i.core_funcs), )?; write!(self.state, "size of function")?; self.print(body.get_binary_reader().original_position())?; @@ -224,54 +232,47 @@ impl<'a> Dump<'a> { } // Component sections - Payload::ComponentTypeSection(s) => self.section(s, "type", |me, end, t| { - write!(me.state, "[type {}] {:?}", inc(&mut i.types), t)?; - component_types.push(match t { - ComponentTypeDef::Module(_) => ComponentTypeKind::Module, - ComponentTypeDef::Component(_) => ComponentTypeKind::Component, - ComponentTypeDef::Instance(_) => ComponentTypeKind::Instance, - ComponentTypeDef::Function(_) => ComponentTypeKind::Func, - ComponentTypeDef::Value(_) => ComponentTypeKind::Value, - ComponentTypeDef::Interface(_) => ComponentTypeKind::Type, - }); - me.print(end) - })?, - - Payload::ComponentImportSection(s) => { - self.section(s, "import", |me, end, item| { - let (desc, idx) = match component_types.get(item.ty as usize) { - Some(ComponentTypeKind::Func) => ("func", inc(&mut i.funcs)), - Some(ComponentTypeKind::Component) => { - ("component", inc(&mut i.components)) - } - Some(ComponentTypeKind::Module) => ("module", inc(&mut i.modules)), - Some(ComponentTypeKind::Instance) => { - ("instance", inc(&mut i.instances)) - } - Some(ComponentTypeKind::Value) => ("value", inc(&mut i.values)), - Some(ComponentTypeKind::Type) => ("type", inc(&mut i.types)), - None => ("???", 0), - }; - write!(me.state, "[{desc} {idx}] {item:?}")?; - me.print(end) - })? - } - - Payload::ComponentFunctionSection(s) => { - self.section(s, "component function", |me, end, f| { - write!(me.state, "[func {}] {:?}", inc(&mut i.funcs), f)?; - me.print(end) - })? - } - Payload::ModuleSection { range, .. } => { - write!(self.state, "[module {}] inline size", inc(&mut i.modules))?; + write!( + self.state, + "[core module {}] inline size", + inc(&mut i.core_modules) + )?; self.print(range.start)?; self.nesting += 1; stack.push(i); i = Indices::default(); } + Payload::InstanceSection(s) => self.section(s, "core instance", |me, end, e| { + write!( + me.state, + "[core instance {}] {:?}", + inc(&mut i.core_instances), + e + )?; + me.print(end) + })?, + + Payload::AliasSection(s) => self.section(s, "core alias", |me, end, a| { + let (kind, num) = match a { + Alias::InstanceExport { kind, .. } => match kind { + ExternalKind::Func => ("func", inc(&mut i.core_funcs)), + ExternalKind::Table => ("table", inc(&mut i.core_tables)), + ExternalKind::Memory => ("memory", inc(&mut i.core_memories)), + ExternalKind::Global => ("global", inc(&mut i.core_globals)), + ExternalKind::Tag => ("tag", inc(&mut i.core_tags)), + }, + }; + write!(me.state, "core alias [{} {}] {:?}", kind, num, a)?; + me.print(end) + })?, + + Payload::CoreTypeSection(s) => self.section(s, "core type", |me, end, t| { + write!(me.state, "[core type {}] {:?}", inc(&mut i.core_types), t)?; + me.print(end) + })?, + Payload::ComponentSection { range, .. } => { write!( self.state, @@ -284,13 +285,107 @@ impl<'a> Dump<'a> { i = Indices::default(); } - Payload::InstanceSection(s) => self.section(s, "instance", |me, end, e| { - write!(me.state, "[instance {}] {:?}", inc(&mut i.instances), e)?; - me.print(end) - })?, + Payload::ComponentInstanceSection(s) => { + self.section(s, "component instance", |me, end, e| { + write!(me.state, "[instance {}] {:?}", inc(&mut i.instances), e)?; + me.print(end) + })? + } + + Payload::ComponentAliasSection(s) => { + self.section(s, "component alias", |me, end, a| { + let (kind, num) = match a { + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Module, + .. + } + | ComponentAlias::Outer { + kind: ComponentOuterAliasKind::CoreModule, + .. + } => ("module", inc(&mut i.core_modules)), + ComponentAlias::Outer { + kind: ComponentOuterAliasKind::CoreType, + .. + } => ("core type", inc(&mut i.core_types)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Func, + .. + } => ("func", inc(&mut i.funcs)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Value, + .. + } => ("value", inc(&mut i.values)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Type, + .. + } + | ComponentAlias::Outer { + kind: ComponentOuterAliasKind::Type, + .. + } => ("type", inc(&mut i.types)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Instance, + .. + } => ("instance", inc(&mut i.instances)), + ComponentAlias::InstanceExport { + kind: ComponentExternalKind::Component, + .. + } + | ComponentAlias::Outer { + kind: ComponentOuterAliasKind::Component, + .. + } => ("component", inc(&mut i.components)), + }; + + write!(me.state, "alias [{} {}] {:?}", kind, num, a)?; + me.print(end) + })? + } + + Payload::ComponentTypeSection(s) => { + self.section(s, "component type", |me, end, t| { + write!(me.state, "[type {}] {:?}", inc(&mut i.types), t)?; + component_types.push(match t { + ComponentType::Defined(_) => ComponentTypeKind::DefinedType, + ComponentType::Func(_) => ComponentTypeKind::Func, + ComponentType::Component(_) => ComponentTypeKind::Component, + ComponentType::Instance(_) => ComponentTypeKind::Instance, + }); + me.print(end) + })? + } + + Payload::ComponentImportSection(s) => { + self.section(s, "component import", |me, end, item| { + let (desc, idx) = match item.ty { + ComponentTypeRef::Module(..) => ("module", inc(&mut i.core_modules)), + ComponentTypeRef::Func(..) => ("func", inc(&mut i.funcs)), + ComponentTypeRef::Value(..) => ("value", inc(&mut i.values)), + ComponentTypeRef::Type(..) => ("type", inc(&mut i.types)), + ComponentTypeRef::Instance(..) => ("instance", inc(&mut i.instances)), + ComponentTypeRef::Component(..) => { + ("component", inc(&mut i.components)) + } + }; + write!(me.state, "[{desc} {idx}] {item:?}")?; + me.print(end) + })? + } + + Payload::ComponentCanonicalSection(s) => { + self.section(s, "canonical function", |me, end, f| { + let (name, col) = match &f { + CanonicalFunction::Lift { .. } => ("func", &mut i.funcs), + CanonicalFunction::Lower { .. } => ("core func", &mut i.core_funcs), + }; + + write!(me.state, "[{} {}] {:?}", name, inc(col), f)?; + me.print(end) + })? + } Payload::ComponentExportSection(s) => { - self.section(s, "component-export", |me, end, e| { + self.section(s, "component export", |me, end, e| { write!(me.state, "export {:?}", e)?; me.print(end) })? @@ -303,28 +398,6 @@ impl<'a> Dump<'a> { self.print(s.range().end)?; } - Payload::AliasSection(s) => self.section(s, "alias", |me, end, a| { - let (kind, num) = match a { - Alias::InstanceExport { kind, .. } => match kind { - AliasKind::Module => ("module", inc(&mut i.modules)), - AliasKind::Component => ("component", inc(&mut i.components)), - AliasKind::Instance => ("instance", inc(&mut i.instances)), - AliasKind::ComponentFunc => ("component func", inc(&mut i.funcs)), - AliasKind::Value => ("value", inc(&mut i.values)), - AliasKind::Func => ("func", inc(&mut i.funcs)), - AliasKind::Table => ("table", inc(&mut i.tables)), - AliasKind::Memory => ("memory", inc(&mut i.memories)), - AliasKind::Global => ("global", inc(&mut i.globals)), - AliasKind::Tag => ("tag", inc(&mut i.tags)), - }, - Alias::OuterModule { .. } => ("module", inc(&mut i.modules)), - Alias::OuterComponent { .. } => ("component", inc(&mut i.components)), - Alias::OuterType { .. } => ("type", inc(&mut i.types)), - }; - write!(me.state, "alias [{} {}] {:?}", kind, num, a)?; - me.print(end) - })?, - Payload::CustomSection(c) => { write!(self.state, "custom section")?; self.print(c.range().start)?; @@ -340,7 +413,7 @@ impl<'a> Dump<'a> { for _ in 0..NBYTES { write!(self.dst, "---")?; } - write!(self.dst, "-| ... {} bytes of data\n", c.data().len())?; + writeln!(self.dst, "-| ... {} bytes of data", c.data().len())?; self.cur += c.data().len(); } } @@ -355,7 +428,7 @@ impl<'a> Dump<'a> { for _ in 0..NBYTES { write!(self.dst, "---")?; } - write!(self.dst, "-| ... {} bytes of data\n", contents.len())?; + writeln!(self.dst, "-| ... {} bytes of data", contents.len())?; self.cur += contents.len(); } Payload::End(_) => { @@ -515,7 +588,7 @@ impl<'a> Dump<'a> { write!(self.dst, "{}", &self.state)?; self.state.truncate(0); } - write!(self.dst, "\n")?; + writeln!(self.dst)?; } self.cur = end; Ok(()) @@ -538,5 +611,5 @@ impl<'a> Dump<'a> { fn inc(spot: &mut u32) -> u32 { let ret = *spot; *spot += 1; - return ret; + ret } diff --git a/crates/wasm-encoder/src/component.rs b/crates/wasm-encoder/src/component.rs index 6fe686da8e..fbac178bf2 100644 --- a/crates/wasm-encoder/src/component.rs +++ b/crates/wasm-encoder/src/component.rs @@ -1,7 +1,7 @@ mod aliases; +mod canonicals; mod components; mod exports; -mod functions; mod imports; mod instances; mod modules; @@ -9,23 +9,38 @@ mod start; mod types; pub use self::aliases::*; +pub use self::canonicals::*; pub use self::components::*; pub use self::exports::*; -pub use self::functions::*; pub use self::imports::*; pub use self::instances::*; pub use self::modules::*; pub use self::start::*; pub use self::types::*; -use crate::Encode; +use crate::{CustomSection, Encode}; + +// Core sorts extended by the component model +const CORE_TYPE_SORT: u8 = 0x10; +const CORE_MODULE_SORT: u8 = 0x11; +const CORE_INSTANCE_SORT: u8 = 0x12; + +const CORE_SORT: u8 = 0x00; +const FUNCTION_SORT: u8 = 0x01; +const VALUE_SORT: u8 = 0x02; +const TYPE_SORT: u8 = 0x03; +const COMPONENT_SORT: u8 = 0x04; +const INSTANCE_SORT: u8 = 0x05; /// A WebAssembly component section. /// /// Various builders defined in this crate already implement this trait, but you /// can also implement it yourself for your own custom section builders, or use /// `RawSection` to use a bunch of raw bytes as a section. -pub trait ComponentSection: Encode {} +pub trait ComponentSection: Encode { + /// Gets the section identifier for this section. + fn id(&self) -> u8; +} /// Known section identifiers of WebAssembly components. /// @@ -33,26 +48,32 @@ pub trait ComponentSection: Encode {} #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] #[repr(u8)] pub enum ComponentSectionId { - /// The section is a custom section. - Custom = 0, - /// The section is a type section. - Type = 1, - /// The section is an import section. - Import = 2, - /// The section is a function section. - Function = 3, - /// The section is a module section. - Module = 4, + /// The section is a core custom section. + CoreCustom = 0, + /// The section is a core module section. + CoreModule = 1, + /// The section is a core instance section. + CoreInstance = 2, + /// The section is a core alias section. + CoreAlias = 3, + /// The section is a core type section. + CoreType = 4, /// The section is a component section. Component = 5, /// The section is an instance section. Instance = 6, - /// The section is an export section. - Export = 7, - /// The section is a start section. - Start = 8, /// The section is an alias section. - Alias = 9, + Alias = 7, + /// The section is a type section. + Type = 8, + /// The section is a canonical function section. + CanonicalFunction = 9, + /// The section is a start section. + Start = 10, + /// The section is an import section. + Import = 11, + /// The section is an export section. + Export = 12, } impl From for u8 { @@ -97,6 +118,7 @@ impl Component { /// Write a section to this component. pub fn section(&mut self, section: &impl ComponentSection) -> &mut Self { + self.bytes.push(section.id()); section.encode(&mut self.bytes); self } @@ -107,3 +129,9 @@ impl Default for Component { Self::new() } } + +impl ComponentSection for CustomSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreCustom.into() + } +} diff --git a/crates/wasm-encoder/src/component/aliases.rs b/crates/wasm-encoder/src/component/aliases.rs index a7b3802566..9a681d668e 100644 --- a/crates/wasm-encoder/src/component/aliases.rs +++ b/crates/wasm-encoder/src/component/aliases.rs @@ -1,60 +1,17 @@ -use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; +use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT}; +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, +}; -/// Represents the expected export kind for an alias. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AliasExportKind { - /// The alias is to a module. - Module, - /// The alias is to a component. - Component, - /// The alias is to an instance. - Instance, - /// The alias is to a component function. - ComponentFunction, - /// The alias is to a value. - Value, - /// The alias is to a core WebAssembly function. - Function, - /// The alias is to a table. - Table, - /// The alias is to a memory. - Memory, - /// The alias is to a global. - Global, - /// The alias is to a tag. - Tag, -} - -impl Encode for AliasExportKind { - fn encode(&self, sink: &mut Vec) { - let (preamble, value) = match self { - AliasExportKind::Module => (0x00, 0x00), - AliasExportKind::Component => (0x00, 0x01), - AliasExportKind::Instance => (0x00, 0x02), - AliasExportKind::ComponentFunction => (0x00, 0x03), - AliasExportKind::Value => (0x00, 0x04), - AliasExportKind::Function => (0x01, 0x00), - AliasExportKind::Table => (0x01, 0x01), - AliasExportKind::Memory => (0x01, 0x02), - AliasExportKind::Global => (0x01, 0x03), - AliasExportKind::Tag => (0x01, 0x04), - }; - - sink.push(preamble); - sink.push(value); - } -} - -/// An encoder for the alias section of WebAssembly component. +/// An encoder for the core alias section of WebAssembly components. /// /// # Example /// /// ```rust -/// use wasm_encoder::{Component, AliasSection, AliasExportKind}; +/// use wasm_encoder::{Component, AliasSection, ExportKind}; /// /// let mut aliases = AliasSection::new(); -/// aliases.outer_type(0, 2); -/// aliases.instance_export(0, AliasExportKind::Function, "foo"); +/// aliases.instance_export(0, ExportKind::Func, "f"); /// /// let mut component = Component::new(); /// component.section(&aliases); @@ -68,7 +25,7 @@ pub struct AliasSection { } impl AliasSection { - /// Create a new alias section encoder. + /// Create a new core alias section encoder. pub fn new() -> Self { Self::default() } @@ -83,49 +40,123 @@ impl AliasSection { self.num_added == 0 } - /// Define an alias that references the export of a defined instance. + /// Define an alias to an instance's export. pub fn instance_export( &mut self, - instance: u32, - kind: AliasExportKind, + instance_index: u32, + kind: ExportKind, name: &str, ) -> &mut Self { kind.encode(&mut self.bytes); - instance.encode(&mut self.bytes); + self.bytes.push(0x00); + instance_index.encode(&mut self.bytes); name.encode(&mut self.bytes); self.num_added += 1; self } +} - /// Define an alias to an outer type. - /// - /// The count starts at 0 to represent the current component. - pub fn outer_type(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x02); - self.bytes.push(0x05); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); - self.num_added += 1; - self +impl Encode for AliasSection { + fn encode(&self, sink: &mut Vec) { + encode_section(sink, self.num_added, &self.bytes); } +} - /// Define an alias to an outer module. - /// - /// The count starts at 0 to represent the current component. - pub fn outer_module(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x02); +impl ComponentSection for AliasSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreAlias.into() + } +} + +/// Represents the kinds of outer aliasable items in a component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentOuterAliasKind { + /// The alias is to a core module. + CoreModule, + /// The alias is to a core type. + CoreType, + /// The alias is to a type. + Type, + /// The alias is to a component. + Component, +} + +impl Encode for ComponentOuterAliasKind { + fn encode(&self, sink: &mut Vec) { + match self { + Self::CoreModule => { + sink.push(CORE_SORT); + sink.push(CORE_MODULE_SORT); + } + Self::CoreType => { + sink.push(CORE_SORT); + sink.push(CORE_TYPE_SORT); + } + Self::Type => sink.push(TYPE_SORT), + Self::Component => sink.push(COMPONENT_SORT), + } + } +} + +/// An encoder for the alias section of WebAssembly component. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind}; +/// +/// let mut aliases = ComponentAliasSection::new(); +/// aliases.instance_export(0, ComponentExportKind::Func, "f"); +/// aliases.outer(0, ComponentOuterAliasKind::Type, 1); +/// +/// let mut component = Component::new(); +/// component.section(&aliases); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ComponentAliasSection { + bytes: Vec, + num_added: u32, +} + +impl ComponentAliasSection { + /// Create a new alias section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of aliases in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Define an alias to an instance's export. + pub fn instance_export( + &mut self, + instance_index: u32, + kind: ComponentExportKind, + name: &str, + ) -> &mut Self { + kind.encode(&mut self.bytes); self.bytes.push(0x00); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); + instance_index.encode(&mut self.bytes); + name.encode(&mut self.bytes); self.num_added += 1; self } - /// Define an alias to an outer component. + /// Define an alias to an outer component item. /// - /// The count starts at 0 to represent the current component. - pub fn outer_component(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x02); + /// The count starts at 0 to indicate the current component, 1 indicates the direct + /// parent, 2 the grandparent, etc. + pub fn outer(&mut self, count: u32, kind: ComponentOuterAliasKind, index: u32) -> &mut Self { + kind.encode(&mut self.bytes); self.bytes.push(0x01); count.encode(&mut self.bytes); index.encode(&mut self.bytes); @@ -134,10 +165,14 @@ impl AliasSection { } } -impl Encode for AliasSection { +impl Encode for ComponentAliasSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, ComponentSectionId::Alias, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl ComponentSection for AliasSection {} +impl ComponentSection for ComponentAliasSection { + fn id(&self) -> u8 { + ComponentSectionId::Alias.into() + } +} diff --git a/crates/wasm-encoder/src/component/functions.rs b/crates/wasm-encoder/src/component/canonicals.rs similarity index 56% rename from crates/wasm-encoder/src/component/functions.rs rename to crates/wasm-encoder/src/component/canonicals.rs index 995696cbe8..e81819c44e 100644 --- a/crates/wasm-encoder/src/component/functions.rs +++ b/crates/wasm-encoder/src/component/canonicals.rs @@ -1,6 +1,6 @@ use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; -/// Represents options for component functions. +/// Represents options for canonical function definitions. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CanonicalOption { /// The string types in the function signature are UTF-8 encoded. @@ -9,12 +9,18 @@ pub enum CanonicalOption { UTF16, /// The string types in the function signature are compact UTF-16 encoded. CompactUTF16, - /// The lifting or lowering operation requires access to a memory, realloc, or - /// free function. + /// The memory to use if the lifting or lowering of a function requires memory access. /// - /// The value is expected to be an instance exporting the canonical ABI memory - /// and functions. - Into(u32), + /// The value is an index to a core memory. + Memory(u32), + /// The realloc function to use if the lifting or lowering of a function requires memory + /// allocation. + /// + /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. + Realloc(u32), + /// The post-return function to use if the lifting of a function requires + /// cleanup after the function returns. + PostReturn(u32), } impl Encode for CanonicalOption { @@ -23,23 +29,31 @@ impl Encode for CanonicalOption { Self::UTF8 => sink.push(0x00), Self::UTF16 => sink.push(0x01), Self::CompactUTF16 => sink.push(0x02), - Self::Into(index) => { + Self::Memory(idx) => { sink.push(0x03); - index.encode(sink); + idx.encode(sink); + } + Self::Realloc(idx) => { + sink.push(0x04); + idx.encode(sink); + } + Self::PostReturn(idx) => { + sink.push(0x05); + idx.encode(sink); } } } } -/// An encoder for the function section of WebAssembly components. +/// An encoder for the canonical function section of WebAssembly components. /// /// # Example /// /// ``` -/// use wasm_encoder::{Component, ComponentFunctionSection, CanonicalOption}; +/// use wasm_encoder::{Component, CanonicalFunctionSection, CanonicalOption}; /// -/// let mut functions = ComponentFunctionSection::new(); -/// functions.lift(0, 0, [CanonicalOption::UTF8, CanonicalOption::Into(0)]); +/// let mut functions = CanonicalFunctionSection::new(); +/// functions.lift(0, 0, [CanonicalOption::UTF8]); /// /// let mut component = Component::new(); /// component.section(&functions); @@ -47,12 +61,12 @@ impl Encode for CanonicalOption { /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] -pub struct ComponentFunctionSection { +pub struct CanonicalFunctionSection { bytes: Vec, num_added: u32, } -impl ComponentFunctionSection { +impl CanonicalFunctionSection { /// Construct a new component function section encoder. pub fn new() -> Self { Self::default() @@ -68,25 +82,26 @@ impl ComponentFunctionSection { self.num_added == 0 } - /// Define a function that will lift a core WebAssembly function to the canonical interface ABI. - pub fn lift(&mut self, type_index: u32, func_index: u32, options: O) -> &mut Self + /// Define a function that will lift a core WebAssembly function to the canonical ABI. + pub fn lift(&mut self, core_func_index: u32, type_index: u32, options: O) -> &mut Self where O: IntoIterator, O::IntoIter: ExactSizeIterator, { let options = options.into_iter(); self.bytes.push(0x00); - type_index.encode(&mut self.bytes); + self.bytes.push(0x00); + core_func_index.encode(&mut self.bytes); options.len().encode(&mut self.bytes); for option in options { option.encode(&mut self.bytes); } - func_index.encode(&mut self.bytes); + type_index.encode(&mut self.bytes); self.num_added += 1; self } - /// Define a function that will lower a canonical interface ABI function to a core WebAssembly function. + /// Define a function that will lower a canonical ABI function to a core WebAssembly function. pub fn lower(&mut self, func_index: u32, options: O) -> &mut Self where O: IntoIterator, @@ -94,25 +109,25 @@ impl ComponentFunctionSection { { let options = options.into_iter(); self.bytes.push(0x01); + self.bytes.push(0x00); + func_index.encode(&mut self.bytes); options.len().encode(&mut self.bytes); for option in options { option.encode(&mut self.bytes); } - func_index.encode(&mut self.bytes); self.num_added += 1; self } } -impl Encode for ComponentFunctionSection { +impl Encode for CanonicalFunctionSection { fn encode(&self, sink: &mut Vec) { - encode_section( - sink, - ComponentSectionId::Function, - self.num_added, - &self.bytes, - ); + encode_section(sink, self.num_added, &self.bytes); } } -impl ComponentSection for ComponentFunctionSection {} +impl ComponentSection for CanonicalFunctionSection { + fn id(&self) -> u8 { + ComponentSectionId::CanonicalFunction.into() + } +} diff --git a/crates/wasm-encoder/src/component/components.rs b/crates/wasm-encoder/src/component/components.rs index 5d3d449548..c08645e3b9 100644 --- a/crates/wasm-encoder/src/component/components.rs +++ b/crates/wasm-encoder/src/component/components.rs @@ -18,9 +18,12 @@ pub struct NestedComponentSection<'a>(pub &'a Component); impl Encode for NestedComponentSection<'_> { fn encode(&self, sink: &mut Vec) { - ComponentSectionId::Component.encode(sink); self.0.bytes.encode(sink); } } -impl ComponentSection for NestedComponentSection<'_> {} +impl ComponentSection for NestedComponentSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::Component.into() + } +} diff --git a/crates/wasm-encoder/src/component/exports.rs b/crates/wasm-encoder/src/component/exports.rs index 378d4f9be3..eefd3ca0ec 100644 --- a/crates/wasm-encoder/src/component/exports.rs +++ b/crates/wasm-encoder/src/component/exports.rs @@ -1,18 +1,62 @@ -use crate::{encode_section, ComponentArg, ComponentSection, ComponentSectionId, Encode}; +use super::{ + COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, + VALUE_SORT, +}; +use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; -/// Represents an export for a WebAssembly component. -pub type ComponentExport = ComponentArg; +/// Represents the kind of an export from a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentExportKind { + /// The export is a core module. + Module, + /// The export is a function. + Func, + /// The export is a value. + Value, + /// The export is a type. + Type, + /// The export is an instance. + Instance, + /// The export is a component. + Component, +} + +impl Encode for ComponentExportKind { + fn encode(&self, sink: &mut Vec) { + match self { + Self::Module => { + sink.push(CORE_SORT); + sink.push(CORE_MODULE_SORT); + } + Self::Func => { + sink.push(FUNCTION_SORT); + } + Self::Value => { + sink.push(VALUE_SORT); + } + Self::Type => { + sink.push(TYPE_SORT); + } + Self::Instance => { + sink.push(INSTANCE_SORT); + } + Self::Component => { + sink.push(COMPONENT_SORT); + } + } + } +} /// An encoder for the export section of WebAssembly component. /// /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentExportSection, ComponentExport}; +/// use wasm_encoder::{Component, ComponentExportSection, ComponentExportKind}; /// -/// // This exports an instance named "foo" that exports a function named "bar". +/// // This exports a function named "foo" /// let mut exports = ComponentExportSection::new(); -/// exports.export("foo", ComponentExport::Function(0)); +/// exports.export("foo", ComponentExportKind::Func, 0); /// /// let mut component = Component::new(); /// component.section(&exports); @@ -42,9 +86,10 @@ impl ComponentExportSection { } /// Define an export in the export section. - pub fn export(&mut self, name: &str, export: impl Into) -> &mut Self { + pub fn export(&mut self, name: &str, kind: ComponentExportKind, index: u32) -> &mut Self { name.encode(&mut self.bytes); - export.into().encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); self.num_added += 1; self } @@ -52,13 +97,12 @@ impl ComponentExportSection { impl Encode for ComponentExportSection { fn encode(&self, sink: &mut Vec) { - encode_section( - sink, - ComponentSectionId::Export, - self.num_added, - &self.bytes, - ); + encode_section(sink, self.num_added, &self.bytes); } } -impl ComponentSection for ComponentExportSection {} +impl ComponentSection for ComponentExportSection { + fn id(&self) -> u8 { + ComponentSectionId::Export.into() + } +} diff --git a/crates/wasm-encoder/src/component/imports.rs b/crates/wasm-encoder/src/component/imports.rs index 8d7481ad6b..f62c328941 100644 --- a/crates/wasm-encoder/src/component/imports.rs +++ b/crates/wasm-encoder/src/component/imports.rs @@ -1,16 +1,105 @@ -use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, ComponentValType, + Encode, +}; + +/// Represents the possible type bounds for type references. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum TypeBounds { + /// The type is bounded by equality. + Eq, +} + +impl Encode for TypeBounds { + fn encode(&self, sink: &mut Vec) { + match self { + Self::Eq => sink.push(0x00), + } + } +} + +/// Represents a reference to a type. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum ComponentTypeRef { + /// The reference is to a core module type. + /// + /// The index is expected to be core type index to a core module type. + Module(u32), + /// The reference is to a function type. + /// + /// The index is expected to be a type index to a function type. + Func(u32), + /// The reference is to a value type. + Value(ComponentValType), + /// The reference is to a bounded type. + /// + /// The index is expected to be a type index. + Type(TypeBounds, u32), + /// The reference is to an instance type. + /// + /// The index is expected to be a type index to an instance type. + Instance(u32), + /// The reference is to a component type. + /// + /// The index is expected to be a type index to a component type. + Component(u32), +} + +impl ComponentTypeRef { + /// Gets the export kind of the reference. + pub fn kind(&self) -> ComponentExportKind { + match self { + Self::Module(_) => ComponentExportKind::Module, + Self::Func(_) => ComponentExportKind::Func, + Self::Value(_) => ComponentExportKind::Value, + Self::Type(..) => ComponentExportKind::Type, + Self::Instance(_) => ComponentExportKind::Instance, + Self::Component(_) => ComponentExportKind::Component, + } + } +} + +impl Encode for ComponentTypeRef { + fn encode(&self, sink: &mut Vec) { + self.kind().encode(sink); + + match self { + Self::Module(idx) | Self::Func(idx) | Self::Instance(idx) | Self::Component(idx) => { + idx.encode(sink); + } + Self::Value(ty) => ty.encode(sink), + Self::Type(bounds, idx) => { + bounds.encode(sink); + idx.encode(sink); + } + } + } +} /// An encoder for the import section of WebAssembly components. /// /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentImportSection}; +/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType, ComponentImportSection, ComponentTypeRef}; +/// +/// let mut types = ComponentTypeSection::new(); +/// +/// // Define a function type of `[string, string] -> string`. +/// types.function( +/// [ +/// (Some("a"), PrimitiveValType::String), +/// (Some("b"), PrimitiveValType::String) +/// ], +/// PrimitiveValType::String +/// ); /// +/// // This imports a function named `f` with the type defined above /// let mut imports = ComponentImportSection::new(); -/// imports.import("f", 0); +/// imports.import("f", ComponentTypeRef::Func(0)); /// /// let mut component = Component::new(); +/// component.section(&types); /// component.section(&imports); /// /// let bytes = component.finish(); @@ -38,9 +127,9 @@ impl ComponentImportSection { } /// Define an import in the component import section. - pub fn import(&mut self, name: &str, type_index: u32) -> &mut Self { + pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { name.encode(&mut self.bytes); - type_index.encode(&mut self.bytes); + ty.encode(&mut self.bytes); self.num_added += 1; self } @@ -48,13 +137,12 @@ impl ComponentImportSection { impl Encode for ComponentImportSection { fn encode(&self, sink: &mut Vec) { - encode_section( - sink, - ComponentSectionId::Import, - self.num_added, - &self.bytes, - ); + encode_section(sink, self.num_added, &self.bytes); } } -impl ComponentSection for ComponentImportSection {} +impl ComponentSection for ComponentImportSection { + fn id(&self) -> u8 { + ComponentSectionId::Import.into() + } +} diff --git a/crates/wasm-encoder/src/component/instances.rs b/crates/wasm-encoder/src/component/instances.rs index 3fb9a9794c..000a872d6b 100644 --- a/crates/wasm-encoder/src/component/instances.rs +++ b/crates/wasm-encoder/src/component/instances.rs @@ -1,7 +1,10 @@ -use crate::{encode_section, ComponentExport, ComponentSection, ComponentSectionId, Encode}; +use super::CORE_INSTANCE_SORT; +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, +}; -/// Represents an argument to instantiating a WebAssembly module. -#[derive(Debug, Clone)] +/// Represents an argument to a module instantiation. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ModuleArg { /// The argument is an instance. Instance(u32), @@ -9,58 +12,24 @@ pub enum ModuleArg { impl Encode for ModuleArg { fn encode(&self, sink: &mut Vec) { - match self { - Self::Instance(index) => { - sink.push(0x02); - index.encode(sink); - } - } - } -} - -/// Represents an argument to instantiating a WebAssembly component. -#[derive(Debug, Clone)] -pub enum ComponentArg { - /// The argument is a module. - Module(u32), - /// The argument is a component. - Component(u32), - /// The argument is an instance. - Instance(u32), - /// The argument is a function. - Function(u32), - /// The argument is a value. - Value(u32), - /// The argument is a type. - Type(u32), -} - -impl Encode for ComponentArg { - fn encode(&self, sink: &mut Vec) { - let (kind, index) = match self { - Self::Module(index) => (0x00, *index), - Self::Component(index) => (0x01, *index), - Self::Instance(index) => (0x02, *index), - Self::Function(index) => (0x03, *index), - Self::Value(index) => (0x04, *index), - Self::Type(index) => (0x05, *index), + let (sort, idx) = match self { + Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx), }; - - sink.push(kind); - index.encode(sink); + sink.push(sort); + idx.encode(sink); } } -/// An encoder for the instance section of WebAssembly components. +/// An encoder for the core instance section of WebAssembly components. /// /// # Example /// /// ```rust -/// use wasm_encoder::{Component, InstanceSection, ModuleArg, Export}; +/// use wasm_encoder::{Component, InstanceSection, ExportKind, ModuleArg}; /// /// let mut instances = InstanceSection::new(); -/// instances.export_core_items([("foo", Export::Function(0))]); -/// instances.instantiate_module(1, [("foo", ModuleArg::Instance(0))]); +/// instances.export_items([("foo", ExportKind::Func, 0)]); +/// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]); /// /// let mut component = Component::new(); /// component.section(&instances); @@ -74,7 +43,7 @@ pub struct InstanceSection { } impl InstanceSection { - /// Create a new instance section encoder. + /// Create a new core instance section encoder. pub fn new() -> Self { Self::default() } @@ -89,96 +58,139 @@ impl InstanceSection { self.num_added == 0 } - /// Define an instance by instantiating a module. - pub fn instantiate_module<'a, Args, Arg>(&mut self, module_index: u32, args: Args) -> &mut Self + /// Define an instance by instantiating a core module. + pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self where - Args: IntoIterator, - Args::IntoIter: ExactSizeIterator, - Arg: Into, + A: IntoIterator, + A::IntoIter: ExactSizeIterator, { let args = args.into_iter(); self.bytes.push(0x00); - self.bytes.push(0x00); module_index.encode(&mut self.bytes); args.len().encode(&mut self.bytes); for (name, arg) in args { name.encode(&mut self.bytes); - arg.into().encode(&mut self.bytes); + arg.encode(&mut self.bytes); } self.num_added += 1; self } /// Define an instance by exporting core WebAssembly items. - pub fn export_core_items<'a, Exports, Export>(&mut self, exports: Exports) -> &mut Self + pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self where - Exports: IntoIterator, - Exports::IntoIter: ExactSizeIterator, - Export: Into, + E: IntoIterator, + E::IntoIter: ExactSizeIterator, { let exports = exports.into_iter(); - self.bytes.push(0x02); + self.bytes.push(0x01); exports.len().encode(&mut self.bytes); - for (name, export) in exports { + for (name, kind, index) in exports { name.encode(&mut self.bytes); - export.into().encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); } self.num_added += 1; self } +} + +impl Encode for InstanceSection { + fn encode(&self, sink: &mut Vec) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for InstanceSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreInstance.into() + } +} + +/// An encoder for the instance section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExportKind}; +/// +/// let mut instances = ComponentInstanceSection::new(); +/// instances.export_items([("foo", ComponentExportKind::Func, 0)]); +/// instances.instantiate(1, [("foo", ComponentExportKind::Instance, 0)]); +/// +/// let mut component = Component::new(); +/// component.section(&instances); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct ComponentInstanceSection { + bytes: Vec, + num_added: u32, +} + +impl ComponentInstanceSection { + /// Create a new instance section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of instances in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } /// Define an instance by instantiating a component. - pub fn instantiate_component<'a, Args, Arg>( - &mut self, - component_index: u32, - args: Args, - ) -> &mut Self + pub fn instantiate<'a, A>(&mut self, component_index: u32, args: A) -> &mut Self where - Args: IntoIterator, - Args::IntoIter: ExactSizeIterator, - Arg: Into, + A: IntoIterator, + A::IntoIter: ExactSizeIterator, { let args = args.into_iter(); self.bytes.push(0x00); - self.bytes.push(0x01); component_index.encode(&mut self.bytes); args.len().encode(&mut self.bytes); - for (name, arg) in args { + for (name, kind, index) in args { name.encode(&mut self.bytes); - arg.into().encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); } self.num_added += 1; self } /// Define an instance by exporting items. - pub fn export_items<'a, Exports, Export>(&mut self, exports: Exports) -> &mut Self + pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self where - Exports: IntoIterator, - Exports::IntoIter: ExactSizeIterator, - Export: Into, + E: IntoIterator, + E::IntoIter: ExactSizeIterator, { let exports = exports.into_iter(); self.bytes.push(0x01); exports.len().encode(&mut self.bytes); - for (name, export) in exports { + for (name, kind, index) in exports { name.encode(&mut self.bytes); - export.into().encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); } self.num_added += 1; self } } -impl Encode for InstanceSection { +impl Encode for ComponentInstanceSection { fn encode(&self, sink: &mut Vec) { - encode_section( - sink, - ComponentSectionId::Instance, - self.num_added, - &self.bytes, - ); + encode_section(sink, self.num_added, &self.bytes); } } -impl ComponentSection for InstanceSection {} +impl ComponentSection for ComponentInstanceSection { + fn id(&self) -> u8 { + ComponentSectionId::Instance.into() + } +} diff --git a/crates/wasm-encoder/src/component/modules.rs b/crates/wasm-encoder/src/component/modules.rs index 4d375e1489..437cd353af 100644 --- a/crates/wasm-encoder/src/component/modules.rs +++ b/crates/wasm-encoder/src/component/modules.rs @@ -18,9 +18,12 @@ pub struct ModuleSection<'a>(pub &'a Module); impl Encode for ModuleSection<'_> { fn encode(&self, sink: &mut Vec) { - ComponentSectionId::Module.encode(sink); self.0.bytes.encode(sink); } } -impl ComponentSection for ModuleSection<'_> {} +impl ComponentSection for ModuleSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreModule.into() + } +} diff --git a/crates/wasm-encoder/src/component/start.rs b/crates/wasm-encoder/src/component/start.rs index dd71c7b4bc..90b8302f1e 100644 --- a/crates/wasm-encoder/src/component/start.rs +++ b/crates/wasm-encoder/src/component/start.rs @@ -32,10 +32,15 @@ where let mut bytes = Vec::new(); self.function_index.encode(&mut bytes); self.args.as_ref().encode(&mut bytes); - - ComponentSectionId::Start.encode(sink); bytes.encode(sink); } } -impl ComponentSection for ComponentStartSection where A: AsRef<[u32]> {} +impl ComponentSection for ComponentStartSection +where + A: AsRef<[u32]>, +{ + fn id(&self) -> u8 { + ComponentSectionId::Start.into() + } +} diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index f7dcfbc0e2..6b9ef489ba 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -1,9 +1,9 @@ use crate::{ - encode_functype, encode_section, ComponentSection, ComponentSectionId, Encode, EntityType, - ValType, + encode_section, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, + ComponentTypeRef, Encode, EntityType, ValType, }; -/// Represents a module type. +/// Represents the type of a core module. #[derive(Debug, Clone, Default)] pub struct ModuleType { bytes: Vec, @@ -12,29 +12,14 @@ pub struct ModuleType { } impl ModuleType { - /// Creates a new module type. + /// Creates a new core module type. pub fn new() -> Self { Self::default() } - /// Define a function in this module type. - pub fn function(&mut self, params: P, results: R) -> &mut Self - where - P: IntoIterator, - P::IntoIter: ExactSizeIterator, - R: IntoIterator, - R::IntoIter: ExactSizeIterator, - { - self.bytes.push(0x01); - encode_functype(&mut self.bytes, params, results); - self.num_added += 1; - self.types_added += 1; - self - } - /// Defines an import in this module type. pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { - self.bytes.push(0x02); + self.bytes.push(0x00); module.encode(&mut self.bytes); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); @@ -42,9 +27,20 @@ impl ModuleType { self } + /// Define a type in this module type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + /// Defines an export in this module type. pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self { - self.bytes.push(0x07); + self.bytes.push(0x03); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; @@ -59,16 +55,127 @@ impl ModuleType { impl Encode for ModuleType { fn encode(&self, sink: &mut Vec) { + sink.push(0x50); self.num_added.encode(sink); sink.extend(&self.bytes); } } +/// Used to encode core types. +#[derive(Debug)] +pub struct CoreTypeEncoder<'a>(pub(crate) &'a mut Vec); + +impl<'a> CoreTypeEncoder<'a> { + /// Define a function type. + pub fn function(self, params: P, results: R) + where + P: IntoIterator, + P::IntoIter: ExactSizeIterator, + R: IntoIterator, + R::IntoIter: ExactSizeIterator, + { + let params = params.into_iter(); + let results = results.into_iter(); + + self.0.push(0x60); + params.len().encode(self.0); + self.0.extend(params.map(u8::from)); + results.len().encode(self.0); + self.0.extend(results.map(u8::from)); + } + + /// Define a module type. + pub fn module(self, ty: &ModuleType) { + ty.encode(self.0); + } +} + +/// An encoder for the core type section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, CoreTypeSection, ModuleType}; +/// +/// let mut types = CoreTypeSection::new(); +/// +/// types.module(&ModuleType::new()); +/// +/// let mut component = Component::new(); +/// component.section(&types); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct CoreTypeSection { + bytes: Vec, + num_added: u32, +} + +impl CoreTypeSection { + /// Create a new core type section encoder. + pub fn new() -> Self { + Self::default() + } + + /// The number of types in the section. + pub fn len(&self) -> u32 { + self.num_added + } + + /// Determines if the section is empty. + pub fn is_empty(&self) -> bool { + self.num_added == 0 + } + + /// Encode a type into this section. + /// + /// The returned encoder must be finished before adding another type. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder<'_> { + self.num_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + + /// Define a function type in this type section. + pub fn function(&mut self, params: P, results: R) -> &mut Self + where + P: IntoIterator, + P::IntoIter: ExactSizeIterator, + R: IntoIterator, + R::IntoIter: ExactSizeIterator, + { + self.ty().function(params, results); + self + } + + /// Define a module type in this type section. + /// + /// Currently this is only used for core type sections in components. + pub fn module(&mut self, ty: &ModuleType) -> &mut Self { + self.ty().module(ty); + self + } +} + +impl Encode for CoreTypeSection { + fn encode(&self, sink: &mut Vec) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for CoreTypeSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreType.into() + } +} + /// Represents a component type. #[derive(Debug, Clone, Default)] pub struct ComponentType { bytes: Vec, num_added: u32, + core_types_added: u32, types_added: u32, } @@ -78,22 +185,55 @@ impl ComponentType { Self::default() } + /// Define a core type in this component type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn core_type(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x00); + self.num_added += 1; + self.core_types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + /// Define a type in this component type. /// - /// The returned encoder must be finished before adding another definition. + /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] - pub fn ty(&mut self) -> TypeEncoder { + pub fn ty(&mut self) -> ComponentTypeEncoder { self.bytes.push(0x01); self.num_added += 1; self.types_added += 1; - TypeEncoder(&mut self.bytes) + ComponentTypeEncoder(&mut self.bytes) } - /// Defines an import in this component type. - /// - /// The type is expected to be an index to a previously defined or aliased type. - pub fn import(&mut self, name: &str, ty: u32) -> &mut Self { + /// Defines an outer core type alias in this component type. + pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + ComponentOuterAliasKind::CoreType.encode(&mut self.bytes); + self.bytes.push(0x01); + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.types_added += 1; + self + } + + /// Defines an outer type alias in this component type. + pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { self.bytes.push(0x02); + ComponentOuterAliasKind::Type.encode(&mut self.bytes); + self.bytes.push(0x01); + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); + self.num_added += 1; + self.types_added += 1; + self + } + + /// Defines an import in this component type. + pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x03); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; @@ -101,26 +241,17 @@ impl ComponentType { } /// Defines an export in this component type. - /// - /// The type is expected to be an index to a previously defined or aliased type. - pub fn export(&mut self, name: &str, ty: u32) -> &mut Self { - self.bytes.push(0x07); + pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x04); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; self } - /// Defines an alias to an outer type in this component type. - pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x09); - self.bytes.push(0x02); - self.bytes.push(0x05); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); - self.num_added += 1; - self.types_added += 1; - self + /// Gets the number of core types that have been added to this component type. + pub fn core_type_count(&self) -> u32 { + self.core_types_added } /// Gets the number of types that have been added or aliased in this component type. @@ -131,6 +262,7 @@ impl ComponentType { impl Encode for ComponentType { fn encode(&self, sink: &mut Vec) { + sink.push(0x41); self.num_added.encode(sink); sink.extend(&self.bytes); } @@ -141,6 +273,7 @@ impl Encode for ComponentType { pub struct InstanceType { bytes: Vec, num_added: u32, + core_types_added: u32, types_added: u32, } @@ -150,33 +283,45 @@ impl InstanceType { Self::default() } + /// Define a core type in this instance type. + /// + /// The returned encoder must be used before adding another definition. + #[must_use = "the encoder must be used to encode the type"] + pub fn core_type(&mut self) -> CoreTypeEncoder { + self.bytes.push(0x00); + self.num_added += 1; + self.core_types_added += 1; + CoreTypeEncoder(&mut self.bytes) + } + /// Define a type in this instance type. /// - /// The returned encoder must be finished before adding another definition. + /// The returned encoder must be used before adding another definition. #[must_use = "the encoder must be used to encode the type"] - pub fn ty(&mut self) -> TypeEncoder { + pub fn ty(&mut self) -> ComponentTypeEncoder { self.bytes.push(0x01); self.num_added += 1; self.types_added += 1; - TypeEncoder(&mut self.bytes) + ComponentTypeEncoder(&mut self.bytes) } - /// Defines an export in this instance type. - /// - /// The type is expected to be an index to a previously defined or aliased type. - pub fn export(&mut self, name: &str, ty: u32) -> &mut Self { - self.bytes.push(0x07); - name.encode(&mut self.bytes); - ty.encode(&mut self.bytes); + /// Defines an outer core type alias in this component type. + pub fn alias_outer_core_type(&mut self, count: u32, index: u32) -> &mut Self { + self.bytes.push(0x02); + ComponentOuterAliasKind::CoreType.encode(&mut self.bytes); + self.bytes.push(0x01); + count.encode(&mut self.bytes); + index.encode(&mut self.bytes); self.num_added += 1; + self.types_added += 1; self } - /// Defines an alias to an outer type in this instance type. + /// Defines an alias in this instance type. pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { - self.bytes.push(0x09); self.bytes.push(0x02); - self.bytes.push(0x05); + ComponentOuterAliasKind::Type.encode(&mut self.bytes); + self.bytes.push(0x01); count.encode(&mut self.bytes); index.encode(&mut self.bytes); self.num_added += 1; @@ -184,6 +329,20 @@ impl InstanceType { self } + /// Defines an export in this instance type. + pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x04); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Gets the number of core types that have been added to this instance type. + pub fn core_type_count(&self) -> u32 { + self.core_types_added + } + /// Gets the number of types that have been added or aliased in this instance type. pub fn type_count(&self) -> u32 { self.types_added @@ -192,43 +351,36 @@ impl InstanceType { impl Encode for InstanceType { fn encode(&self, sink: &mut Vec) { + sink.push(0x42); self.num_added.encode(sink); sink.extend(&self.bytes); } } -/// Used to encode types. +/// Used to encode component and instance types. #[derive(Debug)] -pub struct TypeEncoder<'a>(&'a mut Vec); - -impl<'a> TypeEncoder<'a> { - /// Define a module type. - pub fn module(self, ty: &ModuleType) { - self.0.push(0x4f); - ty.encode(self.0); - } +pub struct ComponentTypeEncoder<'a>(&'a mut Vec); +impl<'a> ComponentTypeEncoder<'a> { /// Define a component type. pub fn component(self, ty: &ComponentType) { - self.0.push(0x4e); ty.encode(self.0); } /// Define an instance type. pub fn instance(self, ty: &InstanceType) { - self.0.push(0x4d); ty.encode(self.0); } /// Define a function type. - pub fn function<'b, P, T>(self, params: P, result: impl Into) + pub fn function<'b, P, T>(self, params: P, result: impl Into) where P: IntoIterator, T)>, P::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let params = params.into_iter(); - self.0.push(0x4c); + self.0.push(0x40); params.len().encode(self.0); for (name, ty) in params { @@ -245,24 +397,18 @@ impl<'a> TypeEncoder<'a> { result.into().encode(self.0); } - /// Define a value type. - pub fn value(self, ty: impl Into) { - self.0.push(0x4b); - ty.into().encode(self.0); - } - - /// Define an interface type. + /// Define a defined component type. /// - /// The returned encoder must be finished before adding another type. + /// The returned encoder must be used before adding another type. #[must_use = "the encoder must be used to encode the type"] - pub fn interface_type(self) -> InterfaceTypeEncoder<'a> { - InterfaceTypeEncoder(self.0) + pub fn defined_type(self) -> ComponentDefinedTypeEncoder<'a> { + ComponentDefinedTypeEncoder(self.0) } } -/// Represents a primitive interface type. +/// Represents a primitive component value type. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum PrimitiveInterfaceType { +pub enum PrimitiveValType { /// The type is the unit type. Unit, /// The type is a boolean. @@ -293,7 +439,7 @@ pub enum PrimitiveInterfaceType { String, } -impl Encode for PrimitiveInterfaceType { +impl Encode for PrimitiveValType { fn encode(&self, sink: &mut Vec) { sink.push(match self { Self::Unit => 0x7f, @@ -314,18 +460,18 @@ impl Encode for PrimitiveInterfaceType { } } -/// Represents a reference to an interface type. +/// Represents a component value type. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum InterfaceTypeRef { - /// The reference is to a primitive type. - Primitive(PrimitiveInterfaceType), - /// The reference is to a type index. +pub enum ComponentValType { + /// The value is a primitive type. + Primitive(PrimitiveValType), + /// The value is to a defined value type. /// - /// The type index must be to an interface type. + /// The type index must be to a value type. Type(u32), } -impl Encode for InterfaceTypeRef { +impl Encode for ComponentValType { fn encode(&self, sink: &mut Vec) { match self { Self::Primitive(ty) => ty.encode(sink), @@ -334,19 +480,19 @@ impl Encode for InterfaceTypeRef { } } -impl From for InterfaceTypeRef { - fn from(ty: PrimitiveInterfaceType) -> Self { +impl From for ComponentValType { + fn from(ty: PrimitiveValType) -> Self { Self::Primitive(ty) } } -/// Used for encoding interface types. +/// Used for encoding component defined types. #[derive(Debug)] -pub struct InterfaceTypeEncoder<'a>(&'a mut Vec); +pub struct ComponentDefinedTypeEncoder<'a>(&'a mut Vec); -impl InterfaceTypeEncoder<'_> { - /// Define a primitive interface type. - pub fn primitive(self, ty: PrimitiveInterfaceType) { +impl ComponentDefinedTypeEncoder<'_> { + /// Define a primitive value type. + pub fn primitive(self, ty: PrimitiveValType) { ty.encode(self.0); } @@ -355,7 +501,7 @@ impl InterfaceTypeEncoder<'_> { where F: IntoIterator, F::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let fields = fields.into_iter(); self.0.push(0x71); @@ -371,15 +517,15 @@ impl InterfaceTypeEncoder<'_> { where C: IntoIterator)>, C::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let cases = cases.into_iter(); self.0.push(0x70); cases.len().encode(self.0); - for (name, ty, default_to) in cases { + for (name, ty, refines) in cases { name.encode(self.0); ty.into().encode(self.0); - if let Some(default) = default_to { + if let Some(default) = refines { self.0.push(0x01); default.encode(self.0); } else { @@ -389,7 +535,7 @@ impl InterfaceTypeEncoder<'_> { } /// Define a list type. - pub fn list(self, ty: impl Into) { + pub fn list(self, ty: impl Into) { self.0.push(0x6f); ty.into().encode(self.0); } @@ -399,7 +545,7 @@ impl InterfaceTypeEncoder<'_> { where I: IntoIterator, I::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let types = types.into_iter(); self.0.push(0x6E); @@ -442,7 +588,7 @@ impl InterfaceTypeEncoder<'_> { where I: IntoIterator, I::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let types = types.into_iter(); self.0.push(0x6B); @@ -453,13 +599,13 @@ impl InterfaceTypeEncoder<'_> { } /// Define an option type. - pub fn option(self, ty: impl Into) { + pub fn option(self, ty: impl Into) { self.0.push(0x6A); ty.into().encode(self.0); } /// Define an expected type. - pub fn expected(self, ok: impl Into, error: impl Into) { + pub fn expected(self, ok: impl Into, error: impl Into) { self.0.push(0x69); ok.into().encode(self.0); error.into().encode(self.0); @@ -471,16 +617,17 @@ impl InterfaceTypeEncoder<'_> { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveInterfaceType}; +/// use wasm_encoder::{Component, ComponentTypeSection, PrimitiveValType}; /// /// let mut types = ComponentTypeSection::new(); /// +/// // Define a function type of `[string, string] -> string`. /// types.function( /// [ -/// (Some("a"), PrimitiveInterfaceType::String), -/// (Some("b"), PrimitiveInterfaceType::String) +/// (Some("a"), PrimitiveValType::String), +/// (Some("b"), PrimitiveValType::String) /// ], -/// PrimitiveInterfaceType::String +/// PrimitiveValType::String /// ); /// /// let mut component = Component::new(); @@ -514,15 +661,9 @@ impl ComponentTypeSection { /// /// The returned encoder must be finished before adding another type. #[must_use = "the encoder must be used to encode the type"] - pub fn ty(&mut self) -> TypeEncoder<'_> { + pub fn ty(&mut self) -> ComponentTypeEncoder<'_> { self.num_added += 1; - TypeEncoder(&mut self.bytes) - } - - /// Define a module type in this type section. - pub fn module(&mut self, ty: &ModuleType) -> &mut Self { - self.ty().module(ty); - self + ComponentTypeEncoder(&mut self.bytes) } /// Define a component type in this type section. @@ -541,36 +682,34 @@ impl ComponentTypeSection { pub fn function<'a, P, T>( &mut self, params: P, - result: impl Into, + result: impl Into, ) -> &mut Self where P: IntoIterator, T)>, P::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { self.ty().function(params, result); self } - /// Define a value type in this type section. - pub fn value(&mut self, ty: impl Into) -> &mut Self { - self.ty().value(ty); - self - } - - /// Define an interface type in this type section. + /// Add a component defined type to this type section. /// - /// The returned encoder must be finished before adding another type. + /// The returned encoder must be used before adding another type. #[must_use = "the encoder must be used to encode the type"] - pub fn interface_type(&mut self) -> InterfaceTypeEncoder<'_> { - self.ty().interface_type() + pub fn defined_type(&mut self) -> ComponentDefinedTypeEncoder<'_> { + self.ty().defined_type() } } impl Encode for ComponentTypeSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, ComponentSectionId::Type, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl ComponentSection for ComponentTypeSection {} +impl ComponentSection for ComponentTypeSection { + fn id(&self) -> u8 { + ComponentSectionId::Type.into() + } +} diff --git a/crates/wasm-encoder/src/core.rs b/crates/wasm-encoder/src/core.rs index b89464af33..e03bd9363e 100644 --- a/crates/wasm-encoder/src/core.rs +++ b/crates/wasm-encoder/src/core.rs @@ -1,4 +1,5 @@ mod code; +mod custom; mod data; mod elements; mod exports; @@ -14,6 +15,7 @@ mod tags; mod types; pub use code::*; +pub use custom::*; pub use data::*; pub use elements::*; pub use exports::*; @@ -30,12 +32,21 @@ pub use types::*; use crate::Encode; +pub(crate) const CORE_FUNCTION_SORT: u8 = 0x00; +pub(crate) const CORE_TABLE_SORT: u8 = 0x01; +pub(crate) const CORE_MEMORY_SORT: u8 = 0x02; +pub(crate) const CORE_GLOBAL_SORT: u8 = 0x03; +pub(crate) const CORE_TAG_SORT: u8 = 0x04; + /// A WebAssembly module section. /// /// Various builders defined in this crate already implement this trait, but you /// can also implement it yourself for your own custom section builders, or use /// `RawSection` to use a bunch of raw bytes as a section. -pub trait Section: Encode {} +pub trait Section: Encode { + /// Gets the section identifier for this section. + fn id(&self) -> u8; +} /// Known section identifiers of WebAssembly modules. #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] @@ -119,6 +130,7 @@ impl Module { /// to use this crate to easily construct test cases for bad Wasm module /// encodings. pub fn section(&mut self, section: &impl Section) -> &mut Self { + self.bytes.push(section.id()); section.encode(&mut self.bytes); self } diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs index a8d712be3d..3bb3ef53a6 100644 --- a/crates/wasm-encoder/src/core/code.rs +++ b/crates/wasm-encoder/src/core/code.rs @@ -96,11 +96,15 @@ impl CodeSection { impl Encode for CodeSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Code, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for CodeSection {} +impl Section for CodeSection { + fn id(&self) -> u8 { + SectionId::Code.into() + } +} /// An encoder for a function body within the code section. /// diff --git a/crates/wasm-encoder/src/custom.rs b/crates/wasm-encoder/src/core/custom.rs similarity index 82% rename from crates/wasm-encoder/src/custom.rs rename to crates/wasm-encoder/src/core/custom.rs index 7217cdabbf..47d78d458c 100644 --- a/crates/wasm-encoder/src/custom.rs +++ b/crates/wasm-encoder/src/core/custom.rs @@ -1,4 +1,4 @@ -use crate::{encoding_size, ComponentSection, Encode, Section, SectionId}; +use crate::{encoding_size, Encode, Section, SectionId}; /// A custom section holding arbitrary data. #[derive(Clone, Debug)] @@ -12,15 +12,17 @@ pub struct CustomSection<'a> { impl Encode for CustomSection<'_> { fn encode(&self, sink: &mut Vec) { let encoded_name_len = encoding_size(u32::try_from(self.name.len()).unwrap()); - SectionId::Custom.encode(sink); (encoded_name_len + self.name.len() + self.data.len()).encode(sink); self.name.encode(sink); sink.extend(self.data); } } -impl Section for CustomSection<'_> {} -impl ComponentSection for CustomSection<'_> {} +impl Section for CustomSection<'_> { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} #[cfg(test)] mod tests { @@ -38,8 +40,6 @@ mod tests { #[rustfmt::skip] assert_eq!(encoded, vec![ - // Section ID - 0, // LEB128 length of section. 9, // LEB128 length of name. diff --git a/crates/wasm-encoder/src/core/data.rs b/crates/wasm-encoder/src/core/data.rs index a7f6393348..473599e66c 100644 --- a/crates/wasm-encoder/src/core/data.rs +++ b/crates/wasm-encoder/src/core/data.rs @@ -155,11 +155,15 @@ impl DataSection { impl Encode for DataSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Data, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for DataSection {} +impl Section for DataSection { + fn id(&self) -> u8 { + SectionId::Data.into() + } +} /// An encoder for the data count section. #[derive(Clone, Copy, Debug)] @@ -170,10 +174,13 @@ pub struct DataCountSection { impl Encode for DataCountSection { fn encode(&self, sink: &mut Vec) { - SectionId::DataCount.encode(sink); encoding_size(self.count).encode(sink); self.count.encode(sink); } } -impl Section for DataCountSection {} +impl Section for DataCountSection { + fn id(&self) -> u8 { + SectionId::DataCount.into() + } +} diff --git a/crates/wasm-encoder/src/core/elements.rs b/crates/wasm-encoder/src/core/elements.rs index 11b85e22fb..a54b8fed1d 100644 --- a/crates/wasm-encoder/src/core/elements.rs +++ b/crates/wasm-encoder/src/core/elements.rs @@ -233,8 +233,12 @@ impl ElementSection { impl Encode for ElementSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Element, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for ElementSection {} +impl Section for ElementSection { + fn id(&self) -> u8 { + SectionId::Element.into() + } +} diff --git a/crates/wasm-encoder/src/core/exports.rs b/crates/wasm-encoder/src/core/exports.rs index 0f54db5cbd..0b8006655f 100644 --- a/crates/wasm-encoder/src/core/exports.rs +++ b/crates/wasm-encoder/src/core/exports.rs @@ -1,34 +1,32 @@ +use super::{ + CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, +}; use crate::{encode_section, Encode, Section, SectionId}; -/// Represents an export from a WebAssembly module. +/// Represents the kind of an export from a WebAssembly module. #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Export { +pub enum ExportKind { /// The export is a function. - Function(u32), + Func, /// The export is a table. - Table(u32), + Table, /// The export is a memory. - Memory(u32), + Memory, /// The export is a global. - Global(u32), + Global, /// The export is a tag. - /// - /// This variant is used with the exception handling proposal. - Tag(u32), + Tag, } -impl Encode for Export { +impl Encode for ExportKind { fn encode(&self, sink: &mut Vec) { - let (kind, index) = match self { - Self::Function(i) => (0x00, *i), - Self::Table(i) => (0x01, *i), - Self::Memory(i) => (0x02, *i), - Self::Global(i) => (0x03, *i), - Self::Tag(i) => (0x04, *i), - }; - - sink.push(kind); - index.encode(sink); + sink.push(match self { + Self::Func => CORE_FUNCTION_SORT, + Self::Table => CORE_TABLE_SORT, + Self::Memory => CORE_MEMORY_SORT, + Self::Global => CORE_GLOBAL_SORT, + Self::Tag => CORE_TAG_SORT, + }); } } @@ -37,10 +35,10 @@ impl Encode for Export { /// # Example /// /// ```rust -/// use wasm_encoder::{Module, ExportSection, Export}; +/// use wasm_encoder::{Module, ExportSection, ExportKind}; /// /// let mut exports = ExportSection::new(); -/// exports.export("foo", Export::Function(0)); +/// exports.export("foo", ExportKind::Func, 0); /// /// let mut module = Module::new(); /// module.section(&exports); @@ -70,9 +68,10 @@ impl ExportSection { } /// Define an export in the export section. - pub fn export(&mut self, name: &str, export: Export) -> &mut Self { + pub fn export(&mut self, name: &str, kind: ExportKind, index: u32) -> &mut Self { name.encode(&mut self.bytes); - export.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); self.num_added += 1; self } @@ -80,8 +79,12 @@ impl ExportSection { impl Encode for ExportSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Export, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for ExportSection {} +impl Section for ExportSection { + fn id(&self) -> u8 { + SectionId::Export.into() + } +} diff --git a/crates/wasm-encoder/src/core/functions.rs b/crates/wasm-encoder/src/core/functions.rs index 032d66c1b0..e21d8c10a7 100644 --- a/crates/wasm-encoder/src/core/functions.rs +++ b/crates/wasm-encoder/src/core/functions.rs @@ -52,8 +52,12 @@ impl FunctionSection { impl Encode for FunctionSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Function, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for FunctionSection {} +impl Section for FunctionSection { + fn id(&self) -> u8 { + SectionId::Function.into() + } +} diff --git a/crates/wasm-encoder/src/core/globals.rs b/crates/wasm-encoder/src/core/globals.rs index 6fbf70e92a..5ee20c03fb 100644 --- a/crates/wasm-encoder/src/core/globals.rs +++ b/crates/wasm-encoder/src/core/globals.rs @@ -64,11 +64,15 @@ impl GlobalSection { impl Encode for GlobalSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Global, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for GlobalSection {} +impl Section for GlobalSection { + fn id(&self) -> u8 { + SectionId::Global.into() + } +} /// A global's type. #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] diff --git a/crates/wasm-encoder/src/core/imports.rs b/crates/wasm-encoder/src/core/imports.rs index fde83bbd90..ca54f2f00c 100644 --- a/crates/wasm-encoder/src/core/imports.rs +++ b/crates/wasm-encoder/src/core/imports.rs @@ -1,5 +1,6 @@ use crate::{ encode_section, Encode, GlobalType, MemoryType, Section, SectionId, TableType, TagType, + CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_MEMORY_SORT, CORE_TABLE_SORT, CORE_TAG_SORT, }; /// The type of an entity. @@ -25,23 +26,23 @@ impl Encode for EntityType { fn encode(&self, sink: &mut Vec) { match self { Self::Function(i) => { - sink.push(0x00); + sink.push(CORE_FUNCTION_SORT); i.encode(sink); } Self::Table(t) => { - sink.push(0x01); + sink.push(CORE_TABLE_SORT); t.encode(sink); } Self::Memory(t) => { - sink.push(0x02); + sink.push(CORE_MEMORY_SORT); t.encode(sink); } Self::Global(t) => { - sink.push(0x03); + sink.push(CORE_GLOBAL_SORT); t.encode(sink); } Self::Tag(t) => { - sink.push(0x04); + sink.push(CORE_TAG_SORT); t.encode(sink); } } @@ -129,8 +130,12 @@ impl ImportSection { impl Encode for ImportSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Import, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for ImportSection {} +impl Section for ImportSection { + fn id(&self) -> u8 { + SectionId::Import.into() + } +} diff --git a/crates/wasm-encoder/src/core/linking.rs b/crates/wasm-encoder/src/core/linking.rs index cd204526d9..3309277be3 100644 --- a/crates/wasm-encoder/src/core/linking.rs +++ b/crates/wasm-encoder/src/core/linking.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, CustomSection, Encode, Section}; +use crate::{encode_section, CustomSection, Encode, Section, SectionId}; const VERSION: u32 = 2; @@ -79,7 +79,11 @@ impl Encode for LinkingSection { } } -impl Section for LinkingSection {} +impl Section for LinkingSection { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} #[allow(unused)] const WASM_SEGMENT_INFO: u8 = 5; @@ -237,7 +241,8 @@ impl SymbolTable { impl Encode for SymbolTable { fn encode(&self, sink: &mut Vec) { - encode_section(sink, WASM_SYMBOL_TABLE, self.num_added, &self.bytes); + sink.push(WASM_SYMBOL_TABLE); + encode_section(sink, self.num_added, &self.bytes); } } diff --git a/crates/wasm-encoder/src/core/memories.rs b/crates/wasm-encoder/src/core/memories.rs index 678be0e5f8..c37b8997f6 100644 --- a/crates/wasm-encoder/src/core/memories.rs +++ b/crates/wasm-encoder/src/core/memories.rs @@ -53,11 +53,15 @@ impl MemorySection { impl Encode for MemorySection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Memory, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for MemorySection {} +impl Section for MemorySection { + fn id(&self) -> u8 { + SectionId::Memory.into() + } +} /// A memory's type. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] diff --git a/crates/wasm-encoder/src/core/names.rs b/crates/wasm-encoder/src/core/names.rs index 240b7d14d9..880925918e 100644 --- a/crates/wasm-encoder/src/core/names.rs +++ b/crates/wasm-encoder/src/core/names.rs @@ -1,4 +1,4 @@ -use crate::{encoding_size, CustomSection, Encode, Section}; +use crate::{encoding_size, CustomSection, Encode, Section, SectionId}; /// An encoder for the custom `name` section. /// @@ -161,7 +161,11 @@ impl Encode for NameSection { } } -impl Section for NameSection {} +impl Section for NameSection { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} /// A map used to name items in a wasm module, organized by naming each /// individual index. diff --git a/crates/wasm-encoder/src/core/start.rs b/crates/wasm-encoder/src/core/start.rs index 7a7677d6b4..8f12c0d0ef 100644 --- a/crates/wasm-encoder/src/core/start.rs +++ b/crates/wasm-encoder/src/core/start.rs @@ -27,10 +27,13 @@ pub struct StartSection { impl Encode for StartSection { fn encode(&self, sink: &mut Vec) { - SectionId::Start.encode(sink); encoding_size(self.function_index).encode(sink); self.function_index.encode(sink); } } -impl Section for StartSection {} +impl Section for StartSection { + fn id(&self) -> u8 { + SectionId::Start.into() + } +} diff --git a/crates/wasm-encoder/src/core/tables.rs b/crates/wasm-encoder/src/core/tables.rs index ba2c6c09a6..57a7628a5d 100644 --- a/crates/wasm-encoder/src/core/tables.rs +++ b/crates/wasm-encoder/src/core/tables.rs @@ -53,11 +53,15 @@ impl TableSection { impl Encode for TableSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Table, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for TableSection {} +impl Section for TableSection { + fn id(&self) -> u8 { + SectionId::Table.into() + } +} /// A table's type. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] diff --git a/crates/wasm-encoder/src/core/tags.rs b/crates/wasm-encoder/src/core/tags.rs index 071f6ecf34..413055f2af 100644 --- a/crates/wasm-encoder/src/core/tags.rs +++ b/crates/wasm-encoder/src/core/tags.rs @@ -50,11 +50,15 @@ impl TagSection { impl Encode for TagSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Tag, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for TagSection {} +impl Section for TagSection { + fn id(&self) -> u8 { + SectionId::Tag.into() + } +} /// Represents a tag kind. #[repr(u8)] diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs index 5316d507c8..d99e22ea94 100644 --- a/crates/wasm-encoder/src/core/types.rs +++ b/crates/wasm-encoder/src/core/types.rs @@ -1,6 +1,6 @@ use crate::{encode_section, Encode, Section, SectionId}; -/// The type of a value. +/// The type of a core WebAssembly value. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[repr(u8)] pub enum ValType { @@ -40,23 +40,6 @@ impl Encode for ValType { } } -pub(crate) fn encode_functype(bytes: &mut Vec, params: P, results: R) -where - P: IntoIterator, - P::IntoIter: ExactSizeIterator, - R: IntoIterator, - R::IntoIter: ExactSizeIterator, -{ - let params = params.into_iter(); - let results = results.into_iter(); - - bytes.push(0x60); - params.len().encode(bytes); - bytes.extend(params.map(u8::from)); - results.len().encode(bytes); - bytes.extend(results.map(u8::from)); -} - /// An encoder for the type section of WebAssembly modules. /// /// # Example @@ -103,7 +86,14 @@ impl TypeSection { R: IntoIterator, R::IntoIter: ExactSizeIterator, { - encode_functype(&mut self.bytes, params, results); + let params = params.into_iter(); + let results = results.into_iter(); + + self.bytes.push(0x60); + params.len().encode(&mut self.bytes); + self.bytes.extend(params.map(u8::from)); + results.len().encode(&mut self.bytes); + self.bytes.extend(results.map(u8::from)); self.num_added += 1; self } @@ -111,8 +101,12 @@ impl TypeSection { impl Encode for TypeSection { fn encode(&self, sink: &mut Vec) { - encode_section(sink, SectionId::Type, self.num_added, &self.bytes); + encode_section(sink, self.num_added, &self.bytes); } } -impl Section for TypeSection {} +impl Section for TypeSection { + fn id(&self) -> u8 { + SectionId::Type.into() + } +} diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs index fa464783e5..d8840f7934 100644 --- a/crates/wasm-encoder/src/lib.rs +++ b/crates/wasm-encoder/src/lib.rs @@ -26,7 +26,7 @@ //! //! ``` //! use wasm_encoder::{ -//! CodeSection, Export, ExportSection, Function, FunctionSection, Instruction, +//! CodeSection, ExportKind, ExportSection, Function, FunctionSection, Instruction, //! Module, TypeSection, ValType, //! }; //! @@ -47,7 +47,7 @@ //! //! // Encode the export section. //! let mut exports = ExportSection::new(); -//! exports.export("f", Export::Function(0)); +//! exports.export("f", ExportKind::Func, 0); //! module.section(&exports); //! //! // Encode the code section. @@ -72,12 +72,10 @@ mod component; mod core; -mod custom; mod raw; pub use self::component::*; pub use self::core::*; -pub use self::custom::*; pub use self::raw::*; /// Implemented by types that can be encoded into a byte sink. @@ -151,8 +149,7 @@ fn encoding_size(n: u32) -> usize { leb128::write::unsigned(&mut &mut buf[..], n.into()).unwrap() } -fn encode_section(sink: &mut Vec, id: impl Into, count: u32, bytes: &[u8]) { - sink.push(id.into()); +fn encode_section(sink: &mut Vec, count: u32, bytes: &[u8]) { (encoding_size(count) + bytes.len()).encode(sink); count.encode(sink); sink.extend(bytes); diff --git a/crates/wasm-encoder/src/raw.rs b/crates/wasm-encoder/src/raw.rs index c69bb57fef..a1323ca88e 100644 --- a/crates/wasm-encoder/src/raw.rs +++ b/crates/wasm-encoder/src/raw.rs @@ -2,7 +2,7 @@ use crate::{ComponentSection, Encode, Section}; /// A section made up of uninterpreted, raw bytes. /// -/// Allows you to splat any data into module or component. +/// Allows you to splat any data into a module or component. #[derive(Clone, Copy, Debug)] pub struct RawSection<'a> { /// The id for this section. @@ -13,10 +13,18 @@ pub struct RawSection<'a> { impl Encode for RawSection<'_> { fn encode(&self, sink: &mut Vec) { - sink.push(self.id); self.data.encode(sink); } } -impl Section for RawSection<'_> {} -impl ComponentSection for RawSection<'_> {} +impl Section for RawSection<'_> { + fn id(&self) -> u8 { + self.id + } +} + +impl ComponentSection for RawSection<'_> { + fn id(&self) -> u8 { + self.id + } +} diff --git a/crates/wasm-mutate/src/module.rs b/crates/wasm-mutate/src/module.rs index 1002a0ab61..024cb6c1f6 100644 --- a/crates/wasm-mutate/src/module.rs +++ b/crates/wasm-mutate/src/module.rs @@ -1,7 +1,6 @@ use crate::{Error, Result}; use std::convert::TryFrom; use wasm_encoder::{BlockType, ValType}; -use wasmparser::{Type, TypeDef}; #[derive(Debug, Clone, PartialEq)] pub enum PrimitiveTypeInfo { @@ -27,26 +26,26 @@ pub enum TypeInfo { // TODO: module linking support will require instance and module types. } -impl From for PrimitiveTypeInfo { - fn from(value: Type) -> Self { +impl From for PrimitiveTypeInfo { + fn from(value: wasmparser::ValType) -> Self { match value { - Type::I32 => PrimitiveTypeInfo::I32, - Type::I64 => PrimitiveTypeInfo::I64, - Type::F32 => PrimitiveTypeInfo::F32, - Type::F64 => PrimitiveTypeInfo::F64, - Type::V128 => PrimitiveTypeInfo::V128, - Type::FuncRef => PrimitiveTypeInfo::FuncRef, - Type::ExternRef => PrimitiveTypeInfo::ExternRef, + wasmparser::ValType::I32 => PrimitiveTypeInfo::I32, + wasmparser::ValType::I64 => PrimitiveTypeInfo::I64, + wasmparser::ValType::F32 => PrimitiveTypeInfo::F32, + wasmparser::ValType::F64 => PrimitiveTypeInfo::F64, + wasmparser::ValType::V128 => PrimitiveTypeInfo::V128, + wasmparser::ValType::FuncRef => PrimitiveTypeInfo::FuncRef, + wasmparser::ValType::ExternRef => PrimitiveTypeInfo::ExternRef, } } } -impl TryFrom for TypeInfo { +impl TryFrom for TypeInfo { type Error = Error; - fn try_from(value: TypeDef) -> Result { + fn try_from(value: wasmparser::Type) -> Result { match value { - TypeDef::Func(ft) => Ok(TypeInfo::Func(FuncInfo { + wasmparser::Type::Func(ft) => Ok(TypeInfo::Func(FuncInfo { params: ft .params .iter() @@ -62,15 +61,15 @@ impl TryFrom for TypeInfo { } } -pub fn map_type(tpe: Type) -> Result { +pub fn map_type(tpe: wasmparser::ValType) -> Result { match tpe { - Type::I32 => Ok(ValType::I32), - Type::I64 => Ok(ValType::I64), - Type::F32 => Ok(ValType::F32), - Type::F64 => Ok(ValType::F64), - Type::V128 => Ok(ValType::V128), - Type::FuncRef => Ok(ValType::FuncRef), - Type::ExternRef => Ok(ValType::ExternRef), + wasmparser::ValType::I32 => Ok(ValType::I32), + wasmparser::ValType::I64 => Ok(ValType::I64), + wasmparser::ValType::F32 => Ok(ValType::F32), + wasmparser::ValType::F64 => Ok(ValType::F64), + wasmparser::ValType::V128 => Ok(ValType::V128), + wasmparser::ValType::FuncRef => Ok(ValType::FuncRef), + wasmparser::ValType::ExternRef => Ok(ValType::ExternRef), } } diff --git a/crates/wasm-mutate/src/mutators/add_type.rs b/crates/wasm-mutate/src/mutators/add_type.rs index a3a06776fc..67e6ea59d0 100644 --- a/crates/wasm-mutate/src/mutators/add_type.rs +++ b/crates/wasm-mutate/src/mutators/add_type.rs @@ -57,7 +57,7 @@ impl Mutator for AddTypeMutator { for _ in 0..reader.get_count() { let ty = reader.read()?; match ty { - wasmparser::TypeDef::Func(ty) => { + wasmparser::Type::Func(ty) => { let params = ty .params .iter() @@ -87,15 +87,15 @@ impl Mutator for AddTypeMutator { } } -fn translate_type(ty: &wasmparser::Type) -> Result { +fn translate_type(ty: &wasmparser::ValType) -> Result { Ok(match ty { - wasmparser::Type::I32 => wasm_encoder::ValType::I32, - wasmparser::Type::I64 => wasm_encoder::ValType::I64, - wasmparser::Type::F32 => wasm_encoder::ValType::F32, - wasmparser::Type::F64 => wasm_encoder::ValType::F64, - wasmparser::Type::V128 => wasm_encoder::ValType::V128, - wasmparser::Type::FuncRef => wasm_encoder::ValType::FuncRef, - wasmparser::Type::ExternRef => wasm_encoder::ValType::ExternRef, + wasmparser::ValType::I32 => wasm_encoder::ValType::I32, + wasmparser::ValType::I64 => wasm_encoder::ValType::I64, + wasmparser::ValType::F32 => wasm_encoder::ValType::F32, + wasmparser::ValType::F64 => wasm_encoder::ValType::F64, + wasmparser::ValType::V128 => wasm_encoder::ValType::V128, + wasmparser::ValType::FuncRef => wasm_encoder::ValType::FuncRef, + wasmparser::ValType::ExternRef => wasm_encoder::ValType::ExternRef, }) } diff --git a/crates/wasm-mutate/src/mutators/modify_data.rs b/crates/wasm-mutate/src/mutators/modify_data.rs index ee5ee46fb1..760c5cadad 100644 --- a/crates/wasm-mutate/src/mutators/modify_data.rs +++ b/crates/wasm-mutate/src/mutators/modify_data.rs @@ -1,8 +1,7 @@ use super::translate::InitExprKind; use super::Mutator; -use crate::{Result, WasmMutate}; - use crate::mutators::{DefaultTranslator, Translator}; +use crate::{Result, WasmMutate}; use rand::Rng; use wasm_encoder::{DataSection, DataSegment, DataSegmentMode, Module}; use wasmparser::{DataKind, DataSectionReader}; @@ -37,7 +36,7 @@ impl Mutator for ModifyDataMutator { } => { offset = DefaultTranslator.translate_init_expr( init_expr, - &wasmparser::Type::I32, + &wasmparser::ValType::I32, InitExprKind::DataOffset, )?; DataSegmentMode::Active { diff --git a/crates/wasm-mutate/src/mutators/modify_init_exprs.rs b/crates/wasm-mutate/src/mutators/modify_init_exprs.rs index 1cfd260e35..96c2cae0b4 100644 --- a/crates/wasm-mutate/src/mutators/modify_init_exprs.rs +++ b/crates/wasm-mutate/src/mutators/modify_init_exprs.rs @@ -3,10 +3,9 @@ use crate::mutators::translate::{self, InitExprKind, Item, Translator}; use crate::{Error, Mutator, Result}; - use rand::Rng; use wasm_encoder::{ElementSection, GlobalSection, Instruction}; -use wasmparser::{ElementSectionReader, GlobalSectionReader, InitExpr, Operator, Type}; +use wasmparser::{ElementSectionReader, GlobalSectionReader, InitExpr, Operator, ValType}; #[derive(Copy, Clone)] pub enum InitExpressionMutator { @@ -60,10 +59,10 @@ impl<'cfg, 'wasm> Translator for InitTranslator<'cfg, 'wasm> { fn translate_init_expr( &mut self, e: &InitExpr<'_>, - ty: &Type, + ty: &ValType, kind: InitExprKind, ) -> Result> { - use {Instruction as I, Operator as O, Type as T}; + use {Instruction as I, Operator as O, ValType as T}; if kind != self.kind || !self.should_process() { return translate::init_expr(self.as_obj(), e); } diff --git a/crates/wasm-mutate/src/mutators/peephole/dfg.rs b/crates/wasm-mutate/src/mutators/peephole/dfg.rs index aa5f6bb5a9..69b991f488 100644 --- a/crates/wasm-mutate/src/mutators/peephole/dfg.rs +++ b/crates/wasm-mutate/src/mutators/peephole/dfg.rs @@ -762,12 +762,12 @@ impl<'a> DFGBuilder { } Operator::RefNull { - ty: wasmparser::Type::ExternRef, + ty: wasmparser::ValType::ExternRef, } => { self.push_node(Lang::RefNull(RefType::Extern), idx); } Operator::RefNull { - ty: wasmparser::Type::FuncRef, + ty: wasmparser::ValType::FuncRef, } => { self.push_node(Lang::RefNull(RefType::Func), idx); } diff --git a/crates/wasm-mutate/src/mutators/remove_export.rs b/crates/wasm-mutate/src/mutators/remove_export.rs index e124496318..a01df8a322 100644 --- a/crates/wasm-mutate/src/mutators/remove_export.rs +++ b/crates/wasm-mutate/src/mutators/remove_export.rs @@ -3,7 +3,7 @@ use super::Mutator; use crate::{Result, WasmMutate}; use rand::Rng; -use wasm_encoder::{Export, ExportSection, Module}; +use wasm_encoder::{ExportKind, ExportSection, Module}; use wasmparser::ExportSectionReader; /// Mutator that removes a random preexisting export @@ -31,16 +31,16 @@ impl Mutator for RemoveExportMutator { match export.kind { wasmparser::ExternalKind::Func => { - exports.export(export.name, Export::Function(export.index)); + exports.export(export.name, ExportKind::Func, export.index); } wasmparser::ExternalKind::Table => { - exports.export(export.name, Export::Table(export.index)); + exports.export(export.name, ExportKind::Table, export.index); } wasmparser::ExternalKind::Memory => { - exports.export(export.name, Export::Memory(export.index)); + exports.export(export.name, ExportKind::Memory, export.index); } wasmparser::ExternalKind::Global => { - exports.export(export.name, Export::Global(export.index)); + exports.export(export.name, ExportKind::Global, export.index); } _ => { panic!("Unknown export {:?}", export) diff --git a/crates/wasm-mutate/src/mutators/remove_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 3f41084bc8..2d953c2624 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -252,22 +252,22 @@ impl RemoveItem { let mut result = ExportSection::new(); for item in ExportSectionReader::new(section.data, 0)? { let item = item?; - let e = match &item.kind { + let (kind, index) = match &item.kind { ExternalKind::Func => { - Export::Function(self.remap(Item::Function, item.index)?) + (ExportKind::Func, self.remap(Item::Function, item.index)?) } ExternalKind::Table => { - Export::Table(self.remap(Item::Table, item.index)?) + (ExportKind::Table, self.remap(Item::Table, item.index)?) } ExternalKind::Memory => { - Export::Memory(self.remap(Item::Memory, item.index)?) + (ExportKind::Memory, self.remap(Item::Memory, item.index)?) } - ExternalKind::Tag => Export::Tag(self.remap(Item::Tag, item.index)?), + ExternalKind::Tag => (ExportKind::Tag, self.remap(Item::Tag, item.index)?), ExternalKind::Global => { - Export::Global(self.remap(Item::Global, item.index)?) + (ExportKind::Global, self.remap(Item::Global, item.index)?) } }; - result.export(item.name, e); + result.export(item.name, kind, index); } module.section(&result); }, diff --git a/crates/wasm-mutate/src/mutators/rename_export.rs b/crates/wasm-mutate/src/mutators/rename_export.rs index 68d16d76cd..9e6707bb6e 100644 --- a/crates/wasm-mutate/src/mutators/rename_export.rs +++ b/crates/wasm-mutate/src/mutators/rename_export.rs @@ -2,7 +2,7 @@ use super::Mutator; use crate::{Result, WasmMutate}; use rand::Rng; -use wasm_encoder::{Export, ExportSection, Module}; +use wasm_encoder::{ExportKind, ExportSection, Module}; use wasmparser::ExportSectionReader; /// Generates a random renaming of pre-existing exports. @@ -68,16 +68,16 @@ impl Mutator for RenameExportMutator { match export.kind { wasmparser::ExternalKind::Func => { - exports.export(new_name.as_str(), Export::Function(export.index)); + exports.export(new_name.as_str(), ExportKind::Func, export.index); } wasmparser::ExternalKind::Table => { - exports.export(new_name.as_str(), Export::Table(export.index)); + exports.export(new_name.as_str(), ExportKind::Table, export.index); } wasmparser::ExternalKind::Memory => { - exports.export(new_name.as_str(), Export::Memory(export.index)); + exports.export(new_name.as_str(), ExportKind::Memory, export.index); } wasmparser::ExternalKind::Global => { - exports.export(new_name.as_str(), Export::Global(export.index)); + exports.export(new_name.as_str(), ExportKind::Global, export.index); } _ => { panic!("Unknown export {:?}", export) diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index ba42398870..e108b6ac10 100644 --- a/crates/wasm-mutate/src/mutators/translate.rs +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -2,7 +2,7 @@ use crate::{Error, Result}; use wasm_encoder::*; use wasmparser::{ DataKind, ElementItem, ElementKind, FunctionBody, Global, InitExpr, MemoryImmediate, Operator, - Type, TypeDef, + Type, }; #[derive(Debug, Hash, Eq, PartialEq, Copy, Clone)] @@ -28,7 +28,7 @@ pub enum InitExprKind { pub trait Translator { fn as_obj(&mut self) -> &mut dyn Translator; - fn translate_type_def(&mut self, ty: TypeDef, s: &mut TypeSection) -> Result<()> { + fn translate_type_def(&mut self, ty: Type, s: &mut TypeSection) -> Result<()> { type_def(self.as_obj(), ty, s) } @@ -57,7 +57,7 @@ pub trait Translator { tag_type(self.as_obj(), ty) } - fn translate_ty(&mut self, t: &Type) -> Result { + fn translate_ty(&mut self, t: &wasmparser::ValType) -> Result { ty(self.as_obj(), t) } @@ -68,7 +68,7 @@ pub trait Translator { fn translate_init_expr( &mut self, e: &InitExpr<'_>, - _ty: &Type, + _ty: &wasmparser::ValType, _ctx: InitExprKind, ) -> Result> { init_expr(self.as_obj(), e) @@ -115,9 +115,10 @@ impl Translator for DefaultTranslator { self } } -pub fn type_def(t: &mut dyn Translator, ty: TypeDef, s: &mut TypeSection) -> Result<()> { + +pub fn type_def(t: &mut dyn Translator, ty: Type, s: &mut TypeSection) -> Result<()> { match ty { - TypeDef::Func(f) => { + Type::Func(f) => { s.function( f.params .iter() @@ -172,15 +173,15 @@ pub fn tag_type(t: &mut dyn Translator, ty: &wasmparser::TagType) -> Result Result { +pub fn ty(_t: &mut dyn Translator, ty: &wasmparser::ValType) -> Result { match ty { - Type::I32 => Ok(ValType::I32), - Type::I64 => Ok(ValType::I64), - Type::F32 => Ok(ValType::F32), - Type::F64 => Ok(ValType::F64), - Type::V128 => Ok(ValType::V128), - Type::FuncRef => Ok(ValType::FuncRef), - Type::ExternRef => Ok(ValType::ExternRef), + wasmparser::ValType::I32 => Ok(ValType::I32), + wasmparser::ValType::I64 => Ok(ValType::I64), + wasmparser::ValType::F32 => Ok(ValType::F32), + wasmparser::ValType::F64 => Ok(ValType::F64), + wasmparser::ValType::V128 => Ok(ValType::V128), + wasmparser::ValType::FuncRef => Ok(ValType::FuncRef), + wasmparser::ValType::ExternRef => Ok(ValType::ExternRef), } } @@ -217,7 +218,11 @@ pub fn element( table_index, init_expr, } => { - offset = t.translate_init_expr(init_expr, &Type::I32, InitExprKind::ElementOffset)?; + offset = t.translate_init_expr( + init_expr, + &wasmparser::ValType::I32, + InitExprKind::ElementOffset, + )?; ElementMode::Active { table: Some(t.remap(Item::Table, *table_index)?), offset: &offset, @@ -937,7 +942,11 @@ pub fn data(t: &mut dyn Translator, data: wasmparser::Data<'_>, s: &mut DataSect memory_index, init_expr, } => { - offset = t.translate_init_expr(init_expr, &Type::I32, InitExprKind::DataOffset)?; + offset = t.translate_init_expr( + init_expr, + &wasmparser::ValType::I32, + InitExprKind::DataOffset, + )?; DataSegmentMode::Active { memory_index: t.remap(Item::Memory, *memory_index)?, offset: &offset, diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs index edadb36e9e..712741a118 100644 --- a/crates/wasm-smith/src/component.rs +++ b/crates/wasm-smith/src/component.rs @@ -12,7 +12,7 @@ use std::{ marker, rc::Rc, }; -use wasm_encoder::{PrimitiveInterfaceType, ValType}; +use wasm_encoder::{ComponentTypeRef, ComponentValType, PrimitiveValType, TypeBounds, ValType}; mod encode; @@ -90,12 +90,19 @@ enum ComponentOrCoreFuncType { } impl ComponentOrCoreFuncType { - fn unwrap_core(self) -> Rc { + fn as_core(&self) -> &Rc { match self { - ComponentOrCoreFuncType::Core(f) => f, + ComponentOrCoreFuncType::Core(t) => t, ComponentOrCoreFuncType::Component(_) => panic!("not a core func type"), } } + + fn as_component(&self) -> &Rc { + match self { + ComponentOrCoreFuncType::Core(_) => panic!("not a component func type"), + ComponentOrCoreFuncType::Component(t) => t, + } + } } #[derive(Debug, Clone)] @@ -120,12 +127,12 @@ struct ComponentContext { // This component's function index space. funcs: Vec, - // Which entries in `funcs` are interface functions? - interface_funcs: Vec, + // Which entries in `funcs` are component functions? + component_funcs: Vec, - // Which entries in `funcs` are interface functions that only use scalar - // interface types? - scalar_interface_funcs: Vec, + // Which entries in `component_funcs` are component functions that only use scalar + // types? + scalar_component_funcs: Vec, // Which entries in `funcs` are core Wasm functions? // @@ -145,7 +152,7 @@ struct ComponentContext { // that section (in this case `j` must also be `0`, since a component // section can only contain a single nested component), or // - // * a `Section::Import` and we are referenceing the `j`th import in that + // * a `Section::Import` and we are referencing the `j`th import in that // section, which is guaranteed to be a component import. components: Vec<(usize, usize)>, @@ -161,7 +168,7 @@ struct ComponentContext { // section (in this case `j` must also be `0`, since a core section can // only contain a single nested module), or // - // * a `Section::Import` and we are referenceing the `j`th import in that + // * a `Section::Import` and we are referencing the `j`th import in that // section, which is guaranteed to be a module import. modules: Vec<(usize, usize)>, @@ -169,7 +176,7 @@ struct ComponentContext { instances: Vec, // This component's value index space. - values: Vec, + values: Vec, } impl ComponentContext { @@ -179,8 +186,8 @@ impl ComponentContext { num_imports: 0, import_names: HashSet::default(), funcs: vec![], - interface_funcs: vec![], - scalar_interface_funcs: vec![], + component_funcs: vec![], + scalar_component_funcs: vec![], core_funcs: vec![], components: vec![], modules: vec![], @@ -212,21 +219,17 @@ impl ComponentContext { #[derive(Debug, Default)] struct TypesScope { - // All types in this index space, regardless of kind. - types: Vec>, - - // The indices of all the entries in `types` that describe things that can - // be imported or exported at instantiation time. - def_types: Vec, + // All core types in this scope, regardless of kind. + core_types: Vec>, - // The indices of all the entries in `types` that are module types. + // The indices of all the entries in `core_types` that are module types. module_types: Vec, - // The indices of all the entries in `types` that are component types. - component_types: Vec, + // All component types in this index space, regardless of kind. + types: Vec>, - // The indices of all the entries in `types` that are instance types. - instance_types: Vec, + // The indices of all the entries in `types` that are defined value types. + defined_types: Vec, // The indices of all the entries in `types` that are func types. func_types: Vec, @@ -234,50 +237,66 @@ struct TypesScope { // A map from function types to their indices in the types space. func_type_to_indices: HashMap, Vec>, - // The indices of all the entries in `types` that are value types. - value_types: Vec, + // The indices of all the entries in `types` that are component types. + component_types: Vec, - // The indices of all the entries in `types` that are interface types. - interface_types: Vec, + // The indices of all the entries in `types` that are instance types. + instance_types: Vec, } impl TypesScope { fn push(&mut self, ty: Rc) -> u32 { let ty_idx = u32::try_from(self.types.len()).unwrap(); - let (is_def_type, kind_list) = match &*ty { - Type::Module(_) => (true, &mut self.module_types), - Type::Component(_) => (true, &mut self.component_types), - Type::Instance(_) => (true, &mut self.instance_types), + let kind_list = match &*ty { + Type::Defined(_) => &mut self.defined_types, Type::Func(func_ty) => { self.func_type_to_indices .entry(func_ty.clone()) .or_default() .push(ty_idx); - (true, &mut self.func_types) + &mut self.func_types } - Type::Value(_) => (true, &mut self.value_types), - Type::Interface(_) => (false, &mut self.interface_types), + Type::Component(_) => &mut self.component_types, + Type::Instance(_) => &mut self.instance_types, }; kind_list.push(ty_idx); - if is_def_type { - self.def_types.push(ty_idx); - } self.types.push(ty); ty_idx } + fn push_core(&mut self, ty: Rc) -> u32 { + let ty_idx = u32::try_from(self.core_types.len()).unwrap(); + + let kind_list = match &*ty { + CoreType::Module(_) => &mut self.module_types, + }; + kind_list.push(ty_idx); + + self.core_types.push(ty); + ty_idx + } + fn get(&self, index: u32) -> &Rc { &self.types[index as usize] } + fn get_core(&self, index: u32) -> &Rc { + &self.core_types[index as usize] + } + fn get_func(&self, index: u32) -> &Rc { match &**self.get(index) { Type::Func(f) => f, _ => panic!("get_func on non-function type"), } } + + fn can_ref_type(&self) -> bool { + // All component types and core module types may be referenced + !self.types.is_empty() || !self.module_types.is_empty() + } } impl<'a> Arbitrary<'a> for Component { @@ -327,7 +346,7 @@ impl Component { /// Construct a new `Component` using the given configuration. pub fn new(config: impl Config, u: &mut Unstructured) -> Result { let mut builder = ComponentBuilder::new(Rc::new(config)); - Ok(builder.build(u)?) + builder.build(u) } fn empty() -> Self { @@ -378,18 +397,19 @@ impl ComponentBuilder { // Only add any choice other than "finish what we've generated thus // far" when there is more arbitrary fuzzer data for us to consume. - if u.len() > 0 { + if !u.is_empty() { choices.push(Self::arbitrary_custom_section); // NB: we add each section as a choice even if we've already // generated our maximum number of entities in that section so that // we can exercise adding empty sections to the end of the module. + choices.push(Self::arbitrary_core_type_section); choices.push(Self::arbitrary_type_section); choices.push(Self::arbitrary_import_section); - choices.push(Self::arbitrary_func_section); + choices.push(Self::arbitrary_canonical_section); if self.total_modules < self.config.max_modules() { - choices.push(Self::arbitrary_core_section); + choices.push(Self::arbitrary_core_module_section); } if self.components.len() < self.config.max_nesting_depth() @@ -433,7 +453,7 @@ impl ComponentBuilder { self.arbitrary_import_section(u)?.unwrap_still_building(); } if self.component().funcs.len() < self.config.min_funcs() { - self.arbitrary_func_section(u)?.unwrap_still_building(); + self.arbitrary_canonical_section(u)?.unwrap_still_building(); } } self.fill_minimums = false; @@ -498,6 +518,59 @@ impl ComponentBuilder { } } + fn push_core_type(&mut self, ty: Rc) -> u32 { + match self.ensure_section( + |s| matches!(s, Section::CoreType(_)), + || Section::CoreType(CoreTypeSection { types: vec![] }), + ) { + Section::CoreType(CoreTypeSection { types }) => { + types.push(ty.clone()); + self.current_type_scope_mut().push_core(ty) + } + _ => unreachable!(), + } + } + + fn arbitrary_core_type_section(&mut self, u: &mut Unstructured) -> Result { + self.push_section(Section::CoreType(CoreTypeSection { types: vec![] })); + + let min = if self.fill_minimums { + self.config + .min_types() + .saturating_sub(self.current_type_scope().types.len()) + } else { + 0 + }; + + let max = self.config.max_types() - self.current_type_scope().types.len(); + + arbitrary_loop(u, min, max, |u| { + let mut type_fuel = self.config.max_type_size(); + let ty = self.arbitrary_core_type(u, &mut type_fuel)?; + self.push_core_type(ty); + Ok(true) + })?; + + Ok(Step::StillBuilding) + } + + fn arbitrary_core_type( + &self, + u: &mut Unstructured, + type_fuel: &mut u32, + ) -> Result> { + *type_fuel = type_fuel.saturating_sub(1); + if *type_fuel == 0 { + return Ok(Rc::new(CoreType::Module(Rc::new(ModuleType::default())))); + } + + let ty = match u.int_in_range::(0..=0)? { + 0 => CoreType::Module(self.arbitrary_module_type(u, type_fuel)?), + _ => unreachable!(), + }; + Ok(Rc::new(ty)) + } + fn arbitrary_type_section(&mut self, u: &mut Unstructured) -> Result { self.push_section(Section::Type(TypeSection { types: vec![] })); @@ -521,26 +594,104 @@ impl ComponentBuilder { Ok(Step::StillBuilding) } + fn arbitrary_type_ref<'a>( + &self, + u: &mut Unstructured<'a>, + for_import: bool, + for_type_def: bool, + ) -> Result> { + let mut choices: Vec Result> = Vec::new(); + let scope = self.current_type_scope(); + + if !scope.module_types.is_empty() + && (for_type_def || !for_import || self.total_modules < self.config.max_modules()) + { + choices.push(|me, u| { + Ok(ComponentTypeRef::Module( + *u.choose(&me.current_type_scope().module_types)?, + )) + }); + } + + // Types cannot be imported currently + if !for_import + && !scope.types.is_empty() + && (for_type_def || scope.types.len() < self.config.max_types()) + { + choices.push(|me, u| { + Ok(ComponentTypeRef::Type( + TypeBounds::Eq, + u.int_in_range( + 0..=u32::try_from(me.current_type_scope().types.len() - 1).unwrap(), + )?, + )) + }); + } + + if for_type_def || !for_import || self.total_values < self.config.max_values() { + choices.push(|me, u| Ok(ComponentTypeRef::Value(me.arbitrary_component_val_type(u)?))); + } + + if !scope.func_types.is_empty() + && (for_type_def + || !for_import + || self.component().num_funcs() < self.config.max_funcs()) + { + choices.push(|me, u| { + Ok(ComponentTypeRef::Func( + *u.choose(&me.current_type_scope().func_types)?, + )) + }); + } + + if !scope.component_types.is_empty() + && (for_type_def || !for_import || self.total_components < self.config.max_components()) + { + choices.push(|me, u| { + Ok(ComponentTypeRef::Component( + *u.choose(&me.current_type_scope().component_types)?, + )) + }); + } + + if !scope.instance_types.is_empty() + && (for_type_def || !for_import || self.total_instances < self.config.max_instances()) + { + choices.push(|me, u| { + Ok(ComponentTypeRef::Instance( + *u.choose(&me.current_type_scope().instance_types)?, + )) + }); + } + + if choices.is_empty() { + return Ok(None); + } + + let f = u.choose(&choices)?; + f(self, u).map(Option::Some) + } + fn arbitrary_type(&mut self, u: &mut Unstructured, type_fuel: &mut u32) -> Result> { *type_fuel = type_fuel.saturating_sub(1); if *type_fuel == 0 { - return Ok(Rc::new(Type::Value(self.arbitrary_value_type(u)?))); + return Ok(Rc::new(Type::Defined( + self.arbitrary_defined_type(u, type_fuel)?, + ))); } - let ty = match u.int_in_range::(0..=5)? { - 0 => Type::Module(self.arbitrary_module_type(u, type_fuel)?), - 1 => Type::Component(self.arbitrary_component_type(u, type_fuel)?), - 2 => Type::Instance(self.arbitrary_instance_type(u, type_fuel)?), - 3 => Type::Func(self.arbitrary_func_type(u, type_fuel)?), - 4 => Type::Value(self.arbitrary_value_type(u)?), - 5 => Type::Interface(self.arbitrary_interface_type(u, type_fuel)?), + let ty = match u.int_in_range::(0..=3)? { + 0 => Type::Defined(self.arbitrary_defined_type(u, type_fuel)?), + 1 => Type::Func(self.arbitrary_func_type(u, type_fuel)?), + 2 => Type::Component(self.arbitrary_component_type(u, type_fuel)?), + 3 => Type::Instance(self.arbitrary_instance_type(u, type_fuel)?), _ => unreachable!(), }; Ok(Rc::new(ty)) } fn arbitrary_module_type( - &mut self, + &self, u: &mut Unstructured, type_fuel: &mut u32, ) -> Result> { @@ -554,7 +705,7 @@ impl ComponentBuilder { let mut counts = EntityCounts::default(); // Special case the canonical ABI functions since certain types can only - // be passed across the interface types boundary if they exist and + // be passed across the component boundary if they exist and // randomly generating them is extremely unlikely. // `memory` @@ -615,7 +766,7 @@ impl ComponentBuilder { let mut entity_choices: Vec< fn( - &mut ComponentBuilder, + &ComponentBuilder, &mut Unstructured, &mut EntityCounts, &[Rc], @@ -650,8 +801,8 @@ impl ComponentBuilder { Some(x) => x, }; defs.push(ModuleTypeDef::Import(crate::core::Import { - module: module.into(), - field: field.into(), + module, + field, entity_type, })); } @@ -699,12 +850,12 @@ impl ComponentBuilder { } fn arbitrary_core_entity_type( - &mut self, + &self, u: &mut Unstructured, types: &[Rc], choices: &mut Vec< fn( - &mut ComponentBuilder, + &ComponentBuilder, &mut Unstructured, &mut EntityCounts, &[Rc], @@ -774,7 +925,7 @@ impl ComponentBuilder { return Ok(None); } - let f = u.choose(&choices)?; + let f = u.choose(choices)?; let ty = f(self, u, counts, types)?; Ok(Some(ty)) } @@ -783,27 +934,18 @@ impl ComponentBuilder { Ok(*u.choose(&self.core_valtypes)?) } - fn arbitrary_core_global_type( - &mut self, - u: &mut Unstructured, - ) -> Result { + fn arbitrary_core_global_type(&self, u: &mut Unstructured) -> Result { Ok(crate::core::GlobalType { val_type: self.arbitrary_core_valtype(u)?, mutable: u.arbitrary()?, }) } - fn arbitrary_core_table_type( - &mut self, - u: &mut Unstructured, - ) -> Result { + fn arbitrary_core_table_type(&self, u: &mut Unstructured) -> Result { crate::core::arbitrary_table_type(u, self.config()) } - fn arbitrary_core_memory_type( - &mut self, - u: &mut Unstructured, - ) -> Result { + fn arbitrary_core_memory_type(&self, u: &mut Unstructured) -> Result { crate::core::arbitrary_memtype(u, self.config()) } @@ -846,19 +988,12 @@ impl ComponentBuilder { return Ok(false); } - if !me.current_type_scope().def_types.is_empty() - && u.int_in_range::(0..=3)? == 0 - { + if me.current_type_scope().can_ref_type() && u.int_in_range::(0..=3)? == 0 { // Imports. let name = crate::unique_string(100, &mut imports, u)?; - let max_def_ty_idx = me.current_type_scope().def_types.len() - 1; - let def_ty_idx = u.int_in_range(0..=max_def_ty_idx)?; - let index = me.current_type_scope().def_types[def_ty_idx]; - let index = u32::try_from(index).unwrap(); - let ty = Rc::clone(me.current_type_scope().get(index)); defs.push(ComponentTypeDef::Import(Import { name, - ty: TypeIndex { index, ty }, + ty: me.arbitrary_type_ref(u, true, true)?.unwrap(), })); } else { // Type definitions, exports, and aliases. @@ -911,37 +1046,45 @@ impl ComponentBuilder { > = Vec::with_capacity(3); // Export. - if !self.current_type_scope().types.is_empty() { + if self.current_type_scope().can_ref_type() { choices.push(|me, exports, u, _type_fuel| { - let index = u.int_in_range( - 0..=u32::try_from(me.current_type_scope().types.len()).unwrap() - 1, - )?; - let ty = Rc::clone(me.current_type_scope().get(index)); Ok(InstanceTypeDef::Export { name: crate::unique_string(100, exports, u)?, - ty: TypeIndex { index, ty }, + ty: me.arbitrary_type_ref(u, false, true)?.unwrap(), }) }); } // Outer type alias. - if self.types.iter().any(|scope| !scope.types.is_empty()) { + if self + .types + .iter() + .any(|scope| !scope.types.is_empty() || !scope.core_types.is_empty()) + { choices.push(|me, _exports, u, _type_fuel| { let alias = me.arbitrary_outer_type_alias(u)?; - let (count, i) = match alias { + match &alias { Alias::Outer { - count, - i, - kind: OuterAliasKind::Type(_), - } => (count, i), + kind: OuterAliasKind::Type(ty), + .. + } => me.current_type_scope_mut().push(ty.clone()), + Alias::Outer { + kind: OuterAliasKind::CoreType(ty), + .. + } => me.current_type_scope_mut().push_core(ty.clone()), _ => unreachable!(), }; - let ty = me.outer_type(count, i).clone(); - me.current_type_scope_mut().push(ty); Ok(InstanceTypeDef::Alias(alias)) }); } + // Core type definition. + choices.push(|me, _exports, u, type_fuel| { + let ty = me.arbitrary_core_type(u, type_fuel)?; + me.current_type_scope_mut().push_core(ty.clone()); + Ok(InstanceTypeDef::CoreType(ty)) + }); + // Type definition. choices.push(|me, _exports, u, type_fuel| { let ty = me.arbitrary_type(u, type_fuel)?; @@ -959,7 +1102,7 @@ impl ComponentBuilder { .iter() .rev() .enumerate() - .filter(|(_, scope)| !scope.types.is_empty()) + .filter(|(_, scope)| !scope.types.is_empty() || !scope.core_types.is_empty()) .collect(); assert!( !non_empty_types_scopes.is_empty(), @@ -968,21 +1111,26 @@ impl ComponentBuilder { let (count, scope) = u.choose(&non_empty_types_scopes)?; let count = u32::try_from(*count).unwrap(); - assert!(!scope.types.is_empty()); + assert!(!scope.types.is_empty() || !scope.core_types.is_empty()); - let max_type_in_scope = u32::try_from(scope.types.len() - 1).unwrap(); + let max_type_in_scope = scope.types.len() + scope.core_types.len() - 1; let i = u.int_in_range(0..=max_type_in_scope)?; - let ty = Rc::clone(scope.get(i)); - Ok(Alias::Outer { - count, - i, - kind: OuterAliasKind::Type(ty), - }) + let (i, kind) = if i < scope.types.len() { + let i = u32::try_from(i).unwrap(); + (i, OuterAliasKind::Type(Rc::clone(scope.get(i)))) + } else if i - scope.types.len() < scope.core_types.len() { + let i = u32::try_from(i - scope.types.len()).unwrap(); + (i, OuterAliasKind::CoreType(Rc::clone(scope.get_core(i)))) + } else { + unreachable!() + }; + + Ok(Alias::Outer { count, i, kind }) } fn arbitrary_func_type( - &mut self, + &self, u: &mut Unstructured, type_fuel: &mut u32, ) -> Result> { @@ -998,69 +1146,62 @@ impl ComponentBuilder { Ok(true) })?; - let result = self.arbitrary_interface_type_ref(u)?; + let result = self.arbitrary_component_val_type(u)?; Ok(Rc::new(FuncType { params, result })) } - fn arbitrary_value_type(&mut self, u: &mut Unstructured) -> Result { - Ok(ValueType(self.arbitrary_interface_type_ref(u)?)) - } - - fn arbitrary_interface_type_ref(&mut self, u: &mut Unstructured) -> Result { - let max_choices = if self.current_type_scope().interface_types.is_empty() { + fn arbitrary_component_val_type(&self, u: &mut Unstructured) -> Result { + let max_choices = if self.current_type_scope().defined_types.is_empty() { 0 } else { 1 }; match u.int_in_range(0..=max_choices)? { - 0 => Ok(InterfaceTypeRef::Primitive( - self.arbitrary_primitive_interface_type(u)?, + 0 => Ok(ComponentValType::Primitive( + self.arbitrary_primitive_val_type(u)?, )), 1 => { - let index = *u.choose(&self.current_type_scope().interface_types)?; + let index = *u.choose(&self.current_type_scope().defined_types)?; let ty = Rc::clone(self.current_type_scope().get(index)); - Ok(InterfaceTypeRef::Type(TypeIndex { index, ty })) + Ok(ComponentValType::Type(index)) } _ => unreachable!(), } } - fn arbitrary_primitive_interface_type( - &mut self, - u: &mut Unstructured, - ) -> Result { + fn arbitrary_primitive_val_type(&self, u: &mut Unstructured) -> Result { match u.int_in_range(0..=13)? { - 0 => Ok(PrimitiveInterfaceType::Unit), - 1 => Ok(PrimitiveInterfaceType::Bool), - 2 => Ok(PrimitiveInterfaceType::S8), - 3 => Ok(PrimitiveInterfaceType::U8), - 4 => Ok(PrimitiveInterfaceType::S16), - 5 => Ok(PrimitiveInterfaceType::U16), - 6 => Ok(PrimitiveInterfaceType::S32), - 7 => Ok(PrimitiveInterfaceType::U32), - 8 => Ok(PrimitiveInterfaceType::S64), - 9 => Ok(PrimitiveInterfaceType::U64), - 10 => Ok(PrimitiveInterfaceType::Float32), - 11 => Ok(PrimitiveInterfaceType::Float64), - 12 => Ok(PrimitiveInterfaceType::Char), - 13 => Ok(PrimitiveInterfaceType::String), + 0 => Ok(PrimitiveValType::Unit), + 1 => Ok(PrimitiveValType::Bool), + 2 => Ok(PrimitiveValType::S8), + 3 => Ok(PrimitiveValType::U8), + 4 => Ok(PrimitiveValType::S16), + 5 => Ok(PrimitiveValType::U16), + 6 => Ok(PrimitiveValType::S32), + 7 => Ok(PrimitiveValType::U32), + 8 => Ok(PrimitiveValType::S64), + 9 => Ok(PrimitiveValType::U64), + 10 => Ok(PrimitiveValType::Float32), + 11 => Ok(PrimitiveValType::Float64), + 12 => Ok(PrimitiveValType::Char), + 13 => Ok(PrimitiveValType::String), _ => unreachable!(), } } fn arbitrary_named_type( - &mut self, + &self, u: &mut Unstructured, names: &mut HashSet, ) -> Result { let name = crate::unique_non_empty_string(100, names, u)?; - let ty = self.arbitrary_interface_type_ref(u)?; + let ty = self.arbitrary_component_val_type(u)?; Ok(NamedType { name, ty }) } fn arbitrary_optional_named_type( - &mut self, + &self, u: &mut Unstructured, names: &mut HashSet, ) -> Result { @@ -1069,12 +1210,12 @@ impl ComponentBuilder { } else { None }; - let ty = self.arbitrary_interface_type_ref(u)?; + let ty = self.arbitrary_component_val_type(u)?; Ok(OptionalNamedType { name, ty }) } fn arbitrary_record_type( - &mut self, + &self, u: &mut Unstructured, type_fuel: &mut u32, ) -> Result { @@ -1093,7 +1234,7 @@ impl ComponentBuilder { } fn arbitrary_variant_type( - &mut self, + &self, u: &mut Unstructured, type_fuel: &mut u32, ) -> Result { @@ -1119,17 +1260,13 @@ impl ComponentBuilder { Ok(VariantType { cases }) } - fn arbitrary_list_type(&mut self, u: &mut Unstructured) -> Result { + fn arbitrary_list_type(&self, u: &mut Unstructured) -> Result { Ok(ListType { - elem_ty: self.arbitrary_interface_type_ref(u)?, + elem_ty: self.arbitrary_component_val_type(u)?, }) } - fn arbitrary_tuple_type( - &mut self, - u: &mut Unstructured, - type_fuel: &mut u32, - ) -> Result { + fn arbitrary_tuple_type(&self, u: &mut Unstructured, type_fuel: &mut u32) -> Result { let mut fields = vec![]; arbitrary_loop(u, 0, 100, |u| { *type_fuel = type_fuel.saturating_sub(1); @@ -1137,17 +1274,13 @@ impl ComponentBuilder { return Ok(false); } - fields.push(self.arbitrary_interface_type_ref(u)?); + fields.push(self.arbitrary_component_val_type(u)?); Ok(true) })?; Ok(TupleType { fields }) } - fn arbitrary_flags_type( - &mut self, - u: &mut Unstructured, - type_fuel: &mut u32, - ) -> Result { + fn arbitrary_flags_type(&self, u: &mut Unstructured, type_fuel: &mut u32) -> Result { let mut fields = vec![]; let mut field_names = HashSet::new(); arbitrary_loop(u, 0, 100, |u| { @@ -1162,11 +1295,7 @@ impl ComponentBuilder { Ok(FlagsType { fields }) } - fn arbitrary_enum_type( - &mut self, - u: &mut Unstructured, - type_fuel: &mut u32, - ) -> Result { + fn arbitrary_enum_type(&self, u: &mut Unstructured, type_fuel: &mut u32) -> Result { let mut variants = vec![]; let mut variant_names = HashSet::new(); arbitrary_loop(u, 0, 100, |u| { @@ -1181,11 +1310,7 @@ impl ComponentBuilder { Ok(EnumType { variants }) } - fn arbitrary_union_type( - &mut self, - u: &mut Unstructured, - type_fuel: &mut u32, - ) -> Result { + fn arbitrary_union_type(&self, u: &mut Unstructured, type_fuel: &mut u32) -> Result { let mut variants = vec![]; arbitrary_loop(u, 0, 100, |u| { *type_fuel = type_fuel.saturating_sub(1); @@ -1193,120 +1318,128 @@ impl ComponentBuilder { return Ok(false); } - variants.push(self.arbitrary_interface_type_ref(u)?); + variants.push(self.arbitrary_component_val_type(u)?); Ok(true) })?; Ok(UnionType { variants }) } - fn arbitrary_option_type(&mut self, u: &mut Unstructured) -> Result { + fn arbitrary_option_type(&self, u: &mut Unstructured) -> Result { Ok(OptionType { - inner_ty: self.arbitrary_interface_type_ref(u)?, + inner_ty: self.arbitrary_component_val_type(u)?, }) } - fn arbitrary_expected_type(&mut self, u: &mut Unstructured) -> Result { + fn arbitrary_expected_type(&self, u: &mut Unstructured) -> Result { Ok(ExpectedType { - ok_ty: self.arbitrary_interface_type_ref(u)?, - err_ty: self.arbitrary_interface_type_ref(u)?, + ok_ty: self.arbitrary_component_val_type(u)?, + err_ty: self.arbitrary_component_val_type(u)?, }) } - fn arbitrary_interface_type( - &mut self, + fn arbitrary_defined_type( + &self, u: &mut Unstructured, type_fuel: &mut u32, - ) -> Result { + ) -> Result { match u.int_in_range(0..=9)? { - 0 => Ok(InterfaceType::Primitive( - self.arbitrary_primitive_interface_type(u)?, + 0 => Ok(DefinedType::Primitive( + self.arbitrary_primitive_val_type(u)?, )), - 1 => Ok(InterfaceType::Record( + 1 => Ok(DefinedType::Record( self.arbitrary_record_type(u, type_fuel)?, )), - 2 => Ok(InterfaceType::Variant( + 2 => Ok(DefinedType::Variant( self.arbitrary_variant_type(u, type_fuel)?, )), - 3 => Ok(InterfaceType::List(self.arbitrary_list_type(u)?)), - 4 => Ok(InterfaceType::Tuple( - self.arbitrary_tuple_type(u, type_fuel)?, - )), - 5 => Ok(InterfaceType::Flags( - self.arbitrary_flags_type(u, type_fuel)?, - )), - 6 => Ok(InterfaceType::Enum(self.arbitrary_enum_type(u, type_fuel)?)), - 7 => Ok(InterfaceType::Union( - self.arbitrary_union_type(u, type_fuel)?, - )), - 8 => Ok(InterfaceType::Option(self.arbitrary_option_type(u)?)), - 9 => Ok(InterfaceType::Expected(self.arbitrary_expected_type(u)?)), + 3 => Ok(DefinedType::List(self.arbitrary_list_type(u)?)), + 4 => Ok(DefinedType::Tuple(self.arbitrary_tuple_type(u, type_fuel)?)), + 5 => Ok(DefinedType::Flags(self.arbitrary_flags_type(u, type_fuel)?)), + 6 => Ok(DefinedType::Enum(self.arbitrary_enum_type(u, type_fuel)?)), + 7 => Ok(DefinedType::Union(self.arbitrary_union_type(u, type_fuel)?)), + 8 => Ok(DefinedType::Option(self.arbitrary_option_type(u)?)), + 9 => Ok(DefinedType::Expected(self.arbitrary_expected_type(u)?)), _ => unreachable!(), } } - fn push_import(&mut self, name: String, ty: TypeIndex) { + fn push_import(&mut self, name: String, ty: ComponentTypeRef) { let nth = match self.ensure_section( |sec| matches!(sec, Section::Import(_)), || Section::Import(ImportSection { imports: vec![] }), ) { Section::Import(sec) => { - sec.imports.push(Import { - name, - ty: ty.clone(), - }); + sec.imports.push(Import { name, ty }); sec.imports.len() - 1 } _ => unreachable!(), }; let section_index = self.component().component.sections.len() - 1; - match &*ty.ty { - Type::Func(func_ty) => { + match ty { + ComponentTypeRef::Module(_) => { + self.total_modules += 1; + self.component_mut().modules.push((section_index, nth)); + } + ComponentTypeRef::Func(ty_index) => { + let func_ty = match self.current_type_scope().get(ty_index).as_ref() { + Type::Func(ty) => ty.clone(), + _ => unreachable!(), + }; + + if func_ty.is_scalar() { + let func_index = u32::try_from(self.component().component_funcs.len()).unwrap(); + self.component_mut().scalar_component_funcs.push(func_index); + } + let func_index = u32::try_from(self.component().funcs.len()).unwrap(); self.component_mut() .funcs - .push(ComponentOrCoreFuncType::Component(Rc::clone(func_ty))); + .push(ComponentOrCoreFuncType::Component(func_ty)); - self.component_mut().interface_funcs.push(func_index); - if func_ty.is_scalar() { - self.component_mut().scalar_interface_funcs.push(func_index); - } + self.component_mut().component_funcs.push(func_index); } - - Type::Module(_) => { - self.total_modules += 1; - self.component_mut().modules.push((section_index, nth)); + ComponentTypeRef::Value(ty) => { + self.total_values += 1; + self.component_mut().values.push(ty); } - Type::Component(_) => { - self.total_components += 1; - self.component_mut().components.push((section_index, nth)); + ComponentTypeRef::Type(TypeBounds::Eq, ty_index) => { + let ty = self.current_type_scope().get(ty_index).clone(); + self.current_type_scope_mut().push(ty); } - Type::Instance(ty) => { + ComponentTypeRef::Instance(ty_index) => { + let instance_ty = match self.current_type_scope().get(ty_index).as_ref() { + Type::Instance(ty) => ty.clone(), + _ => unreachable!(), + }; + self.total_instances += 1; self.component_mut() .instances - .push(ComponentOrCoreInstanceType::Component(Rc::clone(ty))); + .push(ComponentOrCoreInstanceType::Component(instance_ty)); } - Type::Value(ty) => { - self.total_values += 1; - self.component_mut().values.push(ty.clone()); + ComponentTypeRef::Component(_) => { + self.total_components += 1; + self.component_mut().components.push((section_index, nth)); } - Type::Interface(_) => unreachable!("cannot import interface types"), } } - fn interface_function_type(&self, inter_func: u32) -> &Rc { - match &self.component().funcs[inter_func as usize] { - ComponentOrCoreFuncType::Component(ty) => ty, - ComponentOrCoreFuncType::Core(_) => panic!("not an interface function"), - } + fn core_function_type(&self, core_func_index: u32) -> &Rc { + self.component().funcs[self.component().core_funcs[core_func_index as usize] as usize] + .as_core() + } + + fn component_function_type(&self, func_index: u32) -> &Rc { + self.component().funcs[self.component().component_funcs[func_index as usize] as usize] + .as_component() } fn push_func(&mut self, func: Func) { let nth = match self.component_mut().component.sections.last_mut() { - Some(Section::Func(FuncSection { funcs })) => funcs.len(), + Some(Section::Canonical(CanonicalSection { funcs })) => funcs.len(), _ => { - self.push_section(Section::Func(FuncSection { funcs: vec![] })); + self.push_section(Section::Canonical(CanonicalSection { funcs: vec![] })); 0 } }; @@ -1316,17 +1449,20 @@ impl ComponentBuilder { let ty = match &func { Func::CanonLift { func_ty, .. } => { - self.component_mut().interface_funcs.push(func_index); let ty = Rc::clone(self.current_type_scope().get_func(*func_ty)); if ty.is_scalar() { - let interface_func_index = self.component().interface_funcs.len(); - self.component_mut().scalar_interface_funcs.push(func_index); + let func_index = u32::try_from(self.component().component_funcs.len()).unwrap(); + self.component_mut().scalar_component_funcs.push(func_index); } + self.component_mut().component_funcs.push(func_index); ComponentOrCoreFuncType::Component(ty) } - Func::CanonLower { inter_func, .. } => { - let inter_func_ty = self.interface_function_type(*inter_func); - let core_func_ty = canonical_abi_for(inter_func_ty); + Func::CanonLower { + func_index: comp_func_index, + .. + } => { + let comp_func_ty = self.component_function_type(*comp_func_index); + let core_func_ty = canonical_abi_for(comp_func_ty); self.component_mut().core_funcs.push(func_index); ComponentOrCoreFuncType::Core(core_func_ty) } @@ -1335,7 +1471,7 @@ impl ComponentBuilder { self.component_mut().funcs.push(ty); match self.component_mut().component.sections.last_mut() { - Some(Section::Func(FuncSection { funcs })) => funcs.push(func), + Some(Section::Canonical(CanonicalSection { funcs })) => funcs.push(func), _ => unreachable!(), } } @@ -1354,60 +1490,23 @@ impl ComponentBuilder { }; let max = self.config.max_imports() - self.component().num_imports; - if !self.current_type_scope().def_types.is_empty() { - crate::arbitrary_loop(u, min, max, |u| { - let name = crate::unique_string(100, &mut self.component_mut().import_names, u)?; - - let mut choices: Vec Result> = - vec![]; - - if !self.current_type_scope().module_types.is_empty() - && self.total_modules < self.config.max_modules() - { - choices.push(|u, c| u.choose(&c.current_type_scope().module_types).copied()); - } - - if !self.current_type_scope().component_types.is_empty() - && self.total_components < self.config.max_components() - { - choices.push(|u, c| u.choose(&c.current_type_scope().component_types).copied()); - } - - if !self.current_type_scope().instance_types.is_empty() - && self.total_instances < self.config.max_instances() - { - choices.push(|u, c| u.choose(&c.current_type_scope().instance_types).copied()); - } - - if !self.current_type_scope().func_types.is_empty() - && self.component().num_funcs() < self.config.max_funcs() - { - choices.push(|u, c| u.choose(&c.current_type_scope().func_types).copied()); - } - - if !self.current_type_scope().value_types.is_empty() - && self.total_values < self.config.max_values() - { - choices.push(|u, c| u.choose(&c.current_type_scope().value_types).copied()); - } - - if choices.is_empty() { - return Ok(false); + crate::arbitrary_loop(u, min, max, |u| { + match self.arbitrary_type_ref(u, true, false)? { + Some(ty) => { + let name = + crate::unique_string(100, &mut self.component_mut().import_names, u)?; + self.push_import(name, ty); + Ok(true) } - - let f = u.choose(&choices)?; - let index = f(u, self)?; - let ty = Rc::clone(self.current_type_scope().get(index)); - self.push_import(name, TypeIndex { index, ty }); - Ok(true) - })?; - } + None => Ok(false), + } + })?; Ok(Step::StillBuilding) } - fn arbitrary_func_section(&mut self, u: &mut Unstructured) -> Result { - self.push_section(Section::Func(FuncSection { funcs: vec![] })); + fn arbitrary_canonical_section(&mut self, u: &mut Unstructured) -> Result { + self.push_section(Section::Canonical(CanonicalSection { funcs: vec![] })); let min = if self.fill_minimums { self.config @@ -1426,62 +1525,62 @@ impl ComponentBuilder { crate::arbitrary_loop(u, min, max, |u| { choices.clear(); - // NB: We only lift/lower scalar interface functions. + // NB: We only lift/lower scalar component functions. // - // If we generated lifting and lowering of compound interface types, + // If we generated lifting and lowering of compound value types, // the probability of generating a corresponding Wasm module that - // generates valid instances of the compound interface types would + // generates valid instances of the compound value types would // be vanishingly tiny (e.g. for `list` we would have to // generate a core Wasm module that correctly produces a pointer and // length for a memory region that itself is a series of pointers // and lengths of valid strings, as well as `canonical_abi_realloc` // and `canonical_abi_free` functions that do the right thing). // - // This is a pretty serious limitation of `wasm-smith`'s interface + // This is a pretty serious limitation of `wasm-smith`'s component // types support, but it is one we are intentionally // accepting. `wasm-smith` will focus on generating arbitrary // component sections, structures, and import/export topologies; not - // interface functions and core Wasm implementations of interface + // component functions and core Wasm implementations of component // functions. In the future, we intend to build a new, distinct test - // case generator specifically for exercising interface functions + // case generator specifically for exercising component functions // and the canonical ABI. This new generator won't emit arbitrary // component sections, structures, or import/export topologies, and // will instead leave that to `wasm-smith`. - if !self.component().scalar_interface_funcs.is_empty() { + if !self.component().scalar_component_funcs.is_empty() { choices.push(|u, c| { - let inter_func = *u.choose(&c.component().scalar_interface_funcs)?; + let func_index = *u.choose(&c.component().scalar_component_funcs)?; Ok(Some(Func::CanonLower { - // Scalar interface functions don't use any canonical options. + // Scalar component functions don't use any canonical options. options: vec![], - inter_func, + func_index, })) }); } if !self.component().core_funcs.is_empty() { choices.push(|u, c| { - let core_func = *u.choose(&c.component().core_funcs)?; - let core_func_ty = c.component().funcs[core_func as usize] - .clone() - .unwrap_core(); - let inter_func_ty = inverse_scalar_canonical_abi_for(u, &core_func_ty)?; + let core_func_index = u.int_in_range( + 0..=u32::try_from(c.component().core_funcs.len() - 1).unwrap(), + )?; + let core_func_ty = c.core_function_type(core_func_index); + let comp_func_ty = inverse_scalar_canonical_abi_for(u, core_func_ty)?; let func_ty = if let Some(indices) = c .current_type_scope() .func_type_to_indices - .get(&inter_func_ty) + .get(&comp_func_ty) { - // If we've already defined this interface function type + // If we've already defined this component function type // one or more times, then choose one of those // definitions arbitrarily. debug_assert!(!indices.is_empty()); *u.choose(indices)? } else if c.current_type_scope().types.len() < c.config.max_types() { - // If we haven't already defined this interface function + // If we haven't already defined this component function // type, and we haven't defined the configured maximum // amount of types yet, then just define this type. - let ty = Rc::new(Type::Func(Rc::new(inter_func_ty))); + let ty = Rc::new(Type::Func(Rc::new(comp_func_ty))); c.push_type(ty) } else { // Otherwise, give up on lifting this function. @@ -1492,7 +1591,7 @@ impl ComponentBuilder { func_ty, // Scalar functions don't use any canonical options. options: vec![], - core_func, + core_func_index, })) }); } @@ -1512,14 +1611,14 @@ impl ComponentBuilder { Ok(Step::StillBuilding) } - fn arbitrary_core_section(&mut self, u: &mut Unstructured) -> Result { + fn arbitrary_core_module_section(&mut self, u: &mut Unstructured) -> Result { let config: Rc = Rc::clone(&self.config); let module = crate::core::Module::new_internal( config, u, crate::core::DuplicateImportsBehavior::Disallowed, )?; - self.push_section(Section::Core(module)); + self.push_section(Section::CoreModule(module)); self.total_modules += 1; Ok(Step::StillBuilding) } @@ -1548,37 +1647,35 @@ impl ComponentBuilder { } } -fn canonical_abi_for(inter_func_ty: &FuncType) -> Rc { +fn canonical_abi_for(func_ty: &FuncType) -> Rc { let to_core_ty = |ty| match ty { - InterfaceTypeRef::Primitive(prim_ty) => match prim_ty { - PrimitiveInterfaceType::Unit => None, - PrimitiveInterfaceType::Char - | PrimitiveInterfaceType::Bool - | PrimitiveInterfaceType::S8 - | PrimitiveInterfaceType::U8 - | PrimitiveInterfaceType::S16 - | PrimitiveInterfaceType::U16 - | PrimitiveInterfaceType::S32 - | PrimitiveInterfaceType::U32 => Some(ValType::I32), - PrimitiveInterfaceType::S64 | PrimitiveInterfaceType::U64 => Some(ValType::I64), - PrimitiveInterfaceType::Float32 => Some(ValType::F32), - PrimitiveInterfaceType::Float64 => Some(ValType::F64), - PrimitiveInterfaceType::String => { + ComponentValType::Primitive(prim_ty) => match prim_ty { + PrimitiveValType::Unit => None, + PrimitiveValType::Char + | PrimitiveValType::Bool + | PrimitiveValType::S8 + | PrimitiveValType::U8 + | PrimitiveValType::S16 + | PrimitiveValType::U16 + | PrimitiveValType::S32 + | PrimitiveValType::U32 => Some(ValType::I32), + PrimitiveValType::S64 | PrimitiveValType::U64 => Some(ValType::I64), + PrimitiveValType::Float32 => Some(ValType::F32), + PrimitiveValType::Float64 => Some(ValType::F64), + PrimitiveValType::String => { unimplemented!("non-scalar types are not supported yet") } }, - InterfaceTypeRef::Type(_) => unimplemented!("non-scalar types are not supported yet"), + ComponentValType::Type(_) => unimplemented!("non-scalar types are not supported yet"), }; Rc::new(crate::core::FuncType { - params: inter_func_ty + params: func_ty .params .iter() - .flat_map(|ty| to_core_ty(ty.ty.clone())) - .collect(), - results: to_core_ty(inter_func_ty.result.clone()) - .into_iter() + .flat_map(|ty| to_core_ty(ty.ty)) .collect(), + results: to_core_ty(func_ty.result).into_iter().collect(), }) } @@ -1589,24 +1686,24 @@ fn inverse_scalar_canonical_abi_for( let from_core_ty = |u: &mut Unstructured, core_ty| match core_ty { ValType::I32 => u .choose(&[ - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Char), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Bool), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::S8), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::U8), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::S16), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::U16), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::S32), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::U32), + ComponentValType::Primitive(PrimitiveValType::Char), + ComponentValType::Primitive(PrimitiveValType::Bool), + ComponentValType::Primitive(PrimitiveValType::S8), + ComponentValType::Primitive(PrimitiveValType::U8), + ComponentValType::Primitive(PrimitiveValType::S16), + ComponentValType::Primitive(PrimitiveValType::U16), + ComponentValType::Primitive(PrimitiveValType::S32), + ComponentValType::Primitive(PrimitiveValType::U32), ]) .cloned(), ValType::I64 => u .choose(&[ - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::S64), - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::U64), + ComponentValType::Primitive(PrimitiveValType::S64), + ComponentValType::Primitive(PrimitiveValType::U64), ]) .cloned(), - ValType::F32 => Ok(InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Float32)), - ValType::F64 => Ok(InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Float64)), + ValType::F32 => Ok(ComponentValType::Primitive(PrimitiveValType::Float32)), + ValType::F64 => Ok(ComponentValType::Primitive(PrimitiveValType::Float64)), ValType::V128 | ValType::FuncRef | ValType::ExternRef => { unreachable!("not used in canonical ABI") } @@ -1621,7 +1718,7 @@ fn inverse_scalar_canonical_abi_for( } else { None }, - ty: InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Unit), + ty: ComponentValType::Primitive(PrimitiveValType::Unit), }); } for core_ty in &core_func_ty.params { @@ -1640,13 +1737,13 @@ fn inverse_scalar_canonical_abi_for( } else { None }, - ty: InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Unit), + ty: ComponentValType::Primitive(PrimitiveValType::Unit), }); } } let result = match core_func_ty.results.len() { - 0 => InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Unit), + 0 => ComponentValType::Primitive(PrimitiveValType::Unit), 1 => from_core_ty(u, core_func_ty.results[0])?, _ => unimplemented!("non-scalar types are not supported yet"), }; @@ -1657,15 +1754,18 @@ fn inverse_scalar_canonical_abi_for( #[derive(Debug)] enum Section { Custom(CustomSection), - Type(TypeSection), - Import(ImportSection), - Func(FuncSection), - Core(crate::Module), + CoreModule(crate::Module), + CoreInstance(CoreInstanceSection), + CoreAlias(CoreAliasSection), + CoreType(CoreTypeSection), Component(Component), Instance(InstanceSection), - Export(ExportSection), - Start(StartSection), Alias(AliasSection), + Type(TypeSection), + Canonical(CanonicalSection), + Start(StartSection), + Import(ImportSection), + Export(ExportSection), } #[derive(Debug)] @@ -1688,16 +1788,11 @@ struct TypeSection { } #[derive(Clone, Debug, PartialEq, Eq, Hash)] -enum Type { +enum CoreType { Module(Rc), - Component(Rc), - Instance(Rc), - Func(Rc), - Value(ValueType), - Interface(InterfaceType), } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] struct ModuleType { defs: Vec, has_memory: bool, @@ -1712,6 +1807,14 @@ enum ModuleTypeDef { Export(String, crate::core::EntityType), } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +enum Type { + Defined(DefinedType), + Func(Rc), + Component(Rc), + Instance(Rc), +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum Alias { InstanceExport { @@ -1742,6 +1845,7 @@ enum InstanceExportAliasKind { enum OuterAliasKind { Module, Component, + CoreType(Rc), Type(Rc), } @@ -1752,18 +1856,20 @@ struct ComponentType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum ComponentTypeDef { - Import(Import), + CoreType(Rc), Type(Rc), - Export { name: String, ty: TypeIndex }, Alias(Alias), + Import(Import), + Export { name: String, ty: ComponentTypeRef }, } impl From for ComponentTypeDef { fn from(def: InstanceTypeDef) -> Self { match def { - InstanceTypeDef::Type(t) => ComponentTypeDef::Type(t), - InstanceTypeDef::Export { name, ty } => ComponentTypeDef::Export { name, ty }, - InstanceTypeDef::Alias(a) => ComponentTypeDef::Alias(a), + InstanceTypeDef::CoreType(t) => Self::CoreType(t), + InstanceTypeDef::Type(t) => Self::Type(t), + InstanceTypeDef::Export { name, ty } => Self::Export { name, ty }, + InstanceTypeDef::Alias(a) => Self::Alias(a), } } } @@ -1775,15 +1881,16 @@ struct InstanceType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum InstanceTypeDef { + CoreType(Rc), Type(Rc), - Export { name: String, ty: TypeIndex }, Alias(Alias), + Export { name: String, ty: ComponentTypeRef }, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct FuncType { params: Vec, - result: InterfaceTypeRef, + result: ComponentValType, } impl FuncType { @@ -1795,7 +1902,7 @@ impl FuncType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct OptionalNamedType { name: Option, - ty: InterfaceTypeRef, + ty: ComponentValType, } impl OptionalNamedType { @@ -1804,40 +1911,37 @@ impl OptionalNamedType { } } -fn is_scalar(ty: &InterfaceTypeRef) -> bool { +fn is_scalar(ty: &ComponentValType) -> bool { match ty { - InterfaceTypeRef::Primitive(prim) => match prim { - PrimitiveInterfaceType::Unit - | PrimitiveInterfaceType::Bool - | PrimitiveInterfaceType::S8 - | PrimitiveInterfaceType::U8 - | PrimitiveInterfaceType::S16 - | PrimitiveInterfaceType::U16 - | PrimitiveInterfaceType::S32 - | PrimitiveInterfaceType::U32 - | PrimitiveInterfaceType::S64 - | PrimitiveInterfaceType::U64 - | PrimitiveInterfaceType::Float32 - | PrimitiveInterfaceType::Float64 - | PrimitiveInterfaceType::Char => true, - PrimitiveInterfaceType::String => false, + ComponentValType::Primitive(prim) => match prim { + PrimitiveValType::Unit + | PrimitiveValType::Bool + | PrimitiveValType::S8 + | PrimitiveValType::U8 + | PrimitiveValType::S16 + | PrimitiveValType::U16 + | PrimitiveValType::S32 + | PrimitiveValType::U32 + | PrimitiveValType::S64 + | PrimitiveValType::U64 + | PrimitiveValType::Float32 + | PrimitiveValType::Float64 + | PrimitiveValType::Char => true, + PrimitiveValType::String => false, }, - InterfaceTypeRef::Type(_) => false, + ComponentValType::Type(_) => false, } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct NamedType { name: String, - ty: InterfaceTypeRef, + ty: ComponentValType, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct ValueType(InterfaceTypeRef); - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -enum InterfaceType { - Primitive(PrimitiveInterfaceType), +enum DefinedType { + Primitive(PrimitiveValType), Record(RecordType), Variant(VariantType), List(ListType), @@ -1861,12 +1965,12 @@ struct VariantType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct ListType { - elem_ty: InterfaceTypeRef, + elem_ty: ComponentValType, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct TupleType { - fields: Vec, + fields: Vec, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -1881,18 +1985,18 @@ struct EnumType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct UnionType { - variants: Vec, + variants: Vec, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct OptionType { - inner_ty: InterfaceTypeRef, + inner_ty: ComponentValType, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct ExpectedType { - ok_ty: InterfaceTypeRef, - err_ty: InterfaceTypeRef, + ok_ty: ComponentValType, + err_ty: ComponentValType, } #[derive(Debug)] @@ -1903,11 +2007,11 @@ struct ImportSection { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct Import { name: String, - ty: TypeIndex, + ty: ComponentTypeRef, } #[derive(Debug)] -struct FuncSection { +struct CanonicalSection { funcs: Vec, } @@ -1916,11 +2020,11 @@ enum Func { CanonLift { func_ty: u32, options: Vec, - core_func: u32, + core_func_index: u32, }, CanonLower { options: Vec, - inter_func: u32, + func_index: u32, }, } @@ -1929,7 +2033,9 @@ enum CanonOpt { StringUtf8, StringUtf16, StringLatin1Utf16, - Into { instance: u32 }, + Memory(u32), + Realloc(u32), + PostReturn(u32), } #[derive(Debug)] @@ -1944,23 +2050,13 @@ struct StartSection {} #[derive(Debug)] struct AliasSection {} -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -enum InterfaceTypeRef { - Primitive(PrimitiveInterfaceType), - Type(TypeIndex), -} +#[derive(Debug)] +struct CoreInstanceSection {} -impl From for wasm_encoder::InterfaceTypeRef { - fn from(r: InterfaceTypeRef) -> Self { - match r { - InterfaceTypeRef::Primitive(p) => wasm_encoder::InterfaceTypeRef::Primitive(p), - InterfaceTypeRef::Type(t) => wasm_encoder::InterfaceTypeRef::Type(t.index), - } - } -} +#[derive(Debug)] +struct CoreAliasSection {} -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct TypeIndex { - index: u32, - ty: Rc, +#[derive(Debug)] +struct CoreTypeSection { + types: Vec>, } diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index a9f9f3ff68..ebe1a7b725 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -18,28 +18,31 @@ impl Component { impl Section { fn encode(&self, component: &mut wasm_encoder::Component) { match self { - Section::Custom(sec) => sec.encode(component), - Section::Type(sec) => sec.encode(component), - Section::Import(sec) => sec.encode(component), - Section::Func(sec) => sec.encode(component), - Section::Core(module) => { + Self::Custom(sec) => sec.encode(component), + Self::CoreModule(module) => { let bytes = module.to_bytes(); component.section(&wasm_encoder::RawSection { - id: wasm_encoder::ComponentSectionId::Module as u8, + id: wasm_encoder::ComponentSectionId::CoreModule as u8, data: &bytes, }); } - Section::Component(comp) => { + Self::CoreInstance(_) => todo!(), + Self::CoreAlias(_) => todo!(), + Self::CoreType(sec) => sec.encode(component), + Self::Component(comp) => { let bytes = comp.to_bytes(); component.section(&wasm_encoder::RawSection { id: wasm_encoder::ComponentSectionId::Component as u8, data: &bytes, }); } - Section::Instance(_) => todo!(), - Section::Export(_) => todo!(), - Section::Start(_) => todo!(), - Section::Alias(_) => todo!(), + Self::Instance(_) => todo!(), + Self::Alias(_) => todo!(), + Self::Type(sec) => sec.encode(component), + Self::Canonical(sec) => sec.encode(component), + Self::Start(_) => todo!(), + Self::Import(sec) => sec.encode(component), + Self::Export(_) => todo!(), } } } @@ -67,31 +70,31 @@ impl ImportSection { fn encode(&self, component: &mut wasm_encoder::Component) { let mut sec = wasm_encoder::ComponentImportSection::new(); for imp in &self.imports { - sec.import(&imp.name, imp.ty.index); + sec.import(&imp.name, imp.ty); } component.section(&sec); } } -impl FuncSection { +impl CanonicalSection { fn encode(&self, component: &mut wasm_encoder::Component) { - let mut sec = wasm_encoder::ComponentFunctionSection::new(); + let mut sec = wasm_encoder::CanonicalFunctionSection::new(); for func in &self.funcs { match func { Func::CanonLift { func_ty, options, - core_func, + core_func_index, } => { let options = translate_canon_opt(options); - sec.lift(*func_ty, *core_func, options); + sec.lift(*core_func_index, *func_ty, options); } Func::CanonLower { options, - inter_func, + func_index, } => { let options = translate_canon_opt(options); - sec.lower(*inter_func, options); + sec.lower(*func_index, options); } } } @@ -99,15 +102,25 @@ impl FuncSection { } } -impl Type { - fn encode(&self, enc: wasm_encoder::TypeEncoder<'_>) { +impl CoreTypeSection { + fn encode(&self, component: &mut wasm_encoder::Component) { + let mut sec = wasm_encoder::CoreTypeSection::new(); + for ty in &self.types { + ty.encode(sec.ty()); + } + component.section(&sec); + } +} + +impl CoreType { + fn encode(&self, enc: wasm_encoder::CoreTypeEncoder<'_>) { match self { - Type::Module(mod_ty) => { + Self::Module(mod_ty) => { let mut enc_mod_ty = wasm_encoder::ModuleType::new(); for def in &mod_ty.defs { match def { ModuleTypeDef::TypeDef(crate::core::Type::Func(func_ty)) => { - enc_mod_ty.function( + enc_mod_ty.ty().function( func_ty.params.iter().copied(), func_ty.results.iter().copied(), ); @@ -126,18 +139,37 @@ impl Type { } enc.module(&enc_mod_ty); } - Type::Component(comp_ty) => { + } + } +} + +impl Type { + fn encode(&self, enc: wasm_encoder::ComponentTypeEncoder<'_>) { + match self { + Self::Defined(ty) => { + ty.encode(enc.defined_type()); + } + Self::Func(func_ty) => { + enc.function( + func_ty.params.iter().map(translate_optional_named_type), + func_ty.result, + ); + } + Self::Component(comp_ty) => { let mut enc_comp_ty = wasm_encoder::ComponentType::new(); for def in &comp_ty.defs { match def { ComponentTypeDef::Import(imp) => { - enc_comp_ty.import(&imp.name, imp.ty.index); + enc_comp_ty.import(&imp.name, imp.ty); + } + ComponentTypeDef::CoreType(ty) => { + ty.encode(enc_comp_ty.core_type()); } ComponentTypeDef::Type(ty) => { ty.encode(enc_comp_ty.ty()); } ComponentTypeDef::Export { name, ty } => { - enc_comp_ty.export(name, ty.index); + enc_comp_ty.export(name, *ty); } ComponentTypeDef::Alias(Alias::Outer { count, @@ -146,20 +178,30 @@ impl Type { }) => { enc_comp_ty.alias_outer_type(*count, *i); } + ComponentTypeDef::Alias(Alias::Outer { + count, + i, + kind: OuterAliasKind::CoreType(_), + }) => { + enc_comp_ty.alias_outer_core_type(*count, *i); + } ComponentTypeDef::Alias(_) => unreachable!(), } } enc.component(&enc_comp_ty); } - Type::Instance(inst_ty) => { + Self::Instance(inst_ty) => { let mut enc_inst_ty = wasm_encoder::InstanceType::new(); for def in &inst_ty.defs { match def { + InstanceTypeDef::CoreType(ty) => { + ty.encode(enc_inst_ty.core_type()); + } InstanceTypeDef::Type(ty) => { ty.encode(enc_inst_ty.ty()); } InstanceTypeDef::Export { name, ty } => { - enc_inst_ty.export(name, ty.index); + enc_inst_ty.export(name, *ty); } InstanceTypeDef::Alias(Alias::Outer { count, @@ -168,75 +210,67 @@ impl Type { }) => { enc_inst_ty.alias_outer_type(*count, *i); } + InstanceTypeDef::Alias(Alias::Outer { + count, + i, + kind: OuterAliasKind::CoreType(_), + }) => { + enc_inst_ty.alias_outer_core_type(*count, *i); + } InstanceTypeDef::Alias(_) => unreachable!(), } } enc.instance(&enc_inst_ty); } - Type::Func(func_ty) => { - enc.function( - func_ty - .params - .iter() - .map(|p| translate_optional_named_type(p)), - func_ty.result.clone(), - ); - } - Type::Value(val_ty) => { - enc.value(val_ty.0.clone()); - } - Type::Interface(ty) => { - ty.encode(enc.interface_type()); - } } } } -impl InterfaceType { - fn encode(&self, enc: wasm_encoder::InterfaceTypeEncoder<'_>) { +impl DefinedType { + fn encode(&self, enc: wasm_encoder::ComponentDefinedTypeEncoder<'_>) { match self { - InterfaceType::Primitive(ty) => enc.primitive(*ty), - InterfaceType::Record(ty) => { - enc.record(ty.fields.iter().map(|f| translate_named_type(f))); + Self::Primitive(ty) => enc.primitive(*ty), + Self::Record(ty) => { + enc.record(ty.fields.iter().map(translate_named_type)); } - InterfaceType::Variant(ty) => { + Self::Variant(ty) => { enc.variant( - ty.cases.iter().map(|(ty, default_to)| { - (ty.name.as_str(), ty.ty.clone(), default_to.clone()) - }), + ty.cases + .iter() + .map(|(ty, refines)| (ty.name.as_str(), ty.ty, *refines)), ); } - InterfaceType::List(ty) => { - enc.list(ty.elem_ty.clone()); + Self::List(ty) => { + enc.list(ty.elem_ty); } - InterfaceType::Tuple(ty) => { - enc.tuple(ty.fields.iter().cloned()); + Self::Tuple(ty) => { + enc.tuple(ty.fields.iter().copied()); } - InterfaceType::Flags(ty) => { + Self::Flags(ty) => { enc.flags(ty.fields.iter().map(|f| f.as_str())); } - InterfaceType::Enum(ty) => { + Self::Enum(ty) => { enc.enum_type(ty.variants.iter().map(|v| v.as_str())); } - InterfaceType::Union(ty) => { - enc.union(ty.variants.iter().cloned()); + Self::Union(ty) => { + enc.union(ty.variants.iter().copied()); } - InterfaceType::Option(ty) => { - enc.option(ty.inner_ty.clone()); + Self::Option(ty) => { + enc.option(ty.inner_ty); } - InterfaceType::Expected(ty) => { - enc.expected(ty.ok_ty.clone(), ty.err_ty.clone()); + Self::Expected(ty) => { + enc.expected(ty.ok_ty, ty.err_ty); } } } } -fn translate_named_type(ty: &NamedType) -> (&str, InterfaceTypeRef) { - (&ty.name, ty.ty.clone()) +fn translate_named_type(ty: &NamedType) -> (&str, ComponentValType) { + (&ty.name, ty.ty) } -fn translate_optional_named_type(ty: &OptionalNamedType) -> (Option<&str>, InterfaceTypeRef) { - (ty.name.as_deref(), ty.ty.clone()) +fn translate_optional_named_type(ty: &OptionalNamedType) -> (Option<&str>, ComponentValType) { + (ty.name.as_deref(), ty.ty) } fn translate_canon_opt(options: &[CanonOpt]) -> Vec { @@ -246,7 +280,9 @@ fn translate_canon_opt(options: &[CanonOpt]) -> Vec wasm_encoder::CanonicalOption::UTF8, CanonOpt::StringUtf16 => wasm_encoder::CanonicalOption::UTF16, CanonOpt::StringLatin1Utf16 => wasm_encoder::CanonicalOption::CompactUTF16, - CanonOpt::Into { instance } => wasm_encoder::CanonicalOption::Into(*instance), + CanonOpt::Memory(idx) => wasm_encoder::CanonicalOption::Memory(*idx), + CanonOpt::Realloc(idx) => wasm_encoder::CanonicalOption::Realloc(*idx), + CanonOpt::PostReturn(idx) => wasm_encoder::CanonicalOption::PostReturn(*idx), }) .collect() } diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index a6381cb618..43edf8c626 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -14,7 +14,7 @@ use std::marker; use std::ops::Range; use std::rc::Rc; use std::str::{self, FromStr}; -use wasm_encoder::{BlockType, Export, ValType}; +use wasm_encoder::{BlockType, ExportKind, ValType}; pub(crate) use wasm_encoder::{GlobalType, MemoryType, TableType}; // NB: these constants are used to control the rate at which various events @@ -110,7 +110,7 @@ pub struct Module { /// entry is the type of each memory. memories: Vec, - exports: Vec<(String, Export)>, + exports: Vec<(String, ExportKind, u32)>, start: Option, elems: Vec, code: Vec, @@ -409,7 +409,7 @@ impl Module { } fn can_add_local_or_import_func(&self) -> bool { - self.func_types.len() > 0 && self.funcs.len() < self.config.max_funcs() + !self.func_types.is_empty() && self.funcs.len() < self.config.max_funcs() } fn can_add_local_or_import_table(&self) -> bool { @@ -502,15 +502,15 @@ impl Module { match &entity_type { EntityType::Tag(ty) => self.tags.push(ty.clone()), EntityType::Func(idx, ty) => self.funcs.push((*idx, ty.clone())), - EntityType::Global(ty) => self.globals.push(ty.clone()), - EntityType::Table(ty) => self.tables.push(ty.clone()), - EntityType::Memory(ty) => self.memories.push(ty.clone()), + EntityType::Global(ty) => self.globals.push(*ty), + EntityType::Table(ty) => self.tables.push(*ty), + EntityType::Memory(ty) => self.memories.push(*ty), } self.num_imports += 1; self.imports.push(Import { - module: module.into(), - field: field.into(), + module, + field, entity_type, }); Ok(true) @@ -537,7 +537,7 @@ impl Module { // index in our newly generated module. Initially the option is `None` and will become a // `Some` when we encounter an import that uses this signature in the next portion of this // function. See also the `make_func_type` closure below. - let mut available_types = Vec::<(wasmparser::TypeDef, Option)>::new(); + let mut available_types = Vec::<(wasmparser::Type, Option)>::new(); let mut available_imports = Vec::::new(); for payload in wasmparser::Parser::new(0).parse_all(&example_module) { match payload.expect("could not parse the available import payload") { @@ -577,10 +577,10 @@ impl Module { let serialized_sig_idx = match available_types.get_mut(parsed_sig_idx as usize) { None => panic!("signature index refers to a type out of bounds"), Some((_, Some(idx))) => *idx as usize, - Some((wasmparser::TypeDef::Func(func_type), index_store)) => { + Some((wasmparser::Type::Func(func_type), index_store)) => { let multi_value_required = func_type.returns.len() > 1; let new_index = first_type_index + new_types.len(); - if new_index >= max_types || multi_value_required > multi_value_enabled { + if new_index >= max_types || (multi_value_required && !multi_value_enabled) { return None; } let func_type = Rc::new(FuncType { @@ -657,7 +657,7 @@ impl Module { maximum: memory_ty.maximum, memory64: memory_ty.memory64, }; - let entity = EntityType::Memory(memory_ty.clone()); + let entity = EntityType::Memory(memory_ty); let type_size = entity.size(); if type_size_budget < type_size || !self.can_add_local_or_import_memory() { continue; @@ -697,16 +697,16 @@ impl Module { Ok(true) } - fn type_of(&self, item: &Export) -> EntityType { - match *item { - Export::Global(idx) => EntityType::Global(self.globals[idx as usize].clone()), - Export::Memory(idx) => EntityType::Memory(self.memories[idx as usize].clone()), - Export::Table(idx) => EntityType::Table(self.tables[idx as usize].clone()), - Export::Function(idx) => { - let (_idx, ty) = &self.funcs[idx as usize]; + fn type_of(&self, kind: ExportKind, index: u32) -> EntityType { + match kind { + ExportKind::Global => EntityType::Global(self.globals[index as usize]), + ExportKind::Memory => EntityType::Memory(self.memories[index as usize]), + ExportKind::Table => EntityType::Table(self.tables[index as usize]), + ExportKind::Func => { + let (_idx, ty) = &self.funcs[index as usize]; EntityType::Func(u32::max_value(), ty.clone()) } - Export::Tag(idx) => EntityType::Tag(self.tags[idx as usize].clone()), + ExportKind::Tag => EntityType::Tag(self.tags[index as usize].clone()), } } @@ -714,7 +714,7 @@ impl Module { &self.types[idx as usize] } - fn func_types<'a>(&'a self) -> impl Iterator + 'a { + fn func_types(&self) -> impl Iterator + '_ { self.func_types .iter() .copied() @@ -727,14 +727,14 @@ impl Module { } } - fn tags<'a>(&'a self) -> impl Iterator + 'a { + fn tags(&self) -> impl Iterator + '_ { self.tags .iter() .enumerate() .map(move |(i, ty)| (i as u32, ty)) } - fn funcs<'a>(&'a self) -> impl Iterator)> + 'a { + fn funcs(&self) -> impl Iterator)> + '_ { self.funcs .iter() .enumerate() @@ -745,11 +745,11 @@ impl Module { self.tag_func_types().next().is_some() } - fn tag_func_types<'a>(&'a self) -> impl Iterator + 'a { + fn tag_func_types(&self) -> impl Iterator + '_ { self.func_types .iter() .copied() - .filter(move |i| self.func_type(*i).results.len() == 0) + .filter(move |i| self.func_type(*i).results.is_empty()) } fn arbitrary_valtype(&self, u: &mut Unstructured) -> Result { @@ -894,25 +894,25 @@ impl Module { } // Build up a list of candidates for each class of import - let mut choices: Vec> = Vec::with_capacity(6); + let mut choices: Vec> = Vec::with_capacity(6); choices.push( (0..self.funcs.len()) - .map(|i| Export::Function(i as u32)) + .map(|i| (ExportKind::Func, i as u32)) .collect(), ); choices.push( (0..self.tables.len()) - .map(|i| Export::Table(i as u32)) + .map(|i| (ExportKind::Table, i as u32)) .collect(), ); choices.push( (0..self.memories.len()) - .map(|i| Export::Memory(i as u32)) + .map(|i| (ExportKind::Memory, i as u32)) .collect(), ); choices.push( (0..self.globals.len()) - .map(|i| Export::Global(i as u32)) + .map(|i| (ExportKind::Global, i as u32)) .collect(), ); @@ -929,10 +929,10 @@ impl Module { // If there's nothing remaining after this, then we're done. let max_size = self.config.max_type_size() - self.type_size; for list in choices.iter_mut() { - list.retain(|c| self.type_of(c).size() + 1 < max_size); + list.retain(|(kind, idx)| self.type_of(*kind, *idx).size() + 1 < max_size); } - choices.retain(|list| list.len() > 0); - if choices.len() == 0 { + choices.retain(|list| !list.is_empty()); + if choices.is_empty() { return Ok(false); } @@ -940,10 +940,10 @@ impl Module { // information about the chosen export. let name = unique_string(1_000, &mut export_names, u)?; let list = u.choose(&choices)?; - let export = u.choose(list)?; - let ty = self.type_of(export); + let (kind, idx) = *u.choose(list)?; + let ty = self.type_of(kind, idx); self.type_size += 1 + ty.size(); - self.exports.push((name, *export)); + self.exports.push((name, kind, idx)); Ok(true) }, ) @@ -1062,10 +1062,10 @@ impl Module { // Select a kind for this segment now that we know the number of // items the segment will hold. - let (kind, max_size_hint) = u.choose(&kind_candidates)?(u)?; + let (kind, max_size_hint) = u.choose(kind_candidates)?(u)?; let max = max_size_hint .map(|i| usize::try_from(i).unwrap()) - .unwrap_or(self.config.max_elements()); + .unwrap_or_else(|| self.config.max_elements()); // Pick whether we're going to use expression elements or // indices. Note that externrefs must use expressions, @@ -1207,7 +1207,7 @@ impl Module { // With memories we can generate data segments, and with bulk memory we // can generate passive segments. Without these though we can't create // a valid module with data segments. - if memories.len() == 0 && !self.config.bulk_memory_enabled() { + if memories.is_empty() && !self.config.bulk_memory_enabled() { return Ok(()); } @@ -1317,10 +1317,7 @@ pub(crate) fn arbitrary_func_type( results.push(arbitrary_valtype(u, valtypes)?); Ok(true) })?; - Ok(Rc::new(FuncType { - params: params.into(), - results: results.into(), - })) + Ok(Rc::new(FuncType { params, results })) } fn arbitrary_valtype(u: &mut Unstructured, valtypes: &[ValType]) -> Result { @@ -1435,13 +1432,13 @@ fn gradually_grow(u: &mut Unstructured, min: u64, max_inbounds: u64, max: u64) - output.end ); - let x = map_linear(value, input.clone(), 0.0..1.0); + let x = map_linear(value, input, 0.0..1.0); let result = if x < PCT_INBOUNDS { if output_inbounds.start == output_inbounds.end { output_inbounds.start } else { let unscaled = x * x * x * x * x * x; - map_linear(unscaled, 0.0..1.0, output_inbounds.clone()) + map_linear(unscaled, 0.0..1.0, output_inbounds) } } else { map_linear(x, 0.0..1.0, output.clone()) @@ -1511,9 +1508,9 @@ fn arbitrary_vec_u8(u: &mut Unstructured) -> Result> { Ok(u.bytes(size)?.to_vec()) } -/// Convert a wasmparser's `Type` to a `wasm_encoder::ValType`. -fn convert_type(parsed_type: wasmparser::Type) -> ValType { - use wasmparser::Type::*; +/// Convert a wasmparser's `ValType` to a `wasm_encoder::ValType`. +fn convert_type(parsed_type: wasmparser::ValType) -> ValType { + use wasmparser::ValType::*; match parsed_type { I32 => ValType::I32, I64 => ValType::I64, diff --git a/crates/wasm-smith/src/core/encode.rs b/crates/wasm-smith/src/core/encode.rs index c172861221..0a66afcfb2 100644 --- a/crates/wasm-smith/src/core/encode.rs +++ b/crates/wasm-smith/src/core/encode.rs @@ -123,8 +123,8 @@ impl Module { return; } let mut exports = wasm_encoder::ExportSection::new(); - for (name, export) in &self.exports { - exports.export(name, *export); + for (name, kind, idx) in &self.exports { + exports.export(name, *kind, *idx); } module.section(&exports); } diff --git a/crates/wasm-smith/src/lib.rs b/crates/wasm-smith/src/lib.rs index 7b81c76a90..d78e9d1d60 100644 --- a/crates/wasm-smith/src/lib.rs +++ b/crates/wasm-smith/src/lib.rs @@ -103,10 +103,10 @@ pub(crate) fn arbitrary_loop<'a>( pub(crate) fn limited_str<'a>(max_size: usize, u: &mut Unstructured<'a>) -> Result<&'a str> { let size = u.arbitrary_len::()?; let size = std::cmp::min(size, max_size); - match str::from_utf8(&u.peek_bytes(size).unwrap()) { + match str::from_utf8(u.peek_bytes(size).unwrap()) { Ok(s) => { u.bytes(size).unwrap(); - Ok(s.into()) + Ok(s) } Err(e) => { let i = e.valid_up_to(); diff --git a/crates/wasm-smith/tests/core.rs b/crates/wasm-smith/tests/core.rs index c888737878..1acff647a6 100644 --- a/crates/wasm-smith/tests/core.rs +++ b/crates/wasm-smith/tests/core.rs @@ -2,7 +2,7 @@ use arbitrary::{Arbitrary, Unstructured}; use rand::{rngs::SmallRng, RngCore, SeedableRng}; use std::collections::HashMap; use wasm_smith::{Config, ConfiguredModule, Module, SwarmConfig}; -use wasmparser::{Parser, Type, TypeRef, Validator, WasmFeatures}; +use wasmparser::{Parser, TypeRef, ValType, Validator, WasmFeatures}; #[test] fn smoke_test_module() { @@ -131,7 +131,7 @@ fn smoke_test_imports_config() { // Gather the signature types to later check function types against. while let Ok(ty) = rdr.read() { match ty { - wasmparser::TypeDef::Func(ft) => sig_types.push(ft), + wasmparser::Type::Func(ft) => sig_types.push(ft), } } } else if let wasmparser::Payload::ImportSection(mut rdr) = payload { @@ -209,10 +209,10 @@ fn wasm_features() -> WasmFeatures { #[derive(Debug)] enum AvailableImportKind { - Func(&'static [Type], &'static [Type]), - Tag(&'static [Type]), - Global(Type), - Table(Type), + Func(&'static [ValType], &'static [ValType]), + Tag(&'static [ValType]), + Global(ValType), + Table(ValType), Memory, } @@ -225,7 +225,7 @@ fn import_config( let mut config = SwarmConfig::arbitrary(u).expect("arbitrary swarm"); config.exceptions_enabled = u.arbitrary().expect("exceptions enabled for swarm"); let available = { - use {AvailableImportKind::*, Type::*}; + use {AvailableImportKind::*, ValType::*}; vec![ ("env", "pi", Func(&[I32], &[])), ("env", "pi2", Func(&[I32], &[])), diff --git a/crates/wasmparser/benches/benchmark.rs b/crates/wasmparser/benches/benchmark.rs index eb216b731c..4cf2411d21 100644 --- a/crates/wasmparser/benches/benchmark.rs +++ b/crates/wasmparser/benches/benchmark.rs @@ -157,35 +157,50 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> { } // Component sections - ComponentTypeSection(s) => { + ModuleSection { .. } => {} + InstanceSection(s) => { for item in s { item?; } } - ComponentImportSection(s) => { + AliasSection(s) => { for item in s { item?; } } - ComponentFunctionSection(s) => { + CoreTypeSection(s) => { for item in s { item?; } } - ModuleSection { .. } => {} ComponentSection { .. } => {} - InstanceSection(s) => { + ComponentInstanceSection(s) => { for item in s { item?; } } - ComponentExportSection(s) => { + ComponentAliasSection(s) => { + for item in s { + item?; + } + } + ComponentTypeSection(s) => { + for item in s { + item?; + } + } + ComponentCanonicalSection(s) => { for item in s { item?; } } ComponentStartSection { .. } => {} - AliasSection(s) => { + ComponentImportSection(s) => { + for item in s { + item?; + } + } + ComponentExportSection(s) => { for item in s { item?; } diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 5d7d361853..5cdc72b00c 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -13,16 +13,7 @@ * limitations under the License. */ -use crate::{ - limits::*, Alias, AliasKind, BlockType, BrTable, CanonicalOption, ComponentExport, - ComponentFuncType, ComponentFunction, ComponentImport, ComponentStartFunction, ComponentType, - ComponentTypeDef, CustomSectionKind, Export, ExternalKind, FuncType, GlobalType, Ieee32, - Ieee64, Import, InitExpr, Instance, InstanceType, InterfaceType, InterfaceTypeRef, LinkingType, - MemoryImmediate, MemoryType, ModuleArg, ModuleArgKind, ModuleType, NameType, Operator, - PrimitiveInterfaceType, RelocType, SIMDLaneIndex, SectionCode, TableType, TagKind, TagType, - Type, TypeDef, TypeRef, VariantCase, V128, -}; -use crate::{ComponentArg, ComponentArgKind}; +use crate::{limits::*, *}; use std::convert::TryInto; use std::error::Error; use std::fmt; @@ -193,15 +184,15 @@ impl<'a> BinaryReader<'a> { Ok(b) } - /// Reads a core WebAssembly type from the binary reader. - pub fn read_type(&mut self) -> Result { - match Self::type_from_byte(self.peek()?) { + /// Reads a core WebAssembly value type from the binary reader. + pub fn read_val_type(&mut self) -> Result { + match Self::val_type_from_byte(self.peek()?) { Some(ty) => { self.position += 1; Ok(ty) } None => Err(BinaryReaderError::new( - "invalid type", + "invalid value type", self.original_position(), )), } @@ -219,30 +210,69 @@ impl<'a> BinaryReader<'a> { } pub(crate) fn read_external_kind(&mut self) -> Result { - let code = self.read_u8()?; - match code { - 0 => Ok(ExternalKind::Func), - 1 => Ok(ExternalKind::Table), - 2 => Ok(ExternalKind::Memory), - 3 => Ok(ExternalKind::Global), - 4 => Ok(ExternalKind::Tag), - _ => Err(BinaryReaderError::new( - "invalid external kind", - self.original_position() - 1, - )), + match self.read_u8()? { + 0x00 => Ok(ExternalKind::Func), + 0x01 => Ok(ExternalKind::Table), + 0x02 => Ok(ExternalKind::Memory), + 0x03 => Ok(ExternalKind::Global), + 0x04 => Ok(ExternalKind::Tag), + x => self.invalid_leading_byte(x, "external kind"), } } + fn component_external_kind_from_bytes( + byte1: u8, + byte2: Option, + offset: usize, + ) -> Result { + Ok(match byte1 { + 0x00 => match byte2.unwrap() { + 0x11 => ComponentExternalKind::Module, + x => { + return Err(Self::invalid_leading_byte_error( + x, + "component external kind", + offset + 1, + )) + } + }, + 0x01 => ComponentExternalKind::Func, + 0x02 => ComponentExternalKind::Value, + 0x03 => ComponentExternalKind::Type, + 0x04 => ComponentExternalKind::Component, + 0x05 => ComponentExternalKind::Instance, + x => { + return Err(Self::invalid_leading_byte_error( + x, + "component external kind", + offset, + )) + } + }) + } + + pub(crate) fn read_component_external_kind(&mut self) -> Result { + let offset = self.original_position(); + let byte1 = self.read_u8()?; + let byte2 = if byte1 == 0x00 { + Some(self.read_u8()?) + } else { + None + }; + + Self::component_external_kind_from_bytes(byte1, byte2, offset) + } + pub(crate) fn read_func_type(&mut self) -> Result { let params_len = self.read_size(MAX_WASM_FUNCTION_PARAMS, "function params")?; - let mut params: Vec = Vec::with_capacity(params_len); + let mut params = Vec::with_capacity(params_len); for _ in 0..params_len { - params.push(self.read_type()?); + params.push(self.read_val_type()?); } let returns_len = self.read_size(MAX_WASM_FUNCTION_RETURNS, "function returns")?; - let mut returns: Vec = Vec::with_capacity(returns_len); + let mut returns = Vec::with_capacity(returns_len); for _ in 0..returns_len { - returns.push(self.read_type()?); + returns.push(self.read_val_type()?); } Ok(FuncType { params: params.into_boxed_slice(), @@ -250,71 +280,80 @@ impl<'a> BinaryReader<'a> { }) } - pub(crate) fn read_type_def(&mut self) -> Result { + pub(crate) fn read_type(&mut self) -> Result { Ok(match self.read_u8()? { - 0x60 => TypeDef::Func(self.read_func_type()?), + 0x60 => Type::Func(self.read_func_type()?), x => return self.invalid_leading_byte(x, "type"), }) } - pub(crate) fn read_component_type_def(&mut self) -> Result> { + pub(crate) fn read_core_type(&mut self) -> Result> { Ok(match self.read_u8()? { - 0x4f => { - let size = self.read_size(MAX_WASM_MODULE_TYPEDEFS, "module definition")?; - ComponentTypeDef::Module( + 0x60 => CoreType::Func(self.read_func_type()?), + 0x50 => { + let size = self.read_size(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")?; + CoreType::Module( (0..size) - .map(|_| self.read_module_type()) + .map(|_| self.read_module_type_decl()) .collect::>()?, ) } - 0x4e => { - let size = self.read_size(MAX_WASM_COMPONENT_TYPEDEFS, "component definition")?; - ComponentTypeDef::Component( - (0..size) - .map(|_| self.read_component_type()) - .collect::>()?, - ) - } - 0x4d => { - let size = self.read_size(MAX_WASM_INSTANCE_TYPEDEFS, "instance definition")?; - ComponentTypeDef::Instance( - (0..size) - .map(|_| self.read_instance_type()) - .collect::>()?, - ) - } - 0x4c => { + x => return self.invalid_leading_byte(x, "core type"), + }) + } + + pub(crate) fn read_component_type(&mut self) -> Result> { + Ok(match self.read_u8()? { + 0x40 => { let params_size = self.read_size(MAX_WASM_FUNCTION_PARAMS, "function parameters")?; let params = (0..params_size) .map(|_| { Ok(( self.read_optional_string()?, - self.read_interface_type_ref()?, + self.read_component_val_type()?, )) }) .collect::>()?; - ComponentTypeDef::Function(ComponentFuncType { + ComponentType::Func(ComponentFuncType { params, - result: self.read_interface_type_ref()?, + result: self.read_component_val_type()?, }) } - 0x4b => ComponentTypeDef::Value(self.read_interface_type_ref()?), + 0x41 => { + let size = + self.read_size(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")?; + ComponentType::Component( + (0..size) + .map(|_| self.read_component_type_decl()) + .collect::>()?, + ) + } + 0x42 => { + let size = + self.read_size(MAX_WASM_INSTANCE_TYPE_DECLS, "instance type declaration")?; + ComponentType::Instance( + (0..size) + .map(|_| self.read_instance_type_decl()) + .collect::>()?, + ) + } x => { - if let Some(it) = Self::primitive_it_from_byte(x) { - ComponentTypeDef::Interface(InterfaceType::Primitive(it)) + if let Some(ty) = Self::primitive_val_type_from_byte(x) { + ComponentType::Defined(ComponentDefinedType::Primitive(ty)) } else { - ComponentTypeDef::Interface(self.read_interface_type(x)?) + ComponentType::Defined(self.read_component_defined_type(x)?) } } }) } - pub(crate) fn read_module_type(&mut self) -> Result> { + pub(crate) fn read_module_type_decl(&mut self) -> Result> { Ok(match self.read_u8()? { - 0x01 => ModuleType::Type(self.read_type_def()?), - 0x02 => ModuleType::Import(self.read_import()?), - 0x07 => ModuleType::Export { + 0x00 => ModuleTypeDeclaration::Import(self.read_import()?), + 0x01 => ModuleTypeDeclaration::Type(self.read_type()?), + // 0x02 => aliases might be implemented in the future + 0x03 => ModuleTypeDeclaration::Export { name: self.read_string()?, ty: self.read_type_ref()?, }, @@ -322,62 +361,56 @@ impl<'a> BinaryReader<'a> { }) } - pub(crate) fn read_component_type(&mut self) -> Result> { + pub(crate) fn read_component_type_decl(&mut self) -> Result> { // Component types are effectively instance types with the additional // variant of imports; check for imports here or delegate to - // `read_instance_type` with the appropriate conversions. - if self.peek()? == 0x02 { + // `read_instance_type_decl` with the appropriate conversions. + if self.peek()? == 0x03 { self.position += 1; - return Ok(ComponentType::Import(self.read_component_import()?)); + return Ok(ComponentTypeDeclaration::Import( + self.read_component_import()?, + )); } - Ok(match self.read_instance_type()? { - InstanceType::Type(t) => ComponentType::Type(t), - InstanceType::OuterType { count, index } => ComponentType::OuterType { count, index }, - InstanceType::Export { name, ty } => ComponentType::Export { name, ty }, + Ok(match self.read_instance_type_decl()? { + InstanceTypeDeclaration::CoreType(t) => ComponentTypeDeclaration::CoreType(t), + InstanceTypeDeclaration::Type(t) => ComponentTypeDeclaration::Type(t), + InstanceTypeDeclaration::Alias(a) => ComponentTypeDeclaration::Alias(a), + InstanceTypeDeclaration::Export { name, ty } => { + ComponentTypeDeclaration::Export { name, ty } + } }) } - pub(crate) fn read_instance_type(&mut self) -> Result> { + pub(crate) fn read_instance_type_decl(&mut self) -> Result> { Ok(match self.read_u8()? { - 0x01 => InstanceType::Type(self.read_component_type_def()?), - 0x07 => InstanceType::Export { + 0x00 => InstanceTypeDeclaration::CoreType(self.read_core_type()?), + 0x01 => InstanceTypeDeclaration::Type(self.read_component_type()?), + 0x02 => InstanceTypeDeclaration::Alias(self.read_component_alias()?), + 0x04 => InstanceTypeDeclaration::Export { name: self.read_string()?, - ty: self.read_var_u32()?, + ty: self.read_component_type_ref()?, }, - 0x09 => { - let offset = self.original_position(); - let alias = self.read_alias()?; - match alias { - Alias::OuterType { count, index } => InstanceType::OuterType { count, index }, - _ => { - return Err(BinaryReaderError::new( - "only aliases to outer types are supported in type definitions", - offset, - )) - } - } - } - x => return self.invalid_leading_byte(x, "type definition"), + x => return self.invalid_leading_byte(x, "component or instance type declaration"), }) } - fn primitive_it_from_byte(byte: u8) -> Option { + fn primitive_val_type_from_byte(byte: u8) -> Option { Some(match byte { - 0x7f => PrimitiveInterfaceType::Unit, - 0x7e => PrimitiveInterfaceType::Bool, - 0x7d => PrimitiveInterfaceType::S8, - 0x7c => PrimitiveInterfaceType::U8, - 0x7b => PrimitiveInterfaceType::S16, - 0x7a => PrimitiveInterfaceType::U16, - 0x79 => PrimitiveInterfaceType::S32, - 0x78 => PrimitiveInterfaceType::U32, - 0x77 => PrimitiveInterfaceType::S64, - 0x76 => PrimitiveInterfaceType::U64, - 0x75 => PrimitiveInterfaceType::Float32, - 0x74 => PrimitiveInterfaceType::Float64, - 0x73 => PrimitiveInterfaceType::Char, - 0x72 => PrimitiveInterfaceType::String, + 0x7f => PrimitiveValType::Unit, + 0x7e => PrimitiveValType::Bool, + 0x7d => PrimitiveValType::S8, + 0x7c => PrimitiveValType::U8, + 0x7b => PrimitiveValType::S16, + 0x7a => PrimitiveValType::U16, + 0x79 => PrimitiveValType::S32, + 0x78 => PrimitiveValType::U32, + 0x77 => PrimitiveValType::S64, + 0x76 => PrimitiveValType::U64, + 0x75 => PrimitiveValType::Float32, + 0x74 => PrimitiveValType::Float64, + 0x73 => PrimitiveValType::Char, + 0x72 => PrimitiveValType::String, _ => return None, }) } @@ -385,8 +418,8 @@ impl<'a> BinaryReader<'a> { fn read_variant_case(&mut self) -> Result> { Ok(VariantCase { name: self.read_string()?, - ty: self.read_interface_type_ref()?, - default_to: match self.read_u8()? { + ty: self.read_component_val_type()?, + refines: match self.read_u8()? { 0x0 => None, 0x1 => Some(self.read_var_u32()?), x => return self.invalid_leading_byte(x, "variant case default"), @@ -394,45 +427,45 @@ impl<'a> BinaryReader<'a> { }) } - fn read_interface_type_ref(&mut self) -> Result { - if let Some(it) = Self::primitive_it_from_byte(self.peek()?) { + fn read_component_val_type(&mut self) -> Result { + if let Some(ty) = Self::primitive_val_type_from_byte(self.peek()?) { self.position += 1; - return Ok(InterfaceTypeRef::Primitive(it)); + return Ok(ComponentValType::Primitive(ty)); } - Ok(InterfaceTypeRef::Type(self.read_var_s33()? as u32)) + Ok(ComponentValType::Type(self.read_var_s33()? as u32)) } - fn read_interface_type(&mut self, byte: u8) -> Result> { + fn read_component_defined_type(&mut self, byte: u8) -> Result> { Ok(match byte { 0x71 => { let size = self.read_size(MAX_WASM_RECORD_FIELDS, "record field")?; - InterfaceType::Record( + ComponentDefinedType::Record( (0..size) - .map(|_| Ok((self.read_string()?, self.read_interface_type_ref()?))) + .map(|_| Ok((self.read_string()?, self.read_component_val_type()?))) .collect::>()?, ) } 0x70 => { let size = self.read_size(MAX_WASM_VARIANT_CASES, "variant cases")?; - InterfaceType::Variant( + ComponentDefinedType::Variant( (0..size) .map(|_| self.read_variant_case()) .collect::>()?, ) } - 0x6f => InterfaceType::List(self.read_interface_type_ref()?), + 0x6f => ComponentDefinedType::List(self.read_component_val_type()?), 0x6e => { let size = self.read_size(MAX_WASM_TUPLE_TYPES, "tuple types")?; - InterfaceType::Tuple( + ComponentDefinedType::Tuple( (0..size) - .map(|_| self.read_interface_type_ref()) + .map(|_| self.read_component_val_type()) .collect::>()?, ) } 0x6d => { let size = self.read_size(MAX_WASM_FLAG_NAMES, "flag names")?; - InterfaceType::Flags( + ComponentDefinedType::Flags( (0..size) .map(|_| self.read_string()) .collect::>()?, @@ -440,7 +473,7 @@ impl<'a> BinaryReader<'a> { } 0x6c => { let size = self.read_size(MAX_WASM_ENUM_CASES, "enum cases")?; - InterfaceType::Enum( + ComponentDefinedType::Enum( (0..size) .map(|_| self.read_string()) .collect::>()?, @@ -448,18 +481,18 @@ impl<'a> BinaryReader<'a> { } 0x6b => { let size = self.read_size(MAX_WASM_UNION_TYPES, "union types")?; - InterfaceType::Union( + ComponentDefinedType::Union( (0..size) - .map(|_| self.read_interface_type_ref()) + .map(|_| self.read_component_val_type()) .collect::>()?, ) } - 0x6a => InterfaceType::Option(self.read_interface_type_ref()?), - 0x69 => InterfaceType::Expected { - ok: self.read_interface_type_ref()?, - error: self.read_interface_type_ref()?, + 0x6a => ComponentDefinedType::Option(self.read_component_val_type()?), + 0x69 => ComponentDefinedType::Expected { + ok: self.read_component_val_type()?, + error: self.read_component_val_type()?, }, - x => return self.invalid_leading_byte(x, "type"), + x => return self.invalid_leading_byte(x, "component defined type"), }) } @@ -471,29 +504,11 @@ impl<'a> BinaryReader<'a> { }) } - fn read_component_arg_kind(&mut self, desc: &str) -> Result { - Ok(match self.read_u8()? { - 0x00 => ComponentArgKind::Module(self.read_var_u32()?), - 0x01 => ComponentArgKind::Component(self.read_var_u32()?), - 0x02 => ComponentArgKind::Instance(self.read_var_u32()?), - 0x03 => ComponentArgKind::Function(self.read_var_u32()?), - 0x04 => ComponentArgKind::Value(self.read_var_u32()?), - 0x05 => ComponentArgKind::Type(self.read_var_u32()?), - x => return self.invalid_leading_byte(x, desc), - }) - } - - fn read_component_arg(&mut self) -> Result> { - Ok(ComponentArg { - name: self.read_string()?, - kind: self.read_component_arg_kind("component argument kind")?, - }) - } - pub(crate) fn read_component_export(&mut self) -> Result> { Ok(ComponentExport { name: self.read_string()?, - kind: self.read_component_arg_kind("component export kind")?, + kind: self.read_component_external_kind()?, + index: self.read_var_u32()?, }) } @@ -508,34 +523,56 @@ impl<'a> BinaryReader<'a> { pub(crate) fn read_component_import(&mut self) -> Result> { Ok(ComponentImport { name: self.read_string()?, - ty: self.read_var_u32()?, + ty: self.read_component_type_ref()?, + }) + } + + pub(crate) fn read_component_type_ref(&mut self) -> Result { + Ok(match self.read_component_external_kind()? { + ComponentExternalKind::Module => ComponentTypeRef::Module(self.read_var_u32()?), + ComponentExternalKind::Func => ComponentTypeRef::Func(self.read_var_u32()?), + ComponentExternalKind::Value => { + ComponentTypeRef::Value(self.read_component_val_type()?) + } + ComponentExternalKind::Type => { + ComponentTypeRef::Type(self.read_type_bounds()?, self.read_var_u32()?) + } + ComponentExternalKind::Instance => ComponentTypeRef::Instance(self.read_var_u32()?), + ComponentExternalKind::Component => ComponentTypeRef::Component(self.read_var_u32()?), + }) + } + + pub(crate) fn read_type_bounds(&mut self) -> Result { + Ok(match self.read_u8()? { + 0x00 => TypeBounds::Eq, + x => return self.invalid_leading_byte(x, "type bound"), }) } - pub(crate) fn read_component_func(&mut self) -> Result { + pub(crate) fn read_canonical_func(&mut self) -> Result { Ok(match self.read_u8()? { - 0x00 => { - let type_index = self.read_var_u32()?; - let options_size = self.read_size(MAX_WASM_FUNCTION_OPTIONS, "function options")?; - ComponentFunction::Lift { - type_index, - options: (0..options_size) + 0x00 => match self.read_u8()? { + 0x00 => CanonicalFunction::Lift { + core_func_index: self.read_var_u32()?, + options: (0..self + .read_size(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?) .map(|_| self.read_canonical_option()) .collect::>()?, + type_index: self.read_var_u32()?, + }, + x => return self.invalid_leading_byte(x, "canonical function lift"), + }, + 0x01 => match self.read_u8()? { + 0x00 => CanonicalFunction::Lower { func_index: self.read_var_u32()?, - } - } - 0x01 => { - let options_size = self.read_size(MAX_WASM_FUNCTION_OPTIONS, "function options")?; - - ComponentFunction::Lower { - options: (0..options_size) + options: (0..self + .read_size(MAX_WASM_CANONICAL_OPTIONS, "canonical options")?) .map(|_| self.read_canonical_option()) .collect::>()?, - func_index: self.read_var_u32()?, - } - } - x => return self.invalid_leading_byte(x, "component function"), + }, + x => return self.invalid_leading_byte(x, "canonical function lower"), + }, + x => return self.invalid_leading_byte(x, "canonical function"), }) } @@ -544,119 +581,138 @@ impl<'a> BinaryReader<'a> { 0x00 => CanonicalOption::UTF8, 0x01 => CanonicalOption::UTF16, 0x02 => CanonicalOption::CompactUTF16, - 0x03 => CanonicalOption::Into(self.read_var_u32()?), + 0x03 => CanonicalOption::Memory(self.read_var_u32()?), + 0x04 => CanonicalOption::Realloc(self.read_var_u32()?), + 0x05 => CanonicalOption::PostReturn(self.read_var_u32()?), x => return self.invalid_leading_byte(x, "canonical option"), }) } pub(crate) fn read_instance(&mut self) -> Result> { Ok(match self.read_u8()? { - 0x00 => match self.read_u8()? { - 0x00 => { - let index = self.read_var_u32()?; - let args_size = - self.read_size(MAX_WASM_INSTANTIATION_ARGS, "instantiation arguments")?; - Instance::Module { - index, - args: (0..args_size) - .map(|_| self.read_module_arg()) - .collect::>()?, - } - } - 0x01 => { - let index = self.read_var_u32()?; - let args_size = - self.read_size(MAX_WASM_INSTANTIATION_ARGS, "instantiation arguments")?; - Instance::Component { - index, - args: (0..args_size) - .map(|_| self.read_component_arg()) - .collect::>()?, - } - } - x => return self.invalid_leading_byte(x, "instance"), - }, - 0x01 => { - let size = - self.read_size(MAX_WASM_INSTANTIATION_EXPORTS, "instantiation exports")?; - Instance::ComponentFromExports( - (0..size) - .map(|_| self.read_component_export()) - .collect::>()?, - ) - } - 0x02 => { - let size = - self.read_size(MAX_WASM_INSTANTIATION_EXPORTS, "instantiation exports")?; - Instance::ModuleFromExports( - (0..size) - .map(|_| self.read_export()) - .collect::>()?, - ) - } + 0x00 => Instance::Instantiate { + module_index: self.read_var_u32()?, + args: (0..self + .read_size(MAX_WASM_INSTANTIATION_ARGS, "core instantiation arguments")?) + .map(|_| self.read_instantiation_arg()) + .collect::>()?, + }, + 0x01 => Instance::FromExports( + (0..self + .read_size(MAX_WASM_INSTANTIATION_EXPORTS, "core instantiation exports")?) + .map(|_| self.read_export()) + .collect::>()?, + ), + x => return self.invalid_leading_byte(x, "core instance"), + }) + } + + pub(crate) fn read_component_instance(&mut self) -> Result> { + Ok(match self.read_u8()? { + 0x00 => ComponentInstance::Instantiate { + component_index: self.read_var_u32()?, + args: (0..self + .read_size(MAX_WASM_INSTANTIATION_ARGS, "instantiation arguments")?) + .map(|_| self.read_component_instantiation_arg()) + .collect::>()?, + }, + 0x01 => ComponentInstance::FromExports( + (0..self.read_size(MAX_WASM_INSTANTIATION_EXPORTS, "instantiation exports")?) + .map(|_| self.read_component_export()) + .collect::>()?, + ), x => return self.invalid_leading_byte(x, "instance"), }) } - pub(crate) fn read_module_arg(&mut self) -> Result> { - let name = self.read_string()?; - let kind = match self.read_u8()? { - 0x02 => ModuleArgKind::Instance(self.read_var_u32()?), - x => return self.invalid_leading_byte(x, "module argument"), - }; + pub(crate) fn read_instantiation_arg_kind(&mut self) -> Result { + Ok(match self.read_u8()? { + 0x12 => InstantiationArgKind::Instance, + x => return self.invalid_leading_byte(x, "instantiation arg kind"), + }) + } + + pub(crate) fn read_instantiation_arg(&mut self) -> Result> { + Ok(InstantiationArg { + name: self.read_string()?, + kind: self.read_instantiation_arg_kind()?, + index: self.read_var_u32()?, + }) + } - Ok(ModuleArg { name, kind }) + pub(crate) fn read_component_instantiation_arg( + &mut self, + ) -> Result> { + Ok(ComponentInstantiationArg { + name: self.read_string()?, + kind: self.read_component_external_kind()?, + index: self.read_var_u32()?, + }) } pub(crate) fn read_alias(&mut self) -> Result> { - let preamble = self.read_u8()?; + let kind = self.read_external_kind()?; - Ok(match preamble { - 0x00 | 0x01 => { - let offset = self.original_position(); - let kind = self.read_u8()?; - let instance = self.read_var_u32()?; - let name = self.read_string()?; - - let kind = match (preamble, kind) { - (0x00, 0x00) => AliasKind::Module, - (0x00, 0x01) => AliasKind::Component, - (0x00, 0x02) => AliasKind::Instance, - (0x00, 0x03) => AliasKind::ComponentFunc, - (0x00, 0x04) => AliasKind::Value, - (0x01, 0x00) => AliasKind::Func, - (0x01, 0x01) => AliasKind::Table, - (0x01, 0x02) => AliasKind::Memory, - (0x01, 0x03) => AliasKind::Global, - (0x01, 0x04) => AliasKind::Tag, - (_, x) => { - return Err(Self::invalid_leading_byte_error( - x, - "export alias kind", - offset, - )) - } - }; + Ok(match self.read_u8()? { + 0x00 => Alias::InstanceExport { + kind, + instance_index: self.read_var_u32()?, + name: self.read_string()?, + }, + x => return self.invalid_leading_byte(x, "alias"), + }) + } - Alias::InstanceExport { - kind, - instance, - name, + fn component_outer_alias_kind_from_bytes( + byte1: u8, + byte2: Option, + offset: usize, + ) -> Result { + Ok(match byte1 { + 0x00 => match byte2.unwrap() { + 0x10 => ComponentOuterAliasKind::CoreType, + 0x11 => ComponentOuterAliasKind::CoreModule, + x => { + return Err(Self::invalid_leading_byte_error( + x, + "component outer alias kind", + offset + 1, + )) } + }, + 0x03 => ComponentOuterAliasKind::Type, + 0x04 => ComponentOuterAliasKind::Component, + x => { + return Err(Self::invalid_leading_byte_error( + x, + "component outer alias kind", + offset, + )) } - 0x02 => { - let offset = self.original_position(); - let kind = self.read_u8()?; - let count = self.read_var_u32()?; - let index = self.read_var_u32()?; + }) + } - match kind { - 0x00 => Alias::OuterModule { count, index }, - 0x01 => Alias::OuterComponent { count, index }, - 0x05 => Alias::OuterType { count, index }, - x => return Err(Self::invalid_leading_byte_error(x, "outer alias", offset)), - } - } + pub(crate) fn read_component_alias(&mut self) -> Result> { + // We don't know what type of alias it is yet, so just read the sort bytes + let offset = self.original_position(); + let byte1 = self.read_u8()?; + let byte2 = if byte1 == 0x00 { + Some(self.read_u8()?) + } else { + None + }; + + Ok(match self.read_u8()? { + 0x00 => ComponentAlias::InstanceExport { + kind: Self::component_external_kind_from_bytes(byte1, byte2, offset)?, + instance_index: self.read_var_u32()?, + name: self.read_string()?, + }, + 0x01 => ComponentAlias::Outer { + kind: Self::component_outer_alias_kind_from_bytes(byte1, byte2, offset)?, + count: self.read_var_u32()?, + index: self.read_var_u32()?, + }, x => return self.invalid_leading_byte(x, "alias"), }) } @@ -666,13 +722,13 @@ impl<'a> BinaryReader<'a> { ExternalKind::Func => TypeRef::Func(self.read_var_u32()?), ExternalKind::Table => TypeRef::Table(self.read_table_type()?), ExternalKind::Memory => TypeRef::Memory(self.read_memory_type()?), - ExternalKind::Tag => TypeRef::Tag(self.read_tag_type()?), ExternalKind::Global => TypeRef::Global(self.read_global_type()?), + ExternalKind::Tag => TypeRef::Tag(self.read_tag_type()?), }) } pub(crate) fn read_table_type(&mut self) -> Result { - let element_type = self.read_type()?; + let element_type = self.read_val_type()?; let has_max = match self.read_u8()? { 0x00 => false, 0x01 => true, @@ -747,7 +803,7 @@ impl<'a> BinaryReader<'a> { pub(crate) fn read_global_type(&mut self) -> Result { Ok(GlobalType { - content_type: self.read_type()?, + content_type: self.read_val_type()?, mutable: match self.read_u8()? { 0x00 => false, 0x01 => true, @@ -1437,15 +1493,15 @@ impl<'a> BinaryReader<'a> { Ok(self.buffer[self.position]) } - fn type_from_byte(byte: u8) -> Option { + fn val_type_from_byte(byte: u8) -> Option { match byte { - 0x7F => Some(Type::I32), - 0x7E => Some(Type::I64), - 0x7D => Some(Type::F32), - 0x7C => Some(Type::F64), - 0x7B => Some(Type::V128), - 0x70 => Some(Type::FuncRef), - 0x6F => Some(Type::ExternRef), + 0x7F => Some(ValType::I32), + 0x7E => Some(ValType::I64), + 0x7D => Some(ValType::F32), + 0x7C => Some(ValType::F64), + 0x7B => Some(ValType::V128), + 0x70 => Some(ValType::FuncRef), + 0x6F => Some(ValType::ExternRef), _ => None, } } @@ -1460,7 +1516,7 @@ impl<'a> BinaryReader<'a> { } // Check for a block type of form [] -> [t]. - if let Some(ty) = Self::type_from_byte(b) { + if let Some(ty) = Self::val_type_from_byte(b) { self.position += 1; return Ok(BlockType::Type(ty)); } @@ -1553,7 +1609,7 @@ impl<'a> BinaryReader<'a> { )); } Operator::TypedSelect { - ty: self.read_type()?, + ty: self.read_val_type()?, } } 0x20 => Operator::LocalGet { @@ -1797,7 +1853,7 @@ impl<'a> BinaryReader<'a> { 0xc4 => Operator::I64Extend32S, 0xd0 => Operator::RefNull { - ty: self.read_type()?, + ty: self.read_val_type()?, }, 0xd1 => Operator::RefIsNull, 0xd2 => Operator::RefFunc { diff --git a/crates/wasmparser/src/lib.rs b/crates/wasmparser/src/lib.rs index 67c28878ee..d8031c0405 100644 --- a/crates/wasmparser/src/lib.rs +++ b/crates/wasmparser/src/lib.rs @@ -26,14 +26,14 @@ #![deny(missing_docs)] pub use crate::binary_reader::{BinaryReader, BinaryReaderError, Result}; -pub use crate::module_resources::*; pub use crate::parser::*; pub use crate::readers::*; +pub use crate::resources::*; pub use crate::validator::*; mod binary_reader; mod limits; -mod module_resources; mod parser; mod readers; +mod resources; mod validator; diff --git a/crates/wasmparser/src/limits.rs b/crates/wasmparser/src/limits.rs index e430442579..a8a3011c05 100644 --- a/crates/wasmparser/src/limits.rs +++ b/crates/wasmparser/src/limits.rs @@ -15,6 +15,7 @@ // The following limits are imposed by wasmparser on WebAssembly modules. // The limits are agreed upon with other engines for consistency. +pub const MAX_WASM_TYPES: usize = 1_000_000; pub const MAX_WASM_FUNCTIONS: usize = 1_000_000; pub const MAX_WASM_EXPORTS: usize = 100_000; pub const MAX_WASM_GLOBALS: usize = 1_000_000; @@ -31,19 +32,14 @@ pub const _MAX_WASM_TABLE_SIZE: usize = 10_000_000; pub const MAX_WASM_TABLE_ENTRIES: usize = 10_000_000; pub const MAX_WASM_TABLES: usize = 100; pub const MAX_WASM_MEMORIES: usize = 100; -pub const MAX_WASM_MODULES: usize = 1_000; -pub const MAX_WASM_COMPONENTS: usize = 1_000; -pub const MAX_WASM_INSTANCES: usize = 1_000; -pub const MAX_WASM_VALUES: usize = 1_000; pub const MAX_WASM_TAGS: usize = 1_000_000; pub const MAX_WASM_BR_TABLE_SIZE: usize = MAX_WASM_FUNCTION_SIZE; // Component-related limits -pub const MAX_WASM_TYPES: usize = 1_000_000; pub const MAX_WASM_MODULE_SIZE: usize = 1024 * 1024 * 1024; //= 1 GiB -pub const MAX_WASM_MODULE_TYPEDEFS: usize = 1000; -pub const MAX_WASM_COMPONENT_TYPEDEFS: usize = 1000; -pub const MAX_WASM_INSTANCE_TYPEDEFS: usize = 1000; +pub const MAX_WASM_MODULE_TYPE_DECLS: usize = 1000; +pub const MAX_WASM_COMPONENT_TYPE_DECLS: usize = 1000; +pub const MAX_WASM_INSTANCE_TYPE_DECLS: usize = 1000; pub const MAX_WASM_RECORD_FIELDS: usize = 1000; pub const MAX_WASM_VARIANT_CASES: usize = 1000; pub const MAX_WASM_TUPLE_TYPES: usize = 1000; @@ -51,7 +47,11 @@ pub const MAX_WASM_FLAG_NAMES: usize = 1000; pub const MAX_WASM_ENUM_CASES: usize = 1000; pub const MAX_WASM_UNION_TYPES: usize = 1000; pub const MAX_WASM_INSTANTIATION_EXPORTS: usize = 1000; -pub const MAX_WASM_FUNCTION_OPTIONS: usize = 10; +pub const MAX_WASM_CANONICAL_OPTIONS: usize = 10; pub const MAX_WASM_INSTANTIATION_ARGS: usize = 1000; pub const MAX_WASM_START_ARGS: usize = 1000; pub const MAX_WASM_TYPE_SIZE: usize = 100_000; +pub const MAX_WASM_MODULES: usize = 1_000; +pub const MAX_WASM_COMPONENTS: usize = 1_000; +pub const MAX_WASM_INSTANCES: usize = 1_000; +pub const MAX_WASM_VALUES: usize = 1_000; diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index fa9c007c62..4a148029b1 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1,14 +1,12 @@ -use crate::limits::MAX_WASM_MODULE_SIZE; +use crate::CoreTypeSectionReader; use crate::{ - AliasSectionReader, ComponentExportSectionReader, ComponentFunctionSectionReader, - ComponentImportSectionReader, ComponentStartSectionReader, ComponentTypeSectionReader, - InstanceSectionReader, -}; -use crate::{ - BinaryReader, BinaryReaderError, CustomSectionReader, DataSectionReader, ElementSectionReader, + limits::MAX_WASM_MODULE_SIZE, AliasSectionReader, BinaryReader, BinaryReaderError, + ComponentAliasSectionReader, ComponentCanonicalSectionReader, ComponentExportSectionReader, + ComponentImportSectionReader, ComponentInstanceSectionReader, ComponentStartSectionReader, + ComponentTypeSectionReader, CustomSectionReader, DataSectionReader, ElementSectionReader, ExportSectionReader, FunctionBody, FunctionSectionReader, GlobalSectionReader, - ImportSectionReader, MemorySectionReader, Result, TableSectionReader, TagSectionReader, - TypeSectionReader, + ImportSectionReader, InstanceSectionReader, MemorySectionReader, Result, TableSectionReader, + TagSectionReader, TypeSectionReader, }; use std::convert::TryInto; use std::fmt; @@ -109,28 +107,28 @@ pub enum Payload<'a> { /// A module type section was received and the provided reader can be /// used to parse the contents of the type section. - TypeSection(crate::TypeSectionReader<'a>), + TypeSection(TypeSectionReader<'a>), /// A module import section was received and the provided reader can be /// used to parse the contents of the import section. - ImportSection(crate::ImportSectionReader<'a>), + ImportSection(ImportSectionReader<'a>), /// A module function section was received and the provided reader can be /// used to parse the contents of the function section. - FunctionSection(crate::FunctionSectionReader<'a>), + FunctionSection(FunctionSectionReader<'a>), /// A module table section was received and the provided reader can be /// used to parse the contents of the table section. - TableSection(crate::TableSectionReader<'a>), + TableSection(TableSectionReader<'a>), /// A module memory section was received and the provided reader can be /// used to parse the contents of the memory section. - MemorySection(crate::MemorySectionReader<'a>), + MemorySection(MemorySectionReader<'a>), /// A module tag section was received, and the provided reader can be /// used to parse the contents of the tag section. - TagSection(crate::TagSectionReader<'a>), + TagSection(TagSectionReader<'a>), /// A module global section was received and the provided reader can be /// used to parse the contents of the global section. - GlobalSection(crate::GlobalSectionReader<'a>), + GlobalSection(GlobalSectionReader<'a>), /// A module export section was received, and the provided reader can be /// used to parse the contents of the export section. - ExportSection(crate::ExportSectionReader<'a>), + ExportSection(ExportSectionReader<'a>), /// A module start section was received. StartSection { /// The start function index @@ -141,7 +139,7 @@ pub enum Payload<'a> { }, /// A module element section was received and the provided reader can be /// used to parse the contents of the element section. - ElementSection(crate::ElementSectionReader<'a>), + ElementSection(ElementSectionReader<'a>), /// A module data count section was received. DataCountSection { /// The number of data segments. @@ -152,18 +150,42 @@ pub enum Payload<'a> { }, /// A module data section was received and the provided reader can be /// used to parse the contents of the data section. - DataSection(crate::DataSectionReader<'a>), + DataSection(DataSectionReader<'a>), + /// Indicator of the start of the code section of a WebAssembly module. + /// + /// This entry is returned whenever the code section starts. The `count` + /// field indicates how many entries are in this code section. After + /// receiving this start marker you're guaranteed that the next `count` + /// items will be either `CodeSectionEntry` or an error will be returned. + /// + /// This, unlike other sections, is intended to be used for streaming the + /// contents of the code section. The code section is not required to be + /// fully resident in memory when we parse it. Instead a [`Parser`] is + /// capable of parsing piece-by-piece of a code section. + CodeSectionStart { + /// The number of functions in this section. + count: u32, + /// The range of bytes that represent this section, specified in + /// offsets relative to the start of the byte stream. + range: Range, + /// The size, in bytes, of the remaining contents of this section. + /// + /// This can be used in combination with [`Parser::skip_section`] + /// where the caller will know how many bytes to skip before feeding + /// bytes into `Parser` again. + size: u32, + }, + /// An entry of the code section, a function, was parsed from a WebAssembly + /// module. + /// + /// This entry indicates that a function was successfully received from the + /// code section, and the payload here is the window into the original input + /// where the function resides. Note that the function itself has not been + /// parsed, it's only been outlined. You'll need to process the + /// `FunctionBody` provided to test whether it parses and/or is valid. + CodeSectionEntry(FunctionBody<'a>), - /// A component type section was received and the provided reader can be - /// used to parse the contents of the type section. - ComponentTypeSection(crate::ComponentTypeSectionReader<'a>), - /// A component import section was received and the provided reader can be - /// used to parse the contents of the import section. - ComponentImportSection(crate::ComponentImportSectionReader<'a>), - /// A component function section was received and the provided reader can be - /// used to parse the contents of the function section. - ComponentFunctionSection(crate::ComponentFunctionSectionReader<'a>), - /// A component module section was received and the provided parser can be + /// A core module section was received and the provided parser can be /// used to parse the nested module. /// /// This variant is special in that it returns a sub-`Parser`. Upon @@ -182,6 +204,21 @@ pub enum Payload<'a> { /// original byte stream. range: Range, }, + /// A core instance section was received and the provided parser can be + /// used to parse the contents of the core instance section. + /// + /// Currently this section is only parsed in a component. + InstanceSection(InstanceSectionReader<'a>), + /// A core alias section was received and the provided parser can be + /// used to parse the contents of the core alias section. + /// + /// Currently this section is only parsed in a component. + AliasSection(AliasSectionReader<'a>), + /// A core type section was received and the provided parser can be + /// used to parse the contents of the core type section. + /// + /// Currently this section is only parsed in a component. + CoreTypeSection(CoreTypeSectionReader<'a>), /// A component section from a WebAssembly component was received and the /// provided parser can be used to parse the nested component. /// @@ -202,54 +239,29 @@ pub enum Payload<'a> { range: Range, }, /// A component instance section was received and the provided reader can be - /// used to parse the contents of the instance section. - InstanceSection(crate::InstanceSectionReader<'a>), - /// A component export section was received, and the provided reader can be - /// used to parse the contents of the export section. - ComponentExportSection(crate::ComponentExportSectionReader<'a>), - /// A component start section was received, and the provided reader can be - /// used to parse the contents of the start section. - ComponentStartSection(crate::ComponentStartSectionReader<'a>), + /// used to parse the contents of the component instance section. + ComponentInstanceSection(ComponentInstanceSectionReader<'a>), /// A component alias section was received and the provided reader can be - /// used to parse the contents of the alias section. - AliasSection(crate::AliasSectionReader<'a>), - - /// Indicator of the start of the code section of a WebAssembly module. - /// - /// This entry is returned whenever the code section starts. The `count` - /// field indicates how many entries are in this code section. After - /// receiving this start marker you're guaranteed that the next `count` - /// items will be either `CodeSectionEntry` or an error will be returned. - /// - /// This, unlike other sections, is intended to be used for streaming the - /// contents of the code section. The code section is not required to be - /// fully resident in memory when we parse it. Instead a [`Parser`] is - /// capable of parsing piece-by-piece of a code section. - CodeSectionStart { - /// The number of functions in this section. - count: u32, - /// The range of bytes that represent this section, specified in - /// offsets relative to the start of the byte stream. - range: Range, - /// The size, in bytes, of the remaining contents of this section. - /// - /// This can be used in combination with [`Parser::skip_section`] - /// where the caller will know how many bytes to skip before feeding - /// bytes into `Parser` again. - size: u32, - }, - /// An entry of the code section, a function, was parsed from a WebAssembly - /// module. - /// - /// This entry indicates that a function was successfully received from the - /// code section, and the payload here is the window into the original input - /// where the function resides. Note that the function itself has not been - /// parsed, it's only been outlined. You'll need to process the - /// `FunctionBody` provided to test whether it parses and/or is valid. - CodeSectionEntry(crate::FunctionBody<'a>), + /// used to parse the contents of the component alias section. + ComponentAliasSection(ComponentAliasSectionReader<'a>), + /// A component type section was received and the provided reader can be + /// used to parse the contents of the component type section. + ComponentTypeSection(ComponentTypeSectionReader<'a>), + /// A component canonical section was received and the provided reader can be + /// used to parse the contents of the component canonical section. + ComponentCanonicalSection(ComponentCanonicalSectionReader<'a>), + /// A component start section was received, and the provided reader can be + /// used to parse the contents of the component start section. + ComponentStartSection(ComponentStartSectionReader<'a>), + /// A component import section was received and the provided reader can be + /// used to parse the contents of the component import section. + ComponentImportSection(ComponentImportSectionReader<'a>), + /// A component export section was received, and the provided reader can be + /// used to parse the contents of the component export section. + ComponentExportSection(ComponentExportSectionReader<'a>), /// A module or component custom section was received. - CustomSection(crate::CustomSectionReader<'a>), + CustomSection(CustomSectionReader<'a>), /// An unknown section was found. /// @@ -391,15 +403,18 @@ impl Parser { /// } /// /// // Sections for WebAssembly components - /// ComponentTypeSection(_) => { /* ... */ } - /// ComponentImportSection(_) => { /* ... */ } - /// ComponentFunctionSection(_) => { /* ... */ } /// ModuleSection { .. } => { /* ... */ } - /// ComponentSection { .. } => { /* ... */ } /// InstanceSection(_) => { /* ... */ } - /// ComponentExportSection(_) => { /* ... */ } - /// ComponentStartSection { .. } => { /* ... */ } /// AliasSection(_) => { /* ... */ } + /// CoreTypeSection(_) => { /* ... */ } + /// ComponentSection { .. } => { /* ... */ } + /// ComponentInstanceSection(_) => { /* ... */ } + /// ComponentAliasSection(_) => { /* ... */ } + /// ComponentTypeSection(_) => { /* ... */ } + /// ComponentCanonicalSection(_) => { /* ... */ } + /// ComponentStartSection { .. } => { /* ... */ } + /// ComponentImportSection(_) => { /* ... */ } + /// ComponentExportSection(_) => { /* ... */ } /// /// CustomSection(_) => { /* ... */ } /// @@ -586,30 +601,13 @@ impl Parser { } // Component sections - (Encoding::Component, 1) => section( - reader, - len, - ComponentTypeSectionReader::new, - ComponentTypeSection, - ), - (Encoding::Component, 2) => section( - reader, - len, - ComponentImportSectionReader::new, - ComponentImportSection, - ), - (Encoding::Component, 3) => section( - reader, - len, - ComponentFunctionSectionReader::new, - ComponentFunctionSection, - ), - (Encoding::Component, 4) | (Encoding::Component, 5) => { + (Encoding::Component, 1 /* module */) + | (Encoding::Component, 5 /* component */) => { if len as usize > MAX_WASM_MODULE_SIZE { return Err(BinaryReaderError::new( format!( "{} section is too large", - if id == 4 { "module" } else { "component " } + if id == 1 { "module" } else { "component " } ), len_pos, )); @@ -623,29 +621,63 @@ impl Parser { parser.max_size = len.into(); Ok(match id { - 4 => ModuleSection { parser, range }, + 1 => ModuleSection { parser, range }, 5 => ComponentSection { parser, range }, _ => unreachable!(), }) } - (Encoding::Component, 6) => { + (Encoding::Component, 2) => { section(reader, len, InstanceSectionReader::new, InstanceSection) } + (Encoding::Component, 3) => { + section(reader, len, AliasSectionReader::new, AliasSection) + } + (Encoding::Component, 4) => { + section(reader, len, CoreTypeSectionReader::new, CoreTypeSection) + } + // Section 5 handled above + (Encoding::Component, 6) => section( + reader, + len, + ComponentInstanceSectionReader::new, + ComponentInstanceSection, + ), (Encoding::Component, 7) => section( reader, len, - ComponentExportSectionReader::new, - ComponentExportSection, + ComponentAliasSectionReader::new, + ComponentAliasSection, ), (Encoding::Component, 8) => section( + reader, + len, + ComponentTypeSectionReader::new, + ComponentTypeSection, + ), + (Encoding::Component, 9) => section( + reader, + len, + ComponentCanonicalSectionReader::new, + ComponentCanonicalSection, + ), + (Encoding::Component, 10) => section( reader, len, ComponentStartSectionReader::new, ComponentStartSection, ), - (Encoding::Component, 9) => { - section(reader, len, AliasSectionReader::new, AliasSection) - } + (Encoding::Component, 11) => section( + reader, + len, + ComponentImportSectionReader::new, + ComponentImportSection, + ), + (Encoding::Component, 12) => section( + reader, + len, + ComponentExportSectionReader::new, + ComponentExportSection, + ), (_, id) => { let offset = reader.original_position(); let contents = reader.read_bytes(len as usize)?; @@ -954,33 +986,42 @@ impl fmt::Debug for Payload<'_> { CodeSectionEntry(_) => f.debug_tuple("CodeSectionEntry").field(&"...").finish(), // Component sections - ComponentTypeSection(_) => f.debug_tuple("ComponentTypeSection").field(&"...").finish(), - ComponentImportSection(_) => f - .debug_tuple("ComponentImportSection") - .field(&"...") - .finish(), - ComponentFunctionSection(_) => f - .debug_tuple("ComponentFunctionSection") - .field(&"...") - .finish(), ModuleSection { parser: _, range } => f .debug_struct("ModuleSection") .field("range", range) .finish(), + InstanceSection(_) => f.debug_tuple("InstanceSection").field(&"...").finish(), + AliasSection(_) => f.debug_tuple("AliasSection").field(&"...").finish(), + CoreTypeSection(_) => f.debug_tuple("CoreTypeSection").field(&"...").finish(), ComponentSection { parser: _, range } => f .debug_struct("ComponentSection") .field("range", range) .finish(), - InstanceSection(_) => f.debug_tuple("InstanceSection").field(&"...").finish(), - ComponentExportSection(_) => f - .debug_tuple("ComponentExportSection") + ComponentInstanceSection(_) => f + .debug_tuple("ComponentInstanceSection") + .field(&"...") + .finish(), + ComponentAliasSection(_) => f + .debug_tuple("ComponentAliasSection") + .field(&"...") + .finish(), + ComponentTypeSection(_) => f.debug_tuple("ComponentTypeSection").field(&"...").finish(), + ComponentCanonicalSection(_) => f + .debug_tuple("ComponentCanonicalSection") .field(&"...") .finish(), ComponentStartSection(_) => f .debug_tuple("ComponentStartSection") .field(&"...") .finish(), - AliasSection(_) => f.debug_tuple("AliasSection").field(&"...").finish(), + ComponentImportSection(_) => f + .debug_tuple("ComponentImportSection") + .field(&"...") + .finish(), + ComponentExportSection(_) => f + .debug_tuple("ComponentExportSection") + .field(&"...") + .finish(), CustomSection(c) => f.debug_tuple("CustomSection").field(c).finish(), @@ -1312,7 +1353,7 @@ mod tests { assert_matches!(p.parse(&[4], false), Ok(Chunk::NeedMoreData(1))); // A module that's 8 bytes in length - let mut sub = match p.parse(&[4, 8], false) { + let mut sub = match p.parse(&[1, 8], false) { Ok(Chunk::Parsed { consumed: 2, payload: Payload::ModuleSection { parser, .. }, @@ -1363,7 +1404,7 @@ mod tests { let mut p = parser_after_component_header(); // A module that's 10 bytes in length - let mut sub = match p.parse(&[4, 10], false) { + let mut sub = match p.parse(&[1, 10], false) { Ok(Chunk::Parsed { consumed: 2, payload: Payload::ModuleSection { parser, .. }, diff --git a/crates/wasmparser/src/readers/component.rs b/crates/wasmparser/src/readers/component.rs index bd06d3f70e..268b264cce 100644 --- a/crates/wasmparser/src/readers/component.rs +++ b/crates/wasmparser/src/readers/component.rs @@ -1,14 +1,14 @@ mod aliases; +mod canonicals; mod exports; -mod functions; mod imports; mod instances; mod start; mod types; pub use self::aliases::*; +pub use self::canonicals::*; pub use self::exports::*; -pub use self::functions::*; pub use self::imports::*; pub use self::instances::*; pub use self::start::*; diff --git a/crates/wasmparser/src/readers/component/aliases.rs b/crates/wasmparser/src/readers/component/aliases.rs index 77dcc6b298..93848de754 100644 --- a/crates/wasmparser/src/readers/component/aliases.rs +++ b/crates/wasmparser/src/readers/component/aliases.rs @@ -1,67 +1,24 @@ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use crate::{ + BinaryReader, ComponentExternalKind, ExternalKind, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, +}; use std::ops::Range; -/// Represents a kind of alias. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AliasKind { - /// The alias is to a module. - Module, - /// The alias is to a component. - Component, - /// The alias is to an instance. - Instance, - /// The alias is to a component function. - ComponentFunc, - /// The alias is to a value. - Value, - /// The alias is to a core function. - Func, - /// The alias is to a table. - Table, - /// The alias is to a memory. - Memory, - /// The alias is to a global. - Global, - /// The alias is to a tag. - Tag, -} - -/// Represents an alias in a WebAssembly component. +/// Represents a core alias for a WebAssembly module. #[derive(Debug, Clone)] pub enum Alias<'a> { - /// The alias is to an export of an instance. + /// The alias is to an export of a module instance. InstanceExport { /// The alias kind. - kind: AliasKind, - /// The instance identifier. - instance: u32, + kind: ExternalKind, + /// The instance index. + instance_index: u32, /// The export name. name: &'a str, }, - /// The alias is to an outer module. - OuterModule { - /// The outward count, starting at zero for the current component. - count: u32, - /// The index of the module within the outer component. - index: u32, - }, - /// The alias is to an outer component. - OuterComponent { - /// The outward count, starting at zero for the current component. - count: u32, - /// The index of the component within the outer component. - index: u32, - }, - /// The alias is to an outer type. - OuterType { - /// The outward count, starting at zero for the current component. - count: u32, - /// The index of the type within the outer component. - index: u32, - }, } -/// A reader for the alias section of a WebAssembly component. +/// A reader for the core alias section of a WebAssembly component. #[derive(Clone)] pub struct AliasSectionReader<'a> { reader: BinaryReader<'a>, @@ -86,12 +43,12 @@ impl<'a> AliasSectionReader<'a> { self.count } - /// Reads content of the alias section. + /// Reads content of the core alias section. /// /// # Examples /// ``` /// use wasmparser::AliasSectionReader; - /// let data: &[u8] = &[0x01, 0x02, 0x00, 0x03, b'f', b'o', b'o']; + /// let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x03, b'f', b'o', b'o']; /// let mut reader = AliasSectionReader::new(data, 0).unwrap(); /// for _ in 0..reader.get_count() { /// let alias = reader.read().expect("alias"); @@ -137,3 +94,116 @@ impl<'a> IntoIterator for AliasSectionReader<'a> { SectionIteratorLimited::new(self) } } + +/// Represents the kind of an outer alias in a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentOuterAliasKind { + /// The alias is to a core module. + CoreModule, + /// The alias is to a core type. + CoreType, + /// The alias is to a component type. + Type, + /// The alias is to a component. + Component, +} + +/// Represents an alias in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentAlias<'a> { + /// The alias is to an export of a component instance. + InstanceExport { + /// The alias kind. + kind: ComponentExternalKind, + /// The instance index. + instance_index: u32, + /// The export name. + name: &'a str, + }, + /// The alias is to an outer item. + Outer { + /// The alias kind. + kind: ComponentOuterAliasKind, + /// The outward count, starting at zero for the current component. + count: u32, + /// The index of the item within the outer component. + index: u32, + }, +} + +/// A reader for the alias section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentAliasSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentAliasSectionReader<'a> { + /// Constructs a new `ComponentAliasSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the alias section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentAliasSectionReader; + /// let data: &[u8] = &[0x01, 0x01, 0x00, 0x00, 0x03, b'f', b'o', b'o']; + /// let mut reader = ComponentAliasSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let alias = reader.read().expect("alias"); + /// println!("Alias: {:?}", alias); + /// } + /// ``` + pub fn read(&mut self) -> Result> { + self.reader.read_component_alias() + } +} + +impl<'a> SectionReader for ComponentAliasSectionReader<'a> { + type Item = ComponentAlias<'a>; + + fn read(&mut self) -> Result { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentAliasSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentAliasSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/crates/wasmparser/src/readers/component/functions.rs b/crates/wasmparser/src/readers/component/canonicals.rs similarity index 60% rename from crates/wasmparser/src/readers/component/functions.rs rename to crates/wasmparser/src/readers/component/canonicals.rs index 5009acf7e1..321e63fad0 100644 --- a/crates/wasmparser/src/readers/component/functions.rs +++ b/crates/wasmparser/src/readers/component/canonicals.rs @@ -10,43 +10,49 @@ pub enum CanonicalOption { UTF16, /// The string types in the function signature are compact UTF-16 encoded. CompactUTF16, - /// The lifting or lowering operation requires access to a memory, realloc - /// function, or free function. + /// The memory to use if the lifting or lowering of a function requires memory access. /// - /// The value is expected to be an instance exporting the canonical ABI memory - /// and functions. - Into(u32), + /// The value is an index to a core memory. + Memory(u32), + /// The realloc function to use if the lifting or lowering of a function requires memory + /// allocation. + /// + /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. + Realloc(u32), + /// The post-return function to use if the lifting of a function requires + /// cleanup after the function returns. + PostReturn(u32), } -/// Represents a function in a WebAssembly component. +/// Represents a canonical function in a WebAssembly component. #[derive(Debug, Clone)] -pub enum ComponentFunction { - /// The function lifts a core WebAssembly function to the canonical interface ABI. +pub enum CanonicalFunction { + /// The function lifts a core WebAssembly function to the canonical ABI. Lift { + /// The index of the core WebAssembly function to lift. + core_func_index: u32, /// The index of the lifted function's type. type_index: u32, - /// The index of the core WebAssembly function to lift. - func_index: u32, /// The canonical options for the function. options: Box<[CanonicalOption]>, }, - /// The function lowers a canonical interface ABI function to a core WebAssembly function. + /// The function lowers a canonical ABI function to a core WebAssembly function. Lower { - /// The index of the component function to lower. + /// The index of the function to lower. func_index: u32, /// The canonical options for the function. options: Box<[CanonicalOption]>, }, } -/// A reader for the function section of a WebAssembly component. +/// A reader for the canonical section of a WebAssembly component. #[derive(Clone)] -pub struct ComponentFunctionSectionReader<'a> { +pub struct ComponentCanonicalSectionReader<'a> { reader: BinaryReader<'a>, count: u32, } -impl<'a> ComponentFunctionSectionReader<'a> { +impl<'a> ComponentCanonicalSectionReader<'a> { /// Constructs a new `ComponentFunctionSectionReader` for the given data and offset. pub fn new(data: &'a [u8], offset: usize) -> Result { let mut reader = BinaryReader::new_with_offset(data, offset); @@ -69,21 +75,21 @@ impl<'a> ComponentFunctionSectionReader<'a> { /// # Examples /// /// ``` - /// use wasmparser::ComponentFunctionSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x00, 0x00]; - /// let mut reader = ComponentFunctionSectionReader::new(data, 0).unwrap(); + /// use wasmparser::ComponentCanonicalSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00]; + /// let mut reader = ComponentCanonicalSectionReader::new(data, 0).unwrap(); /// for _ in 0..reader.get_count() { /// let func = reader.read().expect("func"); /// println!("Function: {:?}", func); /// } /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_component_func() + pub fn read(&mut self) -> Result { + self.reader.read_canonical_func() } } -impl<'a> SectionReader for ComponentFunctionSectionReader<'a> { - type Item = ComponentFunction; +impl<'a> SectionReader for ComponentCanonicalSectionReader<'a> { + type Item = CanonicalFunction; fn read(&mut self) -> Result { Self::read(self) @@ -102,14 +108,14 @@ impl<'a> SectionReader for ComponentFunctionSectionReader<'a> { } } -impl<'a> SectionWithLimitedItems for ComponentFunctionSectionReader<'a> { +impl<'a> SectionWithLimitedItems for ComponentCanonicalSectionReader<'a> { fn get_count(&self) -> u32 { Self::get_count(self) } } -impl<'a> IntoIterator for ComponentFunctionSectionReader<'a> { - type Item = Result; +impl<'a> IntoIterator for ComponentCanonicalSectionReader<'a> { + type Item = Result; type IntoIter = SectionIteratorLimited; fn into_iter(self) -> Self::IntoIter { diff --git a/crates/wasmparser/src/readers/component/exports.rs b/crates/wasmparser/src/readers/component/exports.rs index ca7aede979..dc08131c3a 100644 --- a/crates/wasmparser/src/readers/component/exports.rs +++ b/crates/wasmparser/src/readers/component/exports.rs @@ -1,11 +1,22 @@ -use crate::{ - BinaryReader, ComponentArgKind, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, -}; +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; use std::ops::Range; -/// Represents the kind of export in a WebAssembly component. -pub type ComponentExportKind = ComponentArgKind; +/// Represents the kind of an external items of a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentExternalKind { + /// The external kind is a core module. + Module, + /// The external kind is a function. + Func, + /// The external kind is a value. + Value, + /// The external kind is a type. + Type, + /// The external kind is an instance. + Instance, + /// The external kind is a component. + Component, +} /// Represents an export in a WebAssembly component. #[derive(Debug, Clone)] @@ -13,7 +24,9 @@ pub struct ComponentExport<'a> { /// The name of the exported item. pub name: &'a str, /// The kind of the export. - pub kind: ComponentExportKind, + pub kind: ComponentExternalKind, + /// The index of the exported item. + pub index: u32, } /// A reader for the export section of a WebAssembly component. @@ -47,7 +60,7 @@ impl<'a> ComponentExportSectionReader<'a> { /// ``` /// use wasmparser::ComponentExportSectionReader; /// - /// # let data: &[u8] = &[0x01, 0x03, b'f', b'o', b'o', 0x00, 0x03, 0x00]; + /// # let data: &[u8] = &[0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; /// let mut reader = ComponentExportSectionReader::new(data, 0).unwrap(); /// for _ in 0..reader.get_count() { /// let export = reader.read().expect("export"); diff --git a/crates/wasmparser/src/readers/component/imports.rs b/crates/wasmparser/src/readers/component/imports.rs index 2c8680aafb..0b7b4faf86 100644 --- a/crates/wasmparser/src/readers/component/imports.rs +++ b/crates/wasmparser/src/readers/component/imports.rs @@ -1,13 +1,50 @@ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use crate::{ + BinaryReader, ComponentValType, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; use std::ops::Range; +/// Represents the type bounds for imports and exports. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TypeBounds { + /// The type is bounded by equality. + Eq, +} + +/// Represents a reference to a component type. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentTypeRef { + /// The reference is to a core module type. + /// + /// The index is expected to be core type index to a core module type. + Module(u32), + /// The reference is to a function type. + /// + /// The index is expected to be a type index to a function type. + Func(u32), + /// The reference is to a value type. + Value(ComponentValType), + /// The reference is to a bounded type. + /// + /// The index is expected to be a type index. + Type(TypeBounds, u32), + /// The reference is to an instance type. + /// + /// The index is a type index to an instance type. + Instance(u32), + /// The reference is to a component type. + /// + /// The index is a type index to a component type. + Component(u32), +} + /// Represents an import in a WebAssembly component #[derive(Debug, Copy, Clone)] pub struct ComponentImport<'a> { /// The name of the imported item. pub name: &'a str, - /// The type index of the item being imported. - pub ty: u32, + /// The type reference for the import. + pub ty: ComponentTypeRef, } /// A reader for the import section of a WebAssembly component. diff --git a/crates/wasmparser/src/readers/component/instances.rs b/crates/wasmparser/src/readers/component/instances.rs index 5291a1880f..79cacfbe94 100644 --- a/crates/wasmparser/src/readers/component/instances.rs +++ b/crates/wasmparser/src/readers/component/instances.rs @@ -1,75 +1,42 @@ use crate::{ - BinaryReader, ComponentExport, Export, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, + BinaryReader, ComponentExport, ComponentExternalKind, Export, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, }; use std::ops::Range; -/// Represents the kind of argument when instantiating a WebAssembly module. -#[derive(Debug, Clone)] -pub enum ModuleArgKind { - /// The argument is an instance. - Instance(u32), +/// Represents the kind of an instantiation argument for a core instance. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum InstantiationArgKind { + /// The instantiation argument is a core instance. + Instance, } -/// Represents an argument to instantiating a WebAssembly component. +/// Represents an argument to instantiating a WebAssembly module. #[derive(Debug, Clone)] -pub struct ModuleArg<'a> { +pub struct InstantiationArg<'a> { /// The name of the module argument. pub name: &'a str, /// The kind of the module argument. - pub kind: ModuleArgKind, + pub kind: InstantiationArgKind, + /// The index of the argument item. + pub index: u32, } -/// Represents the kind of argument when instantiating a WebAssembly component. -#[derive(Debug, Clone)] -pub enum ComponentArgKind { - /// The argument is a module. - Module(u32), - /// The argument is a component. - Component(u32), - /// The argument is an instance. - Instance(u32), - /// The argument is a function. - Function(u32), - /// The argument is a value. - Value(u32), - /// The argument is a type. - Type(u32), -} - -/// Represents an argument to instantiating a WebAssembly component. -#[derive(Debug, Clone)] -pub struct ComponentArg<'a> { - /// The name of the component argument. - pub name: &'a str, - /// The kind of the component argument. - pub kind: ComponentArgKind, -} - -/// Represents an instance in a WebAssembly component. +/// Represents an instance of a WebAssembly module. #[derive(Debug, Clone)] pub enum Instance<'a> { /// The instance is from instantiating a WebAssembly module. - Module { + Instantiate { /// The module index. - index: u32, + module_index: u32, /// The module's instantiation arguments. - args: Box<[ModuleArg<'a>]>, + args: Box<[InstantiationArg<'a>]>, }, - /// The instance is from instantiating a WebAssembly component. - Component { - /// The component index. - index: u32, - /// The component's instantiation arguments. - args: Box<[ComponentArg<'a>]>, - }, - /// The instance is a module instance from exporting local items. - ModuleFromExports(Box<[Export<'a>]>), - /// The instance is a component instance from exporting local items. - ComponentFromExports(Box<[ComponentExport<'a>]>), + /// The instance is a from exporting local items. + FromExports(Box<[Export<'a>]>), } -/// A reader for the instance section of a WebAssembly component. +/// A reader for the core instance section of a WebAssembly component. #[derive(Clone)] pub struct InstanceSectionReader<'a> { reader: BinaryReader<'a>, @@ -99,7 +66,7 @@ impl<'a> InstanceSectionReader<'a> { /// # Examples /// ``` /// use wasmparser::InstanceSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x02, 0x00]; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00]; /// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); /// for _ in 0..reader.get_count() { /// let instance = reader.read().expect("instance"); @@ -147,7 +114,7 @@ impl<'a> IntoIterator for InstanceSectionReader<'a> { /// /// ``` /// use wasmparser::InstanceSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x02, 0x00]; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x12, 0x00]; /// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); /// for inst in reader { /// println!("Instance {:?}", inst.expect("instance")); @@ -157,3 +124,117 @@ impl<'a> IntoIterator for InstanceSectionReader<'a> { SectionIteratorLimited::new(self) } } + +/// Represents an argument to instantiating a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentInstantiationArg<'a> { + /// The name of the component argument. + pub name: &'a str, + /// The kind of the component argument. + pub kind: ComponentExternalKind, + /// The index of the argument item. + pub index: u32, +} + +/// Represents an instance in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentInstance<'a> { + /// The instance is from instantiating a WebAssembly component. + Instantiate { + /// The component index. + component_index: u32, + /// The component's instantiation arguments. + args: Box<[ComponentInstantiationArg<'a>]>, + }, + /// The instance is a from exporting local items. + FromExports(Box<[ComponentExport<'a>]>), +} + +/// A reader for the component instance section of a WebAssembly component. +#[derive(Clone)] +pub struct ComponentInstanceSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> ComponentInstanceSectionReader<'a> { + /// Constructs a new `ComponentInstanceSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the section reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets the count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the instance section. + /// + /// # Examples + /// ``` + /// use wasmparser::ComponentInstanceSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; + /// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let instance = reader.read().expect("instance"); + /// println!("Instance: {:?}", instance); + /// } + /// ``` + pub fn read(&mut self) -> Result> { + self.reader.read_component_instance() + } +} + +impl<'a> SectionReader for ComponentInstanceSectionReader<'a> { + type Item = ComponentInstance<'a>; + + fn read(&mut self) -> Result { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for ComponentInstanceSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for ComponentInstanceSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited; + + /// Implements iterator over the instance section. + /// + /// # Examples + /// + /// ``` + /// use wasmparser::ComponentInstanceSectionReader; + /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; + /// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); + /// for inst in reader { + /// println!("Instance {:?}", inst.expect("instance")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index a4e95535e2..8dc09d4967 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -1,98 +1,134 @@ use crate::{ - BinaryReader, ComponentImport, Import, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, TypeDef, TypeRef, + BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, FuncType, Import, Result, + SectionIteratorLimited, SectionReader, SectionWithLimitedItems, Type, TypeRef, }; use std::ops::Range; -/// Represents a type defined in a WebAssembly component. +/// Represents a core type in a WebAssembly component. #[derive(Debug, Clone)] -pub enum ComponentTypeDef<'a> { - /// The type is a module type. - Module(Box<[ModuleType<'a>]>), - /// The type is a component type. - Component(Box<[ComponentType<'a>]>), - /// The type is an instance type. - Instance(Box<[InstanceType<'a>]>), - /// The type is a function type. - Function(ComponentFuncType<'a>), - /// The type is for a value type. - Value(InterfaceTypeRef), - /// The type is for an interface type. - Interface(InterfaceType<'a>), +pub enum CoreType<'a> { + /// The type is for a core function. + Func(FuncType), + /// The type is for a core module. + Module(Box<[ModuleTypeDeclaration<'a>]>), } -/// Represents a module type definition in a WebAssembly component. +/// Represents a module type declaration in a WebAssembly component. #[derive(Debug, Clone)] -pub enum ModuleType<'a> { +pub enum ModuleTypeDeclaration<'a> { /// The module type definition is for a type. - Type(TypeDef), + Type(Type), /// The module type definition is for an export. Export { /// The name of the exported item. name: &'a str, - /// The type of the exported item. + /// The type reference of the export. ty: TypeRef, }, /// The module type definition is for an import. Import(Import<'a>), } -/// Represents a component type definition in a WebAssembly component. -#[derive(Debug, Clone)] -pub enum ComponentType<'a> { - /// The component type definition is for a type. - Type(ComponentTypeDef<'a>), - /// The component type definition is for an alias to an outer type. - OuterType { - /// The enclosing module count, starting at zero for current module. - count: u32, - /// The outer type index being aliased. - index: u32, - }, - /// The component type definition is for an export. - Export { - /// The name of the exported item. - name: &'a str, - /// The type index of the exported item. - ty: u32, - }, - /// The component type definition is for an import. - Import(ComponentImport<'a>), +/// A reader for the core type section of a WebAssembly component. +#[derive(Clone)] +pub struct CoreTypeSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, } -/// Represents an instance type definition in a WebAssembly component. -#[derive(Debug, Clone)] -pub enum InstanceType<'a> { - /// The instance type definition is for a type. - Type(ComponentTypeDef<'a>), - /// The instance type definition is for an alias to an outer type. - OuterType { - /// The enclosing module count, starting at zero for current module. - count: u32, - /// The outer type index being aliased. - index: u32, - }, - /// The instance type definition is for an export. - Export { - /// The name of the exported item. - name: &'a str, - /// The type index of the exported item. - ty: u32, - }, +impl<'a> CoreTypeSectionReader<'a> { + /// Constructs a new `CoreTypeSectionReader` for the given data and offset. + pub fn new(data: &'a [u8], offset: usize) -> Result { + let mut reader = BinaryReader::new_with_offset(data, offset); + let count = reader.read_var_u32()?; + Ok(Self { reader, count }) + } + + /// Gets the original position of the reader. + pub fn original_position(&self) -> usize { + self.reader.original_position() + } + + /// Gets a count of items in the section. + pub fn get_count(&self) -> u32 { + self.count + } + + /// Reads content of the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::CoreTypeSectionReader; + /// let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; + /// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap(); + /// for _ in 0..reader.get_count() { + /// let ty = reader.read().expect("type"); + /// println!("Type {:?}", ty); + /// } + /// ``` + pub fn read(&mut self) -> Result> { + self.reader.read_core_type() + } } -/// Represents a type of a function in a WebAssembly component. -#[derive(Debug, Clone)] -pub struct ComponentFuncType<'a> { - /// The function parameter types. - pub params: Box<[(Option<&'a str>, InterfaceTypeRef)]>, - /// The function result type. - pub result: InterfaceTypeRef, +impl<'a> SectionReader for CoreTypeSectionReader<'a> { + type Item = CoreType<'a>; + + fn read(&mut self) -> Result { + Self::read(self) + } + + fn eof(&self) -> bool { + self.reader.eof() + } + + fn original_position(&self) -> usize { + Self::original_position(self) + } + + fn range(&self) -> Range { + self.reader.range() + } +} + +impl<'a> SectionWithLimitedItems for CoreTypeSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for CoreTypeSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited; + + /// Implements iterator over the type section. + /// + /// # Examples + /// ``` + /// use wasmparser::CoreTypeSectionReader; + /// # let data: &[u8] = &[0x01, 0x60, 0x00, 0x00]; + /// let mut reader = CoreTypeSectionReader::new(data, 0).unwrap(); + /// for ty in reader { + /// println!("Type {:?}", ty.expect("type")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } } -/// Represents a primitive interface type. +/// Represents a value type in a WebAssembly component. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PrimitiveInterfaceType { +pub enum ComponentValType { + /// The value type is a primitive type. + Primitive(PrimitiveValType), + /// The value type is a reference to a defined type. + Type(u32), +} + +/// Represents a primitive value type. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PrimitiveValType { /// The type is the unit type. Unit, /// The type is a boolean. @@ -123,40 +159,37 @@ pub enum PrimitiveInterfaceType { String, } -impl PrimitiveInterfaceType { - pub(crate) fn requires_into_option(&self) -> bool { - matches!(self, PrimitiveInterfaceType::String) +impl PrimitiveValType { + pub(crate) fn requires_realloc(&self) -> bool { + matches!(self, Self::String) } pub(crate) fn is_subtype_of(&self, other: &Self) -> bool { - // Interface subtyping rules according to + // Subtyping rules according to // https://github.com/WebAssembly/component-model/blob/17f94ed1270a98218e0e796ca1dad1feb7e5c507/design/mvp/Subtyping.md self == other || matches!( (self, other), - (_, PrimitiveInterfaceType::Unit) - | (PrimitiveInterfaceType::S8, PrimitiveInterfaceType::S16) - | (PrimitiveInterfaceType::S8, PrimitiveInterfaceType::S32) - | (PrimitiveInterfaceType::S8, PrimitiveInterfaceType::S64) - | (PrimitiveInterfaceType::U8, PrimitiveInterfaceType::U16) - | (PrimitiveInterfaceType::U8, PrimitiveInterfaceType::U32) - | (PrimitiveInterfaceType::U8, PrimitiveInterfaceType::U64) - | (PrimitiveInterfaceType::U8, PrimitiveInterfaceType::S16) - | (PrimitiveInterfaceType::U8, PrimitiveInterfaceType::S32) - | (PrimitiveInterfaceType::U8, PrimitiveInterfaceType::S64) - | (PrimitiveInterfaceType::S16, PrimitiveInterfaceType::S32) - | (PrimitiveInterfaceType::S16, PrimitiveInterfaceType::S64) - | (PrimitiveInterfaceType::U16, PrimitiveInterfaceType::U32) - | (PrimitiveInterfaceType::U16, PrimitiveInterfaceType::U64) - | (PrimitiveInterfaceType::U16, PrimitiveInterfaceType::S32) - | (PrimitiveInterfaceType::U16, PrimitiveInterfaceType::S64) - | (PrimitiveInterfaceType::S32, PrimitiveInterfaceType::S64) - | (PrimitiveInterfaceType::U32, PrimitiveInterfaceType::U64) - | (PrimitiveInterfaceType::U32, PrimitiveInterfaceType::S64) - | ( - PrimitiveInterfaceType::Float32, - PrimitiveInterfaceType::Float64 - ) + (_, Self::Unit) + | (Self::S8, Self::S16) + | (Self::S8, Self::S32) + | (Self::S8, Self::S64) + | (Self::U8, Self::U16) + | (Self::U8, Self::U32) + | (Self::U8, Self::U64) + | (Self::U8, Self::S16) + | (Self::U8, Self::S32) + | (Self::U8, Self::S64) + | (Self::S16, Self::S32) + | (Self::S16, Self::S64) + | (Self::U16, Self::U32) + | (Self::U16, Self::U64) + | (Self::U16, Self::S32) + | (Self::U16, Self::S64) + | (Self::S32, Self::S64) + | (Self::U32, Self::U64) + | (Self::U32, Self::S64) + | (Self::Float32, Self::Float64) ) } @@ -168,53 +201,104 @@ impl PrimitiveInterfaceType { } } -/// Represents a reference to an interface type. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum InterfaceTypeRef { - /// The reference is to a primitive interface type. - Primitive(PrimitiveInterfaceType), - /// The reference is to an interface type defined in a type section. - Type(u32), +/// Represents a type in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentType<'a> { + /// The type is a component defined type. + Defined(ComponentDefinedType<'a>), + /// The type is a function type. + Func(ComponentFuncType<'a>), + /// The type is a component type. + Component(Box<[ComponentTypeDeclaration<'a>]>), + /// The type is an instance type. + Instance(Box<[InstanceTypeDeclaration<'a>]>), +} + +/// Represents part of a component type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentTypeDeclaration<'a> { + /// The component type declaration is for a core type. + CoreType(CoreType<'a>), + /// The component type declaration is for a type. + Type(ComponentType<'a>), + /// The component type declaration is for an alias. + Alias(ComponentAlias<'a>), + /// The component type declaration is for an export. + Export { + /// The name of the export. + name: &'a str, + /// The type reference for the export. + ty: ComponentTypeRef, + }, + /// The component type declaration is for an import. + Import(ComponentImport<'a>), +} + +/// Represents an instance type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum InstanceTypeDeclaration<'a> { + /// The component type declaration is for a core type. + CoreType(CoreType<'a>), + /// The instance type declaration is for a type. + Type(ComponentType<'a>), + /// The instance type declaration is for an alias. + Alias(ComponentAlias<'a>), + /// The instance type declaration is for an export. + Export { + /// The name of the export. + name: &'a str, + /// The type reference for the export. + ty: ComponentTypeRef, + }, +} + +/// Represents a type of a function in a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentFuncType<'a> { + /// The function parameter types. + pub params: Box<[(Option<&'a str>, ComponentValType)]>, + /// The function result type. + pub result: ComponentValType, } -/// Represents a case in a variant interface type. +/// Represents a case in a variant type. #[derive(Debug, Clone, PartialEq, Eq)] pub struct VariantCase<'a> { /// The name of the variant case. pub name: &'a str, - /// The interface type of the variant case. - pub ty: InterfaceTypeRef, - /// The default-to case index to use when this case is not present. - pub default_to: Option, + /// The value type of the variant case. + pub ty: ComponentValType, + /// The index of the variant case that is refined by this one. + pub refines: Option, } -/// Represents an interface type. +/// Represents a defined type in a WebAssembly component. #[derive(Debug, Clone, PartialEq, Eq)] -pub enum InterfaceType<'a> { - /// The interface type is one of the primitive types. - Primitive(PrimitiveInterfaceType), +pub enum ComponentDefinedType<'a> { + /// The type is one of the primitive value types. + Primitive(PrimitiveValType), /// The type is a record with the given fields. - Record(Box<[(&'a str, InterfaceTypeRef)]>), + Record(Box<[(&'a str, ComponentValType)]>), /// The type is a variant with the given cases. Variant(Box<[VariantCase<'a>]>), - /// The type is a list of the given interface type. - List(InterfaceTypeRef), - /// The type is a tuple of the given interface types. - Tuple(Box<[InterfaceTypeRef]>), + /// The type is a list of the given value type. + List(ComponentValType), + /// The type is a tuple of the given value types. + Tuple(Box<[ComponentValType]>), /// The type is flags with the given names. Flags(Box<[&'a str]>), /// The type is an enum with the given tags. Enum(Box<[&'a str]>), - /// The type is a union of the given interface types. - Union(Box<[InterfaceTypeRef]>), - /// The type is an option of the given interface type. - Option(InterfaceTypeRef), + /// The type is a union of the given value types. + Union(Box<[ComponentValType]>), + /// The type is an option of the given value type. + Option(ComponentValType), /// The type is an expected type. Expected { /// The type returned for success. - ok: InterfaceTypeRef, + ok: ComponentValType, /// The type returned for failure. - error: InterfaceTypeRef, + error: ComponentValType, }, } @@ -248,20 +332,20 @@ impl<'a> ComponentTypeSectionReader<'a> { /// # Examples /// ``` /// use wasmparser::ComponentTypeSectionReader; - /// let data: &[u8] = &[0x01, 0x4c, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72]; + /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72]; /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); /// for _ in 0..reader.get_count() { /// let ty = reader.read().expect("type"); /// println!("Type {:?}", ty); /// } /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_component_type_def() + pub fn read(&mut self) -> Result> { + self.reader.read_component_type() } } impl<'a> SectionReader for ComponentTypeSectionReader<'a> { - type Item = ComponentTypeDef<'a>; + type Item = ComponentType<'a>; fn read(&mut self) -> Result { Self::read(self) @@ -287,7 +371,7 @@ impl<'a> SectionWithLimitedItems for ComponentTypeSectionReader<'a> { } impl<'a> IntoIterator for ComponentTypeSectionReader<'a> { - type Item = Result>; + type Item = Result>; type IntoIter = SectionIteratorLimited; /// Implements iterator over the type section. @@ -295,7 +379,7 @@ impl<'a> IntoIterator for ComponentTypeSectionReader<'a> { /// # Examples /// ``` /// use wasmparser::ComponentTypeSectionReader; - /// # let data: &[u8] = &[0x01, 0x4c, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72]; + /// let data: &[u8] = &[0x01, 0x40, 0x01, 0x01, 0x03, b'f', b'o', b'o', 0x72, 0x72]; /// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); /// for ty in reader { /// println!("Type {:?}", ty.expect("type")); diff --git a/crates/wasmparser/src/readers/core/code.rs b/crates/wasmparser/src/readers/core/code.rs index e2fa60442d..500e3ad189 100644 --- a/crates/wasmparser/src/readers/core/code.rs +++ b/crates/wasmparser/src/readers/core/code.rs @@ -15,7 +15,7 @@ use crate::{ BinaryReader, BinaryReaderError, OperatorsReader, Result, SectionIteratorLimited, - SectionReader, SectionWithLimitedItems, Type, + SectionReader, SectionWithLimitedItems, ValType, }; use std::ops::Range; @@ -112,15 +112,15 @@ impl<'a> LocalsReader<'a> { } /// Reads an item from the reader. - pub fn read(&mut self) -> Result<(u32, Type)> { + pub fn read(&mut self) -> Result<(u32, ValType)> { let count = self.reader.read_var_u32()?; - let value_type = self.reader.read_type()?; + let value_type = self.reader.read_val_type()?; Ok((count, value_type)) } } impl<'a> IntoIterator for LocalsReader<'a> { - type Item = Result<(u32, Type)>; + type Item = Result<(u32, ValType)>; type IntoIter = LocalsIterator<'a>; fn into_iter(self) -> Self::IntoIter { let count = self.count; @@ -140,7 +140,7 @@ pub struct LocalsIterator<'a> { } impl<'a> Iterator for LocalsIterator<'a> { - type Item = Result<(u32, Type)>; + type Item = Result<(u32, ValType)>; fn next(&mut self) -> Option { if self.err || self.left == 0 { return None; diff --git a/crates/wasmparser/src/readers/core/elements.rs b/crates/wasmparser/src/readers/core/elements.rs index 3da203ac5c..e2707ef58f 100644 --- a/crates/wasmparser/src/readers/core/elements.rs +++ b/crates/wasmparser/src/readers/core/elements.rs @@ -15,7 +15,7 @@ use crate::{ BinaryReader, BinaryReaderError, ExternalKind, InitExpr, Result, SectionIteratorLimited, - SectionReader, SectionWithLimitedItems, Type, + SectionReader, SectionWithLimitedItems, ValType, }; use std::ops::Range; @@ -27,7 +27,7 @@ pub struct Element<'a> { /// The initial elements of the element segment. pub items: ElementItems<'a>, /// The type of the elements. - pub ty: Type, + pub ty: ValType, /// The range of the the element segment. pub range: Range, } @@ -256,10 +256,10 @@ impl<'a> ElementSectionReader<'a> { let exprs = flags & 0b100 != 0; let ty = if flags & 0b011 != 0 { if exprs { - self.reader.read_type()? + self.reader.read_val_type()? } else { match self.reader.read_external_kind()? { - ExternalKind::Func => Type::FuncRef, + ExternalKind::Func => ValType::FuncRef, _ => { return Err(BinaryReaderError::new( "only the function external type is supported in elem segment", @@ -269,7 +269,7 @@ impl<'a> ElementSectionReader<'a> { } } } else { - Type::FuncRef + ValType::FuncRef }; let data_start = self.reader.position; let items_count = self.reader.read_var_u32()?; diff --git a/crates/wasmparser/src/readers/core/imports.rs b/crates/wasmparser/src/readers/core/imports.rs index 81df2680d8..a8a7a5d5ae 100644 --- a/crates/wasmparser/src/readers/core/imports.rs +++ b/crates/wasmparser/src/readers/core/imports.rs @@ -19,7 +19,7 @@ use crate::{ }; use std::ops::Range; -/// Represents a reference to a type definition. +/// Represents a reference to a type definition in a WebAssembly module. #[derive(Debug, Clone, Copy)] pub enum TypeRef { /// The type is a function. diff --git a/crates/wasmparser/src/readers/core/operators.rs b/crates/wasmparser/src/readers/core/operators.rs index 7bc8cada14..f78e337c97 100644 --- a/crates/wasmparser/src/readers/core/operators.rs +++ b/crates/wasmparser/src/readers/core/operators.rs @@ -13,7 +13,7 @@ * limitations under the License. */ -use crate::{BinaryReader, BinaryReaderError, Result, Type}; +use crate::{BinaryReader, BinaryReaderError, Result, ValType}; /// Represents a block type. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -21,7 +21,7 @@ pub enum BlockType { /// The block produces consumes nor produces any values. Empty, /// The block produces a singular value of the given type ([] -> \[t]). - Type(Type), + Type(ValType), /// The block is described by a function type. /// /// The index is to a function type in the types section. @@ -166,7 +166,7 @@ pub enum Operator<'a> { Drop, Select, TypedSelect { - ty: Type, + ty: ValType, }, LocalGet { local_index: u32, @@ -273,7 +273,7 @@ pub enum Operator<'a> { value: Ieee64, }, RefNull { - ty: Type, + ty: ValType, }, RefIsNull, RefFunc { diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index 5ffc1adcec..bff2079ea3 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -18,27 +18,27 @@ use std::ops::Range; /// Represents the types of values in a WebAssembly module. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum Type { - /// The type is i32. +pub enum ValType { + /// The value type is i32. I32, - /// The type is i64. + /// The value type is i64. I64, - /// The type is f32. + /// The value type is f32. F32, - /// The type is f64. + /// The value type is f64. F64, - /// The type is v128. + /// The value type is v128. V128, - /// The type is a function reference. + /// The value type is a function reference. FuncRef, - /// The type is an extern reference. + /// The value type is an extern reference. ExternRef, } -/// Represents a type defined in a WebAssembly module. +/// Represents a type in a WebAssembly module. #[derive(Debug, Clone)] -pub enum TypeDef { - /// The type is a function. +pub enum Type { + /// The type is for a function. Func(FuncType), } @@ -46,16 +46,16 @@ pub enum TypeDef { #[derive(Debug, Clone, Eq, PartialEq, Hash)] pub struct FuncType { /// The function parameter types. - pub params: Box<[Type]>, + pub params: Box<[ValType]>, /// The function result types. - pub returns: Box<[Type]>, + pub returns: Box<[ValType]>, } /// Represents a table's type. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TableType { /// The table's element type. - pub element_type: Type, + pub element_type: ValType, /// Initial size of this table, in elements. pub initial: u32, /// Optional maximum size of the table, in elements. @@ -94,11 +94,11 @@ pub struct MemoryType { impl MemoryType { /// Gets the index type for the memory. - pub fn index_type(&self) -> Type { + pub fn index_type(&self) -> ValType { if self.memory64 { - Type::I64 + ValType::I64 } else { - Type::I32 + ValType::I32 } } } @@ -107,7 +107,7 @@ impl MemoryType { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct GlobalType { /// The global's type. - pub content_type: Type, + pub content_type: ValType, /// Whether or not the global is mutable. pub mutable: bool, } @@ -165,13 +165,13 @@ impl<'a> TypeSectionReader<'a> { /// println!("Type {:?}", ty); /// } /// ``` - pub fn read(&mut self) -> Result { - self.reader.read_type_def() + pub fn read(&mut self) -> Result { + self.reader.read_type() } } impl<'a> SectionReader for TypeSectionReader<'a> { - type Item = TypeDef; + type Item = Type; fn read(&mut self) -> Result { Self::read(self) @@ -197,7 +197,7 @@ impl<'a> SectionWithLimitedItems for TypeSectionReader<'a> { } impl<'a> IntoIterator for TypeSectionReader<'a> { - type Item = Result; + type Item = Result; type IntoIter = SectionIteratorLimited; /// Implements iterator over the type section. diff --git a/crates/wasmparser/src/module_resources.rs b/crates/wasmparser/src/resources.rs similarity index 93% rename from crates/wasmparser/src/module_resources.rs rename to crates/wasmparser/src/resources.rs index e306ad5ae7..a15c755af3 100644 --- a/crates/wasmparser/src/module_resources.rs +++ b/crates/wasmparser/src/resources.rs @@ -13,7 +13,7 @@ * limitations under the License. */ -use crate::{FuncType, GlobalType, MemoryType, TableType, Type}; +use crate::{FuncType, GlobalType, MemoryType, TableType, ValType}; use std::ops::Range; /// Types that qualify as Wasm function types for validation purposes. @@ -28,14 +28,14 @@ pub trait WasmFuncType { /// /// The returned type may be wrapped by the user crate and thus /// the actually returned type only has to be comparable to a Wasm type. - fn input_at(&self, at: u32) -> Option; + fn input_at(&self, at: u32) -> Option; /// Returns the type at given index if any. /// /// # Note /// /// The returned type may be wrapped by the user crate and thus /// the actually returned type only has to be comparable to a Wasm type. - fn output_at(&self, at: u32) -> Option; + fn output_at(&self, at: u32) -> Option; /// Returns the list of inputs as an iterator. fn inputs(&self) -> WasmFuncTypeInputs<'_, Self> @@ -70,10 +70,10 @@ where fn len_outputs(&self) -> usize { T::len_outputs(self) } - fn input_at(&self, at: u32) -> Option { + fn input_at(&self, at: u32) -> Option { T::input_at(self, at) } - fn output_at(&self, at: u32) -> Option { + fn output_at(&self, at: u32) -> Option { T::output_at(self, at) } } @@ -90,7 +90,7 @@ impl Iterator for WasmFuncTypeInputs<'_, T> where T: WasmFuncType, { - type Item = crate::Type; + type Item = crate::ValType; fn next(&mut self) -> Option { self.range @@ -144,7 +144,7 @@ impl Iterator for WasmFuncTypeOutputs<'_, T> where T: WasmFuncType, { - type Item = crate::Type; + type Item = crate::ValType; fn next(&mut self) -> Option { self.range @@ -211,7 +211,7 @@ pub trait WasmModuleResources { /// Returns the `FuncType` associated with the given function index. fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType>; /// Returns the element type at the given index. - fn element_type_at(&self, at: u32) -> Option; + fn element_type_at(&self, at: u32) -> Option; /// Returns the number of elements. fn element_count(&self) -> u32; @@ -246,7 +246,7 @@ where fn type_of_function(&self, func_idx: u32) -> Option<&Self::FuncType> { T::type_of_function(self, func_idx) } - fn element_type_at(&self, at: u32) -> Option { + fn element_type_at(&self, at: u32) -> Option { T::element_type_at(self, at) } @@ -291,7 +291,7 @@ where T::type_of_function(self, func_idx) } - fn element_type_at(&self, at: u32) -> Option { + fn element_type_at(&self, at: u32) -> Option { T::element_type_at(self, at) } @@ -317,11 +317,11 @@ impl WasmFuncType for FuncType { self.returns.len() } - fn input_at(&self, at: u32) -> Option { + fn input_at(&self, at: u32) -> Option { self.params.get(at as usize).copied() } - fn output_at(&self, at: u32) -> Option { + fn output_at(&self, at: u32) -> Option { self.returns.get(at as usize).copied() } } diff --git a/crates/wasmparser/src/validator.rs b/crates/wasmparser/src/validator.rs index 0c020790d9..f965af3d72 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -15,7 +15,7 @@ use crate::{ limits::*, BinaryReaderError, Encoding, FunctionBody, Parser, Payload, Result, SectionReader, - SectionWithLimitedItems, Type, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION, + SectionWithLimitedItems, ValType, WASM_COMPONENT_VERSION, WASM_MODULE_VERSION, }; use std::mem; use std::ops::Range; @@ -131,6 +131,7 @@ pub struct Validator { features: WasmFeatures, } +#[derive(Debug, Clone, Copy, Eq, PartialEq)] enum State { /// A header has not yet been parsed. /// @@ -150,42 +151,41 @@ enum State { } impl State { - fn ensure_module_state(&mut self, section: &str, offset: usize) -> Result<()> { + fn ensure_parsable(&self, offset: usize) -> Result<()> { match self { + Self::Module | Self::Component => Ok(()), Self::Unparsed(_) => Err(BinaryReaderError::new( - format!( - "unexpected module {} section before header was parsed", - section - ), - offset, - )), - Self::Module => Ok(()), - Self::Component => Err(BinaryReaderError::new( - format!( - "unexpected module {} section while parsing a component", - section - ), + "unexpected section before header was parsed", offset, )), Self::End => Err(BinaryReaderError::new( - format!( - "unexpected module {} section after parsing has completed", - section - ), + "unexpected section after parsing has completed", offset, )), } } - fn ensure_component_state(&self, section: &str, offset: usize) -> Result<()> { + fn ensure_module(&self, section: &str, offset: usize) -> Result<()> { + self.ensure_parsable(offset)?; + match self { - Self::Unparsed(_) => Err(BinaryReaderError::new( + Self::Module => Ok(()), + Self::Component => Err(BinaryReaderError::new( format!( - "unexpected component {} section before header was parsed", + "unexpected module {} section while parsing a component", section ), offset, )), + _ => unreachable!(), + } + } + + fn ensure_component(&self, section: &str, offset: usize) -> Result<()> { + self.ensure_parsable(offset)?; + + match self { + Self::Component => Ok(()), Self::Module => Err(BinaryReaderError::new( format!( "unexpected component {} section while parsing a module", @@ -193,14 +193,7 @@ impl State { ), offset, )), - Self::Component => Ok(()), - Self::End => Err(BinaryReaderError::new( - format!( - "unexpected component {} section after parsing has completed", - section - ), - offset, - )), + _ => unreachable!(), } } } @@ -249,17 +242,17 @@ pub struct WasmFeatures { } impl WasmFeatures { - pub(crate) fn check_value_type(&self, ty: Type) -> Result<(), &'static str> { + pub(crate) fn check_value_type(&self, ty: ValType) -> Result<(), &'static str> { match ty { - Type::I32 | Type::I64 | Type::F32 | Type::F64 => Ok(()), - Type::FuncRef | Type::ExternRef => { + ValType::I32 | ValType::I64 | ValType::F32 | ValType::F64 => Ok(()), + ValType::FuncRef | ValType::ExternRef => { if self.reference_types { Ok(()) } else { Err("reference types support is not enabled") } } - Type::V128 => { + ValType::V128 => { if self.simd { Ok(()) } else { @@ -419,21 +412,24 @@ impl Validator { DataSection(s) => self.data_section(s)?, // Component sections - ComponentTypeSection(s) => self.component_type_section(s)?, - ComponentImportSection(s) => self.component_import_section(s)?, - ComponentFunctionSection(s) => self.component_function_section(s)?, ModuleSection { parser, range, .. } => { self.module_section(range)?; return Ok(ValidPayload::Parser(parser.clone())); } + InstanceSection(s) => self.instance_section(s)?, + AliasSection(s) => self.alias_section(s)?, + CoreTypeSection(s) => self.core_type_section(s)?, ComponentSection { parser, range, .. } => { self.component_section(range)?; return Ok(ValidPayload::Parser(parser.clone())); } - InstanceSection(s) => self.instance_section(s)?, - ComponentExportSection(s) => self.component_export_section(s)?, + ComponentInstanceSection(s) => self.component_instance_section(s)?, + ComponentAliasSection(s) => self.component_alias_section(s)?, + ComponentTypeSection(s) => self.component_type_section(s)?, + ComponentCanonicalSection(s) => self.component_canonical_section(s)?, ComponentStartSection(s) => self.component_start_section(s)?, - AliasSection(s) => self.alias_section(s)?, + ComponentImportSection(s) => self.component_import_section(s)?, + ComponentExportSection(s) => self.component_export_section(s)?, End(offset) => return Ok(ValidPayload::End(self.end(*offset)?)), @@ -499,10 +495,8 @@ impl Validator { } /// Validates [`Payload::TypeSection`](crate::Payload). - /// - /// This method should only be called when parsing a module. pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Type, section, "type", @@ -531,7 +525,7 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn import_section(&mut self, section: &crate::ImportSectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Import, section, "import", @@ -549,7 +543,7 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn function_section(&mut self, section: &crate::FunctionSectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Function, section, "function", @@ -575,7 +569,7 @@ impl Validator { /// This method should only be called when parsing a module. pub fn table_section(&mut self, section: &crate::TableSectionReader<'_>) -> Result<()> { let features = self.features; - self.ensure_module_section( + self.process_module_section( Order::Table, section, "table", @@ -600,7 +594,7 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn memory_section(&mut self, section: &crate::MemorySectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Memory, section, "memory", @@ -632,7 +626,7 @@ impl Validator { )); } - self.ensure_module_section( + self.process_module_section( Order::Tag, section, "tag", @@ -660,7 +654,7 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn global_section(&mut self, section: &crate::GlobalSectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Global, section, "global", @@ -685,7 +679,7 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn export_section(&mut self, section: &crate::ExportSectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Export, section, "export", @@ -701,9 +695,9 @@ impl Validator { Ok(()) }, |state, features, _, e, offset| { - let module = state.module.assert_mut(); - let ty = module.export_to_entity_type(&e, offset)?; - module.add_export(e.name, ty, features, offset, false /* checked above */) + let state = state.module.assert_mut(); + let ty = state.export_to_entity_type(&e, offset)?; + state.add_export(e.name, ty, features, offset, false /* checked above */) }, ) } @@ -713,7 +707,7 @@ impl Validator { /// This method should only be called when parsing a module. pub fn start_section(&mut self, func: u32, range: &Range) -> Result<()> { let offset = range.start; - self.state.ensure_module_state("start", offset)?; + self.state.ensure_module("start", offset)?; let state = self.module.as_mut().unwrap(); state.update_order(Order::Start, offset)?; @@ -732,7 +726,7 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn element_section(&mut self, section: &crate::ElementSectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Element, section, "element", @@ -762,7 +756,8 @@ impl Validator { /// This method should only be called when parsing a module. pub fn data_count_section(&mut self, count: u32, range: &Range) -> Result<()> { let offset = range.start; - self.state.ensure_module_state("data count", offset)?; + self.state.ensure_module("data count", offset)?; + let state = self.module.as_mut().unwrap(); state.update_order(Order::DataCount, offset)?; @@ -782,7 +777,8 @@ impl Validator { /// This method should only be called when parsing a module. pub fn code_section_start(&mut self, count: u32, range: &Range) -> Result<()> { let offset = range.start; - self.state.ensure_module_state("code", offset)?; + self.state.ensure_module("code", offset)?; + let state = self.module.as_mut().unwrap(); state.update_order(Order::Code, offset)?; @@ -831,7 +827,8 @@ impl Validator { body: &crate::FunctionBody, ) -> Result> { let offset = body.range().start; - self.state.ensure_module_state("code", offset)?; + self.state.ensure_module("code", offset)?; + let state = self.module.as_mut().unwrap(); Ok(FuncValidator::new( @@ -847,7 +844,7 @@ impl Validator { /// /// This method should only be called when parsing a module. pub fn data_section(&mut self, section: &crate::DataSectionReader<'_>) -> Result<()> { - self.ensure_module_section( + self.process_module_section( Order::Data, section, "data", @@ -865,124 +862,101 @@ impl Validator { ) } - /// Validates [`Payload::ComponentTypeSection`](crate::Payload). + /// Validates [`Payload::ModuleSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn component_type_section( - &mut self, - section: &crate::ComponentTypeSectionReader, - ) -> Result<()> { - self.ensure_component_section( + pub fn module_section(&mut self, range: &Range) -> Result<()> { + self.state.ensure_component("module", range.start)?; + + let current = self.components.last_mut().unwrap(); + check_max( + current.core_modules.len(), + 1, + MAX_WASM_MODULES, + "modules", + range.start, + )?; + + match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) { + State::Component => {} + _ => unreachable!(), + } + + Ok(()) + } + + /// Validates [`Payload::InstanceSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> { + self.process_component_section( section, - "type", - |components, types, count, offset| { + "core instance", + |components, _, count, offset| { let current = components.last_mut().unwrap(); - check_max(current.types.len(), count, MAX_WASM_TYPES, "types", offset)?; - types.reserve(count as usize); - current.types.reserve(count as usize); + check_max( + current.instance_count(), + count, + MAX_WASM_INSTANCES, + "instances", + offset, + )?; + current.core_instances.reserve(count as usize); Ok(()) }, - |components, types, features, ty, offset| { - ComponentState::add_type( - components, ty, features, types, offset, false, /* checked above */ - ) + |components, types, _, instance, offset| { + components + .last_mut() + .unwrap() + .add_core_instance(instance, types, offset) }, ) } - /// Validates [`Payload::ComponentImportSection`](crate::Payload). + /// Validates [`Payload::AliasSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn component_import_section( - &mut self, - section: &crate::ComponentImportSectionReader, - ) -> Result<()> { - self.ensure_component_section( + pub fn alias_section(&mut self, section: &crate::AliasSectionReader) -> Result<()> { + self.process_component_section( section, - "import", - |_, _, _, _| Ok(()), // add_import will check limits - |components, types, _, import, offset| { + "core alias", + |_, _, _, _| Ok(()), // maximums checked via `add_alias` + |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { components .last_mut() .unwrap() - .add_import(import, types, offset) + .add_core_alias(alias, types, offset) }, ) } - /// Validates [`Payload::ComponentFunctionSection`](crate::Payload). + /// Validates [`Payload::CoreTypeSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn component_function_section( - &mut self, - section: &crate::ComponentFunctionSectionReader, - ) -> Result<()> { - self.ensure_component_section( + pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> { + self.process_component_section( section, - "function", - |components, _, count, offset| { + "core type", + |components, types, count, offset| { let current = components.last_mut().unwrap(); - check_max( - current.functions.len(), - count, - MAX_WASM_FUNCTIONS, - "functions", - offset, - )?; - current.functions.reserve(count as usize); + check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?; + types.reserve(count as usize); + current.core_types.reserve(count as usize); Ok(()) }, - |components, types, _, func, offset| { + |components, types, features, ty, offset| { let current = components.last_mut().unwrap(); - match func { - crate::ComponentFunction::Lift { - type_index, - func_index, - options, - } => current.lift_function( - type_index, - func_index, - options.into_vec(), - types, - offset, - ), - crate::ComponentFunction::Lower { - func_index, - options, - } => current.lower_function(func_index, options.into_vec(), types, offset), - } + current.add_core_type(ty, features, types, offset, false /* checked above */) }, ) } - /// Validates [`Payload::ModuleSection`](crate::Payload). - /// - /// This method should only be called when parsing a component. - pub fn module_section(&mut self, range: &Range) -> Result<()> { - self.state.ensure_component_state("module", range.start)?; - let current = self.components.last_mut().unwrap(); - check_max( - current.modules.len(), - 1, - MAX_WASM_MODULES, - "modules", - range.start, - )?; - - match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Module))) { - State::Component => {} - _ => unreachable!(), - } - - Ok(()) - } - /// Validates [`Payload::ComponentSection`](crate::Payload). /// /// This method should only be called when parsing a component. pub fn component_section(&mut self, range: &Range) -> Result<()> { - self.state - .ensure_component_state("component", range.start)?; + self.state.ensure_component("component", range.start)?; + let current = self.components.last_mut().unwrap(); check_max( current.components.len(), @@ -1000,17 +974,20 @@ impl Validator { Ok(()) } - /// Validates [`Payload::InstanceSection`](crate::Payload). + /// Validates [`Payload::ComponentInstanceSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> { - self.ensure_component_section( + pub fn component_instance_section( + &mut self, + section: &crate::ComponentInstanceSectionReader, + ) -> Result<()> { + self.process_component_section( section, "instance", |components, _, count, offset| { let current = components.last_mut().unwrap(); check_max( - current.instances.len(), + current.instance_count(), count, MAX_WASM_INSTANCES, "instances", @@ -1028,32 +1005,89 @@ impl Validator { ) } - /// Validates [`Payload::ComponentExportSection`](crate::Payload). + /// Validates [`Payload::ComponentAliasSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn component_export_section( + pub fn component_alias_section( &mut self, - section: &crate::ComponentExportSectionReader, + section: &crate::ComponentAliasSectionReader, ) -> Result<()> { - self.ensure_component_section( + self.process_component_section( section, - "export", + "alias", + |_, _, _, _| Ok(()), // maximums checked via `add_alias` + |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { + ComponentState::add_alias(components, alias, types, offset) + }, + ) + } + + /// Validates [`Payload::ComponentTypeSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + pub fn component_type_section( + &mut self, + section: &crate::ComponentTypeSectionReader, + ) -> Result<()> { + self.process_component_section( + section, + "type", + |components, types, count, offset| { + let current = components.last_mut().unwrap(); + check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?; + types.reserve(count as usize); + current.types.reserve(count as usize); + Ok(()) + }, + |components, types, features, ty, offset| { + ComponentState::add_type( + components, ty, features, types, offset, false, /* checked above */ + ) + }, + ) + } + + /// Validates [`Payload::ComponentCanonicalSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + pub fn component_canonical_section( + &mut self, + section: &crate::ComponentCanonicalSectionReader, + ) -> Result<()> { + self.process_component_section( + section, + "function", |components, _, count, offset| { let current = components.last_mut().unwrap(); check_max( - current.exports.len(), + current.function_count(), count, - MAX_WASM_EXPORTS, - "exports", + MAX_WASM_FUNCTIONS, + "functions", offset, )?; - current.exports.reserve(count as usize); + current.funcs.reserve(count as usize); Ok(()) }, - |components, types, _, export, offset| { + |components, types, _, func, offset| { let current = components.last_mut().unwrap(); - let ty = current.export_to_entity_type(&export, types, offset)?; - current.add_export(export.name, ty, offset, false /* checked above */) + match func { + crate::CanonicalFunction::Lift { + core_func_index, + type_index, + options, + } => current.lift_function( + core_func_index, + type_index, + options.into_vec(), + types, + offset, + ), + crate::CanonicalFunction::Lower { + func_index, + options, + } => current.lower_function(func_index, options.into_vec(), types, offset), + } }, ) } @@ -1066,7 +1100,8 @@ impl Validator { section: &crate::ComponentStartSectionReader, ) -> Result<()> { let range = section.range(); - self.state.ensure_component_state("start", range.start)?; + self.state.ensure_component("start", range.start)?; + let f = section.clone().read()?; self.components.last_mut().unwrap().add_start( @@ -1077,16 +1112,52 @@ impl Validator { ) } - /// Validates [`Payload::AliasSection`](crate::Payload). + /// Validates [`Payload::ComponentImportSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn alias_section(&mut self, section: &crate::AliasSectionReader) -> Result<()> { - self.ensure_component_section( + pub fn component_import_section( + &mut self, + section: &crate::ComponentImportSectionReader, + ) -> Result<()> { + self.process_component_section( section, - "alias", - |_, _, _, _| Ok(()), // maximums checked via `add_alias` - |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { - ComponentState::add_alias(components, alias, types, offset) + "import", + |_, _, _, _| Ok(()), // add_import will check limits + |components, types, _, import, offset| { + components + .last_mut() + .unwrap() + .add_import(import, types, offset) + }, + ) + } + + /// Validates [`Payload::ComponentExportSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + pub fn component_export_section( + &mut self, + section: &crate::ComponentExportSectionReader, + ) -> Result<()> { + self.process_component_section( + section, + "export", + |components, _, count, offset| { + let current = components.last_mut().unwrap(); + check_max( + current.exports.len(), + count, + MAX_WASM_EXPORTS, + "exports", + offset, + )?; + current.exports.reserve(count as usize); + Ok(()) + }, + |components, _, _, export, offset| { + let current = components.last_mut().unwrap(); + let ty = current.export_to_entity_type(&export, offset)?; + current.add_export(export.name, ty, offset, false /* checked above */) }, ) } @@ -1121,7 +1192,7 @@ impl Validator { // If there's a parent component, we'll add a module to the parent state // and continue to validate the component if let Some(parent) = self.components.last_mut() { - parent.add_module(&state.module, &mut self.types, offset)?; + parent.add_core_module(&state.module, &mut self.types, offset)?; self.state = State::Component; } @@ -1145,7 +1216,7 @@ impl Validator { } } - fn ensure_module_section( + fn process_module_section( &mut self, order: Order, section: &T, @@ -1169,7 +1240,7 @@ impl Validator { T: SectionReader + Clone + SectionWithLimitedItems, { let offset = section.range().start; - self.state.ensure_module_state(name, offset)?; + self.state.ensure_module(name, offset)?; let state = self.module.as_mut().unwrap(); state.update_order(order, offset)?; @@ -1194,7 +1265,7 @@ impl Validator { Ok(()) } - fn ensure_component_section( + fn process_component_section( &mut self, section: &T, name: &str, @@ -1219,7 +1290,7 @@ impl Validator { )); } - self.state.ensure_component_state(name, offset)?; + self.state.ensure_component(name, offset)?; validate_section( &mut self.components, &mut self.types, @@ -1248,7 +1319,7 @@ impl Validator { #[cfg(test)] mod tests { - use crate::{GlobalType, MemoryType, TableType, Type, Validator, WasmFeatures}; + use crate::{GlobalType, MemoryType, TableType, ValType, Validator, WasmFeatures}; use anyhow::Result; #[test] @@ -1288,15 +1359,15 @@ mod tests { match types.func_type_at(0) { Some(ty) => { - assert_eq!(ty.params.as_ref(), [Type::I32, Type::I64]); - assert_eq!(ty.returns.as_ref(), [Type::I32]); + assert_eq!(ty.params.as_ref(), [ValType::I32, ValType::I64]); + assert_eq!(ty.returns.as_ref(), [ValType::I32]); } _ => unreachable!(), } match types.func_type_at(1) { Some(ty) => { - assert_eq!(ty.params.as_ref(), [Type::I64, Type::I32]); + assert_eq!(ty.params.as_ref(), [ValType::I64, ValType::I32]); assert_eq!(ty.returns.as_ref(), []); } _ => unreachable!(), @@ -1317,35 +1388,35 @@ mod tests { Some(TableType { initial: 10, maximum: None, - element_type: Type::FuncRef, + element_type: ValType::FuncRef, }) ); assert_eq!( types.global_at(0), Some(GlobalType { - content_type: Type::I32, + content_type: ValType::I32, mutable: true }) ); match types.function_at(0) { Some(ty) => { - assert_eq!(ty.params.as_ref(), [Type::I32, Type::I64]); - assert_eq!(ty.returns.as_ref(), [Type::I32]); + assert_eq!(ty.params.as_ref(), [ValType::I32, ValType::I64]); + assert_eq!(ty.returns.as_ref(), [ValType::I32]); } _ => unreachable!(), } match types.tag_at(0) { Some(ty) => { - assert_eq!(ty.params.as_ref(), [Type::I64, Type::I32]); + assert_eq!(ty.params.as_ref(), [ValType::I64, ValType::I32]); assert_eq!(ty.returns.as_ref(), []); } _ => unreachable!(), } - assert_eq!(types.element_at(0), Some(Type::FuncRef)); + assert_eq!(types.element_at(0), Some(ValType::FuncRef)); Ok(()) } diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 30545b0795..0168fb734b 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -4,32 +4,41 @@ use super::{ check_max, combine_type_sizes, core::Module, types::{ - ComponentFuncType, ComponentType, EntityType, InstanceType, InterfaceType, - InterfaceTypeRef, ModuleType, RecordType, TypeDef, TypeId, TypeList, VariantCase, + ComponentFuncType, ComponentInstanceType, ComponentInstanceTypeKind, ComponentType, + ComponentValType, EntityType, InstanceType, ModuleType, RecordType, Type, TypeId, TypeList, + VariantCase, }, }; use crate::{ limits::*, types::{ - ComponentEntityType, InstanceTypeKind, ModuleInstanceType, ModuleInstanceTypeKind, - TupleType, UnionType, VariantType, + ComponentDefinedType, ComponentEntityType, InstanceTypeKind, TupleType, UnionType, + VariantType, }, - BinaryReaderError, CanonicalOption, FuncType, GlobalType, MemoryType, PrimitiveInterfaceType, - Result, TableType, Type, WasmFeatures, + BinaryReaderError, CanonicalOption, ComponentExternalKind, ComponentOuterAliasKind, + ComponentTypeRef, ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, + PrimitiveValType, Result, TableType, TypeBounds, ValType, WasmFeatures, }; use std::{collections::HashMap, mem}; -pub struct ComponentState { +pub(crate) struct ComponentState { + // Core index spaces + pub core_types: Vec, + pub core_modules: Vec, + pub core_instances: Vec, + pub core_funcs: Vec, + pub core_memories: Vec, + pub core_tables: Vec, + pub core_globals: Vec, + pub core_tags: Vec, + + // Component index spaces pub types: Vec, - pub modules: Vec, - pub components: Vec, + pub funcs: Vec, + pub values: Vec<(ComponentValType, bool)>, pub instances: Vec, - pub functions: Vec, - pub values: Vec<(InterfaceTypeRef, bool)>, - pub memories: Vec, - pub tables: Vec, - pub globals: Vec, - pub tags: Vec, + pub components: Vec, + pub imports: HashMap, pub exports: HashMap, has_start: bool, @@ -37,53 +46,145 @@ pub struct ComponentState { } impl ComponentState { - pub(super) fn add_type( + pub fn type_count(&self) -> usize { + self.core_types.len() + self.types.len() + } + + pub fn instance_count(&self) -> usize { + self.core_instances.len() + self.instances.len() + } + + pub fn function_count(&self) -> usize { + self.core_funcs.len() + self.funcs.len() + } + + pub fn add_core_type( + &mut self, + ty: crate::CoreType, + features: &WasmFeatures, + types: &mut TypeList, + offset: usize, + check_limit: bool, + ) -> Result<()> { + let ty = match ty { + crate::CoreType::Func(ty) => Type::Func(ty), + crate::CoreType::Module(decls) => { + Type::Module(self.create_module_type(decls.into_vec(), features, types, offset)?) + } + }; + + if check_limit { + check_max(self.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; + } + + self.core_types.push(TypeId { + type_size: ty.type_size(), + index: types.len(), + }); + types.push(ty); + + Ok(()) + } + + pub fn add_core_module( + &mut self, + module: &Module, + types: &mut TypeList, + offset: usize, + ) -> Result<()> { + let imports = module.imports_for_module_type(offset)?; + + // We have to clone the module's imports and exports here + // because we cannot take the data out of the `MaybeOwned` + // as it might be shared with a function validator. + let ty = Type::Module(ModuleType { + type_size: module.type_size, + imports, + exports: module.exports.clone(), + }); + + self.core_modules.push(TypeId { + type_size: ty.type_size(), + index: types.len(), + }); + + types.push(ty); + + Ok(()) + } + + pub fn add_core_instance( + &mut self, + instance: crate::Instance, + types: &mut TypeList, + offset: usize, + ) -> Result<()> { + let instance = match instance { + crate::Instance::Instantiate { module_index, args } => { + self.instantiate_module(module_index, args.into_vec(), types, offset)? + } + crate::Instance::FromExports(exports) => { + self.instantiate_core_exports(exports.into_vec(), types, offset)? + } + }; + + self.core_instances.push(instance); + + Ok(()) + } + + pub fn add_core_alias( + &mut self, + alias: crate::Alias, + types: &TypeList, + offset: usize, + ) -> Result<()> { + match alias { + crate::Alias::InstanceExport { + instance_index, + kind, + name, + } => self.alias_core_instance_export(instance_index, kind, name, types, offset), + } + } + + pub fn add_type( components: &mut Vec, - def: crate::ComponentTypeDef, + ty: crate::ComponentType, features: &WasmFeatures, types: &mut TypeList, offset: usize, check_limit: bool, ) -> Result<()> { assert!(!components.is_empty()); - let ty = match def { - crate::ComponentTypeDef::Module(defs) => { - TypeDef::Module(components.last_mut().unwrap().create_module_type( - defs.into_vec(), - features, - types, - offset, - )?) - } - crate::ComponentTypeDef::Component(defs) => TypeDef::Component( - Self::create_component_type(components, defs.into_vec(), features, types, offset)?, - ), - crate::ComponentTypeDef::Instance(defs) => TypeDef::Instance( - Self::create_instance_type(components, defs.into_vec(), features, types, offset)?, - ), - crate::ComponentTypeDef::Function(ty) => TypeDef::ComponentFunc( + let ty = match ty { + crate::ComponentType::Defined(ty) => Type::Defined( components .last_mut() .unwrap() - .create_function_type(ty, types, offset)?, + .create_defined_type(ty, types, offset)?, ), - crate::ComponentTypeDef::Value(ty) => TypeDef::Value( + crate::ComponentType::Func(ty) => Type::ComponentFunc( components .last_mut() .unwrap() - .create_interface_type_ref(ty, types, offset)?, + .create_function_type(ty, types, offset)?, ), - crate::ComponentTypeDef::Interface(ty) => TypeDef::Interface( - components - .last_mut() - .unwrap() - .create_interface_type(ty, types, offset)?, + crate::ComponentType::Component(decls) => Type::Component(Self::create_component_type( + components, + decls.into_vec(), + features, + types, + offset, + )?), + crate::ComponentType::Instance(decls) => Type::ComponentInstance( + Self::create_instance_type(components, decls.into_vec(), features, types, offset)?, ), }; let current = components.last_mut().unwrap(); if check_limit { - check_max(current.types.len(), 1, MAX_WASM_TYPES, "types", offset)?; + check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; } current.types.push(TypeId { @@ -95,37 +196,38 @@ impl ComponentState { Ok(()) } - pub(super) fn add_import( + pub fn add_import( &mut self, import: crate::ComponentImport, types: &TypeList, offset: usize, ) -> Result<()> { - let ty = self.type_index_to_entity_type(import.ty, types, "imported", offset)?; - let (len, max, desc) = match ty { - ComponentEntityType::Module(_) => { - self.modules.push(self.types[import.ty as usize]); - (self.modules.len(), MAX_WASM_MODULES, "modules") + let entity = self.check_type_ref(&import.ty, types, offset)?; + + let (len, max, desc) = match entity { + ComponentEntityType::Module(id) => { + self.core_modules.push(id); + (self.core_modules.len(), MAX_WASM_MODULES, "modules") } - ComponentEntityType::Component(_) => { - self.components.push(self.types[import.ty as usize]); + ComponentEntityType::Component(id) => { + self.components.push(id); (self.components.len(), MAX_WASM_COMPONENTS, "components") } - ComponentEntityType::Instance(_) => { - self.instances.push(self.types[import.ty as usize]); - (self.instances.len(), MAX_WASM_INSTANCES, "instances") + ComponentEntityType::Instance(id) => { + self.instances.push(id); + (self.instance_count(), MAX_WASM_INSTANCES, "instances") } - ComponentEntityType::Func(_) => { - self.functions.push(self.types[import.ty as usize]); - (self.functions.len(), MAX_WASM_FUNCTIONS, "functions") + ComponentEntityType::Func(id) => { + self.funcs.push(id); + (self.function_count(), MAX_WASM_FUNCTIONS, "functions") } - ComponentEntityType::Value(it) => { - self.values.push((it, false)); + ComponentEntityType::Value(ty) => { + self.values.push((ty, false)); (self.values.len(), MAX_WASM_VALUES, "values") } - ComponentEntityType::Type(_) => { + ComponentEntityType::Type(..) => { return Err(BinaryReaderError::new( - "component types cannot be imported", + "component types cannot currently be imported", offset, )); } @@ -133,9 +235,13 @@ impl ComponentState { check_max(len, 0, max, desc, offset)?; - self.type_size = combine_type_sizes(self.type_size, ty.type_size(), offset)?; + self.type_size = combine_type_sizes(self.type_size, entity.type_size(), offset)?; - if self.imports.insert(import.name.to_string(), ty).is_some() { + if self + .imports + .insert(import.name.to_string(), entity) + .is_some() + { return Err(BinaryReaderError::new( format!("duplicate import name `{}` already defined", import.name), offset, @@ -145,7 +251,7 @@ impl ComponentState { Ok(()) } - pub(super) fn add_export( + pub fn add_export( &mut self, name: &str, ty: ComponentEntityType, @@ -168,16 +274,18 @@ impl ComponentState { Ok(()) } - pub(super) fn lift_function( + pub fn lift_function( &mut self, + core_func_index: u32, type_index: u32, - func_index: u32, options: Vec, types: &TypeList, offset: usize, ) -> Result<()> { let ty = self.function_type_at(type_index, types, offset)?; - let core_ty = types[self.core_function_at(func_index, types, offset)?].unwrap_func_type(); + let core_ty = types[self.core_function_at(core_func_index, offset)?] + .as_func_type() + .unwrap(); // Lifting a function is for an export, so match the expected canonical ABI // export signature @@ -185,46 +293,47 @@ impl ComponentState { if core_ty.params.as_ref() != params.as_slice() { return Err(BinaryReaderError::new( - format!("lowered parameter types `{:?}` do not match parameter types `{:?}` of core function {func_index}", params.as_slice(), core_ty.params), + format!("lowered parameter types `{:?}` do not match parameter types `{:?}` of core function {core_func_index}", params.as_slice(), core_ty.params), offset, )); } if core_ty.returns.as_ref() != results.as_slice() { return Err(BinaryReaderError::new( - format!("lowered result types `{:?}` do not match result types `{:?}` of core function {func_index}", results.as_slice(), core_ty.returns), + format!("lowered result types `{:?}` do not match result types `{:?}` of core function {core_func_index}", results.as_slice(), core_ty.returns), offset, )); } - self.check_options(&options, ty, types, offset)?; - self.functions.push(self.types[type_index as usize]); + self.check_options(ty, Some(core_ty), &options, types, offset)?; + self.funcs.push(self.types[type_index as usize]); Ok(()) } - pub(super) fn lower_function( + pub fn lower_function( &mut self, func_index: u32, options: Vec, types: &mut TypeList, offset: usize, ) -> Result<()> { - let ty = types[self.component_function_at(func_index, types, offset)?] - .unwrap_component_func_type(); + let ty = types[self.function_at(func_index, offset)?] + .as_component_func_type() + .unwrap(); - self.check_options(&options, ty, types, offset)?; + self.check_options(ty, None, &options, types, offset)?; // Lowering a function is for an import, so use a function type that matches // the expected canonical ABI import signature. let (params, results) = ty.lower(types, true); - let lowered_ty = TypeDef::Func(FuncType { + let lowered_ty = Type::Func(FuncType { params: params.as_slice().to_vec().into_boxed_slice(), returns: results.as_slice().to_vec().into_boxed_slice(), }); - self.functions.push(TypeId { + self.core_funcs.push(TypeId { type_size: lowered_ty.type_size(), index: types.len(), }); @@ -234,35 +343,8 @@ impl ComponentState { Ok(()) } - pub(super) fn add_module( - &mut self, - module: &Module, - types: &mut TypeList, - offset: usize, - ) -> Result<()> { - let imports = module.imports_for_module_type(offset)?; - - // We have to clone the module's imports and exports here - // because we cannot take the data out of the `MaybeOwned` - // as it might be shared with a function validator. - let ty = TypeDef::Module(ModuleType { - type_size: module.type_size, - imports, - exports: module.exports.clone(), - }); - - self.modules.push(TypeId { - type_size: ty.type_size(), - index: types.len(), - }); - - types.push(ty); - - Ok(()) - } - - pub(super) fn add_component(&mut self, component: &mut Self, types: &mut TypeList) { - let ty = TypeDef::Component(ComponentType { + pub fn add_component(&mut self, component: &mut Self, types: &mut TypeList) { + let ty = Type::Component(ComponentType { type_size: component.type_size, imports: mem::take(&mut component.imports), exports: mem::take(&mut component.exports), @@ -276,25 +358,20 @@ impl ComponentState { types.push(ty); } - pub(super) fn add_instance( + pub fn add_instance( &mut self, - instance: crate::Instance, + instance: crate::ComponentInstance, types: &mut TypeList, offset: usize, ) -> Result<()> { let instance = match instance { - crate::Instance::Module { index, args } => { - self.instantiate_module(index, args.into_vec(), types, offset)? - } - crate::Instance::Component { index, args } => { - self.instantiate_component(index, args.into_vec(), types, offset)? - } - crate::Instance::ComponentFromExports(exports) => { + crate::ComponentInstance::Instantiate { + component_index, + args, + } => self.instantiate_component(component_index, args.into_vec(), types, offset)?, + crate::ComponentInstance::FromExports(exports) => { self.instantiate_exports(exports.into_vec(), types, offset)? } - crate::Instance::ModuleFromExports(exports) => { - self.instantiate_core_exports(exports.into_vec(), types, offset)? - } }; self.instances.push(instance); @@ -302,7 +379,40 @@ impl ComponentState { Ok(()) } - pub(super) fn add_start( + pub fn add_alias( + components: &mut [Self], + alias: crate::ComponentAlias, + types: &TypeList, + offset: usize, + ) -> Result<()> { + match alias { + crate::ComponentAlias::InstanceExport { + instance_index, + kind, + name, + } => components.last_mut().unwrap().alias_instance_export( + instance_index, + kind, + name, + types, + offset, + ), + crate::ComponentAlias::Outer { kind, count, index } => match kind { + ComponentOuterAliasKind::CoreModule => { + Self::alias_module(components, count, index, offset) + } + ComponentOuterAliasKind::CoreType => { + Self::alias_core_type(components, count, index, offset) + } + ComponentOuterAliasKind::Type => Self::alias_type(components, count, index, offset), + ComponentOuterAliasKind::Component => { + Self::alias_component(components, count, index, offset) + } + }, + } + } + + pub fn add_start( &mut self, func_index: u32, args: &[u32], @@ -316,8 +426,9 @@ impl ComponentState { )); } - let ft = types[self.component_function_at(func_index, types, offset)?] - .unwrap_component_func_type(); + let ft = types[self.function_at(func_index, offset)?] + .as_component_func_type() + .unwrap(); if ft.params.len() != args.len() { return Err(BinaryReaderError::new( @@ -344,7 +455,7 @@ impl ComponentState { } match ft.result { - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Unit) => {} + ComponentValType::Primitive(PrimitiveValType::Unit) => {} ty => { self.values.push((ty, false)); } @@ -355,68 +466,11 @@ impl ComponentState { Ok(()) } - pub(super) fn add_alias( - components: &mut [Self], - alias: crate::Alias, - types: &TypeList, - offset: usize, - ) -> Result<()> { - assert!(!components.is_empty()); - match alias { - crate::Alias::InstanceExport { - kind, - instance, - name, - } => components - .last_mut() - .unwrap() - .alias_instance_export(kind, instance, name, types, offset), - crate::Alias::OuterModule { count, index } => { - Self::alias_module(components, count, index, offset) - } - crate::Alias::OuterComponent { count, index } => { - Self::alias_component(components, count, index, offset) - } - crate::Alias::OuterType { count, index } => { - Self::alias_type(components, count, index, offset) - } - } - } - - pub(super) fn export_to_entity_type( - &mut self, - export: &crate::ComponentExport, - types: &mut TypeList, - offset: usize, - ) -> Result { - Ok(match &export.kind { - crate::ComponentExportKind::Module(idx) => { - ComponentEntityType::Module(self.module_at(*idx, offset)?) - } - crate::ComponentExportKind::Component(idx) => { - ComponentEntityType::Component(self.component_at(*idx, offset)?) - } - crate::ComponentExportKind::Instance(idx) => { - self.component_instance_at(*idx, types, offset)?; - ComponentEntityType::Instance(self.instances[*idx as usize]) - } - crate::ComponentExportKind::Function(idx) => { - self.component_function_at(*idx, types, offset)?; - ComponentEntityType::Func(self.functions[*idx as usize]) - } - crate::ComponentExportKind::Value(idx) => { - ComponentEntityType::Value(*self.value_at(*idx, offset)?) - } - crate::ComponentExportKind::Type(idx) => { - ComponentEntityType::Type(self.type_at(*idx, offset)?) - } - }) - } - fn check_options( &self, - options: &[CanonicalOption], ty: &ComponentFuncType, + core_ty: Option<&FuncType>, + options: &[CanonicalOption], types: &TypeList, offset: usize, ) -> Result<()> { @@ -424,42 +478,17 @@ impl ComponentState { match option { CanonicalOption::UTF8 => "utf8", CanonicalOption::UTF16 => "utf16", - CanonicalOption::CompactUTF16 => "compact-utf16", - CanonicalOption::Into(_) => "into", + CanonicalOption::CompactUTF16 => "latin1-utf16", + CanonicalOption::Memory(_) => "memory", + CanonicalOption::Realloc(_) => "realloc", + CanonicalOption::PostReturn(_) => "post-return", } } - fn check_into_func( - into: &ModuleInstanceType, - name: &str, - params: &[Type], - returns: &[Type], - types: &TypeList, - offset: usize, - ) -> Result<()> { - match into.exports(types).get(name) { - Some(EntityType::Func(ty)) => { - let ty = types[*ty].unwrap_func_type(); - if ty.params.as_ref() != params || ty.returns.as_ref() != returns { - return Err(BinaryReaderError::new( - format!("instance specified by `into` option exports a function named `{}` with the wrong signature", name), - offset, - )); - } - } - _ => { - return Err(BinaryReaderError::new( - format!("instance specified by `into` option does not export a function named `{}`", name), - offset, - )); - } - } - - Ok(()) - } - let mut encoding = None; - let mut into = None; + let mut memory = None; + let mut realloc = None; + let mut post_return = None; for option in options { match option { @@ -468,9 +497,9 @@ impl ComponentState { Some(existing) => { return Err(BinaryReaderError::new( format!( - "canonical option `{}` conflicts with option `{}`", + "canonical encoding option `{}` conflicts with option `{}`", display(existing), - display(*option) + display(*option), ), offset, )) @@ -478,118 +507,205 @@ impl ComponentState { None => encoding = Some(*option), } } - CanonicalOption::Into(i) => { - into = match into { - None => Some(*i), + CanonicalOption::Memory(idx) => { + memory = match memory { + None => { + self.memory_at(*idx, offset)?; + Some(*idx) + } Some(_) => { return Err(BinaryReaderError::new( - "canonical option `into` is specified more than once", + "canonical option `memory` is specified more than once", offset, )) } } } - } - } - - match into { - Some(idx) => { - let into_ty = types[self.module_instance_at(idx, types, offset)?] - .unwrap_module_instance_type(); - - match into_ty.exports(types).get("memory") { - Some(EntityType::Memory(_)) => {} - _ => { - return Err(BinaryReaderError::new( - "instance specified by `into` option does not export a memory named `memory`", - offset, - )); + CanonicalOption::Realloc(idx) => { + realloc = match realloc { + None => { + let ty = types[self.core_function_at(*idx, offset)?] + .as_func_type() + .unwrap(); + if ty.params.as_ref() + != [ValType::I32, ValType::I32, ValType::I32, ValType::I32] + || ty.returns.as_ref() != [ValType::I32] + { + return Err(BinaryReaderError::new( + "canonical option `realloc` uses a core function with an incorrect signature", + offset, + )); + } + Some(*idx) + } + Some(_) => { + return Err(BinaryReaderError::new( + "canonical option `realloc` is specified more than once", + offset, + )) + } } } + CanonicalOption::PostReturn(idx) => { + post_return = match post_return { + None => { + let core_ty = core_ty.ok_or_else(|| { + BinaryReaderError::new( + "canonical option `post-return` cannot be specified for lowerings", + offset, + ) + })?; + + let ty = types[self.core_function_at(*idx, offset)?] + .as_func_type() + .unwrap(); + + if ty.params != core_ty.returns || !ty.returns.is_empty() { + return Err(BinaryReaderError::new( + "canonical option `post-return` uses a core function with an incorrect signature", + offset, + )); + } + Some(*idx) + } + Some(_) => { + return Err(BinaryReaderError::new( + "canonical option `post-return` is specified more than once", + offset, + )) + } + } + } + } + } - check_into_func( - into_ty, - "canonical_abi_realloc", - &[Type::I32, Type::I32, Type::I32, Type::I32], - &[Type::I32], - types, - offset, - )?; - check_into_func( - into_ty, - "canonical_abi_free", - &[Type::I32, Type::I32, Type::I32], - &[], - types, + if ty.requires_realloc(types) { + if memory.is_none() { + return Err(BinaryReaderError::new( + "canonical option `memory` is required", offset, - )?; + )); } - None => { - if ty.requires_into_option(types) { - return Err(BinaryReaderError::new( - "canonical option `into` is required", - offset, - )); - } + + if realloc.is_none() { + return Err(BinaryReaderError::new( + "canonical option `realloc` is required", + offset, + )); } } Ok(()) } - fn type_index_to_entity_type( + pub fn check_type_ref( &self, - ty: u32, + ty: &ComponentTypeRef, types: &TypeList, - desc: &str, offset: usize, ) -> Result { - Ok(match &types[self.type_at(ty, offset)?] { - TypeDef::Module(_) => ComponentEntityType::Module(self.types[ty as usize]), - TypeDef::Component(_) => ComponentEntityType::Component(self.types[ty as usize]), - TypeDef::Instance(_) => ComponentEntityType::Instance(self.types[ty as usize]), - TypeDef::ComponentFunc(_) => ComponentEntityType::Func(self.types[ty as usize]), - TypeDef::Value(ty) => ComponentEntityType::Value(*ty), - TypeDef::Interface(_) => ComponentEntityType::Type(self.types[ty as usize]), - TypeDef::ModuleInstance(_) => { - return Err(BinaryReaderError::new( - format!("module instances types cannot be {}", desc), - offset, - )) + Ok(match ty { + ComponentTypeRef::Module(index) => { + let id = self.type_at(*index, true, offset)?; + types[id].as_module_type().ok_or_else(|| { + BinaryReaderError::new( + format!("core type index {} is not a module type", index), + offset, + ) + })?; + ComponentEntityType::Module(id) } - TypeDef::Func(_) => { - return Err(BinaryReaderError::new( - format!("core function types cannot be {}", desc), - offset, - )) + ComponentTypeRef::Func(index) => { + let id = self.type_at(*index, false, offset)?; + types[id].as_component_func_type().ok_or_else(|| { + BinaryReaderError::new( + format!("type index {} is not a function type", index), + offset, + ) + })?; + ComponentEntityType::Func(id) + } + ComponentTypeRef::Value(ty) => { + let ty = match ty { + crate::ComponentValType::Primitive(ty) => ComponentValType::Primitive(*ty), + crate::ComponentValType::Type(index) => { + ComponentValType::Type(self.defined_type_at(*index, types, offset)?) + } + }; + ComponentEntityType::Value(ty) + } + ComponentTypeRef::Type(TypeBounds::Eq, index) => { + ComponentEntityType::Type(self.type_at(*index, false, offset)?) + } + ComponentTypeRef::Instance(index) => { + let id = self.type_at(*index, false, offset)?; + types[id].as_component_instance_type().ok_or_else(|| { + BinaryReaderError::new( + format!("type index {} is not an instance type", index), + offset, + ) + })?; + ComponentEntityType::Instance(id) + } + ComponentTypeRef::Component(index) => { + let id = self.type_at(*index, false, offset)?; + types[id].as_component_type().ok_or_else(|| { + BinaryReaderError::new( + format!("type index {} is not a component type", index), + offset, + ) + })?; + ComponentEntityType::Component(id) + } + }) + } + + pub fn export_to_entity_type( + &mut self, + export: &crate::ComponentExport, + offset: usize, + ) -> Result { + Ok(match export.kind { + ComponentExternalKind::Module => { + ComponentEntityType::Module(self.module_at(export.index, offset)?) + } + ComponentExternalKind::Func => { + ComponentEntityType::Func(self.function_at(export.index, offset)?) + } + ComponentExternalKind::Value => { + ComponentEntityType::Value(*self.value_at(export.index, offset)?) + } + ComponentExternalKind::Type => { + ComponentEntityType::Type(self.type_at(export.index, false, offset)?) + } + ComponentExternalKind::Instance => { + ComponentEntityType::Instance(self.instance_at(export.index, offset)?) + } + ComponentExternalKind::Component => { + ComponentEntityType::Component(self.component_at(export.index, offset)?) } }) } fn create_module_type( &self, - defs: Vec, + decls: Vec, features: &WasmFeatures, types: &mut TypeList, offset: usize, ) -> Result { let mut state = Module::default(); - for def in defs { - match def { - crate::ModuleType::Type(ty) => { + for decl in decls { + match decl { + crate::ModuleTypeDeclaration::Type(ty) => { state.add_type(ty, features, types, offset, true)?; } - crate::ModuleType::Export { name, ty } => { - state.add_export( - name, - state.check_type_ref(&ty, features, types, offset)?, - features, - offset, - true, - )?; + crate::ModuleTypeDeclaration::Export { name, ty } => { + let ty = state.check_type_ref(&ty, features, types, offset)?; + state.add_export(name, ty, features, offset, true)?; } - crate::ModuleType::Import(import) => { + crate::ModuleTypeDeclaration::Import(import) => { state.add_import(import, features, types, offset)?; } } @@ -606,35 +722,56 @@ impl ComponentState { fn create_component_type( components: &mut Vec, - defs: Vec, + decls: Vec, features: &WasmFeatures, types: &mut TypeList, offset: usize, ) -> Result { components.push(ComponentState::default()); - for def in defs { - match def { - crate::ComponentType::Type(ty) => { + for decl in decls { + match decl { + crate::ComponentTypeDeclaration::CoreType(ty) => { + components + .last_mut() + .unwrap() + .add_core_type(ty, features, types, offset, true)?; + } + crate::ComponentTypeDeclaration::Type(ty) => { Self::add_type(components, ty, features, types, offset, true)?; } - crate::ComponentType::Export { name, ty } => { - let component = components.last_mut().unwrap(); - component.add_export( - name, - component.type_index_to_entity_type(ty, types, "exported", offset)?, - offset, - true, - )?; + crate::ComponentTypeDeclaration::Export { name, ty } => { + let current = components.last_mut().unwrap(); + let ty = current.check_type_ref(&ty, types, offset)?; + current.add_export(name, ty, offset, true)?; } - crate::ComponentType::Import(import) => { + crate::ComponentTypeDeclaration::Import(import) => { components .last_mut() .unwrap() .add_import(import, types, offset)?; } - crate::ComponentType::OuterType { count, index } => { - Self::alias_type(components, count, index, offset)?; + crate::ComponentTypeDeclaration::Alias(alias) => { + match alias { + crate::ComponentAlias::Outer { kind, count, index } + if kind == ComponentOuterAliasKind::CoreType + || kind == ComponentOuterAliasKind::Type => + { + match kind { + ComponentOuterAliasKind::CoreType => { + Self::alias_core_type(components, count, index, offset)? + } + ComponentOuterAliasKind::Type => { + Self::alias_type(components, count, index, offset)? + } + _ => unreachable!(), + } + } + _ => return Err(BinaryReaderError::new( + "only outer type aliases are allowed in component type declarations", + offset, + )), + } } }; } @@ -650,38 +787,59 @@ impl ComponentState { fn create_instance_type( components: &mut Vec, - defs: Vec, + decls: Vec, features: &WasmFeatures, types: &mut TypeList, offset: usize, - ) -> Result { + ) -> Result { components.push(ComponentState::default()); - for def in defs { - match def { - crate::InstanceType::Type(ty) => { - Self::add_type(components, ty, features, types, offset, true)?; + for decl in decls { + match decl { + crate::InstanceTypeDeclaration::CoreType(ty) => { + components + .last_mut() + .unwrap() + .add_core_type(ty, features, types, offset, true)?; } - crate::InstanceType::Export { name, ty } => { - let component = components.last_mut().unwrap(); - component.add_export( - name, - component.type_index_to_entity_type(ty, types, "exported", offset)?, - offset, - true, - )?; + crate::InstanceTypeDeclaration::Type(ty) => { + Self::add_type(components, ty, features, types, offset, true)?; } - crate::InstanceType::OuterType { count, index } => { - Self::alias_type(components, count, index, offset)?; + crate::InstanceTypeDeclaration::Export { name, ty } => { + let current = components.last_mut().unwrap(); + let ty = current.check_type_ref(&ty, types, offset)?; + current.add_export(name, ty, offset, true)?; } + crate::InstanceTypeDeclaration::Alias(alias) => match alias { + crate::ComponentAlias::Outer { kind, count, index } + if kind == ComponentOuterAliasKind::CoreType + || kind == ComponentOuterAliasKind::Type => + { + match kind { + ComponentOuterAliasKind::CoreType => { + Self::alias_core_type(components, count, index, offset)? + } + ComponentOuterAliasKind::Type => { + Self::alias_type(components, count, index, offset)? + } + _ => unreachable!(), + } + } + _ => { + return Err(BinaryReaderError::new( + "only outer type aliases are allowed in instance type declarations", + offset, + )) + } + }, }; } let state = components.pop().unwrap(); - Ok(InstanceType { + Ok(ComponentInstanceType { type_size: state.type_size, - kind: InstanceTypeKind::Defined(state.exports), + kind: ComponentInstanceTypeKind::Defined(state.exports), }) } @@ -700,13 +858,13 @@ impl ComponentState { if let Some(name) = name { Self::check_name(name, "function parameter", offset)?; } - let ty = self.create_interface_type_ref(*ty, types, offset)?; + let ty = self.create_component_val_type(*ty, types, offset)?; type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; Ok((name.map(ToOwned::to_owned), ty)) }) .collect::>()?; - let result = self.create_interface_type_ref(ty.result, types, offset)?; + let result = self.create_component_val_type(ty.result, types, offset)?; type_size = combine_type_sizes(type_size, result.type_size(), offset)?; Ok(ComponentFuncType { @@ -727,37 +885,10 @@ impl ComponentState { Ok(()) } - pub fn type_at(&self, idx: u32, offset: usize) -> Result { - if let Some(idx) = self.types.get(idx as usize) { - Ok(*idx) - } else { - Err(BinaryReaderError::new( - format!("unknown type {}: type index out of bounds", idx), - offset, - )) - } - } - - fn function_type_at<'a>( - &self, - idx: u32, - types: &'a TypeList, - offset: usize, - ) -> Result<&'a ComponentFuncType> { - if let TypeDef::ComponentFunc(ty) = &types[self.type_at(idx, offset)?] { - Ok(ty) - } else { - Err(BinaryReaderError::new( - format!("type index {} is not a function type", idx), - offset, - )) - } - } - fn instantiate_module( &self, module_index: u32, - module_args: Vec, + module_args: Vec, types: &mut TypeList, offset: usize, ) -> Result { @@ -787,9 +918,10 @@ impl ComponentState { // Populate the arguments for module_arg in module_args { match module_arg.kind { - crate::ModuleArgKind::Instance(idx) => { - let instance_type = types[self.module_instance_at(idx, types, offset)?] - .unwrap_module_instance_type(); + InstantiationArgKind::Instance => { + let instance_type = types[self.core_instance_at(module_arg.index, offset)?] + .as_instance_type() + .unwrap(); for (name, ty) in instance_type.exports(types).iter() { insert_arg(module_arg.name, name, *ty, &mut args, offset)?; } @@ -798,7 +930,7 @@ impl ComponentState { } // Validate the arguments - let module_type = types[module_type_id].unwrap_module_type(); + let module_type = types[module_type_id].as_module_type().unwrap(); for ((module, name), b) in module_type.imports.iter() { match args.get(&(module.as_str(), name.as_str())) { Some(a) => { @@ -843,12 +975,12 @@ impl ComponentState { } } - let ty = TypeDef::ModuleInstance(ModuleInstanceType { + let ty = Type::Instance(InstanceType { type_size: module_type .exports .iter() .fold(1, |acc, (_, ty)| acc + ty.type_size()), - kind: ModuleInstanceTypeKind::Instantiated(module_type_id), + kind: InstanceTypeKind::Instantiated(module_type_id), }); let id = TypeId { @@ -864,7 +996,7 @@ impl ComponentState { fn instantiate_component( &mut self, component_index: u32, - component_args: Vec, + component_args: Vec, types: &mut TypeList, offset: usize, ) -> Result { @@ -893,56 +1025,58 @@ impl ComponentState { // Populate the arguments for component_arg in component_args { match component_arg.kind { - crate::ComponentArgKind::Module(idx) => { + ComponentExternalKind::Module => { insert_arg( component_arg.name, - ComponentEntityType::Module(self.module_at(idx, offset)?), + ComponentEntityType::Module(self.module_at(component_arg.index, offset)?), &mut args, offset, )?; } - crate::ComponentArgKind::Component(idx) => { + ComponentExternalKind::Component => { insert_arg( component_arg.name, - ComponentEntityType::Component(self.component_at(idx, offset)?), + ComponentEntityType::Component( + self.component_at(component_arg.index, offset)?, + ), &mut args, offset, )?; } - crate::ComponentArgKind::Instance(idx) => { + ComponentExternalKind::Instance => { insert_arg( component_arg.name, ComponentEntityType::Instance( - self.component_instance_at(idx, types, offset)?, + self.instance_at(component_arg.index, offset)?, ), &mut args, offset, )?; } - crate::ComponentArgKind::Function(idx) => { + ComponentExternalKind::Func => { insert_arg( component_arg.name, - ComponentEntityType::Func(self.component_function_at(idx, types, offset)?), + ComponentEntityType::Func(self.function_at(component_arg.index, offset)?), &mut args, offset, )?; } - crate::ComponentArgKind::Value(idx) => { + ComponentExternalKind::Value => { insert_arg( component_arg.name, - ComponentEntityType::Value(*self.value_at(idx, offset)?), + ComponentEntityType::Value(*self.value_at(component_arg.index, offset)?), &mut args, offset, )?; } - crate::ComponentArgKind::Type(_) => { + ComponentExternalKind::Type => { // Type arguments are ignored } } } // Validate the arguments - let component_type = types[component_type_id].unwrap_component_type(); + let component_type = types[component_type_id].as_component_type().unwrap(); for (name, b) in component_type.imports.iter() { match args.get(name.as_str()) { Some(a) => { @@ -989,12 +1123,12 @@ impl ComponentState { } } - let ty = TypeDef::Instance(InstanceType { + let ty = Type::ComponentInstance(ComponentInstanceType { type_size: component_type .exports .iter() .fold(1, |acc, (_, ty)| acc + ty.type_size()), - kind: InstanceTypeKind::Instantiated(component_type_id), + kind: ComponentInstanceTypeKind::Instantiated(component_type_id), }); let id = TypeId { @@ -1039,57 +1173,55 @@ impl ComponentState { let mut inst_exports = HashMap::new(); for export in exports { match export.kind { - crate::ComponentExportKind::Module(idx) => { + ComponentExternalKind::Module => { insert_export( export.name, - ComponentEntityType::Module(self.module_at(idx, offset)?), + ComponentEntityType::Module(self.module_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?; } - crate::ComponentExportKind::Component(idx) => { + ComponentExternalKind::Component => { insert_export( export.name, - ComponentEntityType::Component(self.component_at(idx, offset)?), + ComponentEntityType::Component(self.component_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?; } - crate::ComponentExportKind::Instance(idx) => { + ComponentExternalKind::Instance => { insert_export( export.name, - ComponentEntityType::Instance( - self.component_instance_at(idx, types, offset)?, - ), + ComponentEntityType::Instance(self.instance_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?; } - crate::ComponentExportKind::Function(idx) => { + ComponentExternalKind::Func => { insert_export( export.name, - ComponentEntityType::Func(self.component_function_at(idx, types, offset)?), + ComponentEntityType::Func(self.function_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?; } - crate::ComponentExportKind::Value(idx) => { + ComponentExternalKind::Value => { insert_export( export.name, - ComponentEntityType::Value(*self.value_at(idx, offset)?), + ComponentEntityType::Value(*self.value_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?; } - crate::ComponentExportKind::Type(idx) => { + ComponentExternalKind::Type => { insert_export( export.name, - ComponentEntityType::Type(self.type_at(idx, offset)?), + ComponentEntityType::Type(self.type_at(export.index, false, offset)?), &mut inst_exports, &mut type_size, offset, @@ -1098,9 +1230,9 @@ impl ComponentState { } } - let ty = TypeDef::Instance(InstanceType { + let ty = Type::ComponentInstance(ComponentInstanceType { type_size, - kind: InstanceTypeKind::Exports(inst_exports), + kind: ComponentInstanceTypeKind::Exports(inst_exports), }); let id = TypeId { @@ -1145,30 +1277,30 @@ impl ComponentState { let mut inst_exports = HashMap::new(); for export in exports { match export.kind { - crate::ExternalKind::Func => { + ExternalKind::Func => { insert_export( export.name, - EntityType::Func(self.core_function_at(export.index, types, offset)?), + EntityType::Func(self.core_function_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?; } - crate::ExternalKind::Table => insert_export( + ExternalKind::Table => insert_export( export.name, EntityType::Table(*self.table_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?, - crate::ExternalKind::Memory => insert_export( + ExternalKind::Memory => insert_export( export.name, EntityType::Memory(*self.memory_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, )?, - crate::ExternalKind::Global => { + ExternalKind::Global => { insert_export( export.name, EntityType::Global(*self.global_at(export.index, offset)?), @@ -1177,9 +1309,9 @@ impl ComponentState { offset, )?; } - crate::ExternalKind::Tag => insert_export( + ExternalKind::Tag => insert_export( export.name, - EntityType::Tag(self.core_function_at(export.index, types, offset)?), + EntityType::Tag(self.core_function_at(export.index, offset)?), &mut inst_exports, &mut type_size, offset, @@ -1187,9 +1319,9 @@ impl ComponentState { } } - let ty = TypeDef::ModuleInstance(ModuleInstanceType { + let ty = Type::Instance(InstanceType { type_size, - kind: ModuleInstanceTypeKind::Exports(inst_exports), + kind: InstanceTypeKind::Exports(inst_exports), }); let id = TypeId { @@ -1202,25 +1334,27 @@ impl ComponentState { Ok(id) } - fn alias_instance_export( + fn alias_core_instance_export( &mut self, - kind: crate::AliasKind, - idx: u32, + instance_index: u32, + kind: ExternalKind, name: &str, types: &TypeList, offset: usize, ) -> Result<()> { macro_rules! push_module_export { - ($expected:path, $collection:ident, $limit:ident, $ty:literal) => {{ - check_max(self.$collection.len(), 1, $limit, concat!($ty, "s"), offset)?; - match self.module_instance_export(idx, name, types, offset)? { + ($expected:path, $collection:ident, $ty:literal) => {{ + match self.core_instance_export(instance_index, name, types, offset)? { $expected(ty) => { self.$collection.push(*ty); Ok(()) } _ => { return Err(BinaryReaderError::new( - format!("export `{}` for instance {} is not a {}", name, idx, $ty), + format!( + "export `{}` for core instance {} is not a {}", + name, instance_index, $ty + ), offset, )) } @@ -1228,17 +1362,69 @@ impl ComponentState { }}; } + match kind { + ExternalKind::Func => { + check_max( + self.function_count(), + 1, + MAX_WASM_FUNCTIONS, + "functions", + offset, + )?; + push_module_export!(EntityType::Func, core_funcs, "function") + } + ExternalKind::Table => { + check_max(self.core_tables.len(), 1, MAX_WASM_TABLES, "tables", offset)?; + push_module_export!(EntityType::Table, core_tables, "table") + } + ExternalKind::Memory => { + check_max( + self.core_memories.len(), + 1, + MAX_WASM_MEMORIES, + "memories", + offset, + )?; + push_module_export!(EntityType::Memory, core_memories, "memory") + } + ExternalKind::Global => { + check_max( + self.core_globals.len(), + 1, + MAX_WASM_GLOBALS, + "globals", + offset, + )?; + push_module_export!(EntityType::Global, core_globals, "global") + } + ExternalKind::Tag => { + check_max(self.core_tags.len(), 1, MAX_WASM_TAGS, "tags", offset)?; + push_module_export!(EntityType::Tag, core_tags, "tag") + } + } + } + + fn alias_instance_export( + &mut self, + instance_index: u32, + kind: ComponentExternalKind, + name: &str, + types: &TypeList, + offset: usize, + ) -> Result<()> { macro_rules! push_component_export { - ($expected:path, $collection:ident, $limit:ident, $ty:literal) => {{ - check_max(self.$collection.len(), 1, $limit, concat!($ty, "s"), offset)?; - match self.component_instance_export(idx, name, types, offset)? { + ($expected:path, $collection:ident, $ty:literal) => {{ + match self.instance_export(instance_index, name, types, offset)? { $expected(ty) => { self.$collection.push(*ty); Ok(()) } _ => { return Err(BinaryReaderError::new( - format!("export `{}` for instance {} is not a {}", name, idx, $ty), + format!( + "export `{}` for instance {} is not a {}", + name, instance_index, $ty + ), offset, )) } @@ -1247,80 +1433,67 @@ impl ComponentState { } match kind { - crate::AliasKind::Module => { - push_component_export!( - ComponentEntityType::Module, - modules, + ComponentExternalKind::Module => { + check_max( + self.core_modules.len(), + 1, MAX_WASM_MODULES, - "module" - ) + "modules", + offset, + )?; + push_component_export!(ComponentEntityType::Module, core_modules, "module") } - crate::AliasKind::Component => { - push_component_export!( - ComponentEntityType::Component, - components, + ComponentExternalKind::Component => { + check_max( + self.components.len(), + 1, MAX_WASM_COMPONENTS, - "component" - ) + "components", + offset, + )?; + push_component_export!(ComponentEntityType::Component, components, "component") } - crate::AliasKind::Instance => { + ComponentExternalKind::Instance => { check_max( - self.instances.len(), + self.instance_count(), 1, MAX_WASM_INSTANCES, "instances", offset, )?; - match self.component_instance_export(idx, name, types, offset)? { - ComponentEntityType::Instance(ty) => { - self.instances.push(*ty); - Ok(()) - } - _ => { - return Err(BinaryReaderError::new( - format!("export `{}` for instance {} is not an instance", name, idx), - offset, - )) - } - } + push_component_export!(ComponentEntityType::Instance, instances, "instance") } - crate::AliasKind::ComponentFunc => { - push_component_export!( - ComponentEntityType::Func, - functions, + ComponentExternalKind::Func => { + check_max( + self.function_count(), + 1, MAX_WASM_FUNCTIONS, - "function" - ) + "functions", + offset, + )?; + push_component_export!(ComponentEntityType::Func, funcs, "function") } - crate::AliasKind::Value => { + ComponentExternalKind::Value => { check_max(self.values.len(), 1, MAX_WASM_VALUES, "values", offset)?; - match self.component_instance_export(idx, name, types, offset)? { + match self.instance_export(instance_index, name, types, offset)? { ComponentEntityType::Value(ty) => { self.values.push((*ty, false)); Ok(()) } _ => { return Err(BinaryReaderError::new( - format!("export `{}` for instance {} is not a value", name, idx), + format!( + "export `{}` for instance {} is not a value", + name, instance_index + ), offset, )) } } } - crate::AliasKind::Func => { - push_module_export!(EntityType::Func, functions, MAX_WASM_FUNCTIONS, "function") - } - crate::AliasKind::Table => { - push_module_export!(EntityType::Table, tables, MAX_WASM_TABLES, "table") - } - crate::AliasKind::Memory => { - push_module_export!(EntityType::Memory, memories, MAX_WASM_MEMORIES, "memory") - } - crate::AliasKind::Global => { - push_module_export!(EntityType::Global, globals, MAX_WASM_GLOBALS, "global") - } - crate::AliasKind::Tag => { - push_module_export!(EntityType::Tag, tags, MAX_WASM_TAGS, "tag") + ComponentExternalKind::Type => { + check_max(self.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; + push_component_export!(ComponentEntityType::Type, types, "type") } } } @@ -1331,14 +1504,14 @@ impl ComponentState { let current = components.last_mut().unwrap(); check_max( - current.modules.len(), + current.core_modules.len(), 1, MAX_WASM_MODULES, "modules", offset, )?; - current.modules.push(ty); + current.core_modules.push(ty); Ok(()) } @@ -1364,12 +1537,28 @@ impl ComponentState { Ok(()) } + fn alias_core_type( + components: &mut [Self], + count: u32, + index: u32, + offset: usize, + ) -> Result<()> { + let component = Self::check_alias_count(components, count, offset)?; + let ty = component.type_at(index, true, offset)?; + + let current = components.last_mut().unwrap(); + check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; + + current.core_types.push(ty); + Ok(()) + } + fn alias_type(components: &mut [Self], count: u32, index: u32, offset: usize) -> Result<()> { let component = Self::check_alias_count(components, count, offset)?; - let ty = component.type_at(index, offset)?; + let ty = component.type_at(index, false, offset)?; let current = components.last_mut().unwrap(); - check_max(current.types.len(), 1, MAX_WASM_TYPES, "types", offset)?; + check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; current.types.push(ty); Ok(()) @@ -1387,55 +1576,68 @@ impl ComponentState { Ok(&components[components.len() - count - 1]) } - fn create_interface_type( + fn create_defined_type( &self, - ty: crate::InterfaceType, + ty: crate::ComponentDefinedType, types: &TypeList, offset: usize, - ) -> Result { + ) -> Result { match ty { - crate::InterfaceType::Primitive(ty) => Ok(InterfaceType::Primitive(ty)), - crate::InterfaceType::Record(fields) => { + crate::ComponentDefinedType::Primitive(ty) => Ok(ComponentDefinedType::Primitive(ty)), + crate::ComponentDefinedType::Record(fields) => { self.create_record_type(fields.as_ref(), types, offset) } - crate::InterfaceType::Variant(cases) => { + crate::ComponentDefinedType::Variant(cases) => { self.create_variant_type(cases.as_ref(), types, offset) } - crate::InterfaceType::List(ty) => Ok(InterfaceType::List( - self.create_interface_type_ref(ty, types, offset)?, + crate::ComponentDefinedType::List(ty) => Ok(ComponentDefinedType::List( + self.create_component_val_type(ty, types, offset)?, )), - crate::InterfaceType::Tuple(tys) => self.create_tuple_type(tys.as_ref(), types, offset), - crate::InterfaceType::Flags(names) => self.create_flags_type(names.as_ref(), offset), - crate::InterfaceType::Enum(cases) => self.create_enum_type(cases.as_ref(), offset), - crate::InterfaceType::Union(tys) => self.create_union_type(tys.as_ref(), types, offset), - crate::InterfaceType::Option(ty) => Ok(InterfaceType::Option( - self.create_interface_type_ref(ty, types, offset)?, - )), - crate::InterfaceType::Expected { ok, error } => Ok(InterfaceType::Expected( - self.create_interface_type_ref(ok, types, offset)?, - self.create_interface_type_ref(error, types, offset)?, + crate::ComponentDefinedType::Tuple(tys) => { + self.create_tuple_type(tys.as_ref(), types, offset) + } + crate::ComponentDefinedType::Flags(names) => { + self.create_flags_type(names.as_ref(), offset) + } + crate::ComponentDefinedType::Enum(cases) => { + self.create_enum_type(cases.as_ref(), offset) + } + crate::ComponentDefinedType::Union(tys) => { + self.create_union_type(tys.as_ref(), types, offset) + } + crate::ComponentDefinedType::Option(ty) => Ok(ComponentDefinedType::Option( + self.create_component_val_type(ty, types, offset)?, )), + crate::ComponentDefinedType::Expected { ok, error } => { + Ok(ComponentDefinedType::Expected( + self.create_component_val_type(ok, types, offset)?, + self.create_component_val_type(error, types, offset)?, + )) + } } } fn create_record_type( &self, - fields: &[(&str, crate::InterfaceTypeRef)], + fields: &[(&str, crate::ComponentValType)], types: &TypeList, offset: usize, - ) -> Result { + ) -> Result { let mut type_size = 1; let fields = fields .iter() .map(|(name, ty)| { Self::check_name(name, "record field", offset)?; - let ty = self.create_interface_type_ref(*ty, types, offset)?; + let ty = self.create_component_val_type(*ty, types, offset)?; type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; Ok((name.to_string(), ty)) }) .collect::>()?; - Ok(InterfaceType::Record(RecordType { type_size, fields })) + Ok(ComponentDefinedType::Record(RecordType { + type_size, + fields, + })) } fn create_variant_type( @@ -1443,56 +1645,59 @@ impl ComponentState { cases: &[crate::VariantCase], types: &TypeList, offset: usize, - ) -> Result { + ) -> Result { let mut type_size = 1; let cases = cases .iter() .map(|case| { Self::check_name(case.name, "variant case", offset)?; - if let Some(default_to) = case.default_to { - if default_to >= cases.len() as u32 { + if let Some(refines) = case.refines { + if refines >= cases.len() as u32 { return Err(BinaryReaderError::new( - format!("variant case default index {} is out of bounds", default_to), + format!("variant case refines index {} is out of bounds", refines), offset, )); } } - let ty = self.create_interface_type_ref(case.ty, types, offset)?; + let ty = self.create_component_val_type(case.ty, types, offset)?; type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; Ok(( case.name.to_string(), VariantCase { ty, - default_to: case.default_to.map(|i| cases[i as usize].name.to_string()), + refines: case.refines.map(|i| cases[i as usize].name.to_string()), }, )) }) .collect::>()?; - Ok(InterfaceType::Variant(VariantType { type_size, cases })) + Ok(ComponentDefinedType::Variant(VariantType { + type_size, + cases, + })) } fn create_tuple_type( &self, - tys: &[crate::InterfaceTypeRef], + tys: &[crate::ComponentValType], types: &TypeList, offset: usize, - ) -> Result { + ) -> Result { let mut type_size = 1; let types = tys .iter() .map(|ty| { - let ty = self.create_interface_type_ref(*ty, types, offset)?; + let ty = self.create_component_val_type(*ty, types, offset)?; type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; Ok(ty) }) .collect::>()?; - Ok(InterfaceType::Tuple(TupleType { type_size, types })) + Ok(ComponentDefinedType::Tuple(TupleType { type_size, types })) } - fn create_flags_type(&self, names: &[&str], offset: usize) -> Result { - Ok(InterfaceType::Flags( + fn create_flags_type(&self, names: &[&str], offset: usize) -> Result { + Ok(ComponentDefinedType::Flags( names .iter() .map(|name| { @@ -1503,7 +1708,7 @@ impl ComponentState { )) } - fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result { + fn create_enum_type(&self, cases: &[&str], offset: usize) -> Result { if cases.len() > u32::max_value() as usize { return Err(BinaryReaderError::new( "enumeration type cannot be represented with a 32-bit discriminant value", @@ -1511,7 +1716,7 @@ impl ComponentState { )); } - Ok(InterfaceType::Enum( + Ok(ComponentDefinedType::Enum( cases .iter() .map(|name| { @@ -1524,166 +1729,111 @@ impl ComponentState { fn create_union_type( &self, - tys: &[crate::InterfaceTypeRef], + tys: &[crate::ComponentValType], types: &TypeList, offset: usize, - ) -> Result { + ) -> Result { let mut type_size = 1; let types = tys .iter() .map(|ty| { - let ty = self.create_interface_type_ref(*ty, types, offset)?; + let ty = self.create_component_val_type(*ty, types, offset)?; type_size = combine_type_sizes(type_size, ty.type_size(), offset)?; Ok(ty) }) .collect::>()?; - Ok(InterfaceType::Union(UnionType { type_size, types })) + Ok(ComponentDefinedType::Union(UnionType { type_size, types })) } - fn create_interface_type_ref( + fn create_component_val_type( &self, - ty: crate::InterfaceTypeRef, + ty: crate::ComponentValType, types: &TypeList, offset: usize, - ) -> Result { + ) -> Result { Ok(match ty { - crate::InterfaceTypeRef::Primitive(pt) => InterfaceTypeRef::Primitive(pt), - crate::InterfaceTypeRef::Type(idx) => { - InterfaceTypeRef::Type(self.interface_type_at(idx, types, offset)?) + crate::ComponentValType::Primitive(pt) => ComponentValType::Primitive(pt), + crate::ComponentValType::Type(idx) => { + ComponentValType::Type(self.defined_type_at(idx, types, offset)?) } }) } - fn function_at(&self, idx: u32, offset: usize) -> Result { - match self.functions.get(idx as usize) { - Some(ty) => Ok(*ty), - None => Err(BinaryReaderError::new( - format!("unknown function {}: function index out of bounds", idx), - offset, - )), - } - } - - fn component_function_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result { - let ty = self.function_at(idx, offset)?; - match &types[ty] { - TypeDef::ComponentFunc(_) => Ok(ty), - _ => Err(BinaryReaderError::new( - format!("function {} is not a component function", idx), + pub fn type_at(&self, idx: u32, core: bool, offset: usize) -> Result { + let types = if core { &self.core_types } else { &self.types }; + types.get(idx as usize).copied().ok_or_else(|| { + BinaryReaderError::new( + format!("unknown type {}: type index out of bounds", idx), offset, - )), - } + ) + }) } - fn core_function_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result { - let ty = self.function_at(idx, offset)?; - match &types[ty] { - TypeDef::Func(_) => Ok(ty), - _ => Err(BinaryReaderError::new( - format!("function {} is not a core WebAssembly function", idx), - offset, - )), - } + fn function_type_at<'a>( + &self, + idx: u32, + types: &'a TypeList, + offset: usize, + ) -> Result<&'a ComponentFuncType> { + types[self.type_at(idx, false, offset)?] + .as_component_func_type() + .ok_or_else(|| { + BinaryReaderError::new(format!("type index {} is not a function type", idx), offset) + }) } - fn module_at(&self, idx: u32, offset: usize) -> Result { - match self.modules.get(idx as usize) { - Some(idx) => Ok(*idx), - None => Err(BinaryReaderError::new( - format!("unknown module {}: module index out of bounds", idx), + fn function_at(&self, idx: u32, offset: usize) -> Result { + self.funcs.get(idx as usize).copied().ok_or_else(|| { + BinaryReaderError::new( + format!("unknown function {}: function index out of bounds", idx), offset, - )), - } + ) + }) } fn component_at(&self, idx: u32, offset: usize) -> Result { - match self.components.get(idx as usize) { - Some(idx) => Ok(*idx), - None => Err(BinaryReaderError::new( + self.components.get(idx as usize).copied().ok_or_else(|| { + BinaryReaderError::new( format!("unknown component {}: component index out of bounds", idx), offset, - )), - } + ) + }) } fn instance_at(&self, idx: u32, offset: usize) -> Result { - match self.instances.get(idx as usize) { - Some(idx) => Ok(*idx), - None => Err(BinaryReaderError::new( + self.instances.get(idx as usize).copied().ok_or_else(|| { + BinaryReaderError::new( format!("unknown instance {}: instance index out of bounds", idx), offset, - )), - } - } - - fn module_instance_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result { - let id = self.instance_at(idx, offset)?; - match &types[id] { - TypeDef::ModuleInstance(_) => Ok(id), - _ => Err(BinaryReaderError::new( - format!("instance {} is not a module instance", idx), - offset, - )), - } - } - - fn component_instance_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result { - let id = self.instance_at(idx, offset)?; - match &types[id] { - TypeDef::Instance(_) => Ok(id), - _ => Err(BinaryReaderError::new( - format!("instance {} is not a component instance", idx), - offset, - )), - } - } - - fn module_instance_export<'a>( - &self, - idx: u32, - name: &str, - types: &'a TypeList, - offset: usize, - ) -> Result<&'a EntityType> { - match types[self.module_instance_at(idx, types, offset)?] - .unwrap_module_instance_type() - .exports(types) - .get(name) - { - Some(export) => Ok(export), - None => { - return Err(BinaryReaderError::new( - format!("instance {} has no export named `{}`", idx, name), - offset, - )) - } - } + ) + }) } - fn component_instance_export<'a>( + fn instance_export<'a>( &self, - idx: u32, + instance_index: u32, name: &str, types: &'a TypeList, offset: usize, ) -> Result<&'a ComponentEntityType> { - match types[self.component_instance_at(idx, types, offset)?] - .unwrap_instance_type() + match types[self.instance_at(instance_index, offset)?] + .as_component_instance_type() + .unwrap() .exports(types) .get(name) { Some(export) => Ok(export), None => { return Err(BinaryReaderError::new( - format!("instance {} has no export named `{}`", idx, name), + format!("instance {} has no export named `{}`", instance_index, name), offset, )) } } } - fn value_at(&mut self, idx: u32, offset: usize) -> Result<&InterfaceTypeRef> { + fn value_at(&mut self, idx: u32, offset: usize) -> Result<&ComponentValType> { match self.values.get_mut(idx as usize) { Some((ty, used)) if !*used => { *used = true; @@ -1700,19 +1850,81 @@ impl ComponentState { } } - fn interface_type_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result { - let id = self.type_at(idx, offset)?; + fn defined_type_at(&self, idx: u32, types: &TypeList, offset: usize) -> Result { + let id = self.type_at(idx, false, offset)?; match &types[id] { - TypeDef::Interface(_) => Ok(id), + Type::Defined(_) => Ok(id), _ => Err(BinaryReaderError::new( - format!("type index {} is not an interface type", id.index), + format!("type index {} is not a defined type", id.index), + offset, + )), + } + } + + fn core_function_at(&self, idx: u32, offset: usize) -> Result { + match self.core_funcs.get(idx as usize) { + Some(id) => Ok(*id), + None => Err(BinaryReaderError::new( + format!( + "unknown core function {}: function index out of bounds", + idx + ), + offset, + )), + } + } + + fn module_at(&self, idx: u32, offset: usize) -> Result { + match self.core_modules.get(idx as usize) { + Some(id) => Ok(*id), + None => Err(BinaryReaderError::new( + format!("unknown module {}: module index out of bounds", idx), offset, )), } } + fn core_instance_at(&self, idx: u32, offset: usize) -> Result { + match self.core_instances.get(idx as usize) { + Some(id) => Ok(*id), + None => Err(BinaryReaderError::new( + format!( + "unknown core instance {}: instance index out of bounds", + idx + ), + offset, + )), + } + } + + fn core_instance_export<'a>( + &self, + instance_index: u32, + name: &str, + types: &'a TypeList, + offset: usize, + ) -> Result<&'a EntityType> { + match types[self.core_instance_at(instance_index, offset)?] + .as_instance_type() + .unwrap() + .exports(types) + .get(name) + { + Some(export) => Ok(export), + None => { + return Err(BinaryReaderError::new( + format!( + "core instance {} has no export named `{}`", + instance_index, name + ), + offset, + )) + } + } + } + fn global_at(&self, idx: u32, offset: usize) -> Result<&GlobalType> { - match self.globals.get(idx as usize) { + match self.core_globals.get(idx as usize) { Some(t) => Ok(t), None => Err(BinaryReaderError::new( format!("unknown global {}: global index out of bounds", idx,), @@ -1722,7 +1934,7 @@ impl ComponentState { } fn table_at(&self, idx: u32, offset: usize) -> Result<&TableType> { - match self.tables.get(idx as usize) { + match self.core_tables.get(idx as usize) { Some(t) => Ok(t), None => Err(BinaryReaderError::new( format!("unknown table {}: table index out of bounds", idx), @@ -1732,7 +1944,7 @@ impl ComponentState { } fn memory_at(&self, idx: u32, offset: usize) -> Result<&MemoryType> { - match self.memories.get(idx as usize) { + match self.core_memories.get(idx as usize) { Some(t) => Ok(t), None => Err(BinaryReaderError::new( format!("unknown memory {}: memory index out of bounds", idx,), @@ -1745,16 +1957,19 @@ impl ComponentState { impl Default for ComponentState { fn default() -> Self { Self { + core_types: Default::default(), + core_modules: Default::default(), + core_instances: Default::default(), + core_funcs: Default::default(), + core_memories: Default::default(), + core_tables: Default::default(), + core_globals: Default::default(), + core_tags: Default::default(), types: Default::default(), - modules: Default::default(), - components: Default::default(), - instances: Default::default(), - functions: Default::default(), + funcs: Default::default(), values: Default::default(), - memories: Default::default(), - tables: Default::default(), - globals: Default::default(), - tags: Default::default(), + instances: Default::default(), + components: Default::default(), imports: Default::default(), exports: Default::default(), has_start: Default::default(), diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index a82ac230f8..3727d667b3 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -3,19 +3,19 @@ use super::{ check_max, combine_type_sizes, operators::OperatorValidator, - types::{EntityType, TypeDef, TypeId, TypeList}, + types::{EntityType, Type, TypeId, TypeList}, }; use crate::{ limits::*, BinaryReaderError, Data, DataKind, Element, ElementItem, ElementKind, ExternalKind, - FuncType, Global, GlobalType, InitExpr, MemoryType, Operator, Result, TableType, TagType, Type, - TypeRef, WasmFeatures, WasmModuleResources, + FuncType, Global, GlobalType, InitExpr, MemoryType, Operator, Result, TableType, TagType, + TypeRef, ValType, WasmFeatures, WasmModuleResources, }; use std::{ collections::{HashMap, HashSet}, sync::Arc, }; -fn check_value_type(ty: Type, features: &WasmFeatures, offset: usize) -> Result<()> { +fn check_value_type(ty: ValType, features: &WasmFeatures, offset: usize) -> Result<()> { match features.check_value_type(ty) { Ok(()) => Ok(()), Err(e) => Err(BinaryReaderError::new(e, offset)), @@ -51,26 +51,26 @@ impl Default for Order { } #[derive(Default)] -pub struct ModuleState { +pub(crate) struct ModuleState { /// Internal state that is incrementally built-up for the module being /// validated. This houses type information for all wasm items, like /// functions. Note that this starts out as a solely owned `Arc` so we can /// get mutable access, but after we get to the code section this is never /// mutated to we can clone it cheaply and hand it to sub-validators. - pub(crate) module: arc::MaybeOwned, + pub module: arc::MaybeOwned, /// Where we are, order-wise, in the wasm binary. order: Order, /// The number of data segments in the data section (if present). - pub(crate) data_segment_count: u32, + pub data_segment_count: u32, /// The number of functions we expect to be defined in the code section, or /// basically the length of the function section if it was found. The next /// index is where we are, in the code section index space, for the next /// entry in the code section (used to figure out what type is next for the /// function being validated). - pub(crate) expected_code_bodies: Option, + pub expected_code_bodies: Option, /// When parsing the code section, represents the current index in the section. code_section_index: Option, @@ -129,7 +129,7 @@ impl ModuleState { Ok(ty) } - pub(super) fn add_global( + pub fn add_global( &mut self, global: Global, features: &WasmFeatures, @@ -149,7 +149,7 @@ impl ModuleState { Ok(()) } - pub(super) fn add_data_segment( + pub fn add_data_segment( &mut self, data: Data, features: &WasmFeatures, @@ -168,7 +168,7 @@ impl ModuleState { } } - pub(super) fn add_element_segment( + pub fn add_element_segment( &mut self, e: Element, features: &WasmFeatures, @@ -176,9 +176,9 @@ impl ModuleState { offset: usize, ) -> Result<()> { match e.ty { - Type::FuncRef => {} - Type::ExternRef if features.reference_types => {} - Type::ExternRef => { + ValType::FuncRef => {} + ValType::ExternRef if features.reference_types => {} + ValType::ExternRef => { return Err(BinaryReaderError::new( "reference types must be enabled for externref elem segment", offset, @@ -199,7 +199,7 @@ impl ModuleState { )); } - self.check_init_expr(&init_expr, Type::I32, features, types, offset)?; + self.check_init_expr(&init_expr, ValType::I32, features, types, offset)?; } ElementKind::Passive | ElementKind::Declared => { if !features.bulk_memory { @@ -224,7 +224,7 @@ impl ModuleState { self.check_init_expr(&expr, e.ty, features, types, offset)?; } ElementItem::Func(f) => { - if e.ty != Type::FuncRef { + if e.ty != ValType::FuncRef { return Err(BinaryReaderError::new( "type mismatch: segment does not have funcref type", offset, @@ -243,7 +243,7 @@ impl ModuleState { fn check_init_expr( &mut self, expr: &InitExpr<'_>, - expected_ty: Type, + expected_ty: ValType, features: &WasmFeatures, types: &TypeList, offset: usize, @@ -346,17 +346,17 @@ impl ModuleState { } } -pub struct Module { +pub(crate) struct Module { // This is set once the code section starts. // `WasmModuleResources` implementations use the snapshot to // enable parallel validation of functions. - pub(super) snapshot: Option>, + pub snapshot: Option>, // Stores indexes into the validator's types list. pub types: Vec, pub tables: Vec, pub memories: Vec, pub globals: Vec, - pub element_types: Vec, + pub element_types: Vec, pub data_count: Option, // Stores indexes into `types`. pub functions: Vec, @@ -370,16 +370,16 @@ pub struct Module { } impl Module { - pub(super) fn add_type( + pub fn add_type( &mut self, - def: crate::TypeDef, + ty: crate::Type, features: &WasmFeatures, types: &mut TypeList, offset: usize, check_limit: bool, ) -> Result<()> { - let ty = match def { - crate::TypeDef::Func(t) => { + let ty = match ty { + crate::Type::Func(t) => { for ty in t.params.iter().chain(t.returns.iter()) { check_value_type(*ty, features, offset)?; } @@ -389,7 +389,7 @@ impl Module { offset, )); } - TypeDef::Func(t) + Type::Func(t) } }; @@ -405,7 +405,7 @@ impl Module { Ok(()) } - pub(super) fn add_import( + pub fn add_import( &mut self, import: crate::Import, features: &WasmFeatures, @@ -457,7 +457,7 @@ impl Module { Ok(()) } - pub(super) fn add_export( + pub fn add_export( &mut self, name: &str, ty: EntityType, @@ -491,12 +491,7 @@ impl Module { } } - pub(super) fn add_function( - &mut self, - type_index: u32, - types: &TypeList, - offset: usize, - ) -> Result<()> { + pub fn add_function(&mut self, type_index: u32, types: &TypeList, offset: usize) -> Result<()> { self.func_type_at(type_index, types, offset)?; self.functions.push(type_index); Ok(()) @@ -524,7 +519,7 @@ impl Module { Ok(()) } - pub(super) fn add_tag( + pub fn add_tag( &mut self, ty: TagType, features: &WasmFeatures, @@ -536,7 +531,7 @@ impl Module { Ok(()) } - fn type_at<'a>(&self, idx: u32, types: &'a TypeList, offset: usize) -> Result<&'a TypeDef> { + fn type_at<'a>(&self, idx: u32, types: &'a TypeList, offset: usize) -> Result<&'a Type> { match self.types.get(idx as usize) { Some(id) => Ok(&types[*id]), None => Err(BinaryReaderError::new( @@ -552,10 +547,17 @@ impl Module { types: &'a TypeList, offset: usize, ) -> Result<&'a FuncType> { - Ok(self.type_at(type_index, types, offset)?.unwrap_func_type()) + self.type_at(type_index, types, offset)? + .as_func_type() + .ok_or_else(|| { + BinaryReaderError::new( + format!("type index {} is not a function type", type_index), + offset, + ) + }) } - pub(super) fn check_type_ref( + pub fn check_type_ref( &self, type_ref: &TypeRef, features: &WasmFeatures, @@ -593,8 +595,8 @@ impl Module { offset: usize, ) -> Result<()> { match ty.element_type { - Type::FuncRef => {} - Type::ExternRef => { + ValType::FuncRef => {} + ValType::ExternRef => { if !features.reference_types { return Err(BinaryReaderError::new("element is not anyfunc", offset)); } @@ -792,7 +794,7 @@ impl Module { }) } - pub(super) fn get_func_type<'a>( + pub fn get_func_type<'a>( &self, func_idx: u32, types: &'a TypeList, @@ -877,7 +879,11 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { } fn tag_at(&self, at: u32) -> Option<&Self::FuncType> { - Some(self.types[*self.module.tags.get(at as usize)?].unwrap_func_type()) + Some( + self.types[*self.module.tags.get(at as usize)?] + .as_func_type() + .unwrap(), + ) } fn global_at(&self, at: u32) -> Option { @@ -885,14 +891,18 @@ impl WasmModuleResources for OperatorValidatorResources<'_> { } fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { - Some(self.types[*self.module.types.get(at as usize)?].unwrap_func_type()) + Some( + self.types[*self.module.types.get(at as usize)?] + .as_func_type() + .unwrap(), + ) } fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> { self.func_type_at(*self.module.functions.get(at as usize)?) } - fn element_type_at(&self, at: u32) -> Option { + fn element_type_at(&self, at: u32) -> Option { self.module.element_types.get(at as usize).cloned() } @@ -925,7 +935,11 @@ impl WasmModuleResources for ValidatorResources { } fn tag_at(&self, at: u32) -> Option<&Self::FuncType> { - Some(self.0.snapshot.as_ref().unwrap()[*self.0.tags.get(at as usize)?].unwrap_func_type()) + Some( + self.0.snapshot.as_ref().unwrap()[*self.0.tags.get(at as usize)?] + .as_func_type() + .unwrap(), + ) } fn global_at(&self, at: u32) -> Option { @@ -933,14 +947,18 @@ impl WasmModuleResources for ValidatorResources { } fn func_type_at(&self, at: u32) -> Option<&Self::FuncType> { - Some(self.0.snapshot.as_ref().unwrap()[*self.0.types.get(at as usize)?].unwrap_func_type()) + Some( + self.0.snapshot.as_ref().unwrap()[*self.0.types.get(at as usize)?] + .as_func_type() + .unwrap(), + ) } fn type_of_function(&self, at: u32) -> Option<&Self::FuncType> { self.func_type_at(*self.0.functions.get(at as usize)?) } - fn element_type_at(&self, at: u32) -> Option { + fn element_type_at(&self, at: u32) -> Option { self.0.element_types.get(at as usize).cloned() } diff --git a/crates/wasmparser/src/validator/func.rs b/crates/wasmparser/src/validator/func.rs index bcaedd48f9..bc2a8e3061 100644 --- a/crates/wasmparser/src/validator/func.rs +++ b/crates/wasmparser/src/validator/func.rs @@ -1,5 +1,5 @@ use super::operators::OperatorValidator; -use crate::{BinaryReader, Result, Type}; +use crate::{BinaryReader, Result, ValType}; use crate::{FunctionBody, Operator, WasmFeatures, WasmModuleResources}; /// Validation context for a WebAssembly function. @@ -69,7 +69,7 @@ impl FuncValidator { for _ in 0..reader.read_var_u32()? { let offset = reader.original_position(); let cnt = reader.read_var_u32()?; - let ty = reader.read_type()?; + let ty = reader.read_val_type()?; self.define_locals(offset, cnt, ty)?; } Ok(()) @@ -79,7 +79,7 @@ impl FuncValidator { /// /// This should be used if the application is already reading local /// definitions and there's no need to re-parse the function again. - pub fn define_locals(&mut self, offset: usize, count: u32, ty: Type) -> Result<()> { + pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> { self.validator.define_locals(offset, count, ty) } @@ -143,7 +143,7 @@ mod tests { fn type_of_function(&self, _func_idx: u32) -> Option<&Self::FuncType> { todo!() } - fn element_type_at(&self, _at: u32) -> Option { + fn element_type_at(&self, _at: u32) -> Option { todo!() } fn element_count(&self) -> u32 { @@ -166,10 +166,10 @@ mod tests { fn len_outputs(&self) -> usize { 0 } - fn input_at(&self, _at: u32) -> Option { + fn input_at(&self, _at: u32) -> Option { todo!() } - fn output_at(&self, _at: u32) -> Option { + fn output_at(&self, _at: u32) -> Option { todo!() } } diff --git a/crates/wasmparser/src/validator/operators.rs b/crates/wasmparser/src/validator/operators.rs index 53acd66ea5..a2a5004b86 100644 --- a/crates/wasmparser/src/validator/operators.rs +++ b/crates/wasmparser/src/validator/operators.rs @@ -24,7 +24,7 @@ use crate::{ limits::MAX_WASM_FUNCTION_LOCALS, BinaryReaderError, BlockType, MemoryImmediate, Operator, - Result, SIMDLaneIndex, Type, WasmFeatures, WasmFuncType, WasmModuleResources, + Result, SIMDLaneIndex, ValType, WasmFeatures, WasmFuncType, WasmModuleResources, }; /// A wrapper around a `BinaryReaderError` where the inner error's offset is a @@ -79,11 +79,11 @@ pub(crate) struct OperatorValidator { // `local.{get,set,tee}`. We do a binary search for the index desired, and // it either lies in a "hole" where the maximum index is specified later, // or it's at the end of the list meaning it's out of bounds. - locals: Vec<(u32, Type)>, + locals: Vec<(u32, ValType)>, // The `operands` is the current type stack, and the `control` list is the // list of blocks that we're currently in. - pub(crate) operands: Vec>, + pub(crate) operands: Vec>, control: Vec, // This is a list of flags for wasm features which are used to gate various @@ -91,7 +91,7 @@ pub(crate) struct OperatorValidator { pub(crate) features: WasmFeatures, // Temporary storage used during the validation of `br_table`. - br_table_tmp: Vec>, + br_table_tmp: Vec>, } // This structure corresponds to `ctrl_frame` as specified at in the validation @@ -155,7 +155,7 @@ impl OperatorValidator { /// Creates a new operator validator which will be used to validate an /// `init_expr` constant expression which should result in the `ty` /// specified. - pub fn new_init_expr(features: &WasmFeatures, ty: Type) -> OperatorValidator { + pub fn new_init_expr(features: &WasmFeatures, ty: ValType) -> OperatorValidator { OperatorValidator { num_locals: 0, locals: Vec::new(), @@ -171,7 +171,7 @@ impl OperatorValidator { } } - pub fn define_locals(&mut self, offset: usize, count: u32, ty: Type) -> Result<()> { + pub fn define_locals(&mut self, offset: usize, count: u32, ty: ValType) -> Result<()> { self.features .check_value_type(ty) .map_err(|e| BinaryReaderError::new(e, offset))?; @@ -194,7 +194,7 @@ impl OperatorValidator { /// Fetches the type for the local at `idx`, returning an error if it's out /// of bounds. - fn local(&self, idx: u32) -> OperatorValidatorResult { + fn local(&self, idx: u32) -> OperatorValidatorResult { match self.locals.binary_search_by_key(&idx, |(idx, _)| *idx) { // If this index would be inserted at the end of the list, then the // index is out of bounds and we return an error. @@ -215,7 +215,7 @@ impl OperatorValidator { /// This is used by instructions to represent a value that is pushed to the /// operand stack. This can fail, but only if `Type` is feature gated. /// Otherwise the push operation always succeeds. - fn push_operand(&mut self, ty: Type) -> OperatorValidatorResult<()> { + fn push_operand(&mut self, ty: ValType) -> OperatorValidatorResult<()> { self.features .check_value_type(ty) .map_err(OperatorValidatorError::new)?; @@ -241,7 +241,10 @@ impl OperatorValidator { /// matches `expected`. If `None` is returned then it means that `None` was /// expected and a type was successfully popped, but its exact type is /// indeterminate because the current block is unreachable. - fn pop_operand(&mut self, expected: Option) -> OperatorValidatorResult> { + fn pop_operand( + &mut self, + expected: Option, + ) -> OperatorValidatorResult> { let control = self.control.last().unwrap(); let actual = if self.operands.len() == control.height { if control.unreachable { @@ -351,7 +354,7 @@ impl OperatorValidator { &self, memory_index: u32, resources: impl WasmModuleResources, - ) -> OperatorValidatorResult { + ) -> OperatorValidatorResult { if memory_index > 0 && !self.features.multi_memory { return Err(OperatorValidatorError::new( "multi-memory support is not enabled", @@ -370,7 +373,7 @@ impl OperatorValidator { memarg: MemoryImmediate, max_align: u8, resources: impl WasmModuleResources, - ) -> OperatorValidatorResult { + ) -> OperatorValidatorResult { let index_ty = self.check_memory_index(memarg.memory, resources)?; let align = memarg.align; if align > max_align { @@ -378,7 +381,7 @@ impl OperatorValidator { "alignment must not be larger than natural", )); } - if index_ty == Type::I32 && memarg.offset > u64::from(u32::MAX) { + if index_ty == ValType::I32 && memarg.offset > u64::from(u32::MAX) { return Err(OperatorValidatorError::new( "offset out of range: must be <= 2**32", )); @@ -461,7 +464,7 @@ impl OperatorValidator { &self, memarg: MemoryImmediate, resources: impl WasmModuleResources, - ) -> OperatorValidatorResult { + ) -> OperatorValidatorResult { self.check_memory_index(memarg.memory, resources) } @@ -480,14 +483,14 @@ impl OperatorValidator { ) -> OperatorValidatorResult<()> { match ty { BlockType::Empty - | BlockType::Type(Type::I32) - | BlockType::Type(Type::I64) - | BlockType::Type(Type::F32) - | BlockType::Type(Type::F64) => Ok(()), - BlockType::Type(Type::ExternRef) | BlockType::Type(Type::FuncRef) => { + | BlockType::Type(ValType::I32) + | BlockType::Type(ValType::I64) + | BlockType::Type(ValType::F32) + | BlockType::Type(ValType::F64) => Ok(()), + BlockType::Type(ValType::ExternRef) | BlockType::Type(ValType::FuncRef) => { self.check_reference_types_enabled() } - BlockType::Type(Type::V128) => self.check_simd_enabled(), + BlockType::Type(ValType::V128) => self.check_simd_enabled(), BlockType::FuncType(idx) => { if !self.features.multi_value { return Err(OperatorValidatorError::new( @@ -540,7 +543,7 @@ impl OperatorValidator { )); } Some(tab) => { - if tab.element_type != Type::FuncRef { + if tab.element_type != ValType::FuncRef { return Err(OperatorValidatorError::new( "indirect calls must go through a table of funcref", )); @@ -548,7 +551,7 @@ impl OperatorValidator { } } let ty = func_type_at(&resources, index)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; for ty in ty.inputs().rev() { self.pop_operand(Some(ty))?; } @@ -602,7 +605,7 @@ impl OperatorValidator { } Operator::If { ty } => { self.check_block_type(ty, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; for ty in params(ty, resources)?.rev() { self.pop_operand(Some(ty))?; } @@ -715,7 +718,7 @@ impl OperatorValidator { self.unreachable(); } Operator::BrIf { relative_depth } => { - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; let (ty, kind) = self.jump(relative_depth)?; for ty in label_types(ty, resources, kind)?.rev() { self.pop_operand(Some(ty))?; @@ -725,7 +728,7 @@ impl OperatorValidator { } } Operator::BrTable { ref table } => { - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; let default = self.jump(table.default())?; let default_types = label_types(default.0, resources, default.1)?; for element in table.targets() { @@ -788,17 +791,17 @@ impl OperatorValidator { self.pop_operand(None)?; } Operator::Select => { - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; let ty1 = self.pop_operand(None)?; let ty2 = self.pop_operand(None)?; - fn is_num(ty: Option) -> bool { + fn is_num(ty: Option) -> bool { matches!( ty, - Some(Type::I32) - | Some(Type::I64) - | Some(Type::F32) - | Some(Type::F64) - | Some(Type::V128) + Some(ValType::I32) + | Some(ValType::I64) + | Some(ValType::F32) + | Some(ValType::F64) + | Some(ValType::V128) | None ) } @@ -811,7 +814,7 @@ impl OperatorValidator { self.operands.push(ty1.or(ty2)); } Operator::TypedSelect { ty } => { - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; self.pop_operand(Some(ty))?; self.push_operand(ty)?; @@ -855,95 +858,95 @@ impl OperatorValidator { Operator::I32Load { memarg } => { let ty = self.check_memarg(memarg, 2, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::I64Load { memarg } => { let ty = self.check_memarg(memarg, 3, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::F32Load { memarg } => { self.check_non_deterministic_enabled()?; let ty = self.check_memarg(memarg, 2, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::F32)?; + self.push_operand(ValType::F32)?; } Operator::F64Load { memarg } => { self.check_non_deterministic_enabled()?; let ty = self.check_memarg(memarg, 3, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::F64)?; + self.push_operand(ValType::F64)?; } Operator::I32Load8S { memarg } | Operator::I32Load8U { memarg } => { let ty = self.check_memarg(memarg, 0, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::I32Load16S { memarg } | Operator::I32Load16U { memarg } => { let ty = self.check_memarg(memarg, 1, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::I64Load8S { memarg } | Operator::I64Load8U { memarg } => { let ty = self.check_memarg(memarg, 0, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::I64Load16S { memarg } | Operator::I64Load16U { memarg } => { let ty = self.check_memarg(memarg, 1, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::I64Load32S { memarg } | Operator::I64Load32U { memarg } => { let ty = self.check_memarg(memarg, 2, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::I32Store { memarg } => { let ty = self.check_memarg(memarg, 2, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; } Operator::I64Store { memarg } => { let ty = self.check_memarg(memarg, 3, resources)?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; } Operator::F32Store { memarg } => { self.check_non_deterministic_enabled()?; let ty = self.check_memarg(memarg, 2, resources)?; - self.pop_operand(Some(Type::F32))?; + self.pop_operand(Some(ValType::F32))?; self.pop_operand(Some(ty))?; } Operator::F64Store { memarg } => { self.check_non_deterministic_enabled()?; let ty = self.check_memarg(memarg, 3, resources)?; - self.pop_operand(Some(Type::F64))?; + self.pop_operand(Some(ValType::F64))?; self.pop_operand(Some(ty))?; } Operator::I32Store8 { memarg } => { let ty = self.check_memarg(memarg, 0, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; } Operator::I32Store16 { memarg } => { let ty = self.check_memarg(memarg, 1, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; } Operator::I64Store8 { memarg } => { let ty = self.check_memarg(memarg, 0, resources)?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; } Operator::I64Store16 { memarg } => { let ty = self.check_memarg(memarg, 1, resources)?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; } Operator::I64Store32 { memarg } => { let ty = self.check_memarg(memarg, 2, resources)?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; } Operator::MemorySize { mem, mem_byte } => { @@ -965,19 +968,19 @@ impl OperatorValidator { self.pop_operand(Some(index_ty))?; self.push_operand(index_ty)?; } - Operator::I32Const { .. } => self.push_operand(Type::I32)?, - Operator::I64Const { .. } => self.push_operand(Type::I64)?, + Operator::I32Const { .. } => self.push_operand(ValType::I32)?, + Operator::I64Const { .. } => self.push_operand(ValType::I64)?, Operator::F32Const { .. } => { self.check_non_deterministic_enabled()?; - self.push_operand(Type::F32)?; + self.push_operand(ValType::F32)?; } Operator::F64Const { .. } => { self.check_non_deterministic_enabled()?; - self.push_operand(Type::F64)?; + self.push_operand(ValType::F64)?; } Operator::I32Eqz => { - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::I32)?; } Operator::I32Eq | Operator::I32Ne @@ -989,13 +992,13 @@ impl OperatorValidator { | Operator::I32LeU | Operator::I32GeS | Operator::I32GeU => { - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::I32)?; } Operator::I64Eqz => { - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::I32)?; } Operator::I64Eq | Operator::I64Ne @@ -1007,9 +1010,9 @@ impl OperatorValidator { | Operator::I64LeU | Operator::I64GeS | Operator::I64GeU => { - self.pop_operand(Some(Type::I64))?; - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::I32)?; } Operator::F32Eq | Operator::F32Ne @@ -1018,9 +1021,9 @@ impl OperatorValidator { | Operator::F32Le | Operator::F32Ge => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F32))?; - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::F32))?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::I32)?; } Operator::F64Eq | Operator::F64Ne @@ -1029,13 +1032,13 @@ impl OperatorValidator { | Operator::F64Le | Operator::F64Ge => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F64))?; - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::F64))?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::I32)?; } Operator::I32Clz | Operator::I32Ctz | Operator::I32Popcnt => { - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::I32)?; } Operator::I32Add | Operator::I32Sub @@ -1052,13 +1055,13 @@ impl OperatorValidator { | Operator::I32ShrU | Operator::I32Rotl | Operator::I32Rotr => { - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::I32)?; } Operator::I64Clz | Operator::I64Ctz | Operator::I64Popcnt => { - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::I64)?; } Operator::I64Add | Operator::I64Sub @@ -1075,9 +1078,9 @@ impl OperatorValidator { | Operator::I64ShrU | Operator::I64Rotl | Operator::I64Rotr => { - self.pop_operand(Some(Type::I64))?; - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::I64)?; } Operator::F32Abs | Operator::F32Neg @@ -1087,8 +1090,8 @@ impl OperatorValidator { | Operator::F32Nearest | Operator::F32Sqrt => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::F32)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::F32)?; } Operator::F32Add | Operator::F32Sub @@ -1098,9 +1101,9 @@ impl OperatorValidator { | Operator::F32Max | Operator::F32Copysign => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F32))?; - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::F32)?; + self.pop_operand(Some(ValType::F32))?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::F32)?; } Operator::F64Abs | Operator::F64Neg @@ -1110,8 +1113,8 @@ impl OperatorValidator { | Operator::F64Nearest | Operator::F64Sqrt => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::F64)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::F64)?; } Operator::F64Add | Operator::F64Sub @@ -1121,81 +1124,81 @@ impl OperatorValidator { | Operator::F64Max | Operator::F64Copysign => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F64))?; - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::F64)?; + self.pop_operand(Some(ValType::F64))?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::F64)?; } Operator::I32WrapI64 => { - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::I32)?; } Operator::I32TruncF32S | Operator::I32TruncF32U => { - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::I32)?; } Operator::I32TruncF64S | Operator::I32TruncF64U => { - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::I32)?; } Operator::I64ExtendI32S | Operator::I64ExtendI32U => { - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::I64)?; } Operator::I64TruncF32S | Operator::I64TruncF32U => { - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::I64)?; } Operator::I64TruncF64S | Operator::I64TruncF64U => { - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::I64)?; } Operator::F32ConvertI32S | Operator::F32ConvertI32U => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::F32)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::F32)?; } Operator::F32ConvertI64S | Operator::F32ConvertI64U => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::F32)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::F32)?; } Operator::F32DemoteF64 => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::F32)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::F32)?; } Operator::F64ConvertI32S | Operator::F64ConvertI32U => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::F64)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::F64)?; } Operator::F64ConvertI64S | Operator::F64ConvertI64U => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::F64)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::F64)?; } Operator::F64PromoteF32 => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::F64)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::F64)?; } Operator::I32ReinterpretF32 => { - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::I32)?; } Operator::I64ReinterpretF64 => { - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::I64)?; } Operator::F32ReinterpretI32 => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::F32)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::F32)?; } Operator::F64ReinterpretI64 => { self.check_non_deterministic_enabled()?; - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::F64)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::F64)?; } Operator::I32TruncSatF32S | Operator::I32TruncSatF32U => { if !self.features.saturating_float_to_int { @@ -1203,8 +1206,8 @@ impl OperatorValidator { "saturating float to int conversions support is not enabled", )); } - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::I32)?; } Operator::I32TruncSatF64S | Operator::I32TruncSatF64U => { if !self.features.saturating_float_to_int { @@ -1212,8 +1215,8 @@ impl OperatorValidator { "saturating float to int conversions support is not enabled", )); } - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::I32)?; } Operator::I64TruncSatF32S | Operator::I64TruncSatF32U => { if !self.features.saturating_float_to_int { @@ -1221,8 +1224,8 @@ impl OperatorValidator { "saturating float to int conversions support is not enabled", )); } - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::I64)?; } Operator::I64TruncSatF64S | Operator::I64TruncSatF64U => { if !self.features.saturating_float_to_int { @@ -1230,8 +1233,8 @@ impl OperatorValidator { "saturating float to int conversions support is not enabled", )); } - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::I64)?; } Operator::I32Extend16S | Operator::I32Extend8S => { if !self.features.sign_extension { @@ -1239,8 +1242,8 @@ impl OperatorValidator { "sign extension operations support is not enabled", )); } - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::I32)?; } Operator::I64Extend32S | Operator::I64Extend16S | Operator::I64Extend8S => { @@ -1249,8 +1252,8 @@ impl OperatorValidator { "sign extension operations support is not enabled", )); } - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::I64)?; } Operator::I32AtomicLoad { memarg } @@ -1259,7 +1262,7 @@ impl OperatorValidator { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::I64AtomicLoad { memarg } | Operator::I64AtomicLoad32U { memarg } @@ -1268,14 +1271,14 @@ impl OperatorValidator { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::I32AtomicStore { memarg } | Operator::I32AtomicStore16 { memarg } | Operator::I32AtomicStore8 { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; } Operator::I64AtomicStore { memarg } @@ -1284,7 +1287,7 @@ impl OperatorValidator { | Operator::I64AtomicStore8 { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; } Operator::I32AtomicRmwAdd { memarg } @@ -1304,9 +1307,9 @@ impl OperatorValidator { | Operator::I32AtomicRmw8XorU { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::I64AtomicRmwAdd { memarg } | Operator::I64AtomicRmwSub { memarg } @@ -1330,28 +1333,28 @@ impl OperatorValidator { | Operator::I64AtomicRmw8XorU { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::I32AtomicRmwXchg { memarg } | Operator::I32AtomicRmw16XchgU { memarg } | Operator::I32AtomicRmw8XchgU { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::I32AtomicRmwCmpxchg { memarg } | Operator::I32AtomicRmw16CmpxchgU { memarg } | Operator::I32AtomicRmw8CmpxchgU { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::I64AtomicRmwXchg { memarg } | Operator::I64AtomicRmw32XchgU { memarg } @@ -1359,9 +1362,9 @@ impl OperatorValidator { | Operator::I64AtomicRmw8XchgU { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::I64AtomicRmwCmpxchg { memarg } | Operator::I64AtomicRmw32CmpxchgU { memarg } @@ -1369,33 +1372,33 @@ impl OperatorValidator { | Operator::I64AtomicRmw8CmpxchgU { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I64))?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I64)?; + self.push_operand(ValType::I64)?; } Operator::MemoryAtomicNotify { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::MemoryAtomicWait32 { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I64))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::MemoryAtomicWait64 { memarg } => { self.check_threads_enabled()?; let ty = self.check_shared_memarg_wo_align(memarg, resources)?; - self.pop_operand(Some(Type::I64))?; - self.pop_operand(Some(Type::I64))?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::I64))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::AtomicFence { ref flags } => { self.check_threads_enabled()?; @@ -1408,7 +1411,7 @@ impl OperatorValidator { Operator::RefNull { ty } => { self.check_reference_types_enabled()?; match ty { - Type::FuncRef | Type::ExternRef => {} + ValType::FuncRef | ValType::ExternRef => {} _ => { return Err(OperatorValidatorError::new( "invalid reference type in ref.null", @@ -1420,14 +1423,14 @@ impl OperatorValidator { Operator::RefIsNull => { self.check_reference_types_enabled()?; match self.pop_operand(None)? { - None | Some(Type::FuncRef) | Some(Type::ExternRef) => {} + None | Some(ValType::FuncRef) | Some(ValType::ExternRef) => {} _ => { return Err(OperatorValidatorError::new( "type mismatch: invalid reference type in ref.is_null", )) } } - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::RefFunc { function_index } => { self.check_reference_types_enabled()?; @@ -1440,127 +1443,127 @@ impl OperatorValidator { if !resources.is_function_referenced(function_index) { return Err(OperatorValidatorError::new("undeclared function reference")); } - self.push_operand(Type::FuncRef)?; + self.push_operand(ValType::FuncRef)?; } Operator::V128Load { memarg } => { self.check_simd_enabled()?; let ty = self.check_memarg(memarg, 4, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Store { memarg } => { self.check_simd_enabled()?; let ty = self.check_memarg(memarg, 4, resources)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(ty))?; } Operator::V128Const { .. } => { self.check_simd_enabled()?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::I8x16Splat | Operator::I16x8Splat | Operator::I32x4Splat => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::I32))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::I32))?; + self.push_operand(ValType::V128)?; } Operator::I64x2Splat => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::I64))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::I64))?; + self.push_operand(ValType::V128)?; } Operator::F32x4Splat => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; - self.pop_operand(Some(Type::F32))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::F32))?; + self.push_operand(ValType::V128)?; } Operator::F64x2Splat => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; - self.pop_operand(Some(Type::F64))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::F64))?; + self.push_operand(ValType::V128)?; } Operator::I8x16ExtractLaneS { lane } | Operator::I8x16ExtractLaneU { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; } Operator::I16x8ExtractLaneS { lane } | Operator::I16x8ExtractLaneU { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; } Operator::I32x4ExtractLane { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; } Operator::I8x16ReplaceLane { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I16x8ReplaceLane { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I32x4ReplaceLane { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I64x2ExtractLane { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::I64)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I64)?; } Operator::I64x2ReplaceLane { lane } => { self.check_simd_enabled()?; self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(Type::I64))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::I64))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::F32x4ExtractLane { lane } => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::F32)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::F32)?; } Operator::F32x4ReplaceLane { lane } => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(Type::F32))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::F32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::F64x2ExtractLane { lane } => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::F64)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::F64)?; } Operator::F64x2ReplaceLane { lane } => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(Type::F64))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::F64))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::F32x4Eq | Operator::F32x4Ne @@ -1592,18 +1595,18 @@ impl OperatorValidator { | Operator::F64x2PMax => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::F32x4RelaxedMin | Operator::F32x4RelaxedMax | Operator::F64x2RelaxedMin | Operator::F64x2RelaxedMax => { self.check_relaxed_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I8x16Eq | Operator::I8x16Ne @@ -1697,9 +1700,9 @@ impl OperatorValidator { | Operator::I64x2ExtMulHighI32x4U | Operator::I16x8Q15MulrSatS => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::F32x4Ceil | Operator::F32x4Floor @@ -1727,8 +1730,8 @@ impl OperatorValidator { | Operator::F32x4ConvertI32x4U => { self.check_non_deterministic_enabled()?; self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::V128Not | Operator::I8x16Abs @@ -1757,23 +1760,23 @@ impl OperatorValidator { | Operator::I32x4ExtAddPairwiseI16x8S | Operator::I32x4ExtAddPairwiseI16x8U => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I32x4RelaxedTruncSatF32x4S | Operator::I32x4RelaxedTruncSatF32x4U | Operator::I32x4RelaxedTruncSatF64x2SZero | Operator::I32x4RelaxedTruncSatF64x2UZero => { self.check_relaxed_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::V128Bitselect => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::F32x4Fma | Operator::F32x4Fms @@ -1784,10 +1787,10 @@ impl OperatorValidator { | Operator::I32x4LaneSelect | Operator::I64x2LaneSelect => { self.check_relaxed_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::V128AnyTrue | Operator::I8x16AllTrue @@ -1799,8 +1802,8 @@ impl OperatorValidator { | Operator::I64x2AllTrue | Operator::I64x2Bitmask => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::I32)?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::I32)?; } Operator::I8x16Shl | Operator::I8x16ShrS @@ -1815,48 +1818,48 @@ impl OperatorValidator { | Operator::I64x2ShrS | Operator::I64x2ShrU => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I8x16Swizzle => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I8x16RelaxedSwizzle => { self.check_relaxed_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; - self.push_operand(Type::V128)?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.push_operand(ValType::V128)?; } Operator::I8x16Shuffle { ref lanes } => { self.check_simd_enabled()?; - self.pop_operand(Some(Type::V128))?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; + self.pop_operand(Some(ValType::V128))?; for i in lanes { self.check_simd_lane_index(*i, 32)?; } - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load8Splat { memarg } => { self.check_simd_enabled()?; let ty = self.check_memarg(memarg, 0, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load16Splat { memarg } => { self.check_simd_enabled()?; let ty = self.check_memarg(memarg, 1, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load32Splat { memarg } | Operator::V128Load32Zero { memarg } => { self.check_simd_enabled()?; let ty = self.check_memarg(memarg, 2, resources)?; self.pop_operand(Some(ty))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load64Splat { memarg } | Operator::V128Load64Zero { memarg } @@ -1869,66 +1872,66 @@ impl OperatorValidator { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 3, resources)?; self.pop_operand(Some(idx))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load8Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 0, resources)?; self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load16Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 1, resources)?; self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load32Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 2, resources)?; self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Load64Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 3, resources)?; self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; - self.push_operand(Type::V128)?; + self.push_operand(ValType::V128)?; } Operator::V128Store8Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 0, resources)?; self.check_simd_lane_index(lane, 16)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; } Operator::V128Store16Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 1, resources)?; self.check_simd_lane_index(lane, 8)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; } Operator::V128Store32Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 2, resources)?; self.check_simd_lane_index(lane, 4)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; } Operator::V128Store64Lane { memarg, lane } => { self.check_simd_enabled()?; let idx = self.check_memarg(memarg, 3, resources)?; self.check_simd_lane_index(lane, 2)?; - self.pop_operand(Some(Type::V128))?; + self.pop_operand(Some(ValType::V128))?; self.pop_operand(Some(idx))?; } Operator::MemoryInit { mem, segment } => { @@ -1939,8 +1942,8 @@ impl OperatorValidator { Some(count) if segment < count => {} Some(_) => bail_op_err!("unknown data segment {}", segment), } - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; } Operator::DataDrop { segment } => { @@ -1959,7 +1962,7 @@ impl OperatorValidator { // The length operand here is the smaller of src/dst, which is // i32 if one is i32 self.pop_operand(Some(match src_ty { - Type::I32 => Type::I32, + ValType::I32 => ValType::I32, _ => dst_ty, }))?; @@ -1972,7 +1975,7 @@ impl OperatorValidator { self.check_bulk_memory_enabled()?; let ty = self.check_memory_index(mem, resources)?; self.pop_operand(Some(ty))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; } Operator::TableInit { segment, table } => { @@ -1994,9 +1997,9 @@ impl OperatorValidator { if segment_ty != table.element_type { return Err(OperatorValidatorError::new("type mismatch")); } - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; } Operator::ElemDrop { segment } => { self.check_bulk_memory_enabled()?; @@ -2023,9 +2026,9 @@ impl OperatorValidator { if src.element_type != dst.element_type { return Err(OperatorValidatorError::new("type mismatch")); } - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; + self.pop_operand(Some(ValType::I32))?; } Operator::TableGet { table } => { self.check_reference_types_enabled()?; @@ -2033,7 +2036,7 @@ impl OperatorValidator { Some(ty) => ty.element_type, None => return Err(OperatorValidatorError::new("table index out of bounds")), }; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.push_operand(ty)?; } Operator::TableSet { table } => { @@ -2043,7 +2046,7 @@ impl OperatorValidator { None => return Err(OperatorValidatorError::new("table index out of bounds")), }; self.pop_operand(Some(ty))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; } Operator::TableGrow { table } => { self.check_reference_types_enabled()?; @@ -2051,16 +2054,16 @@ impl OperatorValidator { Some(ty) => ty.element_type, None => return Err(OperatorValidatorError::new("table index out of bounds")), }; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::TableSize { table } => { self.check_reference_types_enabled()?; if resources.table_at(table).is_none() { return Err(OperatorValidatorError::new("table index out of bounds")); } - self.push_operand(Type::I32)?; + self.push_operand(ValType::I32)?; } Operator::TableFill { table } => { self.check_bulk_memory_enabled()?; @@ -2068,9 +2071,9 @@ impl OperatorValidator { Some(ty) => ty.element_type, None => return Err(OperatorValidatorError::new("table index out of bounds")), }; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; self.pop_operand(Some(ty))?; - self.pop_operand(Some(Type::I32))?; + self.pop_operand(Some(ValType::I32))?; } } Ok(()) @@ -2150,7 +2153,7 @@ impl PreciseIterator for T {} fn params( ty: BlockType, resources: &impl WasmModuleResources, -) -> OperatorValidatorResult + '_> { +) -> OperatorValidatorResult + '_> { Ok(match ty { BlockType::Empty | BlockType::Type(_) => Either::B(None.into_iter()), BlockType::FuncType(t) => Either::A(func_type_at(resources, t)?.inputs()), @@ -2160,7 +2163,7 @@ fn params( fn results( ty: BlockType, resources: &impl WasmModuleResources, -) -> OperatorValidatorResult + '_> { +) -> OperatorValidatorResult + '_> { Ok(match ty { BlockType::Empty => Either::B(None.into_iter()), BlockType::Type(t) => Either::B(Some(t).into_iter()), @@ -2172,21 +2175,21 @@ fn label_types( ty: BlockType, resources: &impl WasmModuleResources, kind: FrameKind, -) -> OperatorValidatorResult + '_> { +) -> OperatorValidatorResult + '_> { Ok(match kind { FrameKind::Loop => Either::A(params(ty, resources)?), _ => Either::B(results(ty, resources)?), }) } -fn ty_to_str(ty: Type) -> &'static str { +fn ty_to_str(ty: ValType) -> &'static str { match ty { - Type::I32 => "i32", - Type::I64 => "i64", - Type::F32 => "f32", - Type::F64 => "f64", - Type::V128 => "v128", - Type::FuncRef => "funcref", - Type::ExternRef => "externref", + ValType::I32 => "i32", + ValType::I64 => "i64", + ValType::F32 => "f32", + ValType::F64 => "f64", + ValType::V128 => "v128", + ValType::FuncRef => "funcref", + ValType::ExternRef => "externref", } } diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs index 53f229c541..e079ea8fae 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -1,7 +1,7 @@ //! Types relating to type information provided by validation. use super::{component::ComponentState, core::Module}; -use crate::{FuncType, GlobalType, MemoryType, PrimitiveInterfaceType, TableType, Type}; +use crate::{FuncType, GlobalType, MemoryType, PrimitiveValType, TableType, ValType}; use indexmap::{IndexMap, IndexSet}; use std::{ borrow::Borrow, @@ -27,7 +27,7 @@ const MAX_LOWERED_TYPES: usize = MAX_FLAT_FUNC_PARAMS + 1; /// A simple alloc-free list of types used for calculating lowered function signatures. pub(crate) struct LoweredTypes { - types: [Type; MAX_LOWERED_TYPES], + types: [ValType; MAX_LOWERED_TYPES], len: usize, max: usize, } @@ -36,7 +36,7 @@ impl LoweredTypes { fn new(max: usize) -> Self { assert!(max <= MAX_LOWERED_TYPES); Self { - types: [Type::I32; MAX_LOWERED_TYPES], + types: [ValType::I32; MAX_LOWERED_TYPES], len: 0, max, } @@ -50,7 +50,7 @@ impl LoweredTypes { self.len == self.max } - fn get_mut(&mut self, index: usize) -> Option<&mut Type> { + fn get_mut(&mut self, index: usize) -> Option<&mut ValType> { if index < self.len { Some(&mut self.types[index]) } else { @@ -58,7 +58,7 @@ impl LoweredTypes { } } - fn push(&mut self, ty: Type) -> bool { + fn push(&mut self, ty: ValType) -> bool { if self.maxed() { return false; } @@ -72,34 +72,31 @@ impl LoweredTypes { self.len = 0; } - pub fn as_slice(&self) -> &[Type] { + pub fn as_slice(&self) -> &[ValType] { &self.types[..self.len] } - pub fn iter(&self) -> impl Iterator + '_ { + pub fn iter(&self) -> impl Iterator + '_ { self.as_slice().iter().copied() } } -fn push_primitive_wasm_types( - ty: &PrimitiveInterfaceType, - lowered_types: &mut LoweredTypes, -) -> bool { +fn push_primitive_wasm_types(ty: &PrimitiveValType, lowered_types: &mut LoweredTypes) -> bool { match ty { - PrimitiveInterfaceType::Unit => true, - PrimitiveInterfaceType::Bool - | PrimitiveInterfaceType::S8 - | PrimitiveInterfaceType::U8 - | PrimitiveInterfaceType::S16 - | PrimitiveInterfaceType::U16 - | PrimitiveInterfaceType::S32 - | PrimitiveInterfaceType::U32 - | PrimitiveInterfaceType::Char => lowered_types.push(Type::I32), - PrimitiveInterfaceType::S64 | PrimitiveInterfaceType::U64 => lowered_types.push(Type::I64), - PrimitiveInterfaceType::Float32 => lowered_types.push(Type::F32), - PrimitiveInterfaceType::Float64 => lowered_types.push(Type::F64), - PrimitiveInterfaceType::String => { - lowered_types.push(Type::I32) && lowered_types.push(Type::I32) + PrimitiveValType::Unit => true, + PrimitiveValType::Bool + | PrimitiveValType::S8 + | PrimitiveValType::U8 + | PrimitiveValType::S16 + | PrimitiveValType::U16 + | PrimitiveValType::S32 + | PrimitiveValType::U32 + | PrimitiveValType::Char => lowered_types.push(ValType::I32), + PrimitiveValType::S64 | PrimitiveValType::U64 => lowered_types.push(ValType::I64), + PrimitiveValType::Float32 => lowered_types.push(ValType::F32), + PrimitiveValType::Float64 => lowered_types.push(ValType::F64), + PrimitiveValType::String => { + lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32) } } } @@ -116,87 +113,91 @@ pub struct TypeId { pub(crate) index: usize, } -/// A unified type definition for inspecting WebAssembly modules and components. -pub enum TypeDef { +/// A unified type definition for validating WebAssembly modules and components. +#[derive(Debug)] +pub enum Type { /// The definition is for a core function type. Func(FuncType), - /// The definition is for a module type. + /// The definition is for a core module type. /// /// This variant is only supported when parsing a component. Module(ModuleType), - /// The definition is for a module instance type. + /// The definition is for a core module instance type. /// /// This variant is only supported when parsing a component. - ModuleInstance(ModuleInstanceType), + Instance(InstanceType), /// The definition is for a component type. /// /// This variant is only supported when parsing a component. Component(ComponentType), - /// The definition is for an instance type. + /// The definition is for a component instance type. /// /// This variant is only supported when parsing a component. - Instance(InstanceType), + ComponentInstance(ComponentInstanceType), /// The definition is for a component function type. /// /// This variant is only supported when parsing a component. ComponentFunc(ComponentFuncType), - /// The definition is for a value type. - /// - /// This variant is only supported when parsing a component. - Value(InterfaceTypeRef), - /// The definition is for an interface type. + /// The definition is for a component defined type. /// /// This variant is only supported when parsing a component. - Interface(InterfaceType), + Defined(ComponentDefinedType), } -impl TypeDef { - pub(crate) fn unwrap_func_type(&self) -> &FuncType { +impl Type { + /// Converts the type to a core function type. + pub fn as_func_type(&self) -> Option<&FuncType> { match self { - Self::Func(ty) => ty, - _ => panic!("expected function type"), + Self::Func(ty) => Some(ty), + _ => None, } } - pub(crate) fn unwrap_module_type(&self) -> &ModuleType { + /// Converts the type to a core module type. + pub fn as_module_type(&self) -> Option<&ModuleType> { match self { - Self::Module(ty) => ty, - _ => panic!("expected module type"), + Self::Module(ty) => Some(ty), + _ => None, } } - pub(crate) fn unwrap_module_instance_type(&self) -> &ModuleInstanceType { + /// Converts the type to a core module instance type. + pub fn as_instance_type(&self) -> Option<&InstanceType> { match self { - Self::ModuleInstance(ty) => ty, - _ => panic!("expected module instance type"), + Self::Instance(ty) => Some(ty), + _ => None, } } - pub(crate) fn unwrap_component_type(&self) -> &ComponentType { + /// Converts the type to a component type. + pub fn as_component_type(&self) -> Option<&ComponentType> { match self { - Self::Component(ty) => ty, - _ => panic!("expected component type"), + Self::Component(ty) => Some(ty), + _ => None, } } - pub(crate) fn unwrap_instance_type(&self) -> &InstanceType { + /// Converts the type to a component instance type. + pub fn as_component_instance_type(&self) -> Option<&ComponentInstanceType> { match self { - Self::Instance(ty) => ty, - _ => panic!("expected instance type"), + Self::ComponentInstance(ty) => Some(ty), + _ => None, } } - pub(crate) fn unwrap_component_func_type(&self) -> &ComponentFuncType { + /// Converts the type to a component function type. + pub fn as_component_func_type(&self) -> Option<&ComponentFuncType> { match self { - Self::ComponentFunc(ty) => ty, - _ => panic!("expected component function type"), + Self::ComponentFunc(ty) => Some(ty), + _ => None, } } - pub(crate) fn unwrap_interface_type(&self) -> &InterfaceType { + /// Converts the type to a component defined type. + pub fn as_defined_type(&self) -> Option<&ComponentDefinedType> { match self { - Self::Interface(ty) => ty, - _ => panic!("expected interface type"), + Self::Defined(ty) => Some(ty), + _ => None, } } @@ -204,52 +205,56 @@ impl TypeDef { match self { Self::Func(ty) => 1 + ty.params.len() + ty.returns.len(), Self::Module(ty) => ty.type_size, - Self::ModuleInstance(ty) => ty.type_size, - Self::Component(ty) => ty.type_size, Self::Instance(ty) => ty.type_size, + Self::Component(ty) => ty.type_size, + Self::ComponentInstance(ty) => ty.type_size, Self::ComponentFunc(ty) => ty.type_size, - Self::Value(ty) => ty.type_size(), - Self::Interface(ty) => ty.type_size(), + Self::Defined(ty) => ty.type_size(), } } } -/// A reference to an interface type. +/// A component value type. #[derive(Debug, Clone, Copy)] -pub enum InterfaceTypeRef { - /// The interface type is one of the primitive types. - Primitive(PrimitiveInterfaceType), - /// The interface type is represented with the given type identifier. +pub enum ComponentValType { + /// The value type is one of the primitive types. + Primitive(PrimitiveValType), + /// The type is represented with the given type identifier. Type(TypeId), } -impl InterfaceTypeRef { - pub(crate) fn requires_into_option(&self, types: &TypeList) -> bool { +impl ComponentValType { + pub(crate) fn requires_realloc(&self, types: &TypeList) -> bool { match self { - InterfaceTypeRef::Primitive(ty) => ty.requires_into_option(), - InterfaceTypeRef::Type(ty) => types[*ty] - .unwrap_interface_type() - .requires_into_option(types), + ComponentValType::Primitive(ty) => ty.requires_realloc(), + ComponentValType::Type(ty) => types[*ty] + .as_defined_type() + .unwrap() + .requires_realloc(types), } } pub(crate) fn is_optional(&self, types: &TypeList) -> bool { match self { - InterfaceTypeRef::Primitive(_) => false, - InterfaceTypeRef::Type(ty) => { - matches!(types[*ty].unwrap_interface_type(), InterfaceType::Option(_)) + ComponentValType::Primitive(_) => false, + ComponentValType::Type(ty) => { + matches!( + types[*ty].as_defined_type().unwrap(), + ComponentDefinedType::Option(_) + ) } } } pub(crate) fn is_subtype_of(&self, other: &Self, types: &TypeList) -> bool { match (self, other) { - (InterfaceTypeRef::Primitive(ty), InterfaceTypeRef::Primitive(other_ty)) => { + (ComponentValType::Primitive(ty), ComponentValType::Primitive(other_ty)) => { ty.is_subtype_of(other_ty) } - (InterfaceTypeRef::Type(ty), InterfaceTypeRef::Type(other_ty)) => types[*ty] - .unwrap_interface_type() - .is_subtype_of(types[*other_ty].unwrap_interface_type(), types), + (ComponentValType::Type(ty), ComponentValType::Type(other_ty)) => types[*ty] + .as_defined_type() + .unwrap() + .is_subtype_of(types[*other_ty].as_defined_type().unwrap(), types), _ => false, } } @@ -258,7 +263,8 @@ impl InterfaceTypeRef { match self { Self::Primitive(ty) => push_primitive_wasm_types(ty, lowered_types), Self::Type(id) => types[*id] - .unwrap_interface_type() + .as_defined_type() + .unwrap() .push_wasm_types(types, lowered_types), } } @@ -305,7 +311,7 @@ impl EntityType { match (self, b) { (EntityType::Func(a), EntityType::Func(b)) => { - types[*a].unwrap_func_type() == types[*b].unwrap_func_type() + types[*a].as_func_type().unwrap() == types[*b].as_func_type().unwrap() } (EntityType::Table(a), EntityType::Table(b)) => { a.element_type == b.element_type && limits_match!(a, b) @@ -315,7 +321,7 @@ impl EntityType { } (EntityType::Global(a), EntityType::Global(b)) => a == b, (EntityType::Tag(a), EntityType::Tag(b)) => { - types[*a].unwrap_func_type() == types[*b].unwrap_func_type() + types[*a].as_func_type().unwrap() == types[*b].as_func_type().unwrap() } _ => false, } @@ -385,8 +391,8 @@ impl ModuleImportKey for (&str, &str) { } } -/// Represents a module type. -#[derive(Clone)] +/// Represents a core module type. +#[derive(Debug, Clone)] pub struct ModuleType { /// The effective type size for the module type. pub(crate) type_size: usize, @@ -427,8 +433,8 @@ impl ModuleType { } /// Represents the kind of module instance type. -#[derive(Clone)] -pub enum ModuleInstanceTypeKind { +#[derive(Debug, Clone)] +pub enum InstanceTypeKind { /// The instance type is the result of instantiating a module type. Instantiated(TypeId), /// The instance type is the result of instantiating from exported items. @@ -436,19 +442,19 @@ pub enum ModuleInstanceTypeKind { } /// Represents a module instance type. -#[derive(Clone)] -pub struct ModuleInstanceType { +#[derive(Debug, Clone)] +pub struct InstanceType { /// The effective type size for the module instance type. pub(crate) type_size: usize, /// The kind of module instance type. - pub kind: ModuleInstanceTypeKind, + pub kind: InstanceTypeKind, } -impl ModuleInstanceType { +impl InstanceType { pub(crate) fn exports<'a>(&'a self, types: &'a TypeList) -> &'a HashMap { match &self.kind { - ModuleInstanceTypeKind::Instantiated(id) => &types[*id].unwrap_module_type().exports, - ModuleInstanceTypeKind::Exports(exports) => exports, + InstanceTypeKind::Instantiated(id) => &types[*id].as_module_type().unwrap().exports, + InstanceTypeKind::Exports(exports) => exports, } } } @@ -456,39 +462,47 @@ impl ModuleInstanceType { /// The entity type for imports and exports of a component. #[derive(Debug, Clone, Copy)] pub enum ComponentEntityType { - /// The entity is a module. + /// The entity is a core module. Module(TypeId), - /// The entity is a component. - Component(TypeId), - /// The entity is an instance. - Instance(TypeId), - /// The entity is a component function. + /// The entity is a function. Func(TypeId), /// The entity is a value. - Value(InterfaceTypeRef), + Value(ComponentValType), /// The entity is a type. Type(TypeId), + /// The entity is a component instance. + Instance(TypeId), + /// The entity is a component. + Component(TypeId), } impl ComponentEntityType { pub(crate) fn is_subtype_of(&self, other: &Self, types: &TypeList) -> bool { match (self, other) { (Self::Module(ty), Self::Module(other_ty)) => types[*ty] - .unwrap_module_type() - .is_subtype_of(types[*other_ty].unwrap_module_type(), types), - (Self::Component(ty), Self::Component(other_ty)) => types[*ty] - .unwrap_component_type() - .is_subtype_of(types[*other_ty].unwrap_component_type(), types), - (Self::Instance(ty), Self::Instance(other_ty)) => types[*ty] - .unwrap_instance_type() - .is_subtype_of(types[*other_ty].unwrap_instance_type(), types), + .as_module_type() + .unwrap() + .is_subtype_of(types[*other_ty].as_module_type().unwrap(), types), (Self::Func(ty), Self::Func(other_ty)) => types[*ty] - .unwrap_component_func_type() - .is_subtype_of(types[*other_ty].unwrap_component_func_type(), types), + .as_component_func_type() + .unwrap() + .is_subtype_of(types[*other_ty].as_component_func_type().unwrap(), types), (Self::Value(ty), Self::Value(other_ty)) => ty.is_subtype_of(other_ty, types), (Self::Type(ty), Self::Type(other_ty)) => types[*ty] - .unwrap_interface_type() - .is_subtype_of(types[*other_ty].unwrap_interface_type(), types), + .as_defined_type() + .unwrap() + .is_subtype_of(types[*other_ty].as_defined_type().unwrap(), types), + (Self::Instance(ty), Self::Instance(other_ty)) => types[*ty] + .as_component_instance_type() + .unwrap() + .is_subtype_of( + types[*other_ty].as_component_instance_type().unwrap(), + types, + ), + (Self::Component(ty), Self::Component(other_ty)) => types[*ty] + .as_component_type() + .unwrap() + .is_subtype_of(types[*other_ty].as_component_type().unwrap(), types), _ => false, } } @@ -496,28 +510,28 @@ impl ComponentEntityType { pub(crate) fn desc(&self) -> &'static str { match self { Self::Module(_) => "module", - Self::Component(_) => "component", - Self::Instance(_) => "instance", Self::Func(_) => "function", Self::Value(_) => "value", Self::Type(_) => "type", + Self::Instance(_) => "instance", + Self::Component(_) => "component", } } pub(crate) fn type_size(&self) -> usize { match self { Self::Module(ty) - | Self::Component(ty) - | Self::Instance(ty) | Self::Func(ty) - | Self::Type(ty) => ty.type_size, + | Self::Type(ty) + | Self::Instance(ty) + | Self::Component(ty) => ty.type_size, Self::Value(ty) => ty.type_size(), } } } /// Represents a type of a component. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct ComponentType { /// The effective type size for the component type. pub(crate) type_size: usize, @@ -550,9 +564,9 @@ impl ComponentType { } } -/// Represents the kind of instance type. -#[derive(Clone)] -pub enum InstanceTypeKind { +/// Represents the kind of a component instance. +#[derive(Debug, Clone)] +pub enum ComponentInstanceTypeKind { /// The instance type is from a definition. Defined(HashMap), /// The instance type is the result of instantiating a component type. @@ -562,22 +576,25 @@ pub enum InstanceTypeKind { } /// Represents a type of a component instance. -#[derive(Clone)] -pub struct InstanceType { +#[derive(Debug, Clone)] +pub struct ComponentInstanceType { /// The effective type size for the instance type. pub(crate) type_size: usize, /// The kind of instance type. - pub kind: InstanceTypeKind, + pub kind: ComponentInstanceTypeKind, } -impl InstanceType { +impl ComponentInstanceType { pub(crate) fn exports<'a>( &'a self, types: &'a TypeList, ) -> &'a HashMap { match &self.kind { - InstanceTypeKind::Defined(exports) | InstanceTypeKind::Exports(exports) => exports, - InstanceTypeKind::Instantiated(id) => &types[*id].unwrap_component_type().exports, + ComponentInstanceTypeKind::Defined(exports) + | ComponentInstanceTypeKind::Exports(exports) => exports, + ComponentInstanceTypeKind::Instantiated(id) => { + &types[*id].as_component_type().unwrap().exports + } } } @@ -598,23 +615,20 @@ impl InstanceType { } /// Represents a type of a component function. -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct ComponentFuncType { /// The effective type size for the component function type. pub(crate) type_size: usize, /// The function parameters. - pub params: Box<[(Option, InterfaceTypeRef)]>, + pub params: Box<[(Option, ComponentValType)]>, /// The function's result type. - pub result: InterfaceTypeRef, + pub result: ComponentValType, } impl ComponentFuncType { - pub(crate) fn requires_into_option(&self, types: &TypeList) -> bool { - self.result.requires_into_option(types) - || self - .params - .iter() - .any(|(_, ty)| ty.requires_into_option(types)) + pub(crate) fn requires_realloc(&self, types: &TypeList) -> bool { + self.result.requires_realloc(types) + || self.params.iter().any(|(_, ty)| ty.requires_realloc(types)) } pub(crate) fn is_subtype_of(&self, other: &Self, types: &TypeList) -> bool { @@ -663,7 +677,7 @@ impl ComponentFuncType { // Function will have a single pointer parameter to pass the arguments // via linear memory params.clear(); - assert!(params.push(Type::I32)); + assert!(params.push(ValType::I32)); break; } } @@ -674,9 +688,9 @@ impl ComponentFuncType { results.clear(); if import { params.max = MAX_LOWERED_TYPES; - assert!(params.push(Type::I32)); + assert!(params.push(ValType::I32)); } else { - assert!(results.push(Type::I32)); + assert!(results.push(ValType::I32)); } } @@ -688,9 +702,9 @@ impl ComponentFuncType { #[derive(Debug, Clone)] pub struct VariantCase { /// The variant case type. - pub ty: InterfaceTypeRef, - /// The value of the variant to default to. - pub default_to: Option, + pub ty: ComponentValType, + /// The name of the variant case refined by this one. + pub refines: Option, } /// Represents a record type. @@ -699,7 +713,7 @@ pub struct RecordType { /// The effective type size for the record type. pub(crate) type_size: usize, /// The map of record fields. - pub fields: IndexMap, + pub fields: IndexMap, } /// Represents a variant type. @@ -717,7 +731,7 @@ pub struct TupleType { /// The effective type size for the tuple type. pub(crate) type_size: usize, /// The types of the tuple. - pub types: Box<[InterfaceTypeRef]>, + pub types: Box<[ComponentValType]>, } /// Represents a union type. @@ -726,20 +740,20 @@ pub struct UnionType { /// The inclusive type count for the union type. pub(crate) type_size: usize, /// The types of the union. - pub types: Box<[InterfaceTypeRef]>, + pub types: Box<[ComponentValType]>, } -/// Represents an interface type. +/// Represents a component defined type. #[derive(Debug, Clone)] -pub enum InterfaceType { - /// The type is a primitive interface type. - Primitive(PrimitiveInterfaceType), +pub enum ComponentDefinedType { + /// The type is a primitive value type. + Primitive(PrimitiveValType), /// The type is a record. Record(RecordType), /// The type is a variant. Variant(VariantType), /// The type is a list. - List(InterfaceTypeRef), + List(ComponentValType), /// The type is a tuple. Tuple(TupleType), /// The type is a set of flags. @@ -749,27 +763,24 @@ pub enum InterfaceType { /// The type is a union. Union(UnionType), /// The type is an `option`. - Option(InterfaceTypeRef), + Option(ComponentValType), /// The type is an `expected`. - Expected(InterfaceTypeRef, InterfaceTypeRef), + Expected(ComponentValType, ComponentValType), } -impl InterfaceType { - pub(crate) fn requires_into_option(&self, types: &TypeList) -> bool { +impl ComponentDefinedType { + pub(crate) fn requires_realloc(&self, types: &TypeList) -> bool { match self { - InterfaceType::Primitive(ty) => ty.requires_into_option(), - InterfaceType::Record(r) => r.fields.values().any(|ty| ty.requires_into_option(types)), - InterfaceType::Variant(v) => v - .cases - .values() - .any(|case| case.ty.requires_into_option(types)), - InterfaceType::List(_) => true, - InterfaceType::Tuple(t) => t.types.iter().any(|ty| ty.requires_into_option(types)), - InterfaceType::Union(u) => u.types.iter().any(|ty| ty.requires_into_option(types)), - InterfaceType::Flags(_) | InterfaceType::Enum(_) => false, - InterfaceType::Option(ty) => ty.requires_into_option(types), - InterfaceType::Expected(ok, error) => { - ok.requires_into_option(types) || error.requires_into_option(types) + Self::Primitive(ty) => ty.requires_realloc(), + Self::Record(r) => r.fields.values().any(|ty| ty.requires_realloc(types)), + Self::Variant(v) => v.cases.values().any(|case| case.ty.requires_realloc(types)), + Self::List(_) => true, + Self::Tuple(t) => t.types.iter().any(|ty| ty.requires_realloc(types)), + Self::Union(u) => u.types.iter().any(|ty| ty.requires_realloc(types)), + Self::Flags(_) | Self::Enum(_) => false, + Self::Option(ty) => ty.requires_realloc(types), + Self::Expected(ok, error) => { + ok.requires_realloc(types) || error.requires_realloc(types) } } } @@ -778,10 +789,8 @@ impl InterfaceType { // Subtyping rules according to // https://github.com/WebAssembly/component-model/blob/17f94ed1270a98218e0e796ca1dad1feb7e5c507/design/mvp/Subtyping.md match (self, other) { - (InterfaceType::Primitive(ty), InterfaceType::Primitive(other_ty)) => { - ty.is_subtype_of(other_ty) - } - (InterfaceType::Record(r), InterfaceType::Record(other_r)) => { + (Self::Primitive(ty), Self::Primitive(other_ty)) => ty.is_subtype_of(other_ty), + (Self::Record(r), Self::Record(other_r)) => { for (name, ty) in r.fields.iter() { if let Some(other_ty) = other_r.fields.get(name) { if !ty.is_subtype_of(other_ty, types) { @@ -799,16 +808,16 @@ impl InterfaceType { } true } - (InterfaceType::Variant(v), InterfaceType::Variant(other_v)) => { + (Self::Variant(v), Self::Variant(other_v)) => { for (name, case) in v.cases.iter() { if let Some(other_case) = other_v.cases.get(name) { // Covariant subtype on the case type if !case.ty.is_subtype_of(&other_case.ty, types) { return false; } - } else if let Some(default) = &case.default_to { - if !other_v.cases.contains_key(default) { - // The default is not in the supertype + } else if let Some(refines) = &case.refines { + if !other_v.cases.contains_key(refines) { + // The refined value is not in the supertype return false; } } else { @@ -819,11 +828,10 @@ impl InterfaceType { } true } - (InterfaceType::List(ty), InterfaceType::List(other_ty)) - | (InterfaceType::Option(ty), InterfaceType::Option(other_ty)) => { + (Self::List(ty), Self::List(other_ty)) | (Self::Option(ty), Self::Option(other_ty)) => { ty.is_subtype_of(other_ty, types) } - (InterfaceType::Tuple(t), InterfaceType::Tuple(other_t)) => { + (Self::Tuple(t), Self::Tuple(other_t)) => { if t.types.len() != other_t.types.len() { return false; } @@ -832,7 +840,7 @@ impl InterfaceType { .zip(other_t.types.iter()) .all(|(ty, other_ty)| ty.is_subtype_of(other_ty, types)) } - (InterfaceType::Union(u), InterfaceType::Union(other_u)) => { + (Self::Union(u), Self::Union(other_u)) => { if u.types.len() != other_u.types.len() { return false; } @@ -841,14 +849,11 @@ impl InterfaceType { .zip(other_u.types.iter()) .all(|(ty, other_ty)| ty.is_subtype_of(other_ty, types)) } - (InterfaceType::Flags(set), InterfaceType::Flags(other_set)) - | (InterfaceType::Enum(set), InterfaceType::Enum(other_set)) => { - set.is_subset(other_set) + (Self::Flags(set), Self::Flags(other_set)) + | (Self::Enum(set), Self::Enum(other_set)) => set.is_subset(other_set), + (Self::Expected(ok, error), Self::Expected(other_ok, other_error)) => { + ok.is_subtype_of(other_ok, types) && error.is_subtype_of(other_error, types) } - ( - InterfaceType::Expected(ok, error), - InterfaceType::Expected(other_ok, other_error), - ) => ok.is_subtype_of(other_ok, types) && error.is_subtype_of(other_error, types), _ => false, } } @@ -873,37 +878,39 @@ impl InterfaceType { .fields .iter() .all(|(_, ty)| ty.push_wasm_types(types, lowered_types)), - Self::Variant(v) => Self::push_variant_types( + Self::Variant(v) => Self::push_variant_wasm_types( v.cases.iter().map(|(_, case)| &case.ty), types, lowered_types, ), - Self::List(_) => lowered_types.push(Type::I32) && lowered_types.push(Type::I32), + Self::List(_) => lowered_types.push(ValType::I32) && lowered_types.push(ValType::I32), Self::Tuple(t) => t .types .iter() .all(|ty| ty.push_wasm_types(types, lowered_types)), Self::Flags(names) => { - (0..(names.len() + 31) / 32).all(|_| lowered_types.push(Type::I32)) + (0..(names.len() + 31) / 32).all(|_| lowered_types.push(ValType::I32)) + } + Self::Enum(_) => lowered_types.push(ValType::I32), + Self::Union(u) => Self::push_variant_wasm_types(u.types.iter(), types, lowered_types), + Self::Option(ty) => { + Self::push_variant_wasm_types([ty].into_iter(), types, lowered_types) } - Self::Enum(_) => lowered_types.push(Type::I32), - Self::Union(u) => Self::push_variant_types(u.types.iter(), types, lowered_types), - Self::Option(ty) => Self::push_variant_types([ty].into_iter(), types, lowered_types), Self::Expected(ok, error) => { - Self::push_variant_types([ok, error].into_iter(), types, lowered_types) + Self::push_variant_wasm_types([ok, error].into_iter(), types, lowered_types) } } } - fn push_variant_types<'a>( - cases: impl ExactSizeIterator, + fn push_variant_wasm_types<'a>( + cases: impl ExactSizeIterator, types: &TypeList, lowered_types: &mut LoweredTypes, ) -> bool { let pushed = if cases.len() <= u32::max_value() as usize { - lowered_types.push(Type::I32) + lowered_types.push(ValType::I32) } else { - lowered_types.push(Type::I64) + lowered_types.push(ValType::I64) }; if !pushed { @@ -934,8 +941,8 @@ impl InterfaceType { true } - fn join_types(a: Type, b: Type) -> Type { - use Type::*; + fn join_types(a: ValType, b: ValType) -> ValType { + use ValType::*; match (a, b) { (I32, I32) | (I64, I64) | (F32, F32) | (F64, F64) => a, @@ -975,51 +982,61 @@ impl Types { } } + fn types(&self, core: bool) -> Option<&Vec> { + Some(match &self.kind { + TypesKind::Module(module) => { + if core { + &module.types + } else { + return None; + } + } + TypesKind::Component(component) => { + if core { + &component.core_types + } else { + &component.types + } + } + }) + } + /// Gets a type based on its type id. /// /// Returns `None` if the type id is unknown. - pub fn type_from_id(&self, id: TypeId) -> Option<&TypeDef> { + pub fn type_from_id(&self, id: TypeId) -> Option<&Type> { self.types.get(id.index) } /// Gets a type id from a type index. /// /// Returns `None` if the type index is out of bounds. - pub fn id_from_type_index(&self, index: u32) -> Option { - let types = match &self.kind { - TypesKind::Module(module) => &module.types, - TypesKind::Component(component) => &component.types, - }; - - types.get(index as usize).copied() + pub fn id_from_type_index(&self, index: u32, core: bool) -> Option { + self.types(core)?.get(index as usize).copied() } - /// Gets a defined type at the given type index. + /// Gets a type at the given type index. /// /// Returns `None` if the index is out of bounds. - pub fn type_at(&self, index: u32) -> Option<&TypeDef> { - self.type_from_id(self.id_from_type_index(index)?) + pub fn type_at(&self, index: u32, core: bool) -> Option<&Type> { + self.type_from_id(*self.types(core)?.get(index as usize)?) } /// Gets a defined core function type at the given type index. /// /// Returns `None` if the index is out of bounds. - /// - /// Additionally, this method always returns `None` for components - /// because core function types are never present in a component's - /// type index space. pub fn func_type_at(&self, index: u32) -> Option<&FuncType> { - match self.type_at(index)? { - TypeDef::Func(ty) => Some(ty), + match self.type_at(index, true)? { + Type::Func(ty) => Some(ty), _ => None, } } - /// Gets the count of defined types. + /// Gets the count of core types. pub fn type_count(&self) -> usize { match &self.kind { TypesKind::Module(module) => module.types.len(), - TypesKind::Component(component) => component.types.len(), + TypesKind::Component(component) => component.core_types.len(), } } @@ -1029,7 +1046,7 @@ impl Types { pub fn table_at(&self, index: u32) -> Option { let tables = match &self.kind { TypesKind::Module(module) => &module.tables, - TypesKind::Component(component) => &component.tables, + TypesKind::Component(component) => &component.core_tables, }; tables.get(index as usize).copied() @@ -1039,7 +1056,7 @@ impl Types { pub fn table_count(&self) -> usize { match &self.kind { TypesKind::Module(module) => module.tables.len(), - TypesKind::Component(component) => component.tables.len(), + TypesKind::Component(component) => component.core_tables.len(), } } @@ -1049,7 +1066,7 @@ impl Types { pub fn memory_at(&self, index: u32) -> Option { let memories = match &self.kind { TypesKind::Module(module) => &module.memories, - TypesKind::Component(component) => &component.memories, + TypesKind::Component(component) => &component.core_memories, }; memories.get(index as usize).copied() @@ -1059,7 +1076,7 @@ impl Types { pub fn memory_count(&self) -> usize { match &self.kind { TypesKind::Module(module) => module.memories.len(), - TypesKind::Component(component) => component.memories.len(), + TypesKind::Component(component) => component.core_memories.len(), } } @@ -1069,7 +1086,7 @@ impl Types { pub fn global_at(&self, index: u32) -> Option { let globals = match &self.kind { TypesKind::Module(module) => &module.globals, - TypesKind::Component(component) => &component.globals, + TypesKind::Component(component) => &component.core_globals, }; globals.get(index as usize).copied() @@ -1079,7 +1096,7 @@ impl Types { pub fn global_count(&self) -> usize { match &self.kind { TypesKind::Module(module) => module.globals.len(), - TypesKind::Component(component) => component.globals.len(), + TypesKind::Component(component) => component.core_globals.len(), } } @@ -1089,70 +1106,55 @@ impl Types { pub fn tag_at(&self, index: u32) -> Option<&FuncType> { let tags = match &self.kind { TypesKind::Module(module) => &module.tags, - TypesKind::Component(component) => &component.tags, + TypesKind::Component(component) => &component.core_tags, }; - Some(self.types[*tags.get(index as usize)?].unwrap_func_type()) + Some( + self.types[*tags.get(index as usize)?] + .as_func_type() + .unwrap(), + ) } /// Gets the count of imported and defined tags. pub fn tag_count(&self) -> usize { match &self.kind { TypesKind::Module(module) => module.tags.len(), - TypesKind::Component(component) => component.tags.len(), + TypesKind::Component(component) => component.core_tags.len(), } } /// Gets the type of a core function at the given function index. /// - /// Returns `None` if the index is out of bounds or when parsing - /// a component and the function at the given index is not a core - /// function type. + /// Returns `None` if the index is out of bounds. pub fn function_at(&self, index: u32) -> Option<&FuncType> { let id = match &self.kind { TypesKind::Module(module) => { &module.types[*module.functions.get(index as usize)? as usize] } - TypesKind::Component(component) => component.functions.get(index as usize)?, + TypesKind::Component(component) => component.core_funcs.get(index as usize)?, }; match &self.types[*id] { - TypeDef::Func(ty) => Some(ty), + Type::Func(ty) => Some(ty), _ => None, } } - /// Gets the type of a component function at the given function index. - /// - /// Returns `None` if the index is out of bounds or if the function at - /// the given index is not a component function type. - pub fn component_function_at(&self, index: u32) -> Option<&ComponentFuncType> { - match &self.kind { - TypesKind::Module(_) => None, - TypesKind::Component(component) => { - let id = component.functions.get(index as usize)?; - match &self.types[*id] { - TypeDef::ComponentFunc(ty) => Some(ty), - _ => None, - } - } - } - } - - /// Gets the count of imported and defined functions. + /// Gets the count of imported and defined core functions. /// - /// The count also includes aliased functions in components. + /// The count also includes aliased core functions in components. pub fn function_count(&self) -> usize { match &self.kind { TypesKind::Module(module) => module.functions.len(), - TypesKind::Component(component) => component.functions.len(), + TypesKind::Component(component) => component.core_funcs.len(), } } /// Gets the type of an element segment at the given element segment index. /// /// Returns `None` if the index is out of bounds. - pub fn element_at(&self, index: u32) -> Option { + pub fn element_at(&self, index: u32) -> Option { match &self.kind { TypesKind::Module(module) => module.element_types.get(index as usize).copied(), TypesKind::Component(_) => None, @@ -1167,82 +1169,114 @@ impl Types { } } - /// Gets the type of a module at the given module index. + /// Gets the type of a component function at the given function index. /// /// Returns `None` if the index is out of bounds. - pub fn module_at(&self, index: u32) -> Option<&ModuleType> { + pub fn component_function_at(&self, index: u32) -> Option<&ComponentFuncType> { match &self.kind { TypesKind::Module(_) => None, - TypesKind::Component(component) => { - Some(self.types[*component.modules.get(index as usize)?].unwrap_module_type()) - } + TypesKind::Component(component) => Some( + self.types[*component.funcs.get(index as usize)?] + .as_component_func_type() + .unwrap(), + ), } } - /// Gets the count of imported, exported, or aliased modules. - pub fn module_count(&self) -> usize { + /// Gets the count of imported, exported, or aliased component functions. + pub fn component_function_count(&self) -> usize { match &self.kind { TypesKind::Module(_) => 0, - TypesKind::Component(component) => component.modules.len(), + TypesKind::Component(component) => component.funcs.len(), } } - /// Gets the type of a component at the given component index. + /// Gets the type of a module at the given module index. /// /// Returns `None` if the index is out of bounds. - pub fn component_at(&self, index: u32) -> Option<&ComponentType> { + pub fn module_at(&self, index: u32) -> Option<&ModuleType> { match &self.kind { TypesKind::Module(_) => None, - TypesKind::Component(component) => { - Some(self.types[*component.components.get(index as usize)?].unwrap_component_type()) - } + TypesKind::Component(component) => Some( + self.types[*component.core_modules.get(index as usize)?] + .as_module_type() + .unwrap(), + ), } } - /// Gets the count of imported, exported, or aliased components. - pub fn component_count(&self) -> usize { + /// Gets the count of imported, exported, or aliased modules. + pub fn module_count(&self) -> usize { match &self.kind { TypesKind::Module(_) => 0, - TypesKind::Component(component) => component.components.len(), + TypesKind::Component(component) => component.core_modules.len(), } } - /// Gets the type of an instance at the given instance index. + /// Gets the type of a module instance at the given module instance index. /// - /// Returns `None` if the index is out of bounds or if the instance is not - /// a component instance. + /// Returns `None` if the index is out of bounds. pub fn instance_at(&self, index: u32) -> Option<&InstanceType> { match &self.kind { TypesKind::Module(_) => None, TypesKind::Component(component) => { - let id = component.instances.get(index as usize)?; + let id = component.core_instances.get(index as usize)?; match &self.types[*id] { - TypeDef::Instance(ty) => Some(ty), + Type::Instance(ty) => Some(ty), _ => None, } } } } - /// Gets the type of a core module instance at the given instance index. + /// Gets the count of imported, exported, or aliased core module instances. + pub fn instance_count(&self) -> usize { + match &self.kind { + TypesKind::Module(_) => 0, + TypesKind::Component(component) => component.core_instances.len(), + } + } + + /// Gets the type of a component at the given component index. /// - /// Returns `None` if the index is out of bounds or if the instance is not - /// a module instance. - pub fn module_instance_at(&self, index: u32) -> Option<&ModuleType> { + /// Returns `None` if the index is out of bounds. + pub fn component_at(&self, index: u32) -> Option<&ComponentType> { + match &self.kind { + TypesKind::Module(_) => None, + TypesKind::Component(component) => Some( + self.types[*component.components.get(index as usize)?] + .as_component_type() + .unwrap(), + ), + } + } + + /// Gets the count of imported, exported, or aliased components. + pub fn component_count(&self) -> usize { + match &self.kind { + TypesKind::Module(_) => 0, + TypesKind::Component(component) => component.components.len(), + } + } + + /// Gets the type of an component instance at the given component instance index. + /// + /// Returns `None` if the index is out of bounds. + pub fn component_instance_at(&self, index: u32) -> Option<&ComponentInstanceType> { match &self.kind { TypesKind::Module(_) => None, TypesKind::Component(component) => { let id = component.instances.get(index as usize)?; match &self.types[*id] { - TypeDef::Module(ty) => Some(ty), + Type::ComponentInstance(ty) => Some(ty), _ => None, } } } } - /// Gets the count of imported, exported, or aliased instances. - pub fn instance_count(&self) -> usize { + /// Gets the count of imported, exported, or aliased component instances. + pub fn component_instance_count(&self) -> usize { match &self.kind { TypesKind::Module(_) => 0, TypesKind::Component(component) => component.instances.len(), @@ -1252,7 +1286,7 @@ impl Types { /// Gets the type of a value at the given value index. /// /// Returns `None` if the index is out of bounds. - pub fn value_at(&self, index: u32) -> Option { + pub fn value_at(&self, index: u32) -> Option { match &self.kind { TypesKind::Module(_) => None, TypesKind::Component(component) => { @@ -1413,4 +1447,4 @@ impl Default for SnapshotList { } } -pub(crate) type TypeList = SnapshotList; +pub(crate) type TypeList = SnapshotList; diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index f948d8878d..3333b11ea5 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -46,10 +46,10 @@ pub struct Printer { group_lines: Vec, } -enum TypeDef<'a> { +enum Type<'a> { // A core function type. - // The inner type is `None` for core functions in a component's function - // index space. + // The value is `None` for lowered component function types as they're not + // needed currently. Func(Option), Module, // Stores a map between export name and index into the global type list. @@ -59,40 +59,22 @@ enum TypeDef<'a> { // The exports are a subset of those exports relevant to the printer's state. Instance(HashMap), ComponentFunc(ComponentFuncType<'a>), - Value, - Interface, + // A component defined type + Defined, } -#[derive(Debug, Clone, Copy)] -enum InstanceIndexType { - Module, - // Stores an index into the global type list. - // The expected type is an instance type (for imports or - // an instance from exported items) or a component type - // for component instantiations. - Component(usize), -} - -struct State { - encoding: Encoding, +#[derive(Default)] +struct CoreState { + types: Vec, // Stores indexes into global type list. + funcs: Vec, // Stores indexes into global type list (function type). memories: u32, tags: u32, globals: u32, tables: u32, labels: u32, - values: u32, modules: u32, - // Stores indexes into global type list. - types: Vec, - // Stores indexes into global type list (core or component function type). - functions: Vec, - instances: Vec, - // Stores indexes into global type list (component type). - components: Vec, - // Stores export names to index into global type list. - // This is populated only for components and only relevant exports are inserted. - exports: HashMap, - function_names: HashMap, + instances: u32, + func_names: HashMap, local_names: HashMap<(u32, u32), Naming>, label_names: HashMap<(u32, u32), Naming>, type_names: HashMap, @@ -102,47 +84,48 @@ struct State { element_names: HashMap, data_names: HashMap, module_names: HashMap, + instance_names: HashMap, +} + +#[derive(Default)] +struct ComponentState { + types: Vec, // Stores indexes into global type list. + funcs: Vec, // Stores indexes into global type list (component function type). + instances: Vec, // Stores indexes into global type list (instance or component type). + components: Vec, // Stores indexes into global type list (component type). + values: u32, + exports: HashMap, + type_names: HashMap, + func_names: HashMap, component_names: HashMap, instance_names: HashMap, value_names: HashMap, +} + +struct State { + encoding: Encoding, name: Option, + core: CoreState, + component: ComponentState, } impl State { fn new(encoding: Encoding) -> Self { Self { encoding, - memories: 0, - tags: 0, - globals: 0, - tables: 0, - labels: 0, - values: 0, - modules: 0, - types: Vec::new(), - functions: Vec::new(), - instances: Vec::new(), - components: Vec::new(), - exports: HashMap::new(), - function_names: HashMap::new(), - local_names: HashMap::new(), - label_names: HashMap::new(), - type_names: HashMap::new(), - table_names: HashMap::new(), - memory_names: HashMap::new(), - global_names: HashMap::new(), - element_names: HashMap::new(), - data_names: HashMap::new(), - module_names: HashMap::new(), - component_names: HashMap::new(), - instance_names: HashMap::new(), - value_names: HashMap::new(), name: None, + core: CoreState::default(), + component: ComponentState::default(), } } - fn export(&mut self, name: &str, ty: usize) -> Result<()> { - if self.exports.insert(name.to_string(), ty).is_some() { + fn add_component_export(&mut self, name: &str, ty: usize) -> Result<()> { + if self + .component + .exports + .insert(name.to_string(), ty) + .is_some() + { bail!( "duplicate export name `{}` in export or type definition", name @@ -152,60 +135,67 @@ impl State { Ok(()) } + fn core_ty(&self, index: u32) -> Result { + self.core + .types + .get(index as usize) + .copied() + .ok_or_else(|| anyhow!("type index {} out of bounds", index)) + } + fn ty(&self, index: u32) -> Result { - self.types + self.component + .types .get(index as usize) .copied() .ok_or_else(|| anyhow!("type index {} out of bounds", index)) } - fn function(&self, index: u32) -> Result { - self.functions + fn func(&self, index: u32) -> Result { + self.component + .funcs .get(index as usize) .copied() .ok_or_else(|| anyhow!("function index {} out of bounds", index)) } - fn instance(&self, index: u32) -> Result { - self.instances + fn instance(&self, index: u32) -> Result { + self.component + .instances .get(index as usize) .copied() .ok_or_else(|| anyhow!("instance index {} out of bounds", index)) } fn component(&self, index: u32) -> Result { - self.components + self.component + .components .get(index as usize) .copied() .ok_or_else(|| anyhow!("component index {} out of bounds", index)) } - fn instance_export(&self, types: &[TypeDef], instance: u32, name: &str) -> Result { - match self.instance(instance)? { - InstanceIndexType::Module => unreachable!(), - InstanceIndexType::Component(ty) => match &types[ty] { - TypeDef::Component(exports) | TypeDef::Instance(exports) => { - exports.get(name).copied().ok_or_else(|| { - anyhow!( - "no export named `{}` for instance with index {}", - name, - instance - ) - }) - } - _ => unreachable!(), - }, + fn component_instance_export( + &self, + types: &[Type], + instance_index: u32, + name: &str, + ) -> Result { + match &types[self.instance(instance_index)?] { + Type::Component(exports) | Type::Instance(exports) => { + exports.get(name).copied().ok_or_else(|| { + anyhow!( + "no export named `{}` for instance with index {}", + name, + instance_index + ) + }) + } + _ => unreachable!(), } } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum OuterAliasKind { - Type, - Module, - Component, -} - struct Naming { identifier: Option, name: String, @@ -308,7 +298,7 @@ impl Printer { fn ensure_module(states: &[State]) -> Result<()> { if !matches!(states.last().unwrap().encoding, Encoding::Module) { - bail!("unexpected section found when parsing a module"); + bail!("a module section was encountered when parsing a component"); } Ok(()) @@ -316,7 +306,7 @@ impl Printer { fn ensure_component(states: &[State]) -> Result<()> { if !matches!(states.last().unwrap().encoding, Encoding::Component) { - bail!("unexpected section found when parsing a component"); + bail!("a component section was encountered when parsing a module"); } Ok(()) @@ -353,12 +343,16 @@ impl Printer { match encoding { Encoding::Module => { states.push(State::new(Encoding::Module)); - self.start_group("module"); + if states.len() > 1 { + self.start_group("core module"); + } else { + self.start_group("module"); + } if states.len() > 1 { let parent = &states[states.len() - 2]; self.result.push(' '); - self.print_name(&parent.module_names, parent.modules)?; + self.print_name(&parent.core.module_names, parent.core.modules)?; } } Encoding::Component => { @@ -369,8 +363,8 @@ impl Printer { let parent = &states[states.len() - 2]; self.result.push(' '); self.print_name( - &parent.component_names, - parent.components.len() as u32, + &parent.component.component_names, + parent.component.components.len() as u32, )?; } } @@ -398,7 +392,6 @@ impl Printer { self.printers = printers; } Payload::TypeSection(s) => { - Self::ensure_module(&states)?; self.print_types(states.last_mut().unwrap(), &mut types, s)? } Payload::ImportSection(s) => { @@ -439,7 +432,7 @@ impl Printer { Self::ensure_module(&states)?; self.newline(); self.start_group("start "); - self.print_idx(&states.last().unwrap().function_names, func)?; + self.print_idx(&states.last().unwrap().core.func_names, func)?; self.end_group(); } Payload::ElementSection(s) => { @@ -463,18 +456,6 @@ impl Printer { self.print_data(states.last_mut().unwrap(), &types, s)?; } - Payload::ComponentTypeSection(s) => { - Self::ensure_component(&states)?; - self.print_component_types(&mut states, &mut types, s)?; - } - Payload::ComponentImportSection(s) => { - Self::ensure_component(&states)?; - self.print_component_imports(states.last_mut().unwrap(), &types, s)?; - } - Payload::ComponentFunctionSection(s) => { - Self::ensure_component(&states)?; - self.print_component_functions(states.last_mut().unwrap(), &mut types, s)?; - } Payload::ModuleSection { parser: inner, .. } => { Self::ensure_component(&states)?; expected = Some(Encoding::Module); @@ -482,6 +463,17 @@ impl Printer { parser = inner; self.newline(); } + Payload::InstanceSection(s) => { + Self::ensure_component(&states)?; + self.print_instances(states.last_mut().unwrap(), s)?; + } + Payload::AliasSection(s) => { + Self::ensure_component(&states)?; + self.print_aliases(states.last_mut().unwrap(), &mut types, s)?; + } + Payload::CoreTypeSection(s) => { + self.print_core_types(states.last_mut().unwrap(), &mut types, s)? + } Payload::ComponentSection { parser: inner, .. } => { Self::ensure_component(&states)?; expected = Some(Encoding::Component); @@ -489,21 +481,33 @@ impl Printer { parser = inner; self.newline(); } - Payload::InstanceSection(s) => { + Payload::ComponentInstanceSection(s) => { Self::ensure_component(&states)?; - self.print_instances(states.last_mut().unwrap(), &mut types, s)?; + self.print_component_instances(states.last_mut().unwrap(), &mut types, s)?; } - Payload::ComponentExportSection(s) => { + Payload::ComponentAliasSection(s) => { Self::ensure_component(&states)?; - self.print_component_exports(states.last_mut().unwrap(), s)?; + self.print_component_aliases(&mut states, &types, s)?; + } + Payload::ComponentTypeSection(s) => { + Self::ensure_component(&states)?; + self.print_component_types(&mut states, &mut types, s)?; + } + Payload::ComponentCanonicalSection(s) => { + Self::ensure_component(&states)?; + self.print_canonical_functions(states.last_mut().unwrap(), &mut types, s)?; } Payload::ComponentStartSection(s) => { Self::ensure_component(&states)?; self.print_component_start(states.last_mut().unwrap(), &types, s)?; } - Payload::AliasSection(s) => { + Payload::ComponentImportSection(s) => { Self::ensure_component(&states)?; - self.print_aliases(&mut states, &mut types, s)?; + self.print_component_imports(states.last_mut().unwrap(), &types, s)?; + } + Payload::ComponentExportSection(s) => { + Self::ensure_component(&states)?; + self.print_component_exports(states.last_mut().unwrap(), s)?; } Payload::End(_) => { @@ -513,11 +517,11 @@ impl Printer { if let Some(parent) = states.last_mut() { match state.encoding { Encoding::Module => { - parent.modules += 1; + parent.core.modules += 1; } Encoding::Component => { - parent.components.push(types.len()); - types.push(TypeDef::Component(state.exports)); + parent.component.components.push(types.len()); + types.push(Type::Component(state.component.exports)); } } parser = parsers.pop().unwrap(); @@ -591,71 +595,115 @@ impl Printer { let name = Naming::new(n.get_name()?, 0, "module", &mut HashSet::new()); state.name = Some(name); } - Name::Function(n) => name_map(&mut state.function_names, n, "func")?, - Name::Local(n) => indirect_name_map(&mut state.local_names, n, "local")?, - Name::Label(n) => indirect_name_map(&mut state.label_names, n, "label")?, - Name::Type(n) => name_map(&mut state.type_names, n, "type")?, - Name::Table(n) => name_map(&mut state.table_names, n, "table")?, - Name::Memory(n) => name_map(&mut state.memory_names, n, "memory")?, - Name::Global(n) => name_map(&mut state.global_names, n, "global")?, - Name::Element(n) => name_map(&mut state.element_names, n, "elem")?, - Name::Data(n) => name_map(&mut state.data_names, n, "data")?, + Name::Function(n) => name_map(&mut state.core.func_names, n, "func")?, + Name::Local(n) => indirect_name_map(&mut state.core.local_names, n, "local")?, + Name::Label(n) => indirect_name_map(&mut state.core.label_names, n, "label")?, + Name::Type(n) => name_map(&mut state.core.type_names, n, "type")?, + Name::Table(n) => name_map(&mut state.core.table_names, n, "table")?, + Name::Memory(n) => name_map(&mut state.core.memory_names, n, "memory")?, + Name::Global(n) => name_map(&mut state.core.global_names, n, "global")?, + Name::Element(n) => name_map(&mut state.core.element_names, n, "elem")?, + Name::Data(n) => name_map(&mut state.core.data_names, n, "data")?, Name::Unknown { .. } => (), } } Ok(()) } - fn print_type(&mut self, state: &State, ty: &wasmparser::TypeDef) -> Result<()> { + fn print_core_type( + &mut self, + state: &mut State, + types: &mut Vec, + ty: wasmparser::CoreType, + ) -> Result<()> { + self.start_group("core type "); + self.print_name(&state.core.type_names, state.core.types.len() as u32)?; + self.result.push(' '); + let ty = match ty { + wasmparser::CoreType::Func(ty) => { + self.start_group("func"); + self.print_func_type(state, &ty, None)?; + self.end_group(); + Type::Func(Some(ty)) + } + wasmparser::CoreType::Module(decls) => { + self.print_module_type(types, decls.into_vec())?; + Type::Module + } + }; + self.end_group(); // `core type` itself + + state.core.types.push(types.len()); + types.push(ty); + Ok(()) + } + + fn print_type( + &mut self, + state: &mut State, + types: &mut Vec, + ty: wasmparser::Type, + ) -> Result<()> { self.start_group("type "); - self.print_name(&state.type_names, state.types.len() as u32)?; + self.print_name(&state.core.type_names, state.core.types.len() as u32)?; self.result.push(' '); - match ty { - wasmparser::TypeDef::Func(ty) => { + let ty = match ty { + wasmparser::Type::Func(ty) => { self.start_group("func"); - self.print_func_type(state, ty, None)?; + self.print_func_type(state, &ty, None)?; + self.end_group(); + Type::Func(Some(ty)) } - } - self.end_group(); // inner type + }; self.end_group(); // `type` itself + + state.core.types.push(types.len()); + types.push(ty); + Ok(()) + } + + fn print_core_types( + &mut self, + state: &mut State, + types: &mut Vec, + parser: CoreTypeSectionReader<'_>, + ) -> Result<()> { + for ty in parser { + self.newline(); + self.print_core_type(state, types, ty?)?; + } + Ok(()) } fn print_types( &mut self, state: &mut State, - types: &mut Vec, + types: &mut Vec, parser: TypeSectionReader<'_>, ) -> Result<()> { for ty in parser { - let ty = ty?; self.newline(); - self.print_type(state, &ty)?; - match ty { - wasmparser::TypeDef::Func(ty) => { - state.types.push(types.len()); - types.push(TypeDef::Func(Some(ty))); - } - } + self.print_type(state, types, ty?)?; } Ok(()) } - fn print_functype_idx( + fn print_core_functype_idx( &mut self, state: &State, - types: &[TypeDef], + types: &[Type], idx: u32, always_print_type: bool, names_for: Option, ) -> Result> { if always_print_type { - self.print_type_ref(state, idx)?; + self.print_type_ref(state, idx, true)?; } - match &types[state.ty(idx)?] { - TypeDef::Func(Some(ty)) => self.print_func_type(state, ty, names_for).map(Some), + match &types[state.core_ty(idx)?] { + Type::Func(Some(ty)) => self.print_func_type(state, ty, names_for).map(Some), _ => unreachable!(), } } @@ -677,7 +725,7 @@ impl Printer { // we need to be careful to terminate previous param blocks and open // a new one if that's the case with a named parameter. for (i, param) in ty.params.iter().enumerate() { - let name = names_for.and_then(|n| state.local_names.get(&(n, i as u32))); + let name = names_for.and_then(|n| state.core.local_names.get(&(n, i as u32))); params.start_local(name, &mut self.result); self.print_valtype(*param)?; params.end_local(&mut self.result); @@ -694,23 +742,23 @@ impl Printer { Ok(ty.params.len() as u32) } - fn print_valtype(&mut self, ty: Type) -> Result<()> { + fn print_valtype(&mut self, ty: ValType) -> Result<()> { match ty { - Type::I32 => self.result.push_str("i32"), - Type::I64 => self.result.push_str("i64"), - Type::F32 => self.result.push_str("f32"), - Type::F64 => self.result.push_str("f64"), - Type::V128 => self.result.push_str("v128"), - Type::FuncRef => self.result.push_str("funcref"), - Type::ExternRef => self.result.push_str("externref"), + ValType::I32 => self.result.push_str("i32"), + ValType::I64 => self.result.push_str("i64"), + ValType::F32 => self.result.push_str("f32"), + ValType::F64 => self.result.push_str("f64"), + ValType::V128 => self.result.push_str("v128"), + ValType::FuncRef => self.result.push_str("funcref"), + ValType::ExternRef => self.result.push_str("externref"), } Ok(()) } - fn print_reftype(&mut self, ty: Type) -> Result<()> { + fn print_reftype(&mut self, ty: ValType) -> Result<()> { match ty { - Type::FuncRef => self.result.push_str("func"), - Type::ExternRef => self.result.push_str("extern"), + ValType::FuncRef => self.result.push_str("func"), + ValType::ExternRef => self.result.push_str("extern"), _ => bail!("invalid reference type {:?}", ty), } Ok(()) @@ -719,7 +767,7 @@ impl Printer { fn print_imports( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], parser: ImportSectionReader<'_>, ) -> Result<()> { for import in parser { @@ -728,18 +776,18 @@ impl Printer { self.print_import(state, types, &import, true)?; match import.ty { TypeRef::Func(index) => { - let ty = state.ty(index)?; + let ty = state.core_ty(index)?; match &types[ty] { - TypeDef::Func(_) => { - state.functions.push(ty); + Type::Func(_) => { + state.core.funcs.push(ty); } _ => bail!("index is not a function type"), } } - TypeRef::Table(_) => state.tables += 1, - TypeRef::Memory(_) => state.memories += 1, - TypeRef::Tag(_) => state.tags += 1, - TypeRef::Global(_) => state.globals += 1, + TypeRef::Table(_) => state.core.tables += 1, + TypeRef::Memory(_) => state.core.memories += 1, + TypeRef::Tag(_) => state.core.tags += 1, + TypeRef::Global(_) => state.core.globals += 1, } } Ok(()) @@ -748,7 +796,7 @@ impl Printer { fn print_import( &mut self, state: &State, - types: &[TypeDef], + types: &[Type], import: &Import<'_>, index: bool, ) -> Result<()> { @@ -765,24 +813,23 @@ impl Printer { fn print_import_ty( &mut self, state: &State, - types: &[TypeDef], + types: &[Type], ty: &TypeRef, index: bool, ) -> Result<()> { - use TypeRef::*; match ty { - Func(f) => { + TypeRef::Func(f) => { self.start_group("func"); if index { self.result.push(' '); - self.print_name(&state.function_names, state.functions.len() as u32)?; + self.print_name(&state.core.func_names, state.core.funcs.len() as u32)?; } - self.print_type_ref(state, *f)?; + self.print_type_ref(state, *f, true)?; } - Table(f) => self.print_table_type(state, f, index)?, - Memory(f) => self.print_memory_type(state, f, index)?, - Tag(f) => self.print_tag_type(state, types, f, index)?, - Global(f) => self.print_global_type(state, f, index)?, + TypeRef::Table(f) => self.print_table_type(state, f, index)?, + TypeRef::Memory(f) => self.print_memory_type(state, f, index)?, + TypeRef::Tag(f) => self.print_tag_type(state, types, f, index)?, + TypeRef::Global(f) => self.print_global_type(state, f, index)?, } self.end_group(); Ok(()) @@ -791,7 +838,7 @@ impl Printer { fn print_table_type(&mut self, state: &State, ty: &TableType, index: bool) -> Result<()> { self.start_group("table "); if index { - self.print_name(&state.table_names, state.tables)?; + self.print_name(&state.core.table_names, state.core.tables)?; self.result.push(' '); } self.print_limits(ty.initial, ty.maximum)?; @@ -803,7 +850,7 @@ impl Printer { fn print_memory_type(&mut self, state: &State, ty: &MemoryType, index: bool) -> Result<()> { self.start_group("memory "); if index { - self.print_name(&state.memory_names, state.memories)?; + self.print_name(&state.core.memory_names, state.core.memories)?; self.result.push(' '); } if ty.memory64 { @@ -819,15 +866,15 @@ impl Printer { fn print_tag_type( &mut self, state: &State, - types: &[TypeDef], + types: &[Type], ty: &TagType, index: bool, ) -> Result<()> { self.start_group("tag "); if index { - write!(self.result, "(;{};)", state.tags)?; + write!(self.result, "(;{};)", state.core.tags)?; } - self.print_functype_idx(state, types, ty.func_type_idx, true, None)?; + self.print_core_functype_idx(state, types, ty.func_type_idx, true, None)?; Ok(()) } @@ -845,7 +892,7 @@ impl Printer { fn print_global_type(&mut self, state: &State, ty: &GlobalType, index: bool) -> Result<()> { self.start_group("global "); if index { - self.print_name(&state.global_names, state.globals)?; + self.print_name(&state.core.global_names, state.core.globals)?; self.result.push(' '); } if ty.mutable { @@ -864,7 +911,7 @@ impl Printer { self.newline(); self.print_table_type(state, &table, true)?; self.end_group(); - state.tables += 1; + state.core.tables += 1; } Ok(()) } @@ -875,7 +922,7 @@ impl Printer { self.newline(); self.print_memory_type(state, &memory, true)?; self.end_group(); - state.memories += 1; + state.core.memories += 1; } Ok(()) } @@ -883,7 +930,7 @@ impl Printer { fn print_tags( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], parser: TagSectionReader<'_>, ) -> Result<()> { for tag in parser { @@ -891,7 +938,7 @@ impl Printer { self.newline(); self.print_tag_type(state, types, &tag, true)?; self.end_group(); - state.tags += 1; + state.core.tags += 1; } Ok(()) } @@ -899,7 +946,7 @@ impl Printer { fn print_globals( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], parser: GlobalSectionReader<'_>, ) -> Result<()> { for global in parser { @@ -909,7 +956,7 @@ impl Printer { self.result.push(' '); self.print_init_expr(state, types, &global.init_expr)?; self.end_group(); - state.globals += 1; + state.core.globals += 1; } Ok(()) } @@ -917,7 +964,7 @@ impl Printer { fn print_code( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], code: &[FunctionBody<'_>], mut funcs: FunctionSectionReader<'_>, ) -> Result<()> { @@ -928,10 +975,10 @@ impl Printer { let ty = funcs.read()?; self.newline(); self.start_group("func "); - let func_idx = state.functions.len() as u32; - self.print_name(&state.function_names, func_idx)?; + let func_idx = state.core.funcs.len() as u32; + self.print_name(&state.core.func_names, func_idx)?; let params = self - .print_functype_idx(state, types, ty, true, Some(func_idx))? + .print_core_functype_idx(state, types, ty, true, Some(func_idx))? .unwrap_or(0); let mut first = true; @@ -951,7 +998,7 @@ impl Printer { self.newline(); first = false; } - let name = state.local_names.get(&(func_idx, params + local_idx)); + let name = state.core.local_names.get(&(func_idx, params + local_idx)); locals.start_local(name, &mut self.result); self.print_valtype(ty)?; locals.end_local(&mut self.result); @@ -960,7 +1007,7 @@ impl Printer { } locals.finish(&mut self.result); - state.labels = 0; + state.core.labels = 0; let nesting_start = self.nesting; let mut reader = body.get_operators_reader()?; reader.allow_memarg64(true); @@ -1017,7 +1064,7 @@ impl Printer { self.end_group(); - state.functions.push(state.ty(ty)?); + state.core.funcs.push(state.core_ty(ty)?); } Ok(()) } @@ -1037,7 +1084,7 @@ impl Printer { fn print_operator( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], op: &Operator<'_>, nesting_start: u32, ) -> Result<()> { @@ -1109,7 +1156,7 @@ impl Printer { Return => self.result.push_str("return"), Call { function_index } => { self.result.push_str("call "); - self.print_idx(&state.function_names, *function_index)?; + self.print_idx(&state.core.func_names, *function_index)?; } CallIndirect { table_index, @@ -1119,21 +1166,21 @@ impl Printer { self.result.push_str("call_indirect"); if *table_index != 0 { self.result.push(' '); - self.print_idx(&state.table_names, *table_index)?; + self.print_idx(&state.core.table_names, *table_index)?; } - self.print_type_ref(state, *index)?; + self.print_type_ref(state, *index, true)?; } ReturnCall { function_index } => { self.result.push_str("return_call "); - self.print_idx(&state.function_names, *function_index)?; + self.print_idx(&state.core.func_names, *function_index)?; } ReturnCallIndirect { table_index, index } => { self.result.push_str("return_call_indirect"); if *table_index != 0 { self.result.push(' '); - self.print_idx(&state.table_names, *table_index)?; + self.print_idx(&state.core.table_names, *table_index)?; } - self.print_type_ref(state, *index)?; + self.print_type_ref(state, *index, true)?; } Delegate { relative_depth } => { @@ -1150,24 +1197,24 @@ impl Printer { } LocalGet { local_index } => { self.result.push_str("local.get "); - self.print_local_idx(state, state.functions.len() as u32, *local_index)?; + self.print_local_idx(state, state.core.funcs.len() as u32, *local_index)?; } LocalSet { local_index } => { self.result.push_str("local.set "); - self.print_local_idx(state, state.functions.len() as u32, *local_index)?; + self.print_local_idx(state, state.core.funcs.len() as u32, *local_index)?; } LocalTee { local_index } => { self.result.push_str("local.tee "); - self.print_local_idx(state, state.functions.len() as u32, *local_index)?; + self.print_local_idx(state, state.core.funcs.len() as u32, *local_index)?; } GlobalGet { global_index } => { self.result.push_str("global.get "); - self.print_idx(&state.global_names, *global_index)?; + self.print_idx(&state.core.global_names, *global_index)?; } GlobalSet { global_index } => { self.result.push_str("global.set "); - self.print_idx(&state.global_names, *global_index)?; + self.print_idx(&state.core.global_names, *global_index)?; } I32Load { memarg } => self.mem_instr(state, "i32.load", memarg, 4)?, @@ -1198,12 +1245,12 @@ impl Printer { MemorySize { mem: 0, .. } => self.result.push_str("memory.size"), MemorySize { mem, .. } => { self.result.push_str("memory.size "); - self.print_idx(&state.memory_names, *mem)?; + self.print_idx(&state.core.memory_names, *mem)?; } MemoryGrow { mem: 0, .. } => self.result.push_str("memory.grow"), MemoryGrow { mem, .. } => { self.result.push_str("memory.grow "); - self.print_idx(&state.memory_names, *mem)?; + self.print_idx(&state.core.memory_names, *mem)?; } I32Const { value } => write!(self.result, "i32.const {}", value)?, @@ -1224,7 +1271,7 @@ impl Printer { RefIsNull => self.result.push_str("ref.is_null"), RefFunc { function_index } => { self.result.push_str("ref.func "); - self.print_idx(&state.function_names, *function_index)?; + self.print_idx(&state.core.func_names, *function_index)?; } I32Eqz => self.result.push_str("i32.eqz"), @@ -1379,39 +1426,39 @@ impl Printer { MemoryInit { segment, mem } => { self.result.push_str("memory.init "); if *mem != 0 { - self.print_idx(&state.memory_names, *mem)?; + self.print_idx(&state.core.memory_names, *mem)?; self.result.push(' '); } - self.print_idx(&state.data_names, *segment)?; + self.print_idx(&state.core.data_names, *segment)?; } DataDrop { segment } => { self.result.push_str("data.drop "); - self.print_idx(&state.data_names, *segment)?; + self.print_idx(&state.core.data_names, *segment)?; } MemoryCopy { src: 0, dst: 0 } => self.result.push_str("memory.copy"), MemoryCopy { src, dst } => { self.result.push_str("memory.copy "); - self.print_idx(&state.memory_names, *dst)?; + self.print_idx(&state.core.memory_names, *dst)?; self.result.push(' '); - self.print_idx(&state.memory_names, *src)?; + self.print_idx(&state.core.memory_names, *src)?; } MemoryFill { mem: 0 } => self.result.push_str("memory.fill"), MemoryFill { mem } => { self.result.push_str("memory.fill "); - self.print_idx(&state.memory_names, *mem)?; + self.print_idx(&state.core.memory_names, *mem)?; } TableInit { table, segment } => { self.result.push_str("table.init "); if *table != 0 { - self.print_idx(&state.table_names, *table)?; + self.print_idx(&state.core.table_names, *table)?; self.result.push(' '); } - self.print_idx(&state.element_names, *segment)?; + self.print_idx(&state.core.element_names, *segment)?; } ElemDrop { segment } => { self.result.push_str("elem.drop "); - self.print_idx(&state.element_names, *segment)?; + self.print_idx(&state.core.element_names, *segment)?; } TableCopy { dst_table, @@ -1420,30 +1467,30 @@ impl Printer { self.result.push_str("table.copy"); if *dst_table != *src_table || *src_table != 0 { self.result.push(' '); - self.print_idx(&state.table_names, *dst_table)?; + self.print_idx(&state.core.table_names, *dst_table)?; self.result.push(' '); - self.print_idx(&state.table_names, *src_table)?; + self.print_idx(&state.core.table_names, *src_table)?; } } TableGet { table } => { self.result.push_str("table.get "); - self.print_idx(&state.table_names, *table)?; + self.print_idx(&state.core.table_names, *table)?; } TableSet { table } => { self.result.push_str("table.set "); - self.print_idx(&state.table_names, *table)?; + self.print_idx(&state.core.table_names, *table)?; } TableGrow { table } => { self.result.push_str("table.grow "); - self.print_idx(&state.table_names, *table)?; + self.print_idx(&state.core.table_names, *table)?; } TableSize { table } => { self.result.push_str("table.size "); - self.print_idx(&state.table_names, *table)?; + self.print_idx(&state.core.table_names, *table)?; } TableFill { table } => { self.result.push_str("table.fill "); - self.print_idx(&state.table_names, *table)?; + self.print_idx(&state.core.table_names, *table)?; } MemoryAtomicNotify { memarg } => { @@ -1957,8 +2004,8 @@ impl Printer { ) -> Result<()> { self.result.push_str(name); if memarg.memory != 0 { - self.result.push_str(" "); - self.print_idx(&state.memory_names, memarg.memory)?; + self.result.push(' '); + self.print_idx(&state.core.memory_names, memarg.memory)?; } if memarg.offset != 0 { write!(self.result, " offset={}", memarg.offset)?; @@ -1976,13 +2023,14 @@ impl Printer { fn print_blockty( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], ty: &BlockType, cur_depth: u32, ) -> Result<()> { if let Some(name) = state + .core .label_names - .get(&(state.functions.len() as u32, state.labels)) + .get(&(state.core.funcs.len() as u32, state.core.labels)) { self.result.push(' '); name.write(&mut self.result); @@ -1995,11 +2043,11 @@ impl Printer { self.result.push(')'); } BlockType::FuncType(idx) => { - self.print_functype_idx(state, types, *idx, false, None)?; + self.print_core_functype_idx(state, types, *idx, false, None)?; } } write!(self.result, " ;; label = @{}", cur_depth)?; - state.labels += 1; + state.core.labels += 1; Ok(()) } @@ -2015,29 +2063,29 @@ impl Printer { self.start_group("export "); self.print_str(export.name)?; self.result.push(' '); - self.print_external(state, export.kind, export.index)?; + self.print_external_kind(state, export.kind, export.index)?; self.end_group(); // export Ok(()) } - fn print_external(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> { + fn print_external_kind(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> { self.result.push('('); match kind { ExternalKind::Func => { self.result.push_str("func "); - self.print_idx(&state.function_names, index)?; + self.print_idx(&state.core.func_names, index)?; } ExternalKind::Table => { self.result.push_str("table "); - self.print_idx(&state.table_names, index)?; + self.print_idx(&state.core.table_names, index)?; } ExternalKind::Global => { self.result.push_str("global "); - self.print_idx(&state.global_names, index)?; + self.print_idx(&state.core.global_names, index)?; } ExternalKind::Memory => { self.result.push_str("memory "); - self.print_idx(&state.memory_names, index)?; + self.print_idx(&state.core.memory_names, index)?; } ExternalKind::Tag => write!(self.result, "tag {}", index)?, } @@ -2045,9 +2093,16 @@ impl Printer { Ok(()) } - fn print_type_ref(&mut self, state: &State, idx: u32) -> Result<()> { + fn print_type_ref(&mut self, state: &State, idx: u32, core: bool) -> Result<()> { self.result.push_str(" (type "); - self.print_idx(&state.type_names, idx)?; + self.print_idx( + if core { + &state.core.type_names + } else { + &state.component.type_names + }, + idx, + )?; self.result.push(')'); Ok(()) } @@ -2061,7 +2116,7 @@ impl Printer { } fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> { - match state.local_names.get(&(func, idx)) { + match state.core.local_names.get(&(func, idx)) { Some(name) => write!(self.result, "${}", name.identifier())?, None => write!(self.result, "{}", idx)?, } @@ -2071,7 +2126,7 @@ impl Printer { fn print_name(&mut self, names: &HashMap, cur_idx: u32) -> Result<()> { if let Some(name) = names.get(&cur_idx) { name.write(&mut self.result); - self.result.push_str(" "); + self.result.push(' '); } write!(self.result, "(;{};)", cur_idx)?; Ok(()) @@ -2080,14 +2135,14 @@ impl Printer { fn print_elems( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], data: ElementSectionReader, ) -> Result<()> { for (i, elem) in data.into_iter().enumerate() { let mut elem = elem?; self.newline(); self.start_group("elem "); - self.print_name(&state.element_names, i as u32)?; + self.print_name(&state.core.element_names, i as u32)?; match &mut elem.kind { ElementKind::Passive => {} ElementKind::Declared => write!(self.result, " declare")?, @@ -2097,7 +2152,7 @@ impl Printer { } => { if *table_index != 0 { self.result.push_str(" (table "); - self.print_idx(&state.table_names, *table_index)?; + self.print_idx(&state.core.table_names, *table_index)?; self.result.push(')'); } self.result.push(' '); @@ -2117,7 +2172,7 @@ impl Printer { ElementItem::Expr(expr) => { self.print_init_expr_sugar(state, types, &expr, "item")? } - ElementItem::Func(idx) => self.print_idx(&state.function_names, idx)?, + ElementItem::Func(idx) => self.print_idx(&state.core.func_names, idx)?, } } self.end_group(); @@ -2128,14 +2183,14 @@ impl Printer { fn print_data( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], data: DataSectionReader, ) -> Result<()> { for (i, data) in data.into_iter().enumerate() { let data = data?; self.newline(); self.start_group("data "); - self.print_name(&state.data_names, i as u32)?; + self.print_name(&state.core.data_names, i as u32)?; self.result.push(' '); match &data.kind { DataKind::Passive => {} @@ -2145,7 +2200,7 @@ impl Printer { } => { if *memory_index != 0 { self.result.push_str("(memory "); - self.print_idx(&state.memory_names, *memory_index)?; + self.print_idx(&state.core.memory_names, *memory_index)?; self.result.push_str(") "); } self.print_init_expr_sugar(state, types, init_expr, "offset")?; @@ -2164,7 +2219,7 @@ impl Printer { fn print_init_expr_sugar( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], expr: &InitExpr, explicit: &str, ) -> Result<()> { @@ -2206,7 +2261,7 @@ impl Printer { fn print_init_expr( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], expr: &InitExpr, ) -> Result<()> { for (i, op) in expr.get_operators_reader().into_iter().enumerate() { @@ -2223,29 +2278,29 @@ impl Printer { Ok(()) } - fn print_primitive_type(&mut self, ty: &PrimitiveInterfaceType) { + fn print_primitive_val_type(&mut self, ty: &PrimitiveValType) { match ty { - PrimitiveInterfaceType::Unit => self.result.push_str("unit"), - PrimitiveInterfaceType::Bool => self.result.push_str("bool"), - PrimitiveInterfaceType::S8 => self.result.push_str("s8"), - PrimitiveInterfaceType::U8 => self.result.push_str("u8"), - PrimitiveInterfaceType::S16 => self.result.push_str("s16"), - PrimitiveInterfaceType::U16 => self.result.push_str("u16"), - PrimitiveInterfaceType::S32 => self.result.push_str("s32"), - PrimitiveInterfaceType::U32 => self.result.push_str("u32"), - PrimitiveInterfaceType::S64 => self.result.push_str("s64"), - PrimitiveInterfaceType::U64 => self.result.push_str("u64"), - PrimitiveInterfaceType::Float32 => self.result.push_str("float32"), - PrimitiveInterfaceType::Float64 => self.result.push_str("float64"), - PrimitiveInterfaceType::Char => self.result.push_str("char"), - PrimitiveInterfaceType::String => self.result.push_str("string"), + PrimitiveValType::Unit => self.result.push_str("unit"), + PrimitiveValType::Bool => self.result.push_str("bool"), + PrimitiveValType::S8 => self.result.push_str("s8"), + PrimitiveValType::U8 => self.result.push_str("u8"), + PrimitiveValType::S16 => self.result.push_str("s16"), + PrimitiveValType::U16 => self.result.push_str("u16"), + PrimitiveValType::S32 => self.result.push_str("s32"), + PrimitiveValType::U32 => self.result.push_str("u32"), + PrimitiveValType::S64 => self.result.push_str("s64"), + PrimitiveValType::U64 => self.result.push_str("u64"), + PrimitiveValType::Float32 => self.result.push_str("float32"), + PrimitiveValType::Float64 => self.result.push_str("float64"), + PrimitiveValType::Char => self.result.push_str("char"), + PrimitiveValType::String => self.result.push_str("string"), } } fn print_record_type( &mut self, state: &State, - fields: &[(&str, InterfaceTypeRef)], + fields: &[(&str, ComponentValType)], ) -> Result<()> { self.start_group("record"); for (name, ty) in fields.iter() { @@ -2253,7 +2308,7 @@ impl Printer { self.start_group("field "); self.print_str(name)?; self.result.push(' '); - self.print_interface_type_ref(state, ty)?; + self.print_component_val_type(state, ty)?; self.end_group() } self.end_group(); @@ -2262,24 +2317,21 @@ impl Printer { fn print_variant_type(&mut self, state: &State, cases: &[VariantCase]) -> Result<()> { self.start_group("variant"); - for case in cases.iter() { + for (i, case) in cases.iter().enumerate() { self.result.push(' '); self.start_group("case "); + // TODO: use the identifier from the name section when there is one + write!(&mut self.result, "$c{} ", i)?; self.print_str(case.name)?; self.result.push(' '); - self.print_interface_type_ref(state, &case.ty)?; - - if let Some(default) = case.default_to { - match cases.get(default as usize) { - Some(default) => { - self.start_group("defaults-to "); - self.print_str(default.name)?; - self.end_group(); - } - None => { - bail!("variant case default index out of bounds"); - } - } + self.print_component_val_type(state, &case.ty)?; + + if let Some(refines) = case.refines { + self.result.push(' '); + self.start_group("refines "); + // TODO: use the identifier from the name section when there is one + write!(&mut self.result, "$c{}", refines)?; + self.end_group(); } self.end_group() } @@ -2288,9 +2340,9 @@ impl Printer { Ok(()) } - fn print_list_type(&mut self, state: &State, element_ty: &InterfaceTypeRef) -> Result<()> { + fn print_list_type(&mut self, state: &State, element_ty: &ComponentValType) -> Result<()> { self.start_group("list "); - self.print_interface_type_ref(state, element_ty)?; + self.print_component_val_type(state, element_ty)?; self.end_group(); Ok(()) } @@ -2299,12 +2351,12 @@ impl Printer { &mut self, ty: &str, state: &State, - tys: &[InterfaceTypeRef], + tys: &[ComponentValType], ) -> Result<()> { self.start_group(ty); for ty in tys { self.result.push(' '); - self.print_interface_type_ref(state, ty)?; + self.print_component_val_type(state, ty)?; } self.end_group(); Ok(()) @@ -2320,9 +2372,9 @@ impl Printer { Ok(()) } - fn print_option_type(&mut self, state: &State, inner: &InterfaceTypeRef) -> Result<()> { + fn print_option_type(&mut self, state: &State, inner: &ComponentValType) -> Result<()> { self.start_group("option "); - self.print_interface_type_ref(state, inner)?; + self.print_component_val_type(state, inner)?; self.end_group(); Ok(()) } @@ -2330,76 +2382,71 @@ impl Printer { fn print_expected_type( &mut self, state: &State, - ok: &InterfaceTypeRef, - error: &InterfaceTypeRef, + ok: &ComponentValType, + error: &ComponentValType, ) -> Result<()> { self.start_group("expected "); - self.print_interface_type_ref(state, ok)?; + self.print_component_val_type(state, ok)?; self.result.push(' '); - self.print_interface_type_ref(state, error)?; - self.end_group(); - Ok(()) - } - - fn print_value_type(&mut self, state: &State, ty: &InterfaceTypeRef) -> Result<()> { - self.start_group("value "); - self.print_interface_type_ref(state, ty)?; + self.print_component_val_type(state, error)?; self.end_group(); Ok(()) } - fn print_interface_type(&mut self, state: &State, ty: &InterfaceType) -> Result<()> { + fn print_defined_type(&mut self, state: &State, ty: &ComponentDefinedType) -> Result<()> { match ty { - InterfaceType::Primitive(ty) => self.print_primitive_type(ty), - InterfaceType::Record(fields) => self.print_record_type(state, fields)?, - InterfaceType::Variant(cases) => self.print_variant_type(state, cases)?, - InterfaceType::List(ty) => self.print_list_type(state, ty)?, - InterfaceType::Tuple(tys) => self.print_tuple_or_union_type("tuple", state, tys)?, - InterfaceType::Flags(names) => self.print_flag_or_enum_type("flags", names)?, - InterfaceType::Enum(cases) => self.print_flag_or_enum_type("enum", cases)?, - InterfaceType::Union(tys) => self.print_tuple_or_union_type("union", state, tys)?, - InterfaceType::Option(ty) => self.print_option_type(state, ty)?, - InterfaceType::Expected { ok, error } => self.print_expected_type(state, ok, error)?, + ComponentDefinedType::Primitive(ty) => self.print_primitive_val_type(ty), + ComponentDefinedType::Record(fields) => self.print_record_type(state, fields)?, + ComponentDefinedType::Variant(cases) => self.print_variant_type(state, cases)?, + ComponentDefinedType::List(ty) => self.print_list_type(state, ty)?, + ComponentDefinedType::Tuple(tys) => { + self.print_tuple_or_union_type("tuple", state, tys)? + } + ComponentDefinedType::Flags(names) => self.print_flag_or_enum_type("flags", names)?, + ComponentDefinedType::Enum(cases) => self.print_flag_or_enum_type("enum", cases)?, + ComponentDefinedType::Union(tys) => { + self.print_tuple_or_union_type("union", state, tys)? + } + ComponentDefinedType::Option(ty) => self.print_option_type(state, ty)?, + ComponentDefinedType::Expected { ok, error } => { + self.print_expected_type(state, ok, error)? + } } Ok(()) } - fn print_interface_type_ref(&mut self, state: &State, ty: &InterfaceTypeRef) -> Result<()> { + fn print_component_val_type(&mut self, state: &State, ty: &ComponentValType) -> Result<()> { match ty { - InterfaceTypeRef::Primitive(ty) => self.print_primitive_type(ty), - InterfaceTypeRef::Type(idx) => { - self.print_idx(&state.type_names, *idx)?; + ComponentValType::Primitive(ty) => self.print_primitive_val_type(ty), + ComponentValType::Type(idx) => { + self.print_idx(&state.component.type_names, *idx)?; } } Ok(()) } - fn print_module_type(&mut self, types: &mut Vec, defs: Vec) -> Result<()> { + fn print_module_type( + &mut self, + types: &mut Vec, + decls: Vec, + ) -> Result<()> { let mut state = State::new(Encoding::Module); self.newline(); self.start_group("module"); - for def in defs { + for decl in decls { self.newline(); - match def { - ModuleType::Type(ty) => { - self.print_type(&state, &ty)?; - match ty { - wasmparser::TypeDef::Func(ty) => { - state.types.push(types.len()); - types.push(TypeDef::Func(Some(ty))); - } - } - } - ModuleType::Export { name, ty } => { + match decl { + ModuleTypeDeclaration::Type(ty) => self.print_type(&mut state, types, ty)?, + ModuleTypeDeclaration::Export { name, ty } => { self.start_group("export "); self.print_str(name)?; self.result.push(' '); self.print_import_ty(&state, types, &ty, false)?; self.end_group(); } - ModuleType::Import(import) => { + ModuleTypeDeclaration::Import(import) => { self.print_import(&state, types, &import, false)?; } } @@ -2411,54 +2458,102 @@ impl Printer { fn print_component_type<'a>( &mut self, states: &mut Vec, - types: &mut Vec>, - defs: Vec>, + types: &mut Vec>, + decls: Vec>, ) -> Result> { states.push(State::new(Encoding::Component)); self.newline(); self.start_group("component"); - for def in defs { + for decl in decls { self.newline(); - match def { - ComponentType::Type(ty) => self.print_component_typedef(states, types, ty)?, - ComponentType::OuterType { count, index } => { - self.print_outer_alias(states, OuterAliasKind::Type, count, index)? + match decl { + ComponentTypeDeclaration::CoreType(ty) => { + self.print_core_type(states.last_mut().unwrap(), types, ty)? } - ComponentType::Export { name, ty } => { - self.print_export_from_type(states.last_mut().unwrap(), types, name, ty)? + ComponentTypeDeclaration::Type(ty) => { + self.print_component_type_def(states, types, ty)? } - ComponentType::Import(import) => { - self.print_component_import(states.last_mut().unwrap(), types, &import)? + ComponentTypeDeclaration::Alias(alias) => match alias { + ComponentAlias::InstanceExport { .. } => { + bail!("component types cannot alias instance exports") + } + ComponentAlias::Outer { kind, count, index } => { + self.print_outer_alias(states, kind, count, index)? + } + }, + ComponentTypeDeclaration::Export { name, ty } => { + self.start_group("export "); + self.print_str(name)?; + self.result.push(' '); + self.print_component_import_ty(states.last().unwrap(), &ty, false)?; + self.end_group(); + match ty { + ComponentTypeRef::Func(idx) + | ComponentTypeRef::Instance(idx) + | ComponentTypeRef::Component(idx) => { + let state = states.last_mut().unwrap(); + let idx = state.ty(idx)?; + state.add_component_export(name, idx)?; + } + _ => {} + } + } + ComponentTypeDeclaration::Import(import) => { + self.print_component_import(states.last_mut().unwrap(), &import, false)? } } } self.end_group(); - Ok(states.pop().unwrap().exports) + Ok(states.pop().unwrap().component.exports) } fn print_instance_type<'a>( &mut self, states: &mut Vec, - types: &mut Vec>, - defs: Vec>, + types: &mut Vec>, + decls: Vec>, ) -> Result> { states.push(State::new(Encoding::Component)); self.newline(); self.start_group("instance"); - for def in defs { + for decl in decls { self.newline(); - match def { - InstanceType::Type(ty) => self.print_component_typedef(states, types, ty)?, - InstanceType::OuterType { count, index } => { - self.print_outer_alias(states, OuterAliasKind::Type, count, index)? + match decl { + InstanceTypeDeclaration::CoreType(ty) => { + self.print_core_type(states.last_mut().unwrap(), types, ty)? + } + InstanceTypeDeclaration::Type(ty) => { + self.print_component_type_def(states, types, ty)? } - InstanceType::Export { name, ty } => { - self.print_export_from_type(states.last_mut().unwrap(), types, name, ty)? + InstanceTypeDeclaration::Alias(alias) => match alias { + ComponentAlias::InstanceExport { .. } => { + bail!("instance types cannot alias instance exports") + } + ComponentAlias::Outer { kind, count, index } => { + self.print_outer_alias(states, kind, count, index)? + } + }, + InstanceTypeDeclaration::Export { name, ty } => { + self.start_group("export "); + self.print_str(name)?; + self.result.push(' '); + self.print_component_import_ty(states.last().unwrap(), &ty, false)?; + self.end_group(); + match ty { + ComponentTypeRef::Func(idx) + | ComponentTypeRef::Instance(idx) + | ComponentTypeRef::Component(idx) => { + let state = states.last_mut().unwrap(); + let idx = state.ty(idx)?; + state.add_component_export(name, idx)?; + } + _ => {} + } } } } self.end_group(); - Ok(states.pop().unwrap().exports) + Ok(states.pop().unwrap().component.exports) } fn outer_state(states: &[State], count: u32) -> Result<&State> { @@ -2473,7 +2568,7 @@ impl Printer { fn print_outer_alias( &mut self, states: &mut [State], - kind: OuterAliasKind, + kind: ComponentOuterAliasKind, count: u32, index: u32, ) -> Result<()> { @@ -2488,25 +2583,38 @@ impl Printer { } self.result.push(' '); let index = match kind { - OuterAliasKind::Type => { - self.print_idx(&outer.type_names, index)?; + ComponentOuterAliasKind::CoreModule => { + self.print_idx(&outer.core.module_names, index)?; self.result.push(' '); - self.start_group("type "); - self.print_name(&state.type_names, state.types.len() as u32)?; - Some(outer.ty(index)?) + self.start_group("core module "); + self.print_name(&state.core.module_names, state.core.modules)?; + None } - OuterAliasKind::Module => { - self.print_idx(&outer.module_names, index)?; + ComponentOuterAliasKind::CoreType => { + self.print_idx(&outer.core.type_names, index)?; self.result.push(' '); - self.start_group("module "); - self.print_name(&state.module_names, state.modules)?; - None + self.start_group("core type "); + self.print_name(&state.core.type_names, state.core.types.len() as u32)?; + Some(outer.core_ty(index)?) } - OuterAliasKind::Component => { - self.print_idx(&outer.component_names, index)?; + ComponentOuterAliasKind::Type => { + self.print_idx(&outer.component.type_names, index)?; + self.result.push(' '); + self.start_group("type "); + self.print_name( + &state.component.type_names, + state.component.types.len() as u32, + )?; + Some(outer.ty(index)?) + } + ComponentOuterAliasKind::Component => { + self.print_idx(&outer.component.component_names, index)?; self.result.push(' '); self.start_group("component "); - self.print_name(&state.component_names, state.components.len() as u32)?; + self.print_name( + &state.component.component_names, + state.component.components.len() as u32, + )?; Some(outer.component(index)?) } }; @@ -2517,48 +2625,15 @@ impl Printer { let state = states.last_mut().unwrap(); match kind { - OuterAliasKind::Type => state.types.push(index.unwrap()), - OuterAliasKind::Module => state.modules += 1, - OuterAliasKind::Component => state.components.push(index.unwrap()), + ComponentOuterAliasKind::CoreModule => state.core.modules += 1, + ComponentOuterAliasKind::CoreType => state.core.types.push(index.unwrap()), + ComponentOuterAliasKind::Type => state.component.types.push(index.unwrap()), + ComponentOuterAliasKind::Component => state.component.components.push(index.unwrap()), } Ok(()) } - fn print_export_from_type( - &mut self, - state: &mut State, - types: &[TypeDef], - name: &str, - ty: u32, - ) -> Result<()> { - self.start_group("export "); - self.print_str(name)?; - self.result.push(' '); - - let type_index = state.ty(ty)?; - let type_name = match types[type_index] { - TypeDef::Module => "module", - TypeDef::Component(_) => "component", - TypeDef::Instance(_) => "instance", - TypeDef::ComponentFunc(_) => "func", - TypeDef::Value => "value", - _ => bail!("invalid export type"), - }; - - self.start_group(type_name); - self.result.push(' '); - self.start_group("type "); - self.print_idx(&state.type_names, ty)?; - self.end_group(); // type - self.end_group(); // $type_name - self.end_group(); // export - - state.export(name, state.ty(ty)?)?; - - Ok(()) - } - fn print_component_func_type(&mut self, state: &State, ty: &ComponentFuncType) -> Result<()> { self.start_group("func"); for (name, ty) in ty.params.iter() { @@ -2568,17 +2643,17 @@ impl Printer { self.print_str(name)?; self.result.push(' '); } - self.print_interface_type_ref(state, ty)?; + self.print_component_val_type(state, ty)?; self.end_group() } if !matches!( ty.result, - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Unit) + ComponentValType::Primitive(PrimitiveValType::Unit) ) { self.result.push(' '); self.start_group("result "); - self.print_interface_type_ref(state, &ty.result)?; + self.print_component_val_type(state, &ty.result)?; self.end_group(); } @@ -2587,45 +2662,40 @@ impl Printer { Ok(()) } - fn print_component_typedef<'a>( + fn print_component_type_def<'a>( &mut self, states: &mut Vec, - types: &mut Vec>, - ty: ComponentTypeDef<'a>, + types: &mut Vec>, + ty: ComponentType<'a>, ) -> Result<()> { self.start_group("type "); { let state = states.last_mut().unwrap(); - self.print_name(&state.type_names, state.types.len() as u32)?; + self.print_name( + &state.component.type_names, + state.component.types.len() as u32, + )?; } self.result.push(' '); let ty = match ty { - ComponentTypeDef::Module(defs) => { - self.print_module_type(types, defs.into_vec())?; - TypeDef::Module - } - ComponentTypeDef::Component(defs) => { - TypeDef::Component(self.print_component_type(states, types, defs.into_vec())?) + ComponentType::Defined(ty) => { + self.print_defined_type(states.last_mut().unwrap(), &ty)?; + Type::Defined } - ComponentTypeDef::Instance(defs) => { - TypeDef::Instance(self.print_instance_type(states, types, defs.into_vec())?) - } - ComponentTypeDef::Function(ty) => { + ComponentType::Func(ty) => { self.print_component_func_type(states.last_mut().unwrap(), &ty)?; - TypeDef::ComponentFunc(ty) + Type::ComponentFunc(ty) } - ComponentTypeDef::Value(ty) => { - self.print_value_type(states.last_mut().unwrap(), &ty)?; - TypeDef::Value + ComponentType::Component(decls) => { + Type::Component(self.print_component_type(states, types, decls.into_vec())?) } - ComponentTypeDef::Interface(ty) => { - self.print_interface_type(states.last_mut().unwrap(), &ty)?; - TypeDef::Interface + ComponentType::Instance(decls) => { + Type::Instance(self.print_instance_type(states, types, decls.into_vec())?) } }; self.end_group(); - states.last_mut().unwrap().types.push(types.len()); + states.last_mut().unwrap().component.types.push(types.len()); types.push(ty); Ok(()) @@ -2634,13 +2704,13 @@ impl Printer { fn print_component_types<'a>( &mut self, states: &mut Vec, - types: &mut Vec>, + types: &mut Vec>, parser: ComponentTypeSectionReader<'a>, ) -> Result<()> { for ty in parser { let ty = ty?; self.newline(); - self.print_component_typedef(states, types, ty)?; + self.print_component_type_def(states, types, ty)?; } Ok(()) @@ -2649,13 +2719,49 @@ impl Printer { fn print_component_imports( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], parser: ComponentImportSectionReader, ) -> Result<()> { for import in parser { let import = import?; self.newline(); - self.print_component_import(state, types, &import)?; + self.print_component_import(state, &import, true)?; + match import.ty { + ComponentTypeRef::Module(_) => { + state.core.modules += 1; + } + ComponentTypeRef::Func(idx) => { + let ty = state.ty(idx)?; + match &types[ty] { + Type::ComponentFunc(_) => { + state.component.funcs.push(ty); + } + _ => bail!("index is not a function type"), + } + } + ComponentTypeRef::Value(_) => { + state.component.values += 1; + } + ComponentTypeRef::Type(_, _) => bail!("component type imports are not supported"), + ComponentTypeRef::Instance(idx) => { + let ty = state.ty(idx)?; + match &types[ty] { + Type::Instance(_) => { + state.component.instances.push(ty); + } + _ => bail!("index is not an instance type"), + } + } + ComponentTypeRef::Component(idx) => { + let ty = state.ty(idx)?; + match &types[ty] { + Type::Component(_) => { + state.component.components.push(ty); + } + _ => bail!("index is not an instance type"), + } + } + } } Ok(()) @@ -2664,57 +2770,87 @@ impl Printer { fn print_component_import( &mut self, state: &mut State, - types: &[TypeDef], import: &ComponentImport, + index: bool, ) -> Result<()> { self.start_group("import "); self.print_str(import.name)?; self.result.push(' '); + self.print_component_import_ty(state, &import.ty, index)?; + self.end_group(); + Ok(()) + } - let type_index = state.ty(import.ty)?; - match types[type_index] { - TypeDef::Module => { - self.start_group("module"); - self.result.push(' '); - self.print_name(&state.module_names, state.modules)?; - self.print_type_ref(state, import.ty)?; - state.modules += 1 + fn print_component_import_ty( + &mut self, + state: &State, + ty: &ComponentTypeRef, + index: bool, + ) -> Result<()> { + match ty { + ComponentTypeRef::Module(idx) => { + self.start_group("core module"); + if index { + self.result.push(' '); + self.print_name(&state.core.module_names, state.core.modules as u32)?; + } + self.print_type_ref(state, *idx, true)?; + self.end_group(); } - TypeDef::Component(_) => { - self.start_group("component"); - self.result.push(' '); - self.print_name(&state.component_names, state.components.len() as u32)?; - self.print_type_ref(state, import.ty)?; - state.components.push(type_index); + ComponentTypeRef::Func(idx) => { + self.start_group("func"); + if index { + self.result.push(' '); + self.print_name( + &state.component.func_names, + state.component.funcs.len() as u32, + )?; + } + self.print_type_ref(state, *idx, false)?; + self.end_group(); } - TypeDef::Instance(_) => { - self.start_group("instance"); - self.result.push(' '); - self.print_name(&state.instance_names, state.instances.len() as u32)?; - self.print_type_ref(state, import.ty)?; - state - .instances - .push(InstanceIndexType::Component(type_index)); + ComponentTypeRef::Value(ty) => { + self.start_group("value "); + if index { + self.print_name(&state.component.value_names, state.component.values as u32)?; + self.result.push(' '); + } + match ty { + ComponentValType::Primitive(ty) => self.print_primitive_val_type(ty), + ComponentValType::Type(idx) => { + self.print_type_ref(state, *idx, false)?; + } + } + self.end_group(); } - TypeDef::ComponentFunc(_) => { - self.start_group("func"); - self.result.push(' '); - self.print_name(&state.function_names, state.functions.len() as u32)?; - self.print_type_ref(state, import.ty)?; - state.functions.push(type_index); + ComponentTypeRef::Type(_, idx) => { + self.print_type_ref(state, *idx, false)?; } - TypeDef::Value => { - self.start_group("value"); - self.result.push(' '); - self.print_name(&state.value_names, state.values)?; - self.print_type_ref(state, import.ty)?; - state.values += 1 + ComponentTypeRef::Instance(idx) => { + self.start_group("instance"); + if index { + self.result.push(' '); + self.print_name( + &state.component.instance_names, + state.component.instances.len() as u32, + )?; + } + self.print_type_ref(state, *idx, false)?; + self.end_group(); + } + ComponentTypeRef::Component(idx) => { + self.start_group("component"); + if index { + self.result.push(' '); + self.print_name( + &state.component.component_names, + state.component.components.len() as u32, + )?; + } + self.print_type_ref(state, *idx, false)?; + self.end_group(); } - _ => bail!("invalid import type"), } - self.end_group(); // kind - self.end_group(); // import - Ok(()) } @@ -2729,16 +2865,14 @@ impl Printer { self.print_component_export(state, &export)?; match export.kind { - ComponentArgKind::Component(index) => { - state.export(export.name, state.component(index)?)? + ComponentExternalKind::Component => { + state.add_component_export(export.name, state.component(export.index)?)?; } - ComponentArgKind::Instance(index) => { - if let InstanceIndexType::Component(ty) = state.instance(index)? { - state.export(export.name, ty)?; - } + ComponentExternalKind::Instance => { + state.add_component_export(export.name, state.instance(export.index)?)?; } - ComponentArgKind::Function(index) => { - state.export(export.name, state.function(index)?)? + ComponentExternalKind::Func => { + state.add_component_export(export.name, state.func(export.index)?)?; } _ => {} } @@ -2754,45 +2888,44 @@ impl Printer { self.start_group("export "); self.print_str(export.name)?; self.result.push(' '); - self.print_component_export_kind(state, &export.kind)?; + self.print_component_external_kind(state, export.kind, export.index)?; self.end_group(); Ok(()) } - fn print_component_export_kind( + fn print_component_external_kind( &mut self, state: &State, - kind: &ComponentExportKind, + kind: ComponentExternalKind, + index: u32, ) -> Result<()> { match kind { - ComponentExportKind::Module(index) => { - self.start_group("module "); - self.print_idx(&state.module_names, *index)?; + ComponentExternalKind::Module => { + self.start_group("core module "); + self.print_idx(&state.core.module_names, index)?; } - ComponentExportKind::Component(index) => { + ComponentExternalKind::Component => { self.start_group("component "); - self.print_idx(&state.component_names, *index)?; + self.print_idx(&state.component.component_names, index)?; } - ComponentExportKind::Instance(index) => { + ComponentExternalKind::Instance => { self.start_group("instance "); - self.print_idx(&state.instance_names, *index)?; + self.print_idx(&state.component.instance_names, index)?; } - ComponentExportKind::Function(index) => { + ComponentExternalKind::Func => { self.start_group("func "); - self.print_idx(&state.function_names, *index)?; + self.print_idx(&state.component.func_names, index)?; } - ComponentExportKind::Value(index) => { + ComponentExternalKind::Value => { self.start_group("value "); - self.print_idx(&state.value_names, *index)?; + self.print_idx(&state.component.value_names, index)?; } - ComponentExportKind::Type(index) => { + ComponentExternalKind::Type => { self.start_group("type "); - self.print_idx(&state.type_names, *index)?; + self.print_idx(&state.component.type_names, index)?; } } - self.end_group(); - Ok(()) } @@ -2804,12 +2937,30 @@ impl Printer { for option in options { self.result.push(' '); match option { - CanonicalOption::UTF8 => self.result.push_str("string=utf8"), - CanonicalOption::UTF16 => self.result.push_str("string=utf16"), - CanonicalOption::CompactUTF16 => self.result.push_str("string=latin1+utf16"), - CanonicalOption::Into(index) => { - self.start_group("into "); - self.print_idx(&state.instance_names, *index)?; + CanonicalOption::UTF8 => self.result.push_str("string-encoding=utf8"), + CanonicalOption::UTF16 => self.result.push_str("string-encoding=utf16"), + CanonicalOption::CompactUTF16 => { + self.result.push_str("string-encoding=latin1+utf16") + } + CanonicalOption::Memory(idx) => { + self.start_group("memory "); + self.start_group("core memory "); + self.print_idx(&state.core.memory_names, *idx)?; + self.end_group(); + self.end_group(); + } + CanonicalOption::Realloc(idx) => { + self.start_group("realloc "); + self.start_group("core func "); + self.print_idx(&state.core.func_names, *idx)?; + self.end_group(); + self.end_group(); + } + CanonicalOption::PostReturn(idx) => { + self.start_group("post-return "); + self.start_group("core func "); + self.print_idx(&state.core.func_names, *idx)?; + self.end_group(); self.end_group(); } } @@ -2817,129 +2968,139 @@ impl Printer { Ok(()) } - fn print_component_functions( + fn print_canonical_functions( &mut self, state: &mut State, - types: &mut Vec, - parser: ComponentFunctionSectionReader, + types: &mut Vec, + parser: ComponentCanonicalSectionReader, ) -> Result<()> { for func in parser { self.newline(); - self.start_group("func "); - self.print_name(&state.function_names, state.functions.len() as u32)?; - self.result.push(' '); - match func? { - ComponentFunction::Lift { + CanonicalFunction::Lift { + core_func_index, type_index, - func_index, options, } => { - self.start_group("canon.lift "); + self.start_group("func "); + self.print_name( + &state.component.func_names, + state.component.funcs.len() as u32, + )?; + self.result.push(' '); self.start_group("type "); - self.print_idx(&state.type_names, type_index)?; + self.print_idx(&state.component.type_names, type_index)?; self.end_group(); - self.print_canonical_options(state, &options)?; self.result.push(' '); - self.start_group("func "); - self.print_idx(&state.function_names, func_index)?; + self.start_group("canon lift "); + self.start_group("core func "); + self.print_idx(&state.core.func_names, core_func_index)?; self.end_group(); - state.functions.push(state.ty(type_index)?); + self.print_canonical_options(state, &options)?; + self.end_group(); + self.end_group(); + state.component.funcs.push(state.ty(type_index)?); } - ComponentFunction::Lower { + CanonicalFunction::Lower { func_index, options, } => { - self.start_group("canon.lower"); - self.print_canonical_options(state, &options)?; + self.start_group("core func "); + self.print_name(&state.core.func_names, state.core.funcs.len() as u32)?; self.result.push(' '); + self.start_group("canon lower "); self.start_group("func "); - self.print_idx(&state.function_names, func_index)?; + self.print_idx(&state.component.func_names, func_index)?; + self.end_group(); + self.print_canonical_options(state, &options)?; + self.end_group(); self.end_group(); - state.functions.push(types.len()); // We don't actually care about core func types in components, so don't // bother lowering the component function type. - types.push(TypeDef::Func(None)); + state.core.funcs.push(types.len()); + types.push(Type::Func(None)); } } - self.end_group(); // canon.lift/canon.lower - self.end_group(); // func - self.newline(); } Ok(()) } - fn print_instances( - &mut self, - state: &mut State, - types: &mut Vec, - parser: InstanceSectionReader, - ) -> Result<()> { + fn print_instances(&mut self, state: &mut State, parser: InstanceSectionReader) -> Result<()> { for instance in parser { self.newline(); - self.start_group("instance "); - self.print_name(&state.instance_names, state.instances.len() as u32)?; + self.start_group("core instance "); + self.print_name(&state.core.instance_names, state.core.instances)?; + self.result.push(' '); match instance? { - Instance::Module { index, args } => { - self.result.push(' '); + Instance::Instantiate { module_index, args } => { self.start_group("instantiate "); - self.start_group("module "); - self.print_idx(&state.module_names, index)?; - self.end_group(); + self.print_idx(&state.core.module_names, module_index)?; for arg in args.iter() { self.newline(); - self.print_module_arg(state, arg)?; + self.print_instantiation_arg(state, arg)?; } self.end_group(); - - state.instances.push(InstanceIndexType::Module); + state.core.instances += 1; } - Instance::Component { index, args } => { + Instance::FromExports(exports) => { + for export in exports.iter() { + self.newline(); + self.print_export(state, export)?; + } + state.core.instances += 1; + } + } + self.end_group(); + } + Ok(()) + } + + fn print_component_instances( + &mut self, + state: &mut State, + types: &mut Vec, + parser: ComponentInstanceSectionReader, + ) -> Result<()> { + for instance in parser { + self.newline(); + self.start_group("instance "); + self.print_name( + &state.component.instance_names, + state.component.instances.len() as u32, + )?; + match instance? { + ComponentInstance::Instantiate { + component_index, + args, + } => { self.result.push(' '); self.start_group("instantiate "); - self.start_group("component "); - self.print_idx(&state.component_names, index)?; - self.end_group(); + self.print_idx(&state.component.component_names, component_index)?; for arg in args.iter() { self.newline(); - self.print_component_arg(state, arg)?; + self.print_component_instantiation_arg(state, arg)?; } self.end_group(); - state + .component .instances - .push(InstanceIndexType::Component(state.component(index)?)); + .push(state.component(component_index)?); } - Instance::ModuleFromExports(exports) => { - self.result.push_str(" core"); - for export in exports.iter() { - self.newline(); - self.print_export(state, export)?; - } - - state.instances.push(InstanceIndexType::Module); - } - Instance::ComponentFromExports(exports) => { + ComponentInstance::FromExports(exports) => { let mut type_exports = HashMap::new(); for export in exports.iter() { self.newline(); self.print_component_export(state, export)?; let existing = match export.kind { - ComponentArgKind::Component(index) => type_exports - .insert(export.name.to_string(), state.component(index)?), - ComponentArgKind::Instance(index) => type_exports.insert( - export.name.to_string(), - match state.instance(index)? { - InstanceIndexType::Module => continue, - InstanceIndexType::Component(index) => index, - }, - ), - ComponentArgKind::Function(index) => { - type_exports.insert(export.name.to_string(), state.function(index)?) - } + ComponentExternalKind::Component => type_exports + .insert(export.name.to_string(), state.component(export.index)?), + ComponentExternalKind::Instance => type_exports + .insert(export.name.to_string(), state.instance(export.index)?), + ComponentExternalKind::Func => type_exports + .insert(export.name.to_string(), state.func(export.index)?), _ => continue, }; @@ -2948,10 +3109,8 @@ impl Printer { } } - state - .instances - .push(InstanceIndexType::Component(types.len())); - types.push(TypeDef::Instance(type_exports)); + state.component.instances.push(types.len()); + types.push(Type::Instance(type_exports)); } } self.end_group(); @@ -2959,14 +3118,14 @@ impl Printer { Ok(()) } - fn print_module_arg(&mut self, state: &State, arg: &ModuleArg) -> Result<()> { + fn print_instantiation_arg(&mut self, state: &State, arg: &InstantiationArg) -> Result<()> { self.start_group("with "); self.print_str(arg.name)?; self.result.push(' '); match arg.kind { - ModuleArgKind::Instance(index) => { + InstantiationArgKind::Instance => { self.start_group("instance "); - self.print_idx(&state.instance_names, index)?; + self.print_idx(&state.core.instance_names, arg.index)?; self.end_group(); } } @@ -2974,11 +3133,15 @@ impl Printer { Ok(()) } - fn print_component_arg(&mut self, state: &State, arg: &ComponentArg) -> Result<()> { + fn print_component_instantiation_arg( + &mut self, + state: &State, + arg: &ComponentInstantiationArg, + ) -> Result<()> { self.start_group("with "); self.print_str(arg.name)?; self.result.push(' '); - self.print_component_export_kind(state, &arg.kind)?; + self.print_component_external_kind(state, arg.kind, arg.index)?; self.end_group(); Ok(()) } @@ -2986,14 +3149,14 @@ impl Printer { fn print_component_start( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], mut parser: ComponentStartSectionReader, ) -> Result<()> { let start = parser.read()?; - let ty = match state.functions.get(start.func_index as usize) { + let ty = match state.component.funcs.get(start.func_index as usize) { Some(type_index) => match &types[*type_index] { - TypeDef::ComponentFunc(ty) => ty, + Type::ComponentFunc(ty) => ty, _ => bail!( "start function index {} is not a component function", start.func_index @@ -3004,26 +3167,26 @@ impl Printer { } }; + self.newline(); self.start_group("start "); - self.start_group("func "); - self.print_idx(&state.function_names, start.func_index)?; - self.end_group(); + self.print_idx(&state.component.func_names, start.func_index)?; for arg in start.arguments.iter() { + self.result.push(' '); self.start_group("value "); - self.print_idx(&state.value_names, *arg)?; + self.print_idx(&state.component.value_names, *arg)?; self.end_group(); } if !matches!( ty.result, - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Unit) + ComponentValType::Primitive(PrimitiveValType::Unit) ) { self.result.push(' '); self.start_group("result "); - self.print_name(&state.value_names, state.values)?; + self.print_name(&state.component.value_names, state.component.values)?; self.end_group(); - state.values += 1; + state.component.values += 1; } self.end_group(); // start @@ -3031,157 +3194,176 @@ impl Printer { Ok(()) } - fn print_instance_export_alias( + fn print_aliases( &mut self, state: &mut State, - types: &mut Vec, - kind: AliasKind, - instance_idx: u32, - name: &str, + types: &mut Vec, + parser: AliasSectionReader, ) -> Result<()> { - self.start_group("alias export "); - self.print_idx(&state.instance_names, instance_idx)?; - self.result.push(' '); - self.print_str(name)?; - self.result.push(' '); - match kind { - AliasKind::Module => { - self.start_group("module "); - self.print_name(&state.module_names, state.modules)?; - self.end_group(); - state.modules += 1; - } - AliasKind::Component => { - self.start_group("component "); - self.print_name(&state.component_names, state.components.len() as u32)?; - self.end_group(); - - let ty = state.instance_export(types, instance_idx, name)?; - match types[ty] { - TypeDef::Component(_) => { - state.components.push(ty); - } - _ => { - bail!( - "export `{}` from instance {} is not a component", - name, - instance_idx - ); - } - } - } - AliasKind::Instance => { - self.start_group("instance "); - self.print_name(&state.instance_names, state.instances.len() as u32)?; - self.end_group(); - - let ty = state.instance_export(types, instance_idx, name)?; - match types[ty] { - TypeDef::Instance(_) => { - state.instances.push(InstanceIndexType::Component(ty)); - } - _ => { - bail!( - "export `{}` from instance {} is not an instance", - name, - instance_idx - ); - } - } - } - AliasKind::ComponentFunc => { - self.start_group("func "); - self.print_name(&state.function_names, state.functions.len() as u32)?; - self.end_group(); - - let ty = state.instance_export(types, instance_idx, name)?; - match types[ty] { - TypeDef::ComponentFunc(_) => { - state.functions.push(ty); - } - _ => { - bail!( - "export `{}` from instance {} is not a function", - name, - instance_idx - ); + for alias in parser { + self.newline(); + match alias? { + Alias::InstanceExport { + instance_index, + kind, + name, + } => { + self.start_group("core alias export "); + self.print_idx(&state.core.instance_names, instance_index)?; + self.result.push(' '); + self.print_str(name)?; + self.result.push(' '); + match kind { + ExternalKind::Func => { + self.start_group("func "); + self.print_name(&state.core.func_names, state.core.funcs.len() as u32)?; + self.end_group(); + state.core.funcs.push(types.len()); + types.push(Type::Func(None)); + } + ExternalKind::Table => { + self.start_group("table "); + self.print_name(&state.core.table_names, state.core.tables)?; + self.end_group(); + state.core.tables += 1; + } + ExternalKind::Memory => { + self.start_group("memory "); + self.print_name(&state.core.memory_names, state.core.memories)?; + self.end_group(); + state.core.memories += 1; + } + ExternalKind::Global => { + self.start_group("global "); + self.print_name(&state.core.global_names, state.core.globals)?; + self.end_group(); + state.core.globals += 1; + } + ExternalKind::Tag => { + self.start_group("tag "); + write!(self.result, "(;{};)", state.core.tags)?; + self.end_group(); + state.core.tags += 1; + } } + self.end_group(); // alias export } } - AliasKind::Value => { - self.start_group("value "); - self.print_name(&state.value_names, state.values)?; - self.end_group(); - state.values += 1; - } - AliasKind::Func => { - self.start_group("func "); - self.print_name(&state.function_names, state.functions.len() as u32)?; - self.end_group(); - state.functions.push(types.len()); - types.push(TypeDef::Func(None)); - } - AliasKind::Table => { - self.start_group("table "); - self.print_name(&state.table_names, state.tables)?; - self.end_group(); - state.tables += 1; - } - AliasKind::Memory => { - self.start_group("memory "); - self.print_name(&state.memory_names, state.memories)?; - self.end_group(); - state.memories += 1; - } - AliasKind::Global => { - self.start_group("global "); - self.print_name(&state.global_names, state.globals)?; - self.end_group(); - state.globals += 1; - } - AliasKind::Tag => { - self.start_group("tag "); - write!(self.result, "(;{};)", state.tags)?; - self.end_group(); - state.tags += 1; - } } - - self.end_group(); // alias export - Ok(()) } - fn print_aliases( + fn print_component_aliases( &mut self, states: &mut [State], - types: &mut Vec, - parser: AliasSectionReader, + types: &[Type], + parser: ComponentAliasSectionReader, ) -> Result<()> { for alias in parser { self.newline(); match alias? { - Alias::InstanceExport { + ComponentAlias::InstanceExport { kind, - instance, + instance_index, name, } => { - self.print_instance_export_alias( - states.last_mut().unwrap(), - types, - kind, - instance, - name, - )?; - } - Alias::OuterModule { count, index } => { - self.print_outer_alias(states, OuterAliasKind::Module, count, index)? - } - Alias::OuterComponent { count, index } => { - self.print_outer_alias(states, OuterAliasKind::Component, count, index)? + let state = states.last_mut().unwrap(); + self.start_group("alias export "); + self.print_idx(&state.component.instance_names, instance_index)?; + self.result.push(' '); + self.print_str(name)?; + self.result.push(' '); + match kind { + ComponentExternalKind::Module => { + self.start_group("core module "); + self.print_name(&state.core.module_names, state.core.modules)?; + self.end_group(); + state.core.modules += 1; + } + ComponentExternalKind::Component => { + self.start_group("component "); + self.print_name( + &state.component.component_names, + state.component.components.len() as u32, + )?; + self.end_group(); + + let ty = + state.component_instance_export(types, instance_index, name)?; + match types[ty] { + Type::Component(_) => { + state.component.components.push(ty); + } + _ => { + bail!( + "export `{}` from component instance {} is not a component", + name, + instance_index + ); + } + } + } + ComponentExternalKind::Instance => { + self.start_group("instance "); + self.print_name( + &state.component.instance_names, + state.component.instances.len() as u32, + )?; + self.end_group(); + + let ty = + state.component_instance_export(types, instance_index, name)?; + match types[ty] { + Type::Instance(_) => { + state.component.instances.push(ty); + } + _ => { + bail!( + "export `{}` from component instance {} is not an instance", + name, + instance_index + ); + } + } + } + ComponentExternalKind::Func => { + self.start_group("func "); + self.print_name( + &state.component.func_names, + state.component.funcs.len() as u32, + )?; + self.end_group(); + + let ty = + state.component_instance_export(types, instance_index, name)?; + match types[ty] { + Type::ComponentFunc(_) => { + state.component.funcs.push(ty); + } + _ => { + bail!( + "export `{}` from component instance {} is not a function", + name, + instance_index + ); + } + } + } + ComponentExternalKind::Value => { + self.start_group("value "); + self.print_name(&state.component.value_names, state.component.values)?; + self.end_group(); + state.component.values += 1; + } + ComponentExternalKind::Type => { + bail!("component export alias for types is not supported") + } + } + + self.end_group(); // alias export } - Alias::OuterType { count, index } => { - self.print_outer_alias(states, OuterAliasKind::Type, count, index)? + ComponentAlias::Outer { kind, count, index } => { + self.print_outer_alias(states, kind, count, index)? } } } diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 9aabb54c7d..cb8a5c874f 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -16,6 +16,7 @@ Customizable Rust parsers for the WebAssembly Text formats WAT and WAST leb128 = "0.2" unicode-width = "0.1.9" memchr = "2.4.1" +wasm-encoder = { version = "0.12.0", path = "../wasm-encoder" } [dev-dependencies] anyhow = "1.0" diff --git a/crates/wast/src/component/mod.rs b/crates/wast/src/component.rs similarity index 84% rename from crates/wast/src/component/mod.rs rename to crates/wast/src/component.rs index 0e381148b1..d8fd5a96ac 100644 --- a/crates/wast/src/component/mod.rs +++ b/crates/wast/src/component.rs @@ -1,28 +1,26 @@ //! Types and support for parsing the component model text format. mod alias; +mod binary; mod component; -mod deftype; +mod custom; +mod expand; mod export; mod func; mod import; mod instance; -mod intertype; mod item_ref; mod module; +mod resolve; mod types; + pub use self::alias::*; pub use self::component::*; -pub use self::deftype::*; +pub use self::custom::*; pub use self::export::*; pub use self::func::*; pub use self::import::*; pub use self::instance::*; -pub use self::intertype::*; pub use self::item_ref::*; pub use self::module::*; pub use self::types::*; - -mod binary; -mod expand; -mod resolve; diff --git a/crates/wast/src/component/alias.rs b/crates/wast/src/component/alias.rs index b065cbf4d3..86dfcc3313 100644 --- a/crates/wast/src/component/alias.rs +++ b/crates/wast/src/component/alias.rs @@ -1,10 +1,82 @@ -use crate::core; +use crate::core::ExportKind; use crate::kw; use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, Index, NameAnnotation, Span}; -/// An `alias` statement used to juggle indices with nested components. -#[derive(Debug, Clone)] +/// A inline alias for component exported items. +#[derive(Debug)] +pub struct InlineExportAlias<'a> { + /// The instance to alias the export from. + pub instance: Index<'a>, + /// The name of the export to alias. + pub name: &'a str, +} + +impl<'a> Parse<'a> for InlineExportAlias<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + parser.parse::()?; + let instance = parser.parse()?; + let name = parser.parse()?; + Ok(Self { instance, name }) + } +} + +/// An alias to a core item. +#[derive(Debug)] +pub struct CoreAlias<'a> { + /// Where this `core alias` was defined. + pub span: Span, + /// An identifier that this alias is resolved with (optionally) for name + /// resolution. + pub id: Option>, + /// An optional name for this alias stored in the custom `name` section. + pub name: Option>, + /// The target of the alias. + pub target: CoreAliasTarget<'a>, +} + +impl<'a> Parse<'a> for CoreAlias<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + parser.parse::()?; + + // Right now only export aliases are supported for core aliases. + parser.parse::()?; + + let instance = parser.parse()?; + let export_name = parser.parse()?; + let (kind, id, name) = parser.parens(|p| Ok((p.parse()?, p.parse()?, p.parse()?)))?; + + Ok(Self { + span, + target: CoreAliasTarget::Export { + instance, + name: export_name, + kind, + }, + id, + name, + }) + } +} + +/// The target of a core alias. +#[derive(Debug)] +pub enum CoreAliasTarget<'a> { + /// The alias is to an export of a core module instance. + Export { + /// The core module index exporting the item. + instance: Index<'a>, + /// The name of the exported item being aliased. + name: &'a str, + /// The export kind of the alias. + kind: ExportKind, + }, +} + +/// An alias to a component item. +#[derive(Debug)] pub struct Alias<'a> { /// Where this `alias` was defined. pub span: Span, @@ -15,94 +87,187 @@ pub struct Alias<'a> { pub name: Option>, /// The target of this alias. pub target: AliasTarget<'a>, - /// The kind of item that's being aliased. - pub kind: AliasKind, } -/// aliaskind ::= (module ?) -/// | (component ?) -/// | (instance ?) -/// | (func ?) -/// | (value ?) -/// | (type ?) -/// | (table ?) -/// | (memory ?) -/// | (global ?) -/// | ... other Post-MVP Core definition kinds -#[derive(Debug, Clone)] -#[allow(missing_docs)] -pub enum AliasKind { - Module, +impl<'a> Alias<'a> { + /// Parses only an outer type alias. + pub fn parse_outer_type_alias(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + parser.parse::()?; + let outer = parser.parse()?; + let index = parser.parse()?; + + let (kind, id, name) = parser.parens(|parser| { + let kind: ComponentOuterAliasKind = parser.parse()?; + match kind { + ComponentOuterAliasKind::CoreType | ComponentOuterAliasKind::Type => {} + _ => return Err(parser.error("expected core type or type for outer alias")), + } + + Ok((kind, parser.parse()?, parser.parse()?)) + })?; + + Ok(Self { + span, + target: AliasTarget::Outer { outer, index, kind }, + id, + name, + }) + } +} + +impl<'a> Parse<'a> for Alias<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + + let mut l = parser.lookahead1(); + + let (target, id, name) = if l.peek::() { + parser.parse::()?; + let outer = parser.parse()?; + let index = parser.parse()?; + let (kind, id, name) = + parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?; + + (AliasTarget::Outer { outer, index, kind }, id, name) + } else if l.peek::() { + parser.parse::()?; + let instance = parser.parse()?; + let export_name = parser.parse()?; + let (kind, id, name) = + parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?; + + ( + AliasTarget::Export { + instance, + name: export_name, + kind, + }, + id, + name, + ) + } else { + return Err(l.error()); + }; + + Ok(Self { + span, + target, + id, + name, + }) + } +} + +/// Represents the kind of instance export alias. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ComponentExportAliasKind { + /// The alias is to a core module export. + CoreModule, + /// The alias is to a function export. + Func, + /// The alias is to a value export. + Value, + /// The alias is to a type export. + Type, + /// The alias is to a component export. Component, + /// The alias is to an instance export. Instance, - Value, - ExportKind(core::ExportKind), } -impl<'a> Parse<'a> for AliasKind { +impl<'a> Parse<'a> for ComponentExportAliasKind { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - if l.peek::() { - let kind = parser.parse::()?; - Ok(AliasKind::ExportKind(kind)) - } else if l.peek::() { - parser.parse::()?; - Ok(AliasKind::Module) + if l.peek::() { + parser.parse::()?; + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(Self::CoreModule) + } else { + Err(l.error()) + } + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Func) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Value) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Type) } else if l.peek::() { parser.parse::()?; - Ok(AliasKind::Component) + Ok(Self::Component) } else if l.peek::() { parser.parse::()?; - Ok(AliasKind::Instance) - } else if l.peek::() { - parser.parse::()?; - Ok(AliasKind::Value) + Ok(Self::Instance) } else { Err(l.error()) } } } -/// aliastarget ::= export -/// | outer -#[derive(Debug, Clone)] -#[allow(missing_docs)] +/// Represents the kind of outer alias. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ComponentOuterAliasKind { + /// The alias is to an outer core module. + CoreModule, + /// The alias is to an outer core type. + CoreType, + /// The alias is to an outer type. + Type, + /// The alias is to an outer component. + Component, +} + +impl<'a> Parse<'a> for ComponentOuterAliasKind { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(Self::CoreModule) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::CoreType) + } else { + Err(l.error()) + } + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Type) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Component) + } else { + Err(l.error()) + } + } +} + +/// The target of a component alias. +#[derive(Debug)] pub enum AliasTarget<'a> { + /// The alias is to an export of a component instance. Export { + /// The component instance exporting the item. instance: Index<'a>, - export: &'a str, + /// The name of the exported item to alias. + name: &'a str, + /// The export kind of the alias. + kind: ComponentExportAliasKind, }, + /// The alias is to an item from an outer component. Outer { /// The number of enclosing components to skip. outer: Index<'a>, - /// An index into the target component's `aliaskind` index space. + /// The index of the item being aliased. index: Index<'a>, + /// The outer alias kind. + kind: ComponentOuterAliasKind, }, } - -impl<'a> Parse<'a> for Alias<'a> { - fn parse(parser: Parser<'a>) -> Result { - let span = parser.parse::()?.0; - let target = if parser.parse::>()?.is_some() { - AliasTarget::Outer { - outer: parser.parse()?, - index: parser.parse()?, - } - } else { - parser.parse::()?; - AliasTarget::Export { - instance: parser.parse::>()?, - export: parser.parse()?, - } - }; - let (kind, id, name) = parser.parens(|p| Ok((p.parse()?, p.parse()?, p.parse()?)))?; - - Ok(Alias { - span, - id, - name, - kind, - target, - }) - } -} diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 590e4db734..60ac5cf5ce 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -1,632 +1,798 @@ use crate::component::*; use crate::core; -use crate::encode::Encode; -use crate::token::{Id, NameAnnotation}; +use crate::token::{Id, Index, NameAnnotation}; +use wasm_encoder::{ + AliasSection, CanonicalFunctionSection, ComponentAliasSection, ComponentDefinedTypeEncoder, + ComponentExportSection, ComponentImportSection, ComponentInstanceSection, ComponentSection, + ComponentSectionId, ComponentStartSection, ComponentTypeEncoder, ComponentTypeSection, + CoreTypeEncoder, CoreTypeSection, InstanceSection, NestedComponentSection, RawSection, + SectionId, +}; pub fn encode(component: &Component<'_>) -> Vec { match &component.kind { - ComponentKind::Text(fields) => encode_fields(&component.id, &component.name, fields), - ComponentKind::Binary(bytes) => bytes.iter().flat_map(|b| b.iter().cloned()).collect(), + ComponentKind::Text(fields) => { + encode_fields(&component.id, &component.name, fields).finish() + } + ComponentKind::Binary(bytes) => bytes.iter().flat_map(|b| b.iter().copied()).collect(), } } fn encode_fields( - component_id: &Option>, - component_name: &Option>, + // TODO: use the id and name for a future names section + _component_id: &Option>, + _component_name: &Option>, fields: &[ComponentField<'_>], -) -> Vec { - let mut e = Encoder { - wasm: Vec::new(), - tmp: Vec::new(), - last_section: None, - last_section_contents: Vec::new(), - last_section_count: 0, - }; - e.wasm.extend(b"\0asm"); - e.wasm.extend(b"\x0a\0\x01\0"); +) -> wasm_encoder::Component { + let mut e = Encoder::default(); for field in fields { match field { - ComponentField::Type(i) => e.append(1, i), - ComponentField::Import(i) => e.append(2, i), - ComponentField::Func(i) => e.append(3, i), - ComponentField::Module(i) => e.section(4, i), - ComponentField::Component(i) => e.section(5, i), - ComponentField::Instance(i) => e.append(6, i), - ComponentField::Export(i) => e.append(7, i), - ComponentField::Start(i) => e.section(8, i), - ComponentField::Alias(i) => e.append(9, i), + ComponentField::CoreModule(m) => e.encode_core_module(m), + ComponentField::CoreInstance(i) => e.encode_core_instance(i), + ComponentField::CoreAlias(a) => e.encode_core_alias(a), + ComponentField::CoreType(t) => e.encode_core_type(t), + ComponentField::Component(c) => e.encode_component(c), + ComponentField::Instance(i) => e.encode_instance(i), + ComponentField::Alias(a) => e.encode_alias(a), + ComponentField::Type(t) => e.encode_type(t), + ComponentField::CanonicalFunc(f) => e.encode_canonical_func(f), + ComponentField::CoreFunc(_) | ComponentField::Func(_) => { + unreachable!("should be expanded already") + } + ComponentField::Start(s) => e.encode_start(s), + ComponentField::Import(i) => e.encode_import(i), + ComponentField::Export(ex) => e.encode_export(ex), + ComponentField::Custom(c) => e.encode_custom(c), } } // FIXME(WebAssembly/component-model#14): once a name section is defined it // should be encoded here. - drop((component_id, component_name)); - e.flush(); + e.flush(None); - return e.wasm; + e.component } -struct Encoder { - wasm: Vec, - tmp: Vec, - - last_section: Option, - last_section_contents: Vec, - last_section_count: usize, +fn encode_core_type(encoder: CoreTypeEncoder, ty: &CoreTypeDef) { + match ty { + CoreTypeDef::Def(core::TypeDef::Func(f)) => { + encoder.function( + f.params.iter().map(|(_, _, ty)| (*ty).into()), + f.results.iter().copied().map(Into::into), + ); + } + CoreTypeDef::Def(core::TypeDef::Struct(_)) | CoreTypeDef::Def(core::TypeDef::Array(_)) => { + todo!("encoding of GC proposal types not yet implemented") + } + CoreTypeDef::Module(t) => { + encoder.module(&t.into()); + } + } } -impl Encoder { - /// Appends an entire section represented by the `section` provided - fn section(&mut self, id: u8, section: &dyn Encode) { - self.flush(); - self.tmp.truncate(0); - section.encode(&mut self.tmp); - self.wasm.push(id); - self.tmp.encode(&mut self.wasm); - } - - /// Appends an `item` specified within the section `id` specified. - fn append(&mut self, id: u8, item: &dyn Encode) { - // Flush if necessary to start a new section - if self.last_section != Some(id) { - self.flush(); - } - // ... and afterwards start building up this section incrementally - // in case the next item encoded is also part of this section. - item.encode(&mut self.last_section_contents); - self.last_section_count += 1; - self.last_section = Some(id); - } - - fn flush(&mut self) { - let id = match self.last_section.take() { - Some(id) => id, - None => return, - }; - self.wasm.push(id); - self.tmp.truncate(0); - self.last_section_count.encode(&mut self.tmp); - self.last_section_count = 0; - self.tmp.extend(self.last_section_contents.drain(..)); - self.tmp.encode(&mut self.wasm); +fn encode_type(encoder: ComponentTypeEncoder, ty: &TypeDef) { + match ty { + TypeDef::Defined(t) => { + encode_defined_type(encoder.defined_type(), t); + } + TypeDef::Func(f) => { + encoder.function(f.params.iter().map(|p| (p.name, &p.ty)), &f.result); + } + TypeDef::Component(c) => { + encoder.component(&c.into()); + } + TypeDef::Instance(i) => { + encoder.instance(&i.into()); + } } } -impl Encode for NestedComponent<'_> { - fn encode(&self, e: &mut Vec) { - let fields = match &self.kind { - NestedComponentKind::Import { .. } => panic!("imports should be gone by now"), - NestedComponentKind::Inline(fields) => fields, - }; - e.extend(encode_fields(&self.id, &self.name, fields)); +fn encode_defined_type(encoder: ComponentDefinedTypeEncoder, ty: &ComponentDefinedType) { + match ty { + ComponentDefinedType::Primitive(p) => encoder.primitive((*p).into()), + ComponentDefinedType::Record(r) => { + encoder.record(r.fields.iter().map(|f| (f.name, &f.ty))); + } + ComponentDefinedType::Variant(v) => { + encoder.variant( + v.cases + .iter() + .map(|c| (c.name, &c.ty, c.refines.as_ref().map(Into::into))), + ); + } + ComponentDefinedType::List(l) => { + encoder.list(l.element.as_ref()); + } + ComponentDefinedType::Tuple(t) => { + encoder.tuple(t.fields.iter()); + } + ComponentDefinedType::Flags(f) => { + encoder.flags(f.names.iter().copied()); + } + ComponentDefinedType::Enum(e) => { + encoder.enum_type(e.names.iter().copied()); + } + ComponentDefinedType::Union(u) => encoder.union(u.types.iter()), + ComponentDefinedType::Option(o) => { + encoder.option(o.element.as_ref()); + } + ComponentDefinedType::Expected(e) => { + encoder.expected(e.ok.as_ref(), e.err.as_ref()); + } } } -impl Encode for Module<'_> { - fn encode(&self, e: &mut Vec) { - match &self.kind { - ModuleKind::Import { .. } => panic!("imports should be gone by now"), - ModuleKind::Inline { fields } => { - e.extend(crate::core::binary::encode(&self.id, &self.name, fields)); +#[derive(Default)] +struct Encoder { + component: wasm_encoder::Component, + current_section_id: Option, + + // Core sections + // Note: module sections are written immediately + core_instances: InstanceSection, + core_aliases: AliasSection, + core_types: CoreTypeSection, + + // Component sections + // Note: custom, component, start sections are written immediately + instances: ComponentInstanceSection, + aliases: ComponentAliasSection, + types: ComponentTypeSection, + funcs: CanonicalFunctionSection, + imports: ComponentImportSection, + exports: ComponentExportSection, +} + +impl Encoder { + fn encode_custom(&mut self, custom: &Custom) { + // Flush any in-progress section before encoding the customs section + self.flush(None); + self.component.section(custom); + } + + fn encode_core_module(&mut self, module: &CoreModule) { + // Flush any in-progress section before encoding the module + self.flush(None); + + match &module.kind { + CoreModuleKind::Import { .. } => unreachable!("should be expanded already"), + CoreModuleKind::Inline { fields } => { + // TODO: replace this with a wasm-encoder based encoding (should return `wasm_encoder::Module`) + let data = crate::core::binary::encode(&module.id, &module.name, fields); + self.component.section(&RawSection { + id: ComponentSectionId::CoreModule.into(), + data: &data, + }); } } } -} -impl Encode for Instance<'_> { - fn encode(&self, e: &mut Vec) { - match &self.kind { - InstanceKind::Module { module, args } => { - e.push(0x00); - e.push(0x00); - module.idx.encode(e); - args.encode(e); - } - InstanceKind::Component { component, args } => { - e.push(0x00); - e.push(0x01); - component.idx.encode(e); - args.encode(e); - } - InstanceKind::BundleOfComponentExports { args } => { - e.push(0x01); - args.encode(e); + fn encode_core_instance(&mut self, instance: &CoreInstance) { + match &instance.kind { + CoreInstanceKind::Instantiate { module, args } => { + self.core_instances.instantiate( + (*module).into(), + args.iter().map(|arg| (arg.name, (&arg.kind).into())), + ); } - InstanceKind::BundleOfExports { args } => { - e.push(0x02); - args.encode(e); + CoreInstanceKind::BundleOfExports(exports) => { + self.core_instances.export_items(exports.iter().map(|e| { + let (kind, index) = (&e.item).into(); + (e.name, kind, index) + })); } - InstanceKind::Import { .. } => unreachable!("should be removed during expansion"), } - } -} -impl Encode for NamedModuleArg<'_> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - e.push(0x02); - self.arg.encode(e); + self.flush(Some(self.core_instances.id())); } -} -impl Encode for ModuleArg<'_> { - fn encode(&self, e: &mut Vec) { - match self { - ModuleArg::Def(def) => { - def.idx.encode(e); - } - ModuleArg::BundleOfExports(..) => { - unreachable!("should be expanded already") + fn encode_core_alias(&mut self, alias: &CoreAlias) { + match &alias.target { + CoreAliasTarget::Export { + instance, + name, + kind, + } => { + self.core_aliases + .instance_export((*instance).into(), (*kind).into(), name); } } + + self.flush(Some(self.core_aliases.id())); } -} -impl Encode for NamedComponentArg<'_> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - self.arg.encode(e); + fn encode_core_type(&mut self, ty: &CoreType) { + encode_core_type(self.core_types.ty(), &ty.def); + self.flush(Some(self.core_types.id())); } -} -impl Encode for ComponentArg<'_> { - fn encode(&self, e: &mut Vec) { - match self { - ComponentArg::Def(def) => { - match def.kind { - DefTypeKind::Module => e.push(0x00), - DefTypeKind::Component => e.push(0x01), - DefTypeKind::Instance => e.push(0x02), - DefTypeKind::Func => e.push(0x03), - DefTypeKind::Value => e.push(0x04), - } - def.idx.encode(e); - } - ComponentArg::BundleOfExports(..) => { - unreachable!("should be expanded already") + fn encode_component(&mut self, component: &NestedComponent) { + // Flush any in-progress section before encoding the component + self.flush(None); + + match &component.kind { + NestedComponentKind::Import { .. } => unreachable!("should be expanded already"), + NestedComponentKind::Inline(fields) => { + self.component + .section(&NestedComponentSection(&encode_fields( + &component.id, + &component.name, + fields, + ))); } } } -} -impl Encode for Start<'_> { - fn encode(&self, e: &mut Vec) { - self.func.encode(e); - self.args.encode(e); + fn encode_instance(&mut self, instance: &Instance) { + match &instance.kind { + InstanceKind::Import { .. } => unreachable!("should be expanded already"), + InstanceKind::Instantiate { component, args } => { + self.instances.instantiate( + (*component).into(), + args.iter().map(|arg| { + let (kind, index) = (&arg.kind).into(); + (arg.name, kind, index) + }), + ); + } + InstanceKind::BundleOfExports(exports) => { + self.instances.export_items(exports.iter().map(|e| { + let (kind, index) = (&e.kind).into(); + (e.name, kind, index) + })); + } + } + + self.flush(Some(self.instances.id())); } -} -impl Encode for Alias<'_> { - fn encode(&self, e: &mut Vec) { - match self.target { - AliasTarget::Export { instance, export } => { - match self.kind { - AliasKind::Module => { - e.push(0x00); - e.push(0x00); - } - AliasKind::Component => { - e.push(0x00); - e.push(0x01); - } - AliasKind::Instance => { - e.push(0x00); - e.push(0x02); - } - AliasKind::Value => { - e.push(0x00); - e.push(0x04); - } - AliasKind::ExportKind(export_kind) => { - e.push(0x01); - export_kind.encode(e); - } - } - instance.encode(e); - export.encode(e); + fn encode_alias(&mut self, alias: &Alias) { + match &alias.target { + AliasTarget::Export { + instance, + name, + kind, + } => { + self.aliases + .instance_export((*instance).into(), (*kind).into(), name); } - AliasTarget::Outer { outer, index } => { - e.push(0x02); - match self.kind { - AliasKind::Module => e.push(0x00), - AliasKind::Component => e.push(0x01), - AliasKind::ExportKind(core::ExportKind::Type) => e.push(0x05), - // FIXME(#590): this feels a bit odd but it's also weird to - // make this an explicit error somewhere else. Should - // revisit this when the encodings of aliases and such have - // all settled down. Hopefully #590 and - // WebAssembly/component-model#29 will help solve this. - _ => e.push(0xff), - } - outer.encode(e); - index.encode(e); + AliasTarget::Outer { outer, index, kind } => { + self.aliases + .outer((*outer).into(), (*kind).into(), (*index).into()); } } - } -} -impl Encode for CanonLower<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x01); - self.opts.encode(e); - self.func.encode(e); + self.flush(Some(self.aliases.id())); } -} -impl Encode for CanonLift<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x00); - self.type_.encode(e); - self.opts.encode(e); - self.func.encode(e); - } -} + fn encode_start(&mut self, start: &Start) { + // Flush any in-progress section before encoding the start section + self.flush(None); -impl Encode for CanonOpt<'_> { - fn encode(&self, e: &mut Vec) { - match self { - CanonOpt::StringUtf8 => e.push(0x00), - CanonOpt::StringUtf16 => e.push(0x01), - CanonOpt::StringLatin1Utf16 => e.push(0x02), - CanonOpt::Into(index) => { - e.push(0x03); - index.encode(e); - } - } + self.component.section(&ComponentStartSection { + function_index: start.func.into(), + args: start.args.iter().map(|a| a.idx.into()).collect::>(), + }); } -} -impl Encode for ModuleType<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x4f); - self.defs.encode(e); + fn encode_type(&mut self, ty: &Type) { + encode_type(self.types.ty(), &ty.def); + self.flush(Some(self.types.id())); } -} -impl Encode for ModuleTypeDef<'_> { - fn encode(&self, e: &mut Vec) { - match self { - ModuleTypeDef::Type(f) => { - e.push(0x01); - f.encode(e); - } - ModuleTypeDef::Import(i) => { - e.push(0x02); - i.encode(e); + fn encode_canonical_func(&mut self, func: &CanonicalFunc) { + match &func.kind { + CanonicalFuncKind::Lift { ty, info } => { + self.funcs.lift( + info.func.idx.into(), + ty.into(), + info.opts.iter().map(Into::into), + ); } - ModuleTypeDef::Export(name, x) => { - e.push(0x07); - name.encode(e); - x.encode(e); + CanonicalFuncKind::Lower(info) => { + self.funcs + .lower(info.func.idx.into(), info.opts.iter().map(Into::into)); } } + + self.flush(Some(self.funcs.id())); } -} -impl Encode for ComponentType<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x4e); - self.fields.encode(e); + fn encode_import(&mut self, import: &ComponentImport) { + self.imports.import(import.name, (&import.item.kind).into()); + self.flush(Some(self.imports.id())); } -} -impl Encode for ComponentTypeField<'_> { - fn encode(&self, e: &mut Vec) { - match self { - ComponentTypeField::Type(ty_) => { - e.push(0x01); - ty_.encode(e); - } - ComponentTypeField::Alias(alias) => { - e.push(0x09); - alias.encode(e); - } - ComponentTypeField::Export(export) => { - e.push(0x07); - export.encode(e); - } - ComponentTypeField::Import(import) => { - e.push(0x02); - import.encode(e); + fn encode_export(&mut self, export: &ComponentExport) { + let (kind, index) = (&export.kind).into(); + self.exports.export(export.name, kind, index); + self.flush(Some(self.exports.id())); + } + + fn flush(&mut self, section_id: Option) { + if self.current_section_id == section_id { + return; + } + + if let Some(id) = self.current_section_id { + match id { + // 0 => custom sections are written immediately + // 1 => core modules sections are written immediately + 2 => { + assert_eq!(id, self.core_instances.id()); + self.component.section(&self.core_instances); + self.core_instances = Default::default(); + } + 3 => { + assert_eq!(id, self.core_aliases.id()); + self.component.section(&self.core_aliases); + self.core_aliases = Default::default(); + } + 4 => { + assert_eq!(id, self.core_types.id()); + self.component.section(&self.core_types); + self.core_types = Default::default(); + } + // 5 => components sections are written immediately + 6 => { + assert_eq!(id, self.instances.id()); + self.component.section(&self.instances); + self.instances = Default::default(); + } + 7 => { + assert_eq!(id, self.aliases.id()); + self.component.section(&self.aliases); + self.aliases = Default::default(); + } + 8 => { + assert_eq!(id, self.types.id()); + self.component.section(&self.types); + self.types = Default::default(); + } + 9 => { + assert_eq!(id, self.funcs.id()); + self.component.section(&self.funcs); + self.funcs = Default::default(); + } + // 10 => start sections are written immediately + 11 => { + assert_eq!(id, self.imports.id()); + self.component.section(&self.imports); + self.imports = Default::default(); + } + 12 => { + assert_eq!(id, self.exports.id()); + self.component.section(&self.exports); + self.exports = Default::default(); + } + _ => unreachable!("unknown incremental component section id: {}", id), } } - } -} -impl Encode for InstanceType<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x4d); - self.fields.encode(e); + self.current_section_id = section_id } } -impl Encode for InstanceTypeField<'_> { - fn encode(&self, e: &mut Vec) { - match self { - InstanceTypeField::Type(ty_) => { - e.push(0x01); - ty_.encode(e); - } - InstanceTypeField::Alias(alias) => { - e.push(0x09); - alias.encode(e); - } - InstanceTypeField::Export(export) => { - e.push(0x07); - export.encode(e); - } +// This implementation is much like `wasm_encoder::CustomSection`, except +// that it extends via a list of slices instead of a single slice. +impl wasm_encoder::Encode for Custom<'_> { + fn encode(&self, sink: &mut Vec) { + let mut buf = [0u8; 5]; + let encoded_name_len = + leb128::write::unsigned(&mut &mut buf[..], u64::try_from(self.name.len()).unwrap()) + .unwrap(); + let data_len = self.data.iter().fold(0, |acc, s| acc + s.len()); + + // name length + (encoded_name_len + self.name.len() + data_len).encode(sink); + + // name + self.name.encode(sink); + + // data + for s in &self.data { + sink.extend(*s); } } } -impl Encode for ComponentExportType<'_> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - self.item.encode(e); +impl wasm_encoder::ComponentSection for Custom<'_> { + fn id(&self) -> u8 { + SectionId::Custom.into() } } -impl Encode for TypeField<'_> { - fn encode(&self, e: &mut Vec) { - match &self.def { - ComponentTypeDef::DefType(d) => d.encode(e), - ComponentTypeDef::InterType(i) => i.encode(e), + +// TODO: move these core conversion functions to the core module +// once we update core encoding to use wasm-encoder. +impl From> for wasm_encoder::ValType { + fn from(ty: core::ValType) -> Self { + match ty { + core::ValType::I32 => Self::I32, + core::ValType::I64 => Self::I64, + core::ValType::F32 => Self::F32, + core::ValType::F64 => Self::F64, + core::ValType::V128 => Self::V128, + core::ValType::Ref(r) => r.into(), + core::ValType::Rtt(..) => { + todo!("encoding of GC proposal types not yet implemented") + } } } } -impl Encode for Primitive { - fn encode(&self, e: &mut Vec) { - match self { - Primitive::Unit => e.push(0x7f), - Primitive::Bool => e.push(0x7e), - Primitive::S8 => e.push(0x7d), - Primitive::U8 => e.push(0x7c), - Primitive::S16 => e.push(0x7b), - Primitive::U16 => e.push(0x7a), - Primitive::S32 => e.push(0x79), - Primitive::U32 => e.push(0x78), - Primitive::S64 => e.push(0x77), - Primitive::U64 => e.push(0x76), - Primitive::Float32 => e.push(0x75), - Primitive::Float64 => e.push(0x74), - Primitive::Char => e.push(0x73), - Primitive::String => e.push(0x72), +impl From> for wasm_encoder::ValType { + fn from(r: core::RefType<'_>) -> Self { + match r.heap { + core::HeapType::Func => Self::FuncRef, + core::HeapType::Extern => Self::ExternRef, + _ => { + todo!("encoding of GC proposal types not yet implemented") + } } } } -impl<'a> Encode for InterType<'a> { - fn encode(&self, e: &mut Vec) { - match self { - InterType::Primitive(p) => p.encode(e), - InterType::Record(r) => r.encode(e), - InterType::Variant(v) => v.encode(e), - InterType::List(l) => l.encode(e), - InterType::Tuple(t) => t.encode(e), - InterType::Flags(f) => f.encode(e), - InterType::Enum(n) => n.encode(e), - InterType::Union(u) => u.encode(e), - InterType::Option(o) => o.encode(e), - InterType::Expected(x) => x.encode(e), +impl From<&core::ItemKind<'_>> for wasm_encoder::EntityType { + fn from(kind: &core::ItemKind) -> Self { + match kind { + core::ItemKind::Func(t) => Self::Function(t.into()), + core::ItemKind::Table(t) => Self::Table((*t).into()), + core::ItemKind::Memory(t) => Self::Memory((*t).into()), + core::ItemKind::Global(t) => Self::Global((*t).into()), + core::ItemKind::Tag(t) => Self::Tag(t.into()), } } } -impl<'a> Encode for InterTypeRef<'a> { - fn encode(&self, e: &mut Vec) { - match self { - InterTypeRef::Primitive(p) => p.encode(e), - InterTypeRef::Ref(i) => i.encode(e), - InterTypeRef::Inline(_) => unreachable!("should be expanded by now"), +impl From> for wasm_encoder::TableType { + fn from(ty: core::TableType) -> Self { + Self { + element_type: ty.elem.into(), + minimum: ty.limits.min, + maximum: ty.limits.max, } } } -impl<'a> Encode for DefType<'a> { - fn encode(&self, e: &mut Vec) { - match self { - DefType::Func(f) => f.encode(e), - DefType::Module(m) => m.encode(e), - DefType::Component(c) => c.encode(e), - DefType::Instance(i) => i.encode(e), - DefType::Value(v) => v.encode(e), +impl From for wasm_encoder::MemoryType { + fn from(ty: core::MemoryType) -> Self { + let (minimum, maximum, memory64) = match ty { + core::MemoryType::B32 { limits, shared: _ } => { + (limits.min.into(), limits.max.map(Into::into), false) + } + core::MemoryType::B64 { limits, shared: _ } => (limits.min, limits.max, true), + }; + + Self { + minimum, + maximum, + memory64, } } } -impl<'a> Encode for Record<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x71); - self.fields.encode(e); +impl From> for wasm_encoder::GlobalType { + fn from(ty: core::GlobalType) -> Self { + Self { + val_type: ty.ty.into(), + mutable: ty.mutable, + } } } -impl<'a> Encode for Field<'a> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - self.type_.encode(e); +impl From<&core::TagType<'_>> for wasm_encoder::TagType { + fn from(ty: &core::TagType) -> Self { + match ty { + core::TagType::Exception(r) => Self { + kind: wasm_encoder::TagKind::Exception, + func_type_idx: r.into(), + }, + } } } -impl<'a> Encode for Variant<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x70); - self.cases.encode(e); +impl From<&core::TypeUse<'_, T>> for u32 { + fn from(u: &core::TypeUse<'_, T>) -> Self { + match &u.index { + Some(i) => (*i).into(), + None => unreachable!("unresolved type use in encoding: {:?}", u), + } } } -impl<'a> Encode for Case<'a> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - self.type_.encode(e); - if let Some(defaults_to) = self.defaults_to { - e.push(0x01); - defaults_to.encode(e); - } else { - e.push(0x00); +impl From<&CoreInstantiationArgKind<'_>> for wasm_encoder::ModuleArg { + fn from(kind: &CoreInstantiationArgKind) -> Self { + match kind { + CoreInstantiationArgKind::Instance(i) => { + wasm_encoder::ModuleArg::Instance(i.idx.into()) + } + CoreInstantiationArgKind::BundleOfExports(..) => { + unreachable!("should be expanded already") + } } } } -impl<'a> Encode for List<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x6f); - self.element.encode(e); +impl From<&CoreItemRef<'_, core::ExportKind>> for (wasm_encoder::ExportKind, u32) { + fn from(item: &CoreItemRef<'_, core::ExportKind>) -> Self { + match &item.kind { + core::ExportKind::Func => (wasm_encoder::ExportKind::Func, item.idx.into()), + core::ExportKind::Table => (wasm_encoder::ExportKind::Table, item.idx.into()), + core::ExportKind::Memory => (wasm_encoder::ExportKind::Memory, item.idx.into()), + core::ExportKind::Global => (wasm_encoder::ExportKind::Global, item.idx.into()), + core::ExportKind::Tag => (wasm_encoder::ExportKind::Tag, item.idx.into()), + } } } -impl<'a> Encode for Tuple<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x6e); - self.fields.encode(e); +impl From for wasm_encoder::ExportKind { + fn from(kind: core::ExportKind) -> Self { + match kind { + core::ExportKind::Func => Self::Func, + core::ExportKind::Table => Self::Table, + core::ExportKind::Memory => Self::Memory, + core::ExportKind::Global => Self::Global, + core::ExportKind::Tag => Self::Tag, + } } } -impl<'a> Encode for Flags<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x6d); - self.flag_names.encode(e); +impl From> for u32 { + fn from(i: Index<'_>) -> Self { + match i { + Index::Num(i, _) => i, + Index::Id(_) => unreachable!("unresolved index in encoding: {:?}", i), + } } } -impl<'a> Encode for Enum<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x6c); - self.arms.encode(e); +impl From<&CoreTypeUse<'_, T>> for u32 { + fn from(u: &CoreTypeUse<'_, T>) -> Self { + match u { + CoreTypeUse::Inline(_) => unreachable!("should be expanded already"), + CoreTypeUse::Ref(r) => r.idx.into(), + } } } -impl<'a> Encode for Union<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x6b); - self.arms.encode(e); +impl From<&ComponentTypeUse<'_, T>> for u32 { + fn from(u: &ComponentTypeUse<'_, T>) -> Self { + match u { + ComponentTypeUse::Inline(_) => unreachable!("should be expanded already"), + ComponentTypeUse::Ref(r) => r.idx.into(), + } } } -impl<'a> Encode for OptionType<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x6a); - self.element.encode(e); +impl From<&ComponentValType<'_>> for wasm_encoder::ComponentValType { + fn from(r: &ComponentValType) -> Self { + match r { + ComponentValType::Primitive(p) => Self::Primitive((*p).into()), + ComponentValType::Ref(i) => Self::Type(u32::from(*i)), + ComponentValType::Inline(_) => unreachable!("should be expanded by now"), + } } } -impl<'a> Encode for Expected<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x69); - self.ok.encode(e); - self.err.encode(e); +impl From for wasm_encoder::PrimitiveValType { + fn from(p: PrimitiveValType) -> Self { + match p { + PrimitiveValType::Unit => Self::Unit, + PrimitiveValType::Bool => Self::Bool, + PrimitiveValType::S8 => Self::S8, + PrimitiveValType::U8 => Self::U8, + PrimitiveValType::S16 => Self::S16, + PrimitiveValType::U16 => Self::U16, + PrimitiveValType::S32 => Self::S32, + PrimitiveValType::U32 => Self::U32, + PrimitiveValType::S64 => Self::S64, + PrimitiveValType::U64 => Self::U64, + PrimitiveValType::Float32 => Self::Float32, + PrimitiveValType::Float64 => Self::Float64, + PrimitiveValType::Char => Self::Char, + PrimitiveValType::String => Self::String, + } } } -impl<'a> Encode for ComponentFunctionType<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x4c); - self.params.encode(e); - self.result.encode(e); +impl From<&Refinement<'_>> for u32 { + fn from(r: &Refinement) -> Self { + match r { + Refinement::Index(..) => unreachable!("should be resolved by now"), + Refinement::Resolved(i) => *i, + } } } -impl<'a> Encode for ComponentFunctionParam<'a> { - fn encode(&self, e: &mut Vec) { - if let Some(id) = self.name { - e.push(0x01); - id.encode(e); - } else { - e.push(0x00); +impl From<&ItemSigKind<'_>> for wasm_encoder::ComponentTypeRef { + fn from(k: &ItemSigKind) -> Self { + match k { + ItemSigKind::Component(c) => Self::Component(c.into()), + ItemSigKind::CoreModule(m) => Self::Module(m.into()), + ItemSigKind::Instance(i) => Self::Instance(i.into()), + ItemSigKind::Value(v) => Self::Value(v.into()), + ItemSigKind::Func(f) => Self::Func(f.into()), + ItemSigKind::Type(TypeBounds::Eq(t)) => { + Self::Type(wasm_encoder::TypeBounds::Eq, (*t).into()) + } } - self.type_.encode(e); } } -impl<'a> Encode for ValueType<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x4b); - self.value_type.encode(e) - } -} +impl From<&ComponentType<'_>> for wasm_encoder::ComponentType { + fn from(ty: &ComponentType) -> Self { + let mut encoded = wasm_encoder::ComponentType::new(); -impl Encode for ComponentTypeUse<'_, T> { - fn encode(&self, e: &mut Vec) { - match self { - ComponentTypeUse::Inline(_) => unreachable!("should be expanded already"), - ComponentTypeUse::Ref(index) => index.encode(e), + for decl in &ty.decls { + match decl { + ComponentTypeDecl::CoreType(t) => { + encode_core_type(encoded.core_type(), &t.def); + } + ComponentTypeDecl::Type(t) => { + encode_type(encoded.ty(), &t.def); + } + ComponentTypeDecl::Alias(a) => match &a.target { + AliasTarget::Outer { + outer, + index, + kind: ComponentOuterAliasKind::CoreType, + } => { + encoded.alias_outer_core_type(u32::from(*outer), u32::from(*index)); + } + AliasTarget::Outer { + outer, + index, + kind: ComponentOuterAliasKind::Type, + } => { + encoded.alias_outer_type(u32::from(*outer), u32::from(*index)); + } + _ => unreachable!("only outer type aliases are supported"), + }, + ComponentTypeDecl::Import(i) => { + encoded.import(i.name, (&i.item.kind).into()); + } + ComponentTypeDecl::Export(e) => { + encoded.export(e.name, (&e.item.kind).into()); + } + } } + + encoded } } -impl Encode for ComponentExport<'_> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - match &self.arg { - ComponentArg::Def(item_ref) => { - match item_ref.kind { - DefTypeKind::Module => e.push(0x00), - DefTypeKind::Component => e.push(0x01), - DefTypeKind::Instance => e.push(0x02), - DefTypeKind::Func => e.push(0x03), - DefTypeKind::Value => e.push(0x04), +impl From<&InstanceType<'_>> for wasm_encoder::InstanceType { + fn from(ty: &InstanceType) -> Self { + let mut encoded = wasm_encoder::InstanceType::new(); + + for decl in &ty.decls { + match decl { + InstanceTypeDecl::CoreType(t) => { + encode_core_type(encoded.core_type(), &t.def); + } + InstanceTypeDecl::Type(t) => { + encode_type(encoded.ty(), &t.def); + } + InstanceTypeDecl::Alias(a) => match &a.target { + AliasTarget::Outer { + outer, + index, + kind: ComponentOuterAliasKind::CoreType, + } => { + encoded.alias_outer_core_type(u32::from(*outer), u32::from(*index)); + } + AliasTarget::Outer { + outer, + index, + kind: ComponentOuterAliasKind::Type, + } => { + encoded.alias_outer_type(u32::from(*outer), u32::from(*index)); + } + _ => unreachable!("only outer type aliases are supported"), + }, + InstanceTypeDecl::Export(e) => { + encoded.export(e.name, (&e.item.kind).into()); } - item_ref.idx.encode(e); - } - ComponentArg::BundleOfExports(..) => { - unreachable!("should be expanded already") } } + + encoded } } -impl Encode for ComponentFunc<'_> { - fn encode(&self, e: &mut Vec) { - match &self.kind { - ComponentFuncKind::Import { .. } => unreachable!("should be expanded by now"), - ComponentFuncKind::Inline { body } => { - body.encode(e); +impl From<&ModuleType<'_>> for wasm_encoder::ModuleType { + fn from(ty: &ModuleType) -> Self { + let mut encoded = wasm_encoder::ModuleType::new(); + + for decl in &ty.decls { + match decl { + ModuleTypeDecl::Type(t) => match &t.def { + core::TypeDef::Func(f) => encoded.ty().function( + f.params.iter().map(|(_, _, ty)| (*ty).into()), + f.results.iter().copied().map(Into::into), + ), + core::TypeDef::Struct(_) | core::TypeDef::Array(_) => { + todo!("encoding of GC proposal types not yet implemented") + } + }, + ModuleTypeDecl::Import(i) => { + encoded.import(i.module, i.field, (&i.item.kind).into()); + } + ModuleTypeDecl::Export(name, item) => { + encoded.export(name, (&item.kind).into()); + } } } + + encoded } } -impl Encode for ComponentFuncBody<'_> { - fn encode(&self, e: &mut Vec) { - match self { - ComponentFuncBody::CanonLift(lift) => lift.encode(e), - ComponentFuncBody::CanonLower(lower) => lower.encode(e), +impl From<&InstantiationArgKind<'_>> for (wasm_encoder::ComponentExportKind, u32) { + fn from(kind: &InstantiationArgKind) -> Self { + match kind { + InstantiationArgKind::Item(i) => i.into(), + InstantiationArgKind::BundleOfExports(..) => unreachable!("should be expanded already"), } } } -impl Encode for ComponentImport<'_> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - self.item.encode(e); +impl From<&ComponentExportKind<'_>> for (wasm_encoder::ComponentExportKind, u32) { + fn from(kind: &ComponentExportKind) -> Self { + match kind { + ComponentExportKind::CoreModule(m) => { + (wasm_encoder::ComponentExportKind::Module, m.idx.into()) + } + ComponentExportKind::Func(f) => (wasm_encoder::ComponentExportKind::Func, f.idx.into()), + ComponentExportKind::Value(v) => { + (wasm_encoder::ComponentExportKind::Value, v.idx.into()) + } + ComponentExportKind::Type(t) => (wasm_encoder::ComponentExportKind::Type, t.idx.into()), + ComponentExportKind::Component(c) => { + (wasm_encoder::ComponentExportKind::Component, c.idx.into()) + } + ComponentExportKind::Instance(i) => { + (wasm_encoder::ComponentExportKind::Instance, i.idx.into()) + } + } } } -impl Encode for ItemSig<'_> { - fn encode(&self, e: &mut Vec) { - match &self.kind { - ItemKind::Component(t) => t.encode(e), - ItemKind::Module(t) => t.encode(e), - ItemKind::Func(t) => t.encode(e), - ItemKind::Instance(t) => t.encode(e), - ItemKind::Value(t) => t.encode(e), +impl From for wasm_encoder::ComponentOuterAliasKind { + fn from(kind: ComponentOuterAliasKind) -> Self { + match kind { + ComponentOuterAliasKind::CoreModule => Self::CoreModule, + ComponentOuterAliasKind::CoreType => Self::CoreType, + ComponentOuterAliasKind::Type => Self::Type, + ComponentOuterAliasKind::Component => Self::Component, } } } -impl Encode for ItemRef<'_, K> { - fn encode(&self, dst: &mut Vec) { - assert!(self.export_names.is_empty()); - self.idx.encode(dst); +impl From for wasm_encoder::ComponentExportKind { + fn from(kind: ComponentExportAliasKind) -> Self { + match kind { + ComponentExportAliasKind::CoreModule => Self::Module, + ComponentExportAliasKind::Func => Self::Func, + ComponentExportAliasKind::Value => Self::Value, + ComponentExportAliasKind::Type => Self::Type, + ComponentExportAliasKind::Component => Self::Component, + ComponentExportAliasKind::Instance => Self::Instance, + } } } -impl Encode for CoreExport<'_> { - fn encode(&self, dst: &mut Vec) { - self.name.encode(dst); - self.index.kind.encode(dst); - self.index.encode(dst); +impl From<&CanonOpt<'_>> for wasm_encoder::CanonicalOption { + fn from(opt: &CanonOpt) -> Self { + match opt { + CanonOpt::StringUtf8 => Self::UTF8, + CanonOpt::StringUtf16 => Self::UTF16, + CanonOpt::StringLatin1Utf16 => Self::CompactUTF16, + CanonOpt::Memory(m) => Self::Memory(m.idx.into()), + CanonOpt::Realloc(f) => Self::Realloc(f.idx.into()), + CanonOpt::PostReturn(f) => Self::PostReturn(f.idx.into()), + } } } diff --git a/crates/wast/src/component/component.rs b/crates/wast/src/component/component.rs index 5212e99c93..3f319507a6 100644 --- a/crates/wast/src/component/component.rs +++ b/crates/wast/src/component/component.rs @@ -1,7 +1,9 @@ +use crate::annotation; use crate::component::*; use crate::core; use crate::kw; use crate::parser::{Parse, Parser, Result}; +use crate::token::Index; use crate::token::{Id, NameAnnotation, Span}; /// A parsed WebAssembly component module. @@ -135,15 +137,21 @@ impl<'a> Parse<'a> for Component<'a> { #[allow(missing_docs)] #[derive(Debug)] pub enum ComponentField<'a> { - Type(TypeField<'a>), - Import(ComponentImport<'a>), - Func(ComponentFunc<'a>), - Export(ComponentExport<'a>), - Start(Start<'a>), - Instance(Instance<'a>), - Module(Module<'a>), + CoreModule(CoreModule<'a>), + CoreInstance(CoreInstance<'a>), + CoreAlias(CoreAlias<'a>), + CoreType(CoreType<'a>), Component(NestedComponent<'a>), + Instance(Instance<'a>), Alias(Alias<'a>), + Type(Type<'a>), + CanonicalFunc(CanonicalFunc<'a>), + CoreFunc(CoreFunc<'a>), // Supports inverted forms of other items + Func(Func<'a>), // Supports inverted forms of other items + Start(Start<'a>), + Import(ComponentImport<'a>), + Export(ComponentExport<'a>), + Custom(Custom<'a>), } impl<'a> ComponentField<'a> { @@ -158,54 +166,60 @@ impl<'a> ComponentField<'a> { impl<'a> Parse<'a> for ComponentField<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - return Ok(ComponentField::Type(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Import(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Func(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Export(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Start(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Instance(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Module(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Component(parser.parse()?)); - } - if parser.peek::() { - return Ok(ComponentField::Alias(parser.parse()?)); + if parser.peek::() { + if parser.peek2::() { + return Ok(Self::CoreModule(parser.parse()?)); + } + if parser.peek2::() { + return Ok(Self::CoreInstance(parser.parse()?)); + } + if parser.peek2::() { + return Ok(Self::CoreAlias(parser.parse()?)); + } + if parser.peek2::() { + return Ok(Self::CoreType(parser.parse()?)); + } + if parser.peek2::() { + return Ok(Self::CoreFunc(parser.parse()?)); + } + } else { + if parser.peek::() { + return Ok(Self::Component(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Instance(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Alias(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Type(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Import(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Func(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Export(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Start(parser.parse()?)); + } + if parser.peek::() { + return Ok(Self::Custom(parser.parse()?)); + } } Err(parser.error("expected valid component field")) } } -impl<'a> From> for ComponentField<'a> { - fn from(field: TypeField<'a>) -> ComponentField<'a> { - ComponentField::Type(field) - } -} - -impl<'a> From> for ComponentField<'a> { - fn from(field: Alias<'a>) -> ComponentField<'a> { - ComponentField::Alias(field) - } -} - /// A function to call at instantiation time. #[derive(Debug)] pub struct Start<'a> { /// The function to call. - pub func: ItemRef<'a, kw::func>, + pub func: Index<'a>, /// The arguments to pass to the function. pub args: Vec>, /// Name of the result value. @@ -215,10 +229,10 @@ pub struct Start<'a> { impl<'a> Parse<'a> for Start<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; - let func = parser.parse::>()?.0; + let func = parser.parse()?; let mut args = Vec::new(); while !parser.is_empty() && !parser.peek2::() { - args.push(parser.parse()?); + args.push(parser.parens(|parser| parser.parse())?); } let result = if !parser.is_empty() { parser.parens(|parser| { @@ -240,7 +254,7 @@ impl<'a> Parse<'a> for Start<'a> { } } -/// A parsed WebAssembly component module. +/// A nested WebAssembly component. #[derive(Debug)] pub struct NestedComponent<'a> { /// Where this `component` was defined @@ -273,10 +287,7 @@ pub enum NestedComponentKind<'a> { impl<'a> Parse<'a> for NestedComponent<'a> { fn parse(parser: Parser<'a>) -> Result { - // See comments in `module.rs` for why this is tested here. - if parser.parens_depth() > 100 { - return Err(parser.error("component type nesting too deep")); - } + parser.depth_check()?; let span = parser.parse::()?.0; let id = parser.parse()?; diff --git a/crates/wast/src/component/custom.rs b/crates/wast/src/component/custom.rs new file mode 100644 index 0000000000..b17a7fafb4 --- /dev/null +++ b/crates/wast/src/component/custom.rs @@ -0,0 +1,28 @@ +use crate::annotation; +use crate::parser::{Parse, Parser, Result}; +use crate::token::Span; + +/// A custom section within a component. +#[derive(Debug)] +pub struct Custom<'a> { + /// Where this `@custom` was defined. + pub span: Span, + + /// Name of the custom section. + pub name: &'a str, + + /// Payload of this custom section. + pub data: Vec<&'a [u8]>, +} + +impl<'a> Parse<'a> for Custom<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let name = parser.parse()?; + let mut data = Vec::new(); + while !parser.is_empty() { + data.push(parser.parse()?); + } + Ok(Self { span, name, data }) + } +} diff --git a/crates/wast/src/component/deftype.rs b/crates/wast/src/component/deftype.rs deleted file mode 100644 index a7eb8c5eb8..0000000000 --- a/crates/wast/src/component/deftype.rs +++ /dev/null @@ -1,330 +0,0 @@ -//! The `deftype` production in the component-model AST, and its children. - -use crate::component::*; -use crate::core; -use crate::kw; -use crate::parser::{Cursor, Parse, Parser, Peek, Result}; - -/// Different kinds of elements that can be exported from a WebAssembly component, -/// contained in a [`ComponentExport`]. -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] -#[allow(missing_docs)] -pub enum DefTypeKind { - Func, - Module, - Component, - Instance, - Value, -} - -impl<'a> Parse<'a> for DefTypeKind { - fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(DefTypeKind::Func) - } else if l.peek::() { - parser.parse::()?; - Ok(DefTypeKind::Module) - } else if l.peek::() { - parser.parse::()?; - Ok(DefTypeKind::Component) - } else if l.peek::() { - parser.parse::()?; - Ok(DefTypeKind::Instance) - } else if l.peek::() { - parser.parse::()?; - Ok(DefTypeKind::Value) - } else { - Err(l.error()) - } - } -} - -impl Peek for DefTypeKind { - fn peek(cursor: Cursor<'_>) -> bool { - kw::func::peek(cursor) - || kw::module::peek(cursor) - || kw::component::peek(cursor) - || kw::instance::peek(cursor) - || kw::value::peek(cursor) - } - fn display() -> &'static str { - "deftype kind" - } -} - -/// deftype ::= -/// | -/// | -/// | -/// | -#[derive(Debug)] -#[allow(missing_docs)] -pub enum DefType<'a> { - Func(ComponentFunctionType<'a>), - Module(ModuleType<'a>), - Component(ComponentType<'a>), - Instance(InstanceType<'a>), - Value(ValueType<'a>), -} - -impl<'a> Parse<'a> for DefType<'a> { - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - parser.parse::()?; - Ok(DefType::Func(parser.parse()?)) - } else if parser.peek::() { - parser.parse::()?; - Ok(DefType::Module(parser.parse()?)) - } else if parser.peek::() { - parser.parse::()?; - Ok(DefType::Component(parser.parse()?)) - } else if parser.peek::() { - parser.parse::()?; - Ok(DefType::Instance(parser.parse()?)) - } else if parser.peek::() { - parser.parse::()?; - Ok(DefType::Value(parser.parse()?)) - } else { - Err(parser.error("expected a deftype")) - } - } -} - -/// A component function type with parameters and results. -/// -/// functype ::= (func ? (param ? )* (result )?) -#[derive(Debug)] -pub struct ComponentFunctionType<'a> { - /// The parameters of a function, optionally each having an identifier for - /// name resolution and a name for the custom `name` section. - pub params: Box<[ComponentFunctionParam<'a>]>, - /// The result type of a function. - pub result: InterTypeRef<'a>, -} - -impl<'a> Parse<'a> for ComponentFunctionType<'a> { - fn parse(parser: Parser<'a>) -> Result { - let mut params = Vec::new(); - while parser.peek2::() { - parser.parens(|p| { - p.parse::()?; - params.push(ComponentFunctionParam { - name: p.parse()?, - type_: p.parse()?, - }); - Ok(()) - })?; - } - let result = if parser.peek2::() { - // Parse a `(result ...)`. - parser.parens(|parser| { - parser.parse::()?; - parser.parse() - })? - } else { - // If the result is omitted, use `unit`. - InterTypeRef::Primitive(Primitive::Unit) - }; - Ok(Self { - params: params.into(), - result, - }) - } -} - -/// A parameter of a [`ComponentFunctionType`]. -#[derive(Clone, Debug)] -pub struct ComponentFunctionParam<'a> { - /// An optionally-specified name of this parameter - pub name: Option<&'a str>, - /// The type of the parameter. - pub type_: InterTypeRef<'a>, -} - -/// A type for a nested module -#[derive(Debug)] -pub struct ModuleType<'a> { - /// The fields of the module type. - pub defs: Vec>, -} - -impl<'a> Parse<'a> for ModuleType<'a> { - fn parse(parser: Parser<'a>) -> Result { - // See comments in `module.rs` for why this is tested here. - if parser.parens_depth() > 100 { - return Err(parser.error("module type nesting too deep")); - } - - let mut defs = Vec::new(); - while !parser.is_empty() { - defs.push(parser.parens(|p| p.parse())?); - } - Ok(ModuleType { defs }) - } -} - -/// The contents of a [`ModuleType`]. -#[derive(Debug)] -pub enum ModuleTypeDef<'a> { - /// A function type. - Type(core::Type<'a>), - /// An import. - Import(core::Import<'a>), - /// An export. - Export(&'a str, core::ItemSig<'a>), -} - -impl<'a> Parse<'a> for ModuleTypeDef<'a> { - fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - if l.peek::() { - Ok(ModuleTypeDef::Type(parser.parse()?)) - } else if l.peek::() { - Ok(ModuleTypeDef::Import(parser.parse()?)) - } else if l.peek::() { - parser.parse::()?; - let name = parser.parse()?; - let et = parser.parens(|parser| parser.parse())?; - Ok(ModuleTypeDef::Export(name, et)) - } else { - Err(parser.error("Expected a moduletype-def")) - } - } -} - -/// A type for a nested component -#[derive(Debug, Default)] -pub struct ComponentType<'a> { - /// The fields of this `ComponentType`. - pub fields: Vec>, -} - -impl<'a> Parse<'a> for ComponentType<'a> { - fn parse(parser: Parser<'a>) -> Result { - // See comments in `module.rs` for why this is tested here. - if parser.parens_depth() > 100 { - return Err(parser.error("component type nesting too deep")); - } - - let mut fields = Vec::new(); - while !parser.is_empty() { - parser.parens(|parser| { - if parser.peek::() { - fields.push(ComponentTypeField::Import(parser.parse()?)); - } else if parser.peek::() { - fields.push(ComponentTypeField::Export(parser.parse()?)); - } else if parser.peek::() { - fields.push(ComponentTypeField::Type(parser.parse()?)); - } else if parser.peek::() { - fields.push(ComponentTypeField::Alias(parser.parse()?)); - } - Ok(()) - })?; - } - Ok(ComponentType { fields }) - } -} - -/// A field of a type for a nested component -#[derive(Debug)] -pub enum ComponentTypeField<'a> { - /// A public type for this component. - Type(TypeField<'a>), - - /// A public type relationships for this component. - Alias(Alias<'a>), - - /// An import expected for this component type. - Import(ComponentImport<'a>), - - /// An export this component type is expected to have. - Export(ComponentExportType<'a>), -} - -impl<'a> From> for ComponentTypeField<'a> { - fn from(field: TypeField<'a>) -> ComponentTypeField<'a> { - ComponentTypeField::Type(field) - } -} - -impl<'a> From> for ComponentTypeField<'a> { - fn from(field: Alias<'a>) -> ComponentTypeField<'a> { - ComponentTypeField::Alias(field) - } -} - -/// A type for a nested instance -#[derive(Debug)] -pub struct InstanceType<'a> { - /// The fields of this `InstanceType`. - pub fields: Vec>, -} - -impl<'a> Parse<'a> for InstanceType<'a> { - fn parse(parser: Parser<'a>) -> Result { - // See comments in `module.rs` for why this is tested here. - if parser.parens_depth() > 100 { - return Err(parser.error("instance type nesting too deep")); - } - - let mut fields = Vec::new(); - while !parser.is_empty() { - parser.parens(|parser| { - let mut l = parser.lookahead1(); - if l.peek::() { - fields.push(InstanceTypeField::Export(parser.parse()?)); - } else if l.peek::() { - fields.push(InstanceTypeField::Type(parser.parse()?)); - } else if l.peek::() { - fields.push(InstanceTypeField::Alias(parser.parse()?)); - } else { - return Err(l.error()); - } - Ok(()) - })?; - } - Ok(InstanceType { fields }) - } -} - -/// A field of a type for a nested instance -#[derive(Debug)] -pub enum InstanceTypeField<'a> { - /// A public type for this component. - Type(TypeField<'a>), - - /// A public type relationships for this component. - Alias(Alias<'a>), - - /// An export this component type is expected to have. - Export(ComponentExportType<'a>), -} - -impl<'a> From> for InstanceTypeField<'a> { - fn from(field: TypeField<'a>) -> InstanceTypeField<'a> { - InstanceTypeField::Type(field) - } -} - -impl<'a> From> for InstanceTypeField<'a> { - fn from(field: Alias<'a>) -> InstanceTypeField<'a> { - InstanceTypeField::Alias(field) - } -} - -/// A value type. -#[derive(Debug, Clone)] -pub struct ValueType<'a> { - /// The type of the value. - pub value_type: InterTypeRef<'a>, -} - -impl<'a> Parse<'a> for ValueType<'a> { - fn parse(parser: Parser<'a>) -> Result { - Ok(ValueType { - value_type: parser.parse()?, - }) - } -} diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs index c5a7f1ed6e..9fe32212eb 100644 --- a/crates/wast/src/component/expand.rs +++ b/crates/wast/src/component/expand.rs @@ -2,7 +2,8 @@ use crate::component::*; use crate::core; use crate::gensym; use crate::kw; -use crate::token::{Id, Index, Span}; +use crate::token::Id; +use crate::token::{Index, Span}; use std::collections::HashMap; use std::mem; @@ -20,12 +21,44 @@ pub fn expand(fields: &mut Vec>) { Expander::default().expand_component_fields(fields) } +enum AnyType<'a> { + Core(CoreType<'a>), + Component(Type<'a>), +} + +impl<'a> From> for ComponentTypeDecl<'a> { + fn from(t: AnyType<'a>) -> Self { + match t { + AnyType::Core(t) => Self::CoreType(t), + AnyType::Component(t) => Self::Type(t), + } + } +} + +impl<'a> From> for InstanceTypeDecl<'a> { + fn from(t: AnyType<'a>) -> Self { + match t { + AnyType::Core(t) => Self::CoreType(t), + AnyType::Component(t) => Self::Type(t), + } + } +} + +impl<'a> From> for ComponentField<'a> { + fn from(t: AnyType<'a>) -> Self { + match t { + AnyType::Core(t) => Self::CoreType(t), + AnyType::Component(t) => Self::Type(t), + } + } +} + #[derive(Default)] struct Expander<'a> { /// Fields, during processing, which should be prepended to the /// currently-being-processed field. This should always be empty after /// processing is complete. - to_prepend: Vec>, + types_to_prepend: Vec>, component_fields_to_prepend: Vec>, /// Fields that are appended to the end of the module once everything has @@ -38,218 +71,292 @@ impl<'a> Expander<'a> { let mut cur = 0; while cur < fields.len() { self.expand_field(&mut fields[cur]); - let amt = self.to_prepend.len() + self.component_fields_to_prepend.len(); + let amt = self.types_to_prepend.len() + self.component_fields_to_prepend.len(); fields.splice(cur..cur, self.component_fields_to_prepend.drain(..)); - fields.splice(cur..cur, self.to_prepend.drain(..).map(|f| f.into())); + fields.splice(cur..cur, self.types_to_prepend.drain(..).map(Into::into)); cur += 1 + amt; } - fields.extend(self.component_fields_to_append.drain(..)); + fields.append(&mut self.component_fields_to_append); } - fn expand_fields(&mut self, fields: &mut Vec, expand: fn(&mut Self, &mut T)) + fn expand_decls(&mut self, decls: &mut Vec, expand: fn(&mut Self, &mut T)) where - T: From>, + T: From>, { let mut cur = 0; - while cur < fields.len() { - expand(self, &mut fields[cur]); + while cur < decls.len() { + expand(self, &mut decls[cur]); assert!(self.component_fields_to_prepend.is_empty()); assert!(self.component_fields_to_append.is_empty()); - let amt = self.to_prepend.len(); - fields.splice(cur..cur, self.to_prepend.drain(..).map(T::from)); + let amt = self.types_to_prepend.len(); + decls.splice(cur..cur, self.types_to_prepend.drain(..).map(From::from)); cur += 1 + amt; } } fn expand_field(&mut self, item: &mut ComponentField<'a>) { - match item { - ComponentField::Type(t) => self.expand_type_field(t), - ComponentField::Import(t) => { - self.expand_item_sig(&mut t.item); + let expanded = match item { + ComponentField::CoreModule(m) => self.expand_core_module(m), + ComponentField::CoreInstance(i) => { + self.expand_core_instance(i); + None } - ComponentField::Component(c) => { - for name in c.exports.names.drain(..) { - self.component_fields_to_append.push(export( - c.span, - name, - DefTypeKind::Component, - &mut c.id, - )); - } - match &mut c.kind { - NestedComponentKind::Inline(fields) => expand(fields), - NestedComponentKind::Import { import, ty } => { - let idx = self.expand_component_type_use(ty); - *item = ComponentField::Import(ComponentImport { - span: c.span, - name: import.name, - item: ItemSig { - span: c.span, - id: c.id, - name: None, - kind: ItemKind::Component(ComponentTypeUse::Ref(idx)), - }, - }); - } - } + ComponentField::CoreType(t) => { + self.expand_core_type(t); + None } + ComponentField::Component(c) => self.expand_nested_component(c), + ComponentField::Instance(i) => self.expand_instance(i), + ComponentField::Type(t) => { + self.expand_type(t); + None + } + ComponentField::CanonicalFunc(f) => { + self.expand_canonical_func(f); + None + } + ComponentField::CoreFunc(f) => self.expand_core_func(f), + ComponentField::Func(f) => self.expand_func(f), + ComponentField::Import(i) => { + self.expand_item_sig(&mut i.item); + None + } + ComponentField::Start(_) + | ComponentField::CoreAlias(_) + | ComponentField::Alias(_) + | ComponentField::Export(_) + | ComponentField::Custom(_) => None, + }; - ComponentField::Func(f) => { - for name in f.exports.names.drain(..) { - self.component_fields_to_append.push(export( - f.span, - name, - DefTypeKind::Func, - &mut f.id, - )); - } - match &mut f.kind { - ComponentFuncKind::Import { import, ty } => { - let idx = self.expand_component_type_use(ty); - *item = ComponentField::Import(ComponentImport { - span: f.span, - name: import.name, - item: ItemSig { - span: f.span, - id: f.id, - name: None, - kind: ItemKind::Func(ComponentTypeUse::Ref(idx)), - }, - }); - } - ComponentFuncKind::Inline { body } => match body { - ComponentFuncBody::CanonLift(lift) => { - self.expand_component_type_use(&mut lift.type_); - } - ComponentFuncBody::CanonLower(_) => {} + if let Some(expanded) = expanded { + *item = expanded; + } + } + + fn expand_core_module(&mut self, module: &mut CoreModule<'a>) -> Option> { + for name in module.exports.names.drain(..) { + let id = gensym::fill(module.span, &mut module.id); + self.component_fields_to_append + .push(ComponentField::Export(ComponentExport { + span: module.span, + name, + kind: ComponentExportKind::module(module.span, id), + })); + } + match &mut module.kind { + // inline modules are expanded later during resolution + CoreModuleKind::Inline { .. } => None, + CoreModuleKind::Import { import, ty } => { + let idx = self.expand_core_type_use(ty); + Some(ComponentField::Import(ComponentImport { + span: module.span, + name: import.name, + item: ItemSig { + span: module.span, + id: module.id, + name: None, + kind: ItemSigKind::CoreModule(CoreTypeUse::Ref(idx)), }, - } + })) } + } + } - ComponentField::Module(m) => { - for name in m.exports.names.drain(..) { - self.component_fields_to_append.push(export( - m.span, - name, - DefTypeKind::Module, - &mut m.id, - )); - } - match &mut m.kind { - // inline modules are expanded later during resolution - ModuleKind::Inline { .. } => {} - ModuleKind::Import { import, ty } => { - let idx = self.expand_component_type_use(ty); - *item = ComponentField::Import(ComponentImport { - span: m.span, - name: import.name, - item: ItemSig { - span: m.span, - id: m.id, - name: None, - kind: ItemKind::Module(ComponentTypeUse::Ref(idx)), - }, - }); - } + fn expand_core_instance(&mut self, instance: &mut CoreInstance<'a>) { + match &mut instance.kind { + CoreInstanceKind::Instantiate { args, .. } => { + for arg in args { + self.expand_core_instantiation_arg(&mut arg.kind); } } + CoreInstanceKind::BundleOfExports { .. } => {} + } + } - ComponentField::Instance(i) => { - for name in i.exports.names.drain(..) { - self.component_fields_to_append.push(export( - i.span, - name, - DefTypeKind::Instance, - &mut i.id, - )); - } - match &mut i.kind { - InstanceKind::Import { import, ty } => { - let idx = self.expand_component_type_use(ty); - *item = ComponentField::Import(ComponentImport { - span: i.span, - name: import.name, - item: ItemSig { - span: i.span, - id: i.id, - name: None, - kind: ItemKind::Instance(ComponentTypeUse::Ref(idx)), - }, - }); - } - InstanceKind::Module { args, .. } => { - for arg in args { - self.expand_module_arg(&mut arg.arg); - } - } - InstanceKind::Component { args, .. } => { - for arg in args { - self.expand_component_arg(&mut arg.arg); - } - } - InstanceKind::BundleOfExports { .. } - | InstanceKind::BundleOfComponentExports { .. } => {} + fn expand_nested_component( + &mut self, + component: &mut NestedComponent<'a>, + ) -> Option> { + for name in component.exports.names.drain(..) { + let id = gensym::fill(component.span, &mut component.id); + self.component_fields_to_append + .push(ComponentField::Export(ComponentExport { + span: component.span, + name, + kind: ComponentExportKind::component(component.span, id), + })); + } + match &mut component.kind { + NestedComponentKind::Inline(fields) => { + expand(fields); + None + } + NestedComponentKind::Import { import, ty } => { + let idx = self.expand_component_type_use(ty); + Some(ComponentField::Import(ComponentImport { + span: component.span, + name: import.name, + item: ItemSig { + span: component.span, + id: component.id, + name: None, + kind: ItemSigKind::Component(ComponentTypeUse::Ref(idx)), + }, + })) + } + } + } + + fn expand_instance(&mut self, instance: &mut Instance<'a>) -> Option> { + for name in instance.exports.names.drain(..) { + let id = gensym::fill(instance.span, &mut instance.id); + self.component_fields_to_append + .push(ComponentField::Export(ComponentExport { + span: instance.span, + name, + kind: ComponentExportKind::instance(instance.span, id), + })); + } + match &mut instance.kind { + InstanceKind::Import { import, ty } => { + let idx = self.expand_component_type_use(ty); + Some(ComponentField::Import(ComponentImport { + span: instance.span, + name: import.name, + item: ItemSig { + span: instance.span, + id: instance.id, + name: None, + kind: ItemSigKind::Instance(ComponentTypeUse::Ref(idx)), + }, + })) + } + InstanceKind::Instantiate { args, .. } => { + for arg in args { + self.expand_instantiation_arg(&mut arg.kind); } + None } + InstanceKind::BundleOfExports { .. } => None, + } + } - ComponentField::Export(e) => { - self.expand_component_arg(&mut e.arg); + fn expand_canonical_func(&mut self, func: &mut CanonicalFunc<'a>) { + match &mut func.kind { + CanonicalFuncKind::Lift { ty, .. } => { + self.expand_component_type_use(ty); } + CanonicalFuncKind::Lower(_) => {} + } + } - ComponentField::Alias(_) | ComponentField::Start(_) => {} + fn expand_core_func(&mut self, func: &mut CoreFunc<'a>) -> Option> { + match &mut func.kind { + CoreFuncKind::Alias(a) => Some(ComponentField::CoreAlias(CoreAlias { + span: func.span, + id: func.id, + name: func.name, + target: CoreAliasTarget::Export { + instance: a.instance, + name: a.name, + kind: core::ExportKind::Func, + }, + })), + CoreFuncKind::Lower(info) => Some(ComponentField::CanonicalFunc(CanonicalFunc { + span: func.span, + id: func.id, + name: func.name, + kind: CanonicalFuncKind::Lower(mem::take(info)), + })), } + } - fn export<'a>( - span: Span, - name: &'a str, - kind: DefTypeKind, - id: &mut Option>, - ) -> ComponentField<'a> { - let id = gensym::fill(span, id); - ComponentField::Export(ComponentExport { - span, - name, - arg: ComponentArg::Def(ItemRef { - idx: Index::Id(id), - kind, - export_names: Vec::new(), - }), - }) + fn expand_func(&mut self, func: &mut Func<'a>) -> Option> { + for name in func.exports.names.drain(..) { + let id = gensym::fill(func.span, &mut func.id); + self.component_fields_to_append + .push(ComponentField::Export(ComponentExport { + span: func.span, + name, + kind: ComponentExportKind::func(func.span, id), + })); + } + match &mut func.kind { + FuncKind::Import { import, ty } => { + let idx = self.expand_component_type_use(ty); + Some(ComponentField::Import(ComponentImport { + span: func.span, + name: import.name, + item: ItemSig { + span: func.span, + id: func.id, + name: None, + kind: ItemSigKind::Func(ComponentTypeUse::Ref(idx)), + }, + })) + } + FuncKind::Lift { ty, info } => { + let idx = self.expand_component_type_use(ty); + Some(ComponentField::CanonicalFunc(CanonicalFunc { + span: func.span, + id: func.id, + name: func.name, + kind: CanonicalFuncKind::Lift { + ty: ComponentTypeUse::Ref(idx), + info: mem::take(info), + }, + })) + } + FuncKind::Alias(a) => Some(ComponentField::Alias(Alias { + span: func.span, + id: func.id, + name: func.name, + target: AliasTarget::Export { + instance: a.instance, + name: a.name, + kind: ComponentExportAliasKind::Func, + }, + })), } } - fn expand_type_field(&mut self, field: &mut TypeField<'a>) { + fn expand_core_type(&mut self, field: &mut CoreType<'a>) { match &mut field.def { - ComponentTypeDef::DefType(t) => self.expand_deftype(t), - ComponentTypeDef::InterType(t) => self.expand_intertype(t), + CoreTypeDef::Def(_) => {} + CoreTypeDef::Module(m) => self.expand_module_ty(m), } - let name = gensym::fill(field.span, &mut field.id); - let name = Index::Id(name); + + let id = gensym::fill(field.span, &mut field.id); + let index = Index::Id(id); match &field.def { - ComponentTypeDef::DefType(DefType::Func(t)) => t.key().insert(self, name), - ComponentTypeDef::DefType(DefType::Module(t)) => t.key().insert(self, name), - ComponentTypeDef::DefType(DefType::Component(t)) => t.key().insert(self, name), - ComponentTypeDef::DefType(DefType::Instance(t)) => t.key().insert(self, name), - ComponentTypeDef::DefType(DefType::Value(t)) => t.key().insert(self, name), - ComponentTypeDef::InterType(t) => t.key().insert(self, name), + CoreTypeDef::Def(_) => {} + CoreTypeDef::Module(t) => t.key().insert(self, index), } } - fn expand_deftype(&mut self, ty: &mut DefType<'a>) { - match ty { - DefType::Func(t) => self.expand_func_ty(t), - DefType::Module(m) => self.expand_module_ty(m), - DefType::Component(c) => self.expand_component_ty(c), - DefType::Instance(i) => self.expand_instance_ty(i), - DefType::Value(v) => self.expand_value_ty(v), + fn expand_type(&mut self, field: &mut Type<'a>) { + match &mut field.def { + TypeDef::Defined(d) => self.expand_defined_ty(d), + TypeDef::Func(f) => self.expand_func_ty(f), + TypeDef::Component(c) => self.expand_component_ty(c), + TypeDef::Instance(i) => self.expand_instance_ty(i), + } + + let id = gensym::fill(field.span, &mut field.id); + let index = Index::Id(id); + match &field.def { + TypeDef::Defined(t) => t.key().insert(self, index), + TypeDef::Func(t) => t.key().insert(self, index), + TypeDef::Component(t) => t.key().insert(self, index), + TypeDef::Instance(t) => t.key().insert(self, index), } } fn expand_func_ty(&mut self, ty: &mut ComponentFunctionType<'a>) { for param in ty.params.iter_mut() { - self.expand_intertype_ref(&mut param.type_); + self.expand_component_val_ty(&mut param.ty); } - self.expand_intertype_ref(&mut ty.result); + self.expand_component_val_ty(&mut ty.result); } fn expand_module_ty(&mut self, ty: &mut ModuleType<'a>) { @@ -263,9 +370,9 @@ impl<'a> Expander<'a> { let mut func_type_to_idx = HashMap::new(); let mut to_prepend = Vec::new(); let mut i = 0; - while i < ty.defs.len() { - match &mut ty.defs[i] { - ModuleTypeDef::Type(ty) => match &ty.def { + while i < ty.decls.len() { + match &mut ty.decls[i] { + ModuleTypeDecl::Type(ty) => match &ty.def { core::TypeDef::Func(f) => { let id = gensym::fill(ty.span, &mut ty.id); func_type_to_idx.insert(f.key(), Index::Id(id)); @@ -273,20 +380,20 @@ impl<'a> Expander<'a> { core::TypeDef::Struct(_) => {} core::TypeDef::Array(_) => {} }, - ModuleTypeDef::Import(ty) => { + ModuleTypeDecl::Import(ty) => { expand_sig(&mut ty.item, &mut to_prepend, &mut func_type_to_idx); } - ModuleTypeDef::Export(_, item) => { + ModuleTypeDecl::Export(_, item) => { expand_sig(item, &mut to_prepend, &mut func_type_to_idx); } } - ty.defs.splice(i..i, to_prepend.drain(..)); + ty.decls.splice(i..i, to_prepend.drain(..)); i += 1; } fn expand_sig<'a>( item: &mut core::ItemSig<'a>, - to_prepend: &mut Vec>, + to_prepend: &mut Vec>, func_type_to_idx: &mut HashMap, Index<'a>>, ) { match &mut item.kind { @@ -304,11 +411,11 @@ impl<'a> Expander<'a> { let ty = t.inline.take().unwrap_or_default(); let key = ty.key(); if let Some(idx) = func_type_to_idx.get(&key) { - t.index = Some(idx.clone()); + t.index = Some(*idx); return; } let id = gensym::gen(item.span); - to_prepend.push(ModuleTypeDef::Type(core::Type { + to_prepend.push(ModuleTypeDecl::Type(core::Type { span: item.span, id: Some(id), name: None, @@ -325,99 +432,161 @@ impl<'a> Expander<'a> { } fn expand_component_ty(&mut self, ty: &mut ComponentType<'a>) { - Expander::default().expand_fields(&mut ty.fields, |e, field| match field { - ComponentTypeField::Type(t) => e.expand_type_field(t), - ComponentTypeField::Alias(_) => {} - ComponentTypeField::Export(t) => e.expand_item_sig(&mut t.item), - ComponentTypeField::Import(t) => e.expand_item_sig(&mut t.item), + Expander::default().expand_decls(&mut ty.decls, |e, decl| match decl { + ComponentTypeDecl::CoreType(t) => e.expand_core_type(t), + ComponentTypeDecl::Type(t) => e.expand_type(t), + ComponentTypeDecl::Alias(_) => {} + ComponentTypeDecl::Export(t) => e.expand_item_sig(&mut t.item), + ComponentTypeDecl::Import(t) => e.expand_item_sig(&mut t.item), }) } fn expand_instance_ty(&mut self, ty: &mut InstanceType<'a>) { - Expander::default().expand_fields(&mut ty.fields, |e, field| match field { - InstanceTypeField::Type(t) => e.expand_type_field(t), - InstanceTypeField::Alias(_) => {} - InstanceTypeField::Export(t) => e.expand_item_sig(&mut t.item), + Expander::default().expand_decls(&mut ty.decls, |e, decl| match decl { + InstanceTypeDecl::CoreType(t) => e.expand_core_type(t), + InstanceTypeDecl::Type(t) => e.expand_type(t), + InstanceTypeDecl::Alias(_) => {} + InstanceTypeDecl::Export(t) => e.expand_item_sig(&mut t.item), }) } - fn expand_item_sig(&mut self, sig: &mut ItemSig<'a>) { - match &mut sig.kind { - ItemKind::Component(t) => self.expand_component_type_use(t), - ItemKind::Module(t) => self.expand_component_type_use(t), - ItemKind::Instance(t) => self.expand_component_type_use(t), - ItemKind::Value(t) => self.expand_component_type_use(t), - ItemKind::Func(t) => self.expand_component_type_use(t), - }; - } - - fn expand_value_ty(&mut self, ty: &mut ValueType<'a>) { - self.expand_intertype_ref(&mut ty.value_type); + fn expand_item_sig(&mut self, ext: &mut ItemSig<'a>) { + match &mut ext.kind { + ItemSigKind::CoreModule(t) => { + self.expand_core_type_use(t); + } + ItemSigKind::Func(t) => { + self.expand_component_type_use(t); + } + ItemSigKind::Component(t) => { + self.expand_component_type_use(t); + } + ItemSigKind::Instance(t) => { + self.expand_component_type_use(t); + } + ItemSigKind::Value(t) => { + self.expand_component_val_ty(t); + } + ItemSigKind::Type(_) => {} + } } - fn expand_intertype(&mut self, ty: &mut InterType<'a>) { + fn expand_defined_ty(&mut self, ty: &mut ComponentDefinedType<'a>) { match ty { - InterType::Primitive(_) | InterType::Flags(_) | InterType::Enum(_) => {} - InterType::Record(r) => { + ComponentDefinedType::Primitive(_) + | ComponentDefinedType::Flags(_) + | ComponentDefinedType::Enum(_) => {} + ComponentDefinedType::Record(r) => { for field in r.fields.iter_mut() { - self.expand_intertype_ref(&mut field.type_); + self.expand_component_val_ty(&mut field.ty); } } - InterType::Variant(v) => { + ComponentDefinedType::Variant(v) => { for case in v.cases.iter_mut() { - self.expand_intertype_ref(&mut case.type_); + self.expand_component_val_ty(&mut case.ty); } } - InterType::List(t) => { - self.expand_intertype_ref(&mut t.element); + ComponentDefinedType::List(t) => { + self.expand_component_val_ty(&mut t.element); } - InterType::Tuple(t) => { + ComponentDefinedType::Tuple(t) => { for field in t.fields.iter_mut() { - self.expand_intertype_ref(field); + self.expand_component_val_ty(field); } } - InterType::Union(u) => { - for arm in u.arms.iter_mut() { - self.expand_intertype_ref(arm); + ComponentDefinedType::Union(u) => { + for ty in u.types.iter_mut() { + self.expand_component_val_ty(ty); } } - InterType::Option(t) => { - self.expand_intertype_ref(&mut t.element); + ComponentDefinedType::Option(t) => { + self.expand_component_val_ty(&mut t.element); } - InterType::Expected(e) => { - self.expand_intertype_ref(&mut e.ok); - self.expand_intertype_ref(&mut e.err); + ComponentDefinedType::Expected(e) => { + self.expand_component_val_ty(&mut e.ok); + self.expand_component_val_ty(&mut e.err); } } } - fn expand_intertype_ref(&mut self, ty: &mut InterTypeRef<'a>) { + fn expand_component_val_ty(&mut self, ty: &mut ComponentValType<'a>) { let inline = match ty { - InterTypeRef::Primitive(_) | InterTypeRef::Ref(_) => return, - InterTypeRef::Inline(inline) => { - self.expand_intertype(inline); - mem::replace(inline, InterType::Primitive(Primitive::Unit)) + ComponentValType::Primitive(_) | ComponentValType::Ref(_) => return, + ComponentValType::Inline(inline) => { + self.expand_defined_ty(inline); + mem::take(inline) } }; // If this inline type has already been defined within this context // then reuse the previously defined type to avoid injecting too many // types into the type index space. if let Some(idx) = inline.key().lookup(self) { - *ty = InterTypeRef::Ref(idx); + *ty = ComponentValType::Ref(idx); return; } + // And if this type isn't already defined we append it to the index // space with a fresh and unique name. let span = Span::from_offset(0); // FIXME(#613): don't manufacture let id = gensym::gen(span); - self.to_prepend.push(TypeField { - span, - id: Some(id), - name: None, - def: inline.into_def(), - }); + + self.types_to_prepend.push(inline.into_any_type(span, id)); + let idx = Index::Id(id); - *ty = InterTypeRef::Ref(idx); + *ty = ComponentValType::Ref(idx); + } + + fn expand_core_type_use( + &mut self, + item: &mut CoreTypeUse<'a, T>, + ) -> CoreItemRef<'a, kw::r#type> + where + T: TypeReference<'a>, + { + let span = Span::from_offset(0); // FIXME(#613): don't manufacture + let mut inline = match mem::take(item) { + // If this type-use was already a reference to an existing type + // then we put it back the way it was and return the corresponding + // index. + CoreTypeUse::Ref(idx) => { + *item = CoreTypeUse::Ref(idx.clone()); + return idx; + } + + // ... otherwise with an inline type definition we go into + // processing below. + CoreTypeUse::Inline(inline) => inline, + }; + inline.expand(self); + + // If this inline type has already been defined within this context + // then reuse the previously defined type to avoid injecting too many + // types into the type index space. + if let Some(idx) = inline.key().lookup(self) { + let ret = CoreItemRef { + idx, + kind: kw::r#type(span), + export_name: None, + }; + *item = CoreTypeUse::Ref(ret.clone()); + return ret; + } + + // And if this type isn't already defined we append it to the index + // space with a fresh and unique name. + let id = gensym::gen(span); + + self.types_to_prepend.push(inline.into_any_type(span, id)); + + let idx = Index::Id(id); + let ret = CoreItemRef { + idx, + kind: kw::r#type(span), + export_name: None, + }; + + *item = CoreTypeUse::Ref(ret.clone()); + ret } fn expand_component_type_use( @@ -428,12 +597,7 @@ impl<'a> Expander<'a> { T: TypeReference<'a>, { let span = Span::from_offset(0); // FIXME(#613): don't manufacture - let dummy = ComponentTypeUse::Ref(ItemRef { - idx: Index::Num(0, span), - kind: kw::r#type(span), - export_names: Vec::new(), - }); - let mut inline = match mem::replace(item, dummy) { + let mut inline = match mem::take(item) { // If this type-use was already a reference to an existing type // then we put it back the way it was and return the corresponding // index. @@ -464,47 +628,44 @@ impl<'a> Expander<'a> { // And if this type isn't already defined we append it to the index // space with a fresh and unique name. let id = gensym::gen(span); - self.to_prepend.push(TypeField { - span, - id: Some(id), - name: None, - def: inline.into_def(), - }); + + self.types_to_prepend.push(inline.into_any_type(span, id)); + let idx = Index::Id(id); let ret = ItemRef { idx, kind: kw::r#type(span), export_names: Vec::new(), }; + *item = ComponentTypeUse::Ref(ret.clone()); - return ret; + ret } - fn expand_module_arg(&mut self, arg: &mut ModuleArg<'a>) { - let (span, args) = match arg { - ModuleArg::Def(_) => return, - ModuleArg::BundleOfExports(span, exports) => (*span, mem::take(exports)), + fn expand_core_instantiation_arg(&mut self, arg: &mut CoreInstantiationArgKind<'a>) { + let (span, exports) = match arg { + CoreInstantiationArgKind::Instance(_) => return, + CoreInstantiationArgKind::BundleOfExports(span, exports) => (*span, mem::take(exports)), }; let id = gensym::gen(span); self.component_fields_to_prepend - .push(ComponentField::Instance(Instance { + .push(ComponentField::CoreInstance(CoreInstance { span, id: Some(id), name: None, - exports: Default::default(), - kind: InstanceKind::BundleOfExports { args }, + kind: CoreInstanceKind::BundleOfExports(exports), })); - *arg = ModuleArg::Def(ItemRef { - idx: Index::Id(id), + *arg = CoreInstantiationArgKind::Instance(CoreItemRef { kind: kw::instance(span), - export_names: Vec::new(), + idx: Index::Id(id), + export_name: None, }); } - fn expand_component_arg(&mut self, arg: &mut ComponentArg<'a>) { - let (span, args) = match arg { - ComponentArg::Def(_) => return, - ComponentArg::BundleOfExports(span, exports) => (*span, mem::take(exports)), + fn expand_instantiation_arg(&mut self, arg: &mut InstantiationArgKind<'a>) { + let (span, exports) = match arg { + InstantiationArgKind::Item(_) => return, + InstantiationArgKind::BundleOfExports(span, exports) => (*span, mem::take(exports)), }; let id = gensym::gen(span); self.component_fields_to_prepend @@ -513,13 +674,9 @@ impl<'a> Expander<'a> { id: Some(id), name: None, exports: Default::default(), - kind: InstanceKind::BundleOfComponentExports { args }, + kind: InstanceKind::BundleOfExports(exports), })); - *arg = ComponentArg::Def(ItemRef { - idx: Index::Id(id), - kind: DefTypeKind::Instance, - export_names: Vec::new(), - }); + *arg = InstantiationArgKind::Item(ComponentExportKind::instance(span, id)); } } @@ -527,10 +684,10 @@ trait TypeReference<'a> { type Key: TypeKey<'a>; fn key(&self) -> Self::Key; fn expand(&mut self, cx: &mut Expander<'a>); - fn into_def(self) -> ComponentTypeDef<'a>; + fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a>; } -impl<'a> TypeReference<'a> for InterType<'a> { +impl<'a> TypeReference<'a> for ComponentDefinedType<'a> { type Key = Todo; // FIXME(#598): should implement this fn key(&self) -> Self::Key { @@ -538,11 +695,17 @@ impl<'a> TypeReference<'a> for InterType<'a> { } fn expand(&mut self, cx: &mut Expander<'a>) { - cx.expand_intertype(self) + cx.expand_defined_ty(self) } - fn into_def(self) -> ComponentTypeDef<'a> { - ComponentTypeDef::InterType(self) + fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> { + AnyType::Component(Type { + span, + id: Some(id), + name: None, + exports: Default::default(), + def: TypeDef::Defined(self), + }) } } @@ -557,8 +720,14 @@ impl<'a> TypeReference<'a> for ComponentType<'a> { cx.expand_component_ty(self) } - fn into_def(self) -> ComponentTypeDef<'a> { - ComponentTypeDef::DefType(DefType::Component(self)) + fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> { + AnyType::Component(Type { + span, + id: Some(id), + name: None, + exports: Default::default(), + def: TypeDef::Component(self), + }) } } @@ -573,8 +742,13 @@ impl<'a> TypeReference<'a> for ModuleType<'a> { cx.expand_module_ty(self) } - fn into_def(self) -> ComponentTypeDef<'a> { - ComponentTypeDef::DefType(DefType::Module(self)) + fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> { + AnyType::Core(CoreType { + span, + id: Some(id), + name: None, + def: CoreTypeDef::Module(self), + }) } } @@ -589,8 +763,14 @@ impl<'a> TypeReference<'a> for InstanceType<'a> { cx.expand_instance_ty(self) } - fn into_def(self) -> ComponentTypeDef<'a> { - ComponentTypeDef::DefType(DefType::Instance(self)) + fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> { + AnyType::Component(Type { + span, + id: Some(id), + name: None, + exports: Default::default(), + def: TypeDef::Instance(self), + }) } } @@ -605,30 +785,20 @@ impl<'a> TypeReference<'a> for ComponentFunctionType<'a> { cx.expand_func_ty(self) } - fn into_def(self) -> ComponentTypeDef<'a> { - ComponentTypeDef::DefType(DefType::Func(self)) - } -} - -impl<'a> TypeReference<'a> for ValueType<'a> { - type Key = Todo; // FIXME(#598): should implement this - - fn key(&self) -> Self::Key { - Todo - } - - fn expand(&mut self, cx: &mut Expander<'a>) { - cx.expand_value_ty(self) - } - - fn into_def(self) -> ComponentTypeDef<'a> { - ComponentTypeDef::DefType(DefType::Value(self)) + fn into_any_type(self, span: Span, id: Id<'a>) -> AnyType<'a> { + AnyType::Component(Type { + span, + id: Some(id), + name: None, + exports: Default::default(), + def: TypeDef::Func(self), + }) } } trait TypeKey<'a> { fn lookup(&self, cx: &Expander<'a>) -> Option>; - fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>); + fn insert(&self, cx: &mut Expander<'a>, index: Index<'a>); } struct Todo; @@ -637,7 +807,8 @@ impl<'a> TypeKey<'a> for Todo { fn lookup(&self, _cx: &Expander<'a>) -> Option> { None } - fn insert(&self, cx: &mut Expander<'a>, id: Index<'a>) { - drop((cx, id)); + + fn insert(&self, cx: &mut Expander<'a>, index: Index<'a>) { + drop((cx, index)); } } diff --git a/crates/wast/src/component/export.rs b/crates/wast/src/component/export.rs index 0539c41221..a3b2bd7c0e 100644 --- a/crates/wast/src/component/export.rs +++ b/crates/wast/src/component/export.rs @@ -1,26 +1,141 @@ -use crate::component::ComponentArg; +use super::ItemRef; use crate::kw; -use crate::parser::{Parse, Parser, Result}; -use crate::token::Span; +use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::token::{Id, Index, Span}; -/// A entry in a WebAssembly component's export section. -/// -/// export ::= (export ) +/// An entry in a WebAssembly component's export section. #[derive(Debug)] pub struct ComponentExport<'a> { /// Where this export was defined. pub span: Span, /// The name of this export from the component. pub name: &'a str, - /// What's being exported from the component. - pub arg: ComponentArg<'a>, + /// The kind of export. + pub kind: ComponentExportKind<'a>, } impl<'a> Parse<'a> for ComponentExport<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let name = parser.parse()?; - let arg = parser.parse()?; - Ok(ComponentExport { span, name, arg }) + let kind = parser.parse()?; + Ok(ComponentExport { span, name, kind }) + } +} + +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut exports = Vec::new(); + while !parser.is_empty() { + exports.push(parser.parens(|parser| parser.parse())?); + } + Ok(exports) + } +} + +/// The kind of exported item. +#[derive(Debug)] +pub enum ComponentExportKind<'a> { + /// The export is a core module. + /// + /// Note this isn't a core item ref as currently only + /// components can export core modules. + CoreModule(ItemRef<'a, kw::module>), + /// The export is a function. + Func(ItemRef<'a, kw::func>), + /// The export is a value. + Value(ItemRef<'a, kw::value>), + /// The export is a type. + Type(ItemRef<'a, kw::r#type>), + /// The export is a component. + Component(ItemRef<'a, kw::component>), + /// The export is an instance. + Instance(ItemRef<'a, kw::instance>), +} + +impl<'a> ComponentExportKind<'a> { + pub(crate) fn module(span: Span, id: Id<'a>) -> Self { + Self::CoreModule(ItemRef { + kind: kw::module(span), + idx: Index::Id(id), + export_names: Default::default(), + }) + } + + pub(crate) fn component(span: Span, id: Id<'a>) -> Self { + Self::Component(ItemRef { + kind: kw::component(span), + idx: Index::Id(id), + export_names: Default::default(), + }) + } + + pub(crate) fn instance(span: Span, id: Id<'a>) -> Self { + Self::Instance(ItemRef { + kind: kw::instance(span), + idx: Index::Id(id), + export_names: Default::default(), + }) + } + + pub(crate) fn func(span: Span, id: Id<'a>) -> Self { + Self::Func(ItemRef { + kind: kw::func(span), + idx: Index::Id(id), + export_names: Default::default(), + }) + } +} + +impl<'a> Parse<'a> for ComponentExportKind<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|parser| { + let mut l = parser.lookahead1(); + if l.peek::() { + // Remove core prefix + parser.parse::()?; + Ok(Self::CoreModule(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Func(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Value(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Type(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Component(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Instance(parser.parse()?)) + } else { + Err(l.error()) + } + }) + } +} + +impl Peek for ComponentExportKind<'_> { + fn peek(cursor: Cursor) -> bool { + let cursor = match cursor.lparen() { + Some(c) => c, + None => return false, + }; + + let cursor = match cursor.keyword() { + Some(("core", c)) => match c.keyword() { + Some(("module", c)) => c, + _ => return false, + }, + Some(("func", c)) + | Some(("value", c)) + | Some(("type", c)) + | Some(("component", c)) + | Some(("instance", c)) => c, + _ => return false, + }; + + Index::peek(cursor) + } + + fn display() -> &'static str { + "component export" } } diff --git a/crates/wast/src/component/func.rs b/crates/wast/src/component/func.rs index 0a675db08a..f655d4b8b4 100644 --- a/crates/wast/src/component/func.rs +++ b/crates/wast/src/component/func.rs @@ -2,13 +2,75 @@ use crate::component::*; use crate::core; use crate::kw; use crate::parser::{Parse, Parser, Result}; -use crate::token::{Id, LParen, NameAnnotation, Span}; +use crate::token::{Id, Index, LParen, NameAnnotation, Span}; -/// A WebAssembly function to be inserted into a module. +/// A declared core function. /// -/// This is a member of both the function and code sections. +/// This is a member of both the core alias and canon sections. #[derive(Debug)] -pub struct ComponentFunc<'a> { +pub struct CoreFunc<'a> { + /// Where this `core func` was defined. + pub span: Span, + /// An identifier that this function is resolved with (optionally) for name + /// resolution. + pub id: Option>, + /// An optional name for this function stored in the custom `name` section. + pub name: Option>, + /// The kind of core function. + pub kind: CoreFuncKind<'a>, +} + +impl<'a> Parse<'a> for CoreFunc<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + parser.parse::()?; + let id = parser.parse()?; + let name = parser.parse()?; + let kind = parser.parse()?; + + Ok(Self { + span, + id, + name, + kind, + }) + } +} + +/// Represents the kind of core functions. +#[derive(Debug)] +pub enum CoreFuncKind<'a> { + /// The core function is defined in terms of lowering a component function. + /// + /// The core function is actually a member of the canon section. + Lower(CanonLower<'a>), + /// The core function is defined in terms of aliasing a module instance export. + /// + /// The core function is actually a member of the core alias section. + Alias(InlineExportAlias<'a>), +} + +impl<'a> Parse<'a> for CoreFuncKind<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|parser| { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(Self::Lower(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Alias(parser.parse()?)) + } else { + Err(l.error()) + } + }) + } +} + +/// A declared component function. +/// +/// This may be a member of the import, alias, or canon sections. +#[derive(Debug)] +pub struct Func<'a> { /// Where this `func` was defined. pub span: Span, /// An identifier that this function is resolved with (optionally) for name @@ -19,131 +81,218 @@ pub struct ComponentFunc<'a> { /// If present, inline export annotations which indicate names this /// definition should be exported under. pub exports: core::InlineExport<'a>, - /// What kind of function this is, be it an inline-defined or imported - /// function. - pub kind: ComponentFuncKind<'a>, + /// The kind of function. + pub kind: FuncKind<'a>, +} + +impl<'a> Parse<'a> for Func<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + let exports = parser.parse()?; + let kind = parser.parse()?; + + Ok(Self { + span, + id, + name, + exports, + kind, + }) + } } -/// Possible ways to define a function in the text format. +/// Represents the kind of component functions. #[derive(Debug)] -pub enum ComponentFuncKind<'a> { +pub enum FuncKind<'a> { /// A function which is actually defined as an import, such as: /// /// ```text - /// (func (import "foo") (type 3)) + /// (func (import "foo") (param string)) /// ``` Import { - /// The import name of this import + /// The import name of this import. import: InlineImport<'a>, /// The type that this function will have. ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>, }, - - /// Almost all functions, those defined inline in a wasm module. - Inline { - /// The body of the function. - body: ComponentFuncBody<'a>, + /// The function is defined in terms of lifting a core function. + /// + /// The function is actually a member of the canon section. + Lift { + /// The lifted function's type. + ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>, + /// Information relating to the lifting of the core function. + info: CanonLift<'a>, }, + /// The function is defined in terms of aliasing a component instance export. + /// + /// The function is actually a member of the alias section. + Alias(InlineExportAlias<'a>), } -impl<'a> Parse<'a> for ComponentFunc<'a> { +impl<'a> Parse<'a> for FuncKind<'a> { fn parse(parser: Parser<'a>) -> Result { - let span = parser.parse::()?.0; - let id = parser.parse()?; - let name = parser.parse()?; - let exports = parser.parse()?; - - let kind = if let Some(import) = parser.parse()? { - ComponentFuncKind::Import { + if let Some(import) = parser.parse()? { + Ok(Self::Import { import, ty: parser.parse()?, - } + }) + } else if parser.peek::() && parser.peek2::() { + parser.parens(|parser| Ok(Self::Alias(parser.parse()?))) } else { - ComponentFuncKind::Inline { - body: parser.parens(|p| p.parse())?, - } - }; - - Ok(ComponentFunc { - span, - id, - name, - exports, - kind, - }) + Ok(Self::Lift { + ty: parser.parse()?, + info: parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })?, + }) + } } } -/// The body of a `ComponentFunc`. +/// A WebAssembly canonical function to be inserted into a component. +/// +/// This is a member of the canonical section. #[derive(Debug)] -pub enum ComponentFuncBody<'a> { - /// A `canon.lift`. - CanonLift(CanonLift<'a>), - /// A `canon.lower`. - CanonLower(CanonLower<'a>), +pub struct CanonicalFunc<'a> { + /// Where this `func` was defined. + pub span: Span, + /// An identifier that this function is resolved with (optionally) for name + /// resolution. + pub id: Option>, + /// An optional name for this function stored in the custom `name` section. + pub name: Option>, + /// What kind of function this is, be it a lowered or lifted function. + pub kind: CanonicalFuncKind<'a>, } -impl<'a> Parse<'a> for ComponentFuncBody<'a> { +impl<'a> Parse<'a> for CanonicalFunc<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - Ok(ComponentFuncBody::CanonLift(parser.parse()?)) - } else if parser.peek::() { - Ok(ComponentFuncBody::CanonLower(parser.parse()?)) + let span = parser.parse::()?.0; + + if parser.peek::() { + let info = parser.parse()?; + let (id, name, ty) = parser.parens(|parser| { + parser.parse::()?; + let id = parser.parse()?; + let name = parser.parse()?; + let ty = parser.parse()?; + Ok((id, name, ty)) + })?; + + Ok(Self { + span, + id, + name, + kind: CanonicalFuncKind::Lift { info, ty }, + }) + } else if parser.peek::() { + let info = parser.parse()?; + let (id, name) = parser.parens(|parser| { + parser.parse::()?; + parser.parse::()?; + let id = parser.parse()?; + let name = parser.parse()?; + Ok((id, name)) + })?; + + Ok(Self { + span, + id, + name, + kind: CanonicalFuncKind::Lower(info), + }) } else { - Err(parser.error("Expected canon.lift or canon.lower")) + Err(parser.error("expected `canon lift` or `canon lower`")) } } } -/// Extra information associated with canon.lift instructions. +/// Possible ways to define a canonical function in the text format. +#[derive(Debug)] +pub enum CanonicalFuncKind<'a> { + /// A canonical function that is defined in terms of lifting a core function. + Lift { + /// The lifted function's type. + ty: ComponentTypeUse<'a, ComponentFunctionType<'a>>, + /// Information relating to the lifting of the core function. + info: CanonLift<'a>, + }, + /// A canonical function that is defined in terms of lowering a component function. + Lower(CanonLower<'a>), +} + +/// Information relating to lifting a core function. #[derive(Debug)] pub struct CanonLift<'a> { - /// The type exported to other components - pub type_: ComponentTypeUse<'a, ComponentFunctionType<'a>>, - /// Configuration options + /// The core function being lifted. + pub func: CoreItemRef<'a, kw::func>, + /// The canonical options for the lifting. pub opts: Vec>, - /// The function to wrap - pub func: ItemRef<'a, kw::func>, } impl<'a> Parse<'a> for CanonLift<'a> { fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let type_ = if parser.peek2::() { - ComponentTypeUse::Inline(parser.parens(|p| { - p.parse::()?; - p.parse() - })?) - } else { - ComponentTypeUse::Ref(parser.parse()?) - }; - let mut opts = Vec::new(); - while !parser.peek2::() { - opts.push(parser.parse()?); + parser.parse::()?; + + Ok(Self { + func: parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })?, + opts: parser.parse()?, + }) + } +} + +impl Default for CanonLift<'_> { + fn default() -> Self { + let span = Span::from_offset(0); + Self { + func: CoreItemRef { + kind: kw::func(span), + idx: Index::Num(0, span), + export_name: None, + }, + opts: Vec::new(), } - let func = parser.parse()?; - Ok(CanonLift { type_, opts, func }) } } -/// Extra information associated with canon.lower instructions. +/// Information relating to lowering a component function. #[derive(Debug)] pub struct CanonLower<'a> { - /// Configuration options - pub opts: Vec>, - /// The function being wrapped + /// The function being lowered. pub func: ItemRef<'a, kw::func>, + /// The canonical options for the lowering. + pub opts: Vec>, } impl<'a> Parse<'a> for CanonLower<'a> { fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut opts = Vec::new(); - while !parser.is_empty() && (!parser.peek::() || !parser.peek2::()) { - opts.push(parser.parse()?); + parser.parse::()?; + + Ok(Self { + func: parser.parens(|parser| parser.parse())?, + opts: parser.parse()?, + }) + } +} + +impl Default for CanonLower<'_> { + fn default() -> Self { + let span = Span::from_offset(0); + Self { + func: ItemRef { + kind: kw::func(span), + idx: Index::Num(0, span), + export_names: Vec::new(), + }, + opts: Vec::new(), } - let func = parser.parse()?; - Ok(CanonLower { opts, func }) } } @@ -156,10 +305,12 @@ pub enum CanonOpt<'a> { StringUtf16, /// Encode strings as "compact UTF-16". StringLatin1Utf16, - /// A target instance which supplies the memory that the canonical ABI - /// should operate on as well as functions that the canonical ABI can call - /// to allocate, reallocate and free linear memory - Into(ItemRef<'a, kw::instance>), + /// Use the specified memory for canonical ABI memory access. + Memory(CoreItemRef<'a, kw::memory>), + /// Use the specified reallocation function for memory allocations. + Realloc(CoreItemRef<'a, kw::func>), + /// Call the specified function after the lifted function has returned. + PostReturn(CoreItemRef<'a, kw::func>), } impl<'a> Parse<'a> for CanonOpt<'a> { @@ -167,19 +318,34 @@ impl<'a> Parse<'a> for CanonOpt<'a> { let mut l = parser.lookahead1(); if l.peek::() { parser.parse::()?; - Ok(CanonOpt::StringUtf8) + Ok(Self::StringUtf8) } else if l.peek::() { parser.parse::()?; - Ok(CanonOpt::StringUtf16) + Ok(Self::StringUtf16) } else if l.peek::() { parser.parse::()?; - Ok(CanonOpt::StringLatin1Utf16) + Ok(Self::StringLatin1Utf16) } else if l.peek::() { parser.parens(|parser| { let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(CanonOpt::Into(parser.parse::>()?.0)) + if l.peek::() { + parser.parse::()?; + Ok(CanonOpt::Memory(parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })?)) + } else if l.peek::() { + parser.parse::()?; + Ok(CanonOpt::Realloc(parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })?)) + } else if l.peek::() { + parser.parse::()?; + Ok(CanonOpt::PostReturn(parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })?)) } else { Err(l.error()) } @@ -190,8 +356,12 @@ impl<'a> Parse<'a> for CanonOpt<'a> { } } -impl Default for kw::instance { - fn default() -> kw::instance { - kw::instance(Span::from_offset(0)) +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut funcs = Vec::new(); + while !parser.is_empty() { + funcs.push(parser.parse()?); + } + Ok(funcs) } } diff --git a/crates/wast/src/component/import.rs b/crates/wast/src/component/import.rs index 429d68fbcf..5e54d5410e 100644 --- a/crates/wast/src/component/import.rs +++ b/crates/wast/src/component/import.rs @@ -1,6 +1,7 @@ use crate::component::*; use crate::kw; use crate::parser::{Cursor, Parse, Parser, Peek, Result}; +use crate::token::Index; use crate::token::{Id, NameAnnotation, Span}; /// An `import` statement and entry in a WebAssembly component. @@ -23,8 +24,8 @@ impl<'a> Parse<'a> for ComponentImport<'a> { } } +/// An item signature for imported items. #[derive(Debug)] -#[allow(missing_docs)] pub struct ItemSig<'a> { /// Where this item is defined in the source. pub span: Span, @@ -35,42 +36,38 @@ pub struct ItemSig<'a> { /// custom `name` section. pub name: Option>, /// What kind of item this is. - pub kind: ItemKind<'a>, -} - -#[derive(Debug)] -#[allow(missing_docs)] -pub enum ItemKind<'a> { - Component(ComponentTypeUse<'a, ComponentType<'a>>), - Module(ComponentTypeUse<'a, ModuleType<'a>>), - Instance(ComponentTypeUse<'a, InstanceType<'a>>), - Value(ComponentTypeUse<'a, ValueType<'a>>), - Func(ComponentTypeUse<'a, ComponentFunctionType<'a>>), + pub kind: ItemSigKind<'a>, } impl<'a> Parse<'a> for ItemSig<'a> { fn parse(parser: Parser<'a>) -> Result { let mut l = parser.lookahead1(); - let (span, parse_kind): (_, fn(Parser<'a>) -> Result) = - if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemKind::Component(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemKind::Module(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemKind::Instance(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemKind::Func(parser.parse()?))) - } else if l.peek::() { - let span = parser.parse::()?.0; - (span, |parser| Ok(ItemKind::Value(parser.parse()?))) - } else { - return Err(l.error()); - }; - Ok(ItemSig { + let (span, parse_kind): (_, fn(Parser<'a>) -> Result) = if l.peek::() + { + let span = parser.parse::()?.0; + parser.parse::()?; + (span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Func(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Component(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Instance(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| Ok(ItemSigKind::Value(parser.parse()?))) + } else if l.peek::() { + let span = parser.parse::()?.0; + (span, |parser| { + Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?)) + }) + } else { + return Err(l.error()); + }; + Ok(Self { span, id: parser.parse()?, name: parser.parse()?, @@ -79,13 +76,45 @@ impl<'a> Parse<'a> for ItemSig<'a> { } } +/// The kind of signatures for imported items. +#[derive(Debug)] +pub enum ItemSigKind<'a> { + /// The item signature is for a core module. + CoreModule(CoreTypeUse<'a, ModuleType<'a>>), + /// The item signature is for a function. + Func(ComponentTypeUse<'a, ComponentFunctionType<'a>>), + /// The item signature is for a component. + Component(ComponentTypeUse<'a, ComponentType<'a>>), + /// The item signature is for an instance. + Instance(ComponentTypeUse<'a, InstanceType<'a>>), + /// The item signature is for a value. + Value(ComponentValType<'a>), + /// The item signature is for a type. + Type(TypeBounds<'a>), +} + +/// Represents the bounds applied to types being imported. +#[derive(Debug)] +pub enum TypeBounds<'a> { + /// The equality type bounds. + Eq(Index<'a>), +} + +impl<'a> Parse<'a> for TypeBounds<'a> { + fn parse(parser: Parser<'a>) -> Result { + // Currently this is the only supported type bounds. + parser.parse::()?; + Ok(Self::Eq(parser.parse()?)) + } +} + /// A listing of a inline `(import "foo")` statement. /// /// This is the same as `core::InlineImport` except only one string import is /// required. #[derive(Debug, Copy, Clone)] -#[allow(missing_docs)] pub struct InlineImport<'a> { + /// The name of the item being imported. pub name: &'a str, } diff --git a/crates/wast/src/component/instance.rs b/crates/wast/src/component/instance.rs index 63d52eb723..bba45e3603 100644 --- a/crates/wast/src/component/instance.rs +++ b/crates/wast/src/component/instance.rs @@ -4,129 +4,167 @@ use crate::kw; use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, Index, LParen, NameAnnotation, Span}; -/// A nested WebAssembly instance to be created as part of a module. +/// A core instance defined by instantiation or exporting core items. #[derive(Debug)] -pub struct Instance<'a> { - /// Where this `instance` was defined. +pub struct CoreInstance<'a> { + /// Where this `core instance` was defined. pub span: Span, /// An identifier that this instance is resolved with (optionally) for name /// resolution. pub id: Option>, - /// An optional name for this function stored in the custom `name` section. + /// An optional name for this instance stored in the custom `name` section. pub name: Option>, - /// If present, inline export annotations which indicate names this - /// definition should be exported under. - pub exports: core::InlineExport<'a>, - /// What kind of instance this is, be it an inline-defined or imported one. - pub kind: InstanceKind<'a>, + /// What kind of instance this is. + pub kind: CoreInstanceKind<'a>, } -/// Possible ways to define a instance in the text format. -#[derive(Debug)] -pub enum InstanceKind<'a> { - /// The `(instance (import "x"))` sugar syntax - Import { - /// The name of the import - import: InlineImport<'a>, - /// The type of the instance being imported - ty: ComponentTypeUse<'a, InstanceType<'a>>, - }, - - /// Instantiate a core module. - Module { - /// Module that we're instantiating - module: ItemRef<'a, kw::module>, - /// Arguments used to instantiate the instance - args: Vec>, - }, +impl<'a> Parse<'a> for CoreInstance<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + parser.parse::()?; + let id = parser.parse()?; + let name = parser.parse()?; + let kind = parser.parse()?; - /// Instantiate a component. - Component { - /// Component that we're instantiating - component: ItemRef<'a, kw::component>, - /// Arguments used to instantiate the instance - args: Vec>, - }, + Ok(Self { + span, + id, + name, + kind, + }) + } +} - /// A bundle of module exports which isn't an instance, but can be used - /// in places that need an instance. - BundleOfExports { - /// Arguments used to create the anonymous instance - args: Vec>, +/// The kinds of core instances in the text format. +#[derive(Debug)] +pub enum CoreInstanceKind<'a> { + /// Instantiate a core module. + Instantiate { + /// The module being instantiated. + module: Index<'a>, + /// Arguments used to instantiate the instance. + args: Vec>, }, + /// The instance is defined by exporting local items as an instance. + BundleOfExports(Vec>), +} - /// A bundle of component exports which isn't an instance, but can be used - /// in places that need an instance. - BundleOfComponentExports { - /// Arguments used to create the anonymous instance - args: Vec>, - }, +impl<'a> Parse<'a> for CoreInstanceKind<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::() && parser.peek2::() { + parser.parens(|parser| { + parser.parse::()?; + Ok(Self::Instantiate { + module: parser.parse()?, + args: parser.parse()?, + }) + }) + } else { + Ok(Self::BundleOfExports(parser.parse()?)) + } + } } -/// Arguments to the module `instantiate` instruction +/// An argument to instantiate a core module. #[derive(Debug)] -#[allow(missing_docs)] -pub struct NamedModuleArg<'a> { +pub struct CoreInstantiationArg<'a> { + /// The name of the instantiation argument. pub name: &'a str, - pub arg: ModuleArg<'a>, + /// The kind of core instantiation argument. + pub kind: CoreInstantiationArgKind<'a>, } -impl<'a> Parse<'a> for NamedModuleArg<'a> { +impl<'a> Parse<'a> for CoreInstantiationArg<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parse::()?; - Ok(NamedModuleArg { + Ok(Self { name: parser.parse()?, - arg: parser.parse()?, + kind: parser.parse()?, + }) + } +} + +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut args = Vec::new(); + while !parser.is_empty() { + args.push(parser.parens(|parser| parser.parse())?); + } + Ok(args) + } +} + +/// The kind of core instantiation argument. +#[derive(Debug)] +pub enum CoreInstantiationArgKind<'a> { + /// The argument is a reference to an instance. + Instance(CoreItemRef<'a, kw::instance>), + /// The argument is an instance created from local exported core items. + /// + /// This is syntactic sugar for defining a core instance and also using it + /// as an instantiation argument. + BundleOfExports(Span, Vec>), +} + +impl<'a> Parse<'a> for CoreInstantiationArgKind<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|parser| { + if let Some(r) = parser.parse()? { + Ok(Self::Instance(r)) + } else { + let span = parser.parse::()?.0; + Ok(Self::BundleOfExports(span, parser.parse()?)) + } }) } } -/// Arguments to the component `instantiate` instruction +/// An exported item as part of a core instance. #[derive(Debug)] -#[allow(missing_docs)] -pub struct NamedComponentArg<'a> { +pub struct CoreInstanceExport<'a> { + /// Where this export was defined. + pub span: Span, + /// The name of this export from the instance. pub name: &'a str, - pub arg: ComponentArg<'a>, + /// What's being exported from the instance. + pub item: CoreItemRef<'a, core::ExportKind>, } -impl<'a> Parse<'a> for NamedComponentArg<'a> { +impl<'a> Parse<'a> for CoreInstanceExport<'a> { fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - Ok(NamedComponentArg { + Ok(Self { + span: parser.parse::()?.0, name: parser.parse()?, - arg: parser.parse()?, + item: parser.parens(|parser| parser.parse())?, }) } } -/// ```text -/// modulearg ::= (instance ) -/// | (instance *) -/// ``` -#[derive(Debug)] -pub enum ModuleArg<'a> { - /// Core modules can reference instances. - Def(ItemRef<'a, kw::instance>), - /// `instance`, but it isn't actually an instance; it's a tuple of exports - /// which can be used in place of an instance. - BundleOfExports(Span, Vec>), -} - -/// ```text -/// componentarg ::= (module ) -/// | (component ) -/// | (instance ) -/// | (func ) -/// | (value ) -/// | (instance *) -/// ``` +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut exports = Vec::new(); + while !parser.is_empty() { + exports.push(parser.parens(|parser| parser.parse())?); + } + Ok(exports) + } +} + +/// A component instance defined by instantiation or exporting items. #[derive(Debug)] -pub enum ComponentArg<'a> { - /// A reference to an item of one of the deftype kinds. - Def(ItemRef<'a, DefTypeKind>), - /// `instance`, but it isn't actually an instance; it's a tuple of exports - /// which can be used in place of an instance. - BundleOfExports(Span, Vec>), +pub struct Instance<'a> { + /// Where this `instance` was defined. + pub span: Span, + /// An identifier that this instance is resolved with (optionally) for name + /// resolution. + pub id: Option>, + /// An optional name for this instance stored in the custom `name` section. + pub name: Option>, + /// If present, inline export annotations which indicate names this + /// definition should be exported under. + pub exports: core::InlineExport<'a>, + /// What kind of instance this is. + pub kind: InstanceKind<'a>, } impl<'a> Parse<'a> for Instance<'a> { @@ -135,49 +173,9 @@ impl<'a> Parse<'a> for Instance<'a> { let id = parser.parse()?; let name = parser.parse()?; let exports = parser.parse()?; + let kind = parser.parse()?; - let kind = if let Some(import) = parser.parse()? { - InstanceKind::Import { - import, - ty: parser.parse()?, - } - } else if parser.peek::() && parser.peek2::() { - parser.parens(|p| { - p.parse::()?; - if p.peek2::() { - let module = p.parse()?; - let mut args = Vec::new(); - while !p.is_empty() { - args.push(p.parens(|p| p.parse())?); - } - Ok(InstanceKind::Module { module, args }) - } else if p.peek2::() { - let component = p.parse()?; - let mut args = Vec::new(); - while !p.is_empty() { - args.push(p.parens(|p| p.parse())?); - } - Ok(InstanceKind::Component { component, args }) - } else { - return Err(parser.error("expected module or component")); - } - })? - } else if parser.peek::() { - parser.parse::()?; - let mut args = Vec::new(); - while !parser.is_empty() { - args.push(parser.parens(|p| p.parse())?); - } - InstanceKind::BundleOfExports { args } - } else { - let mut args = Vec::new(); - while !parser.is_empty() { - args.push(parser.parens(|p| p.parse())?); - } - InstanceKind::BundleOfComponentExports { args } - }; - - Ok(Instance { + Ok(Self { span, id, name, @@ -187,67 +185,100 @@ impl<'a> Parse<'a> for Instance<'a> { } } -impl<'a> Parse<'a> for ModuleArg<'a> { - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() && parser.peek3::() { - // `(instance )` - let def = parser.parse::>()?; - Ok(ModuleArg::Def(def)) - } else if parser.peek::() && parser.peek2::() { - let (span, exports) = parser.parens(|p| { - let span = p.parse::()?.0; - let mut exports = Vec::new(); - while !parser.is_empty() { - exports.push(parser.parens(|parser| parser.parse())?); - } - Ok((span, exports)) - })?; - Ok(ModuleArg::BundleOfExports(span, exports)) - } else { - Err(parser.error("expected an instance")) - } - } +/// The kinds of instances in the text format. +#[derive(Debug)] +pub enum InstanceKind<'a> { + /// The `(instance (import "x"))` sugar syntax + Import { + /// The name of the import + import: InlineImport<'a>, + /// The type of the instance being imported + ty: ComponentTypeUse<'a, InstanceType<'a>>, + }, + /// Instantiate a component. + Instantiate { + /// The component being instantiated. + component: Index<'a>, + /// Arguments used to instantiate the instance. + args: Vec>, + }, + /// The instance is defined by exporting local items as an instance. + BundleOfExports(Vec>), } -impl<'a> Parse<'a> for ComponentArg<'a> { +impl<'a> Parse<'a> for InstanceKind<'a> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() && parser.peek3::() { - // `( )` - let def = parser.parse::>()?; - Ok(ComponentArg::Def(def)) - } else if parser.peek::() && parser.peek2::() { - let (span, exports) = parser.parens(|p| { - let span = p.parse::()?.0; - let mut exports = Vec::new(); - while !p.is_empty() { - exports.push(p.parens(|p| p.parse())?); - } - Ok((span, exports)) - })?; - Ok(ComponentArg::BundleOfExports(span, exports)) + if let Some(import) = parser.parse()? { + return Ok(Self::Import { + import, + ty: parser.parse()?, + }); + } + + if parser.peek::() && parser.peek2::() { + parser.parens(|parser| { + parser.parse::()?; + Ok(Self::Instantiate { + component: parser.parse()?, + args: parser.parse()?, + }) + }) } else { - Err(parser.error("expected def type, type, or instance")) + Ok(Self::BundleOfExports(parser.parse()?)) } } } -/// A entry in a WebAssembly module's export section. +/// An argument to instantiate a component. #[derive(Debug)] -pub struct CoreExport<'a> { - /// Where this export was defined. - pub span: Span, - /// The name of this export from the module. +pub struct InstantiationArg<'a> { + /// The name of the instantiation argument. pub name: &'a str, - /// What's being exported from the module. - pub index: ItemRef<'a, core::ExportKind>, + /// The kind of instantiation argument. + pub kind: InstantiationArgKind<'a>, } -impl<'a> Parse<'a> for CoreExport<'a> { +impl<'a> Parse<'a> for InstantiationArg<'a> { fn parse(parser: Parser<'a>) -> Result { - Ok(CoreExport { - span: parser.parse::()?.0, + parser.parse::()?; + Ok(Self { name: parser.parse()?, - index: parser.parse()?, + kind: parser.parse()?, }) } } + +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut args = Vec::new(); + while !parser.is_empty() { + args.push(parser.parens(|parser| parser.parse())?); + } + Ok(args) + } +} + +/// The kind of instantiation argument. +#[derive(Debug)] +pub enum InstantiationArgKind<'a> { + /// The argument is a reference to a component item. + Item(ComponentExportKind<'a>), + /// The argument is an instance created from local exported items. + /// + /// This is syntactic sugar for defining an instance and also using it + /// as an instantiation argument. + BundleOfExports(Span, Vec>), +} + +impl<'a> Parse<'a> for InstantiationArgKind<'a> { + fn parse(parser: Parser<'a>) -> Result { + if let Some(item) = parser.parse()? { + Ok(Self::Item(item)) + } else { + parser.parens(|parser| { + let span = parser.parse::()?.0; + Ok(Self::BundleOfExports(span, parser.parse()?)) + }) + } + } +} diff --git a/crates/wast/src/component/intertype.rs b/crates/wast/src/component/intertype.rs deleted file mode 100644 index 0798984b4f..0000000000 --- a/crates/wast/src/component/intertype.rs +++ /dev/null @@ -1,369 +0,0 @@ -use crate::kw; -use crate::parser::{Parse, Parser, Result}; -use crate::token::*; - -/// An interface-types type. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub enum Primitive { - Unit, - Bool, - S8, - U8, - S16, - U16, - S32, - U32, - S64, - U64, - Float32, - Float64, - Char, - String, -} - -impl<'a> Parse<'a> for Primitive { - fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(Primitive::Unit) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::Bool) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::S8) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::U8) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::S16) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::U16) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::S32) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::U32) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::S64) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::U64) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::Float32) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::Float64) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::Char) - } else if l.peek::() { - parser.parse::()?; - Ok(Primitive::String) - } else { - Err(l.error()) - } - } -} - -/// An interface-types type. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub enum InterType<'a> { - Primitive(Primitive), - Record(Record<'a>), - Variant(Variant<'a>), - List(List<'a>), - Tuple(Tuple<'a>), - Flags(Flags<'a>), - Enum(Enum<'a>), - Union(Union<'a>), - Option(OptionType<'a>), - Expected(Expected<'a>), -} - -impl<'a> Parse<'a> for InterType<'a> { - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - parser.parens(|parser| { - if parser.peek::() { - let record = parser.parse()?; - Ok(InterType::Record(record)) - } else if parser.peek::() { - let variant = parser.parse()?; - Ok(InterType::Variant(variant)) - } else if parser.peek::() { - let list = parser.parse()?; - Ok(InterType::List(list)) - } else if parser.peek::() { - let tuple = parser.parse()?; - Ok(InterType::Tuple(tuple)) - } else if parser.peek::() { - let flags = parser.parse()?; - Ok(InterType::Flags(flags)) - } else if parser.peek::() { - let enum_ = parser.parse()?; - Ok(InterType::Enum(enum_)) - } else if parser.peek::() { - let union = parser.parse()?; - Ok(InterType::Union(union)) - } else if parser.peek::() { - let optional = parser.parse()?; - Ok(InterType::Option(optional)) - } else if parser.peek::() { - let expected = parser.parse()?; - Ok(InterType::Expected(expected)) - } else { - Err(parser.error("expected derived intertype")) - } - }) - } else { - Ok(InterType::Primitive(parser.parse()?)) - } - } -} - -/// An interface-types type. -#[allow(missing_docs)] -#[derive(Debug, Clone)] -pub enum InterTypeRef<'a> { - Primitive(Primitive), - Inline(InterType<'a>), - Ref(Index<'a>), -} - -impl<'a> Parse<'a> for InterTypeRef<'a> { - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { - Ok(InterTypeRef::Ref(parser.parse()?)) - } else if parser.peek::() { - Ok(InterTypeRef::Inline(parser.parse()?)) - } else { - Ok(InterTypeRef::Primitive(parser.parse()?)) - } - } -} - -/// An interface-types record, aka a struct. -#[derive(Debug, Clone)] -pub struct Record<'a> { - /// The fields of the struct. - pub fields: Vec>, -} - -impl<'a> Parse<'a> for Record<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut fields = Vec::new(); - while !parser.is_empty() { - fields.push(parser.parens(|p| p.parse())?); - } - Ok(Record { fields }) - } -} - -/// An interface-types record field. -#[derive(Debug, Clone)] -pub struct Field<'a> { - /// The name of the field. - pub name: &'a str, - /// The type of the field. - pub type_: InterTypeRef<'a>, -} - -impl<'a> Parse<'a> for Field<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - Ok(Field { - name: parser.parse()?, - type_: parser.parse()?, - }) - } -} - -/// An interface-types variant, aka a discriminated union with named arms. -#[derive(Debug, Clone)] -pub struct Variant<'a> { - /// The cases of the variant type. - pub cases: Vec>, -} - -impl<'a> Parse<'a> for Variant<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut cases = Vec::new(); - while !parser.is_empty() { - cases.push(parser.parens(|p| p.parse())?); - } - Ok(Variant { cases }) - } -} - -/// An interface-types variant case. -#[derive(Debug, Clone)] -pub struct Case<'a> { - /// The name of the case. - pub name: &'a str, - /// Where this `component` was defined - pub span: Span, - /// The type of the case. - pub type_: InterTypeRef<'a>, - /// The optional defaults-to name. - pub defaults_to: Option<&'a str>, -} - -impl<'a> Parse<'a> for Case<'a> { - fn parse(parser: Parser<'a>) -> Result { - let span = parser.parse::()?.0; - let name = parser.parse()?; - let type_ = parser.parse()?; - let defaults_to = if !parser.is_empty() { - Some(parser.parens(|parser| { - parser.parse::()?; - Ok(parser.parse()?) - })?) - } else { - None - }; - Ok(Case { - name, - span, - type_, - defaults_to, - }) - } -} - -/// An interface-types list, aka a fixed-size array. -#[derive(Debug, Clone)] -pub struct List<'a> { - /// The element type of the array. - pub element: Box>, -} - -impl<'a> Parse<'a> for List<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let ty = parser.parse()?; - Ok(List { - element: Box::new(ty), - }) - } -} - -/// An interface-types tuple, aka a record with anonymous fields. -#[derive(Debug, Clone)] -pub struct Tuple<'a> { - /// The types of the fields of the tuple. - pub fields: Vec>, -} - -impl<'a> Parse<'a> for Tuple<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut fields = Vec::new(); - while !parser.is_empty() { - fields.push(parser.parse()?); - } - Ok(Tuple { fields }) - } -} - -/// An interface-types flags, aka a fixed-sized bitfield with named fields. -#[derive(Debug, Clone)] -pub struct Flags<'a> { - /// The names of the individual flags. - pub flag_names: Vec<&'a str>, -} - -impl<'a> Parse<'a> for Flags<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut flag_names = Vec::new(); - while !parser.is_empty() { - flag_names.push(parser.parse()?); - } - Ok(Flags { flag_names }) - } -} - -/// An interface-types enum, aka a discriminated union with unit arms. -#[derive(Debug, Clone)] -pub struct Enum<'a> { - /// The arms of the enum. - pub arms: Vec<&'a str>, -} - -impl<'a> Parse<'a> for Enum<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut arms = Vec::new(); - while !parser.is_empty() { - arms.push(parser.parse()?); - } - Ok(Enum { arms }) - } -} - -/// An interface-types union, aka a discriminated union with anonymous arms. -#[derive(Debug, Clone)] -pub struct Union<'a> { - /// The arms of the union. - pub arms: Vec>, -} - -impl<'a> Parse<'a> for Union<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let mut arms = Vec::new(); - while !parser.is_empty() { - arms.push(parser.parse()?); - } - Ok(Union { arms }) - } -} - -/// An interface-types optional, aka an option. -#[derive(Debug, Clone)] -pub struct OptionType<'a> { - /// The type of the value, when a value is present. - pub element: Box>, -} - -impl<'a> Parse<'a> for OptionType<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let ty = parser.parse()?; - Ok(OptionType { - element: Box::new(ty), - }) - } -} - -/// An interface-types expected, aka an result. -#[derive(Debug, Clone)] -pub struct Expected<'a> { - /// The type on success. - pub ok: Box>, - /// The type on failure. - pub err: Box>, -} - -impl<'a> Parse<'a> for Expected<'a> { - fn parse(parser: Parser<'a>) -> Result { - parser.parse::()?; - let ok = parser.parse()?; - let err = parser.parse()?; - Ok(Expected { - ok: Box::new(ok), - err: Box::new(err), - }) - } -} diff --git a/crates/wast/src/component/item_ref.rs b/crates/wast/src/component/item_ref.rs index b7745b75be..6b2632ea46 100644 --- a/crates/wast/src/component/item_ref.rs +++ b/crates/wast/src/component/item_ref.rs @@ -1,98 +1,112 @@ use crate::parser::{Cursor, Parse, Parser, Peek, Result}; use crate::token::Index; -/// Parses `(func $foo)` +fn peek(cursor: Cursor) -> bool { + // This is a little fancy because when parsing something like: + // + // (type (component (type $foo))) + // + // we need to disambiguate that from + // + // (type (component (type $foo (func)))) + // + // where the first is a type reference and the second is an inline + // component type defining a type internally. The peek here not only + // peeks for `K` but also for the index and possibly trailing + // strings. + + // Peek for the given keyword type + if !K::peek(cursor) { + return false; + } + + // Move past the given keyword + let cursor = match cursor.keyword() { + Some((_, c)) => c, + _ => return false, + }; + + // Peek an id or integer index, followed by `)` or string to disambiguate + match cursor + .id() + .map(|p| p.1) + .or_else(|| cursor.integer().map(|p| p.1)) + { + Some(cursor) => cursor.rparen().is_some() || cursor.string().is_some(), + None => false, + } +} + +/// Parses core item references. #[derive(Clone, Debug)] -#[allow(missing_docs)] -pub struct ItemRef<'a, K> { +pub struct CoreItemRef<'a, K> { + /// The item kind being parsed. pub kind: K, + /// The item or instance reference. pub idx: Index<'a>, - pub export_names: Vec<&'a str>, + /// Export name to resolve the item from. + pub export_name: Option<&'a str>, } -impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { +impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> { fn parse(parser: Parser<'a>) -> Result { - parser.parens(|parser| { - let kind = parser.parse::()?; - let idx = parser.parse()?; - let mut export_names = Vec::new(); - while !parser.is_empty() { - export_names.push(parser.parse()?); - } - Ok(ItemRef { - kind, - idx, - export_names, - }) + // This does not parse the surrounding `(` and `)` because + // core prefix is context dependent and only the caller knows if it should be + // present for core references; therefore, the caller parses the parens and any core prefix + let kind = parser.parse::()?; + let idx = parser.parse()?; + let export_name = parser.parse()?; + Ok(Self { + kind, + idx, + export_name, }) } } -impl<'a, K: Peek> Peek for ItemRef<'a, K> { +impl<'a, K: Peek> Peek for CoreItemRef<'a, K> { fn peek(cursor: Cursor<'_>) -> bool { - match cursor.lparen() { - // This is a little fancy because when parsing something like: - // - // (type (component (type $foo))) - // - // we need to disambiguate that from - // - // (type (component (type $foo (func)))) - // - // where the first is a type reference and the second is an inline - // component type defining a type internally. The peek here not only - // peeks for `K` but also for the index and possibly trailing - // strings. - Some(remaining) if K::peek(remaining) => { - let remaining = match remaining.keyword() { - Some((_, remaining)) => remaining, - None => return false, - }; - match remaining - .id() - .map(|p| p.1) - .or_else(|| remaining.integer().map(|p| p.1)) - { - Some(remaining) => remaining.rparen().is_some() || remaining.string().is_some(), - None => false, - } - } - _ => false, - } + peek::(cursor) } fn display() -> &'static str { - "an item reference" + "a core item reference" } } -/// Convenience structure to parse `$f` or `(item $f)`. +/// Parses component item references. #[derive(Clone, Debug)] -pub struct IndexOrRef<'a, K>(pub ItemRef<'a, K>); +pub struct ItemRef<'a, K> { + /// The item kind being parsed. + pub kind: K, + /// The item or instance reference. + pub idx: Index<'a>, + /// Export names to resolve the item from. + pub export_names: Vec<&'a str>, +} -impl<'a, K> Parse<'a> for IndexOrRef<'a, K> -where - K: Parse<'a> + Default, -{ +impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { - Ok(IndexOrRef(ItemRef { - kind: K::default(), - idx: parser.parse()?, - export_names: Vec::new(), - })) - } else { - Ok(IndexOrRef(parser.parse()?)) + let kind = parser.parse::()?; + let idx = parser.parse()?; + let mut export_names = Vec::new(); + while !parser.is_empty() { + export_names.push(parser.parse()?); } + Ok(Self { + kind, + idx, + export_names, + }) } } -impl<'a, K: Peek> Peek for IndexOrRef<'a, K> { +impl<'a, K: Peek> Peek for ItemRef<'a, K> { fn peek(cursor: Cursor<'_>) -> bool { - Index::peek(cursor) || ItemRef::::peek(cursor) + peek::(cursor) } fn display() -> &'static str { - "an item reference" + "a component item reference" } } diff --git a/crates/wast/src/component/module.rs b/crates/wast/src/component/module.rs index 3dd8ed14cd..a8c606136c 100644 --- a/crates/wast/src/component/module.rs +++ b/crates/wast/src/component/module.rs @@ -4,12 +4,14 @@ use crate::kw; use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, NameAnnotation, Span}; -/// A nested WebAssembly module to be created as part of a component. +/// A core WebAssembly module to be created as part of a component. +/// +/// This is a member of the core module section. #[derive(Debug)] -pub struct Module<'a> { - /// Where this `nested module` was defined. +pub struct CoreModule<'a> { + /// Where this `core module` was defined. pub span: Span, - /// An identifier that this nested module is resolved with (optionally) for name + /// An identifier that this module is resolved with (optionally) for name /// resolution. pub id: Option>, /// An optional name for this module stored in the custom `name` section. @@ -17,50 +19,40 @@ pub struct Module<'a> { /// If present, inline export annotations which indicate names this /// definition should be exported under. pub exports: core::InlineExport<'a>, - /// What kind of nested module this is, be it an inline-defined or imported one. - pub kind: ModuleKind<'a>, + /// What kind of module this is, be it an inline-defined or imported one. + pub kind: CoreModuleKind<'a>, } -/// Possible ways to define a nested module in the text format. +/// Possible ways to define a core module in the text format. #[derive(Debug)] -pub enum ModuleKind<'a> { - /// An nested module which is actually defined as an import, such as: +pub enum CoreModuleKind<'a> { + /// A core module which is actually defined as an import Import { - /// Where this nested module is imported from + /// Where this core module is imported from import: InlineImport<'a>, - /// The type that this nested module will have. - ty: ComponentTypeUse<'a, ModuleType<'a>>, + /// The type that this core module will have. + ty: CoreTypeUse<'a, ModuleType<'a>>, }, - /// modules whose instantiation is defined inline. + /// Modules that are defined inline. Inline { - /// Fields in the nested module. + /// Fields in the core module. fields: Vec>, }, } -impl<'a> Parse<'a> for Module<'a> { +impl<'a> Parse<'a> for CoreModule<'a> { fn parse(parser: Parser<'a>) -> Result { - // This is sort of a fundamental limitation of the way this crate is - // designed. Everything is done through recursive descent parsing which - // means, well, that we're recursively going down the stack as we parse - // nested data structures. While we can handle this for wasm expressions - // since that's a pretty local decision, handling this for nested - // modules which be far trickier. For now we just say that when the - // parser goes too deep we return an error saying there's too many - // nested modules. It would be great to not return an error here, - // though! - if parser.parens_depth() > 100 { - return Err(parser.error("module nesting too deep")); - } + parser.depth_check()?; - let span = parser.parse::()?.0; + let span = parser.parse::()?.0; + parser.parse::()?; let id = parser.parse()?; let name = parser.parse()?; let exports = parser.parse()?; let kind = if let Some(import) = parser.parse()? { - ModuleKind::Import { + CoreModuleKind::Import { import, ty: parser.parse()?, } @@ -69,10 +61,10 @@ impl<'a> Parse<'a> for Module<'a> { while !parser.is_empty() { fields.push(parser.parens(|p| p.parse())?); } - ModuleKind::Inline { fields } + CoreModuleKind::Inline { fields } }; - Ok(Module { + Ok(Self { span, id, name, diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index ba9e673491..0bb22cfc45 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -16,6 +16,38 @@ pub fn resolve(component: &mut Component<'_>) -> Result<(), Error> { resolver.fields(component.id, fields) } +enum AnyAlias<'a> { + Core(CoreAlias<'a>), + Component(Alias<'a>), +} + +impl<'a> From> for ComponentField<'a> { + fn from(a: AnyAlias<'a>) -> Self { + match a { + AnyAlias::Core(a) => Self::CoreAlias(a), + AnyAlias::Component(a) => Self::Alias(a), + } + } +} + +impl<'a> From> for ComponentTypeDecl<'a> { + fn from(a: AnyAlias<'a>) -> Self { + match a { + AnyAlias::Core(_) => unreachable!("cannot alias core instance export from type decl"), + AnyAlias::Component(a) => Self::Alias(a), + } + } +} + +impl<'a> From> for InstanceTypeDecl<'a> { + fn from(a: AnyAlias<'a>) -> Self { + match a { + AnyAlias::Core(_) => unreachable!("cannot alias core instance export from type decl"), + AnyAlias::Component(a) => Self::Alias(a), + } + } +} + #[derive(Default)] struct Resolver<'a> { stack: Vec>, @@ -23,7 +55,7 @@ struct Resolver<'a> { // When a name refers to a definition in an outer scope, we'll need to // insert an outer alias before it. This collects the aliases to be // inserted during resolution. - aliases_to_insert: Vec>, + aliases_to_insert: Vec>, } /// Context structure used to perform name resolution. @@ -35,14 +67,18 @@ struct ComponentState<'a> { // with it information about the signature of the item in that namespace. // The signature is later used to synthesize the type of a component and // inject type annotations if necessary. + core_funcs: Namespace<'a>, + core_globals: Namespace<'a>, + core_tables: Namespace<'a>, + core_memories: Namespace<'a>, + core_types: Namespace<'a>, + core_tags: Namespace<'a>, + core_instances: Namespace<'a>, + core_modules: Namespace<'a>, + funcs: Namespace<'a>, - globals: Namespace<'a>, - tables: Namespace<'a>, - memories: Namespace<'a>, types: Namespace<'a>, - tags: Namespace<'a>, instances: Namespace<'a>, - modules: Namespace<'a>, components: Namespace<'a>, values: Namespace<'a>, } @@ -81,7 +117,7 @@ impl<'a> Resolver<'a> { register: fn(&mut ComponentState<'a>, &T) -> Result<(), Error>, ) -> Result<(), Error> where - T: From>, + T: From>, { assert!(self.aliases_to_insert.is_empty()); @@ -101,7 +137,7 @@ impl<'a> Resolver<'a> { // Definitions can't refer to themselves or to definitions that appear // later in the format. Now that we're done resolving this field, - // assign it an index for later defintions to refer to. + // assign it an index for later definitions to refer to. register(self.current(), &fields[i])?; i += 1; @@ -112,127 +148,138 @@ impl<'a> Resolver<'a> { fn field(&mut self, field: &mut ComponentField<'a>) -> Result<(), Error> { match field { + ComponentField::CoreModule(m) => self.core_module(m), + ComponentField::CoreInstance(i) => self.core_instance(i), + ComponentField::CoreAlias(a) => self.core_alias(a), + ComponentField::CoreType(t) => self.core_ty(t), + ComponentField::Component(c) => self.component(c), + ComponentField::Instance(i) => self.instance(i), + ComponentField::Alias(a) => self.alias(a), + ComponentField::Type(t) => self.ty(t), + ComponentField::CanonicalFunc(f) => self.canonical_func(f), + ComponentField::CoreFunc(_) => unreachable!("should be expanded already"), + ComponentField::Func(_) => unreachable!("should be expanded already"), + ComponentField::Start(s) => self.start(s), ComponentField::Import(i) => self.item_sig(&mut i.item), + ComponentField::Export(e) => self.export(&mut e.kind), + ComponentField::Custom(_) => Ok(()), + } + } - ComponentField::Type(t) => self.type_field(t), + fn core_module(&mut self, module: &mut CoreModule) -> Result<(), Error> { + match &mut module.kind { + CoreModuleKind::Inline { fields } => { + crate::core::resolve::resolve(fields)?; + } - ComponentField::Func(f) => { - let body = match &mut f.kind { - ComponentFuncKind::Import { .. } => return Ok(()), - ComponentFuncKind::Inline { body } => body, - }; - let opts = match body { - ComponentFuncBody::CanonLift(lift) => { - self.type_use(&mut lift.type_)?; - self.item_ref(&mut lift.func)?; - &mut lift.opts - } - ComponentFuncBody::CanonLower(lower) => { - self.item_ref(&mut lower.func)?; - &mut lower.opts - } - }; - for opt in opts { - match opt { - CanonOpt::StringUtf8 - | CanonOpt::StringUtf16 - | CanonOpt::StringLatin1Utf16 => {} - CanonOpt::Into(instance) => { - self.item_ref(instance)?; - } - } - } - Ok(()) + CoreModuleKind::Import { .. } => { + unreachable!("should be expanded already") } + } - ComponentField::Instance(i) => match &mut i.kind { - InstanceKind::Module { module, args } => { - self.item_ref(module)?; - for arg in args { - match &mut arg.arg { - ModuleArg::Def(def) => { - self.item_ref(def)?; - } - ModuleArg::BundleOfExports(..) => { - unreachable!("should be expanded already"); - } + Ok(()) + } + + fn component(&mut self, component: &mut NestedComponent<'a>) -> Result<(), Error> { + match &mut component.kind { + NestedComponentKind::Import { .. } => unreachable!("should be expanded already"), + NestedComponentKind::Inline(fields) => self.fields(component.id, fields), + } + } + + fn core_instance(&mut self, instance: &mut CoreInstance<'a>) -> Result<(), Error> { + match &mut instance.kind { + CoreInstanceKind::Instantiate { module, args } => { + self.resolve_ns(module, Ns::CoreModule)?; + for arg in args { + match &mut arg.kind { + CoreInstantiationArgKind::Instance(i) => { + self.core_item_ref(i)?; } - } - Ok(()) - } - InstanceKind::Component { component, args } => { - self.item_ref(component)?; - for arg in args { - match &mut arg.arg { - ComponentArg::Def(def) => { - self.item_ref(def)?; - } - ComponentArg::BundleOfExports(..) => { - unreachable!("should be expanded already") - } + CoreInstantiationArgKind::BundleOfExports(..) => { + unreachable!("should be expanded already"); } } - Ok(()) - } - InstanceKind::BundleOfExports { args } => { - for arg in args { - self.item_ref(&mut arg.index)?; - } - Ok(()) - } - InstanceKind::BundleOfComponentExports { args } => { - for arg in args { - self.arg(&mut arg.arg)?; - } - Ok(()) } - InstanceKind::Import { .. } => { - unreachable!("should be removed by expansion") + } + CoreInstanceKind::BundleOfExports(exports) => { + for export in exports { + self.core_item_ref(&mut export.item)?; } - }, - ComponentField::Module(m) => { - match &mut m.kind { - ModuleKind::Inline { fields } => { - crate::core::resolve::resolve(fields)?; - } + } + } + Ok(()) + } - ModuleKind::Import { .. } => { - unreachable!("should be expanded already") + fn instance(&mut self, instance: &mut Instance<'a>) -> Result<(), Error> { + match &mut instance.kind { + InstanceKind::Instantiate { component, args } => { + self.resolve_ns(component, Ns::Component)?; + for arg in args { + match &mut arg.kind { + InstantiationArgKind::Item(e) => { + self.export(e)?; + } + InstantiationArgKind::BundleOfExports(..) => { + unreachable!("should be expanded already") + } } } - - Ok(()) } - ComponentField::Component(c) => match &mut c.kind { - NestedComponentKind::Import { .. } => { - unreachable!("should be expanded already") + InstanceKind::BundleOfExports(exports) => { + for export in exports { + self.export(&mut export.kind)?; } - NestedComponentKind::Inline(fields) => self.fields(c.id, fields), + } + InstanceKind::Import { .. } => { + unreachable!("should be expanded already") + } + } + Ok(()) + } + + fn item_sig(&mut self, item: &mut ItemSig<'a>) -> Result<(), Error> { + match &mut item.kind { + // Here we must be explicit otherwise the module type reference will + // be assumed to be in the component type namespace + ItemSigKind::CoreModule(t) => self.core_type_use(t), + ItemSigKind::Func(t) => self.component_type_use(t), + ItemSigKind::Component(t) => self.component_type_use(t), + ItemSigKind::Instance(t) => self.component_type_use(t), + ItemSigKind::Value(t) => self.component_val_type(t), + ItemSigKind::Type(b) => match b { + TypeBounds::Eq(i) => self.resolve_ns(i, Ns::Type), }, - ComponentField::Alias(a) => self.alias(a), + } + } - ComponentField::Start(s) => { - self.item_ref(&mut s.func)?; - for arg in s.args.iter_mut() { - self.item_ref(arg)?; - } - Ok(()) - } + fn export(&mut self, kind: &mut ComponentExportKind<'a>) -> Result<(), Error> { + match kind { + // Here we do *not* have to be explicit as the item ref is to a core module + ComponentExportKind::CoreModule(r) => self.component_item_ref(r), + ComponentExportKind::Func(r) => self.component_item_ref(r), + ComponentExportKind::Value(r) => self.component_item_ref(r), + ComponentExportKind::Type(r) => self.component_item_ref(r), + ComponentExportKind::Component(r) => self.component_item_ref(r), + ComponentExportKind::Instance(r) => self.component_item_ref(r), + } + } - ComponentField::Export(e) => { - self.arg(&mut e.arg)?; - Ok(()) - } + fn start(&mut self, start: &mut Start<'a>) -> Result<(), Error> { + self.resolve_ns(&mut start.func, Ns::Func)?; + for arg in start.args.iter_mut() { + self.component_item_ref(arg)?; } + Ok(()) } - fn item_sig(&mut self, sig: &mut ItemSig<'a>) -> Result<(), Error> { - match &mut sig.kind { - ItemKind::Component(t) => self.type_use(t), - ItemKind::Module(t) => self.type_use(t), - ItemKind::Instance(t) => self.type_use(t), - ItemKind::Func(t) => self.type_use(t), - ItemKind::Value(t) => self.type_use(t), + fn core_alias(&mut self, alias: &mut CoreAlias<'a>) -> Result<(), Error> { + match &mut alias.target { + CoreAliasTarget::Export { + instance, + name: _, + kind: _, + } => self.resolve_ns(instance, Ns::CoreInstance), } } @@ -240,9 +287,10 @@ impl<'a> Resolver<'a> { match &mut alias.target { AliasTarget::Export { instance, - export: _, + name: _, + kind: _, } => self.resolve_ns(instance, Ns::Instance), - AliasTarget::Outer { outer, index } => { + AliasTarget::Outer { outer, index, kind } => { // Short-circuit when both indices are already resolved as this // helps to write tests for invalid modules where wasmparser should // be the one returning the error. @@ -282,139 +330,178 @@ impl<'a> Resolver<'a> { } // Resolve `index` within the computed scope depth. - let ns = match alias.kind { - AliasKind::Module => Ns::Module, - AliasKind::Component => Ns::Component, - AliasKind::Instance => Ns::Instance, - AliasKind::Value => Ns::Value, - AliasKind::ExportKind(kind) => kind.into(), - }; let computed = self.stack.len() - 1 - depth as usize; - self.stack[computed].resolve(ns, index)?; + self.stack[computed].resolve((*kind).into(), index)?; Ok(()) } } } - fn arg(&mut self, arg: &mut ComponentArg<'a>) -> Result<(), Error> { - match arg { - ComponentArg::Def(item_ref) => { - self.item_ref(item_ref)?; + fn canonical_func(&mut self, func: &mut CanonicalFunc<'a>) -> Result<(), Error> { + let opts = match &mut func.kind { + CanonicalFuncKind::Lift { ty, info } => { + self.component_type_use(ty)?; + self.core_item_ref(&mut info.func)?; + &mut info.opts + } + CanonicalFuncKind::Lower(info) => { + self.component_item_ref(&mut info.func)?; + &mut info.opts + } + }; + + for opt in opts { + match opt { + CanonOpt::StringUtf8 | CanonOpt::StringUtf16 | CanonOpt::StringLatin1Utf16 => {} + CanonOpt::Memory(r) => self.core_item_ref(r)?, + CanonOpt::Realloc(r) | CanonOpt::PostReturn(r) => self.core_item_ref(r)?, } - ComponentArg::BundleOfExports(..) => unreachable!("should be expanded already"), } + Ok(()) } - fn type_use(&mut self, ty: &mut ComponentTypeUse<'a, T>) -> Result<(), Error> { + fn core_type_use(&mut self, ty: &mut CoreTypeUse<'a, T>) -> Result<(), Error> { + let item = match ty { + CoreTypeUse::Ref(r) => r, + CoreTypeUse::Inline(_) => { + unreachable!("inline type-use should be expanded by now") + } + }; + self.core_item_ref(item) + } + + fn component_type_use(&mut self, ty: &mut ComponentTypeUse<'a, T>) -> Result<(), Error> { let item = match ty { ComponentTypeUse::Ref(r) => r, ComponentTypeUse::Inline(_) => { unreachable!("inline type-use should be expanded by now") } }; - self.item_ref(item) + self.component_item_ref(item) } - fn intertype(&mut self, ty: &mut InterType<'a>) -> Result<(), Error> { + fn defined_type(&mut self, ty: &mut ComponentDefinedType<'a>) -> Result<(), Error> { match ty { - InterType::Primitive(_) => {} - InterType::Flags(_) => {} - InterType::Enum(_) => {} - InterType::Record(r) => { + ComponentDefinedType::Primitive(_) => {} + ComponentDefinedType::Flags(_) => {} + ComponentDefinedType::Enum(_) => {} + ComponentDefinedType::Record(r) => { for field in r.fields.iter_mut() { - self.intertype_ref(&mut field.type_)?; + self.component_val_type(&mut field.ty)?; } } - InterType::Variant(v) => { + ComponentDefinedType::Variant(v) => { + // Namespace for case identifier resolution + let mut ns = Namespace::default(); for case in v.cases.iter_mut() { - self.intertype_ref(&mut case.type_)?; + let index = ns.register(case.id, "variant case")?; + self.component_val_type(&mut case.ty)?; + + if let Some(refines) = &mut case.refines { + if let Refinement::Index(span, idx) = refines { + let resolved = ns.resolve(idx, "variant case")?; + if resolved == index { + return Err(Error::new( + *span, + "variant case cannot refine itself".to_string(), + )); + } + + *refines = Refinement::Resolved(resolved); + } + } } } - InterType::List(l) => { - self.intertype_ref(&mut *l.element)?; + ComponentDefinedType::List(l) => { + self.component_val_type(&mut *l.element)?; } - InterType::Tuple(t) => { + ComponentDefinedType::Tuple(t) => { for field in t.fields.iter_mut() { - self.intertype_ref(field)?; + self.component_val_type(field)?; } } - InterType::Union(t) => { - for arm in t.arms.iter_mut() { - self.intertype_ref(arm)?; + ComponentDefinedType::Union(t) => { + for ty in t.types.iter_mut() { + self.component_val_type(ty)?; } } - InterType::Option(o) => { - self.intertype_ref(&mut *o.element)?; + ComponentDefinedType::Option(o) => { + self.component_val_type(&mut *o.element)?; } - InterType::Expected(r) => { - self.intertype_ref(&mut *r.ok)?; - self.intertype_ref(&mut *r.err)?; + ComponentDefinedType::Expected(r) => { + self.component_val_type(&mut *r.ok)?; + self.component_val_type(&mut *r.err)?; } } Ok(()) } - fn intertype_ref(&mut self, ty: &mut InterTypeRef<'a>) -> Result<(), Error> { + fn component_val_type(&mut self, ty: &mut ComponentValType<'a>) -> Result<(), Error> { match ty { - InterTypeRef::Primitive(_) => Ok(()), - InterTypeRef::Ref(idx) => self.resolve_ns(idx, Ns::Type), - InterTypeRef::Inline(_) => unreachable!("should be expanded by now"), + ComponentValType::Primitive(_) => Ok(()), + ComponentValType::Ref(idx) => self.resolve_ns(idx, Ns::Type), + ComponentValType::Inline(_) => unreachable!("should be expanded by now"), } } - fn type_field(&mut self, field: &mut TypeField<'a>) -> Result<(), Error> { + fn core_ty(&mut self, field: &mut CoreType<'a>) -> Result<(), Error> { match &mut field.def { - ComponentTypeDef::DefType(DefType::Func(f)) => { + CoreTypeDef::Def(_) => Ok(()), + CoreTypeDef::Module(t) => self.module_type(t), + } + } + + fn ty(&mut self, field: &mut Type<'a>) -> Result<(), Error> { + match &mut field.def { + TypeDef::Defined(t) => { + self.defined_type(t)?; + } + TypeDef::Func(f) => { for param in f.params.iter_mut() { - self.intertype_ref(&mut param.type_)?; + self.component_val_type(&mut param.ty)?; } - self.intertype_ref(&mut f.result)?; - } - ComponentTypeDef::DefType(DefType::Module(m)) => { - self.stack.push(ComponentState::new(field.id)); - self.moduletype(m)?; - self.stack.pop(); + self.component_val_type(&mut f.result)?; } - ComponentTypeDef::DefType(DefType::Component(c)) => { + TypeDef::Component(c) => { self.stack.push(ComponentState::new(field.id)); - self.nested_component_type(c)?; + self.component_type(c)?; self.stack.pop(); } - ComponentTypeDef::DefType(DefType::Instance(i)) => { + TypeDef::Instance(i) => { self.stack.push(ComponentState::new(field.id)); self.instance_type(i)?; self.stack.pop(); } - ComponentTypeDef::DefType(DefType::Value(v)) => { - self.intertype_ref(&mut v.value_type)? - } - ComponentTypeDef::InterType(i) => self.intertype(i)?, } Ok(()) } - fn nested_component_type(&mut self, c: &mut ComponentType<'a>) -> Result<(), Error> { + fn component_type(&mut self, c: &mut ComponentType<'a>) -> Result<(), Error> { self.resolve_prepending_aliases( - &mut c.fields, - |resolver, field| match field { - ComponentTypeField::Alias(alias) => resolver.alias(alias), - ComponentTypeField::Type(ty) => resolver.type_field(ty), - ComponentTypeField::Import(import) => resolver.item_sig(&mut import.item), - ComponentTypeField::Export(export) => resolver.item_sig(&mut export.item), + &mut c.decls, + |resolver, decl| match decl { + ComponentTypeDecl::Alias(alias) => resolver.alias(alias), + ComponentTypeDecl::CoreType(ty) => resolver.core_ty(ty), + ComponentTypeDecl::Type(ty) => resolver.ty(ty), + ComponentTypeDecl::Import(import) => resolver.item_sig(&mut import.item), + ComponentTypeDecl::Export(export) => resolver.item_sig(&mut export.item), }, - |state, field| { - match field { - ComponentTypeField::Alias(alias) => { + |state, decl| { + match decl { + ComponentTypeDecl::Alias(alias) => { state.register_alias(alias)?; } - ComponentTypeField::Type(ty) => { + ComponentTypeDecl::CoreType(ty) => { + state.core_types.register(ty.id, "core type")?; + } + ComponentTypeDecl::Type(ty) => { state.types.register(ty.id, "type")?; } // Only the type namespace is populated within the component type // namespace so these are ignored here. - ComponentTypeField::Import(_) | ComponentTypeField::Export(_) => {} + ComponentTypeDecl::Import(_) | ComponentTypeDecl::Export(_) => {} } Ok(()) }, @@ -423,84 +510,103 @@ impl<'a> Resolver<'a> { fn instance_type(&mut self, c: &mut InstanceType<'a>) -> Result<(), Error> { self.resolve_prepending_aliases( - &mut c.fields, - |resolver, field| match field { - InstanceTypeField::Alias(alias) => resolver.alias(alias), - InstanceTypeField::Type(ty) => resolver.type_field(ty), - InstanceTypeField::Export(export) => resolver.item_sig(&mut export.item), + &mut c.decls, + |resolver, decl| match decl { + InstanceTypeDecl::Alias(alias) => resolver.alias(alias), + InstanceTypeDecl::CoreType(ty) => resolver.core_ty(ty), + InstanceTypeDecl::Type(ty) => resolver.ty(ty), + InstanceTypeDecl::Export(export) => resolver.item_sig(&mut export.item), }, - |state, field| { - match field { - InstanceTypeField::Alias(alias) => { + |state, decl| { + match decl { + InstanceTypeDecl::Alias(alias) => { state.register_alias(alias)?; } - InstanceTypeField::Type(ty) => { + InstanceTypeDecl::CoreType(ty) => { + state.core_types.register(ty.id, "core type")?; + } + InstanceTypeDecl::Type(ty) => { state.types.register(ty.id, "type")?; } - InstanceTypeField::Export(_export) => {} + InstanceTypeDecl::Export(_export) => {} } Ok(()) }, ) } - fn item_ref(&mut self, item: &mut ItemRef<'a, K>) -> Result<(), Error> + fn core_item_ref(&mut self, item: &mut CoreItemRef<'a, K>) -> Result<(), Error> where - K: Into + Copy, + K: CoreItem + Copy, { - let last_ns = item.kind.into(); + // Check for not being an instance export reference + if item.export_name.is_none() { + self.resolve_ns(&mut item.idx, item.kind.ns())?; + return Ok(()); + } + + // This is a reference to a core instance export + let mut index = item.idx; + self.resolve_ns(&mut index, Ns::CoreInstance)?; + + // Record an alias to reference the export + let span = item.idx.span(); + let alias = CoreAlias { + span, + id: None, + name: None, + target: CoreAliasTarget::Export { + instance: index, + name: item.export_name.unwrap(), + kind: item.kind.ns().into(), + }, + }; + + index = Index::Num(self.current().register_core_alias(&alias)?, span); + self.aliases_to_insert.push(AnyAlias::Core(alias)); - // If there are no extra `export_names` listed then this is a reference to - // something defined within this component's index space, so resolve as - // necessary. + item.idx = index; + item.export_name = None; + + Ok(()) + } + + fn component_item_ref(&mut self, item: &mut ItemRef<'a, K>) -> Result<(), Error> + where + K: ComponentItem + Copy, + { + // Check for not being an instance export reference if item.export_names.is_empty() { - self.resolve_ns(&mut item.idx, last_ns)?; + self.resolve_ns(&mut item.idx, item.kind.ns())?; return Ok(()); } - // ... otherwise the `index` of `item` refers to an intance and the - // `export_names` refer to recursive exports from this item. Resolve the - // instance locally and then process the export names one at a time, - // injecting aliases as necessary. - let mut index = item.idx.clone(); + // This is a reference to an instance export + let mut index = item.idx; self.resolve_ns(&mut index, Ns::Instance)?; + let span = item.idx.span(); for (pos, export_name) in item.export_names.iter().enumerate() { - // The last name is in the namespace of the reference. All others are - // instances. - let ns = if pos == item.export_names.len() - 1 { - last_ns - } else { - Ns::Instance - }; - - // Record an outer alias to be inserted in front of the current - // definition. - let mut alias = Alias { + // Record an alias to reference the export + let alias = Alias { span, id: None, name: None, target: AliasTarget::Export { instance: index, - export: export_name, - }, - kind: match ns { - Ns::Module => AliasKind::Module, - Ns::Component => AliasKind::Component, - Ns::Instance => AliasKind::Instance, - Ns::Value => AliasKind::Value, - Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), - Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), - Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), - Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), - Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), - Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), + name: export_name, + kind: if pos == item.export_names.len() - 1 { + item.kind.ns().into() + } else { + ComponentExportAliasKind::Instance + }, }, }; - index = Index::Num(self.current().register_alias(&mut alias)?, span); - self.aliases_to_insert.push(alias); + index = Index::Num(self.current().register_alias(&alias)?, span); + self.aliases_to_insert.push(AnyAlias::Component(alias)); } + item.idx = index; item.export_names = Vec::new(); @@ -512,7 +618,7 @@ impl<'a> Resolver<'a> { // that we have. Note that a local clone is used since we don't want to use // the parent's resolved index if a parent matches, instead we want to use // the index of the alias that we will automatically insert. - let mut idx_clone = idx.clone(); + let mut idx_clone = *idx; for (depth, resolver) in self.stack.iter_mut().rev().enumerate() { let depth = depth as u32; let found = match resolver.resolve(ns, &mut idx_clone) { @@ -528,36 +634,25 @@ impl<'a> Resolver<'a> { return Ok(()); } let id = match idx { - Index::Id(id) => id.clone(), + Index::Id(id) => *id, Index::Num(..) => unreachable!(), }; // When resolution succeeds in a parent then an outer alias is // automatically inserted here in this component. let span = idx.span(); - let mut alias = Alias { + let alias = Alias { span, id: Some(id), name: None, target: AliasTarget::Outer { outer: Index::Num(depth, span), index: Index::Num(found, span), - }, - kind: match ns { - Ns::Module => AliasKind::Module, - Ns::Component => AliasKind::Component, - Ns::Instance => AliasKind::Instance, - Ns::Value => AliasKind::Value, - Ns::Func => AliasKind::ExportKind(core::ExportKind::Func), - Ns::Table => AliasKind::ExportKind(core::ExportKind::Table), - Ns::Global => AliasKind::ExportKind(core::ExportKind::Global), - Ns::Memory => AliasKind::ExportKind(core::ExportKind::Memory), - Ns::Tag => AliasKind::ExportKind(core::ExportKind::Tag), - Ns::Type => AliasKind::ExportKind(core::ExportKind::Type), + kind: ns.into(), }, }; - let local_index = self.current().register_alias(&mut alias)?; - self.aliases_to_insert.push(alias); + let local_index = self.current().register_alias(&alias)?; + self.aliases_to_insert.push(AnyAlias::Component(alias)); *idx = Index::Num(local_index, span); return Ok(()); } @@ -568,15 +663,15 @@ impl<'a> Resolver<'a> { unreachable!() } - fn moduletype(&mut self, ty: &mut ModuleType<'_>) -> Result<(), Error> { + fn module_type(&mut self, ty: &mut ModuleType<'_>) -> Result<(), Error> { let mut types = Namespace::default(); - for def in ty.defs.iter_mut() { - match def { - ModuleTypeDef::Type(t) => { + for decl in ty.decls.iter_mut() { + match decl { + ModuleTypeDecl::Type(t) => { types.register(t.id, "type")?; } - ModuleTypeDef::Import(t) => resolve_item_sig(&mut t.item, &types)?, - ModuleTypeDef::Export(_, t) => resolve_item_sig(t, &types)?, + ModuleTypeDecl::Import(t) => resolve_item_sig(&mut t.item, &types)?, + ModuleTypeDecl::Export(_, t) => resolve_item_sig(t, &types)?, } } return Ok(()); @@ -602,125 +697,235 @@ impl<'a> Resolver<'a> { impl<'a> ComponentState<'a> { fn resolve(&mut self, ns: Ns, idx: &mut Index<'a>) -> Result { match ns { + Ns::CoreFunc => self.core_funcs.resolve(idx, "core func"), + Ns::CoreGlobal => self.core_globals.resolve(idx, "core global"), + Ns::CoreTable => self.core_tables.resolve(idx, "core table"), + Ns::CoreMemory => self.core_memories.resolve(idx, "core memory"), + Ns::CoreType => self.core_types.resolve(idx, "core type"), + Ns::CoreTag => self.core_tags.resolve(idx, "core tag"), + Ns::CoreInstance => self.core_instances.resolve(idx, "core instance"), + Ns::CoreModule => self.core_modules.resolve(idx, "core module"), Ns::Func => self.funcs.resolve(idx, "func"), - Ns::Table => self.tables.resolve(idx, "table"), - Ns::Global => self.globals.resolve(idx, "global"), - Ns::Memory => self.memories.resolve(idx, "memory"), - Ns::Tag => self.tags.resolve(idx, "tag"), Ns::Type => self.types.resolve(idx, "type"), - Ns::Component => self.components.resolve(idx, "component"), - Ns::Module => self.modules.resolve(idx, "module"), Ns::Instance => self.instances.resolve(idx, "instance"), - Ns::Value => self.values.resolve(idx, "instance"), + Ns::Component => self.components.resolve(idx, "component"), + Ns::Value => self.values.resolve(idx, "value"), } } /// Assign an index to the given field. fn register(&mut self, item: &ComponentField<'a>) -> Result<(), Error> { match item { - ComponentField::Import(i) => match &i.item.kind { - ItemKind::Module(_) => self.modules.register(i.item.id, "module")?, - ItemKind::Component(_) => self.components.register(i.item.id, "component")?, - ItemKind::Instance(_) => self.instances.register(i.item.id, "instance")?, - ItemKind::Value(_) => self.values.register(i.item.id, "value")?, - ItemKind::Func(_) => self.funcs.register(i.item.id, "func")?, - }, - - ComponentField::Func(i) => self.funcs.register(i.id, "func")?, - ComponentField::Type(i) => self.types.register(i.id, "type")?, + ComponentField::CoreModule(m) => self.core_modules.register(m.id, "core module")?, + ComponentField::CoreInstance(i) => { + self.core_instances.register(i.id, "core instance")? + } + ComponentField::CoreAlias(a) => self.register_core_alias(a)?, + ComponentField::CoreType(t) => self.core_types.register(t.id, "core type")?, + ComponentField::Component(c) => self.components.register(c.id, "component")?, ComponentField::Instance(i) => self.instances.register(i.id, "instance")?, - ComponentField::Module(m) => self.modules.register(m.id, "nested module")?, - ComponentField::Component(c) => self.components.register(c.id, "nested component")?, ComponentField::Alias(a) => self.register_alias(a)?, + ComponentField::Type(t) => self.types.register(t.id, "type")?, + ComponentField::CanonicalFunc(f) => match &f.kind { + CanonicalFuncKind::Lift { .. } => self.funcs.register(f.id, "func")?, + CanonicalFuncKind::Lower(_) => self.core_funcs.register(f.id, "core func")?, + }, + ComponentField::CoreFunc(_) | ComponentField::Func(_) => { + unreachable!("should be expanded already") + } ComponentField::Start(s) => self.values.register(s.result, "value")?, - - // These fields don't define any items in any index space. - ComponentField::Export(_) => return Ok(()), + ComponentField::Import(i) => match &i.item.kind { + ItemSigKind::CoreModule(_) => { + self.core_modules.register(i.item.id, "core module")? + } + ItemSigKind::Func(_) => self.funcs.register(i.item.id, "func")?, + ItemSigKind::Component(_) => self.components.register(i.item.id, "component")?, + ItemSigKind::Instance(_) => self.instances.register(i.item.id, "instance")?, + ItemSigKind::Value(_) => self.values.register(i.item.id, "value")?, + ItemSigKind::Type(_) => self.types.register(i.item.id, "type")?, + }, + ComponentField::Export(_) | ComponentField::Custom(_) => { + // Exports and custom sections don't define any items + return Ok(()); + } }; Ok(()) } fn register_alias(&mut self, alias: &Alias<'a>) -> Result { - match alias.kind { - AliasKind::Module => self.modules.register(alias.id, "module"), - AliasKind::Component => self.components.register(alias.id, "component"), - AliasKind::Instance => self.instances.register(alias.id, "instance"), - AliasKind::Value => self.values.register(alias.id, "value"), - AliasKind::ExportKind(core::ExportKind::Func) => self.funcs.register(alias.id, "func"), - AliasKind::ExportKind(core::ExportKind::Table) => { - self.tables.register(alias.id, "table") + match alias.target { + AliasTarget::Export { + kind: ComponentExportAliasKind::Component, + .. } - AliasKind::ExportKind(core::ExportKind::Memory) => { - self.memories.register(alias.id, "memory") + | AliasTarget::Outer { + kind: ComponentOuterAliasKind::Component, + .. + } => self.components.register(alias.id, "component"), + AliasTarget::Export { + kind: ComponentExportAliasKind::CoreModule, + .. } - AliasKind::ExportKind(core::ExportKind::Global) => { - self.globals.register(alias.id, "global") + | AliasTarget::Outer { + kind: ComponentOuterAliasKind::CoreModule, + .. + } => self.core_modules.register(alias.id, "core module"), + AliasTarget::Export { + kind: ComponentExportAliasKind::Type, + .. } - AliasKind::ExportKind(core::ExportKind::Tag) => self.tags.register(alias.id, "tag"), - AliasKind::ExportKind(core::ExportKind::Type) => self.types.register(alias.id, "type"), + | AliasTarget::Outer { + kind: ComponentOuterAliasKind::Type, + .. + } => self.types.register(alias.id, "type"), + AliasTarget::Outer { + kind: ComponentOuterAliasKind::CoreType, + .. + } => self.core_types.register(alias.id, "core type"), + AliasTarget::Export { + kind: ComponentExportAliasKind::Func, + .. + } => self.funcs.register(alias.id, "func"), + AliasTarget::Export { + kind: ComponentExportAliasKind::Value, + .. + } => self.values.register(alias.id, "value"), + AliasTarget::Export { + kind: ComponentExportAliasKind::Instance, + .. + } => self.instances.register(alias.id, "instance"), + } + } + + fn register_core_alias(&mut self, alias: &CoreAlias<'a>) -> Result { + match alias.target { + CoreAliasTarget::Export { kind, .. } => match kind { + core::ExportKind::Func => self.core_funcs.register(alias.id, "core func"), + core::ExportKind::Table => self.core_tables.register(alias.id, "core table"), + core::ExportKind::Memory => self.core_memories.register(alias.id, "core memory"), + core::ExportKind::Global => self.core_globals.register(alias.id, "core global"), + core::ExportKind::Tag => self.core_tags.register(alias.id, "core tag"), + }, } } } #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] enum Ns { + CoreFunc, + CoreGlobal, + CoreTable, + CoreMemory, + CoreType, + CoreTag, + CoreInstance, + CoreModule, Func, - Table, - Global, - Memory, - Tag, Type, - Component, - Module, Instance, + Component, Value, } -macro_rules! component_kw_conversions { - ($($kw:ident => $kind:ident)*) => ($( - impl From for Ns { - fn from(_: kw::$kw) -> Ns { +trait ComponentItem { + fn ns(&self) -> Ns; +} + +trait CoreItem { + fn ns(&self) -> Ns; +} + +macro_rules! component_item { + ($kw:path, $kind:ident) => { + impl ComponentItem for $kw { + fn ns(&self) -> Ns { + Ns::$kind + } + } + }; +} + +macro_rules! core_item { + ($kw:path, $kind:ident) => { + impl CoreItem for $kw { + fn ns(&self) -> Ns { Ns::$kind } } - )*); + }; +} + +component_item!(kw::func, Func); +component_item!(kw::r#type, Type); +component_item!(kw::r#instance, Instance); +component_item!(kw::component, Component); +component_item!(kw::value, Value); +component_item!(kw::module, CoreModule); + +core_item!(kw::func, CoreFunc); +core_item!(kw::memory, CoreMemory); +core_item!(kw::r#type, CoreType); +core_item!(kw::r#instance, CoreInstance); + +impl From for ComponentExportAliasKind { + fn from(ns: Ns) -> Self { + match ns { + Ns::CoreModule => Self::CoreModule, + Ns::Func => Self::Func, + Ns::Type => Self::Type, + Ns::Instance => Self::Instance, + Ns::Component => Self::Component, + Ns::Value => Self::Value, + _ => unreachable!("not a component exportable namespace"), + } + } } -component_kw_conversions! { - func => Func - module => Module - component => Component - instance => Instance - value => Value - table => Table - memory => Memory - global => Global - tag => Tag - r#type => Type +impl From for ComponentOuterAliasKind { + fn from(ns: Ns) -> Self { + match ns { + Ns::CoreModule => Self::CoreModule, + Ns::CoreType => Self::CoreType, + Ns::Type => Self::Type, + Ns::Component => Self::Component, + _ => unreachable!("not an outer alias namespace"), + } + } } -impl From for Ns { - fn from(kind: DefTypeKind) -> Self { - match kind { - DefTypeKind::Module => Ns::Module, - DefTypeKind::Component => Ns::Component, - DefTypeKind::Instance => Ns::Instance, - DefTypeKind::Value => Ns::Value, - DefTypeKind::Func => Ns::Func, +impl From for core::ExportKind { + fn from(ns: Ns) -> Self { + match ns { + Ns::CoreFunc => Self::Func, + Ns::CoreTable => Self::Table, + Ns::CoreGlobal => Self::Global, + Ns::CoreMemory => Self::Memory, + Ns::CoreTag => Self::Tag, + _ => unreachable!("not a core exportable namespace"), } } } -impl From for Ns { - fn from(kind: core::ExportKind) -> Self { +impl From for Ns { + fn from(kind: ComponentOuterAliasKind) -> Self { match kind { - core::ExportKind::Func => Ns::Func, - core::ExportKind::Table => Ns::Table, - core::ExportKind::Global => Ns::Global, - core::ExportKind::Memory => Ns::Memory, - core::ExportKind::Tag => Ns::Tag, - core::ExportKind::Type => Ns::Type, + ComponentOuterAliasKind::CoreModule => Self::CoreModule, + ComponentOuterAliasKind::CoreType => Self::CoreType, + ComponentOuterAliasKind::Type => Self::Type, + ComponentOuterAliasKind::Component => Self::Component, + } + } +} + +impl CoreItem for core::ExportKind { + fn ns(&self) -> Ns { + match self { + Self::Func => Ns::CoreFunc, + Self::Table => Ns::CoreTable, + Self::Global => Ns::CoreGlobal, + Self::Memory => Ns::CoreMemory, + Self::Tag => Ns::CoreTag, } } } diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index ebc28a317c..2aea8979ec 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -1,73 +1,807 @@ use crate::component::*; +use crate::core; use crate::kw; +use crate::parser::Lookahead1; use crate::parser::{Parse, Parser, Result}; +use crate::token::Index; +use crate::token::LParen; use crate::token::{Id, NameAnnotation, Span}; -/// A definition of a type. +/// A core type declaration. +#[derive(Debug)] +pub struct CoreType<'a> { + /// Where this type was defined. + pub span: Span, + /// An optional identifier to refer to this `core type` by as part of name + /// resolution. + pub id: Option>, + /// An optional name for this type stored in the custom `name` section. + pub name: Option>, + /// The core type's definition. + pub def: CoreTypeDef<'a>, +} + +impl<'a> Parse<'a> for CoreType<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + parser.parse::()?; + let id = parser.parse()?; + let name = parser.parse()?; + let def = parser.parens(|p| p.parse())?; + + Ok(Self { + span, + id, + name, + def, + }) + } +} + +/// Represents a core type definition. /// -/// typeexpr ::= -/// | +/// In the future this may be removed when module types are a part of +/// a core module. #[derive(Debug)] -pub enum ComponentTypeDef<'a> { - /// The type of an entity. - DefType(DefType<'a>), - /// The type of a value. - InterType(InterType<'a>), +pub enum CoreTypeDef<'a> { + /// The type definition is one of the core types. + Def(core::TypeDef<'a>), + /// The type definition is a module type. + Module(ModuleType<'a>), +} + +impl<'a> Parse<'a> for CoreTypeDef<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::() { + parser.parse::()?; + Ok(Self::Module(parser.parse()?)) + } else { + Ok(Self::Def(parser.parse()?)) + } + } } -/// The type of an exported item from an component or instance. +/// A type definition for a core module. #[derive(Debug)] -pub struct ComponentExportType<'a> { - /// Where this export was defined. - pub span: Span, - /// The name of this export. - pub name: &'a str, - /// The signature of the item that's exported. - pub item: ItemSig<'a>, +pub struct ModuleType<'a> { + /// The declarations of the module type. + pub decls: Vec>, } -impl<'a> Parse<'a> for ComponentExportType<'a> { +impl<'a> Parse<'a> for ModuleType<'a> { fn parse(parser: Parser<'a>) -> Result { - let span = parser.parse::()?.0; - let name = parser.parse()?; - let item = parser.parens(|p| p.parse())?; - Ok(ComponentExportType { span, name, item }) + parser.depth_check()?; + Ok(Self { + decls: parser.parse()?, + }) + } +} + +/// The declarations of a [`ModuleType`]. +#[derive(Debug)] +pub enum ModuleTypeDecl<'a> { + /// A core type. + Type(core::Type<'a>), + /// An import. + Import(core::Import<'a>), + /// An export. + Export(&'a str, core::ItemSig<'a>), +} + +impl<'a> Parse<'a> for ModuleTypeDecl<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + Ok(Self::Type(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Import(parser.parse()?)) + } else if l.peek::() { + parser.parse::()?; + let name = parser.parse()?; + let et = parser.parens(|parser| parser.parse())?; + Ok(Self::Export(name, et)) + } else { + Err(l.error()) + } } } + +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut decls = Vec::new(); + while !parser.is_empty() { + decls.push(parser.parens(|parser| parser.parse())?); + } + Ok(decls) + } +} + /// A type declaration in a component. -/// -/// type ::= (type ? ) #[derive(Debug)] -pub struct TypeField<'a> { +pub struct Type<'a> { /// Where this type was defined. pub span: Span, - /// An optional identifer to refer to this `type` by as part of name + /// An optional identifier to refer to this `type` by as part of name /// resolution. pub id: Option>, - /// An optional name for this function stored in the custom `name` section. + /// An optional name for this type stored in the custom `name` section. pub name: Option>, - /// The type that we're declaring. - pub def: ComponentTypeDef<'a>, + /// If present, inline export annotations which indicate names this + /// definition should be exported under. + pub exports: core::InlineExport<'a>, + /// The type definition. + pub def: TypeDef<'a>, } -impl<'a> Parse<'a> for TypeField<'a> { +impl<'a> Parse<'a> for Type<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; - let def = if parser.peek2::() { - ComponentTypeDef::DefType(parser.parens(|p| p.parse())?) + let exports = parser.parse()?; + let def = parser.parse()?; + + Ok(Self { + span, + id, + name, + exports, + def, + }) + } +} + +/// A definition of a component type. +#[derive(Debug)] +pub enum TypeDef<'a> { + /// A defined value type. + Defined(ComponentDefinedType<'a>), + /// A component function type. + Func(ComponentFunctionType<'a>), + /// A component type. + Component(ComponentType<'a>), + /// An instance type. + Instance(InstanceType<'a>), +} + +impl<'a> Parse<'a> for TypeDef<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::() { + parser.parens(|parser| { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(Self::Func(parser.parse()?)) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Component(parser.parse()?)) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Instance(parser.parse()?)) + } else { + Ok(Self::Defined(ComponentDefinedType::parse_non_primitive( + parser, l, + )?)) + } + }) + } else { + // Only primitive types have no parens + Ok(Self::Defined(ComponentDefinedType::Primitive( + parser.parse()?, + ))) + } + } +} + +/// A primitive value type. +#[allow(missing_docs)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PrimitiveValType { + Unit, + Bool, + S8, + U8, + S16, + U16, + S32, + U32, + S64, + U64, + Float32, + Float64, + Char, + String, +} + +impl<'a> Parse<'a> for PrimitiveValType { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(Self::Unit) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Bool) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::S8) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::U8) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::S16) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::U16) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::S32) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::U32) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::S64) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::U64) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Float32) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Float64) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Char) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::String) + } else { + Err(l.error()) + } + } +} + +/// An component value type. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum ComponentValType<'a> { + /// The value type is a primitive value type. + Primitive(PrimitiveValType), + /// The value type is an inline defined type. + Inline(ComponentDefinedType<'a>), + /// The value type is an index reference to a defined type. + Ref(Index<'a>), +} + +impl<'a> Parse<'a> for ComponentValType<'a> { + fn parse(parser: Parser<'a>) -> Result { + if parser.peek::>() { + Ok(Self::Ref(parser.parse()?)) + } else if parser.peek::() { + parser.parens(|parser| { + Ok(Self::Inline(ComponentDefinedType::parse_non_primitive( + parser, + parser.lookahead1(), + )?)) + }) + } else { + Ok(Self::Primitive(parser.parse()?)) + } + } +} + +// A component defined type. +#[allow(missing_docs)] +#[derive(Debug)] +pub enum ComponentDefinedType<'a> { + Primitive(PrimitiveValType), + Record(Record<'a>), + Variant(Variant<'a>), + List(List<'a>), + Tuple(Tuple<'a>), + Flags(Flags<'a>), + Enum(Enum<'a>), + Union(Union<'a>), + Option(OptionType<'a>), + Expected(Expected<'a>), +} + +impl<'a> ComponentDefinedType<'a> { + fn parse_non_primitive(parser: Parser<'a>, mut l: Lookahead1<'a>) -> Result { + if l.peek::() { + Ok(Self::Record(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Variant(parser.parse()?)) + } else if l.peek::() { + Ok(Self::List(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Tuple(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Flags(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Enum(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Union(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Option(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Expected(parser.parse()?)) + } else { + Err(l.error()) + } + } +} + +impl Default for ComponentDefinedType<'_> { + fn default() -> Self { + Self::Primitive(PrimitiveValType::Unit) + } +} + +/// A record defined type. +#[derive(Debug)] +pub struct Record<'a> { + /// The fields of the record. + pub fields: Vec>, +} + +impl<'a> Parse<'a> for Record<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut fields = Vec::new(); + while !parser.is_empty() { + fields.push(parser.parens(|p| p.parse())?); + } + Ok(Self { fields }) + } +} + +/// A record type field. +#[derive(Debug)] +pub struct RecordField<'a> { + /// The name of the field. + pub name: &'a str, + /// The type of the field. + pub ty: ComponentValType<'a>, +} + +impl<'a> Parse<'a> for RecordField<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(Self { + name: parser.parse()?, + ty: parser.parse()?, + }) + } +} + +/// A variant defined type. +#[derive(Debug)] +pub struct Variant<'a> { + /// The cases of the variant type. + pub cases: Vec>, +} + +impl<'a> Parse<'a> for Variant<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut cases = Vec::new(); + while !parser.is_empty() { + cases.push(parser.parens(|p| p.parse())?); + } + Ok(Self { cases }) + } +} + +/// A case of a variant type. +#[derive(Debug)] +pub struct VariantCase<'a> { + /// Where this `case` was defined + pub span: Span, + /// An optional identifier to refer to this case by as part of name + /// resolution. + pub id: Option>, + /// The name of the case. + pub name: &'a str, + /// The type of the case. + pub ty: ComponentValType<'a>, + /// The optional refinement. + pub refines: Option>, +} + +impl<'a> Parse<'a> for VariantCase<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let id = parser.parse()?; + let name = parser.parse()?; + let ty = parser.parse()?; + let refines = if !parser.is_empty() { + Some(parser.parse()?) } else { - ComponentTypeDef::InterType(parser.parse()?) + None }; - Ok(TypeField { + Ok(Self { span, id, name, - def, + ty, + refines, + }) + } +} + +/// A refinement for a variant case. +#[derive(Debug)] +pub enum Refinement<'a> { + /// The refinement is referenced by index. + Index(Span, Index<'a>), + /// The refinement has been resolved to an index into + /// the cases of the variant. + Resolved(u32), +} + +impl<'a> Parse<'a> for Refinement<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|parser| { + let span = parser.parse::()?.0; + let id = parser.parse()?; + Ok(Self::Index(span, id)) + }) + } +} + +/// A list type. +#[derive(Debug)] +pub struct List<'a> { + /// The element type of the array. + pub element: Box>, +} + +impl<'a> Parse<'a> for List<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(Self { + element: Box::new(parser.parse()?), + }) + } +} + +/// A tuple type. +#[derive(Debug)] +pub struct Tuple<'a> { + /// The types of the fields of the tuple. + pub fields: Vec>, +} + +impl<'a> Parse<'a> for Tuple<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut fields = Vec::new(); + while !parser.is_empty() { + fields.push(parser.parse()?); + } + Ok(Self { fields }) + } +} + +/// A flags type. +#[derive(Debug)] +pub struct Flags<'a> { + /// The names of the individual flags. + pub names: Vec<&'a str>, +} + +impl<'a> Parse<'a> for Flags<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut names = Vec::new(); + while !parser.is_empty() { + names.push(parser.parse()?); + } + Ok(Self { names }) + } +} + +/// An enum type. +#[derive(Debug)] +pub struct Enum<'a> { + /// The tag names of the enum. + pub names: Vec<&'a str>, +} + +impl<'a> Parse<'a> for Enum<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut names = Vec::new(); + while !parser.is_empty() { + names.push(parser.parse()?); + } + Ok(Self { names }) + } +} + +/// A union type. +#[derive(Debug)] +pub struct Union<'a> { + /// The types of the union. + pub types: Vec>, +} + +impl<'a> Parse<'a> for Union<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let mut types = Vec::new(); + while !parser.is_empty() { + types.push(parser.parse()?); + } + Ok(Self { types }) + } +} + +/// An optional type. +#[derive(Debug)] +pub struct OptionType<'a> { + /// The type of the value, when a value is present. + pub element: Box>, +} + +impl<'a> Parse<'a> for OptionType<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(Self { + element: Box::new(parser.parse()?), + }) + } +} + +/// An expected type. +#[derive(Debug)] +pub struct Expected<'a> { + /// The type on success. + pub ok: Box>, + /// The type on failure. + pub err: Box>, +} + +impl<'a> Parse<'a> for Expected<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + let ok = parser.parse()?; + let err = parser.parse()?; + Ok(Self { + ok: Box::new(ok), + err: Box::new(err), + }) + } +} + +/// A component function type with parameters and result. +#[derive(Debug)] +pub struct ComponentFunctionType<'a> { + /// The parameters of a function, optionally each having an identifier for + /// name resolution and a name for the custom `name` section. + pub params: Box<[ComponentFunctionParam<'a>]>, + /// The result type of a function. + pub result: ComponentValType<'a>, +} + +impl<'a> Parse<'a> for ComponentFunctionType<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut params = Vec::new(); + while parser.peek2::() { + params.push(parser.parens(|p| p.parse())?); + } + + let result = if parser.peek2::() { + // Parse a `(result ...)`. + parser.parens(|parser| { + parser.parse::()?; + parser.parse() + })? + } else { + // If the result is omitted, use `unit`. + ComponentValType::Primitive(PrimitiveValType::Unit) + }; + + Ok(Self { + params: params.into(), + result, + }) + } +} + +/// A parameter of a [`ComponentFunctionType`]. +#[derive(Debug)] +pub struct ComponentFunctionParam<'a> { + /// An optionally-specified name of this parameter + pub name: Option<&'a str>, + /// The type of the parameter. + pub ty: ComponentValType<'a>, +} + +impl<'a> Parse<'a> for ComponentFunctionParam<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(Self { + name: parser.parse()?, + ty: parser.parse()?, + }) + } +} + +/// The type of an exported item from an component or instance type. +#[derive(Debug)] +pub struct ComponentExportType<'a> { + /// Where this export was defined. + pub span: Span, + /// The name of this export. + pub name: &'a str, + /// The signature of the item. + pub item: ItemSig<'a>, +} + +impl<'a> Parse<'a> for ComponentExportType<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let name = parser.parse()?; + let item = parser.parens(|p| p.parse())?; + Ok(Self { span, name, item }) + } +} + +/// A type definition for a component type. +#[derive(Debug, Default)] +pub struct ComponentType<'a> { + /// The declarations of the component type. + pub decls: Vec>, +} + +impl<'a> Parse<'a> for ComponentType<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.depth_check()?; + Ok(Self { + decls: parser.parse()?, + }) + } +} + +/// A declaration of a component type. +#[derive(Debug)] +pub enum ComponentTypeDecl<'a> { + /// A core type definition local to the component type. + CoreType(CoreType<'a>), + /// A type definition local to the component type. + Type(Type<'a>), + /// An alias local to the component type. + Alias(Alias<'a>), + /// An import of the component type. + Import(ComponentImport<'a>), + /// An export of the component type. + Export(ComponentExportType<'a>), +} + +impl<'a> Parse<'a> for ComponentTypeDecl<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + Ok(Self::CoreType(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Type(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Alias(Alias::parse_outer_type_alias(parser)?)) + } else if l.peek::() { + Ok(Self::Import(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Export(parser.parse()?)) + } else { + Err(l.error()) + } + } +} + +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut decls = Vec::new(); + while !parser.is_empty() { + decls.push(parser.parens(|parser| parser.parse())?); + } + Ok(decls) + } +} + +/// A type definition for an instance type. +#[derive(Debug)] +pub struct InstanceType<'a> { + /// The declarations of the instance type. + pub decls: Vec>, +} + +impl<'a> Parse<'a> for InstanceType<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.depth_check()?; + Ok(Self { + decls: parser.parse()?, }) } } + +/// A declaration of an instance type. +#[derive(Debug)] +pub enum InstanceTypeDecl<'a> { + /// A core type definition local to the component type. + CoreType(CoreType<'a>), + /// A type definition local to the instance type. + Type(Type<'a>), + /// An alias local to the instance type. + Alias(Alias<'a>), + /// An export of the instance type. + Export(ComponentExportType<'a>), +} + +impl<'a> Parse<'a> for InstanceTypeDecl<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + Ok(Self::CoreType(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Type(parser.parse()?)) + } else if l.peek::() { + Ok(Self::Alias(Alias::parse_outer_type_alias(parser)?)) + } else if l.peek::() { + Ok(Self::Export(parser.parse()?)) + } else { + Err(l.error()) + } + } +} + +impl<'a> Parse<'a> for Vec> { + fn parse(parser: Parser<'a>) -> Result { + let mut decls = Vec::new(); + while !parser.is_empty() { + decls.push(parser.parens(|parser| parser.parse())?); + } + Ok(decls) + } +} + +/// A reference to a core type defined in this component. +/// +/// This is the same as `TypeUse`, but accepts `$T` as shorthand for +/// `(type $T)`. +#[derive(Debug, Clone)] +pub enum CoreTypeUse<'a, T> { + /// The type that we're referencing. + Ref(CoreItemRef<'a, kw::r#type>), + /// The inline type. + Inline(T), +} + +impl<'a, T: Parse<'a>> Parse<'a> for CoreTypeUse<'a, T> { + fn parse(parser: Parser<'a>) -> Result { + // Here the core context is assumed, so no core prefix is expected + if parser.peek::() && parser.peek2::>() { + Ok(Self::Ref(parser.parens(|parser| parser.parse())?)) + } else { + Ok(Self::Inline(parser.parse()?)) + } + } +} + +impl Default for CoreTypeUse<'_, T> { + fn default() -> Self { + let span = Span::from_offset(0); + Self::Ref(CoreItemRef { + idx: Index::Num(0, span), + kind: kw::r#type(span), + export_name: None, + }) + } +} + /// A reference to a type defined in this component. /// /// This is the same as `TypeUse`, but accepts `$T` as shorthand for @@ -82,10 +816,21 @@ pub enum ComponentTypeUse<'a, T> { impl<'a, T: Parse<'a>> Parse<'a> for ComponentTypeUse<'a, T> { fn parse(parser: Parser<'a>) -> Result { - if parser.peek::>() { - Ok(ComponentTypeUse::Ref(parser.parse()?)) + if parser.peek::() && parser.peek2::>() { + Ok(Self::Ref(parser.parens(|parser| parser.parse())?)) } else { - Ok(ComponentTypeUse::Inline(parser.parse()?)) + Ok(Self::Inline(parser.parse()?)) } } } + +impl Default for ComponentTypeUse<'_, T> { + fn default() -> Self { + let span = Span::from_offset(0); + Self::Ref(ItemRef { + idx: Index::Num(0, span), + kind: kw::r#type(span), + export_names: Vec::new(), + }) + } +} diff --git a/crates/wast/src/core/mod.rs b/crates/wast/src/core.rs similarity index 100% rename from crates/wast/src/core/mod.rs rename to crates/wast/src/core.rs diff --git a/crates/wast/src/core/binary.rs b/crates/wast/src/core/binary.rs index 7d6d4feb45..49d95002e7 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -446,7 +446,6 @@ impl Encode for ExportKind { ExportKind::Memory => e.push(0x02), ExportKind::Global => e.push(0x03), ExportKind::Tag => e.push(0x04), - ExportKind::Type => e.push(0x07), } } } diff --git a/crates/wast/src/core/export.rs b/crates/wast/src/core/export.rs index 5ebe002f97..66354d0546 100644 --- a/crates/wast/src/core/export.rs +++ b/crates/wast/src/core/export.rs @@ -25,7 +25,6 @@ pub enum ExportKind { Memory, Global, Tag, - Type, } impl<'a> Parse<'a> for Export<'a> { @@ -60,9 +59,6 @@ impl<'a> Parse<'a> for ExportKind { } else if l.peek::() { parser.parse::()?; Ok(ExportKind::Tag) - } else if l.peek::() { - parser.parse::()?; - Ok(ExportKind::Type) } else { Err(l.error()) } @@ -76,7 +72,6 @@ impl Peek for ExportKind { || kw::memory::peek(cursor) || kw::global::peek(cursor) || kw::tag::peek(cursor) - || kw::r#type::peek(cursor) } fn display() -> &'static str { "export kind" @@ -105,7 +100,6 @@ kw_conversions! { global => Global tag => Tag memory => Memory - r#type => Type } /// A listing of inline `(export "foo")` statements on a WebAssembly item in diff --git a/crates/wast/src/core/expr.rs b/crates/wast/src/core/expr.rs index 0f1ee8a2ea..9e04479bb1 100644 --- a/crates/wast/src/core/expr.rs +++ b/crates/wast/src/core/expr.rs @@ -1218,8 +1218,7 @@ pub struct BrTableIndices<'a> { impl<'a> Parse<'a> for BrTableIndices<'a> { fn parse(parser: Parser<'a>) -> Result { - let mut labels = Vec::new(); - labels.push(parser.parse()?); + let mut labels = vec![parser.parse()?]; while parser.peek::() { labels.push(parser.parse()?); } @@ -1286,7 +1285,7 @@ impl<'a> MemArg<'a> { return Ok((None, c)); } let kw = &kw[name.len()..]; - if !kw.starts_with("=") { + if !kw.starts_with('=') { return Ok((None, c)); } let num = &kw[1..]; @@ -1314,7 +1313,7 @@ impl<'a> MemArg<'a> { let memory = parser .parse::>()? - .unwrap_or(Index::Num(0, parser.prev_span())); + .unwrap_or_else(|| Index::Num(0, parser.prev_span())); let offset = parse_u64("offset", parser)?.unwrap_or(0); let align = match parse_u32("align", parser)? { Some(n) if !n.is_power_of_two() => { diff --git a/crates/wast/src/core/memory.rs b/crates/wast/src/core/memory.rs index 20baf28a3c..ed845e055d 100644 --- a/crates/wast/src/core/memory.rs +++ b/crates/wast/src/core/memory.rs @@ -62,10 +62,8 @@ impl<'a> Parse<'a> for Memory<'a> { } else if l.peek::() || parser.peek2::() { let is_32 = if parser.parse::>()?.is_some() { true - } else if parser.parse::>()?.is_some() { - false } else { - true + parser.parse::>()?.is_none() }; let data = parser.parens(|parser| { parser.parse::()?; diff --git a/crates/wast/src/core/resolve/names.rs b/crates/wast/src/core/resolve/names.rs index 76abef83b2..5d91f8fb8c 100644 --- a/crates/wast/src/core/resolve/names.rs +++ b/crates/wast/src/core/resolve/names.rs @@ -217,7 +217,6 @@ impl<'a> Resolver<'a> { ExportKind::Memory => Ns::Memory, ExportKind::Global => Ns::Global, ExportKind::Tag => Ns::Tag, - ExportKind::Type => Ns::Type, }, )?; Ok(()) diff --git a/crates/wast/src/core/resolve/types.rs b/crates/wast/src/core/resolve/types.rs index 6bf080e3b8..381cf12271 100644 --- a/crates/wast/src/core/resolve/types.rs +++ b/crates/wast/src/core/resolve/types.rs @@ -44,7 +44,7 @@ impl<'a> Expander<'a> { for field in fields.iter_mut() { self.expand(field); } - fields.extend(self.to_prepend.drain(..)); + fields.append(&mut self.to_prepend); } fn expand_header(&mut self, item: &mut ModuleField<'a>) { @@ -179,7 +179,7 @@ impl<'a> Expander<'a> { T: TypeReference<'a>, { if let Some(idx) = &item.index { - return idx.clone(); + return *idx; } let key = match item.inline.as_mut() { Some(ty) => { @@ -191,7 +191,7 @@ impl<'a> Expander<'a> { let span = Span::from_offset(0); // FIXME(#613): don't manufacture let idx = self.key_to_idx(span, key); item.index = Some(idx); - return idx; + idx } fn key_to_idx(&mut self, span: Span, key: impl TypeKey<'a>) -> Index<'a> { @@ -211,8 +211,7 @@ impl<'a> Expander<'a> { })); let idx = Index::Id(id); key.insert(self, idx); - - return idx; + idx } } diff --git a/crates/wast/src/core/types.rs b/crates/wast/src/core/types.rs index 8f02b83fcc..78f1b0a144 100644 --- a/crates/wast/src/core/types.rs +++ b/crates/wast/src/core/types.rs @@ -633,12 +633,30 @@ pub enum TypeDef<'a> { Array(ArrayType<'a>), } +impl<'a> Parse<'a> for TypeDef<'a> { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + Ok(TypeDef::Func(parser.parse()?)) + } else if l.peek::() { + parser.parse::()?; + Ok(TypeDef::Struct(parser.parse()?)) + } else if l.peek::() { + parser.parse::()?; + Ok(TypeDef::Array(parser.parse()?)) + } else { + Err(l.error()) + } + } +} + /// A type declaration in a module #[derive(Debug)] pub struct Type<'a> { /// Where this type was defined. pub span: Span, - /// An optional identifer to refer to this `type` by as part of name + /// An optional identifier to refer to this `type` by as part of name /// resolution. pub id: Option>, /// An optional name for this function stored in the custom `name` section. @@ -652,21 +670,7 @@ impl<'a> Parse<'a> for Type<'a> { let span = parser.parse::()?.0; let id = parser.parse()?; let name = parser.parse()?; - let def = parser.parens(|parser| { - let mut l = parser.lookahead1(); - if l.peek::() { - parser.parse::()?; - Ok(TypeDef::Func(parser.parse()?)) - } else if l.peek::() { - parser.parse::()?; - Ok(TypeDef::Struct(parser.parse()?)) - } else if l.peek::() { - parser.parse::()?; - Ok(TypeDef::Array(parser.parse()?)) - } else { - Err(l.error()) - } - })?; + let def = parser.parens(|parser| parser.parse())?; Ok(Type { span, id, diff --git a/crates/wast/src/encode.rs b/crates/wast/src/encode.rs index 8e6d3ac733..3fc932690e 100644 --- a/crates/wast/src/encode.rs +++ b/crates/wast/src/encode.rs @@ -57,7 +57,7 @@ impl Encode for i32 { impl Encode for u64 { fn encode(&self, e: &mut Vec) { - leb128::write::unsigned(e, (*self).into()).unwrap(); + leb128::write::unsigned(e, *self).unwrap(); } } diff --git a/crates/wast/src/error.rs b/crates/wast/src/error.rs index d2c4039811..214e678338 100644 --- a/crates/wast/src/error.rs +++ b/crates/wast/src/error.rs @@ -50,7 +50,7 @@ impl Error { }), }; ret.set_text(content); - return ret; + ret } pub(crate) fn parse(span: Span, content: &str, message: String) -> Error { @@ -63,7 +63,7 @@ impl Error { }), }; ret.set_text(content); - return ret; + ret } /// Creates a new error with the given `message` which is targeted at the diff --git a/crates/wast/src/lexer.rs b/crates/wast/src/lexer.rs index 5b6f577bfa..2a08119bca 100644 --- a/crates/wast/src/lexer.rs +++ b/crates/wast/src/lexer.rs @@ -95,6 +95,7 @@ pub enum Token<'a> { /// All lexing errors have line/colum/position information as well as a /// `LexError` indicating what kind of error happened while lexing. #[derive(Debug, Clone, PartialEq)] +#[non_exhaustive] pub enum LexError { /// A dangling block comment was found with an unbalanced `(;` which was /// never terminated in the file. @@ -147,9 +148,6 @@ pub enum LexError { /// version to behave differently than the compiler-visible version, so /// these are simply rejected for now. ConfusingUnicode(char), - - #[doc(hidden)] - __Nonexhaustive, } /// A sign token for an integer. @@ -746,8 +744,7 @@ impl<'a> Lexer<'a> { 'u' => { Lexer::must_eat_char(it, '{')?; let n = Lexer::hexnum(it)?; - let c = char::from_u32(n) - .ok_or_else(|| LexError::InvalidUnicodeValue(n))?; + let c = char::from_u32(n).ok_or(LexError::InvalidUnicodeValue(n))?; buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()); Lexer::must_eat_char(it, '}')?; } @@ -944,7 +941,6 @@ impl fmt::Display for LexError { InvalidUnicodeValue(c) => write!(f, "invalid unicode scalar value 0x{:x}", c)?, LoneUnderscore => write!(f, "bare underscore in numeric literal")?, ConfusingUnicode(c) => write!(f, "likely-confusing unicode character found {:?}", c)?, - __Nonexhaustive => unreachable!(), } Ok(()) } diff --git a/crates/wast/src/lib.rs b/crates/wast/src/lib.rs index ce2b39216e..4ba6b74d78 100644 --- a/crates/wast/src/lib.rs +++ b/crates/wast/src/lib.rs @@ -478,7 +478,7 @@ pub mod kw { custom_keyword!(u64); custom_keyword!(char); custom_keyword!(case); - custom_keyword!(defaults_to = "defaults-to"); + custom_keyword!(refines); custom_keyword!(record); custom_keyword!(string); custom_keyword!(bool_ = "bool"); @@ -492,13 +492,15 @@ pub mod kw { custom_keyword!(list); custom_keyword!(union); custom_keyword!(expected); - custom_keyword!(canon_lift = "canon.lift"); - custom_keyword!(canon_lower = "canon.lower"); + custom_keyword!(canon); + custom_keyword!(lift); + custom_keyword!(lower); custom_keyword!(enum_ = "enum"); - custom_keyword!(string_utf8 = "string=utf8"); - custom_keyword!(string_utf16 = "string=utf16"); - custom_keyword!(string_latin1_utf16 = "string=latin1+utf16"); - custom_keyword!(into); + custom_keyword!(string_utf8 = "string-encoding=utf8"); + custom_keyword!(string_utf16 = "string-encoding=utf16"); + custom_keyword!(string_latin1_utf16 = "string-encoding=latin1+utf16"); + custom_keyword!(realloc); + custom_keyword!(post_return = "post-return"); custom_keyword!(with); custom_keyword!(core); } diff --git a/crates/wast/src/names.rs b/crates/wast/src/names.rs index 2605673d4d..b6cf06f443 100644 --- a/crates/wast/src/names.rs +++ b/crates/wast/src/names.rs @@ -47,7 +47,7 @@ impl<'a> Namespace<'a> { pub fn alloc(&mut self) -> u32 { let index = self.count; self.count += 1; - return index; + index } pub fn register_specific(&mut self, name: Id<'a>, index: u32, desc: &str) -> Result<(), Error> { diff --git a/crates/wast/src/parser.rs b/crates/wast/src/parser.rs index 2c30a4d1ab..aba5c5d40e 100644 --- a/crates/wast/src/parser.rs +++ b/crates/wast/src/parser.rs @@ -72,6 +72,18 @@ use std::collections::HashMap; use std::fmt; use std::usize; +/// The maximum recursive depth of parens to parse. +/// +/// This is sort of a fundamental limitation of the way this crate is +/// designed. Everything is done through recursive descent parsing which +/// means, well, that we're recursively going down the stack as we parse +/// nested data structures. While we can handle this for wasm expressions +/// since that's a pretty local decision, handling this for nested +/// modules/components which be far trickier. For now we just say that when +/// the parser goes too deep we return an error saying there's too many +/// nested items. It would be great to not return an error here, though! +pub(crate) const MAX_PARENS_DEPTH: usize = 100; + /// A top-level convenience parseing function that parss a `T` from `buf` and /// requires that all tokens in `buf` are consume. /// @@ -388,7 +400,7 @@ impl ParseBuffer<'_> { // If the previous state was an `LParen`, we may have an // annotation if the next keyword is reserved - (Reserved(s), State::LParen) if s.starts_with("@") && s.len() > 0 => { + (Reserved(s), State::LParen) if s.starts_with('@') && !s.is_empty() => { let offset = self.input_pos(s); State::Annotation { span: Span { offset }, @@ -415,7 +427,7 @@ impl ParseBuffer<'_> { }; } if let State::Annotation { span, .. } = state { - return Err(Error::new(span, format!("unclosed annotation"))); + return Err(Error::new(span, "unclosed annotation".to_string())); } Ok(()) } @@ -702,7 +714,7 @@ impl<'a> Parser<'a> { if res.is_err() { self.buf.cur.set(before); } - return res; + res } /// Return the depth of nested parens we've parsed so far. @@ -713,6 +725,15 @@ impl<'a> Parser<'a> { self.buf.depth.get() } + /// Checks that the parser parens depth hasn't exceeded the maximum depth. + pub(crate) fn depth_check(&self) -> Result<()> { + if self.parens_depth() > MAX_PARENS_DEPTH { + Err(self.error("item nesting too deep")) + } else { + Ok(()) + } + } + fn cursor(self) -> Cursor<'a> { Cursor { parser: self, @@ -756,7 +777,9 @@ impl<'a> Parser<'a> { /// Returns the span of the previous token pub fn prev_span(&self) -> Span { - self.cursor().prev_span().unwrap_or(Span::from_offset(0)) + self.cursor() + .prev_span() + .unwrap_or_else(|| Span::from_offset(0)) } /// Registers a new known annotation with this parser to allow parsing @@ -1087,7 +1110,7 @@ impl<'a> Cursor<'a> { /// [annotation]: https://github.com/WebAssembly/annotations pub fn annotation(self) -> Option<(&'a str, Self)> { let (token, cursor) = self.reserved()?; - if !token.starts_with("@") || token.len() <= 1 { + if !token.starts_with('@') || token.len() <= 1 { return None; } match &self.parser.buf.tokens.get(self.cur.wrapping_sub(1))?.0 { @@ -1183,7 +1206,7 @@ impl<'a> Cursor<'a> { Some(Token::Reserved(n)) => n, _ => return None, }; - if reserved.starts_with("@") && reserved.len() > 1 { + if reserved.starts_with('@') && reserved.len() > 1 { Some(&reserved[1..]) } else { None diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index 071161f101..eaafc396b7 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -227,7 +227,7 @@ impl<'a> Parse<'a> for WastExecute<'a> { } } -fn parse_wat<'a>(parser: Parser<'a>) -> Result> { +fn parse_wat(parser: Parser) -> Result { // Note that this doesn't use `Parse for Wat` since the `parser` provided // has already peeled back the first layer of parentheses while `Parse for // Wat` expects to be the top layer which means it also tries to peel off @@ -293,11 +293,11 @@ impl QuoteWat<'_> { return Err(Error::new(*span, "malformed UTF-8 encoding".to_string())); } } - ret.push_str(" "); + ret.push(' '); } if let Some(prefix) = prefix { ret.insert_str(0, prefix); - ret.push_str(")"); + ret.push(')'); } let buf = ParseBuffer::new(&ret)?; let mut wat = parser::parse::>(&buf)?; diff --git a/fuzz/fuzz_targets/incremental-parse.rs b/fuzz/fuzz_targets/incremental-parse.rs index 0c0e8adaa0..be6e6487b3 100644 --- a/fuzz/fuzz_targets/incremental-parse.rs +++ b/fuzz/fuzz_targets/incremental-parse.rs @@ -145,13 +145,6 @@ fuzz_target!(|data: Vec>| { assert_eq!(a.get_binary_reader().range(), b.get_binary_reader().range()); } - (ComponentTypeSection(a), ComponentTypeSection(b)) => assert_eq!(a.range(), b.range()), - (ComponentImportSection(a), ComponentImportSection(b)) => { - assert_eq!(a.range(), b.range()) - } - (ComponentFunctionSection(a), ComponentFunctionSection(b)) => { - assert_eq!(a.range(), b.range()) - } ( ModuleSection { parser: p, @@ -163,6 +156,8 @@ fuzz_target!(|data: Vec>| { stack.push(parser); parser = p; } + (InstanceSection(a), InstanceSection(b)) => assert_eq!(a.range(), b.range()), + (AliasSection(a), AliasSection(b)) => assert_eq!(a.range(), b.range()), ( ComponentSection { parser: p, @@ -174,14 +169,25 @@ fuzz_target!(|data: Vec>| { stack.push(parser); parser = p; } - (InstanceSection(a), InstanceSection(b)) => assert_eq!(a.range(), b.range()), - (ComponentExportSection(a), ComponentExportSection(b)) => { + (ComponentInstanceSection(a), ComponentInstanceSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (ComponentAliasSection(a), ComponentAliasSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (ComponentTypeSection(a), ComponentTypeSection(b)) => assert_eq!(a.range(), b.range()), + (ComponentCanonicalSection(a), ComponentCanonicalSection(b)) => { assert_eq!(a.range(), b.range()) } (ComponentStartSection(a), ComponentStartSection(b)) => { assert_eq!(a.range(), b.range()) } - (AliasSection(a), AliasSection(b)) => assert_eq!(a.range(), b.range()), + (ComponentImportSection(a), ComponentImportSection(b)) => { + assert_eq!(a.range(), b.range()) + } + (ComponentExportSection(a), ComponentExportSection(b)) => { + assert_eq!(a.range(), b.range()) + } ( UnknownSection { diff --git a/src/bin/wasm-tools/objdump.rs b/src/bin/wasm-tools/objdump.rs index 7f5e47ea23..4b55fab293 100644 --- a/src/bin/wasm-tools/objdump.rs +++ b/src/bin/wasm-tools/objdump.rs @@ -44,23 +44,26 @@ impl Opts { } CodeSectionEntry(_) => {} - ComponentTypeSection(s) => printer.section(s, "types")?, - ComponentImportSection(s) => printer.section(s, "imports")?, - ComponentFunctionSection(s) => printer.section(s, "functions")?, ModuleSection { range, .. } => { printer.section_raw(range, 1, "module")?; printer.start(Encoding::Module)?; } + InstanceSection(s) => printer.section(s, "core instances")?, + AliasSection(s) => printer.section(s, "core aliases")?, + CoreTypeSection(s) => printer.section(s, "core types")?, ComponentSection { range, .. } => { printer.section_raw(range, 1, "component")?; printer.indices.push(IndexSpace::default()); printer.start(Encoding::Component)?; } - InstanceSection(s) => printer.section(s, "instances")?, - ComponentExportSection(s) => printer.section(s, "exports")?, - ComponentStartSection(s) => printer.section_raw(s.range(), 1, "start")?, - AliasSection(s) => printer.section(s, "alias")?, - + ComponentInstanceSection(s) => printer.section(s, "component instances")?, + ComponentAliasSection(s) => printer.section(s, "component alias")?, + ComponentTypeSection(s) => printer.section(s, "component types")?, + ComponentCanonicalSection(s) => printer.section(s, "canonical functions")?, + ComponentStartSection(s) => printer.section_raw(s.range(), 1, "component start")?, + ComponentImportSection(s) => printer.section(s, "component imports")?, + ComponentExportSection(s) => printer.section(s, "component exports")?, + CustomSection(c) => printer.section_raw( c.data_offset()..c.data_offset() + c.data().len(), 1, diff --git a/tests/dump/alias.wat b/tests/dump/alias.wat new file mode 100644 index 0000000000..164e901157 --- /dev/null +++ b/tests/dump/alias.wat @@ -0,0 +1,19 @@ +(component + (import "i" (instance $i + (export "f1" (func $f1)) + (export "f2" (func $f2 (param string))) + )) + + (func (alias export $i "f1")) + (alias export $i "f2" (func)) + + (core func (canon lower (func $i "f1"))) + + (core module $m + (func (export "f3")) + ) + + (core instance $m (instantiate $m)) + (core func (alias export $m "f3")) + (core alias export $m "f3" (func)) +) diff --git a/tests/dump/alias.wat.dump b/tests/dump/alias.wat.dump index ee62f851c4..3998b7328c 100644 --- a/tests/dump/alias.wat.dump +++ b/tests/dump/alias.wat.dump @@ -1,31 +1,57 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 14 | type section -0x000a | 03 | 3 count -0x000b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) -0x000e | 60 01 7f 00 | [type 1] Func(FuncType { params: [I32], returns: [] }) -0x0012 | 62 02 02 66 | [type 2] Instance(InstanceType { exports: [ExportType { name: "f1", ty: Function(0) }, ExportType { name: "f2", ty: Function(1) }] }) - | 31 00 00 02 - | 66 32 00 01 -0x001e | 02 07 | import section -0x0020 | 01 | 1 count -0x0021 | 01 69 00 ff | import [instance 0] Import { module: "i", field: None, ty: Instance(2) } - | 06 02 -0x0027 | 10 07 | alias section -0x0029 | 01 | 1 count -0x002a | 00 00 00 02 | [alias] InstanceExport { instance: 0, kind: Function, export: "f1" } - | 66 31 -0x0030 | 03 02 | func section -0x0032 | 01 | 1 count -0x0033 | 00 | [func 1] type 0 -0x0034 | 07 07 | export section -0x0036 | 01 | 1 count -0x0037 | 03 72 75 6e | export Export { name: "run", kind: Function, index: 1 } - | 00 01 -0x003d | 0a 06 | code section -0x003f | 01 | 1 count -============== func 1 ==================== -0x0040 | 04 | size of function -0x0041 | 00 | 0 local blocks -0x0042 | 10 00 | Call { function_index: 0 } -0x0044 | 0b | End + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 19 | component type section + 0xa | 01 | 1 count + 0xb | 42 04 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "f1", ty: Func(0) }, Type(Func(ComponentFuncType { params: [(None, Primitive(String))], result: Primitive(Unit) })), Export { name: "f2", ty: Func(1) }]) + | 00 7f 04 02 + | 66 31 01 00 + | 01 40 01 00 + | 72 7f 04 02 + | 66 32 01 01 + 0x23 | 0b 05 | component import section + 0x25 | 01 | 1 count + 0x26 | 01 69 05 00 | [instance 0] ComponentImport { name: "i", ty: Instance(0) } + 0x2a | 07 13 | component alias section + 0x2c | 03 | 3 count + 0x2d | 01 00 00 02 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "f1" } + | 66 31 + 0x33 | 01 00 00 02 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f2" } + | 66 32 + 0x39 | 01 00 00 02 | alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f1" } + | 66 31 + 0x3f | 09 05 | canonical function section + 0x41 | 01 | 1 count + 0x42 | 01 00 02 00 | [core func 0] Lower { func_index: 2, options: [] } + 0x46 | 01 2b | [core module 0] inline size + 0x48 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x50 | 01 04 | type section + 0x52 | 01 | 1 count + 0x53 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) + 0x56 | 03 02 | func section + 0x58 | 01 | 1 count + 0x59 | 00 | [func 0] type 0 + 0x5a | 07 06 | export section + 0x5c | 01 | 1 count + 0x5d | 02 66 33 00 | export Export { name: "f3", kind: Func, index: 0 } + | 00 + 0x62 | 0a 04 | code section + 0x64 | 01 | 1 count +============== func 0 ==================== + 0x65 | 02 | size of function + 0x66 | 00 | 0 local blocks + 0x67 | 0b | End + 0x68 | 00 09 | custom section + 0x6a | 04 6e 61 6d | name: "name" + | 65 + 0x6f | 00 02 | module name + 0x71 | 01 6d | "m" + 0x73 | 02 04 | core instance section + 0x75 | 01 | 1 count + 0x76 | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } + 0x79 | 03 0d | core alias section + 0x7b | 02 | 2 count + 0x7c | 00 00 00 02 | core alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "f3" } + | 66 33 + 0x82 | 00 00 00 02 | core alias [func 2] InstanceExport { kind: Func, instance_index: 0, name: "f3" } + | 66 33 diff --git a/tests/dump/alias.wat.fixme b/tests/dump/alias.wat.fixme deleted file mode 100644 index 2ca2ab2863..0000000000 --- a/tests/dump/alias.wat.fixme +++ /dev/null @@ -1,10 +0,0 @@ -(module - (import "i" (instance $i - (export "f1" (func $f1)) - (export "f2" (func $f2 (param i32))) - )) - - (func (export "run") - call (func $i "f1") - ) -) diff --git a/tests/dump/alias2.wat b/tests/dump/alias2.wat new file mode 100644 index 0000000000..1eca8cb987 --- /dev/null +++ b/tests/dump/alias2.wat @@ -0,0 +1,82 @@ +(component + (type $t (instance + (export "1" (core module)) + (export "2" (func)) + (export "3" (value string)) + (export "4" (instance)) + (export "5" (component)) + )) + + (import "" (instance $i (type $t))) + + (component $c + (import "1" (core module)) + (import "2" (func)) + (import "3" (value string)) + (import "4" (instance)) + (import "5" (component)) + ) + + (instance (instantiate $c + (with "1" (core module $i "1")) + (with "2" (func $i "2")) + (with "3" (value $i "4")) + (with "4" (instance $i "3")) + (with "5" (component $i "5")) + )) + + (component $c2 + (import "" (instance (type $t))) + ) + + (alias export $i "1" (core module $m)) + (alias export $i "2" (func $f)) + (alias export $i "3" (value $v)) + (alias export $i "4" (instance $i2)) + (alias export $i "5" (component $c3)) + + (instance + (instantiate $c2 + (with "" (instance + (export "1" (core module $m)) + (export "2" (func $f)) + (export "3" (value $v)) + (export "4" (instance $i2)) + (export "5" (component $c3)) + )) + ) + ) + + (core module $m1 + (func (export "1")) + (memory (export "2") 1) + (global (export "3") i32) + (table (export "4") 1 funcref) + ) + + (core module $m2 + (import "" "1" (func)) + (import "" "2" (memory 1)) + (import "" "3" (global i32)) + (import "" "4" (table 1 funcref)) + ) + + (core instance $i (instantiate $m1)) + (core instance (instantiate $m2 (with "" (instance $i)))) + + (core alias export $i "1" (func $f)) + (core alias export $i "2" (memory $m)) + (core alias export $i "3" (global $g)) + (core alias export $i "4" (table $t)) + + (core instance + (instantiate $m2 + (with "" (instance + (export "1" (func $f)) + (export "2" (memory $m)) + (export "3" (global $g)) + (export "4" (table $t)) + )) + ) + ) +) diff --git a/tests/dump/alias2.wat.dump b/tests/dump/alias2.wat.dump index 4d2814db69..c0347983a3 100644 --- a/tests/dump/alias2.wat.dump +++ b/tests/dump/alias2.wat.dump @@ -1,72 +1,179 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 27 | type section -0x000a | 04 | 4 count -0x000b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) -0x000e | 61 00 00 | [type 1] Module(ModuleType { imports: [], exports: [] }) -0x0011 | 62 00 | [type 2] Instance(InstanceType { exports: [] }) -0x0013 | 62 06 01 31 | [type 3] Instance(InstanceType { exports: [ExportType { name: "1", ty: Function(0) }, ExportType { name: "2", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) }, ExportType { name: "3", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) }, ExportType { name: "4", ty: Global(GlobalType { content_type: I32, mutable: false }) }, ExportType { name: "5", ty: Module(1) }, ExportType { name: "6", ty: Instance(2) }] }) - | 00 00 01 32 - | 02 00 01 01 - | 33 01 70 00 - | 01 01 34 03 - | 7f 00 01 35 - | 05 01 01 36 - | 06 02 -0x0031 | 02 06 | import section -0x0033 | 01 | 1 count -0x0034 | 00 00 ff 06 | import [instance 0] Import { module: "", field: None, ty: Instance(3) } - | 03 -0x0039 | 0e 4b | module section -0x003b | 01 | 1 count -0x003c | 49 | inline module size - 0x003d | 00 61 73 6d | version 1 (Module) + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 2a | component type section + 0xa | 01 | 1 count + 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) + | 00 04 01 31 + | 00 11 00 01 + | 40 00 7f 04 + | 01 32 01 00 + | 04 01 33 02 + | 72 01 42 00 + | 04 01 34 05 + | 01 01 41 00 + | 04 01 35 04 + | 02 + 0x34 | 0b 04 | component import section + 0x36 | 01 | 1 count + 0x37 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } + 0x3a | 05 3e | [component 0] inline size + 0x3c | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x44 | 04 03 | core type section + 0x46 | 01 | 1 count + 0x47 | 50 00 | [core type 0] Module([]) + 0x49 | 0b 06 | component import section + 0x4b | 01 | 1 count + 0x4c | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } + | 00 + 0x51 | 08 04 | component type section + 0x53 | 01 | 1 count + 0x54 | 40 00 7f | [type 0] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) + 0x57 | 0b 09 | component import section + 0x59 | 02 | 2 count + 0x5a | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } + 0x5e | 01 33 02 72 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } + 0x62 | 08 03 | component type section + 0x64 | 01 | 1 count + 0x65 | 42 00 | [type 1] Instance([]) + 0x67 | 0b 05 | component import section + 0x69 | 01 | 1 count + 0x6a | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } + 0x6e | 08 03 | component type section + 0x70 | 01 | 1 count + 0x71 | 41 00 | [type 2] Component([]) + 0x73 | 0b 05 | component import section + 0x75 | 01 | 1 count + 0x76 | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } + 0x7a | 07 1b | component alias section + 0x7c | 05 | 5 count + 0x7d | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } + | 01 31 + 0x83 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } + | 32 + 0x88 | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } + | 34 + 0x8d | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } + | 33 + 0x92 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } + | 35 + 0x97 | 06 19 | component instance section + 0x99 | 01 | 1 count + 0x9a | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } + | 31 00 11 00 + | 01 32 01 00 + | 01 33 02 00 + | 01 34 05 01 + | 01 35 04 01 + 0xb2 | 05 15 | [component 2] inline size + 0xb4 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0xbc | 07 05 | component alias section + 0xbe | 01 | 1 count + 0xbf | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0xc3 | 0b 04 | component import section + 0xc5 | 01 | 1 count + 0xc6 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } + 0xc9 | 07 1b | component alias section + 0xcb | 05 | 5 count + 0xcc | 00 11 00 00 | alias [module 1] InstanceExport { kind: Module, instance_index: 0, name: "1" } + | 01 31 + 0xd2 | 01 00 00 01 | alias [func 1] InstanceExport { kind: Func, instance_index: 0, name: "2" } + | 32 + 0xd7 | 02 00 00 01 | alias [value 1] InstanceExport { kind: Value, instance_index: 0, name: "3" } + | 33 + 0xdc | 05 00 00 01 | alias [instance 3] InstanceExport { kind: Instance, instance_index: 0, name: "4" } + | 34 + 0xe1 | 04 00 00 01 | alias [component 3] InstanceExport { kind: Component, instance_index: 0, name: "5" } + | 35 + 0xe6 | 06 1e | component instance section + 0xe8 | 02 | 2 count + 0xe9 | 01 05 01 31 | [instance 4] FromExports([ComponentExport { name: "1", kind: Module, index: 1 }, ComponentExport { name: "2", kind: Func, index: 1 }, ComponentExport { name: "3", kind: Value, index: 1 }, ComponentExport { name: "4", kind: Instance, index: 3 }, ComponentExport { name: "5", kind: Component, index: 3 }]) + | 00 11 01 01 + | 32 01 01 01 + | 33 02 01 01 + | 34 05 03 01 + | 35 04 03 + 0x100 | 00 02 01 00 | [instance 5] Instantiate { component_index: 2, args: [ComponentInstantiationArg { name: "", kind: Instance, index: 4 }] } + | 05 04 + 0x106 | 01 48 | [core module 2] inline size + 0x108 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x110 | 01 04 | type section + 0x112 | 01 | 1 count + 0x113 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) + 0x116 | 03 02 | func section + 0x118 | 01 | 1 count + 0x119 | 00 | [func 0] type 0 + 0x11a | 04 04 | table section + 0x11c | 01 | 1 count + 0x11d | 70 00 01 | [table 0] TableType { element_type: FuncRef, initial: 1, maximum: None } + 0x120 | 05 03 | memory section + 0x122 | 01 | 1 count + 0x123 | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } + 0x125 | 06 04 | global section + 0x127 | 01 | 1 count + 0x128 | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } + 0x12a | 0b | End + 0x12b | 07 11 | export section + 0x12d | 04 | 4 count + 0x12e | 01 31 00 00 | export Export { name: "1", kind: Func, index: 0 } + 0x132 | 01 32 02 00 | export Export { name: "2", kind: Memory, index: 0 } + 0x136 | 01 33 03 00 | export Export { name: "3", kind: Global, index: 0 } + 0x13a | 01 34 01 00 | export Export { name: "4", kind: Table, index: 0 } + 0x13e | 0a 04 | code section + 0x140 | 01 | 1 count +============== func 0 ==================== + 0x141 | 02 | size of function + 0x142 | 00 | 0 local blocks + 0x143 | 0b | End + 0x144 | 00 0a | custom section + 0x146 | 04 6e 61 6d | name: "name" + | 65 + 0x14b | 00 03 | module name + 0x14d | 02 6d 31 | "m1" + 0x150 | 01 35 | [core module 3] inline size + 0x152 | 00 61 73 6d | version 1 (Module) | 01 00 00 00 - 0x0045 | 01 09 | type section - 0x0047 | 03 | 3 count - 0x0048 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x004b | 61 00 00 | [type 1] Module(ModuleType { imports: [], exports: [] }) - 0x004e | 62 00 | [type 2] Instance(InstanceType { exports: [] }) - 0x0050 | 02 29 | import section - 0x0052 | 06 | 6 count - 0x0053 | 01 31 00 ff | import [func 0] Import { module: "1", field: None, ty: Function(0) } - | 00 00 - 0x0059 | 01 32 00 ff | import [memory 0] Import { module: "2", field: None, ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) } - | 02 00 01 - 0x0060 | 01 33 00 ff | import [global 0] Import { module: "3", field: None, ty: Global(GlobalType { content_type: I32, mutable: false }) } - | 03 7f 00 - 0x0067 | 01 34 00 ff | import [table 0] Import { module: "4", field: None, ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) } - | 01 70 00 01 - 0x006f | 01 35 00 ff | import [module 0] Import { module: "5", field: None, ty: Module(1) } - | 05 01 - 0x0075 | 01 36 00 ff | import [instance 0] Import { module: "6", field: None, ty: Instance(2) } - | 06 02 - 0x007b | 00 09 | custom section - 0x007d | 04 6e 61 6d | name: "name" + 0x15a | 01 04 | type section + 0x15c | 01 | 1 count + 0x15d | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) + 0x160 | 02 19 | import section + 0x162 | 04 | 4 count + 0x163 | 00 01 31 00 | import [func 0] Import { module: "", name: "1", ty: Func(0) } + | 00 + 0x168 | 00 01 32 02 | import [memory 0] Import { module: "", name: "2", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) } + | 00 01 + 0x16e | 00 01 33 03 | import [global 0] Import { module: "", name: "3", ty: Global(GlobalType { content_type: I32, mutable: false }) } + | 7f 00 + 0x174 | 00 01 34 01 | import [table 0] Import { module: "", name: "4", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) } + | 70 00 01 + 0x17b | 00 0a | custom section + 0x17d | 04 6e 61 6d | name: "name" | 65 - 0x0082 | 00 02 | module name - 0x0084 | 01 6d | "m" -0x0086 | 10 1f | alias section -0x0088 | 06 | 6 count -0x0089 | 00 00 00 01 | [alias] InstanceExport { instance: 0, kind: Function, export: "1" } + 0x182 | 00 03 | module name + 0x184 | 02 6d 32 | "m2" + 0x187 | 02 0a | core instance section + 0x189 | 02 | 2 count + 0x18a | 00 02 00 | [core instance 0] Instantiate { module_index: 2, args: [] } + 0x18d | 00 03 01 00 | [core instance 1] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 0 }] } + | 12 00 + 0x193 | 03 15 | core alias section + 0x195 | 04 | 4 count + 0x196 | 00 00 00 01 | core alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "1" } | 31 -0x008e | 00 00 02 01 | [alias] InstanceExport { instance: 0, kind: Memory, export: "2" } + 0x19b | 02 00 00 01 | core alias [memory 0] InstanceExport { kind: Memory, instance_index: 0, name: "2" } | 32 -0x0093 | 00 00 03 01 | [alias] InstanceExport { instance: 0, kind: Global, export: "4" } - | 34 -0x0098 | 00 00 01 01 | [alias] InstanceExport { instance: 0, kind: Table, export: "3" } + 0x1a0 | 03 00 00 01 | core alias [global 0] InstanceExport { kind: Global, instance_index: 0, name: "3" } | 33 -0x009d | 00 00 05 01 | [alias] InstanceExport { instance: 0, kind: Module, export: "5" } - | 35 -0x00a2 | 00 00 06 01 | [alias] InstanceExport { instance: 0, kind: Instance, export: "6" } - | 36 -0x00a7 | 0f 1c | instance section -0x00a9 | 01 | 1 count -0x00aa | 00 00 | [instance 2] instantiate module:0 -0x00ac | 06 | 6 count -0x00ad | 01 31 00 00 | [instantiate arg] InstanceArg { name: "1", kind: Function, index: 0 } -0x00b1 | 01 32 02 00 | [instantiate arg] InstanceArg { name: "2", kind: Memory, index: 0 } -0x00b5 | 01 33 03 00 | [instantiate arg] InstanceArg { name: "3", kind: Global, index: 0 } -0x00b9 | 01 34 01 00 | [instantiate arg] InstanceArg { name: "4", kind: Table, index: 0 } -0x00bd | 01 35 05 01 | [instantiate arg] InstanceArg { name: "5", kind: Module, index: 1 } -0x00c1 | 01 36 06 01 | [instantiate arg] InstanceArg { name: "6", kind: Instance, index: 1 } + 0x1a5 | 01 00 00 01 | core alias [table 0] InstanceExport { kind: Table, instance_index: 0, name: "4" } + | 34 + 0x1aa | 02 19 | core instance section + 0x1ac | 02 | 2 count + 0x1ad | 01 04 01 31 | [core instance 2] FromExports([Export { name: "1", kind: Func, index: 0 }, Export { name: "2", kind: Memory, index: 0 }, Export { name: "3", kind: Global, index: 0 }, Export { name: "4", kind: Table, index: 0 }]) + | 00 00 01 32 + | 02 00 01 33 + | 03 00 01 34 + | 01 00 + 0x1bf | 00 03 01 00 | [core instance 3] Instantiate { module_index: 3, args: [InstantiationArg { name: "", kind: Instance, index: 2 }] } + | 12 02 diff --git a/tests/dump/alias2.wat.fixme b/tests/dump/alias2.wat.fixme deleted file mode 100644 index 6eb307bc72..0000000000 --- a/tests/dump/alias2.wat.fixme +++ /dev/null @@ -1,28 +0,0 @@ -(module - (import "" (instance $i - (export "1" (func $func)) - (export "2" (memory $memory 1)) - (export "3" (table $table 1 funcref)) - (export "4" (global $global i32)) - (export "5" (module $module)) - (export "6" (instance $instance)) - )) - - (module $m - (import "1" (func)) - (import "2" (memory 1)) - (import "3" (global i32)) - (import "4" (table 1 funcref)) - (import "5" (module)) - (import "6" (instance)) - ) - - (instance (instantiate $m - (import "1" (func $i "1")) - (import "2" (memory $i "2")) - (import "3" (global $i "4")) - (import "4" (table $i "3")) - (import "5" (module $i "5")) - (import "6" (instance $i "6")) - )) -) diff --git a/tests/dump/bundled.wat b/tests/dump/bundled.wat new file mode 100644 index 0000000000..8fb82f1308 --- /dev/null +++ b/tests/dump/bundled.wat @@ -0,0 +1,49 @@ +(component + (type $WasiFile (instance + (export "read" (func $read (param u32) (result (list u8)))) + (export "write" (func $write (param (list u8)) (result u32))) + )) + (import "wasi_file" (instance $real-wasi (type $WasiFile))) + + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + + (core instance $libc (instantiate $libc)) + + (core module $CHILD + (import "wasi_file" "read" (func $wasi-file (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core module $VIRTUALIZE + (import "wasi_file" "read" (func (param i32 i32))) + (func (export "read") (param i32 i32) + unreachable + ) + (func (export "write") (param i32 i32 i32) + unreachable + ) + ) + + (core func $real-wasi-read + (canon lower (func $real-wasi "read") + (memory (core memory $libc "mem")) + (realloc (core func $libc "realloc")) + ) + ) + + (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi_file" (instance (export "read" (func $real-wasi-read)))))) + (core instance $child (instantiate $CHILD (with "wasi_file" (instance $virt-wasi)))) + (func (export "work") + (canon lift (core func $child "play") + (memory (core memory $libc "mem")) + (realloc (core func $libc "realloc")) + ) + ) +) diff --git a/tests/dump/bundled.wat.dump b/tests/dump/bundled.wat.dump index e8ea7a0067..a3ae5f6d61 100644 --- a/tests/dump/bundled.wat.dump +++ b/tests/dump/bundled.wat.dump @@ -1,148 +1,191 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 19 | type section -0x000a | 02 | 2 count -0x000b | 60 03 7f 7f | [type 0] Func(FuncType { params: [I32, I32, I32], returns: [I32] }) - | 7f 01 7f -0x0012 | 62 02 04 72 | [type 1] Instance(InstanceType { exports: [ExportType { name: "read", ty: Function(0) }, ExportType { name: "write", ty: Function(0) }] }) - | 65 61 64 00 - | 00 05 77 72 - | 69 74 65 00 - | 00 -0x0023 | 02 0f | import section -0x0025 | 01 | 1 count -0x0026 | 09 77 61 73 | import [instance 0] Import { module: "wasi_file", field: None, ty: Instance(1) } + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 26 | component type section + 0xa | 01 | 1 count + 0xb | 42 06 01 6f | [type 0] Instance([Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: [(None, Primitive(U32))], result: Type(0) })), Export { name: "read", ty: Func(1) }, Type(Defined(List(Primitive(U8)))), Type(Func(ComponentFuncType { params: [(None, Type(2))], result: Primitive(U32) })), Export { name: "write", ty: Func(3) }]) + | 7c 01 40 01 + | 00 78 00 04 + | 04 72 65 61 + | 64 01 01 01 + | 6f 7c 01 40 + | 01 00 02 78 + | 04 05 77 72 + | 69 74 65 01 + | 03 + 0x30 | 0b 0d | component import section + 0x32 | 01 | 1 count + 0x33 | 09 77 61 73 | [instance 0] ComponentImport { name: "wasi_file", ty: Instance(0) } | 69 5f 66 69 - | 6c 65 00 ff - | 06 01 -0x0034 | 0e c4 01 | module section -0x0037 | 02 | 2 count -0x0038 | 5f | inline module size - 0x0039 | 00 61 73 6d | version 1 (Module) + | 6c 65 05 00 + 0x3f | 01 44 | [core module 0] inline size + 0x41 | 00 61 73 6d | version 1 (Module) | 01 00 00 00 - 0x0041 | 10 05 | alias section - 0x0043 | 01 | 1 count - 0x0044 | 01 00 07 01 | [alias] OuterType { relative_depth: 0, index: 1 } - 0x0048 | 02 0f | import section - 0x004a | 01 | 1 count - 0x004b | 09 77 61 73 | import [instance 0] Import { module: "wasi_file", field: None, ty: Instance(0) } + 0x49 | 01 09 | type section + 0x4b | 01 | 1 count + 0x4c | 60 04 7f 7f | [type 0] Func(FuncType { params: [I32, I32, I32, I32], returns: [I32] }) + | 7f 7f 01 7f + 0x54 | 03 02 | func section + 0x56 | 01 | 1 count + 0x57 | 00 | [func 0] type 0 + 0x58 | 05 03 | memory section + 0x5a | 01 | 1 count + 0x5b | 00 00 | [memory 0] MemoryType { memory64: false, shared: false, initial: 0, maximum: None } + 0x5d | 07 11 | export section + 0x5f | 02 | 2 count + 0x60 | 03 6d 65 6d | export Export { name: "mem", kind: Memory, index: 0 } + | 02 00 + 0x66 | 07 72 65 61 | export Export { name: "realloc", kind: Func, index: 0 } + | 6c 6c 6f 63 + | 00 00 + 0x70 | 0a 05 | code section + 0x72 | 01 | 1 count +============== func 0 ==================== + 0x73 | 03 | size of function + 0x74 | 00 | 0 local blocks + 0x75 | 00 | Unreachable + 0x76 | 0b | End + 0x77 | 00 0c | custom section + 0x79 | 04 6e 61 6d | name: "name" + | 65 + 0x7e | 00 05 | module name + 0x80 | 04 6c 69 62 | "libc" + | 63 + 0x85 | 02 04 | core instance section + 0x87 | 01 | 1 count + 0x88 | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } + 0x8b | 01 5f | [core module 1] inline size + 0x8d | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x95 | 01 09 | type section + 0x97 | 02 | 2 count + 0x98 | 60 02 7f 7f | [type 0] Func(FuncType { params: [I32, I32], returns: [] }) + | 00 + 0x9d | 60 00 00 | [type 1] Func(FuncType { params: [], returns: [] }) + 0xa0 | 02 12 | import section + 0xa2 | 01 | 1 count + 0xa3 | 09 77 61 73 | import [func 0] Import { module: "wasi_file", name: "read", ty: Func(0) } | 69 5f 66 69 - | 6c 65 00 ff - | 06 00 - 0x0059 | 10 09 | alias section - 0x005b | 01 | 1 count - 0x005c | 00 00 00 04 | [alias] InstanceExport { instance: 0, kind: Function, export: "read" } - | 72 65 61 64 - 0x0064 | 01 04 | type section - 0x0066 | 01 | 1 count - 0x0067 | 60 00 00 | [type 1] Func(FuncType { params: [], returns: [] }) - 0x006a | 03 02 | func section - 0x006c | 01 | 1 count - 0x006d | 01 | [func 1] type 1 - 0x006e | 07 08 | export section - 0x0070 | 01 | 1 count - 0x0071 | 04 70 6c 61 | export Export { name: "play", kind: Function, index: 1 } + | 6c 65 04 72 + | 65 61 64 00 + | 00 + 0xb4 | 03 02 | func section + 0xb6 | 01 | 1 count + 0xb7 | 01 | [func 1] type 1 + 0xb8 | 07 08 | export section + 0xba | 01 | 1 count + 0xbb | 04 70 6c 61 | export Export { name: "play", kind: Func, index: 1 } | 79 00 01 - 0x0078 | 0a 06 | code section - 0x007a | 01 | 1 count + 0xc2 | 0a 05 | code section + 0xc4 | 01 | 1 count ============== func 1 ==================== - 0x007b | 04 | size of function - 0x007c | 00 | 0 local blocks - 0x007d | 10 00 | Call { function_index: 0 } - 0x007f | 0b | End - 0x0080 | 00 16 | custom section - 0x0082 | 04 6e 61 6d | name: "name" + 0xc5 | 03 | size of function + 0xc6 | 00 | 0 local blocks + 0xc7 | 00 | Unreachable + 0xc8 | 0b | End + 0xc9 | 00 21 | custom section + 0xcb | 04 6e 61 6d | name: "name" | 65 - 0x0087 | 00 06 | module name - 0x0089 | 05 43 48 49 | "CHILD" + 0xd0 | 00 06 | module name + 0xd2 | 05 43 48 49 | "CHILD" | 4c 44 - 0x008f | 01 07 | function names - 0x0091 | 01 | 1 count - 0x0092 | 01 04 70 6c | Naming { index: 1, name: "play" } + 0xd8 | 01 12 | function names + 0xda | 02 | 2 count + 0xdb | 00 09 77 61 | Naming { index: 0, name: "wasi-file" } + | 73 69 2d 66 + | 69 6c 65 + 0xe6 | 01 04 70 6c | Naming { index: 1, name: "play" } | 61 79 -0x0098 | 62 | inline module size - 0x0099 | 00 61 73 6d | version 1 (Module) + 0xec | 01 60 | [core module 2] inline size + 0xee | 00 61 73 6d | version 1 (Module) | 01 00 00 00 - 0x00a1 | 10 05 | alias section - 0x00a3 | 01 | 1 count - 0x00a4 | 01 00 07 01 | [alias] OuterType { relative_depth: 0, index: 1 } - 0x00a8 | 02 0f | import section - 0x00aa | 01 | 1 count - 0x00ab | 09 77 61 73 | import [instance 0] Import { module: "wasi_file", field: None, ty: Instance(0) } + 0xf6 | 01 0c | type section + 0xf8 | 02 | 2 count + 0xf9 | 60 02 7f 7f | [type 0] Func(FuncType { params: [I32, I32], returns: [] }) + | 00 + 0xfe | 60 03 7f 7f | [type 1] Func(FuncType { params: [I32, I32, I32], returns: [] }) + | 7f 00 + 0x104 | 02 12 | import section + 0x106 | 01 | 1 count + 0x107 | 09 77 61 73 | import [func 0] Import { module: "wasi_file", name: "read", ty: Func(0) } | 69 5f 66 69 - | 6c 65 00 ff - | 06 00 - 0x00b9 | 01 08 | type section - 0x00bb | 01 | 1 count - 0x00bc | 60 03 7f 7f | [type 1] Func(FuncType { params: [I32, I32, I32], returns: [I32] }) - | 7f 01 7f - 0x00c3 | 03 03 | func section - 0x00c5 | 02 | 2 count - 0x00c6 | 01 | [func 0] type 1 - 0x00c7 | 01 | [func 1] type 1 - 0x00c8 | 07 10 | export section - 0x00ca | 02 | 2 count - 0x00cb | 04 72 65 61 | export Export { name: "read", kind: Function, index: 0 } - | 64 00 00 - 0x00d2 | 05 77 72 69 | export Export { name: "write", kind: Function, index: 1 } - | 74 65 00 01 - 0x00da | 0a 0b | code section - 0x00dc | 02 | 2 count -============== func 0 ==================== - 0x00dd | 04 | size of function - 0x00de | 00 | 0 local blocks - 0x00df | 41 00 | I32Const { value: 0 } - 0x00e1 | 0b | End + | 6c 65 04 72 + | 65 61 64 00 + | 00 + 0x118 | 03 03 | func section + 0x11a | 02 | 2 count + 0x11b | 00 | [func 1] type 0 + 0x11c | 01 | [func 2] type 1 + 0x11d | 07 10 | export section + 0x11f | 02 | 2 count + 0x120 | 04 72 65 61 | export Export { name: "read", kind: Func, index: 1 } + | 64 00 01 + 0x127 | 05 77 72 69 | export Export { name: "write", kind: Func, index: 2 } + | 74 65 00 02 + 0x12f | 0a 09 | code section + 0x131 | 02 | 2 count ============== func 1 ==================== - 0x00e2 | 04 | size of function - 0x00e3 | 00 | 0 local blocks - 0x00e4 | 41 00 | I32Const { value: 0 } - 0x00e6 | 0b | End - 0x00e7 | 00 12 | custom section - 0x00e9 | 04 6e 61 6d | name: "name" + 0x132 | 03 | size of function + 0x133 | 00 | 0 local blocks + 0x134 | 00 | Unreachable + 0x135 | 0b | End +============== func 2 ==================== + 0x136 | 03 | size of function + 0x137 | 00 | 0 local blocks + 0x138 | 00 | Unreachable + 0x139 | 0b | End + 0x13a | 00 12 | custom section + 0x13c | 04 6e 61 6d | name: "name" | 65 - 0x00ee | 00 0b | module name - 0x00f0 | 0a 56 49 52 | "VIRTUALIZE" + 0x141 | 00 0b | module name + 0x143 | 0a 56 49 52 | "VIRTUALIZE" | 54 55 41 4c | 49 5a 45 -0x00fb | 0f 1f | instance section -0x00fd | 02 | 2 count -0x00fe | 00 01 | [instance 1] instantiate module:1 -0x0100 | 01 | 1 count -0x0101 | 09 77 61 73 | [instantiate arg] InstanceArg { name: "wasi_file", kind: Instance, index: 0 } - | 69 5f 66 69 - | 6c 65 06 00 -0x010d | 00 00 | [instance 2] instantiate module:0 -0x010f | 01 | 1 count -0x0110 | 09 77 61 73 | [instantiate arg] InstanceArg { name: "wasi_file", kind: Instance, index: 1 } - | 69 5f 66 69 - | 6c 65 06 01 -0x011c | 10 09 | alias section -0x011e | 01 | 1 count -0x011f | 00 02 00 04 | [alias] InstanceExport { instance: 2, kind: Function, export: "play" } + 0x14e | 07 09 | component alias section + 0x150 | 01 | 1 count + 0x151 | 01 00 00 04 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "read" } + | 72 65 61 64 + 0x159 | 03 13 | core alias section + 0x15b | 02 | 2 count + 0x15c | 02 00 00 03 | core alias [memory 0] InstanceExport { kind: Memory, instance_index: 0, name: "mem" } + | 6d 65 6d + 0x163 | 00 00 00 07 | core alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "realloc" } + | 72 65 61 6c + | 6c 6f 63 + 0x16e | 09 09 | canonical function section + 0x170 | 01 | 1 count + 0x171 | 01 00 00 02 | [core func 1] Lower { func_index: 0, options: [Memory(0), Realloc(0)] } + | 03 00 04 00 + 0x179 | 02 28 | core instance section + 0x17b | 03 | 3 count + 0x17c | 01 01 04 72 | [core instance 1] FromExports([Export { name: "read", kind: Func, index: 1 }]) + | 65 61 64 00 + | 01 + 0x185 | 00 02 01 09 | [core instance 2] Instantiate { module_index: 2, args: [InstantiationArg { name: "wasi_file", kind: Instance, index: 1 }] } + | 77 61 73 69 + | 5f 66 69 6c + | 65 12 01 + 0x194 | 00 01 01 09 | [core instance 3] Instantiate { module_index: 1, args: [InstantiationArg { name: "wasi_file", kind: Instance, index: 2 }] } + | 77 61 73 69 + | 5f 66 69 6c + | 65 12 02 + 0x1a3 | 08 04 | component type section + 0x1a5 | 01 | 1 count + 0x1a6 | 40 00 7f | [type 1] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) + 0x1a9 | 03 1b | core alias section + 0x1ab | 03 | 3 count + 0x1ac | 00 00 03 04 | core alias [func 2] InstanceExport { kind: Func, instance_index: 3, name: "play" } | 70 6c 61 79 -0x0127 | 01 04 | type section -0x0129 | 01 | 1 count -0x012a | 60 00 00 | [type 2] Func(FuncType { params: [], returns: [] }) -0x012d | 03 02 | func section -0x012f | 01 | 1 count -0x0130 | 02 | [func 1] type 2 -0x0131 | 07 08 | export section -0x0133 | 01 | 1 count -0x0134 | 04 77 6f 72 | export Export { name: "work", kind: Function, index: 1 } - | 6b 00 01 -0x013b | 0a 06 | code section -0x013d | 01 | 1 count -============== func 1 ==================== -0x013e | 04 | size of function -0x013f | 00 | 0 local blocks -0x0140 | 10 00 | Call { function_index: 0 } -0x0142 | 0b | End -0x0143 | 00 12 | custom section -0x0145 | 04 6e 61 6d | name: "name" - | 65 -0x014a | 04 0b | type names -0x014c | 01 | 1 count -0x014d | 01 08 57 61 | Naming { index: 1, name: "WasiFile" } - | 73 69 46 69 - | 6c 65 + 0x1b4 | 02 00 00 03 | core alias [memory 1] InstanceExport { kind: Memory, instance_index: 0, name: "mem" } + | 6d 65 6d + 0x1bb | 00 00 00 07 | core alias [func 3] InstanceExport { kind: Func, instance_index: 0, name: "realloc" } + | 72 65 61 6c + | 6c 6f 63 + 0x1c6 | 09 0a | canonical function section + 0x1c8 | 01 | 1 count + 0x1c9 | 00 00 02 02 | [func 1] Lift { core_func_index: 2, type_index: 1, options: [Memory(1), Realloc(3)] } + | 03 01 04 03 + | 01 + 0x1d2 | 0c 08 | component export section + 0x1d4 | 01 | 1 count + 0x1d5 | 04 77 6f 72 | export ComponentExport { name: "work", kind: Func, index: 1 } + | 6b 01 01 diff --git a/tests/dump/bundled.wat.fixme b/tests/dump/bundled.wat.fixme deleted file mode 100644 index 54b1a3d860..0000000000 --- a/tests/dump/bundled.wat.fixme +++ /dev/null @@ -1,32 +0,0 @@ -(module - (type $WasiFile (instance - (export "read" (func $read (param i32 i32 i32) (result i32))) - (export "write" (func $write (param i32 i32 i32) (result i32))) - )) - (import "wasi_file" (instance $real-wasi (type $WasiFile))) - - (module $CHILD - (import "wasi_file" (instance $wasi-file (type outer 0 $WasiFile))) - (func $play (export "play") - call (func $wasi-file "read") - ) - ) - - - (module $VIRTUALIZE - (import "wasi_file" (instance $wasi-file (type outer 0 $WasiFile))) - (func (export "read") (param i32 i32 i32) (result i32) - i32.const 0 - ) - (func (export "write") (param i32 i32 i32) (result i32) - i32.const 0 - ) - ) - - (instance $virt-wasi (instantiate $VIRTUALIZE (import "wasi_file" (instance $real-wasi)))) - (instance $child (instantiate $CHILD (import "wasi_file" (instance $virt-wasi)))) - - (func (export "work") - call (func $child "play") - ) -) diff --git a/tests/dump/component-expand-bundle.wat b/tests/dump/component-expand-bundle.wat index 8af4f42a8a..c704707a7a 100644 --- a/tests/dump/component-expand-bundle.wat +++ b/tests/dump/component-expand-bundle.wat @@ -1,11 +1,11 @@ (component - (module $m + (core module $m (func (export "")) ) - (module $m2 (import "" "a" (func))) - (instance $M (instantiate (module $m))) - (alias export $M "" (func $f)) - (instance (instantiate (module $m2) (with "" (instance + (core module $m2 (import "" "a" (func))) + (core instance $M (instantiate $m)) + (core alias export $M "" (func $f)) + (core instance (instantiate $m2 (with "" (instance (export "a" (func $f)) )))) ) diff --git a/tests/dump/component-expand-bundle.wat.dump b/tests/dump/component-expand-bundle.wat.dump index 879b2164b4..224381d75a 100644 --- a/tests/dump/component-expand-bundle.wat.dump +++ b/tests/dump/component-expand-bundle.wat.dump @@ -1,6 +1,6 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 04 29 | [module 0] inline size + 0x8 | 01 29 | [core module 0] inline size 0xa | 00 61 73 6d | version 1 (Module) | 01 00 00 00 0x12 | 01 04 | type section @@ -23,7 +23,7 @@ | 65 0x2f | 00 02 | module name 0x31 | 01 6d | "m" - 0x33 | 04 22 | [module 1] inline size + 0x33 | 01 22 | [core module 1] inline size 0x35 | 00 61 73 6d | version 1 (Module) | 01 00 00 00 0x3d | 01 04 | type section @@ -38,15 +38,15 @@ | 65 0x52 | 00 03 | module name 0x54 | 02 6d 32 | "m2" - 0x57 | 06 05 | instance section + 0x57 | 02 04 | core instance section 0x59 | 01 | 1 count - 0x5a | 00 00 00 00 | [instance 0] Module { index: 0, args: [] } - 0x5e | 09 05 | alias section - 0x60 | 01 | 1 count - 0x61 | 01 00 00 00 | alias [func 0] InstanceExport { kind: Func, instance: 0, name: "" } - 0x65 | 06 0e | instance section - 0x67 | 02 | 2 count - 0x68 | 02 01 01 61 | [instance 1] ModuleFromExports([Export { name: "a", kind: Func, index: 0 }]) + 0x5a | 00 00 00 | [core instance 0] Instantiate { module_index: 0, args: [] } + 0x5d | 03 05 | core alias section + 0x5f | 01 | 1 count + 0x60 | 00 00 00 00 | core alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "" } + 0x64 | 02 0d | core instance section + 0x66 | 02 | 2 count + 0x67 | 01 01 01 61 | [core instance 1] FromExports([Export { name: "a", kind: Func, index: 0 }]) | 00 00 - 0x6e | 00 00 01 01 | [instance 2] Module { index: 1, args: [ModuleArg { name: "", kind: Instance(1) }] } - | 00 02 01 + 0x6d | 00 01 01 00 | [core instance 2] Instantiate { module_index: 1, args: [InstantiationArg { name: "", kind: Instance, index: 1 }] } + | 12 01 diff --git a/tests/dump/component-expand-bundle2.wat b/tests/dump/component-expand-bundle2.wat index c3e180d9b7..4b09abe45a 100644 --- a/tests/dump/component-expand-bundle2.wat +++ b/tests/dump/component-expand-bundle2.wat @@ -1,11 +1,11 @@ (component (component $c - (module (export "")) + (core module (export "")) ) - (component $c2 (import "" (component (import "" (module))))) - (instance $C (instantiate (component $c))) - (alias export $C "" (module $m)) - (instance (instantiate (component $c2) (with "" (instance - (export "" (module $m)) + (component $c2 (import "" (component (import "" (core module))))) + (instance $C (instantiate $c)) + (alias export $C "" (core module $m)) + (instance (instantiate $c2 (with "" (instance + (export "" (core module $m)) )))) ) diff --git a/tests/dump/component-expand-bundle2.wat.dump b/tests/dump/component-expand-bundle2.wat.dump index 9585ec4c5d..4788ec4d8b 100644 --- a/tests/dump/component-expand-bundle2.wat.dump +++ b/tests/dump/component-expand-bundle2.wat.dump @@ -1,33 +1,35 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 05 18 | [component 0] inline size + 0x8 | 05 19 | [component 0] inline size 0xa | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x12 | 04 08 | [module 0] inline size + 0x12 | 01 08 | [core module 0] inline size 0x14 | 00 61 73 6d | version 1 (Module) | 01 00 00 00 - 0x1c | 07 04 | component-export section + 0x1c | 0c 05 | component export section 0x1e | 01 | 1 count - 0x1f | 00 00 00 | export ComponentExport { name: "", kind: Module(0) } - 0x22 | 05 18 | [component 1] inline size - 0x24 | 00 61 73 6d | version 65546 (Component) + 0x1f | 00 00 11 00 | export ComponentExport { name: "", kind: Module, index: 0 } + 0x23 | 05 1b | [component 1] inline size + 0x25 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x2c | 01 09 | type section - 0x2e | 01 | 1 count - 0x2f | 4e 02 01 4f | [type 0] Component([Type(Module([])), Import(ComponentImport { name: "", ty: 0 })]) - | 00 02 00 00 - 0x37 | 02 03 | import section - 0x39 | 01 | 1 count - 0x3a | 00 00 | [component 0] ComponentImport { name: "", ty: 0 } - 0x3c | 06 05 | instance section - 0x3e | 01 | 1 count - 0x3f | 00 01 00 00 | [instance 0] Component { index: 0, args: [] } - 0x43 | 09 05 | alias section - 0x45 | 01 | 1 count - 0x46 | 00 00 00 00 | alias [module 0] InstanceExport { kind: Module, instance: 0, name: "" } - 0x4a | 06 0d | instance section - 0x4c | 02 | 2 count - 0x4d | 01 01 00 00 | [instance 1] ComponentFromExports([ComponentExport { name: "", kind: Module(0) }]) + 0x2d | 08 0b | component type section + 0x2f | 01 | 1 count + 0x30 | 41 02 00 50 | [type 0] Component([CoreType(Module([])), Import(ComponentImport { name: "", ty: Module(0) })]) + | 00 03 00 00 + | 11 00 + 0x3a | 0b 04 | component import section + 0x3c | 01 | 1 count + 0x3d | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } + 0x40 | 06 04 | component instance section + 0x42 | 01 | 1 count + 0x43 | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } + 0x46 | 07 06 | component alias section + 0x48 | 01 | 1 count + 0x49 | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "" } | 00 - 0x52 | 00 01 01 01 | [instance 2] Component { index: 1, args: [ComponentArg { name: "", kind: Instance(1) }] } - | 00 02 01 + 0x4e | 06 0d | component instance section + 0x50 | 02 | 2 count + 0x51 | 01 01 00 00 | [instance 1] FromExports([ComponentExport { name: "", kind: Module, index: 0 }]) + | 11 00 + 0x57 | 00 01 01 00 | [instance 2] Instantiate { component_index: 1, args: [ComponentInstantiationArg { name: "", kind: Instance, index: 1 }] } + | 05 01 diff --git a/tests/dump/component-inline-export-import.wat b/tests/dump/component-inline-export-import.wat index 7f6e48baae..542a5c5072 100644 --- a/tests/dump/component-inline-export-import.wat +++ b/tests/dump/component-inline-export-import.wat @@ -3,7 +3,7 @@ (export "") (import "") ) - (module + (core module (export "a") (import "a") ) diff --git a/tests/dump/component-inline-export-import.wat.dump b/tests/dump/component-inline-export-import.wat.dump index 3c33257f43..4c892ee58d 100644 --- a/tests/dump/component-inline-export-import.wat.dump +++ b/tests/dump/component-inline-export-import.wat.dump @@ -1,18 +1,20 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 01 03 | type section + 0x8 | 08 03 | component type section 0xa | 01 | 1 count - 0xb | 4e 00 | [type 0] Component([]) - 0xd | 02 03 | import section + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0b 04 | component import section 0xf | 01 | 1 count - 0x10 | 00 00 | [component 0] ComponentImport { name: "", ty: 0 } - 0x12 | 01 03 | type section - 0x14 | 01 | 1 count - 0x15 | 4f 00 | [type 1] Module([]) - 0x17 | 02 04 | import section - 0x19 | 01 | 1 count - 0x1a | 01 61 01 | [module 0] ComponentImport { name: "a", ty: 1 } - 0x1d | 07 08 | component-export section - 0x1f | 02 | 2 count - 0x20 | 00 01 00 | export ComponentExport { name: "", kind: Component(0) } - 0x23 | 01 61 00 00 | export ComponentExport { name: "a", kind: Module(0) } + 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } + 0x13 | 04 03 | core type section + 0x15 | 01 | 1 count + 0x16 | 50 00 | [core type 0] Module([]) + 0x18 | 0b 06 | component import section + 0x1a | 01 | 1 count + 0x1b | 01 61 00 11 | [module 0] ComponentImport { name: "a", ty: Module(0) } + | 00 + 0x20 | 0c 09 | component export section + 0x22 | 02 | 2 count + 0x23 | 00 04 00 | export ComponentExport { name: "", kind: Component, index: 0 } + 0x26 | 01 61 00 11 | export ComponentExport { name: "a", kind: Module, index: 0 } + | 00 diff --git a/tests/dump/component-inline-type.wat b/tests/dump/component-inline-type.wat index c6721dfcfa..4a1128f5e3 100644 --- a/tests/dump/component-inline-type.wat +++ b/tests/dump/component-inline-type.wat @@ -1,6 +1,6 @@ (component (import "" (component)) - (import "" (module)) + (import "" (core module)) (import "" (instance)) (import "" (func)) ) diff --git a/tests/dump/component-inline-type.wat.dump b/tests/dump/component-inline-type.wat.dump index bb507d8d3f..f2d6ee74c8 100644 --- a/tests/dump/component-inline-type.wat.dump +++ b/tests/dump/component-inline-type.wat.dump @@ -1,26 +1,26 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 01 03 | type section + 0x8 | 08 03 | component type section 0xa | 01 | 1 count - 0xb | 4e 00 | [type 0] Component([]) - 0xd | 02 03 | import section + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0b 04 | component import section 0xf | 01 | 1 count - 0x10 | 00 00 | [component 0] ComponentImport { name: "", ty: 0 } - 0x12 | 01 03 | type section - 0x14 | 01 | 1 count - 0x15 | 4f 00 | [type 1] Module([]) - 0x17 | 02 03 | import section - 0x19 | 01 | 1 count - 0x1a | 00 01 | [module 0] ComponentImport { name: "", ty: 1 } - 0x1c | 01 03 | type section - 0x1e | 01 | 1 count - 0x1f | 4d 00 | [type 2] Instance([]) - 0x21 | 02 03 | import section - 0x23 | 01 | 1 count - 0x24 | 00 02 | [instance 0] ComponentImport { name: "", ty: 2 } - 0x26 | 01 04 | type section - 0x28 | 01 | 1 count - 0x29 | 4c 00 7f | [type 3] Function(ComponentFuncType { params: [], result: Primitive(Unit) }) - 0x2c | 02 03 | import section - 0x2e | 01 | 1 count - 0x2f | 00 03 | [func 0] ComponentImport { name: "", ty: 3 } + 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } + 0x13 | 04 03 | core type section + 0x15 | 01 | 1 count + 0x16 | 50 00 | [core type 0] Module([]) + 0x18 | 0b 05 | component import section + 0x1a | 01 | 1 count + 0x1b | 00 00 11 00 | [module 0] ComponentImport { name: "", ty: Module(0) } + 0x1f | 08 03 | component type section + 0x21 | 01 | 1 count + 0x22 | 42 00 | [type 1] Instance([]) + 0x24 | 0b 04 | component import section + 0x26 | 01 | 1 count + 0x27 | 00 05 01 | [instance 0] ComponentImport { name: "", ty: Instance(1) } + 0x2a | 08 04 | component type section + 0x2c | 01 | 1 count + 0x2d | 40 00 7f | [type 2] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) + 0x30 | 0b 04 | component import section + 0x32 | 01 | 1 count + 0x33 | 00 01 02 | [func 0] ComponentImport { name: "", ty: Func(2) } diff --git a/tests/dump/component-instance-type.wat.dump b/tests/dump/component-instance-type.wat.dump index 37a97bf508..0cc0bab9b4 100644 --- a/tests/dump/component-instance-type.wat.dump +++ b/tests/dump/component-instance-type.wat.dump @@ -1,12 +1,13 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 01 20 | type section + 0x8 | 08 23 | component type section 0xa | 01 | 1 count - 0xb | 4d 03 01 4c | [type 0] Instance([Type(Function(ComponentFuncType { params: [], result: Primitive(Unit) })), Type(Component([Type(Function(ComponentFuncType { params: [], result: Primitive(Unit) })), OuterType { count: 1, index: 0 }, Import(ComponentImport { name: "1", ty: 0 }), Export { name: "1", ty: 1 }])), Export { name: "c5", ty: 1 }]) - | 00 7f 01 4e - | 04 01 4c 00 - | 7f 09 02 05 - | 01 00 02 01 - | 31 00 07 01 - | 31 01 07 02 - | 63 35 01 + 0xb | 42 03 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Type(Component([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Alias(Outer { kind: Type, count: 1, index: 0 }), Import(ComponentImport { name: "1", ty: Func(0) }), Export { name: "1", ty: Func(1) }])), Export { name: "c5", ty: Component(1) }]) + | 00 7f 01 41 + | 04 01 40 00 + | 7f 02 03 01 + | 01 00 03 01 + | 31 01 00 04 + | 01 31 01 01 + | 04 02 63 35 + | 04 01 diff --git a/tests/dump/component-linking.wat b/tests/dump/component-linking.wat new file mode 100644 index 0000000000..bcdabbf8fb --- /dev/null +++ b/tests/dump/component-linking.wat @@ -0,0 +1,25 @@ +(component + (import "" (instance $i + (export "1" (core module)) + (export "2" (func)) + (export "3" (value string)) + (export "4" (instance)) + (export "5" (component)) + )) + + (component $c + (import "1" (core module)) + (import "2" (func)) + (import "3" (value string)) + (import "4" (instance)) + (import "5" (component)) + ) + + (instance (instantiate $c + (with "1" (core module $i "1")) + (with "2" (func $i "2")) + (with "3" (value $i "4")) + (with "4" (instance $i "3")) + (with "5" (component $i "5")) + )) +) diff --git a/tests/dump/component-linking.wat.dump b/tests/dump/component-linking.wat.dump new file mode 100644 index 0000000000..52fc4a9ff9 --- /dev/null +++ b/tests/dump/component-linking.wat.dump @@ -0,0 +1,67 @@ + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 2a | component type section + 0xa | 01 | 1 count + 0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "1", ty: Module(0) }, Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "2", ty: Func(0) }, Export { name: "3", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "4", ty: Instance(1) }, Type(Component([])), Export { name: "5", ty: Component(2) }]) + | 00 04 01 31 + | 00 11 00 01 + | 40 00 7f 04 + | 01 32 01 00 + | 04 01 33 02 + | 72 01 42 00 + | 04 01 34 05 + | 01 01 41 00 + | 04 01 35 04 + | 02 + 0x34 | 0b 04 | component import section + 0x36 | 01 | 1 count + 0x37 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } + 0x3a | 05 3e | [component 0] inline size + 0x3c | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x44 | 04 03 | core type section + 0x46 | 01 | 1 count + 0x47 | 50 00 | [core type 0] Module([]) + 0x49 | 0b 06 | component import section + 0x4b | 01 | 1 count + 0x4c | 01 31 00 11 | [module 0] ComponentImport { name: "1", ty: Module(0) } + | 00 + 0x51 | 08 04 | component type section + 0x53 | 01 | 1 count + 0x54 | 40 00 7f | [type 0] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) + 0x57 | 0b 09 | component import section + 0x59 | 02 | 2 count + 0x5a | 01 32 01 00 | [func 0] ComponentImport { name: "2", ty: Func(0) } + 0x5e | 01 33 02 72 | [value 0] ComponentImport { name: "3", ty: Value(Primitive(String)) } + 0x62 | 08 03 | component type section + 0x64 | 01 | 1 count + 0x65 | 42 00 | [type 1] Instance([]) + 0x67 | 0b 05 | component import section + 0x69 | 01 | 1 count + 0x6a | 01 34 05 01 | [instance 0] ComponentImport { name: "4", ty: Instance(1) } + 0x6e | 08 03 | component type section + 0x70 | 01 | 1 count + 0x71 | 41 00 | [type 2] Component([]) + 0x73 | 0b 05 | component import section + 0x75 | 01 | 1 count + 0x76 | 01 35 04 02 | [component 0] ComponentImport { name: "5", ty: Component(2) } + 0x7a | 07 1b | component alias section + 0x7c | 05 | 5 count + 0x7d | 00 11 00 00 | alias [module 0] InstanceExport { kind: Module, instance_index: 0, name: "1" } + | 01 31 + 0x83 | 01 00 00 01 | alias [func 0] InstanceExport { kind: Func, instance_index: 0, name: "2" } + | 32 + 0x88 | 02 00 00 01 | alias [value 0] InstanceExport { kind: Value, instance_index: 0, name: "4" } + | 34 + 0x8d | 05 00 00 01 | alias [instance 1] InstanceExport { kind: Instance, instance_index: 0, name: "3" } + | 33 + 0x92 | 04 00 00 01 | alias [component 1] InstanceExport { kind: Component, instance_index: 0, name: "5" } + | 35 + 0x97 | 06 19 | component instance section + 0x99 | 01 | 1 count + 0x9a | 00 00 05 01 | [instance 2] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "1", kind: Module, index: 0 }, ComponentInstantiationArg { name: "2", kind: Func, index: 0 }, ComponentInstantiationArg { name: "3", kind: Value, index: 0 }, ComponentInstantiationArg { name: "4", kind: Instance, index: 1 }, ComponentInstantiationArg { name: "5", kind: Component, index: 1 }] } + | 31 00 11 00 + | 01 32 01 00 + | 01 33 02 00 + | 01 34 05 01 + | 01 35 04 01 diff --git a/tests/dump/component-outer-alias.wat b/tests/dump/component-outer-alias.wat index 345aed0315..05bdf845fb 100644 --- a/tests/dump/component-outer-alias.wat +++ b/tests/dump/component-outer-alias.wat @@ -2,22 +2,22 @@ (type $t string) (type (component - (type (value $t)) + (type (func (result $t))) )) (component - (type (value $t)) + (type (func (result $t))) ) ;; should only have one alias in here (component - (type (value $t)) - (type (value $t)) + (type (func (result $t))) + (type (func (result $t))) ) ;; can work with later types too (type $t2 u8) (component - (type (value $t2)) - (type (value $t2)) + (type (func (result $t2))) + (type (func (result $t2))) ) ) diff --git a/tests/dump/component-outer-alias.wat.dump b/tests/dump/component-outer-alias.wat.dump index 1d2d0d1297..451fd0b9d3 100644 --- a/tests/dump/component-outer-alias.wat.dump +++ b/tests/dump/component-outer-alias.wat.dump @@ -1,40 +1,40 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 01 0c | type section + 0x8 | 08 0d | component type section 0xa | 02 | 2 count - 0xb | 72 | [type 0] Interface(Primitive(String)) - 0xc | 4e 02 09 02 | [type 1] Component([OuterType { count: 1, index: 0 }, Type(Value(Type(0)))]) - | 05 01 00 01 - | 4b 00 - 0x16 | 05 14 | [component 0] inline size - 0x18 | 00 61 73 6d | version 65546 (Component) + 0xb | 72 | [type 0] Defined(Primitive(String)) + 0xc | 41 02 02 03 | [type 1] Component([Alias(Outer { kind: Type, count: 1, index: 0 }), Type(Func(ComponentFuncType { params: [], result: Type(0) }))]) + | 01 01 00 01 + | 40 00 00 + 0x17 | 05 15 | [component 0] inline size + 0x19 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x20 | 09 05 | alias section - 0x22 | 01 | 1 count - 0x23 | 02 05 01 00 | alias [type 0] OuterType { count: 1, index: 0 } - 0x27 | 01 03 | type section - 0x29 | 01 | 1 count - 0x2a | 4b 00 | [type 1] Value(Type(0)) - 0x2c | 05 16 | [component 1] inline size - 0x2e | 00 61 73 6d | version 65546 (Component) + 0x21 | 07 05 | component alias section + 0x23 | 01 | 1 count + 0x24 | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0x28 | 08 04 | component type section + 0x2a | 01 | 1 count + 0x2b | 40 00 00 | [type 1] Func(ComponentFuncType { params: [], result: Type(0) }) + 0x2e | 05 18 | [component 1] inline size + 0x30 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x36 | 09 05 | alias section - 0x38 | 01 | 1 count - 0x39 | 02 05 01 00 | alias [type 0] OuterType { count: 1, index: 0 } - 0x3d | 01 05 | type section - 0x3f | 02 | 2 count - 0x40 | 4b 00 | [type 1] Value(Type(0)) - 0x42 | 4b 00 | [type 2] Value(Type(0)) - 0x44 | 01 02 | type section - 0x46 | 01 | 1 count - 0x47 | 7c | [type 2] Interface(Primitive(U8)) - 0x48 | 05 16 | [component 2] inline size - 0x4a | 00 61 73 6d | version 65546 (Component) + 0x38 | 07 05 | component alias section + 0x3a | 01 | 1 count + 0x3b | 03 01 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 } + 0x3f | 08 07 | component type section + 0x41 | 02 | 2 count + 0x42 | 40 00 00 | [type 1] Func(ComponentFuncType { params: [], result: Type(0) }) + 0x45 | 40 00 00 | [type 2] Func(ComponentFuncType { params: [], result: Type(0) }) + 0x48 | 08 02 | component type section + 0x4a | 01 | 1 count + 0x4b | 7c | [type 2] Defined(Primitive(U8)) + 0x4c | 05 18 | [component 2] inline size + 0x4e | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x52 | 09 05 | alias section - 0x54 | 01 | 1 count - 0x55 | 02 05 01 02 | alias [type 0] OuterType { count: 1, index: 2 } - 0x59 | 01 05 | type section - 0x5b | 02 | 2 count - 0x5c | 4b 00 | [type 1] Value(Type(0)) - 0x5e | 4b 00 | [type 2] Value(Type(0)) + 0x56 | 07 05 | component alias section + 0x58 | 01 | 1 count + 0x59 | 03 01 01 02 | alias [type 0] Outer { kind: Type, count: 1, index: 2 } + 0x5d | 08 07 | component type section + 0x5f | 02 | 2 count + 0x60 | 40 00 00 | [type 1] Func(ComponentFuncType { params: [], result: Type(0) }) + 0x63 | 40 00 00 | [type 2] Func(ComponentFuncType { params: [], result: Type(0) }) diff --git a/tests/dump/import-modules.wat b/tests/dump/import-modules.wat new file mode 100644 index 0000000000..5a28f05d23 --- /dev/null +++ b/tests/dump/import-modules.wat @@ -0,0 +1,10 @@ +(component + (import "" (core module $m1 + (import "" "f" (func)) + )) + (core module $m2 + (func (export "f")) + ) + (core instance $i1 (instantiate $m2)) + (core instance $i2 (instantiate $m1 (with "" (instance $i1)))) +) diff --git a/tests/dump/import-modules.wat.dump b/tests/dump/import-modules.wat.dump index 6bd8faa7df..782811c4f1 100644 --- a/tests/dump/import-modules.wat.dump +++ b/tests/dump/import-modules.wat.dump @@ -1,25 +1,38 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 0c | type section -0x000a | 02 | 2 count -0x000b | 61 00 00 | [type 0] Module(ModuleType { imports: [], exports: [] }) -0x000e | 61 01 00 00 | [type 1] Module(ModuleType { imports: [Import { module: "", field: None, ty: Module(0) }], exports: [] }) - | ff 05 00 00 -0x0016 | 02 06 | import section -0x0018 | 01 | 1 count -0x0019 | 00 00 ff 05 | import [module 0] Import { module: "", field: None, ty: Module(1) } - | 01 -0x001e | 01 0c | type section -0x0020 | 02 | 2 count -0x0021 | 60 00 00 | [type 2] Func(FuncType { params: [], returns: [] }) -0x0024 | 61 01 00 00 | [type 3] Module(ModuleType { imports: [Import { module: "", field: None, ty: Function(2) }], exports: [] }) - | ff 00 02 00 -0x002c | 02 06 | import section -0x002e | 01 | 1 count -0x002f | 00 00 ff 05 | import [module 1] Import { module: "", field: None, ty: Module(3) } - | 03 -0x0034 | 0f 07 | instance section -0x0036 | 01 | 1 count -0x0037 | 00 00 | [instance 0] instantiate module:0 -0x0039 | 01 | 1 count -0x003a | 00 05 01 | [instantiate arg] InstanceArg { name: "", kind: Module, index: 1 } + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 04 0d | core type section + 0xa | 01 | 1 count + 0xb | 50 02 01 60 | [core type 0] Module([Type(Func(FuncType { params: [], returns: [] })), Import(Import { module: "", name: "f", ty: Func(0) })]) + | 00 00 00 00 + | 01 66 00 00 + 0x17 | 0b 05 | component import section + 0x19 | 01 | 1 count + 0x1a | 00 00 11 00 | [module 0] ComponentImport { name: "", ty: Module(0) } + 0x1e | 01 2b | [core module 1] inline size + 0x20 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x28 | 01 04 | type section + 0x2a | 01 | 1 count + 0x2b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) + 0x2e | 03 02 | func section + 0x30 | 01 | 1 count + 0x31 | 00 | [func 0] type 0 + 0x32 | 07 05 | export section + 0x34 | 01 | 1 count + 0x35 | 01 66 00 00 | export Export { name: "f", kind: Func, index: 0 } + 0x39 | 0a 04 | code section + 0x3b | 01 | 1 count +============== func 0 ==================== + 0x3c | 02 | size of function + 0x3d | 00 | 0 local blocks + 0x3e | 0b | End + 0x3f | 00 0a | custom section + 0x41 | 04 6e 61 6d | name: "name" + | 65 + 0x46 | 00 03 | module name + 0x48 | 02 6d 32 | "m2" + 0x4b | 02 0a | core instance section + 0x4d | 02 | 2 count + 0x4e | 00 01 00 | [core instance 0] Instantiate { module_index: 1, args: [] } + 0x51 | 00 00 01 00 | [core instance 1] Instantiate { module_index: 0, args: [InstantiationArg { name: "", kind: Instance, index: 0 }] } + | 12 00 diff --git a/tests/dump/import-modules.wat.fixme b/tests/dump/import-modules.wat.fixme deleted file mode 100644 index d75481be8f..0000000000 --- a/tests/dump/import-modules.wat.fixme +++ /dev/null @@ -1,9 +0,0 @@ -(module - (import "" (module $m - (import "" (module)) - )) - (import "" (module $i - (import "" (func)) - )) - (instance $i (instantiate $m (import "" (module $i)))) -) diff --git a/tests/dump/instance-expand.wat.fixme b/tests/dump/instance-expand.wat similarity index 88% rename from tests/dump/instance-expand.wat.fixme rename to tests/dump/instance-expand.wat index e2375e0e3c..86d4db9843 100644 --- a/tests/dump/instance-expand.wat.fixme +++ b/tests/dump/instance-expand.wat @@ -1,4 +1,4 @@ -(module +(component (type $i (instance (export "" (func)) )) diff --git a/tests/dump/instance-expand.wat.dump b/tests/dump/instance-expand.wat.dump index d0c63cf086..185864fd1a 100644 --- a/tests/dump/instance-expand.wat.dump +++ b/tests/dump/instance-expand.wat.dump @@ -1,17 +1,10 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 09 | type section -0x000a | 02 | 2 count -0x000b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) -0x000e | 62 01 00 00 | [type 1] Instance(InstanceType { exports: [ExportType { name: "", ty: Function(0) }] }) - | 00 -0x0013 | 02 06 | import section -0x0015 | 01 | 1 count -0x0016 | 00 00 ff 06 | import [instance 0] Import { module: "", field: None, ty: Instance(1) } - | 01 -0x001b | 00 0b | custom section -0x001d | 04 6e 61 6d | name: "name" - | 65 -0x0022 | 04 04 | type names -0x0024 | 01 | 1 count -0x0025 | 01 01 69 | Naming { index: 1, name: "i" } + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 0b | component type section + 0xa | 01 | 1 count + 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "", ty: Func(0) }]) + | 00 7f 04 00 + | 01 00 + 0x15 | 0b 04 | component import section + 0x17 | 01 | 1 count + 0x18 | 00 05 00 | [instance 0] ComponentImport { name: "", ty: Instance(0) } diff --git a/tests/dump/instance-type.wat.fixme b/tests/dump/instance-type.wat similarity index 89% rename from tests/dump/instance-type.wat.fixme rename to tests/dump/instance-type.wat index a6775e72ed..20b7c334a5 100644 --- a/tests/dump/instance-type.wat.fixme +++ b/tests/dump/instance-type.wat @@ -1,4 +1,4 @@ -(module +(component (type (instance (export "" (func)) )) diff --git a/tests/dump/instance-type.wat.dump b/tests/dump/instance-type.wat.dump index 1e020d2624..b028e2d256 100644 --- a/tests/dump/instance-type.wat.dump +++ b/tests/dump/instance-type.wat.dump @@ -1,10 +1,10 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 10 | type section -0x000a | 04 | 4 count -0x000b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) -0x000e | 62 01 00 00 | [type 1] Instance(InstanceType { exports: [ExportType { name: "", ty: Function(0) }] }) - | 00 -0x0013 | 62 00 | [type 2] Instance(InstanceType { exports: [] }) -0x0015 | 62 01 00 06 | [type 3] Instance(InstanceType { exports: [ExportType { name: "", ty: Instance(2) }] }) - | 02 + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 14 | component type section + 0xa | 02 | 2 count + 0xb | 42 02 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "", ty: Func(0) }]) + | 00 7f 04 00 + | 01 00 + 0x15 | 42 02 01 42 | [type 1] Instance([Type(Instance([])), Export { name: "", ty: Instance(0) }]) + | 00 04 00 05 + | 00 diff --git a/tests/dump/instance-type2.wat.fixme b/tests/dump/instance-type2.wat similarity index 93% rename from tests/dump/instance-type2.wat.fixme rename to tests/dump/instance-type2.wat index 1fc7f5d5ab..53a3b338f7 100644 --- a/tests/dump/instance-type2.wat.fixme +++ b/tests/dump/instance-type2.wat @@ -1,4 +1,4 @@ -(module +(component (type (instance)) (type (instance (export "" (instance (type 0))))) (type $x (instance)) diff --git a/tests/dump/instance-type2.wat.dump b/tests/dump/instance-type2.wat.dump index 89d0c4fa26..a64e9cd442 100644 --- a/tests/dump/instance-type2.wat.dump +++ b/tests/dump/instance-type2.wat.dump @@ -1,16 +1,11 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 0f | type section -0x000a | 04 | 4 count -0x000b | 62 00 | [type 0] Instance(InstanceType { exports: [] }) -0x000d | 62 01 00 06 | [type 1] Instance(InstanceType { exports: [ExportType { name: "", ty: Instance(0) }] }) - | 00 -0x0012 | 62 00 | [type 2] Instance(InstanceType { exports: [] }) -0x0014 | 62 01 00 06 | [type 3] Instance(InstanceType { exports: [ExportType { name: "", ty: Instance(2) }] }) - | 02 -0x0019 | 00 0b | custom section -0x001b | 04 6e 61 6d | name: "name" - | 65 -0x0020 | 04 04 | type names -0x0022 | 01 | 1 count -0x0023 | 02 01 78 | Naming { index: 2, name: "x" } + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 16 | component type section + 0xa | 04 | 4 count + 0xb | 42 00 | [type 0] Instance([]) + 0xd | 42 01 04 00 | [type 1] Instance([Export { name: "", ty: Instance(0) }]) + | 05 00 + 0x13 | 42 00 | [type 2] Instance([]) + 0x15 | 42 02 02 03 | [type 3] Instance([Alias(Outer { kind: Type, count: 1, index: 2 }), Export { name: "", ty: Instance(0) }]) + | 01 01 02 04 + | 00 05 00 diff --git a/tests/dump/instantiate.wat b/tests/dump/instantiate.wat new file mode 100644 index 0000000000..89bb92cf3a --- /dev/null +++ b/tests/dump/instantiate.wat @@ -0,0 +1,11 @@ + +(component + (import "a" (component $c)) + (func $f (import "f")) + + (instance $a + (instantiate $c + (with "a" (func $f)) + ) + ) +) diff --git a/tests/dump/instantiate.wat.dump b/tests/dump/instantiate.wat.dump index 465d21f8ce..068f3012d5 100644 --- a/tests/dump/instantiate.wat.dump +++ b/tests/dump/instantiate.wat.dump @@ -1,68 +1,18 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 04 | type section -0x000a | 01 | 1 count -0x000b | 61 00 00 | [type 0] Module(ModuleType { imports: [], exports: [] }) -0x000e | 02 0d | import section -0x0010 | 02 | 2 count -0x0011 | 01 61 00 ff | import [module 0] Import { module: "a", field: None, ty: Module(0) } - | 05 00 -0x0017 | 01 62 00 ff | import [module 1] Import { module: "b", field: None, ty: Module(0) } - | 05 00 -0x001d | 01 03 | type section -0x001f | 01 | 1 count -0x0020 | 62 00 | [type 1] Instance(InstanceType { exports: [] }) -0x0022 | 02 07 | import section -0x0024 | 01 | 1 count -0x0025 | 01 63 00 ff | import [instance 0] Import { module: "c", field: None, ty: Instance(1) } - | 06 01 -0x002b | 0f 1c | instance section -0x002d | 01 | 1 count -0x002e | 00 00 | [instance 1] instantiate module:0 -0x0030 | 06 | 6 count -0x0031 | 01 61 05 01 | [instantiate arg] InstanceArg { name: "a", kind: Module, index: 1 } -0x0035 | 01 62 00 00 | [instantiate arg] InstanceArg { name: "b", kind: Function, index: 0 } -0x0039 | 01 63 03 00 | [instantiate arg] InstanceArg { name: "c", kind: Global, index: 0 } -0x003d | 01 64 06 00 | [instantiate arg] InstanceArg { name: "d", kind: Instance, index: 0 } -0x0041 | 01 65 02 00 | [instantiate arg] InstanceArg { name: "e", kind: Memory, index: 0 } -0x0045 | 01 66 01 00 | [instantiate arg] InstanceArg { name: "f", kind: Table, index: 0 } -0x0049 | 01 04 | type section -0x004b | 01 | 1 count -0x004c | 60 00 00 | [type 2] Func(FuncType { params: [], returns: [] }) -0x004f | 03 02 | func section -0x0051 | 01 | 1 count -0x0052 | 02 | [func 0] type 2 -0x0053 | 04 04 | table section -0x0055 | 01 | 1 count -0x0056 | 70 00 01 | [table 0] TableType { element_type: FuncRef, initial: 1, maximum: None } -0x0059 | 05 03 | memory section -0x005b | 01 | 1 count -0x005c | 00 01 | [memory 0] MemoryType { memory64: false, shared: false, initial: 1, maximum: None } -0x005e | 06 06 | global section -0x0060 | 01 | 1 count -0x0061 | 7f 00 | [global 0] GlobalType { content_type: I32, mutable: false } -0x0063 | 41 00 | I32Const { value: 0 } -0x0065 | 0b | End -0x0066 | 0a 04 | code section -0x0068 | 01 | 1 count -============== func 0 ==================== -0x0069 | 02 | size of function -0x006a | 00 | 0 local blocks -0x006b | 0b | End -0x006c | 00 23 | custom section -0x006e | 04 6e 61 6d | name: "name" - | 65 -0x0073 | 01 04 | function names -0x0075 | 01 | 1 count -0x0076 | 00 01 66 | Naming { index: 0, name: "f" } -0x0079 | 05 08 | table names -0x007b | 01 | 1 count -0x007c | 00 05 74 61 | Naming { index: 0, name: "table" } - | 62 6c 65 -0x0083 | 06 06 | memory names -0x0085 | 01 | 1 count -0x0086 | 00 03 6d 65 | Naming { index: 0, name: "mem" } - | 6d -0x008b | 07 04 | global names -0x008d | 01 | 1 count -0x008e | 00 01 67 | Naming { index: 0, name: "g" } + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 03 | component type section + 0xa | 01 | 1 count + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0b 05 | component import section + 0xf | 01 | 1 count + 0x10 | 01 61 04 00 | [component 0] ComponentImport { name: "a", ty: Component(0) } + 0x14 | 08 04 | component type section + 0x16 | 01 | 1 count + 0x17 | 40 00 7f | [type 1] Func(ComponentFuncType { params: [], result: Primitive(Unit) }) + 0x1a | 0b 05 | component import section + 0x1c | 01 | 1 count + 0x1d | 01 66 01 01 | [func 0] ComponentImport { name: "f", ty: Func(1) } + 0x21 | 06 08 | component instance section + 0x23 | 01 | 1 count + 0x24 | 00 00 01 01 | [instance 0] Instantiate { component_index: 0, args: [ComponentInstantiationArg { name: "a", kind: Func, index: 0 }] } + | 61 01 00 diff --git a/tests/dump/instantiate.wat.fixme b/tests/dump/instantiate.wat.fixme deleted file mode 100644 index 0ab7197f39..0000000000 --- a/tests/dump/instantiate.wat.fixme +++ /dev/null @@ -1,21 +0,0 @@ - -(module - (import "a" (module $m)) - (import "b" (module $m2)) - (import "c" (instance $b)) - (func $f) - (global $g i32 (i32.const 0)) - (memory $mem 1) - (table $table 1 funcref) - - (instance $a - (instantiate $m - (import "a" (module $m2)) - (import "b" (func $f)) - (import "c" (global $g)) - (import "d" (instance $b)) - (import "e" (memory $mem)) - (import "f" (table $table)) - ) - ) -) diff --git a/tests/dump/instantiate2.wat b/tests/dump/instantiate2.wat new file mode 100644 index 0000000000..99b04ee104 --- /dev/null +++ b/tests/dump/instantiate2.wat @@ -0,0 +1,4 @@ +(component + (import "" (component $c (import "" (func)))) + (instance (instantiate $c)) +) diff --git a/tests/dump/instantiate2.wat.dump b/tests/dump/instantiate2.wat.dump index 078fedf558..56d3e6ffbf 100644 --- a/tests/dump/instantiate2.wat.dump +++ b/tests/dump/instantiate2.wat.dump @@ -1,15 +1,13 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 0c | type section -0x000a | 02 | 2 count -0x000b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) -0x000e | 61 01 00 00 | [type 1] Module(ModuleType { imports: [Import { module: "", field: None, ty: Function(0) }], exports: [] }) - | ff 00 00 00 -0x0016 | 02 06 | import section -0x0018 | 01 | 1 count -0x0019 | 00 00 ff 05 | import [module 0] Import { module: "", field: None, ty: Module(1) } - | 01 -0x001e | 0f 04 | instance section -0x0020 | 01 | 1 count -0x0021 | 00 00 | [instance 0] instantiate module:0 -0x0023 | 00 | 0 count + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 0b | component type section + 0xa | 01 | 1 count + 0xb | 41 02 01 40 | [type 0] Component([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Import(ComponentImport { name: "", ty: Func(0) })]) + | 00 7f 03 00 + | 01 00 + 0x15 | 0b 04 | component import section + 0x17 | 01 | 1 count + 0x18 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } + 0x1b | 06 04 | component instance section + 0x1d | 01 | 1 count + 0x1e | 00 00 00 | [instance 0] Instantiate { component_index: 0, args: [] } diff --git a/tests/dump/instantiate2.wat.fixme b/tests/dump/instantiate2.wat.fixme deleted file mode 100644 index 35b298739b..0000000000 --- a/tests/dump/instantiate2.wat.fixme +++ /dev/null @@ -1,4 +0,0 @@ -(module - (import "" (module $m (import "" (func)))) - (instance (instantiate $m)) -) diff --git a/tests/dump/module-linking.wat.dump b/tests/dump/module-linking.wat.dump deleted file mode 100644 index 4d2814db69..0000000000 --- a/tests/dump/module-linking.wat.dump +++ /dev/null @@ -1,72 +0,0 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 27 | type section -0x000a | 04 | 4 count -0x000b | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) -0x000e | 61 00 00 | [type 1] Module(ModuleType { imports: [], exports: [] }) -0x0011 | 62 00 | [type 2] Instance(InstanceType { exports: [] }) -0x0013 | 62 06 01 31 | [type 3] Instance(InstanceType { exports: [ExportType { name: "1", ty: Function(0) }, ExportType { name: "2", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) }, ExportType { name: "3", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) }, ExportType { name: "4", ty: Global(GlobalType { content_type: I32, mutable: false }) }, ExportType { name: "5", ty: Module(1) }, ExportType { name: "6", ty: Instance(2) }] }) - | 00 00 01 32 - | 02 00 01 01 - | 33 01 70 00 - | 01 01 34 03 - | 7f 00 01 35 - | 05 01 01 36 - | 06 02 -0x0031 | 02 06 | import section -0x0033 | 01 | 1 count -0x0034 | 00 00 ff 06 | import [instance 0] Import { module: "", field: None, ty: Instance(3) } - | 03 -0x0039 | 0e 4b | module section -0x003b | 01 | 1 count -0x003c | 49 | inline module size - 0x003d | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x0045 | 01 09 | type section - 0x0047 | 03 | 3 count - 0x0048 | 60 00 00 | [type 0] Func(FuncType { params: [], returns: [] }) - 0x004b | 61 00 00 | [type 1] Module(ModuleType { imports: [], exports: [] }) - 0x004e | 62 00 | [type 2] Instance(InstanceType { exports: [] }) - 0x0050 | 02 29 | import section - 0x0052 | 06 | 6 count - 0x0053 | 01 31 00 ff | import [func 0] Import { module: "1", field: None, ty: Function(0) } - | 00 00 - 0x0059 | 01 32 00 ff | import [memory 0] Import { module: "2", field: None, ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) } - | 02 00 01 - 0x0060 | 01 33 00 ff | import [global 0] Import { module: "3", field: None, ty: Global(GlobalType { content_type: I32, mutable: false }) } - | 03 7f 00 - 0x0067 | 01 34 00 ff | import [table 0] Import { module: "4", field: None, ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) } - | 01 70 00 01 - 0x006f | 01 35 00 ff | import [module 0] Import { module: "5", field: None, ty: Module(1) } - | 05 01 - 0x0075 | 01 36 00 ff | import [instance 0] Import { module: "6", field: None, ty: Instance(2) } - | 06 02 - 0x007b | 00 09 | custom section - 0x007d | 04 6e 61 6d | name: "name" - | 65 - 0x0082 | 00 02 | module name - 0x0084 | 01 6d | "m" -0x0086 | 10 1f | alias section -0x0088 | 06 | 6 count -0x0089 | 00 00 00 01 | [alias] InstanceExport { instance: 0, kind: Function, export: "1" } - | 31 -0x008e | 00 00 02 01 | [alias] InstanceExport { instance: 0, kind: Memory, export: "2" } - | 32 -0x0093 | 00 00 03 01 | [alias] InstanceExport { instance: 0, kind: Global, export: "4" } - | 34 -0x0098 | 00 00 01 01 | [alias] InstanceExport { instance: 0, kind: Table, export: "3" } - | 33 -0x009d | 00 00 05 01 | [alias] InstanceExport { instance: 0, kind: Module, export: "5" } - | 35 -0x00a2 | 00 00 06 01 | [alias] InstanceExport { instance: 0, kind: Instance, export: "6" } - | 36 -0x00a7 | 0f 1c | instance section -0x00a9 | 01 | 1 count -0x00aa | 00 00 | [instance 2] instantiate module:0 -0x00ac | 06 | 6 count -0x00ad | 01 31 00 00 | [instantiate arg] InstanceArg { name: "1", kind: Function, index: 0 } -0x00b1 | 01 32 02 00 | [instantiate arg] InstanceArg { name: "2", kind: Memory, index: 0 } -0x00b5 | 01 33 03 00 | [instantiate arg] InstanceArg { name: "3", kind: Global, index: 0 } -0x00b9 | 01 34 01 00 | [instantiate arg] InstanceArg { name: "4", kind: Table, index: 0 } -0x00bd | 01 35 05 01 | [instantiate arg] InstanceArg { name: "5", kind: Module, index: 1 } -0x00c1 | 01 36 06 01 | [instantiate arg] InstanceArg { name: "6", kind: Instance, index: 1 } diff --git a/tests/dump/module-linking.wat.fixme b/tests/dump/module-linking.wat.fixme deleted file mode 100644 index 6eb307bc72..0000000000 --- a/tests/dump/module-linking.wat.fixme +++ /dev/null @@ -1,28 +0,0 @@ -(module - (import "" (instance $i - (export "1" (func $func)) - (export "2" (memory $memory 1)) - (export "3" (table $table 1 funcref)) - (export "4" (global $global i32)) - (export "5" (module $module)) - (export "6" (instance $instance)) - )) - - (module $m - (import "1" (func)) - (import "2" (memory 1)) - (import "3" (global i32)) - (import "4" (table 1 funcref)) - (import "5" (module)) - (import "6" (instance)) - ) - - (instance (instantiate $m - (import "1" (func $i "1")) - (import "2" (memory $i "2")) - (import "3" (global $i "4")) - (import "4" (table $i "3")) - (import "5" (module $i "5")) - (import "6" (instance $i "6")) - )) -) diff --git a/tests/dump/module-types.wat b/tests/dump/module-types.wat new file mode 100644 index 0000000000..e16c11a3a8 --- /dev/null +++ b/tests/dump/module-types.wat @@ -0,0 +1,9 @@ +(component + (import "" (core module $m + (import "" "f" (func)) + (import "" "g" (global i32)) + (import "" "t" (table 1 funcref)) + (import "" "m" (memory 1)) + )) + (type $empty (instance)) +) diff --git a/tests/dump/module-types.wat.dump b/tests/dump/module-types.wat.dump index 9a810df994..fd66f96a75 100644 --- a/tests/dump/module-types.wat.dump +++ b/tests/dump/module-types.wat.dump @@ -1,28 +1,19 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 2e | type section -0x000a | 04 | 4 count -0x000b | 62 00 | [type 0] Instance(InstanceType { exports: [] }) -0x000d | 61 00 00 | [type 1] Module(ModuleType { imports: [], exports: [] }) -0x0010 | 60 00 00 | [type 2] Func(FuncType { params: [], returns: [] }) -0x0013 | 61 06 00 00 | [type 3] Module(ModuleType { imports: [Import { module: "", field: None, ty: Module(1) }, Import { module: "", field: None, ty: Function(2) }, Import { module: "", field: None, ty: Global(GlobalType { content_type: I32, mutable: false }) }, Import { module: "", field: None, ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) }, Import { module: "", field: None, ty: Instance(0) }, Import { module: "", field: None, ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) }], exports: [] }) - | ff 05 01 00 - | 00 ff 00 02 - | 00 00 ff 03 - | 7f 00 00 00 - | ff 01 70 00 - | 01 00 00 ff - | 06 00 00 00 - | ff 02 00 01 - | 00 -0x0038 | 02 06 | import section -0x003a | 01 | 1 count -0x003b | 00 00 ff 05 | import [module 0] Import { module: "", field: None, ty: Module(3) } - | 03 -0x0040 | 00 0f | custom section -0x0042 | 04 6e 61 6d | name: "name" - | 65 -0x0047 | 04 08 | type names -0x0049 | 01 | 1 count -0x004a | 00 05 65 6d | Naming { index: 0, name: "empty" } - | 70 74 79 + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 04 23 | core type section + 0xa | 01 | 1 count + 0xb | 50 05 01 60 | [core type 0] Module([Type(Func(FuncType { params: [], returns: [] })), Import(Import { module: "", name: "f", ty: Func(0) }), Import(Import { module: "", name: "g", ty: Global(GlobalType { content_type: I32, mutable: false }) }), Import(Import { module: "", name: "t", ty: Table(TableType { element_type: FuncRef, initial: 1, maximum: None }) }), Import(Import { module: "", name: "m", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None }) })]) + | 00 00 00 00 + | 01 66 00 00 + | 00 00 01 67 + | 03 7f 00 00 + | 00 01 74 01 + | 70 00 01 00 + | 00 01 6d 02 + | 00 01 + 0x2d | 0b 05 | component import section + 0x2f | 01 | 1 count + 0x30 | 00 00 11 00 | [module 0] ComponentImport { name: "", ty: Module(0) } + 0x34 | 08 03 | component type section + 0x36 | 01 | 1 count + 0x37 | 42 00 | [type 0] Instance([]) diff --git a/tests/dump/module-types.wat.fixme b/tests/dump/module-types.wat.fixme deleted file mode 100644 index 887f6aaa1b..0000000000 --- a/tests/dump/module-types.wat.fixme +++ /dev/null @@ -1,11 +0,0 @@ -(module - (import "" (module $m - (import "" (module)) - (import "" (func)) - (import "" (global i32)) - (import "" (table 1 funcref)) - (import "" (instance)) - (import "" (memory 1)) - )) - (type $empty (instance)) -) diff --git a/tests/dump/nested-component.wat b/tests/dump/nested-component.wat new file mode 100644 index 0000000000..714e77328d --- /dev/null +++ b/tests/dump/nested-component.wat @@ -0,0 +1,23 @@ + +(component + (component (import "")) + + (component) + (component) + + (component (export "x")) + + (component + (component) + ) + + (component + (core module $m) + (import "" (func (param string))) + (export "a" (core module $m)) + + (instance (export "b") (import "") + (export "b" (func)) + ) + ) +) diff --git a/tests/dump/nested-component.wat.dump b/tests/dump/nested-component.wat.dump new file mode 100644 index 0000000000..fea5779333 --- /dev/null +++ b/tests/dump/nested-component.wat.dump @@ -0,0 +1,59 @@ + 0x0 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x8 | 08 03 | component type section + 0xa | 01 | 1 count + 0xb | 41 00 | [type 0] Component([]) + 0xd | 0b 04 | component import section + 0xf | 01 | 1 count + 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } + 0x13 | 05 08 | [component 1] inline size + 0x15 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x1d | 05 08 | [component 2] inline size + 0x1f | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x27 | 05 08 | [component 3] inline size + 0x29 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x31 | 05 12 | [component 4] inline size + 0x33 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x3b | 05 08 | [component 0] inline size + 0x3d | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x45 | 05 4e | [component 5] inline size + 0x47 | 00 61 73 6d | version 65546 (Component) + | 0a 00 01 00 + 0x4f | 01 13 | [core module 0] inline size + 0x51 | 00 61 73 6d | version 1 (Module) + | 01 00 00 00 + 0x59 | 00 09 | custom section + 0x5b | 04 6e 61 6d | name: "name" + | 65 + 0x60 | 00 02 | module name + 0x62 | 01 6d | "m" + 0x64 | 08 06 | component type section + 0x66 | 01 | 1 count + 0x67 | 40 01 00 72 | [type 0] Func(ComponentFuncType { params: [(None, Primitive(String))], result: Primitive(Unit) }) + | 7f + 0x6c | 0b 04 | component import section + 0x6e | 01 | 1 count + 0x6f | 00 01 00 | [func 0] ComponentImport { name: "", ty: Func(0) } + 0x72 | 0c 06 | component export section + 0x74 | 01 | 1 count + 0x75 | 01 61 00 11 | export ComponentExport { name: "a", kind: Module, index: 0 } + | 00 + 0x7a | 08 0c | component type section + 0x7c | 01 | 1 count + 0x7d | 42 02 01 40 | [type 1] Instance([Type(Func(ComponentFuncType { params: [], result: Primitive(Unit) })), Export { name: "b", ty: Func(0) }]) + | 00 7f 04 01 + | 62 01 00 + 0x88 | 0b 04 | component import section + 0x8a | 01 | 1 count + 0x8b | 00 05 01 | [instance 0] ComponentImport { name: "", ty: Instance(1) } + 0x8e | 0c 05 | component export section + 0x90 | 01 | 1 count + 0x91 | 01 62 05 00 | export ComponentExport { name: "b", kind: Instance, index: 0 } + 0x95 | 0c 05 | component export section + 0x97 | 01 | 1 count + 0x98 | 01 78 04 03 | export ComponentExport { name: "x", kind: Component, index: 3 } diff --git a/tests/dump/nested-module.wat.dump b/tests/dump/nested-module.wat.dump deleted file mode 100644 index 5f2f188d9c..0000000000 --- a/tests/dump/nested-module.wat.dump +++ /dev/null @@ -1,64 +0,0 @@ -0x0000 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0008 | 01 04 | type section -0x000a | 01 | 1 count -0x000b | 61 00 00 | [type 0] Module(ModuleType { imports: [], exports: [] }) -0x000e | 02 06 | import section -0x0010 | 01 | 1 count -0x0011 | 00 00 ff 05 | import [module 0] Import { module: "", field: None, ty: Module(0) } - | 00 -0x0016 | 0e 7f | module section -0x0018 | 05 | 5 count -0x0019 | 08 | inline module size - 0x001a | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0022 | 08 | inline module size - 0x0023 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x002b | 08 | inline module size - 0x002c | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0034 | 14 | inline module size - 0x0035 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x003d | 0e 0a | module section - 0x003f | 01 | 1 count - 0x0040 | 08 | inline module size - 0x0041 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 -0x0049 | 4d | inline module size - 0x004a | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x0052 | 0e 15 | module section - 0x0054 | 01 | 1 count - 0x0055 | 13 | inline module size - 0x0056 | 00 61 73 6d | version 1 (Module) - | 01 00 00 00 - 0x005e | 00 09 | custom section - 0x0060 | 04 6e 61 6d | name: "name" - | 65 - 0x0065 | 00 02 | module name - 0x0067 | 01 6d | "m" - 0x0069 | 01 05 | type section - 0x006b | 01 | 1 count - 0x006c | 60 01 7f 00 | [type 0] Func(FuncType { params: [I32], returns: [] }) - 0x0070 | 02 06 | import section - 0x0072 | 01 | 1 count - 0x0073 | 00 00 ff 00 | import [func 0] Import { module: "", field: None, ty: Function(0) } - | 00 - 0x0078 | 01 0a | type section - 0x007a | 02 | 2 count - 0x007b | 60 00 00 | [type 1] Func(FuncType { params: [], returns: [] }) - 0x007e | 62 01 01 62 | [type 2] Instance(InstanceType { exports: [ExportType { name: "b", ty: Function(1) }] }) - | 00 01 - 0x0084 | 02 06 | import section - 0x0086 | 01 | 1 count - 0x0087 | 00 00 ff 06 | import [instance 0] Import { module: "", field: None, ty: Instance(2) } - | 02 - 0x008c | 07 09 | export section - 0x008e | 02 | 2 count - 0x008f | 01 61 05 00 | export Export { name: "a", kind: Module, index: 0 } - 0x0093 | 01 62 06 00 | export Export { name: "b", kind: Instance, index: 0 } -0x0097 | 07 05 | export section -0x0099 | 01 | 1 count -0x009a | 01 78 05 03 | export Export { name: "x", kind: Module, index: 3 } diff --git a/tests/dump/nested-module.wat.fixme b/tests/dump/nested-module.wat.fixme deleted file mode 100644 index 4d2b8602af..0000000000 --- a/tests/dump/nested-module.wat.fixme +++ /dev/null @@ -1,23 +0,0 @@ - -(module - (module (import "")) - - (module) - (module) - - (module (export "x")) - - (module - (module) - ) - - (module - (module $m) - (import "" (func (param i32))) - (export "a" (module $m)) - - (instance (export "b") (import "") - (export "b" (func)) - ) - ) -) diff --git a/tests/local/component-model/a.wast b/tests/local/component-model/a.wast index eef64725ed..0c2126fdd3 100644 --- a/tests/local/component-model/a.wast +++ b/tests/local/component-model/a.wast @@ -7,7 +7,7 @@ (import "two" (value string)) (import "three" (instance (export "four" (instance - (export "five" (module + (export "five" (core module (import "six" "a" (func)) (import "six" "b" (func)) )) diff --git a/tests/local/component-model/adapt.wast b/tests/local/component-model/adapt.wast index 3b0cfdf0e1..3f873993f0 100644 --- a/tests/local/component-model/adapt.wast +++ b/tests/local/component-model/adapt.wast @@ -1,14 +1,12 @@ (component (import "log" (func $log (param string))) - (module $libc + (core module $libc (memory (export "memory") 1) (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) unreachable) - (func (export "canonical_abi_free") (param i32 i32 i32) - unreachable) ) - (module $my_module + (core module $my_module (import "env" "log-utf8" (func $log_utf8 (param i32 i32))) (import "env" "log-utf16" (func $log_utf16 (param i32 i32))) (import "env" "log-compact-utf16" (func $log_compact_utf16 (param i32 i32))) @@ -30,13 +28,13 @@ ) ) - (instance $libc (instantiate (module $libc))) + (core instance $libc (instantiate $libc)) - (func $log_lower_utf8 (canon.lower string=utf8 (into $libc) (func $log))) - (func $log_lower_utf16 (canon.lower string=utf16 (into $libc) (func $log))) - (func $log_lower_compact_utf16 (canon.lower string=latin1+utf16 (into $libc) (func $log))) + (core func $log_lower_utf8 (canon lower (func $log) string-encoding=utf8 (memory (core memory $libc "memory")) (realloc (core func $libc "canonical_abi_realloc")))) + (core func $log_lower_utf16 (canon lower (func $log) string-encoding=utf16 (memory (core memory $libc "memory")) (realloc (core func $libc "canonical_abi_realloc")))) + (core func $log_lower_compact_utf16 (canon lower (func $log) string-encoding=latin1+utf16 (memory (core memory $libc "memory")) (realloc (core func $libc "canonical_abi_realloc")))) - (instance $my_instance (instantiate (module $my_module) + (core instance $my_instance (instantiate $my_module (with "libc" (instance $libc)) (with "env" (instance (export "log-utf8" (func $log_lower_utf8)) @@ -45,174 +43,243 @@ )) )) - (func (export "log1") - (canon.lift (func (param string)) string=utf8 (into $libc) - (func $my_instance "log-utf8"))) - (func (export "log2") - (canon.lift (func (param string)) string=utf16 (into $libc) - (func $my_instance "log-utf16"))) - (func (export "log3") - (canon.lift (func (param string)) string=latin1+utf16 (into $libc) - (func $my_instance "log-compact-utf16"))) + (func (export "log1") (param string) + (canon lift + (core func $my_instance "log-utf8") + string-encoding=utf8 + (memory (core memory $libc "memory")) + (realloc (core func $libc "canonical_abi_realloc")) + ) + ) + (func (export "log2") (param string) + (canon lift + (core func $my_instance "log-utf16") + string-encoding=utf16 + (memory (core memory $libc "memory")) + (realloc (core func $libc "canonical_abi_realloc")) + ) + ) + (func (export "log3") (param string) + (canon lift + (core func $my_instance "log-compact-utf16") + string-encoding=latin1+utf16 + (memory (core memory $libc "memory")) + (realloc (core func $libc "canonical_abi_realloc")) + ) + ) ) (assert_invalid (component (import "" (func $f)) - (func (canon.lower string=utf8 string=utf16 (func $f))) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=utf16)) ) - "canonical option `utf8` conflicts with option `utf16`") + "canonical encoding option `utf8` conflicts with option `utf16`") (assert_invalid (component (import "" (func $f)) - (func (canon.lower string=utf8 string=latin1+utf16 (func $f))) + (core func (canon lower (func $f) string-encoding=utf8 string-encoding=latin1+utf16)) ) - "canonical option `utf8` conflicts with option `compact-utf16`") + "canonical encoding option `utf8` conflicts with option `latin1-utf16`") (assert_invalid (component (import "" (func $f)) - (func (canon.lower string=utf16 string=latin1+utf16 (func $f))) + (core func (canon lower (func $f) string-encoding=utf16 string-encoding=latin1+utf16)) ) - "canonical option `utf16` conflicts with option `compact-utf16`") + "canonical encoding option `utf16` conflicts with option `latin1-utf16`") (assert_invalid (component (import "" (func $f)) - (func (canon.lower (into 0) (func $f))) + (core func (canon lower (func $f) (memory (core memory 0)))) ) - "instance index out of bounds") + "memory index out of bounds") (assert_invalid (component (import "" (func $f)) - (import "i" (instance $i)) - (func (canon.lower (into $i) (func $f))) + (core module $m (memory (export "memory") 1)) + (core instance $i (instantiate $m)) + (core func (canon lower (func $f) (memory (core memory $i "memory")) (memory (core memory $i "memory")))) ) - "not a module instance") + "`memory` is specified more than once") (assert_invalid (component - (import "" (func $f)) - (module $m) - (instance $i (instantiate (module $m))) - (func (canon.lower (into $i) (into $i) (func $f))) + (core module $m + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param (list u8)) (canon lift (core func $i "f"))) ) - "`into` is specified more than once") + "canonical option `memory` is required") (assert_invalid (component - (module $m - (func (export "") (param i32 i32)) + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + ) + (core instance $i (instantiate $m)) + (func (param (list u8)) + (canon lift (core func $i "f") + (memory (core memory $i "m")) + ) ) - (instance $i (instantiate (module $m))) - (func (canon.lift (func (param (list u8))) (func $i ""))) ) - "canonical option `into` is required") + "canonical option `realloc` is required") (assert_invalid (component - (module $m - (func (export "") (param i32 i32)) + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + ) + (core instance $i (instantiate $m)) + (func (param (list u8)) + (canon lift (core func $i "f") + (memory (core memory $i "m")) + (realloc (core func $i "r")) + (realloc (core func $i "r")) + ) ) - (instance $i (instantiate (module $m))) - (func (canon.lift (func (param (list u8))) (into $i) (func $i ""))) ) - "does not export a memory") + "canonical option `realloc` is specified more than once") (assert_invalid (component - (module $m - (func (export "") (param i32 i32)) - (memory (export "memory") 0) + (core module $m + (memory (export "m") 1) + (func (export "f") (param i32 i32)) + (func (export "r")) + ) + (core instance $i (instantiate $m)) + (func (param (list u8)) + (canon lift (core func $i "f") + (memory (core memory $i "m")) + (realloc (core func $i "r")) + ) ) - (instance $i (instantiate (module $m))) - (func (canon.lift (func (param (list u8))) (into $i) (func $i ""))) ) - "does not export a function named `canonical_abi_realloc`") + "canonical option `realloc` uses a core function with an incorrect signature") (assert_invalid (component - (module $m - (func (export "") (param i32 i32)) - (memory (export "memory") 0) - (func (export "canonical_abi_realloc")) + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p")) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory (core memory $i "m")) + (realloc (core func $i "r")) + (post-return (core func $i "p")) + ) ) - (instance $i (instantiate (module $m))) - (func (canon.lift (func (param (list u8))) (into $i) (func $i ""))) ) - "wrong signature") + "canonical option `post-return` uses a core function with an incorrect signature") (assert_invalid (component - (module $m - (func (export "") (param i32 i32)) - (memory (export "memory") 0) - (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) - unreachable) + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory (core memory $i "m")) + (realloc (core func $i "r")) + (post-return (core func $i "p")) + (post-return (core func $i "p")) + ) ) - (instance $i (instantiate (module $m))) - (func (canon.lift (func (param (list u8))) (into $i) (func $i ""))) ) - "does not export a function named `canonical_abi_free`") + "canonical option `post-return` is specified more than once") (assert_invalid (component - (module $m - (func (export "") (param i32 i32)) - (memory (export "memory") 0) - (func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32) - unreachable) - (func (export "canonical_abi_free")) + (import "" (func $f (param string))) + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32)) + (func (export "r") (param i32 i32 i32 i32) (result i32)) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (core func + (canon lower (func $f) + (memory (core memory $i "m")) + (realloc (core func $i "r")) + (post-return (core func $i "p")) + ) + ) + ) + "canonical option `post-return` cannot be specified for lowerings") + +(component + (core module $m + (memory (export "m") 1) + (func (export "f") (result i32) unreachable) + (func (export "r") (param i32 i32 i32 i32) (result i32) unreachable) + (func (export "p") (param i32)) + ) + (core instance $i (instantiate $m)) + (func (result string) + (canon lift (core func $i "f") + (memory (core memory $i "m")) + (realloc (core func $i "r")) + (post-return (core func $i "p")) ) - (instance $i (instantiate (module $m))) - (func (canon.lift (func (param (list u8))) (into $i) (func $i ""))) ) - "wrong signature") +) (assert_invalid (component - (module $m + (core module $m (func (export "")) ) - (instance $i (instantiate (module $m))) - (func (canon.lower (func $i ""))) + (core instance $i (instantiate $m)) + (core func (canon lower (func $i ""))) ) - "not a component function") + "failed to find instance named `$i`") (assert_invalid (component - (module $m (func (export "foo") (param i32))) - (instance $i (instantiate (module $m))) - (func (export "foo") - (canon.lift (func) (func $i "foo"))) + (core module $m (func (export "foo") (param i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) ) "lowered parameter types `[]` do not match parameter types `[I32]`") (assert_invalid (component - (module $m (func (export "foo") (result i32))) - (instance $i (instantiate (module $m))) - (func (export "foo") - (canon.lift (func) (func $i "foo"))) + (core module $m (func (export "foo") (result i32))) + (core instance $i (instantiate $m)) + (func (export "foo") (canon lift (core func $i "foo"))) ) "lowered result types `[]` do not match result types `[I32]`") (assert_invalid (component (type $f string) - (module $m (func (export "foo"))) - (instance $i (instantiate (module $m))) - (func (export "foo") - (canon.lift (type $f) (func $i "foo"))) + (core module $m (func (export "foo"))) + (core instance $i (instantiate $m)) + (func (export "foo") (type $f) (canon lift (core func $i "foo"))) ) "not a function type") (assert_invalid (component (import "" (func $f)) - (func (export "foo") - (canon.lift (func) (func $f))) + (func (export "foo") (canon lift (core func $f))) ) - "not a core WebAssembly function") + "failed to find core func named `$f`") diff --git a/tests/local/component-model/alias.wast b/tests/local/component-model/alias.wast index bd308754ec..99ae4e6e38 100644 --- a/tests/local/component-model/alias.wast +++ b/tests/local/component-model/alias.wast @@ -1,5 +1,3 @@ -;; FIXME(#588) should be valid -(assert_invalid (component (import "i" (instance $i (export "f1" (func $f1)) @@ -7,48 +5,44 @@ )) (export "run" (func $i "f1")) ) -"instance 0 is not a module instance") -;; FIXME(#588) should be valid -(assert_invalid (component (import "i" (component $c (export "f1" (func $f1)) (export "f2" (func $f2 (param string))) )) - (instance $i (instantiate (component $c))) + (instance $i (instantiate $c)) (export "run" (func $i "f1")) ) -"instance 0 is not a module instance") (component - (import "i" (module $m + (import "i" (core module $m (export "f1" (func $f1)) (export "f2" (func $f2 (param i32))) )) - (instance $i (instantiate (module $m))) + (core instance $i (instantiate $m)) - (module $m2 (import "" "" (func))) + (core module $m2 (import "" "" (func))) - (instance (instantiate (module $m2) (with "" (instance (export "" (func $i "f1")))))) + (core instance (instantiate $m2 (with "" (instance (export "" (func $i "f1")))))) ) (component - (import "" (module $libc + (import "" (core module $libc (export "memory" (memory 1)) (export "table" (table 0 funcref)) (export "func" (func)) (export "global" (global i32)) (export "global mut" (global (mut i64))) )) - (instance $libc (instantiate (module $libc))) - (alias export $libc "memory" (memory $mem)) - (alias export $libc "table" (table $tbl)) - (alias export $libc "func" (func $func)) - (alias export $libc "global" (global $global)) - (alias export $libc "global mut" (global $global_mut)) - - (import "x" (module $needs_libc + (core instance $libc (instantiate $libc)) + (core alias export $libc "memory" (memory $mem)) + (core alias export $libc "table" (table $tbl)) + (core alias export $libc "func" (func $func)) + (core alias export $libc "global" (global $global)) + (core alias export $libc "global mut" (global $global_mut)) + + (import "x" (core module $needs_libc (import "" "memory" (memory 1)) (import "" "table" (table 0 funcref)) (import "" "func" (func)) @@ -56,7 +50,7 @@ (import "" "global mut" (global (mut i64))) )) - (instance (instantiate (module $needs_libc) (with "" (instance + (core instance (instantiate $needs_libc (with "" (instance (export "memory" (memory $mem)) (export "table" (table $tbl)) (export "func" (func $func)) @@ -65,22 +59,19 @@ )))) ) -;; FIXME(#588) should be valid -(assert_invalid (component (import "" (instance $i (export "1" (func)) - (export "2" (module)) + (export "2" (core module)) (export "3" (instance)) )) (export "1" (func $i "1")) - (export "2" (module $i "2")) + (export "2" (core module $i "2")) (export "3" (instance $i "3")) ) -"instance 0 is not a module instance") (component - (import "" (module $libc + (import "" (core module $libc (export "memory" (memory 1)) (export "table" (table 0 funcref)) (export "func" (func)) @@ -88,7 +79,7 @@ (export "global mut" (global (mut i64))) )) - (import "x" (module $needs_libc + (import "x" (core module $needs_libc (import "" "memory" (memory 1)) (import "" "table" (table 0 funcref)) (import "" "func" (func)) @@ -96,8 +87,8 @@ (import "" "global mut" (global (mut i64))) )) - (instance $libc (instantiate (module $libc))) - (instance (instantiate (module $needs_libc) (with "" (instance + (core instance $libc (instantiate $libc)) + (core instance (instantiate $needs_libc (with "" (instance (export "memory" (memory $libc "memory")) (export "table" (table $libc "table")) (export "func" (func $libc "func")) @@ -106,26 +97,10 @@ )))) ) -(assert_invalid - (component $outer - (import "" (instance $i (export "a" (func)))) - - (import "a" (component $m - (import "" (component (export "a" (func)))) - )) - - (component $local - (alias outer $outer $i (instance)) - ) - - (instance (instantiate (component $m) (with "" (component $local)))) - ) - "invalid leading byte (0xff) for outer alias") - (assert_invalid (component (import "" (instance (export "" (func)))) - (export "" (module 0 "")) + (export "" (core module 0 "")) ) "export `` for instance 0 is not a module") @@ -134,44 +109,42 @@ (component (component (export "")) ) - (instance (instantiate (component 0))) - (export "" (module 0 "")) + (instance (instantiate 0)) + (export "" (core module 0 "")) ) "export `` for instance 0 is not a module") (assert_invalid (component - (import "" (module)) - (instance (instantiate (module 0))) - (alias export 0 "" (func)) + (import "" (core module)) + (core instance (instantiate 0)) + (core alias export 0 "" (func)) ) - "instance 0 has no export named ``") + "core instance 0 has no export named ``") (assert_invalid (component - (module) - (instance (instantiate (module 0))) - (alias export 0 "" (func)) + (core module) + (core instance (instantiate 0)) + (core alias export 0 "" (func)) ) - "instance 0 has no export named ``") + "core instance 0 has no export named ``") -;; FIXME(#588) should have a different error (assert_invalid (component (import "" (component)) - (instance (instantiate (component 0))) + (instance (instantiate 0)) (alias export 0 "" (func)) ) - "instance 0 is not a module instance") - (; "instance 0 has no export named ``") ;) + "instance 0 has no export named ``") (assert_invalid (component - (import "a" (module $a (export "" (func)))) - (import "b" (module $b (import "" "" (func (param i32))))) + (import "a" (core module $a (export "" (func)))) + (import "b" (core module $b (import "" "" (func (param i32))))) - (instance $a (instantiate (module $a))) - (instance $b (instantiate (module $b) (with "" (instance $a)))) + (core instance $a (instantiate $a)) + (core instance $b (instantiate $b (with "" (instance $a)))) ) "type mismatch") @@ -207,7 +180,7 @@ (import "c" (func (result s32))) )) - (instance (instantiate (component $C) + (instance (instantiate $C (with "a" (func $a)) (with "b" (func $b)) (with "c" (func $c)) @@ -218,8 +191,6 @@ ) ;; multiple projections in alias sugar -;; FIXME(#588) should be valid -(assert_invalid (component $a (import "" (instance $a (export "b" (instance @@ -233,11 +204,10 @@ (import "b" (component $b (import "" (func)))) - (instance (instantiate (component $b) + (instance (instantiate $b (with "" (func $a "b" "c" "d" "f")) )) ) -"instance 3 is not a module instance") ;; alias some constructs (component @@ -251,14 +221,14 @@ ) (component - (import "" (instance $foo (export "v" (module)))) - (export "v" (module $foo "v")) + (import "" (instance $foo (export "v" (core module)))) + (export "v" (core module $foo "v")) ) (component $C - (module $m) - (alias outer $C $m (module $target)) - (export "v" (module $target)) + (core module $m) + (alias outer $C $m (core module $target)) + (export "v" (core module $target)) ) (component $C @@ -268,11 +238,11 @@ ) (assert_invalid - (component (alias outer 100 0 (module))) + (component (alias outer 100 0 (core module))) "invalid outer alias count of 100") (assert_invalid - (component (alias outer 0 0 (module))) + (component (alias outer 0 0 (core module))) "index out of bounds") (assert_invalid diff --git a/tests/local/component-model/big.wast b/tests/local/component-model/big.wast index 5b8db82f20..56c61f3d46 100644 --- a/tests/local/component-model/big.wast +++ b/tests/local/component-model/big.wast @@ -1,38 +1,34 @@ -;; With this, we can finally write a non-trivial component that takes a string, does some logging, then returns a string. - -;; FIXME(#588) this should actuall be a valid module -(assert_invalid (component (import "wasi:logging" (instance $logging (export "log" (func (param string))) )) - (import "libc" (module $Libc + (import "libc" (core module $Libc (export "memory" (memory 1)) - (export "realloc" (func (param i32 i32) (result i32))) - (export "free" (func (param i32))) + (export "realloc" (func (param i32 i32 i32 i32) (result i32))) )) - (instance $libc (instantiate (module $Libc))) - (func $log - (canon.lower (into $libc) (func $logging "log")) - ) - (module $Main + (core instance $libc (instantiate $Libc)) + (core func $log (canon lower + (func $logging "log") + (memory (core memory $libc "memory")) (realloc (core func $libc "realloc")) + )) + (core module $Main (import "libc" "memory" (memory 1)) - (import "libc" "realloc" (func (param i32 i32) (result i32))) - (import "libc" "free" (func (param i32))) + (import "libc" "realloc" (func (param i32 i32 i32 i32) (result i32))) (import "wasi:logging" "log" (func $log (param i32 i32))) - (func (export "run") (param i32 i32) (result i32 i32) - ;; ... + (func (export "run") (param i32 i32) (result i32) + (local.get 0) + (local.get 1) (call $log) - ;; ... (unreachable) ) ) - (instance $main (instantiate (module $Main) + (core instance $main (instantiate $Main (with "libc" (instance $libc)) (with "wasi:logging" (instance (export "log" (func $log)))) )) - (func (export "run") - (canon.lift (func (param string) (result string)) (into $libc) (func $main "run")) - ) + (func $run (param string) (result string) (canon lift + (core func $main "run") + (memory (core memory $libc "memory")) (realloc (core func $libc "realloc")) + )) + (export "run" (func $run)) ) -"not a module instance") diff --git a/tests/local/component-model/intertypes.wast b/tests/local/component-model/definedtypes.wast similarity index 65% rename from tests/local/component-model/intertypes.wast rename to tests/local/component-model/definedtypes.wast index 82de5f98a7..91fe642b31 100644 --- a/tests/local/component-model/intertypes.wast +++ b/tests/local/component-model/definedtypes.wast @@ -21,10 +21,8 @@ (type $A15a (variant)) (type $A15b (variant (case "x" unit))) (type $A15c (variant (case "x" $A1))) - - ;; FIXME(#594) should implement this - (; (type $A15d (variant (case "x" unit (defaults-to "x")))) ;) - (; (type $A15e (variant (case "x" $A2 (defaults-to "x")))) ;) + (type $A15e (variant (case $x "x" unit) (case $y "y" string (refines $x)) (case "z" string (refines $y)))) + (type $A15f (variant (case "x" unit) (case "y" string (refines 0)) (case "z" string (refines 1)))) (type $A16a (list unit)) (type $A16b (list $A3)) @@ -54,31 +52,62 @@ (assert_invalid (component - (type $t (module)) - (type (func (param $t))) + (type $t (variant (case $x "x" string (refines $x)))) ) - "not an interface type") + "variant case cannot refine itself" +) (assert_invalid (component - (type $t (module)) - (type (func (result $t))) + (type $t (variant (case "x" unit (refines $y)) (case $y "y" string))) + ) + "failed to find variant case named `$y`" +) + +(assert_invalid + (component + (type $t string) + (type $v (variant (case "x" $t (refines $z)))) + ) + "failed to find variant case named `$z`" +) + +(assert_invalid + (component + (type $t string) + (type $v (variant (case "x" $t (refines 1)))) ) - "not an interface type") + "variant case refines index 1 is out of bounds" +) + +(assert_invalid + (component + (type $t string) + (type $v (variant (case $x "x" $t) (case $x "y" $t))) + ) + "duplicate variant case identifier" +) (assert_invalid (component - (type $t (module)) - (type (value $t)) + (type $t (func)) + (type (func (param $t))) + ) + "type index 0 is not a defined type") + +(assert_invalid + (component + (type $t (instance)) + (type (func (result $t))) ) - "not an interface type") + "type index 0 is not a defined type") (assert_invalid (component - (type $t (module)) + (type $t (component)) (type (option $t)) ) - "not an interface type") + "type index 0 is not a defined type") (assert_invalid (component (type (option 0))) diff --git a/tests/local/component-model/example.wast b/tests/local/component-model/example.wast index b41bcf7d16..f2d009efb3 100644 --- a/tests/local/component-model/example.wast +++ b/tests/local/component-model/example.wast @@ -2,13 +2,13 @@ (component (component - (module (func (export "one") (result i32) (i32.const 1))) - (module (func (export "two") (result f32) (f32.const 2))) + (core module (func (export "one") (result i32) (i32.const 1))) + (core module (func (export "two") (result f32) (f32.const 2))) ) - (module (func (export "three") (result i64) (i64.const 3))) + (core module (func (export "three") (result i64) (i64.const 3))) (component (component - (module (func (export "four") (result f64) (f64.const 4))) + (core module (func (export "four") (result f64) (f64.const 4))) ) ) (component) diff --git a/tests/local/component-model/export.wast b/tests/local/component-model/export.wast index 1f43f3901e..2cb0238dd9 100644 --- a/tests/local/component-model/export.wast +++ b/tests/local/component-model/export.wast @@ -1,10 +1,3 @@ -;; test that "bundle of exports" works in `export` statements -;; -;; TODO: may want to confirm with the spec whether or not this is intended. -(component - (export "" (instance)) -) - (assert_invalid (component (export "" (instance 0))) "index out of bounds") @@ -14,7 +7,7 @@ "index out of bounds") (assert_invalid - (component (export "" (module 0))) + (component (export "" (core module 0))) "index out of bounds") (assert_invalid @@ -27,13 +20,13 @@ (component (import "1" (instance $i)) - (import "2" (module $m)) + (import "2" (core module $m)) (import "3" (component $c)) (import "4" (value $v string)) (import "5" (func $f)) (export "1" (instance $i)) - (export "2" (module $m)) + (export "2" (core module $m)) (export "3" (component $c)) (export "4" (value $v)) (export "5" (func $f)) diff --git a/tests/local/component-model/import.wast b/tests/local/component-model/import.wast index 090c8ce3bb..6698a8dc22 100644 --- a/tests/local/component-model/import.wast +++ b/tests/local/component-model/import.wast @@ -6,31 +6,36 @@ (export "" (func)) )) (import "d" (component - (import "" (module)) + (import "" (core module)) (export "" (func)) )) ) -;; TODO: these tests will all eventually fail once the binary format is updated -;; again. Currently the text parser ignores the "kind" on the import field but -;; it will one day be encode as part of the binary format. -(component - (type $f (func)) - (import "" (instance (type $f))) -) -(component - (type $f (func)) - (import "" (module (type $f))) -) -(component - (type $f (module)) - (import "" (func (type $f))) -) +(assert_invalid + (component + (type $f (func)) + (import "" (instance (type $f))) + ) + "type index 0 is not an instance type") + +(assert_invalid + (component + (core type $f (func)) + (import "" (core module (type $f))) + ) + "core type index 0 is not a module type") + +(assert_invalid + (component + (type $f string) + (import "" (func (type $f))) + ) + "type index 0 is not a function type") ;; Disallow duplicate imports for core wasm modules (assert_invalid (component - (type (module + (core type (module (import "" "" (func)) (import "" "" (func)) )) @@ -38,7 +43,7 @@ "duplicate import name `:`") (assert_invalid (component - (module + (core module (import "" "" (func)) (import "" "" (func)) ) @@ -46,7 +51,7 @@ "duplicate import name `:`") (assert_invalid (component - (type (module + (core type (module (import "" "a" (func)) (import "" "a" (func)) )) @@ -54,7 +59,7 @@ "duplicate import name `:a`") (assert_invalid (component - (module + (core module (import "" "a" (func)) (import "" "a" (func)) ) @@ -85,9 +90,9 @@ (assert_invalid (component - (module $m (func (export ""))) - (instance $i (instantiate (module $m))) - (func (canon.lift (type 100) (func $i ""))) + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (func (type 100) (canon lift (core func $i ""))) ) "type index out of bounds") diff --git a/tests/local/component-model/imports-exports.wast b/tests/local/component-model/imports-exports.wast index b3a0c07170..1a7b463eaf 100644 --- a/tests/local/component-model/imports-exports.wast +++ b/tests/local/component-model/imports-exports.wast @@ -1,7 +1,5 @@ ;; With what's defined so far, we can define a component that imports, links and exports other components: -;; FIXME(#588) this should be valid -(assert_invalid (component (import "c" (instance $c (export "f" (func (result string))) @@ -12,14 +10,13 @@ )) (export "g" (func (result string))) )) - (instance $d1 (instantiate (component $D) + (instance $d1 (instantiate $D (with "c" (instance $c)) )) - (instance $d2 (instantiate (component $D) + (instance $d2 (instantiate $D (with "c" (instance (export "f" (func $d1 "g")) )) )) (export "d2" (instance $d2)) ) -"instance 1 is not a module instance") diff --git a/tests/local/component-model/instance-type.wast b/tests/local/component-model/instance-type.wast index 6ce614f8e8..dd597dacc2 100644 --- a/tests/local/component-model/instance-type.wast +++ b/tests/local/component-model/instance-type.wast @@ -6,7 +6,7 @@ (type $t (func (result string))) - (type (module + (core type (module (type $local_type (func)) ;; functions (export "a" (func)) @@ -81,7 +81,7 @@ ;; recursive (component - (type (instance (export "" (module + (type (instance (export "" (core module (type $functype (func)) (export "a" (func)) @@ -105,14 +105,14 @@ ;; modules (component - (type (module)) + (core type (module)) - (type $foo (module)) + (core type $foo (module)) (type $empty (func)) (type $i (instance)) - (type (module + (core type (module (type $empty (func)) (import "" "a" (func)) (import "" "b" (func (type $empty))) @@ -146,8 +146,8 @@ (export "c" (func (param s32))) )) - (import "k" (module)) - (import "l" (module + (import "k" (core module)) + (import "l" (core module (type $empty (func)) (import "" "a" (func (type $empty))) (import "" "b" (func (param i32))) @@ -165,7 +165,7 @@ (export "c" (func (param s32))) )) - (export "h" (module + (export "h" (core module (type $empty (func)) (import "" "a" (func (type $empty))) (import "" "b" (func (param i32))) @@ -182,56 +182,47 @@ (export "" (func))))) "duplicate export name") -;; FIXME(#590) these should all be invalid -(; (assert_invalid ;) +(assert_invalid (component (type $t (func)) (type (instance (export "" (instance (type $t))) ))) - (; "type index is not an instance") ;) + "type index 0 is not an instance type") -(; (assert_invalid ;) +(assert_invalid (component - (type $t (module)) + (core type $t (func)) (type (instance - (export "" (instance (type $t))) + (export "" (core module (type $t))) ))) - (; "type index is not an instance") ;) + "core type index 0 is not a module type") -(; (assert_invalid ;) +(assert_invalid (component (type $t (func)) (type (instance - (export "" (module (type $t))) - ))) - (; "type index is not a module") ;) - -(; (assert_invalid ;) - (component - (type $t (instance)) - (type (instance - (export "" (module (type $t))) + (export "" (core module (type $t))) ))) - (; "type index is not a module") ;) + "failed to find core type named `$t`") -(; (assert_invalid ;) +(assert_invalid (component - (type $t (module)) + (type $t (record (field "a" string))) (type (instance (export "" (func (type $t))) ))) - (; "type index is not a function") ;) + "type index 0 is not a function type") -(; (assert_invalid ;) +(assert_invalid (component (type $t (instance)) (type (instance (export "" (func (type $t))) ))) - (; "type index is not a function") ;) + "type index 0 is not a function type") -(; (assert_invalid ;) +(assert_invalid (component (type $t (instance)) (type (instance @@ -239,4 +230,4 @@ (export "" (func (type $t))) )) ))) - (; "type index is not a function") ;) + "type index 0 is not a function type") diff --git a/tests/local/component-model/instantiate.wast b/tests/local/component-model/instantiate.wast index 4c5dbb709c..9ca320e727 100644 --- a/tests/local/component-model/instantiate.wast +++ b/tests/local/component-model/instantiate.wast @@ -1,71 +1,71 @@ (component - (import "" (module $m)) - (instance $a (instantiate (module $m))) + (import "" (core module $m)) + (core instance $a (instantiate $m)) ) (component (import "a" (func $i)) (import "" (component $c (import "a" (func)))) - (instance (instantiate (component $c) (with "a" (func $i)))) + (instance (instantiate $c (with "a" (func $i)))) ) (component (import "a" (value $i string)) (import "" (component $c (import "a" (value string)))) - (instance (instantiate (component $c) (with "a" (value $i)))) + (instance (instantiate $c (with "a" (value $i)))) ) (component (import "a" (component $i)) (import "" (component $c (import "a" (component)))) - (instance (instantiate (component $c) (with "a" (component $i)))) + (instance (instantiate $c (with "a" (component $i)))) ) (component - (import "a" (module $i)) - (import "" (component $c (import "a" (module)))) - (instance (instantiate (component $c) (with "a" (module $i)))) + (import "a" (core module $i)) + (import "" (component $c (import "a" (core module)))) + (instance (instantiate $c (with "a" (core module $i)))) ) (component (import "a" (instance $i)) (import "" (component $c (import "a" (instance)))) - (instance (instantiate (component $c) (with "a" (instance $i)))) + (instance (instantiate $c (with "a" (instance $i)))) ) (component - (import "a" (module $m + (import "a" (core module $m (import "" "a" (func)) (import "" "b" (global i32)) (import "" "c" (table 1 funcref)) (import "" "d" (memory 1)) )) - (import "b" (module $m2 + (import "b" (core module $m2 (export "a" (func)) (export "b" (global i32)) (export "c" (table 1 funcref)) (export "d" (memory 1)) )) - (instance $x (instantiate (module $m2))) - (instance (instantiate (module $m) (with "" (instance $x)))) + (core instance $x (instantiate $m2)) + (core instance (instantiate $m (with "" (instance $x)))) ) (component - (import "a" (module $m + (import "a" (core module $m (import "" "d" (func)) (import "" "c" (global i32)) (import "" "b" (table 1 funcref)) (import "" "a" (memory 1)) )) - (import "b" (module $m2 + (import "b" (core module $m2 (export "a" (func)) (export "b" (global i32)) (export "c" (table 1 funcref)) (export "d" (memory 1)) )) - (instance $x (instantiate (module $m2))) + (core instance $x (instantiate $m2)) - (instance (instantiate (module $m) (with "" (instance + (core instance (instantiate $m (with "" (instance (export "d" (func $x "a")) (export "c" (global $x "b")) (export "b" (table $x "c")) @@ -76,38 +76,36 @@ (component (import "a" (component $m (import "" (instance - (export "a" (module)) + (export "a" (core module)) )) )) (import "b" (component $m2 - (export "b" (module)) + (export "b" (core module)) )) - (instance $x (instantiate (component $m2))) + (instance $x (instantiate $m2)) - (instance (instantiate (component $m) (with "" (instance - (export "a" (module $x "b")) + (instance (instantiate $m (with "" (instance + (export "a" (core module $x "b")) )))) ) -;; FIXME(#588) this should actually validate but it does not right now -(assert_invalid (component (import "a" (component $c - (import "a" (module)) + (import "a" (core module)) (import "b" (func)) (import "c" (component)) (import "d" (instance)) (import "e" (value string)) )) - (module $m (import "b")) + (core module $m (import "b")) (func $f (import "c")) (component $c2 (import "d")) (instance $i (import "e")) (import "f" (value $v string)) (instance - (instantiate (component $c) - (with "a" (module $m)) + (instantiate $c + (with "a" (core module $m)) (with "b" (func $f)) (with "c" (component $c2)) (with "d" (instance $i)) @@ -115,50 +113,50 @@ ) ) + (core instance $c (instantiate $m)) + (core instance (instantiate $m)) + ;; inline exports/imports - (instance $c (export "i") (instantiate (module $m))) (type $empty (instance)) (instance $d (import "i1") (type $empty)) (instance (import "i2")) (instance (import "i3") (export "x" (func))) - (instance (export "a") (export "b") (instantiate (module $m))) (instance (export "c") (export "d") (import "x")) ) -"instance 2 is not a component instance") (assert_invalid (component - (instance (instantiate (module 0))) + (core instance (instantiate 0)) ) "unknown module") (assert_invalid (component - (instance (instantiate (component 0))) + (instance (instantiate 0)) ) "unknown component") (assert_invalid (component - (import "" (module)) - (instance (instantiate (module 1))) + (import "" (core module)) + (core instance (instantiate 1)) ) "unknown module") (component (import "a" (func $f)) (import "b" (component $c)) - (instance (instantiate (component $c) (with "a" (func $f)))) + (instance (instantiate $c (with "a" (func $f)))) ) (assert_invalid (component - (import "" (module $m (import "" "" (func)))) - (instance (instantiate (module $m))) + (import "" (core module $m (import "" "" (func)))) + (core instance (instantiate $m)) ) "missing module instantiation argument") (assert_invalid (component (import "" (component $m (import "" (func)))) - (instance (instantiate (component $m))) + (instance (instantiate $m)) ) "missing component instantiation argument") @@ -168,20 +166,17 @@ (import "" (func)) )) (import "i" (component $c)) - (instance $i (instantiate (component $m) (with "" (component $c)))) + (instance $i (instantiate $m (with "" (component $c)))) ) "to be of type `function`") -;; FIXME(#587) this should be an invalid module -;; (assert_invalid - (component - (import "" (component $m - (import "" (func)) - )) - (import "i" (func $f (result string))) - (instance $i (instantiate (component $m) (with "" (func $f)))) - ) -;; "func type mismatch") +(component + (import "" (component $m + (import "" (func)) + )) + (import "i" (func $f (result string))) + (instance $i (instantiate $m (with "" (func $f)))) +) (assert_invalid (component @@ -189,62 +184,62 @@ (import "" (func)) )) (import "i" (func (param string))) - (instance $i (instantiate (component $m) (with "" (func 0)))) + (instance $i (instantiate $m (with "" (func 0)))) ) "function type mismatch") (assert_invalid (component (import "" (component $m - (import "" (module + (import "" (core module (import "" "" (func)) )) )) - (import "i" (module $i + (import "i" (core module $i (import "" "" (global i32)) )) - (instance $i (instantiate (component $m) (with "" (module $i)))) + (instance $i (instantiate $m (with "" (core module $i)))) ) "module type mismatch") (assert_invalid (component (import "" (component $m - (import "" (module)) + (import "" (core module)) )) - (import "i" (module $i + (import "i" (core module $i (import "" "foobar" (global i32)) )) - (instance $i (instantiate (component $m) (with "" (module $i)))) + (instance $i (instantiate $m (with "" (core module $i)))) ) "module type mismatch") ;; it's ok to give a module with fewer imports (component (import "" (component $m - (import "" (module + (import "" (core module (import "" "" (global i32)) (import "" "f" (func)) )) )) - (import "i" (module $i + (import "i" (core module $i (import "" "" (global i32)) )) - (instance $i (instantiate (component $m) (with "" (module $i)))) + (instance $i (instantiate $m (with "" (core module $i)))) ) ;; export subsets (component (import "" (component $m - (import "" (module + (import "" (core module (export "" (func)) )) )) - (import "i" (module $i + (import "i" (core module $i (export "" (func)) (export "a" (func)) )) - (instance $i (instantiate (component $m) (with "" (module $i)))) + (instance $i (instantiate $m (with "" (core module $i)))) ) (component (import "" (component $m @@ -256,7 +251,7 @@ (export "" (func)) (export "a" (func)) )) - (instance (instantiate (component $m) (with "" (instance $i)))) + (instance (instantiate $m (with "" (instance $i)))) ) @@ -265,99 +260,99 @@ (assert_invalid (component - (import "m1" (module $m1 (import "" "" (func)))) - (import "m2" (module $m2 (export "" (func (param i32))))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (param i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "function type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (func)))) - (import "m2" (module $m2 (export "" (func (result i32))))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (func)))) + (import "m2" (core module $m2 (export "" (func (result i32))))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "function type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (global i32)))) - (import "m2" (module $m2 (export "" (global i64)))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (global i32)))) + (import "m2" (core module $m2 (export "" (global i64)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "global type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (table 1 funcref)))) - (import "m2" (module $m2 (export "" (table 2 externref)))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (table 1 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 externref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "table type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (table 1 2 funcref)))) - (import "m2" (module $m2 (export "" (table 2 funcref)))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (table 1 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "table type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (table 2 2 funcref)))) - (import "m2" (module $m2 (export "" (table 1 funcref)))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 1 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "table type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (table 2 2 funcref)))) - (import "m2" (module $m2 (export "" (table 2 3 funcref)))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (table 2 2 funcref)))) + (import "m2" (core module $m2 (export "" (table 2 3 funcref)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "table type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (memory 1 2 shared)))) - (import "m2" (module $m2 (export "" (memory 1)))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (memory 1 2 shared)))) + (import "m2" (core module $m2 (export "" (memory 1)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "memory type mismatch") (assert_invalid (component - (import "m1" (module $m1 (import "" "" (memory 1)))) - (import "m2" (module $m2 (export "" (memory 0)))) - (instance $i (instantiate (module $m2))) - (instance (instantiate (module $m1) (with "" (instance $i)))) + (import "m1" (core module $m1 (import "" "" (memory 1)))) + (import "m2" (core module $m2 (export "" (memory 0)))) + (core instance $i (instantiate $m2)) + (core instance (instantiate $m1 (with "" (instance $i)))) ) "memory type mismatch") (assert_invalid (component - (instance (instantiate (module 0))) + (core instance (instantiate 0)) ) "unknown module") (component (component $m - (module $sub (export "module") + (core module $sub (export "module") (func $f (export "") (result i32) i32.const 5)) ) - (instance $a (instantiate (component $m))) - (alias export $a "module" (module $sub)) - (instance $b (instantiate (module $sub))) + (instance $a (instantiate $m)) + (alias export $a "module" (core module $sub)) + (core instance $b (instantiate $sub)) - (module $final + (core module $final (import "" "" (func $b (result i32))) (func (export "get") (result i32) call $b)) - (instance (instantiate (module $final) (with "" (instance $b)))) + (core instance (instantiate $final (with "" (instance $b)))) ) (assert_invalid @@ -377,7 +372,7 @@ "index out of bounds") (assert_invalid - (component (instance $i (export "" (module 0)))) + (component (instance $i (export "" (core module 0)))) "index out of bounds") (assert_invalid @@ -385,34 +380,25 @@ "index out of bounds") (assert_invalid - (component (instance core (export "" (func 0)))) + (component (core instance (export "" (func 0)))) "index out of bounds") (assert_invalid - (component (instance core (export "" (table 0)))) + (component (core instance (export "" (table 0)))) "index out of bounds") (assert_invalid - (component (instance core (export "" (global 0)))) + (component (core instance (export "" (global 0)))) "index out of bounds") (assert_invalid - (component (instance core (export "" (memory 0)))) + (component (core instance (export "" (memory 0)))) "index out of bounds") -(assert_invalid - (component - (import "" (instance $i)) - (module $m) - (instance (instantiate (module $m) (with "" (instance $i)))) - ) - "not a module instance") - -;; FIXME(#605) I think this should be invalid (component - (module $m) - (instance $i (instantiate (module $m))) - (instance (instantiate (module $m) + (core module $m) + (core instance $i (instantiate $m)) + (core instance (instantiate $m (with "" (instance $i)) (with "" (instance $i)) )) @@ -420,9 +406,9 @@ (assert_invalid (component - (module $m (func (export ""))) - (instance $i (instantiate (module $m))) - (instance (instantiate (module $m) + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance (instantiate $m (with "" (instance $i)) (with "" (instance $i)) )) @@ -431,29 +417,20 @@ (assert_invalid (component - (module $m1 (func (export ""))) - (module $m2 (import "" "" (global i32))) - (instance $i (instantiate (module $m1))) - (instance (instantiate (module $m2) + (core module $m1 (func (export ""))) + (core module $m2 (import "" "" (global i32))) + (core instance $i (instantiate $m1)) + (core instance (instantiate $m2 (with "" (instance $i)) )) ) "expected module instantiation argument `::` to be of type `global`") -(assert_invalid - (component - (module $m) - (instance $i (instantiate (module $m))) - (component $c) - (instance (instantiate (component $c) (with "" (instance $i)))) - ) - "not a component instance") - (assert_invalid (component (component $m) - (instance $i (instantiate (component $m))) - (instance (instantiate (component $m) + (instance $i (instantiate $m)) + (instance (instantiate $m (with "" (instance $i)) (with "" (instance $i)) )) @@ -463,7 +440,7 @@ (assert_invalid (component (component $c (import "" (func))) - (instance (instantiate (component $c) + (instance (instantiate $c (with "" (component $c)) )) ) @@ -472,8 +449,8 @@ (assert_invalid (component (component $c) - (instance (instantiate (component $c) - (with "" (module 0)) + (instance (instantiate $c + (with "" (core module 0)) )) ) "index out of bounds") @@ -481,7 +458,7 @@ (assert_invalid (component (component $c) - (instance (instantiate (component $c) + (instance (instantiate $c (with "" (value 0)) )) ) @@ -490,7 +467,7 @@ (assert_invalid (component (component $c) - (instance (instantiate (component $c) + (instance (instantiate $c (with "" (instance 0)) )) ) @@ -499,7 +476,7 @@ (assert_invalid (component (component $c) - (instance (instantiate (component $c) + (instance (instantiate $c (with "" (func 0)) )) ) @@ -508,7 +485,7 @@ (assert_invalid (component (component $c) - (instance (instantiate (component $c) + (instance (instantiate $c (with "" (component 100)) )) ) @@ -528,26 +505,26 @@ (import "1" (instance $i)) (import "2" (func $f)) (import "3" (component $c)) - (import "4" (module $m)) + (import "4" (core module $m)) (import "5" (value $v string)) (instance (export "1" (instance $i)) (export "2" (func $f)) (export "3" (component $c)) - (export "4" (module $m)) + (export "4" (core module $m)) (export "5" (value $v)) ) ) (component - (module $m + (core module $m (func (export "1")) (memory (export "2") 1) (table (export "3") 1 funcref) (global (export "4") i32 i32.const 0) ) - (instance $i (instantiate (module $m))) - (instance core + (core instance $i (instantiate $m)) + (core instance (export "a" (func $i "1")) (export "b" (memory $i "2")) (export "c" (table $i "3")) @@ -557,9 +534,9 @@ (assert_invalid (component - (module $m (func (export ""))) - (instance $i (instantiate (module $m))) - (instance core + (core module $m (func (export ""))) + (core instance $i (instantiate $m)) + (core instance (export "" (func $i "")) (export "" (func $i "")) ) @@ -569,7 +546,7 @@ (assert_invalid (component (component $c) - (instance $i (instantiate (component $c))) + (instance $i (instantiate $c)) (export "" (instance $i "")) ) "no export named ``") diff --git a/tests/local/component-model/invalid.wast b/tests/local/component-model/invalid.wast index 8aac06bfab..85b60d9493 100644 --- a/tests/local/component-model/invalid.wast +++ b/tests/local/component-model/invalid.wast @@ -1,21 +1,12 @@ (assert_invalid (component - (type (module + (core type (module (import "" "" (func (type 1))) )) (type (func)) ) "type index out of bounds") -(assert_invalid - (component - (import "" (func $f)) - (component - (alias outer 1 $f (func $f)) - ) - ) - "invalid leading byte") - (assert_malformed (component quote "(export \"\" (func $foo))" @@ -24,12 +15,12 @@ (assert_malformed (component quote - "(alias outer 100 $foo (func $foo))" + "(alias outer 100 $foo (type $foo))" ) "component depth of `100` is too large") (assert_malformed (component quote - "(alias outer $nonexistent $foo (func $foo))" + "(alias outer $nonexistent $foo (type $foo))" ) "outer component `nonexistent` not found") diff --git a/tests/local/component-model/link.wast b/tests/local/component-model/link.wast index 0c6e96c8f6..33e1796fa7 100644 --- a/tests/local/component-model/link.wast +++ b/tests/local/component-model/link.wast @@ -1,12 +1,12 @@ ;; Based on this, we can link two modules $A and $B together with the following component: (component - (module $A + (core module $A (func (export "one") (result i32) (i32.const 1)) ) - (module $B + (core module $B (func (import "a" "one") (result i32)) ) - (instance $a (instantiate (module $A))) - (instance $b (instantiate (module $B) (with "a" (instance $a)))) + (core instance $a (instantiate $A)) + (core instance $b (instantiate $B (with "a" (instance $a)))) ) diff --git a/tests/local/component-model/memory64.wast b/tests/local/component-model/memory64.wast index aad31e6424..6edc0da62b 100644 --- a/tests/local/component-model/memory64.wast +++ b/tests/local/component-model/memory64.wast @@ -1,21 +1,21 @@ (assert_invalid (component - (module $A + (core module $A (import "" "" (memory 1))) - (module $B + (core module $B (memory (export "") i64 1)) - (instance $b (instantiate (module $B))) - (instance $a (instantiate (module $A) (with "" (instance $b)))) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) ) "memory type mismatch") (assert_invalid (component - (module $A + (core module $A (import "" "" (memory i64 1))) - (module $B + (core module $B (memory (export "") 1)) - (instance $b (instantiate (module $B))) - (instance $a (instantiate (module $A) (with "" (instance $b)))) + (core instance $b (instantiate $B)) + (core instance $a (instantiate $A (with "" (instance $b)))) ) "memory type mismatch") diff --git a/tests/local/component-model/module-link.wast b/tests/local/component-model/module-link.wast index fa6b4bb868..ffaca03ed0 100644 --- a/tests/local/component-model/module-link.wast +++ b/tests/local/component-model/module-link.wast @@ -3,14 +3,10 @@ (component $B) (component $B_wrap (import "wasi" (instance $wasi (type $Wasi))) - (instance $b (instantiate (component $B))) + (instance $b (instantiate $B)) ) ) -;; FIXME(#588) this should be valid, or at least it ideally should be assuming -;; the rest of this test is updated. This is a pretty hard test to update while -;; that issue isn't implemented though. -(assert_invalid (component (type $Wasi (instance)) (import "wasi" (instance $wasi (type $Wasi))) @@ -19,13 +15,13 @@ (type $Wasi (instance)) (import "wasi" (instance (type $Wasi))) - (module $m + (core module $m (func (export "a")) ) - (instance $i (instantiate (module $m))) + (core instance $i (instantiate $m)) (func (export "a") - (canon.lift (func) (func $i "a")) + (canon lift (core func $i "a")) ) ) @@ -36,66 +32,65 @@ (import "wasi" (instance (type $Wasi))) (export "a" (func)) )) - (instance $a (instantiate (component $A) (with "wasi" (instance $wasi)))) + (instance $a (instantiate $A (with "wasi" (instance $wasi)))) - (func $lower (canon.lower (func $a "a"))) - (module $b + (core func $lower (canon lower (func $a "a"))) + (core module $b (import "a" "a" (func)) (func (export "b")) ) - (instance $b (instantiate (module $b) - (with "a" (instance (export "" (func $lower)))) + (core instance $b (instantiate $b + (with "a" (instance (export "a" (func $lower)))) )) (func (export "b") - (canon.lift (func) (func $b "a")) + (canon lift (core func $b "b")) ) ) (component $B_wrap (type $Wasi (instance)) (import "wasi" (instance $wasi (type $Wasi))) - (instance $b (instantiate (component $B) + (instance $b (instantiate $B (with "wasi" (instance $wasi)) (with "A:1.x" (component $A))) ) (export "b" (func $b "b")) ) - (; (component $C ;) - (; (type $Wasi (instance)) ;) - (; (import "wasi" (instance $wasi (type $Wasi))) ;) - (; (import "B:1.x" (component $B ;) - (; (import "wasi" (instance $wasi (type $Wasi))) ;) - (; (export "b" (func)) ;) - (; )) ;) - (; (instance $b (instantiate $B (import "wasi" (instance $wasi)))) ;) - (; (func (export "c")) ;) - (; ) ;) - (; (component $C_wrap ;) - (; (type $Wasi (instance)) ;) - (; (import "wasi" (instance $wasi (type $Wasi))) ;) - (; (instance $c (instantiate (component $C) ;) - (; (import "wasi" (instance $wasi)) ;) - (; (import "B:1.x" (component $B_wrap)) ;) - (; )) ;) - (; (export "c" (func $c "c")) ;) - (; ) ;) + (component $C + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "B:1.x" (component $B + (import "wasi" (instance $wasi (type $Wasi))) + (export "b" (func)) + )) + (instance $b (instantiate $B (with "wasi" (instance $wasi)))) + (export "c" (func $b "b")) + ) + (component $C_wrap + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (instance $c (instantiate $C + (with "wasi" (instance $wasi)) + (with "B:1.x" (component $B_wrap)) + )) + (export "c" (func $c "c")) + ) - (; (component $D ;) - (; (type $Wasi (instance)) ;) - (; (import "wasi" (instance $wasi (type $Wasi))) ;) - (; (import "C:1.x" (component $C ;) - (; (import "wasi" (instance $wasi (type $Wasi))) ;) - (; (export "c" (func)) ;) - (; )) ;) - (; (instance $c (instantiate $C (import "wasi" (instance $wasi)))) ;) - (; (func (export "d")) ;) - (; ) ;) + (component $D + (type $Wasi (instance)) + (import "wasi" (instance $wasi (type $Wasi))) + (import "C:1.x" (component $C + (import "wasi" (instance $wasi (type $Wasi))) + (export "c" (func)) + )) + (instance $c (instantiate $C (with "wasi" (instance $wasi)))) + (export "d" (func $c "c")) + ) - (; (instance $d (instantiate $D ;) - (; (import "wasi" (instance $wasi)) ;) - (; (import "C:1.x" (component $C_wrap)) ;) - (; )) ;) + (instance $d (instantiate $D + (with "wasi" (instance $wasi)) + (with "C:1.x" (component $C_wrap)) + )) - (; (export "d" (func $d "d")) ;) + (export "d" (func $d "d")) ) -"instance 1 is not a module instance") diff --git a/tests/local/component-model/nested-modules.wast b/tests/local/component-model/nested-modules.wast index d0d71bcd85..ca62ba658b 100644 --- a/tests/local/component-model/nested-modules.wast +++ b/tests/local/component-model/nested-modules.wast @@ -1,32 +1,32 @@ (component - (import "" (module)) + (import "" (core module)) - (module) - (module) + (core module) + (core module) - (module (export "x")) + (core module (export "x")) (component - (module) + (core module) ) (component - (module $m) + (core module $m) (import "" (func (param string))) - (export "a" (module $m)) + (export "a" (core module $m)) ) ) ;; does the `import` use the type annotation specified later? (component - (import "" (module)) - (type (module)) + (import "" (core module)) + (core type (module)) ) ;; be sure to typecheck nested modules (assert_invalid (component - (module + (core module (func i32.add) ) @@ -36,12 +36,12 @@ ;; interleave module definitions with imports/aliases and ensure that we ;; typecheck the module code section correctly (component - (module + (core module (func (export ""))) - (import "" (module)) - (module + (import "" (core module)) + (core module (func (export "") (result i32) i32.const 5)) - (import "b" (instance (export "" (module)))) - (alias export 0 "" (module)) + (import "b" (instance (export "" (core module)))) + (alias export 0 "" (core module)) ) diff --git a/tests/local/component-model/start.wast b/tests/local/component-model/start.wast index b6f0d6b3bd..c0307a6e9c 100644 --- a/tests/local/component-model/start.wast +++ b/tests/local/component-model/start.wast @@ -45,11 +45,3 @@ (start $f (result)) ) "cannot have more than one start") - -(assert_invalid - (component - (module $m (func (export ""))) - (instance $i (instantiate (module $m))) - (start (func $i "") (result)) - ) - "not a component function") diff --git a/tests/local/component-model/string.wast b/tests/local/component-model/string.wast index efe63a8eb5..19d0e0f6a7 100644 --- a/tests/local/component-model/string.wast +++ b/tests/local/component-model/string.wast @@ -1,27 +1,30 @@ ;; With this, we can define a component that imports a string and computes a new exported string, all at instantiation time: - (component (import "name" (value $name string)) - (import "libc" (module $Libc + (import "libc" (core module $Libc (export "memory" (memory 1)) (export "realloc" (func (param i32 i32 i32 i32) (result i32))) (export "free" (func (param i32 i32 i32))) (export "canonical_abi_realloc" (func (param i32 i32 i32 i32) (result i32))) - (export "canonical_abi_free" (func (param i32 i32 i32))) )) - (instance $libc (instantiate (module $Libc))) - (module $Main + (core instance $libc (instantiate $Libc)) + (core module $Main (import "libc" "memory" (memory 1)) (func (export "start") (param i32 i32) (result i32) ;;... general-purpose compute unreachable ) + (func (export "start-post-return") (param i32)) ) - (instance $main (instantiate (module $Main) (with "libc" (instance $libc)))) - (alias export $main "start" (func $main_func)) - (func $start - (canon.lift (func (param string) (result string)) (into $libc) (func $main_func)) + (core instance $main (instantiate $Main (with "libc" (instance $libc)))) + (core alias export $main "start" (func $main_func)) + (func $start (param string) (result string) + (canon lift (core func $main_func) + (memory (core memory $libc "memory")) + (realloc (core func $libc "canonical_abi_realloc")) + (post-return (core func $main "start-post-return")) + ) ) (start $start (value $name) (result (value $greeting))) (export "greeting" (value $greeting)) diff --git a/tests/local/component-model/types.wast b/tests/local/component-model/types.wast index bb4b8eb21a..eb41231e0c 100644 --- a/tests/local/component-model/types.wast +++ b/tests/local/component-model/types.wast @@ -1,55 +1,54 @@ -;; FIXME(#590) these should be invalid -(; (assert_invalid ;) +(assert_invalid (component (type $t (instance)) (import "" (func (type $t))) ) - (; "type index is not a function") ;) + "type index 0 is not a function type") -(; (assert_invalid ;) +(assert_invalid (component - (type $t (instance)) - (import "" (module (type $t))) + (core type $t (func)) + (import "" (core module (type $t))) ) - (; "type index is not a module") ;) + "core type index 0 is not a module type") -(; (assert_invalid ;) +(assert_invalid (component (type $t (func)) (import "" (instance (type $t))) ) - (; "type index is not an instance") ;) + "type index 0 is not an instance type") -(; (assert_invalid ;) +(assert_invalid (component (type $t (func)) (type (component (import "" (instance (type $t))) )) ) - (; "type index is not an instance") ;) + "type index 0 is not an instance type") -(; (assert_invalid ;) +(assert_invalid (component - (type $t (func)) + (core type $t (func)) (type (component - (import "" (module (type $t))) + (import "" (core module (type $t))) )) ) - (; "type index is not a module") ;) + "core type index 0 is not a module type") -(; (assert_invalid ;) +(assert_invalid (component (type $t (instance)) (type (component (import "" (func (type $t))) )) ) - (; "type index is not a func") ;) + "type index 0 is not a function type") (assert_invalid (component - (export "" (module 0)) + (export "" (core module 0)) ) "module index out of bounds") @@ -61,7 +60,7 @@ (assert_invalid (component - (type (module + (core type (module (export "" (func (type 0))) )) ) @@ -69,7 +68,7 @@ (assert_invalid (component - (type (module + (core type (module (export "" (func)) (export "" (func)) )) @@ -78,7 +77,7 @@ (assert_invalid (component - (type (module + (core type (module (import "" "" (func)) (import "" "" (func)) )) @@ -87,7 +86,7 @@ (assert_invalid (component - (type (module + (core type (module (import "" "" (memory 70000)) )) ) @@ -148,7 +147,7 @@ (component $c (type $f (func)) (type $t (component - (type (module + (core type (module (export "" (func)) (export "" (func)) )) @@ -202,7 +201,7 @@ (component $c (type $f (func)) (type $t (instance - (type (module + (core type (module (export "" (func)) (export "" (func)) )) diff --git a/tests/local/component-model/very-nested.wast b/tests/local/component-model/very-nested.wast index 38428192da..c008fb2925 100644 --- a/tests/local/component-model/very-nested.wast +++ b/tests/local/component-model/very-nested.wast @@ -1681,7 +1681,7 @@ )) (import "a" (component $a (type $m9))) (import "b" (component $b (type $m))) - (instance (instantiate (component $b) (with "" (component $a)))) + (instance (instantiate $b (with "" (component $a)))) ) "effective type size exceeds the limit") @@ -1689,88 +1689,88 @@ (component (component $m0) (component $m1 - (instance (export "0") (instantiate (component $m0))) - (instance (export "1") (instantiate (component $m0))) - (instance (export "2") (instantiate (component $m0))) - (instance (export "3") (instantiate (component $m0))) - (instance (export "4") (instantiate (component $m0))) - (instance (export "5") (instantiate (component $m0))) - (instance (export "6") (instantiate (component $m0))) - (instance (export "7") (instantiate (component $m0))) - (instance (export "8") (instantiate (component $m0))) - (instance (export "9") (instantiate (component $m0))) + (instance (export "0") (instantiate $m0)) + (instance (export "1") (instantiate $m0)) + (instance (export "2") (instantiate $m0)) + (instance (export "3") (instantiate $m0)) + (instance (export "4") (instantiate $m0)) + (instance (export "5") (instantiate $m0)) + (instance (export "6") (instantiate $m0)) + (instance (export "7") (instantiate $m0)) + (instance (export "8") (instantiate $m0)) + (instance (export "9") (instantiate $m0)) ) (component $m2 - (instance (export "0") (instantiate (component $m1))) - (instance (export "1") (instantiate (component $m1))) - (instance (export "2") (instantiate (component $m1))) - (instance (export "3") (instantiate (component $m1))) - (instance (export "4") (instantiate (component $m1))) - (instance (export "5") (instantiate (component $m1))) - (instance (export "6") (instantiate (component $m1))) - (instance (export "7") (instantiate (component $m1))) - (instance (export "8") (instantiate (component $m1))) - (instance (export "9") (instantiate (component $m1))) + (instance (export "0") (instantiate $m1)) + (instance (export "1") (instantiate $m1)) + (instance (export "2") (instantiate $m1)) + (instance (export "3") (instantiate $m1)) + (instance (export "4") (instantiate $m1)) + (instance (export "5") (instantiate $m1)) + (instance (export "6") (instantiate $m1)) + (instance (export "7") (instantiate $m1)) + (instance (export "8") (instantiate $m1)) + (instance (export "9") (instantiate $m1)) ) (component $m3 - (instance (export "0") (instantiate (component $m2))) - (instance (export "1") (instantiate (component $m2))) - (instance (export "2") (instantiate (component $m2))) - (instance (export "3") (instantiate (component $m2))) - (instance (export "4") (instantiate (component $m2))) - (instance (export "5") (instantiate (component $m2))) - (instance (export "6") (instantiate (component $m2))) - (instance (export "7") (instantiate (component $m2))) - (instance (export "8") (instantiate (component $m2))) - (instance (export "9") (instantiate (component $m2))) + (instance (export "0") (instantiate $m2)) + (instance (export "1") (instantiate $m2)) + (instance (export "2") (instantiate $m2)) + (instance (export "3") (instantiate $m2)) + (instance (export "4") (instantiate $m2)) + (instance (export "5") (instantiate $m2)) + (instance (export "6") (instantiate $m2)) + (instance (export "7") (instantiate $m2)) + (instance (export "8") (instantiate $m2)) + (instance (export "9") (instantiate $m2)) ) (component $m4 - (instance (export "0") (instantiate (component $m3))) - (instance (export "1") (instantiate (component $m3))) - (instance (export "2") (instantiate (component $m3))) - (instance (export "3") (instantiate (component $m3))) - (instance (export "4") (instantiate (component $m3))) - (instance (export "5") (instantiate (component $m3))) - (instance (export "6") (instantiate (component $m3))) - (instance (export "7") (instantiate (component $m3))) - (instance (export "8") (instantiate (component $m3))) - (instance (export "9") (instantiate (component $m3))) + (instance (export "0") (instantiate $m3)) + (instance (export "1") (instantiate $m3)) + (instance (export "2") (instantiate $m3)) + (instance (export "3") (instantiate $m3)) + (instance (export "4") (instantiate $m3)) + (instance (export "5") (instantiate $m3)) + (instance (export "6") (instantiate $m3)) + (instance (export "7") (instantiate $m3)) + (instance (export "8") (instantiate $m3)) + (instance (export "9") (instantiate $m3)) ) (component $m5 - (instance (export "0") (instantiate (component $m4))) - (instance (export "1") (instantiate (component $m4))) - (instance (export "2") (instantiate (component $m4))) - (instance (export "3") (instantiate (component $m4))) - (instance (export "4") (instantiate (component $m4))) - (instance (export "5") (instantiate (component $m4))) - (instance (export "6") (instantiate (component $m4))) - (instance (export "7") (instantiate (component $m4))) - (instance (export "8") (instantiate (component $m4))) - (instance (export "9") (instantiate (component $m4))) + (instance (export "0") (instantiate $m4)) + (instance (export "1") (instantiate $m4)) + (instance (export "2") (instantiate $m4)) + (instance (export "3") (instantiate $m4)) + (instance (export "4") (instantiate $m4)) + (instance (export "5") (instantiate $m4)) + (instance (export "6") (instantiate $m4)) + (instance (export "7") (instantiate $m4)) + (instance (export "8") (instantiate $m4)) + (instance (export "9") (instantiate $m4)) ) (component $m6 - (instance (export "0") (instantiate (component $m5))) - (instance (export "1") (instantiate (component $m5))) - (instance (export "2") (instantiate (component $m5))) - (instance (export "3") (instantiate (component $m5))) - (instance (export "4") (instantiate (component $m5))) - (instance (export "5") (instantiate (component $m5))) - (instance (export "6") (instantiate (component $m5))) - (instance (export "7") (instantiate (component $m5))) - (instance (export "8") (instantiate (component $m5))) - (instance (export "9") (instantiate (component $m5))) + (instance (export "0") (instantiate $m5)) + (instance (export "1") (instantiate $m5)) + (instance (export "2") (instantiate $m5)) + (instance (export "3") (instantiate $m5)) + (instance (export "4") (instantiate $m5)) + (instance (export "5") (instantiate $m5)) + (instance (export "6") (instantiate $m5)) + (instance (export "7") (instantiate $m5)) + (instance (export "8") (instantiate $m5)) + (instance (export "9") (instantiate $m5)) ) (component $m7 - (instance (export "0") (instantiate (component $m6))) - (instance (export "1") (instantiate (component $m6))) - (instance (export "2") (instantiate (component $m6))) - (instance (export "3") (instantiate (component $m6))) - (instance (export "4") (instantiate (component $m6))) - (instance (export "5") (instantiate (component $m6))) - (instance (export "6") (instantiate (component $m6))) - (instance (export "7") (instantiate (component $m6))) - (instance (export "8") (instantiate (component $m6))) - (instance (export "9") (instantiate (component $m6))) + (instance (export "0") (instantiate $m6)) + (instance (export "1") (instantiate $m6)) + (instance (export "2") (instantiate $m6)) + (instance (export "3") (instantiate $m6)) + (instance (export "4") (instantiate $m6)) + (instance (export "5") (instantiate $m6)) + (instance (export "6") (instantiate $m6)) + (instance (export "7") (instantiate $m6)) + (instance (export "8") (instantiate $m6)) + (instance (export "9") (instantiate $m6)) ) ) "effective type size exceeds the limit") diff --git a/tests/local/component-model/virtualize.wast b/tests/local/component-model/virtualize.wast index fd6a338908..538866fa27 100644 --- a/tests/local/component-model/virtualize.wast +++ b/tests/local/component-model/virtualize.wast @@ -1,110 +1,117 @@ -;; FIXME(#588) this test should be valid and the rest of the file should roughly -;; be updated to use a similar scheme. -(assert_invalid -(component $child - (import "wasi-file" (instance $wasi-file - (export "read" (func $read (param u32) (result (list u8)))) - (export "write" (func $write (param (list u8)) (result u32))) - )) - - (module $libc - (memory (export "memory") 1) +(component + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) ) - (module $m - (import "wasi-file" "read" (func $read (param i32 i32))) - (import "libc" "memory" (memory 1)) - (func $play (export "play") - i32.const 0 - i32.const 0 - call $read + (core instance $libc (instantiate $libc)) + + (component $child + (import "wasi-file" (instance $wasi-file + (export "read" (func $read (param u32) (result (list u8)))) + (export "write" (func $write (param (list u8)) (result u32))) + )) + + (core instance $libc (instantiate $libc)) + + (core module $m + (import "wasi-file" "read" (func $read (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core func $wasi_file_read + (canon lower (func $wasi-file "read") + (memory (core memory $libc "mem")) + (realloc (core func $libc "realloc")) + ) ) + + (core instance $i (instantiate $m + (with "wasi-file" (instance + (export "read" (func $wasi_file_read)) + )) + )) + + (func (export "play") + (canon lift (core func $i "play")) + ) + ) + + (component $virtualize + (import "wasi-file" (instance $wasi-file + (export "read" (func $read (param u32) (result (list u8)))) + (export "write" (func $write (param (list u8)) (result u32))) + )) + (export "read" (func $wasi-file "read")) + (export "write" (func $wasi-file "write")) ) - (instance $libc (instantiate (module $libc))) - (func $wasi_file_read - (canon.lower (into $libc) (func $wasi-file "read")) + (component + (type $WasiFile (instance + (export "read" (func $read (param u32) (result (list u8)))) + (export "write" (func $write (param (list u8)) (result u32))) + )) + (import "wasi_file" (instance $real-wasi (type $WasiFile))) + (import "./virtualize.wasm" (component $VIRTUALIZE + (import "wasi_file" (instance (type $WasiFile))) + (export "read" (func $read (param u32) (result (list u8)))) + (export "write" (func $write (param (list u8)) (result u32))) + )) + (import "./child.wasm" (component $CHILD + (import "wasi_file" (instance (type $WasiFile))) + (export "play" (func $play)) + ) + ) + + (instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi_file" (instance $real-wasi)))) + (instance $child (instantiate $CHILD (with "wasi_file" (instance $virt-wasi)))) + + (export "work" (func $child "play")) ) - (instance $i (instantiate (module $m) - (with "libc" (instance $libc)) - (with "wasi-file" (instance - (export "read" (func $wasi_file_read)) + + (component + (type $WasiFile (instance + (export "read" (func $read (param u32) (result (list u8)))) + (export "write" (func $write (param (list u8)) (result u32))) )) - )) - (func (export "play") - (canon.lift (func) (func $i "play")) + (import "wasi_file" (instance $real-wasi (type $WasiFile))) + + (core instance $libc (instantiate $libc)) + + (core module $CHILD + (import "wasi_file" "read" (func $wasi-file (param i32 i32))) + (func $play (export "play") + unreachable + ) + ) + + (core module $VIRTUALIZE + (import "wasi_file" "read" (func (param i32 i32))) + (func (export "read") (param i32 i32) + unreachable + ) + (func (export "write") (param i32 i32 i32) + unreachable + ) + ) + + (core func $real-wasi-read + (canon lower (func $real-wasi "read") + (memory (core memory $libc "mem")) + (realloc (core func $libc "realloc")) + ) + ) + + (core instance $virt-wasi (instantiate $VIRTUALIZE (with "wasi_file" (instance (export "read" (func $real-wasi-read)))))) + (core instance $child (instantiate $CHILD (with "wasi_file" (instance $virt-wasi)))) + (func (export "work") + (canon lift (core func $child "play") + (memory (core memory $libc "mem")) + (realloc (core func $libc "realloc")) + ) + ) ) ) -"instance 0 is not a module instance") - - -(; (module $virtualize ;) -(; (import "wasi_file" (instance $wasi-file ;) -(; (export "read" (func $read (param i32 i32 i32) (result i32))) ;) -(; (export "write" (func $write (param i32 i32 i32) (result i32))) ;) -(; )) ;) -(; (export "read" (func $wasi-file "read")) ;) -(; (export "write" (func $wasi-file "write")) ;) -(; ) ;) - - -(; ;; parent.wat ;) -(; (module ;) -(; (type $WasiFile (instance ;) -(; (export "read" (func (param i32 i32 i32) (result i32))) ;) -(; (export "write" (func (param i32 i32 i32) (result i32))) ;) -(; )) ;) -(; (import "wasi_file" (instance $real-wasi (type $WasiFile))) ;) -(; (import "./virtualize.wasm" (module $VIRTUALIZE ;) -(; (import "wasi_file" (instance (type $WasiFile))) ;) -(; (export "read" (func (param i32 i32 i32) (result i32))) ;) -(; (export "write" (func (param i32 i32 i32) (result i32))) ;) -(; )) ;) -(; (import "./child.wasm" (module $CHILD ;) -(; (import "wasi_file" (instance (type $WasiFile))) ;) -(; (export "play" (func $play)) ;) -(; )) ;) -(; (instance $virt-wasi (instantiate $VIRTUALIZE (import "wasi_file" (instance $real-wasi)))) ;) -(; (instance $child (instantiate $CHILD (import "wasi_file" (instance $virt-wasi)))) ;) - -(; (func (export "work") ;) -(; call (func $child "play") ;) -(; ) ;) -(; ) ;) - - -(; ;; bundled.wat ;) -(; (module ;) -(; (type $WasiFile (instance ;) -(; (export "read" (func $read (param i32 i32 i32) (result i32))) ;) -(; (export "write" (func $write (param i32 i32 i32) (result i32))) ;) -(; )) ;) -(; (import "wasi_file" (instance $real-wasi (type $WasiFile))) ;) - -(; (module $CHILD ;) -(; (import "wasi_file" (instance $wasi-file (type outer 0 $WasiFile))) ;) -(; (func $play (export "play") ;) -(; i32.const 0 ;) -(; i32.const 0 ;) -(; i32.const 0 ;) -(; call (func $wasi-file "read") ;) -(; drop ;) -(; ) ;) -(; ) ;) - - -(; (module $VIRTUALIZE ;) -(; (import "wasi_file" (instance $wasi-file (type outer 0 $WasiFile))) ;) -(; (func (export "read") (param i32 i32 i32) (result i32) ;) -(; i32.const 0 ;) -(; ) ;) -(; (func (export "write") (param i32 i32 i32) (result i32) ;) -(; i32.const 0 ;) -(; ) ;) -(; ) ;) - -(; (instance $virt-wasi (instantiate $VIRTUALIZE (import "wasi_file" (instance $real-wasi)))) ;) -(; (instance $child (instantiate $CHILD (import "wasi_file" (instance $virt-wasi)))) ;) -(; (func (export "work") ;) -(; call (func $child "play") ;) -(; ) ;) -(; ) ;) diff --git a/tests/roundtrip.rs b/tests/roundtrip.rs index 9f53e83903..7ae4d40e3d 100644 --- a/tests/roundtrip.rs +++ b/tests/roundtrip.rs @@ -524,7 +524,7 @@ fn error_matches(error: &str, message: &str) -> bool { } if message == "malformed import kind" { - return error.contains("invalid external kind") + return error.contains("invalid leading byte") // wasmparser understands more import kinds than the default spec // interpreter || error.contains("unexpected end-of-file");