From 0adc25167fcd5843312d384507334ee533cbeeb6 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Wed, 11 May 2022 12:43:57 -0700 Subject: [PATCH 01/33] wasm-encoder: update to the latest component model changes. This commit updates and refactors `wasm-encoder` to include the latest component model changes. Most notably, the index spaces for core and component items in the component model have been separated. As a result, some of the component section encoders have been split in two, with a "core" version going into the `core` module; for things like aliases and instance sections, the core versions may one day be used in module encoding if a standalone module linking proposal is put forth. --- crates/wasm-encoder/src/component.rs | 80 ++++-- crates/wasm-encoder/src/component/aliases.rs | 159 ++++++----- .../component/{functions.rs => canonicals.rs} | 73 +++-- .../wasm-encoder/src/component/components.rs | 7 +- crates/wasm-encoder/src/component/exports.rs | 118 +++++++- crates/wasm-encoder/src/component/imports.rs | 112 +++++++- .../wasm-encoder/src/component/instances.rs | 141 ++------- crates/wasm-encoder/src/component/modules.rs | 7 +- crates/wasm-encoder/src/component/start.rs | 11 +- crates/wasm-encoder/src/component/types.rs | 268 ++++++------------ crates/wasm-encoder/src/core.rs | 21 +- crates/wasm-encoder/src/core/aliases.rs | 59 ++++ crates/wasm-encoder/src/core/code.rs | 8 +- crates/wasm-encoder/src/{ => core}/custom.rs | 12 +- crates/wasm-encoder/src/core/data.rs | 15 +- crates/wasm-encoder/src/core/elements.rs | 8 +- crates/wasm-encoder/src/core/exports.rs | 74 ++++- crates/wasm-encoder/src/core/functions.rs | 8 +- crates/wasm-encoder/src/core/globals.rs | 8 +- crates/wasm-encoder/src/core/imports.rs | 19 +- crates/wasm-encoder/src/core/instances.rs | 99 +++++++ crates/wasm-encoder/src/core/linking.rs | 11 +- crates/wasm-encoder/src/core/memories.rs | 8 +- crates/wasm-encoder/src/core/names.rs | 8 +- crates/wasm-encoder/src/core/start.rs | 7 +- crates/wasm-encoder/src/core/tables.rs | 8 +- crates/wasm-encoder/src/core/tags.rs | 8 +- crates/wasm-encoder/src/core/types.rs | 132 +++++++-- crates/wasm-encoder/src/lib.rs | 7 +- crates/wasm-encoder/src/raw.rs | 16 +- 30 files changed, 977 insertions(+), 535 deletions(-) rename crates/wasm-encoder/src/component/{functions.rs => canonicals.rs} (55%) create mode 100644 crates/wasm-encoder/src/core/aliases.rs rename crates/wasm-encoder/src/{ => core}/custom.rs (82%) create mode 100644 crates/wasm-encoder/src/core/instances.rs diff --git a/crates/wasm-encoder/src/component.rs b/crates/wasm-encoder/src/component.rs index 6fe686da8e..d2d0647f01 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,34 @@ 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::TypeSection; +use crate::{AliasSection, CustomSection, Encode, InstanceSection}; + +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 +44,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 +114,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 +125,27 @@ impl Default for Component { Self::new() } } + +impl ComponentSection for CustomSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreCustom.into() + } +} + +impl ComponentSection for InstanceSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreInstance.into() + } +} + +impl ComponentSection for AliasSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreAlias.into() + } +} + +impl ComponentSection for TypeSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreType.into() + } +} diff --git a/crates/wasm-encoder/src/component/aliases.rs b/crates/wasm-encoder/src/component/aliases.rs index a7b3802566..4c1db00052 100644 --- a/crates/wasm-encoder/src/component/aliases.rs +++ b/crates/wasm-encoder/src/component/aliases.rs @@ -1,47 +1,74 @@ -use crate::{encode_section, ComponentSection, ComponentSectionId, Encode}; +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, + CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_INSTANCE_SORT, CORE_MEMORY_SORT, CORE_MODULE_SORT, + CORE_TABLE_SORT, CORE_TYPE_SORT, +}; -/// 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, +use super::{COMPONENT_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT}; + +/// Represents the kinds of aliasable core items. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CoreAliasKind { + /// 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, + /// The alias is to a core type. + Type, + /// The alias is to a core module. + Module, + /// The alias is to a core instance. + Instance, } -impl Encode for AliasExportKind { +impl Encode for CoreAliasKind { 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), - }; + match self { + Self::Func => sink.push(CORE_FUNCTION_SORT), + Self::Table => sink.push(CORE_TABLE_SORT), + Self::Memory => sink.push(CORE_MEMORY_SORT), + Self::Global => sink.push(CORE_GLOBAL_SORT), + Self::Type => sink.push(CORE_TYPE_SORT), + Self::Module => sink.push(CORE_MODULE_SORT), + Self::Instance => sink.push(CORE_INSTANCE_SORT), + } + } +} + +/// Represents the kinds of aliasable component items. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentAliasKind { + /// The alias is to a core item. + Core(CoreAliasKind), + /// The alias is to a function. + Func, + /// The alias is to a value. + Value, + /// The alias is to a type. + Type, + /// The alias is to a component. + Component, + /// The alias is to an instance. + Instance, +} - sink.push(preamble); - sink.push(value); +impl Encode for ComponentAliasKind { + fn encode(&self, sink: &mut Vec) { + match self { + Self::Core(kind) => { + sink.push(CORE_SORT); + kind.encode(sink); + } + Self::Func => sink.push(FUNCTION_SORT), + Self::Value => sink.push(VALUE_SORT), + Self::Type => sink.push(TYPE_SORT), + Self::Component => sink.push(COMPONENT_SORT), + Self::Instance => sink.push(INSTANCE_SORT), + } } } @@ -50,11 +77,11 @@ impl Encode for AliasExportKind { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, AliasSection, AliasExportKind}; +/// use wasm_encoder::{Component, ComponentAliasSection, ComponentExportKind, ComponentAliasKind}; /// -/// let mut aliases = AliasSection::new(); -/// aliases.outer_type(0, 2); -/// aliases.instance_export(0, AliasExportKind::Function, "foo"); +/// let mut aliases = ComponentAliasSection::new(); +/// aliases.instance_export(0, ComponentExportKind::Func, "f"); +/// aliases.outer(0, ComponentAliasKind::Instance, 1); /// /// let mut component = Component::new(); /// component.section(&aliases); @@ -62,12 +89,12 @@ impl Encode for AliasExportKind { /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] -pub struct AliasSection { +pub struct ComponentAliasSection { bytes: Vec, num_added: u32, } -impl AliasSection { +impl ComponentAliasSection { /// Create a new alias section encoder. pub fn new() -> Self { Self::default() @@ -83,61 +110,41 @@ 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: ComponentExportKind, name: &str, ) -> &mut Self { kind.encode(&mut self.bytes); - instance.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 - } - - /// 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); self.bytes.push(0x00); - count.encode(&mut self.bytes); - index.encode(&mut self.bytes); - self.num_added += 1; + instance_index.encode(&mut self.bytes); + name.encode(&mut self.bytes); 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: ComponentAliasKind, index: u32) -> &mut Self { + kind.encode(&mut self.bytes); self.bytes.push(0x01); count.encode(&mut self.bytes); index.encode(&mut self.bytes); - self.num_added += 1; self } } -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::CoreCustom.into() + } +} diff --git a/crates/wasm-encoder/src/component/functions.rs b/crates/wasm-encoder/src/component/canonicals.rs similarity index 55% rename from crates/wasm-encoder/src/component/functions.rs rename to crates/wasm-encoder/src/component/canonicals.rs index 995696cbe8..374defa16c 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,20 @@ 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 or lowering of a function requires + /// cleanup after the function returns. + /// + /// The value is an index to a core function of type `(func)`. + PostReturn(u32), } impl Encode for CanonicalOption { @@ -23,23 +31,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 +63,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 +84,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 +111,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..cd6670a350 100644 --- a/crates/wasm-encoder/src/component/exports.rs +++ b/crates/wasm-encoder/src/component/exports.rs @@ -1,7 +1,98 @@ -use crate::{encode_section, ComponentArg, ComponentSection, ComponentSectionId, Encode}; +use super::{COMPONENT_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT}; +use crate::{encode_section, ComponentSection, ComponentSectionId, Encode, CORE_MODULE_SORT}; -/// 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); + } + } + } +} + +/// Represents an export from a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentExport { + /// The export is a core module. + Module(u32), + /// The export is a function. + Func(u32), + /// The export is a value. + Value(u32), + /// The export is a type. + Type(u32), + /// The export is an instance. + Instance(u32), + /// The export is a component. + Component(u32), +} + +impl ComponentExport { + /// Gets the kind of the export. + 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, + } + } + + /// Gets the index of the export. + fn index(&self) -> u32 { + match self { + Self::Module(idx) + | Self::Func(idx) + | Self::Value(idx) + | Self::Type(idx) + | Self::Instance(idx) + | Self::Component(idx) => *idx, + } + } +} + +impl Encode for ComponentExport { + fn encode(&self, sink: &mut Vec) { + self.kind().encode(sink); + self.index().encode(sink); + } +} /// An encoder for the export section of WebAssembly component. /// @@ -10,9 +101,9 @@ pub type ComponentExport = ComponentArg; /// ```rust /// use wasm_encoder::{Component, ComponentExportSection, ComponentExport}; /// -/// // 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", ComponentExport::Func(0)); /// /// let mut component = Component::new(); /// component.section(&exports); @@ -42,9 +133,9 @@ 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, export: ComponentExport) -> &mut Self { name.encode(&mut self.bytes); - export.into().encode(&mut self.bytes); + export.encode(&mut self.bytes); self.num_added += 1; self } @@ -52,13 +143,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..7e054db06e 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)] +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)] +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..6a50e178f4 100644 --- a/crates/wasm-encoder/src/component/instances.rs +++ b/crates/wasm-encoder/src/component/instances.rs @@ -1,66 +1,15 @@ use crate::{encode_section, ComponentExport, ComponentSection, ComponentSectionId, Encode}; -/// Represents an argument to instantiating a WebAssembly module. -#[derive(Debug, Clone)] -pub enum ModuleArg { - /// The argument is an instance. - Instance(u32), -} - -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), - }; - - sink.push(kind); - index.encode(sink); - } -} - /// An encoder for the instance section of WebAssembly components. /// /// # Example /// /// ```rust -/// use wasm_encoder::{Component, InstanceSection, ModuleArg, Export}; +/// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExport}; /// -/// let mut instances = InstanceSection::new(); -/// instances.export_core_items([("foo", Export::Function(0))]); -/// instances.instantiate_module(1, [("foo", ModuleArg::Instance(0))]); +/// let mut instances = ComponentInstanceSection::new(); +/// instances.export_items([("foo", ComponentExport::Func(0))]); +/// instances.instantiate(1, [("foo", ComponentExport::Instance(0))]); /// /// let mut component = Component::new(); /// component.section(&instances); @@ -68,12 +17,12 @@ impl Encode for ComponentArg { /// let bytes = component.finish(); /// ``` #[derive(Clone, Debug, Default)] -pub struct InstanceSection { +pub struct ComponentInstanceSection { bytes: Vec, num_added: u32, } -impl InstanceSection { +impl ComponentInstanceSection { /// Create a new instance section encoder. pub fn new() -> Self { Self::default() @@ -89,96 +38,50 @@ 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 - where - Args: IntoIterator, - Args::IntoIter: ExactSizeIterator, - Arg: Into, - { - 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); - } - 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 - where - Exports: IntoIterator, - Exports::IntoIter: ExactSizeIterator, - Export: Into, - { - let exports = exports.into_iter(); - self.bytes.push(0x02); - exports.len().encode(&mut self.bytes); - for (name, export) in exports { - name.encode(&mut self.bytes); - export.into().encode(&mut self.bytes); - } - self.num_added += 1; - self - } - /// 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, export) in args { name.encode(&mut self.bytes); - arg.into().encode(&mut self.bytes); + export.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 { name.encode(&mut self.bytes); - export.into().encode(&mut self.bytes); + export.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..a86aa2f969 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -1,128 +1,63 @@ use crate::{ - encode_functype, encode_section, ComponentSection, ComponentSectionId, Encode, EntityType, - ValType, + encode_section, ComponentAliasKind, ComponentSection, ComponentSectionId, ComponentTypeRef, + Encode, }; -/// Represents a module type. +/// Represents a component type. #[derive(Debug, Clone, Default)] -pub struct ModuleType { +pub struct ComponentType { bytes: Vec, num_added: u32, types_added: u32, } -impl ModuleType { - /// Creates a new module type. +impl ComponentType { + /// Creates a new component 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); - module.encode(&mut self.bytes); - name.encode(&mut self.bytes); - ty.encode(&mut self.bytes); - self.num_added += 1; - self - } - - /// Defines an export in this module type. - pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self { - self.bytes.push(0x07); + /// Defines an import in this component type. + pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + self.bytes.push(0x00); name.encode(&mut self.bytes); ty.encode(&mut self.bytes); self.num_added += 1; self } - /// Gets the number of types that have been added to this module type. - pub fn type_count(&self) -> u32 { - self.types_added - } -} - -impl Encode for ModuleType { - fn encode(&self, sink: &mut Vec) { - self.num_added.encode(sink); - sink.extend(&self.bytes); - } -} - -/// Represents a component type. -#[derive(Debug, Clone, Default)] -pub struct ComponentType { - bytes: Vec, - num_added: u32, - types_added: u32, -} - -impl ComponentType { - /// Creates a new component type. - pub fn new() -> Self { - Self::default() - } - /// 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 alias in this component type. + pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { self.bytes.push(0x02); - name.encode(&mut self.bytes); - ty.encode(&mut self.bytes); + ComponentAliasKind::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 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(0x03); 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 types that have been added or aliased in this component type. pub fn type_count(&self) -> u32 { self.types_added @@ -131,6 +66,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); } @@ -152,31 +88,20 @@ impl InstanceType { /// 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) - } - - /// 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); - self.num_added += 1; - self + ComponentTypeEncoder(&mut self.bytes) } - /// 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); + ComponentAliasKind::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 +109,15 @@ impl InstanceType { self } + /// Defines an export in this instance type. + pub fn export(&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; + self + } + /// 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 +126,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 +172,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 +214,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 +235,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 +255,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 +276,7 @@ impl InterfaceTypeEncoder<'_> { where F: IntoIterator, F::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let fields = fields.into_iter(); self.0.push(0x71); @@ -371,7 +292,7 @@ impl InterfaceTypeEncoder<'_> { where C: IntoIterator)>, C::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let cases = cases.into_iter(); self.0.push(0x70); @@ -389,7 +310,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 +320,7 @@ impl InterfaceTypeEncoder<'_> { where I: IntoIterator, I::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let types = types.into_iter(); self.0.push(0x6E); @@ -442,7 +363,7 @@ impl InterfaceTypeEncoder<'_> { where I: IntoIterator, I::IntoIter: ExactSizeIterator, - T: Into, + T: Into, { let types = types.into_iter(); self.0.push(0x6B); @@ -453,13 +374,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 +392,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 +436,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 +457,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..ceba1d18b0 100644 --- a/crates/wasm-encoder/src/core.rs +++ b/crates/wasm-encoder/src/core.rs @@ -1,10 +1,13 @@ +mod aliases; mod code; +mod custom; mod data; mod elements; mod exports; mod functions; mod globals; mod imports; +mod instances; mod linking; mod memories; mod names; @@ -13,13 +16,16 @@ mod tables; mod tags; mod types; +pub use aliases::*; pub use code::*; +pub use custom::*; pub use data::*; pub use elements::*; pub use exports::*; pub use functions::*; pub use globals::*; pub use imports::*; +pub use instances::*; pub use linking::*; pub use memories::*; pub use names::*; @@ -30,12 +36,24 @@ 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; +pub(crate) const CORE_TYPE_SORT: u8 = 0x10; +pub(crate) const CORE_MODULE_SORT: u8 = 0x11; +pub(crate) const CORE_INSTANCE_SORT: u8 = 0x12; + /// 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 +137,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/aliases.rs b/crates/wasm-encoder/src/core/aliases.rs new file mode 100644 index 0000000000..0878984494 --- /dev/null +++ b/crates/wasm-encoder/src/core/aliases.rs @@ -0,0 +1,59 @@ +use crate::{encode_section, Encode, ExportKind}; + +/// An encoder for the core alias section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, AliasSection, ExportKind}; +/// +/// let mut aliases = AliasSection::new(); +/// aliases.instance_export(0, ExportKind::Func, "f"); +/// +/// let mut component = Component::new(); +/// component.section(&aliases); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct AliasSection { + bytes: Vec, + num_added: u32, +} + +impl AliasSection { + /// Create a new core 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: ExportKind, + name: &str, + ) -> &mut Self { + kind.encode(&mut self.bytes); + self.bytes.push(0x00); + instance_index.encode(&mut self.bytes); + name.encode(&mut self.bytes); + self + } +} + +impl Encode for AliasSection { + fn encode(&self, sink: &mut Vec) { + encode_section(sink, self.num_added, &self.bytes); + } +} 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..46da9aecb9 100644 --- a/crates/wasm-encoder/src/core/exports.rs +++ b/crates/wasm-encoder/src/core/exports.rs @@ -1,10 +1,40 @@ +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 the kind of an export from a WebAssembly module. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ExportKind { + /// The export is a function. + Func, + /// The export is a table. + Table, + /// The export is a memory. + Memory, + /// The export is a global. + Global, + /// The export is a tag. + Tag, +} + +impl Encode for ExportKind { + fn encode(&self, sink: &mut Vec) { + 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, + }); + } +} + /// Represents an export from a WebAssembly module. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Export { /// The export is a function. - Function(u32), + Func(u32), /// The export is a table. Table(u32), /// The export is a memory. @@ -17,18 +47,30 @@ pub enum Export { Tag(u32), } +impl Export { + /// Gets the kind of the export. + pub fn kind(&self) -> ExportKind { + match self { + Self::Func(_) => ExportKind::Func, + Self::Table(_) => ExportKind::Table, + Self::Memory(_) => ExportKind::Memory, + Self::Global(_) => ExportKind::Global, + Self::Tag(_) => ExportKind::Tag, + } + } + + /// Gets the index of the export. + fn index(&self) -> u32 { + match self { + Self::Func(i) | Self::Table(i) | Self::Memory(i) | Self::Global(i) | Self::Tag(i) => *i, + } + } +} + impl Encode for Export { 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); + self.kind().encode(sink); + self.index().encode(sink); } } @@ -40,7 +82,7 @@ impl Encode for Export { /// use wasm_encoder::{Module, ExportSection, Export}; /// /// let mut exports = ExportSection::new(); -/// exports.export("foo", Export::Function(0)); +/// exports.export("foo", Export::Func(0)); /// /// let mut module = Module::new(); /// module.section(&exports); @@ -80,8 +122,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/instances.rs b/crates/wasm-encoder/src/core/instances.rs new file mode 100644 index 0000000000..6c82e074fd --- /dev/null +++ b/crates/wasm-encoder/src/core/instances.rs @@ -0,0 +1,99 @@ +use super::CORE_INSTANCE_SORT; +use crate::{encode_section, Encode, Export}; + +/// Represents an argument to a module instantiation. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ModuleArg { + /// The argument is an instance. + Instance(u32), +} + +impl Encode for ModuleArg { + fn encode(&self, sink: &mut Vec) { + let (sort, idx) = match self { + Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx), + }; + sink.push(sort); + idx.encode(sink); + } +} + +/// An encoder for the core instance section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, InstanceSection, Export, ModuleArg}; +/// +/// let mut instances = InstanceSection::new(); +/// instances.export_items([("foo", Export::Func(0))]); +/// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]); +/// +/// let mut component = Component::new(); +/// component.section(&instances); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct InstanceSection { + bytes: Vec, + num_added: u32, +} + +impl InstanceSection { + /// Create a new core 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 core module. + pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self + where + A: IntoIterator, + A::IntoIter: ExactSizeIterator, + { + let args = args.into_iter(); + 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.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + /// Define an instance by exporting core WebAssembly items. + pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self + where + 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 { + name.encode(&mut self.bytes); + export.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); + } +} 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..5d6ec8a649 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}; +use crate::{encode_section, Encode, EntityType, 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,21 +40,91 @@ 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)); +/// Represents the type of a core module. +#[derive(Debug, Clone, Default)] +pub struct ModuleType { + bytes: Vec, + num_added: u32, + types_added: u32, +} + +impl ModuleType { + /// Creates a new core module type. + pub fn new() -> Self { + Self::default() + } + + /// Defines an import in this module type. + pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { + self.bytes.push(0x00); + module.encode(&mut self.bytes); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + 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) -> TypeEncoder { + self.bytes.push(0x01); + self.num_added += 1; + self.types_added += 1; + TypeEncoder(&mut self.bytes) + } + + /// Defines an export in this module type. + pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self { + self.bytes.push(0x03); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Gets the number of types that have been added to this module type. + pub fn type_count(&self) -> u32 { + self.types_added + } +} + +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 TypeEncoder<'a>(&'a mut Vec); + +impl<'a> TypeEncoder<'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 type section of WebAssembly modules. @@ -95,6 +165,15 @@ impl TypeSection { 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) -> TypeEncoder<'_> { + self.num_added += 1; + TypeEncoder(&mut self.bytes) + } + /// Define a function type in this type section. pub fn function(&mut self, params: P, results: R) -> &mut Self where @@ -103,16 +182,27 @@ impl TypeSection { R: IntoIterator, R::IntoIter: ExactSizeIterator, { - encode_functype(&mut self.bytes, params, results); - self.num_added += 1; + 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 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..b17261214d 100644 --- a/crates/wasm-encoder/src/lib.rs +++ b/crates/wasm-encoder/src/lib.rs @@ -47,7 +47,7 @@ //! //! // Encode the export section. //! let mut exports = ExportSection::new(); -//! exports.export("f", Export::Function(0)); +//! exports.export("f", Export::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 + } +} From 0d95394ce792f9902c72146896136c0a60095da0 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Fri, 20 May 2022 12:03:36 -0700 Subject: [PATCH 02/33] wasm-mutate: update for wasm-encoder changes. This commit updates `wasm-mutate` so that it builds with the `wasm-encoder` API changes. --- crates/wasm-mutate/src/mutators/remove_export.rs | 2 +- crates/wasm-mutate/src/mutators/remove_item.rs | 2 +- crates/wasm-mutate/src/mutators/rename_export.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/wasm-mutate/src/mutators/remove_export.rs b/crates/wasm-mutate/src/mutators/remove_export.rs index e124496318..ebed27132d 100644 --- a/crates/wasm-mutate/src/mutators/remove_export.rs +++ b/crates/wasm-mutate/src/mutators/remove_export.rs @@ -31,7 +31,7 @@ impl Mutator for RemoveExportMutator { match export.kind { wasmparser::ExternalKind::Func => { - exports.export(export.name, Export::Function(export.index)); + exports.export(export.name, Export::Func(export.index)); } wasmparser::ExternalKind::Table => { exports.export(export.name, Export::Table(export.index)); diff --git a/crates/wasm-mutate/src/mutators/remove_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 3f41084bc8..64cd21812b 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -254,7 +254,7 @@ impl RemoveItem { let item = item?; let e = match &item.kind { ExternalKind::Func => { - Export::Function(self.remap(Item::Function, item.index)?) + Export::Func(self.remap(Item::Function, item.index)?) } ExternalKind::Table => { Export::Table(self.remap(Item::Table, item.index)?) diff --git a/crates/wasm-mutate/src/mutators/rename_export.rs b/crates/wasm-mutate/src/mutators/rename_export.rs index 68d16d76cd..e0be9ccc09 100644 --- a/crates/wasm-mutate/src/mutators/rename_export.rs +++ b/crates/wasm-mutate/src/mutators/rename_export.rs @@ -68,7 +68,7 @@ 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(), Export::Func(export.index)); } wasmparser::ExternalKind::Table => { exports.export(new_name.as_str(), Export::Table(export.index)); From 8567df2886133b4139e596b1d20c36b6afc66f86 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 23 May 2022 18:42:43 -0700 Subject: [PATCH 03/33] wasm-smith: update for wasm-encoder changes. This commit updates `wasm-smith` for the `wasm-encoder` API changes. It also updates `wasm-smith` for the component model spec changes, namely encoding core and component types in discrete sections. --- crates/wasm-encoder/src/component/imports.rs | 4 +- crates/wasm-smith/src/component.rs | 823 ++++++++++--------- crates/wasm-smith/src/component/encode.rs | 150 ++-- crates/wasm-smith/src/core.rs | 55 +- crates/wasm-smith/src/lib.rs | 4 +- 5 files changed, 557 insertions(+), 479 deletions(-) diff --git a/crates/wasm-encoder/src/component/imports.rs b/crates/wasm-encoder/src/component/imports.rs index 7e054db06e..f62c328941 100644 --- a/crates/wasm-encoder/src/component/imports.rs +++ b/crates/wasm-encoder/src/component/imports.rs @@ -4,7 +4,7 @@ use crate::{ }; /// Represents the possible type bounds for type references. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum TypeBounds { /// The type is bounded by equality. Eq, @@ -19,7 +19,7 @@ impl Encode for TypeBounds { } /// Represents a reference to a type. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] pub enum ComponentTypeRef { /// The reference is to a core module type. /// diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs index edadb36e9e..2383270d04 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; @@ -120,12 +120,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 `funcs` are component functions that only use scalar + // types? + scalar_component_funcs: Vec, // Which entries in `funcs` are core Wasm functions? // @@ -145,7 +145,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 +161,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 +169,7 @@ struct ComponentContext { instances: Vec, // This component's value index space. - values: Vec, + values: Vec, } impl ComponentContext { @@ -179,8 +179,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 +212,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 +230,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 +339,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 +390,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 +446,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 +511,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 +587,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 +698,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 +759,7 @@ impl ComponentBuilder { let mut entity_choices: Vec< fn( - &mut ComponentBuilder, + &ComponentBuilder, &mut Unstructured, &mut EntityCounts, &[Rc], @@ -650,8 +794,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 +843,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 +918,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 +927,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 +981,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,15 +1039,11 @@ 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(), }) }); } @@ -982,7 +1106,7 @@ impl ComponentBuilder { } fn arbitrary_func_type( - &mut self, + &self, u: &mut Unstructured, type_fuel: &mut u32, ) -> Result> { @@ -998,69 +1122,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 +1186,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 +1210,7 @@ impl ComponentBuilder { } fn arbitrary_variant_type( - &mut self, + &self, u: &mut Unstructured, type_fuel: &mut u32, ) -> Result { @@ -1119,17 +1236,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 +1250,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 +1271,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 +1286,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 +1294,123 @@ 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!(), + }; + let is_scalar = func_ty.is_scalar(); 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); + if is_scalar { + self.component_mut().scalar_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] { + fn component_function_type(&self, func_index: u32) -> &Rc { + match &self.component().funcs[func_index as usize] { ComponentOrCoreFuncType::Component(ty) => ty, - ComponentOrCoreFuncType::Core(_) => panic!("not an interface function"), + ComponentOrCoreFuncType::Core(_) => panic!("not a component function"), } } 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 +1420,19 @@ impl ComponentBuilder { let ty = match &func { Func::CanonLift { func_ty, .. } => { - self.component_mut().interface_funcs.push(func_index); + self.component_mut().component_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); + self.component_mut().scalar_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 +1441,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 +1460,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 +1495,65 @@ 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] + let core_func_index = u.int_in_range( + 0..=u32::try_from(c.component().core_funcs.len() - 1).unwrap(), + )?; + let core_func_ty = c.component().funcs + [c.component().core_funcs[core_func_index as usize] as usize] .clone() .unwrap_core(); - let inter_func_ty = inverse_scalar_canonical_abi_for(u, &core_func_ty)?; + 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 +1564,7 @@ impl ComponentBuilder { func_ty, // Scalar functions don't use any canonical options. options: vec![], - core_func, + core_func_index, })) }); } @@ -1512,14 +1584,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 +1620,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 +1659,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 +1691,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 +1710,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 +1727,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)] @@ -1687,17 +1760,12 @@ struct TypeSection { types: Vec>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -enum Type { +#[derive(Debug)] +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 +1780,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 { @@ -1754,7 +1830,7 @@ struct ComponentType { enum ComponentTypeDef { Import(Import), Type(Rc), - Export { name: String, ty: TypeIndex }, + Export { name: String, ty: ComponentTypeRef }, Alias(Alias), } @@ -1776,14 +1852,14 @@ struct InstanceType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum InstanceTypeDef { Type(Rc), - Export { name: String, ty: TypeIndex }, + Export { name: String, ty: ComponentTypeRef }, Alias(Alias), } #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct FuncType { params: Vec, - result: InterfaceTypeRef, + result: ComponentValType, } impl FuncType { @@ -1795,7 +1871,7 @@ impl FuncType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] struct OptionalNamedType { name: Option, - ty: InterfaceTypeRef, + ty: ComponentValType, } impl OptionalNamedType { @@ -1804,40 +1880,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 +1934,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 +1954,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 +1976,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 +1989,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 +2002,9 @@ enum CanonOpt { StringUtf8, StringUtf16, StringLatin1Utf16, - Into { instance: u32 }, + Memory(u32), + Realloc(u32), + PostReturn(u32), } #[derive(Debug)] @@ -1944,23 +2019,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..e6ec9aee35 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 { +impl CoreTypeSection { + fn encode(&self, component: &mut wasm_encoder::Component) { + let mut sec = wasm_encoder::TypeSection::new(); + for ty in &self.types { + ty.encode(sec.ty()); + } + component.section(&sec); + } +} + +impl CoreType { fn encode(&self, enc: wasm_encoder::TypeEncoder<'_>) { 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,34 @@ 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::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, @@ -151,7 +180,7 @@ impl Type { } 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 { @@ -159,7 +188,7 @@ impl Type { 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, @@ -173,70 +202,55 @@ impl Type { } 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, default_to)| (ty.name.as_str(), ty.ty, *default_to)), ); } - 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 +260,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..6a4851d59f 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -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) @@ -580,7 +580,7 @@ impl Module { Some((wasmparser::TypeDef::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; @@ -699,10 +699,10 @@ impl Module { 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) => { + Export::Global(idx) => EntityType::Global(self.globals[idx as usize]), + Export::Memory(idx) => EntityType::Memory(self.memories[idx as usize]), + Export::Table(idx) => EntityType::Table(self.tables[idx as usize]), + Export::Func(idx) => { let (_idx, ty) = &self.funcs[idx as usize]; EntityType::Func(u32::max_value(), ty.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 { @@ -897,7 +897,7 @@ impl Module { let mut choices: Vec> = Vec::with_capacity(6); choices.push( (0..self.funcs.len()) - .map(|i| Export::Function(i as u32)) + .map(|i| Export::Func(i as u32)) .collect(), ); choices.push( @@ -931,8 +931,8 @@ impl Module { for list in choices.iter_mut() { list.retain(|c| self.type_of(c).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); } @@ -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()) 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(); From 636ed932f8e00d4d1042465ffd4d481a04f25f91 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Tue, 24 May 2022 12:44:16 -0700 Subject: [PATCH 04/33] wasmparser: update for the component model spec changes. This commit refactors `wasmparser` to conform to the latest component model spec. The biggest change is that core items and component items have distinct index spaces and sections. This had a large impact on the validator. Various type names have been changed to better align with the terminology used in the component model spec ("interface" is now gone in favor of component "value types"). --- crates/wasmparser/benches/benchmark.rs | 26 +- crates/wasmparser/src/binary_reader.rs | 553 ++++--- crates/wasmparser/src/lib.rs | 4 +- crates/wasmparser/src/limits.rs | 18 +- crates/wasmparser/src/parser.rs | 277 ++-- crates/wasmparser/src/readers/component.rs | 4 +- .../src/readers/component/aliases.rs | 88 +- .../component/{functions.rs => canonicals.rs} | 58 +- .../src/readers/component/exports.rs | 29 +- .../src/readers/component/imports.rs | 43 +- .../src/readers/component/instances.rs | 98 +- .../wasmparser/src/readers/component/types.rs | 259 ++- crates/wasmparser/src/readers/core.rs | 4 + crates/wasmparser/src/readers/core/aliases.rs | 96 ++ crates/wasmparser/src/readers/core/code.rs | 10 +- .../wasmparser/src/readers/core/elements.rs | 10 +- crates/wasmparser/src/readers/core/exports.rs | 8 + crates/wasmparser/src/readers/core/imports.rs | 8 +- .../wasmparser/src/readers/core/instances.rs | 119 ++ .../wasmparser/src/readers/core/operators.rs | 8 +- crates/wasmparser/src/readers/core/types.rs | 69 +- .../src/{module_resources.rs => resources.rs} | 24 +- crates/wasmparser/src/validator.rs | 323 ++-- crates/wasmparser/src/validator/component.rs | 1399 ++++++++++------- crates/wasmparser/src/validator/core.rs | 139 +- crates/wasmparser/src/validator/func.rs | 12 +- crates/wasmparser/src/validator/operators.rs | 575 +++---- crates/wasmparser/src/validator/types.rs | 594 +++---- 28 files changed, 2721 insertions(+), 2134 deletions(-) rename crates/wasmparser/src/readers/component/{functions.rs => canonicals.rs} (59%) create mode 100644 crates/wasmparser/src/readers/core/aliases.rs create mode 100644 crates/wasmparser/src/readers/core/instances.rs rename crates/wasmparser/src/{module_resources.rs => resources.rs} (93%) diff --git a/crates/wasmparser/benches/benchmark.rs b/crates/wasmparser/benches/benchmark.rs index eb216b731c..789ba1c9ef 100644 --- a/crates/wasmparser/benches/benchmark.rs +++ b/crates/wasmparser/benches/benchmark.rs @@ -157,35 +157,45 @@ 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) => { + ComponentSection { .. } => {} + ComponentInstanceSection(s) => { for item in s { item?; } } - ModuleSection { .. } => {} - ComponentSection { .. } => {} - InstanceSection(s) => { + ComponentAliasSection(s) => { for item in s { item?; } } - ComponentExportSection(s) => { + 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..8ff44471e1 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,46 @@ 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), + 0x11 => Ok(ExternalKind::Module), + 0x12 => Ok(ExternalKind::Instance), + x => self.invalid_leading_byte(x, "external kind"), + } + } + + pub(crate) fn read_component_external_kind(&mut self) -> Result { + match self.read_u8()? { + 0x00 => match self.read_external_kind()? { + ExternalKind::Module => Ok(ComponentExternalKind::Module), + _ => Err(BinaryReaderError::new( + "only core modules are allowed for component external kind", + self.original_position() - 1, + )), + }, + 0x01 => Ok(ComponentExternalKind::Func), + 0x02 => Ok(ComponentExternalKind::Value), + 0x03 => Ok(ComponentExternalKind::Type), + 0x04 => Ok(ComponentExternalKind::Component), + 0x05 => Ok(ComponentExternalKind::Instance), + x => self.invalid_leading_byte(x, "component external kind"), } } 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 +257,73 @@ 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()?), + 0x50 => { + let size = self.read_size(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")?; + Type::Module( + (0..size) + .map(|_| self.read_module_type_decl()) + .collect::>()?, + ) + } x => return self.invalid_leading_byte(x, "type"), }) } - pub(crate) fn read_component_type_def(&mut self) -> Result> { + pub(crate) fn read_component_type(&mut self) -> Result> { Ok(match self.read_u8()? { - 0x4f => { - let size = self.read_size(MAX_WASM_MODULE_TYPEDEFS, "module definition")?; - ComponentTypeDef::Module( - (0..size) - .map(|_| self.read_module_type()) - .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 => { + 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 +331,54 @@ 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()? == 0x00 { 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::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 { + 0x01 => InstanceTypeDeclaration::Type(self.read_component_type()?), + 0x02 => InstanceTypeDeclaration::Alias(self.read_component_alias()?), + 0x03 => 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,7 +386,7 @@ impl<'a> BinaryReader<'a> { fn read_variant_case(&mut self) -> Result> { Ok(VariantCase { name: self.read_string()?, - ty: self.read_interface_type_ref()?, + ty: self.read_component_val_type()?, default_to: match self.read_u8()? { 0x0 => None, 0x1 => Some(self.read_var_u32()?), @@ -394,45 +395,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 +441,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 +449,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 +472,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 +491,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 +549,106 @@ 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> { + pub(crate) fn read_instantiation_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"), + let kind = match self.read_external_kind()? { + ExternalKind::Instance => ExternalKind::Instance, + _ => { + return Err(BinaryReaderError::new( + "only instances are supported for module instantiation arguments", + self.original_position() - 1, + )) + } }; - Ok(ModuleArg { name, kind }) + Ok(InstantiationArg { + name, + kind, + index: self.read_var_u32()?, + }) } - pub(crate) fn read_alias(&mut self) -> Result> { - let preamble = self.read_u8()?; + 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()?, + }) + } - 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()?; + pub(crate) fn read_alias(&mut self) -> Result> { + let kind = self.read_external_kind()?; - 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, - } - } - 0x02 => { - let offset = self.original_position(); - let kind = self.read_u8()?; - let count = self.read_var_u32()?; - let index = self.read_var_u32()?; + pub(crate) fn read_component_alias(&mut self) -> Result> { + let kind = self.read_component_external_kind()?; - 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)), - } - } + Ok(match self.read_u8()? { + 0x00 => ComponentAlias::InstanceExport { + kind, + instance_index: self.read_var_u32()?, + name: self.read_string()?, + }, + 0x01 => ComponentAlias::Outer { + kind, + count: self.read_var_u32()?, + index: self.read_var_u32()?, + }, x => return self.invalid_leading_byte(x, "alias"), }) } @@ -666,13 +658,20 @@ 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()?), + ExternalKind::Module => TypeRef::Module(self.read_var_u32()?), + ExternalKind::Instance => { + return Err(BinaryReaderError::new( + "references to core instances is not currently supported", + self.original_position() - 1, + )) + } }) } 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 +746,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 +1436,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 +1459,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 +1552,7 @@ impl<'a> BinaryReader<'a> { )); } Operator::TypedSelect { - ty: self.read_type()?, + ty: self.read_val_type()?, } } 0x20 => Operator::LocalGet { @@ -1797,7 +1796,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..5ff7a15145 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1,14 +1,11 @@ -use crate::limits::MAX_WASM_MODULE_SIZE; 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 +106,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 +138,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 +149,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 +203,16 @@ 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 component section from a WebAssembly component was received and the /// provided parser can be used to parse the nested component. /// @@ -202,54 +233,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 +397,17 @@ impl Parser { /// } /// /// // Sections for WebAssembly components - /// ComponentTypeSection(_) => { /* ... */ } - /// ComponentImportSection(_) => { /* ... */ } - /// ComponentFunctionSection(_) => { /* ... */ } /// ModuleSection { .. } => { /* ... */ } - /// ComponentSection { .. } => { /* ... */ } /// InstanceSection(_) => { /* ... */ } - /// ComponentExportSection(_) => { /* ... */ } - /// ComponentStartSection { .. } => { /* ... */ } /// AliasSection(_) => { /* ... */ } + /// ComponentSection { .. } => { /* ... */ } + /// ComponentInstanceSection(_) => { /* ... */ } + /// ComponentAliasSection(_) => { /* ... */ } + /// ComponentTypeSection(_) => { /* ... */ } + /// ComponentCanonicalSection(_) => { /* ... */ } + /// ComponentStartSection { .. } => { /* ... */ } + /// ComponentImportSection(_) => { /* ... */ } + /// ComponentExportSection(_) => { /* ... */ } /// /// CustomSection(_) => { /* ... */ } /// @@ -586,30 +594,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 +614,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, TypeSectionReader::new, TypeSection) + } + // 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 +979,41 @@ 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(), 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 +1345,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 +1396,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..ebf471e49a 100644 --- a/crates/wasmparser/src/readers/component/aliases.rs +++ b/crates/wasmparser/src/readers/component/aliases.rs @@ -1,75 +1,41 @@ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use crate::{ + BinaryReader, ComponentExternalKind, 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. #[derive(Debug, Clone)] -pub enum Alias<'a> { - /// The alias is to an export of an instance. +pub enum ComponentAlias<'a> { + /// The alias is to an export of a component instance. InstanceExport { /// The alias kind. - kind: AliasKind, - /// The instance identifier. - instance: u32, + kind: ComponentExternalKind, + /// 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 alias is to an outer item. + Outer { + /// The alias kind. + kind: ComponentExternalKind, /// The outward count, starting at zero for the current component. count: u32, - /// The index of the type within the outer component. + /// 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 AliasSectionReader<'a> { +pub struct ComponentAliasSectionReader<'a> { reader: BinaryReader<'a>, count: u32, } -impl<'a> AliasSectionReader<'a> { - /// Constructs a new `AliasSectionReader` for the given data and offset. +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()?; @@ -90,21 +56,21 @@ impl<'a> AliasSectionReader<'a> { /// /// # Examples /// ``` - /// use wasmparser::AliasSectionReader; - /// let data: &[u8] = &[0x01, 0x02, 0x00, 0x03, b'f', b'o', b'o']; - /// let mut reader = AliasSectionReader::new(data, 0).unwrap(); + /// 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_alias() + pub fn read(&mut self) -> Result> { + self.reader.read_component_alias() } } -impl<'a> SectionReader for AliasSectionReader<'a> { - type Item = Alias<'a>; +impl<'a> SectionReader for ComponentAliasSectionReader<'a> { + type Item = ComponentAlias<'a>; fn read(&mut self) -> Result { Self::read(self) @@ -123,14 +89,14 @@ impl<'a> SectionReader for AliasSectionReader<'a> { } } -impl<'a> SectionWithLimitedItems for AliasSectionReader<'a> { +impl<'a> SectionWithLimitedItems for ComponentAliasSectionReader<'a> { fn get_count(&self) -> u32 { Self::get_count(self) } } -impl<'a> IntoIterator for AliasSectionReader<'a> { - type Item = Result>; +impl<'a> IntoIterator for ComponentAliasSectionReader<'a> { + type Item = Result>; type IntoIter = SectionIteratorLimited; fn into_iter(self) -> Self::IntoIter { diff --git a/crates/wasmparser/src/readers/component/functions.rs b/crates/wasmparser/src/readers/component/canonicals.rs similarity index 59% rename from crates/wasmparser/src/readers/component/functions.rs rename to crates/wasmparser/src/readers/component/canonicals.rs index 5009acf7e1..2864a428ca 100644 --- a/crates/wasmparser/src/readers/component/functions.rs +++ b/crates/wasmparser/src/readers/component/canonicals.rs @@ -10,43 +10,51 @@ 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 or lowering of a function requires + /// cleanup after the function returns. + /// + /// The value is an index to a core function of type `(func)`. + 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 +77,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 +110,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..10da93e5aa 100644 --- a/crates/wasmparser/src/readers/component/instances.rs +++ b/crates/wasmparser/src/readers/component/instances.rs @@ -1,83 +1,43 @@ use crate::{ - BinaryReader, ComponentExport, Export, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, + BinaryReader, ComponentExport, ComponentExternalKind, 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 an argument to instantiating a WebAssembly component. -#[derive(Debug, Clone)] -pub struct ModuleArg<'a> { - /// The name of the module argument. - pub name: &'a str, - /// The kind of the module argument. - pub kind: ModuleArgKind, -} - -/// 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> { +pub struct ComponentInstantiationArg<'a> { /// The name of the component argument. pub name: &'a str, /// The kind of the component argument. - pub kind: ComponentArgKind, + pub kind: ComponentExternalKind, + /// The index of the argument item. + pub index: u32, } /// Represents an instance in a WebAssembly component. #[derive(Debug, Clone)] -pub enum Instance<'a> { - /// The instance is from instantiating a WebAssembly module. - Module { - /// The module index. - index: u32, - /// The module's instantiation arguments. - args: Box<[ModuleArg<'a>]>, - }, +pub enum ComponentInstance<'a> { /// The instance is from instantiating a WebAssembly component. - Component { + Instantiate { /// The component index. - index: u32, + component_index: u32, /// The component's instantiation arguments. - args: Box<[ComponentArg<'a>]>, + args: Box<[ComponentInstantiationArg<'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<[ComponentExport<'a>]>), } -/// A reader for the instance section of a WebAssembly component. +/// A reader for the component instance section of a WebAssembly component. #[derive(Clone)] -pub struct InstanceSectionReader<'a> { +pub struct ComponentInstanceSectionReader<'a> { reader: BinaryReader<'a>, count: u32, } -impl<'a> InstanceSectionReader<'a> { - /// Constructs a new `InstanceSectionReader` for the given data and offset. +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()?; @@ -98,21 +58,21 @@ 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 mut reader = InstanceSectionReader::new(data, 0).unwrap(); + /// 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_instance() + pub fn read(&mut self) -> Result> { + self.reader.read_component_instance() } } -impl<'a> SectionReader for InstanceSectionReader<'a> { - type Item = Instance<'a>; +impl<'a> SectionReader for ComponentInstanceSectionReader<'a> { + type Item = ComponentInstance<'a>; fn read(&mut self) -> Result { Self::read(self) @@ -131,14 +91,14 @@ impl<'a> SectionReader for InstanceSectionReader<'a> { } } -impl<'a> SectionWithLimitedItems for InstanceSectionReader<'a> { +impl<'a> SectionWithLimitedItems for ComponentInstanceSectionReader<'a> { fn get_count(&self) -> u32 { Self::get_count(self) } } -impl<'a> IntoIterator for InstanceSectionReader<'a> { - type Item = Result>; +impl<'a> IntoIterator for ComponentInstanceSectionReader<'a> { + type Item = Result>; type IntoIter = SectionIteratorLimited; /// Implements iterator over the instance section. @@ -146,9 +106,9 @@ impl<'a> IntoIterator for InstanceSectionReader<'a> { /// # Examples /// /// ``` - /// use wasmparser::InstanceSectionReader; - /// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x02, 0x00]; - /// let mut reader = InstanceSectionReader::new(data, 0).unwrap(); + /// 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")); /// } diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index a4e95535e2..4e8a1e250f 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -1,98 +1,21 @@ use crate::{ - BinaryReader, ComponentImport, Import, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, TypeDef, TypeRef, + BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, Result, + SectionIteratorLimited, SectionReader, SectionWithLimitedItems, }; use std::ops::Range; -/// Represents a type defined 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>), -} - -/// Represents a module type definition in a WebAssembly component. -#[derive(Debug, Clone)] -pub enum ModuleType<'a> { - /// The module type definition is for a type. - Type(TypeDef), - /// The module type definition is for an export. - Export { - /// The name of the exported item. - name: &'a str, - /// The type of the exported item. - 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>), -} - -/// 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, - }, -} - -/// 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, +/// Represents a value type in a WebAssembly component. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +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 interface type. +/// Represents a primitive value type. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PrimitiveInterfaceType { +pub enum PrimitiveValType { /// The type is the unit type. Unit, /// The type is a boolean. @@ -123,40 +46,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 +88,100 @@ 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 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 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 value type of the variant case. + pub ty: ComponentValType, /// The default-to case index to use when this case is not present. pub default_to: 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 +215,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 +254,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 +262,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.rs b/crates/wasmparser/src/readers/core.rs index 941f208548..f99ac87b8d 100644 --- a/crates/wasmparser/src/readers/core.rs +++ b/crates/wasmparser/src/readers/core.rs @@ -1,3 +1,4 @@ +mod aliases; mod code; mod custom; mod data; @@ -7,6 +8,7 @@ mod functions; mod globals; mod imports; mod init; +mod instances; mod linking; mod memories; mod names; @@ -17,6 +19,7 @@ mod tables; mod tags; mod types; +pub use self::aliases::*; pub use self::code::*; pub use self::custom::*; pub use self::data::*; @@ -26,6 +29,7 @@ pub use self::functions::*; pub use self::globals::*; pub use self::imports::*; pub use self::init::*; +pub use self::instances::*; pub use self::linking::*; pub use self::memories::*; pub use self::names::*; diff --git a/crates/wasmparser/src/readers/core/aliases.rs b/crates/wasmparser/src/readers/core/aliases.rs new file mode 100644 index 0000000000..d8ce3fa9b7 --- /dev/null +++ b/crates/wasmparser/src/readers/core/aliases.rs @@ -0,0 +1,96 @@ +use crate::{ + BinaryReader, ExternalKind, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents a core alias for a WebAssembly module. +#[derive(Debug, Clone)] +pub enum Alias<'a> { + /// The alias is to an export of a module instance. + InstanceExport { + /// The alias kind. + kind: ExternalKind, + /// The instance index. + instance_index: u32, + /// The export name. + name: &'a str, + }, +} + +/// A reader for the core alias section of a WebAssembly component. +#[derive(Clone)] +pub struct AliasSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> AliasSectionReader<'a> { + /// Constructs a new `AliasSectionReader` 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 core alias section. + /// + /// # Examples + /// ``` + /// use wasmparser::AliasSectionReader; + /// 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"); + /// println!("Alias: {:?}", alias); + /// } + /// ``` + pub fn read(&mut self) -> Result> { + self.reader.read_alias() + } +} + +impl<'a> SectionReader for AliasSectionReader<'a> { + type Item = Alias<'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 AliasSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for AliasSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited; + + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} 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/exports.rs b/crates/wasmparser/src/readers/core/exports.rs index 5aa8e7316f..88805f57bd 100644 --- a/crates/wasmparser/src/readers/core/exports.rs +++ b/crates/wasmparser/src/readers/core/exports.rs @@ -31,6 +31,14 @@ pub enum ExternalKind { Global, /// The external kind is a tag. Tag, + /// The external kind is a module. + /// + /// This is used with the component model proposal. + Module, + /// The external kind is an instance of a module. + /// + /// This is used with the component model proposal. + Instance, } /// Represents an export in a WebAssembly module. diff --git a/crates/wasmparser/src/readers/core/imports.rs b/crates/wasmparser/src/readers/core/imports.rs index 81df2680d8..db97b530cc 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. @@ -38,6 +38,12 @@ pub enum TypeRef { /// /// The value is an index in the types index space. Tag(TagType), + /// The type is a module. + /// + /// The value is an index into the the type section. + /// + /// This variant is currently only used with the component model proposal. + Module(u32), } /// Represents an import in a WebAssembly module. diff --git a/crates/wasmparser/src/readers/core/instances.rs b/crates/wasmparser/src/readers/core/instances.rs new file mode 100644 index 0000000000..a2505adb57 --- /dev/null +++ b/crates/wasmparser/src/readers/core/instances.rs @@ -0,0 +1,119 @@ +use crate::{ + BinaryReader, Export, ExternalKind, Result, SectionIteratorLimited, SectionReader, + SectionWithLimitedItems, +}; +use std::ops::Range; + +/// Represents an argument to instantiating a WebAssembly module. +#[derive(Debug, Clone)] +pub struct InstantiationArg<'a> { + /// The name of the module argument. + pub name: &'a str, + /// The kind of the module argument. + pub kind: ExternalKind, + /// The index of the argument item. + pub index: u32, +} + +/// Represents an instance of a WebAssembly module. +#[derive(Debug, Clone)] +pub enum Instance<'a> { + /// The instance is from instantiating a WebAssembly module. + Instantiate { + /// The module index. + module_index: u32, + /// The module's instantiation arguments. + args: Box<[InstantiationArg<'a>]>, + }, + /// The instance is a from exporting local items. + FromExports(Box<[Export<'a>]>), +} + +/// A reader for the core instance section of a WebAssembly component. +#[derive(Clone)] +pub struct InstanceSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> InstanceSectionReader<'a> { + /// Constructs a new `InstanceSectionReader` 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::InstanceSectionReader; + /// # 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"); + /// println!("Instance: {:?}", instance); + /// } + /// ``` + pub fn read(&mut self) -> Result> { + self.reader.read_instance() + } +} + +impl<'a> SectionReader for InstanceSectionReader<'a> { + type Item = Instance<'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 InstanceSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for InstanceSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited; + + /// Implements iterator over the instance section. + /// + /// # Examples + /// + /// ``` + /// use wasmparser::InstanceSectionReader; + /// # 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")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} 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..91e80fb449 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -13,49 +13,72 @@ * limitations under the License. */ -use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; +use crate::{ + BinaryReader, Import, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, + TypeRef, +}; 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<'a> { + /// The type is for a function. Func(FuncType), + /// The type is for a module. + /// + /// Currently this variant is only used when parsing components. + Module(Box<[ModuleTypeDeclaration<'a>]>), +} + +/// Represents a module type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ModuleTypeDeclaration<'a> { + /// The module type definition is for a type. + Type(Type<'a>), + /// The module type definition is for an export. + Export { + /// The name of the exported item. + name: &'a str, + /// The type reference of the export. + ty: TypeRef, + }, + /// The module type definition is for an import. + Import(Import<'a>), } /// Represents a type of a function in a WebAssembly module. #[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 +117,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 +130,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 +188,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<'a>; fn read(&mut self) -> Result { Self::read(self) @@ -197,7 +220,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..7193b19a6b 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,23 @@ 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)?, 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,39 +494,63 @@ 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( - Order::Type, - section, - "type", - |state, _, types, count, offset| { - check_max( - state.module.types.len(), - count, - MAX_WASM_TYPES, - "types", - offset, - )?; - types.reserve(count as usize); - state.module.assert_mut().types.reserve(count as usize); - Ok(()) - }, - |state, features, types, def, offset| { - state - .module - .assert_mut() - .add_type(def, features, types, offset, false /* checked above */) - }, - ) + self.state.ensure_parsable(section.range().start)?; + + match self.state { + State::Module => { + self.process_module_section( + Order::Type, + section, + "type", + |state, _, types, count, offset| { + check_max( + state.module.types.len(), + count, + MAX_WASM_TYPES, + "types", + offset, + )?; + types.reserve(count as usize); + state.module.assert_mut().types.reserve(count as usize); + Ok(()) + }, + |state, features, types, def, offset| { + state + .module + .assert_mut() + .add_type(def, features, types, offset, false /* checked above */) + }, + ) + } + State::Component => { + self.process_component_section( + section, + "core 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.core_types.reserve(count as usize); + Ok(()) + }, + |components, types, features, ty, offset| { + let current = components.last_mut().unwrap(); + current.add_core_type( + ty, features, types, offset, false, /* checked above */ + ) + }, + ) + } + _ => unreachable!(), + } } /// Validates [`Payload::ImportSection`](crate::Payload). /// /// 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 +568,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 +594,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 +619,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 +651,7 @@ impl Validator { )); } - self.ensure_module_section( + self.process_module_section( Order::Tag, section, "tag", @@ -660,7 +679,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 +704,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 +720,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 +732,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 +751,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 +781,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 +802,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 +852,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 +869,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,6 +887,54 @@ impl Validator { ) } + /// Validates [`Payload::ComponentInstanceSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + 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.instance_count(), + count, + MAX_WASM_INSTANCES, + "instances", + offset, + )?; + current.instances.reserve(count as usize); + Ok(()) + }, + |components, types, _, instance, offset| { + components + .last_mut() + .unwrap() + .add_instance(instance, types, offset) + }, + ) + } + + /// Validates [`Payload::ComponentAliasSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + pub fn component_alias_section( + &mut self, + section: &crate::ComponentAliasSectionReader, + ) -> 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) + }, + ) + } + /// Validates [`Payload::ComponentTypeSection`](crate::Payload). /// /// This method should only be called when parsing a component. @@ -872,12 +942,12 @@ impl Validator { &mut self, section: &crate::ComponentTypeSectionReader, ) -> Result<()> { - self.ensure_component_section( + self.process_component_section( section, "type", |components, types, count, offset| { let current = components.last_mut().unwrap(); - check_max(current.types.len(), count, MAX_WASM_TYPES, "types", offset)?; + check_max(current.type_count(), count, MAX_WASM_TYPES, "types", offset)?; types.reserve(count as usize); current.types.reserve(count as usize); Ok(()) @@ -897,7 +967,7 @@ impl Validator { &mut self, section: &crate::ComponentImportSectionReader, ) -> Result<()> { - self.ensure_component_section( + self.process_component_section( section, "import", |_, _, _, _| Ok(()), // add_import will check limits @@ -910,43 +980,43 @@ impl Validator { ) } - /// Validates [`Payload::ComponentFunctionSection`](crate::Payload). + /// Validates [`Payload::ComponentCanonicalSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn component_function_section( + pub fn component_canonical_section( &mut self, - section: &crate::ComponentFunctionSectionReader, + section: &crate::ComponentCanonicalSectionReader, ) -> Result<()> { - self.ensure_component_section( + self.process_component_section( section, "function", |components, _, count, offset| { let current = components.last_mut().unwrap(); check_max( - current.functions.len(), + current.function_count(), count, MAX_WASM_FUNCTIONS, "functions", offset, )?; - current.functions.reserve(count as usize); + current.funcs.reserve(count as usize); Ok(()) }, |components, types, _, func, offset| { let current = components.last_mut().unwrap(); match func { - crate::ComponentFunction::Lift { + crate::CanonicalFunction::Lift { + core_func_index, type_index, - func_index, options, } => current.lift_function( + core_func_index, type_index, - func_index, options.into_vec(), types, offset, ), - crate::ComponentFunction::Lower { + crate::CanonicalFunction::Lower { func_index, options, } => current.lower_function(func_index, options.into_vec(), types, offset), @@ -959,10 +1029,11 @@ impl Validator { /// /// 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)?; + self.state.ensure_component("module", range.start)?; + let current = self.components.last_mut().unwrap(); check_max( - current.modules.len(), + current.core_modules.len(), 1, MAX_WASM_MODULES, "modules", @@ -981,8 +1052,8 @@ impl Validator { /// /// 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(), @@ -1004,26 +1075,26 @@ impl Validator { /// /// This method should only be called when parsing a component. pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> { - self.ensure_component_section( + self.process_component_section( section, - "instance", + "core instance", |components, _, count, offset| { let current = components.last_mut().unwrap(); check_max( - current.instances.len(), + current.instance_count(), count, MAX_WASM_INSTANCES, "instances", offset, )?; - current.instances.reserve(count as usize); + current.core_instances.reserve(count as usize); Ok(()) }, |components, types, _, instance, offset| { components .last_mut() .unwrap() - .add_instance(instance, types, offset) + .add_core_instance(instance, types, offset) }, ) } @@ -1035,7 +1106,7 @@ impl Validator { &mut self, section: &crate::ComponentExportSectionReader, ) -> Result<()> { - self.ensure_component_section( + self.process_component_section( section, "export", |components, _, count, offset| { @@ -1050,9 +1121,9 @@ impl Validator { current.exports.reserve(count as usize); Ok(()) }, - |components, types, _, export, offset| { + |components, _, _, export, offset| { let current = components.last_mut().unwrap(); - let ty = current.export_to_entity_type(&export, types, offset)?; + let ty = current.export_to_entity_type(&export, offset)?; current.add_export(export.name, ty, offset, false /* checked above */) }, ) @@ -1066,7 +1137,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( @@ -1081,12 +1153,15 @@ impl Validator { /// /// This method should only be called when parsing a component. pub fn alias_section(&mut self, section: &crate::AliasSectionReader) -> Result<()> { - self.ensure_component_section( + self.process_component_section( section, - "alias", + "core alias", |_, _, _, _| Ok(()), // maximums checked via `add_alias` |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { - ComponentState::add_alias(components, alias, types, offset) + components + .last_mut() + .unwrap() + .add_core_alias(alias, types, offset) }, ) } @@ -1121,7 +1196,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 +1220,7 @@ impl Validator { } } - fn ensure_module_section( + fn process_module_section( &mut self, order: Order, section: &T, @@ -1169,7 +1244,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 +1269,7 @@ impl Validator { Ok(()) } - fn ensure_component_section( + fn process_component_section( &mut self, section: &T, name: &str, @@ -1219,7 +1294,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 +1323,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 +1363,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 +1392,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..50d21cb9a7 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, ComponentTypeRef, ExternalKind, + FuncType, GlobalType, 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::Type, + features: &WasmFeatures, + types: &mut TypeList, + offset: usize, + check_limit: bool, + ) -> Result<()> { + let ty = match ty { + crate::Type::Func(ty) => Type::Func(ty), + crate::Type::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, &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, &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,43 @@ 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 { + ComponentExternalKind::Module => { + Self::alias_module(components, count, index, offset) + } + ComponentExternalKind::Type => Self::alias_type(components, count, index, offset), + ComponentExternalKind::Component => { + Self::alias_component(components, count, index, offset) + } + ComponentExternalKind::Func + | ComponentExternalKind::Value + | ComponentExternalKind::Instance => Err(BinaryReaderError::new( + "outer aliases may only be made to types, modules, and components", + offset, + )), + }, + } + } + + pub fn add_start( &mut self, func_index: u32, args: &[u32], @@ -316,8 +429,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 +458,7 @@ impl ComponentState { } match ft.result { - InterfaceTypeRef::Primitive(PrimitiveInterfaceType::Unit) => {} + ComponentValType::Primitive(PrimitiveValType::Unit) => {} ty => { self.values.push((ty, false)); } @@ -355,68 +469,10 @@ 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, + options: &[CanonicalOption], types: &TypeList, offset: usize, ) -> Result<()> { @@ -424,42 +480,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 { @@ -478,118 +509,197 @@ 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.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( + "invalid realloc function 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 ty = types[self.function_at(*idx, offset)?] + .as_func_type() + .unwrap(); + if !ty.params.as_ref().is_empty() || !ty.returns.as_ref().is_empty() { + return Err(BinaryReaderError::new( + "invalid post-return function 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 +716,41 @@ 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::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 == ComponentExternalKind::Type => + { + Self::alias_type(components, count, index, offset)?; + } + _ => return Err(BinaryReaderError::new( + "only outer type aliases are allowed in component type declarations", + offset, + )), + } } }; } @@ -650,38 +766,44 @@ 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) => { + for decl in decls { + match decl { + crate::InstanceTypeDeclaration::Type(ty) => { Self::add_type(components, 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::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::InstanceType::OuterType { count, index } => { - Self::alias_type(components, count, index, offset)?; + crate::InstanceTypeDeclaration::Alias(alias) => { + match alias { + crate::ComponentAlias::Outer { kind, count, index } + if kind == ComponentExternalKind::Type => + { + Self::alias_type(components, count, index, offset)?; + } + _ => return Err(BinaryReaderError::new( + "only outer type aliases are allowed in component 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 +822,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 +849,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,18 +882,25 @@ 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(); + ExternalKind::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)?; } } + _ => { + return Err(BinaryReaderError::new( + "only instance instantiation arguments are allowed", + offset, + )); + } } } // 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 +945,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 +966,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 +995,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 +1093,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 +1143,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 +1200,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 +1247,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,19 +1279,25 @@ 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, )?, + ExternalKind::Module | ExternalKind::Instance => { + return Err(BinaryReaderError::new( + "cannot create a core instance from a module or instance export", + offset, + )) + } } } - 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 +1310,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 +1338,73 @@ 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") + } + ExternalKind::Module | ExternalKind::Instance => Err(BinaryReaderError::new( + "aliases to core modules or instances is not supported", + offset, + )), + } + } + + 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 +1413,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 +1484,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(()) } @@ -1366,10 +1519,10 @@ impl ComponentState { 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 +1540,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,7 +1609,7 @@ impl ComponentState { cases: &[crate::VariantCase], types: &TypeList, offset: usize, - ) -> Result { + ) -> Result { let mut type_size = 1; let cases = cases .iter() @@ -1457,7 +1623,7 @@ impl ComponentState { )); } } - 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(), @@ -1469,30 +1635,33 @@ impl ComponentState { }) .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 +1672,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 +1680,7 @@ impl ComponentState { )); } - Ok(InterfaceType::Enum( + Ok(ComponentDefinedType::Enum( cases .iter() .map(|name| { @@ -1524,166 +1693,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 +1814,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 +1898,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 +1908,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 +1921,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..80bf231fcf 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,14 @@ impl Module { offset, )); } - TypeDef::Func(t) + Type::Func(t) + } + crate::Type::Module(_) => { + // Currently an error, but may be supported with a future module linking proposal. + return Err(BinaryReaderError::new( + "module types are not currently supported in core modules", + offset, + )); } }; @@ -405,7 +412,7 @@ impl Module { Ok(()) } - pub(super) fn add_import( + pub fn add_import( &mut self, import: crate::Import, features: &WasmFeatures, @@ -443,6 +450,7 @@ impl Module { self.num_imported_globals += 1; (self.globals.len(), MAX_WASM_GLOBALS, "globals") } + TypeRef::Module(_) => unreachable!(), }; check_max(len, 0, max, desc, offset)?; @@ -457,7 +465,7 @@ impl Module { Ok(()) } - pub(super) fn add_export( + pub fn add_export( &mut self, name: &str, ty: EntityType, @@ -491,12 +499,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 +527,7 @@ impl Module { Ok(()) } - pub(super) fn add_tag( + pub fn add_tag( &mut self, ty: TagType, features: &WasmFeatures, @@ -536,7 +539,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 +555,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, @@ -583,6 +593,13 @@ impl Module { self.check_global_type(t, features, offset)?; EntityType::Global(*t) } + TypeRef::Module(_) => { + // Currently an error, but may be supported with a future module linking proposal. + return Err(BinaryReaderError::new( + "modules cannot import other modules", + offset, + )); + } }) } @@ -593,8 +610,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)); } @@ -789,10 +806,24 @@ impl Module { check("tag", export.index, self.tags.len())?; EntityType::Tag(self.tags[export.index as usize]) } + ExternalKind::Module => { + // May be supported with a module linking proposal in the future + return Err(BinaryReaderError::new( + "module exports are not allowed in core modules", + offset, + )); + } + ExternalKind::Instance => { + // May be supported with a module linking proposal in the future + return Err(BinaryReaderError::new( + "instance exports are not allowed in core modules", + offset, + )); + } }) } - pub(super) fn get_func_type<'a>( + pub fn get_func_type<'a>( &self, func_idx: u32, types: &'a TypeList, @@ -877,7 +908,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 +920,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 +964,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 +976,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..faf59eb968 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,7 +702,7 @@ impl ComponentFuncType { #[derive(Debug, Clone)] pub struct VariantCase { /// The variant case type. - pub ty: InterfaceTypeRef, + pub ty: ComponentValType, /// The value of the variant to default to. pub default_to: Option, } @@ -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,7 +808,7 @@ 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 @@ -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; From 3b06f9eac67ed47c99356d75b7b9f235cddc1d6b Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Wed, 25 May 2022 20:30:29 -0700 Subject: [PATCH 05/33] wasmparser-dump: update for component model changes. This commit updates `wasmparser-dump` to the latest `wasmparser` changes. --- crates/dump/src/lib.rs | 239 ++++++++++++++++++++++++----------------- 1 file changed, 142 insertions(+), 97 deletions(-) diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index 064be25741..9ea86fb96f 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,47 @@ 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::Module(_) => { + write!(me.state, "[module {}]", inc(&mut i.core_modules))? } - 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 +139,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 +203,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 +216,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 +235,44 @@ 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, + "[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, "instance", |me, end, e| { + write!( + me.state, + "[instance {}] {:?}", + inc(&mut i.core_instances), + e + )?; + me.print(end) + })?, + + Payload::AliasSection(s) => self.section(s, "alias", |me, end, a| { + let (kind, num) = match a { + Alias::InstanceExport { kind, .. } => match kind { + ExternalKind::Func => ("core 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)), + ExternalKind::Module => ("module", inc(&mut i.core_modules)), + ExternalKind::Instance => ("core instance", inc(&mut i.core_instances)), + }, + }; + write!(me.state, "alias [{} {}] {:?}", kind, num, a)?; + me.print(end) + })?, + Payload::ComponentSection { range, .. } => { write!( self.state, @@ -284,13 +285,79 @@ 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 = match a { + ComponentAlias::InstanceExport { kind, .. } => kind, + ComponentAlias::Outer { kind, .. } => kind, + }; + + let (kind, num) = match kind { + ComponentExternalKind::Module => ("module", inc(&mut i.core_modules)), + ComponentExternalKind::Func => ("func", inc(&mut i.funcs)), + ComponentExternalKind::Value => ("value", inc(&mut i.values)), + ComponentExternalKind::Type => ("type", inc(&mut i.types)), + ComponentExternalKind::Instance => ("instance", inc(&mut i.instances)), + ComponentExternalKind::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 +370,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 +385,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 +400,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 +560,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 +583,5 @@ impl<'a> Dump<'a> { fn inc(spot: &mut u32) -> u32 { let ret = *spot; *spot += 1; - return ret; + ret } From fd3c1785f42e5827a653b2bb4079c0ea1cb59a75 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Wed, 25 May 2022 20:53:09 -0700 Subject: [PATCH 06/33] wasm-mutate: update to latest wasmparser changes. This commit updates `wasm-mutate` to the latest changes in `wasmparser`. --- crates/wasm-mutate/src/info.rs | 5 ++- crates/wasm-mutate/src/module.rs | 44 ++++++++++--------- crates/wasm-mutate/src/mutators/add_type.rs | 23 ++++++---- .../wasm-mutate/src/mutators/modify_data.rs | 5 +-- .../src/mutators/modify_init_exprs.rs | 7 ++- .../wasm-mutate/src/mutators/peephole/dfg.rs | 4 +- .../wasm-mutate/src/mutators/remove_item.rs | 3 ++ crates/wasm-mutate/src/mutators/translate.rs | 42 +++++++++++------- 8 files changed, 77 insertions(+), 56 deletions(-) diff --git a/crates/wasm-mutate/src/info.rs b/crates/wasm-mutate/src/info.rs index 50e7d12cd6..fb21ffb2b0 100644 --- a/crates/wasm-mutate/src/info.rs +++ b/crates/wasm-mutate/src/info.rs @@ -1,6 +1,6 @@ use crate::{ module::{PrimitiveTypeInfo, TypeInfo}, - Result, + Error, Result, }; use std::collections::HashSet; use std::convert::TryFrom; @@ -130,6 +130,9 @@ impl<'a> ModuleInfo<'a> { info.tag_count += 1; info.imported_tags_count += 1; } + wasmparser::TypeRef::Module(_) => { + return Err(Error::unsupported("module imports are not supported")) + } } } } diff --git a/crates/wasm-mutate/src/module.rs b/crates/wasm-mutate/src/module.rs index 1002a0ab61..0e1efded95 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() @@ -58,19 +57,22 @@ impl TryFrom for TypeInfo { .map(|&t| PrimitiveTypeInfo::from(t)) .collect(), })), + wasmparser::Type::Module(_) => Err(Error::unsupported( + "module types in core sections are not supported", + )), } } } -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..22ee398cba 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() @@ -70,6 +70,11 @@ impl Mutator for AddTypeMutator { .collect::, _>>()?; types.function(params, results); } + wasmparser::Type::Module(_) => { + return Err(crate::Error::unsupported( + "module types in core sections are not supported", + )); + } } } // And then add our new type. @@ -87,15 +92,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_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 64cd21812b..9cdb7b3c26 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -191,6 +191,7 @@ impl RemoveItem { } tag += 1; } + wasmparser::TypeRef::Module(_) => return Err(Error::unsupported("module imports are not supported")), } } module.section(&result); @@ -266,6 +267,8 @@ impl RemoveItem { ExternalKind::Global => { Export::Global(self.remap(Item::Global, item.index)?) } + ExternalKind::Module => return Err(Error::unsupported("module exports are not supported")), + ExternalKind::Instance => return Err(Error::unsupported("instance exports are not supported")), }; result.export(item.name, e); } diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index ba42398870..ca186481c0 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() @@ -130,6 +131,7 @@ pub fn type_def(t: &mut dyn Translator, ty: TypeDef, s: &mut TypeSection) -> Res ); Ok(()) } + Type::Module(_) => Err(Error::unsupported("module types are not supported")), } } @@ -172,15 +174,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 +219,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 +943,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, From 2b76150afbd4d11628dfa2d8be1eea8ae572e443 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Wed, 25 May 2022 21:16:01 -0700 Subject: [PATCH 07/33] wasm-smith: update for wasmparser changes. This commit updates `wasm-smith` for the latest `wasmparser` changes. --- crates/wasm-smith/src/core.rs | 13 ++++++++----- crates/wasm-smith/tests/core.rs | 15 ++++++++------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index 6a4851d59f..284238fe4e 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -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,7 +577,7 @@ 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) { @@ -591,6 +591,7 @@ impl Module { new_types.push(Type::Func(Rc::clone(&func_type))); new_index } + Some((wasmparser::Type::Module(_), _)) => unimplemented!(), }; match &new_types[serialized_sig_idx - first_type_index] { Type::Func(f) => Some((serialized_sig_idx as u32, Rc::clone(f))), @@ -681,6 +682,8 @@ impl Module { self.globals.push(global_ty); entity } + + wasmparser::TypeRef::Module(_) => unimplemented!(), }; new_imports.push(Import { module: import.module.to_string(), @@ -1508,9 +1511,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/tests/core.rs b/crates/wasm-smith/tests/core.rs index c888737878..84d30b16e0 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,8 @@ 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), + wasmparser::Type::Module(_) => unreachable!(), } } } else if let wasmparser::Payload::ImportSection(mut rdr) = payload { @@ -209,10 +210,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 +226,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], &[])), From d96330cc490a7c7541c4ee530d48465952e507f1 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Thu, 26 May 2022 11:43:16 -0700 Subject: [PATCH 08/33] wasmprinter: update for latest component model spec changes. This commit updates `wasmprinter` for both the latest `wasmparser` changes and to implement the separate index spaces for core and component items. --- crates/wasmprinter/src/lib.rs | 1511 ++++++++++++++++++--------------- 1 file changed, 822 insertions(+), 689 deletions(-) diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index f948d8878d..efa4f46393 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(()) @@ -358,7 +348,7 @@ impl Printer { 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 +359,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 +388,7 @@ impl Printer { self.printers = printers; } Payload::TypeSection(s) => { - Self::ensure_module(&states)?; + // This section is supported by both modules and components. self.print_types(states.last_mut().unwrap(), &mut types, s)? } Payload::ImportSection(s) => { @@ -439,7 +429,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 +453,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 +460,14 @@ 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::ComponentSection { parser: inner, .. } => { Self::ensure_component(&states)?; expected = Some(Encoding::Component); @@ -489,21 +475,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 +511,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 +589,77 @@ 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_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 + wasmparser::Type::Module(decls) => { + self.print_module_type(types, decls.into_vec())?; + Type::Module + } + }; self.end_group(); // `type` itself + + state.core.types.push(types.len()); + types.push(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 +681,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 +698,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 +723,7 @@ impl Printer { fn print_imports( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], parser: ImportSectionReader<'_>, ) -> Result<()> { for import in parser { @@ -728,18 +732,19 @@ 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, + TypeRef::Module(_) => bail!("core module imports are not supported"), } } Ok(()) @@ -748,7 +753,7 @@ impl Printer { fn print_import( &mut self, state: &State, - types: &[TypeDef], + types: &[Type], import: &Import<'_>, index: bool, ) -> Result<()> { @@ -765,24 +770,24 @@ 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)?, + TypeRef::Module(_) => bail!("core module imports are not supported"), } self.end_group(); Ok(()) @@ -791,7 +796,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 +808,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 +824,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 +850,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 +869,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 +880,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 +888,7 @@ impl Printer { fn print_tags( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], parser: TagSectionReader<'_>, ) -> Result<()> { for tag in parser { @@ -891,7 +896,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 +904,7 @@ impl Printer { fn print_globals( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], parser: GlobalSectionReader<'_>, ) -> Result<()> { for global in parser { @@ -909,7 +914,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 +922,7 @@ impl Printer { fn print_code( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], code: &[FunctionBody<'_>], mut funcs: FunctionSectionReader<'_>, ) -> Result<()> { @@ -928,10 +933,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 +956,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 +965,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 +1022,7 @@ impl Printer { self.end_group(); - state.functions.push(state.ty(ty)?); + state.core.funcs.push(state.core_ty(ty)?); } Ok(()) } @@ -1037,7 +1042,7 @@ impl Printer { fn print_operator( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], op: &Operator<'_>, nesting_start: u32, ) -> Result<()> { @@ -1109,7 +1114,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 +1124,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 +1155,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 +1203,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 +1229,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 +1384,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 +1425,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 +1962,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 +1981,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 +2001,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,39 +2021,54 @@ 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)?, + ExternalKind::Module => { + self.result.push_str("module "); + self.print_idx(&state.core.module_names, index)?; + } + ExternalKind::Instance => { + self.result.push_str("instance "); + self.print_idx(&state.core.instance_names, index)?; + } } self.result.push(')'); 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 +2082,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 +2092,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 +2101,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 +2118,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 +2138,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 +2149,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 +2166,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 +2185,7 @@ impl Printer { fn print_init_expr_sugar( &mut self, state: &mut State, - types: &[TypeDef], + types: &[Type], expr: &InitExpr, explicit: &str, ) -> Result<()> { @@ -2206,7 +2227,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 +2244,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 +2274,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(); @@ -2267,12 +2288,12 @@ impl Printer { self.start_group("case "); self.print_str(case.name)?; self.result.push(' '); - self.print_interface_type_ref(state, &case.ty)?; + self.print_component_val_type(state, &case.ty)?; if let Some(default) = case.default_to { match cases.get(default as usize) { Some(default) => { - self.start_group("defaults-to "); + self.start_group("refines "); self.print_str(default.name)?; self.end_group(); } @@ -2288,9 +2309,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 +2320,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 +2341,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 +2351,76 @@ 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.print_component_val_type(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.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))); - } + match decl { + ModuleTypeDeclaration::Type(ty) => match ty { + wasmparser::Type::Func(ty) => { + self.print_type(&mut state, types, wasmparser::Type::Func(ty))? } - } - ModuleType::Export { name, ty } => { + wasmparser::Type::Module(_) => bail!("invalid nested module type"), + }, + 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 +2432,76 @@ 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::Type(ty) => { + self.print_component_type_def(states, types, ty)? } - ComponentType::Export { name, ty } => { - self.print_export_from_type(states.last_mut().unwrap(), types, name, ty)? + 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(); } - ComponentType::Import(import) => { - self.print_component_import(states.last_mut().unwrap(), types, &import)? + 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::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(); } } } 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 +2516,7 @@ impl Printer { fn print_outer_alias( &mut self, states: &mut [State], - kind: OuterAliasKind, + kind: ComponentExternalKind, count: u32, index: u32, ) -> Result<()> { @@ -2488,27 +2531,34 @@ impl Printer { } self.result.push(' '); let index = match kind { - OuterAliasKind::Type => { - self.print_idx(&outer.type_names, index)?; + ComponentExternalKind::Type => { + self.print_idx(&outer.component.type_names, index)?; self.result.push(' '); self.start_group("type "); - self.print_name(&state.type_names, state.types.len() as u32)?; + self.print_name( + &state.component.type_names, + state.component.types.len() as u32, + )?; Some(outer.ty(index)?) } - OuterAliasKind::Module => { - self.print_idx(&outer.module_names, index)?; + ComponentExternalKind::Module => { + self.print_idx(&outer.core.module_names, index)?; self.result.push(' '); self.start_group("module "); - self.print_name(&state.module_names, state.modules)?; + self.print_name(&state.core.module_names, state.core.modules)?; None } - OuterAliasKind::Component => { - self.print_idx(&outer.component_names, index)?; + ComponentExternalKind::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)?) } + _ => bail!("invalid outer alias kind"), }; self.end_group(); // kind self.end_group(); // alias @@ -2517,48 +2567,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()), + ComponentExternalKind::Type => state.component.types.push(index.unwrap()), + ComponentExternalKind::Module => state.core.modules += 1, + ComponentExternalKind::Component => state.component.components.push(index.unwrap()), + _ => unreachable!(), } 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 +2585,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 +2604,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 +2646,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 +2661,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 +2712,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 => { + fn print_component_import_ty( + &mut self, + state: &State, + ty: &ComponentTypeRef, + index: bool, + ) -> Result<()> { + match ty { + ComponentTypeRef::Module(idx) => { 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 - } - 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); - } - 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)); + 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::ComponentFunc(_) => { + ComponentTypeRef::Func(idx) => { 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); + 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::Value => { + ComponentTypeRef::Value(ty) => { 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 + if index { + self.result.push(' '); + self.print_name(&state.component.value_names, state.component.values as u32)?; + } + match ty { + ComponentValType::Primitive(ty) => self.print_primitive_val_type(ty), + ComponentValType::Type(idx) => { + self.print_type_ref(state, *idx, false)?; + } + } + self.end_group(); + } + ComponentTypeRef::Type(_, idx) => { + self.print_type_ref(state, *idx, false)?; + } + 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 +2807,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 +2830,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) => { + ComponentExternalKind::Module => { self.start_group("module "); - self.print_idx(&state.module_names, *index)?; + 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 +2879,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 +2910,144 @@ 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_idx( + &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(); + self.print_canonical_options(state, &options)?; self.end_group(); - state.functions.push(state.ty(type_index)?); + 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_idx(&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.print_name(&state.core.instance_names, state.core.instances)?; match instance? { - Instance::Module { index, args } => { + Instance::Instantiate { module_index, args } => { self.result.push(' '); self.start_group("instantiate "); self.start_group("module "); - self.print_idx(&state.module_names, index)?; + self.print_idx(&state.core.module_names, module_index)?; self.end_group(); 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::FromExports(exports) => { + self.result.push_str(" core"); + for export in exports.iter() { + self.newline(); + self.print_export(state, export)?; + } + state.core.instances += 1; } - Instance::Component { index, args } => { + } + 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.print_idx(&state.component.component_names, component_index)?; self.end_group(); 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)?)); - } - 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); + .push(state.component(component_index)?); } - 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 +3056,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,26 +3065,31 @@ 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) => { + ExternalKind::Instance => { self.start_group("instance "); - self.print_idx(&state.instance_names, index)?; + self.print_idx(&state.core.instance_names, arg.index)?; self.end_group(); } + _ => bail!("only instances are supported for module instantiation arguments"), } self.end_group(); 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 +3097,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 @@ -3006,24 +3117,24 @@ impl Printer { self.start_group("start "); self.start_group("func "); - self.print_idx(&state.function_names, start.func_index)?; + self.print_idx(&state.component.func_names, start.func_index)?; self.end_group(); for arg in start.arguments.iter() { 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 +3142,179 @@ 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; + } + ExternalKind::Module | ExternalKind::Instance => { + bail!("core export alias for modules and instances is not supported") + } } + 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("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)? } } } From 232d0d564fec66a23e183ec9a526cff8f13cb9db Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Thu, 26 May 2022 15:47:15 -0700 Subject: [PATCH 09/33] fuzz-targets: update fuzz targets for wasmparser changes. This commit updates the incremental-parse fuzz target to conform to the latest `wasmparser` changes. --- fuzz/fuzz_targets/incremental-parse.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) 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 { From b87b70a1dacba4baa0ed877b8a71bdb33d9241a3 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Thu, 26 May 2022 15:50:29 -0700 Subject: [PATCH 10/33] objdump: fix the objdump command for latest `wasmparser` changes. This commit updates the `wasm-tools objdump` command for the latest `wasmparser` changes. --- src/bin/wasm-tools/objdump.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/bin/wasm-tools/objdump.rs b/src/bin/wasm-tools/objdump.rs index 7f5e47ea23..4027773701 100644 --- a/src/bin/wasm-tools/objdump.rs +++ b/src/bin/wasm-tools/objdump.rs @@ -44,23 +44,25 @@ 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, "instances")?, + AliasSection(s) => printer.section(s, "aliases")?, 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, From ad0124ead7c63b732aa4ce27691dcc7cb4b25730 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Fri, 3 Jun 2022 14:06:59 -0700 Subject: [PATCH 11/33] Add core types to component and instance types. This commit updates `wasm-encoder`, `wasmparser`, `wasmprinter`, and `wasm-smith` to support core types in component and instance type declarations. This was missing from the recent spec updates and has now been fixed in the spec. --- crates/wasm-encoder/src/component/types.rs | 50 ++++++++++++++++--- crates/wasm-encoder/src/core/types.rs | 2 +- crates/wasm-smith/src/component.rs | 24 ++++++--- crates/wasm-smith/src/component/encode.rs | 6 +++ crates/wasmparser/src/binary_reader.rs | 6 ++- .../wasmparser/src/readers/component/types.rs | 6 ++- crates/wasmparser/src/validator/component.rs | 9 ++++ crates/wasmprinter/src/lib.rs | 6 +++ 8 files changed, 90 insertions(+), 19 deletions(-) diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index a86aa2f969..f5eafbf844 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -1,6 +1,6 @@ use crate::{ encode_section, ComponentAliasKind, ComponentSection, ComponentSectionId, ComponentTypeRef, - Encode, + Encode, TypeEncoder, }; /// Represents a component type. @@ -8,6 +8,7 @@ use crate::{ pub struct ComponentType { bytes: Vec, num_added: u32, + core_types_added: u32, types_added: u32, } @@ -17,13 +18,15 @@ impl ComponentType { Self::default() } - /// Defines an import in this component type. - pub fn import(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { + /// 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) -> TypeEncoder { self.bytes.push(0x00); - name.encode(&mut self.bytes); - ty.encode(&mut self.bytes); self.num_added += 1; - self + self.core_types_added += 1; + TypeEncoder(&mut self.bytes) } /// Define a type in this component type. @@ -49,15 +52,29 @@ impl ComponentType { 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; + self + } + /// Defines an export in this component type. pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { - self.bytes.push(0x03); + 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 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. pub fn type_count(&self) -> u32 { self.types_added @@ -77,6 +94,7 @@ impl Encode for ComponentType { pub struct InstanceType { bytes: Vec, num_added: u32, + core_types_added: u32, types_added: u32, } @@ -86,6 +104,17 @@ impl InstanceType { 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) -> TypeEncoder { + self.bytes.push(0x00); + self.num_added += 1; + self.core_types_added += 1; + TypeEncoder(&mut self.bytes) + } + /// Define a type in this instance type. /// /// The returned encoder must be used before adding another definition. @@ -111,13 +140,18 @@ impl InstanceType { /// Defines an export in this instance type. pub fn export(&mut self, name: &str, ty: ComponentTypeRef) -> &mut Self { - self.bytes.push(0x03); + 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 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 instance type. pub fn type_count(&self) -> u32 { self.types_added diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs index 5d6ec8a649..9a03cc85ce 100644 --- a/crates/wasm-encoder/src/core/types.rs +++ b/crates/wasm-encoder/src/core/types.rs @@ -100,7 +100,7 @@ impl Encode for ModuleType { /// Used to encode core types. #[derive(Debug)] -pub struct TypeEncoder<'a>(&'a mut Vec); +pub struct TypeEncoder<'a>(pub(crate) &'a mut Vec); impl<'a> TypeEncoder<'a> { /// Define a function type. diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs index 2383270d04..8db475b464 100644 --- a/crates/wasm-smith/src/component.rs +++ b/crates/wasm-smith/src/component.rs @@ -1066,6 +1066,13 @@ impl ComponentBuilder { }); } + // 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)?; @@ -1760,7 +1767,7 @@ struct TypeSection { types: Vec>, } -#[derive(Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] enum CoreType { Module(Rc), } @@ -1828,18 +1835,20 @@ struct ComponentType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum ComponentTypeDef { - Import(Import), + CoreType(Rc), Type(Rc), - Export { name: String, ty: ComponentTypeRef }, 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), } } } @@ -1851,9 +1860,10 @@ struct InstanceType { #[derive(Clone, Debug, PartialEq, Eq, Hash)] enum InstanceTypeDef { + CoreType(Rc), Type(Rc), - Export { name: String, ty: ComponentTypeRef }, Alias(Alias), + Export { name: String, ty: ComponentTypeRef }, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index e6ec9aee35..8a6b534780 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -162,6 +162,9 @@ impl Type { ComponentTypeDef::Import(imp) => { 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()); } @@ -184,6 +187,9 @@ impl Type { 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()); } diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index 8ff44471e1..e9be0c74d2 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -335,7 +335,7 @@ impl<'a> BinaryReader<'a> { // Component types are effectively instance types with the additional // variant of imports; check for imports here or delegate to // `read_instance_type_decl` with the appropriate conversions. - if self.peek()? == 0x00 { + if self.peek()? == 0x03 { self.position += 1; return Ok(ComponentTypeDeclaration::Import( self.read_component_import()?, @@ -343,6 +343,7 @@ impl<'a> BinaryReader<'a> { } 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 } => { @@ -353,9 +354,10 @@ impl<'a> BinaryReader<'a> { pub(crate) fn read_instance_type_decl(&mut self) -> Result> { Ok(match self.read_u8()? { + 0x00 => InstanceTypeDeclaration::CoreType(self.read_type()?), 0x01 => InstanceTypeDeclaration::Type(self.read_component_type()?), 0x02 => InstanceTypeDeclaration::Alias(self.read_component_alias()?), - 0x03 => InstanceTypeDeclaration::Export { + 0x04 => InstanceTypeDeclaration::Export { name: self.read_string()?, ty: self.read_component_type_ref()?, }, diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 4e8a1e250f..8c6b2d145c 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -1,6 +1,6 @@ use crate::{ BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, Result, - SectionIteratorLimited, SectionReader, SectionWithLimitedItems, + SectionIteratorLimited, SectionReader, SectionWithLimitedItems, Type, }; use std::ops::Range; @@ -104,6 +104,8 @@ pub enum ComponentType<'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(Type<'a>), /// The component type declaration is for a type. Type(ComponentType<'a>), /// The component type declaration is for an alias. @@ -122,6 +124,8 @@ pub enum ComponentTypeDeclaration<'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(Type<'a>), /// The instance type declaration is for a type. Type(ComponentType<'a>), /// The instance type declaration is for an alias. diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 50d21cb9a7..60eacf6e37 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -725,6 +725,12 @@ impl ComponentState { 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)?; } @@ -775,6 +781,9 @@ impl ComponentState { for decl in decls { match decl { + crate::InstanceTypeDeclaration::CoreType(ty) => { + components.last_mut().unwrap().add_core_type(ty, features, types, offset, true)?; + } crate::InstanceTypeDeclaration::Type(ty) => { Self::add_type(components, ty, features, types, offset, true)?; } diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index efa4f46393..1187c4b136 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -2441,6 +2441,9 @@ impl Printer { for decl in decls { self.newline(); match decl { + ComponentTypeDeclaration::CoreType(ty) => { + self.print_type(states.last_mut().unwrap(), types, ty)? + } ComponentTypeDeclaration::Type(ty) => { self.print_component_type_def(states, types, ty)? } @@ -2480,6 +2483,9 @@ impl Printer { for decl in decls { self.newline(); match decl { + InstanceTypeDeclaration::CoreType(ty) => { + self.print_type(states.last_mut().unwrap(), types, ty)? + } InstanceTypeDeclaration::Type(ty) => { self.print_component_type_def(states, types, ty)? } From bcdacf12d4581d964b4eb641ff157d63d59d9131 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Fri, 3 Jun 2022 14:53:52 -0700 Subject: [PATCH 12/33] wasm-encoder: fix incorrect section id for component alias section. This fixes a typo that resulted from refactoring the alias section into a core and component alias section. --- crates/wasm-encoder/src/component/aliases.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wasm-encoder/src/component/aliases.rs b/crates/wasm-encoder/src/component/aliases.rs index 4c1db00052..50a0144be0 100644 --- a/crates/wasm-encoder/src/component/aliases.rs +++ b/crates/wasm-encoder/src/component/aliases.rs @@ -145,6 +145,6 @@ impl Encode for ComponentAliasSection { impl ComponentSection for ComponentAliasSection { fn id(&self) -> u8 { - ComponentSectionId::CoreCustom.into() + ComponentSectionId::Alias.into() } } From ac199504b8a7b1d8ac4ab13fdc896f00553767f5 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Fri, 3 Jun 2022 16:55:07 -0700 Subject: [PATCH 13/33] wasm-encoder: fix missing increments when adding alias items. This commit fixes the missing increments of `num_added` for both core and component aliases. --- crates/wasm-encoder/src/component/aliases.rs | 2 ++ crates/wasm-encoder/src/core/aliases.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/crates/wasm-encoder/src/component/aliases.rs b/crates/wasm-encoder/src/component/aliases.rs index 50a0144be0..56aeffc2b1 100644 --- a/crates/wasm-encoder/src/component/aliases.rs +++ b/crates/wasm-encoder/src/component/aliases.rs @@ -121,6 +121,7 @@ impl ComponentAliasSection { self.bytes.push(0x00); instance_index.encode(&mut self.bytes); name.encode(&mut self.bytes); + self.num_added += 1; self } @@ -133,6 +134,7 @@ impl ComponentAliasSection { self.bytes.push(0x01); count.encode(&mut self.bytes); index.encode(&mut self.bytes); + self.num_added += 1; self } } diff --git a/crates/wasm-encoder/src/core/aliases.rs b/crates/wasm-encoder/src/core/aliases.rs index 0878984494..4b5801e215 100644 --- a/crates/wasm-encoder/src/core/aliases.rs +++ b/crates/wasm-encoder/src/core/aliases.rs @@ -48,6 +48,7 @@ impl AliasSection { self.bytes.push(0x00); instance_index.encode(&mut self.bytes); name.encode(&mut self.bytes); + self.num_added += 1; self } } From f86c942d18b678099ce657f3439708b7e9ec61aa Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Sat, 4 Jun 2022 19:54:23 -0700 Subject: [PATCH 14/33] wasmparser: fix incorrect canonical option checking. This commit fixes component validation to ensure the types referenced from the `Realloc` and `PostReturn` options are core function types. --- crates/wasmparser/src/validator/component.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 60eacf6e37..6f48c36b47 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -499,7 +499,7 @@ impl ComponentState { Some(existing) => { return Err(BinaryReaderError::new( format!( - "canonical option `{}` conflicts with option `{}`", + "canonical encoding option `{}` conflicts with option `{}`", display(existing), display(*option) ), @@ -526,7 +526,7 @@ impl ComponentState { CanonicalOption::Realloc(idx) => { realloc = match realloc { None => { - let ty = types[self.function_at(*idx, offset)?] + let ty = types[self.core_function_at(*idx, offset)?] .as_func_type() .unwrap(); if ty.params.as_ref() @@ -551,7 +551,7 @@ impl ComponentState { CanonicalOption::PostReturn(idx) => { post_return = match post_return { None => { - let ty = types[self.function_at(*idx, offset)?] + let ty = types[self.core_function_at(*idx, offset)?] .as_func_type() .unwrap(); if !ty.params.as_ref().is_empty() || !ty.returns.as_ref().is_empty() { From 448faea124289aacb9689eaa9e5d3477d4b55522 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Sat, 4 Jun 2022 19:55:46 -0700 Subject: [PATCH 15/33] wasmprinter: fixes to output to conform to text format. This commit fixes wasmprinter in places where it wasn't conforming properly to the text format. Additionally, it fixes a bug where instance/component types weren't registering the exports of the type and subsequent lookups of the exports would fail. --- crates/wasmprinter/src/lib.rs | 74 +++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 1187c4b136..e142adcc37 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -343,7 +343,11 @@ 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]; @@ -606,11 +610,16 @@ impl Printer { fn print_type( &mut self, + core: bool, state: &mut State, types: &mut Vec, ty: wasmparser::Type, ) -> Result<()> { - self.start_group("type "); + if core { + self.start_group("core type "); + } else { + self.start_group("type "); + } self.print_name(&state.core.type_names, state.core.types.len() as u32)?; self.result.push(' '); let ty = match ty { @@ -640,7 +649,15 @@ impl Printer { ) -> Result<()> { for ty in parser { self.newline(); - self.print_type(state, types, ty?)?; + self.print_type( + match state.encoding { + Encoding::Component => true, + Encoding::Module => false, + }, + state, + types, + ty?, + )?; } Ok(()) @@ -2409,7 +2426,7 @@ impl Printer { match decl { ModuleTypeDeclaration::Type(ty) => match ty { wasmparser::Type::Func(ty) => { - self.print_type(&mut state, types, wasmparser::Type::Func(ty))? + self.print_type(false, &mut state, types, wasmparser::Type::Func(ty))? } wasmparser::Type::Module(_) => bail!("invalid nested module type"), }, @@ -2442,7 +2459,7 @@ impl Printer { self.newline(); match decl { ComponentTypeDeclaration::CoreType(ty) => { - self.print_type(states.last_mut().unwrap(), types, ty)? + self.print_type(true, states.last_mut().unwrap(), types, ty)? } ComponentTypeDeclaration::Type(ty) => { self.print_component_type_def(states, types, ty)? @@ -2461,6 +2478,16 @@ impl Printer { 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)? @@ -2484,7 +2511,7 @@ impl Printer { self.newline(); match decl { InstanceTypeDeclaration::CoreType(ty) => { - self.print_type(states.last_mut().unwrap(), types, ty)? + self.print_type(true, states.last_mut().unwrap(), types, ty)? } InstanceTypeDeclaration::Type(ty) => { self.print_component_type_def(states, types, ty)? @@ -2503,6 +2530,16 @@ impl Printer { 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)?; + } + _ => {} + } } } } @@ -2550,7 +2587,7 @@ impl Printer { ComponentExternalKind::Module => { self.print_idx(&outer.core.module_names, index)?; self.result.push(' '); - self.start_group("module "); + self.start_group("core module "); self.print_name(&state.core.module_names, state.core.modules)?; None } @@ -2737,7 +2774,7 @@ impl Printer { ) -> Result<()> { match ty { ComponentTypeRef::Module(idx) => { - self.start_group("module"); + self.start_group("core module"); if index { self.result.push(' '); self.print_name(&state.core.module_names, state.core.modules as u32)?; @@ -2758,10 +2795,10 @@ impl Printer { self.end_group(); } ComponentTypeRef::Value(ty) => { - self.start_group("value"); + self.start_group("value "); if index { - self.result.push(' '); 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), @@ -2849,7 +2886,7 @@ impl Printer { ) -> Result<()> { match kind { ComponentExternalKind::Module => { - self.start_group("module "); + self.start_group("core module "); self.print_idx(&state.core.module_names, index)?; } ComponentExternalKind::Component => { @@ -2931,7 +2968,7 @@ impl Printer { options, } => { self.start_group("func "); - self.print_idx( + self.print_name( &state.component.func_names, state.component.funcs.len() as u32, )?; @@ -2954,7 +2991,7 @@ impl Printer { options, } => { self.start_group("core func "); - self.print_idx(&state.core.func_names, state.core.funcs.len() as u32)?; + 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 "); @@ -2978,15 +3015,13 @@ impl Printer { fn print_instances(&mut self, state: &mut State, parser: InstanceSectionReader) -> Result<()> { for instance in parser { self.newline(); - self.start_group("instance "); + self.start_group("core instance "); self.print_name(&state.core.instance_names, state.core.instances)?; + self.result.push(' '); match instance? { Instance::Instantiate { module_index, args } => { - self.result.push(' '); self.start_group("instantiate "); - self.start_group("module "); self.print_idx(&state.core.module_names, module_index)?; - self.end_group(); for arg in args.iter() { self.newline(); self.print_instantiation_arg(state, arg)?; @@ -2995,7 +3030,6 @@ impl Printer { state.core.instances += 1; } Instance::FromExports(exports) => { - self.result.push_str(" core"); for export in exports.iter() { self.newline(); self.print_export(state, export)?; @@ -3028,9 +3062,7 @@ impl Printer { } => { self.result.push(' '); self.start_group("instantiate "); - self.start_group("component "); self.print_idx(&state.component.component_names, component_index)?; - self.end_group(); for arg in args.iter() { self.newline(); self.print_component_instantiation_arg(state, arg)?; @@ -3232,7 +3264,7 @@ impl Printer { self.result.push(' '); match kind { ComponentExternalKind::Module => { - self.start_group("module "); + self.start_group("core module "); self.print_name(&state.core.module_names, state.core.modules)?; self.end_group(); state.core.modules += 1; From f85b717cc9c5482100f1e68153d7f0947e61460d Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Sun, 5 Jun 2022 17:38:57 -0700 Subject: [PATCH 16/33] wasmparser: fix validation for post-return option. This commit fixes the validation of the post-return option so that it be present for lifting operations and that the parameters to the refer function match the results of the function being lifted. --- crates/wasmparser/src/validator/component.rs | 21 ++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 6f48c36b47..0bcacaac00 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -305,7 +305,7 @@ impl ComponentState { )); } - self.check_options(ty, &options, types, offset)?; + self.check_options(ty, Some(core_ty), &options, types, offset)?; self.funcs.push(self.types[type_index as usize]); Ok(()) @@ -322,7 +322,7 @@ impl ComponentState { .as_component_func_type() .unwrap(); - self.check_options(ty, &options, 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. @@ -472,6 +472,7 @@ impl ComponentState { fn check_options( &self, ty: &ComponentFuncType, + core_ty: Option<&FuncType>, options: &[CanonicalOption], types: &TypeList, offset: usize, @@ -501,7 +502,7 @@ impl ComponentState { format!( "canonical encoding option `{}` conflicts with option `{}`", display(existing), - display(*option) + display(*option), ), offset, )) @@ -534,7 +535,7 @@ impl ComponentState { || ty.returns.as_ref() != [ValType::I32] { return Err(BinaryReaderError::new( - "invalid realloc function signature", + "canonical option `realloc` uses a core function with an incorrect signature", offset, )); } @@ -551,12 +552,20 @@ impl ComponentState { 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.as_ref().is_empty() || !ty.returns.as_ref().is_empty() { + + if ty.params != core_ty.returns || !ty.returns.is_empty() { return Err(BinaryReaderError::new( - "invalid post-return function signature", + "canonical option `post-return` uses a core function with an incorrect signature", offset, )); } From da2938e3f6fcdab98b6c655a9aecf3bd2bb8075e Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Sun, 5 Jun 2022 17:39:18 -0700 Subject: [PATCH 17/33] wasmprinter: fix output for component start functions. This commit fixes the printer output for start functions to match what's expected in the text format. --- crates/wasmprinter/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index e142adcc37..8af597465b 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -3153,12 +3153,12 @@ impl Printer { } }; + self.newline(); self.start_group("start "); - self.start_group("func "); self.print_idx(&state.component.func_names, start.func_index)?; - self.end_group(); for arg in start.arguments.iter() { + self.result.push(' '); self.start_group("value "); self.print_idx(&state.component.value_names, *arg)?; self.end_group(); From 21a160397be0ee39f805d3bf956a76912b1d4c18 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Sun, 5 Jun 2022 18:17:44 -0700 Subject: [PATCH 18/33] wasmparser-dump: fix output to make core vs. component items clearer. --- crates/dump/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index 9ea86fb96f..d0f3141dc1 100644 --- a/crates/dump/src/lib.rs +++ b/crates/dump/src/lib.rs @@ -238,7 +238,7 @@ impl<'a> Dump<'a> { Payload::ModuleSection { range, .. } => { write!( self.state, - "[module {}] inline size", + "[core module {}] inline size", inc(&mut i.core_modules) )?; self.print(range.start)?; @@ -247,29 +247,29 @@ impl<'a> Dump<'a> { i = Indices::default(); } - Payload::InstanceSection(s) => self.section(s, "instance", |me, end, e| { + Payload::InstanceSection(s) => self.section(s, "core instance", |me, end, e| { write!( me.state, - "[instance {}] {:?}", + "[core instance {}] {:?}", inc(&mut i.core_instances), e )?; me.print(end) })?, - Payload::AliasSection(s) => self.section(s, "alias", |me, end, a| { + Payload::AliasSection(s) => self.section(s, "core alias", |me, end, a| { let (kind, num) = match a { Alias::InstanceExport { kind, .. } => match kind { - ExternalKind::Func => ("core func", inc(&mut i.core_funcs)), + 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)), ExternalKind::Module => ("module", inc(&mut i.core_modules)), - ExternalKind::Instance => ("core instance", inc(&mut i.core_instances)), + ExternalKind::Instance => ("instance", inc(&mut i.core_instances)), }, }; - write!(me.state, "alias [{} {}] {:?}", kind, num, a)?; + write!(me.state, "core alias [{} {}] {:?}", kind, num, a)?; me.print(end) })?, From 6a4e65a9e448acbbe473f298b3045bb439190389 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Fri, 27 May 2022 17:50:08 -0700 Subject: [PATCH 19/33] wast: update for the component model proposal changes. This commit basically rewrites the component model support in wast for the latest text format and binary format changes. `wast` now depends on `wasm-encoder` for encoding components so that there is a single implementation of the component binary format. In the future, we can also replace the core encoding implementation with using `wasm-encoder` instead (once it supports the GC proposal encoding). --- crates/wasm-encoder/src/component/aliases.rs | 5 +- crates/wasm-encoder/src/component/types.rs | 4 +- crates/wast/Cargo.toml | 1 + .../src/{component/mod.rs => component.rs} | 14 +- crates/wast/src/component/alias.rs | 309 +++-- crates/wast/src/component/binary.rs | 1057 ++++++++++------- crates/wast/src/component/component.rs | 117 +- crates/wast/src/component/custom.rs | 28 + crates/wast/src/component/deftype.rs | 330 ----- crates/wast/src/component/expand.rs | 759 +++++++----- crates/wast/src/component/export.rs | 135 ++- crates/wast/src/component/func.rs | 354 ++++-- crates/wast/src/component/import.rs | 95 +- crates/wast/src/component/instance.rs | 383 +++--- crates/wast/src/component/intertype.rs | 369 ------ crates/wast/src/component/item_ref.rs | 147 ++- crates/wast/src/component/module.rs | 54 +- crates/wast/src/component/resolve.rs | 857 ++++++++----- crates/wast/src/component/types.rs | 816 ++++++++++++- crates/wast/src/{core/mod.rs => core.rs} | 0 crates/wast/src/core/binary.rs | 1 - crates/wast/src/core/export.rs | 6 - crates/wast/src/core/expr.rs | 7 +- crates/wast/src/core/memory.rs | 4 +- crates/wast/src/core/resolve/names.rs | 1 - crates/wast/src/core/resolve/types.rs | 9 +- crates/wast/src/core/types.rs | 36 +- crates/wast/src/encode.rs | 2 +- crates/wast/src/error.rs | 4 +- crates/wast/src/lexer.rs | 8 +- crates/wast/src/lib.rs | 16 +- crates/wast/src/names.rs | 2 +- crates/wast/src/parser.rs | 35 +- crates/wast/src/wast.rs | 6 +- 34 files changed, 3564 insertions(+), 2407 deletions(-) rename crates/wast/src/{component/mod.rs => component.rs} (84%) create mode 100644 crates/wast/src/component/custom.rs delete mode 100644 crates/wast/src/component/deftype.rs delete mode 100644 crates/wast/src/component/intertype.rs rename crates/wast/src/{core/mod.rs => core.rs} (100%) diff --git a/crates/wasm-encoder/src/component/aliases.rs b/crates/wasm-encoder/src/component/aliases.rs index 56aeffc2b1..fa1f6a1060 100644 --- a/crates/wasm-encoder/src/component/aliases.rs +++ b/crates/wasm-encoder/src/component/aliases.rs @@ -1,7 +1,7 @@ use crate::{ encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_INSTANCE_SORT, CORE_MEMORY_SORT, CORE_MODULE_SORT, - CORE_TABLE_SORT, CORE_TYPE_SORT, + CORE_TABLE_SORT, CORE_TAG_SORT, CORE_TYPE_SORT, }; use super::{COMPONENT_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT}; @@ -17,6 +17,8 @@ pub enum CoreAliasKind { Memory, /// The alias is to a global. Global, + /// The alias is to a tag. + Tag, /// The alias is to a core type. Type, /// The alias is to a core module. @@ -32,6 +34,7 @@ impl Encode for CoreAliasKind { Self::Table => sink.push(CORE_TABLE_SORT), Self::Memory => sink.push(CORE_MEMORY_SORT), Self::Global => sink.push(CORE_GLOBAL_SORT), + Self::Tag => sink.push(CORE_TAG_SORT), Self::Type => sink.push(CORE_TYPE_SORT), Self::Module => sink.push(CORE_MODULE_SORT), Self::Instance => sink.push(CORE_INSTANCE_SORT), diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index f5eafbf844..a57ac36b13 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -104,7 +104,7 @@ impl InstanceType { Self::default() } - /// Define a core type in this component type. + /// 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"] @@ -147,7 +147,7 @@ impl InstanceType { self } - /// Gets the number of core types that have been added to this component type. + /// 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 } diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 9aabb54c7d..e529a1bd8b 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 = { 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..790500279f 100644 --- a/crates/wast/src/component/alias.rs +++ b/crates/wast/src/component/alias.rs @@ -1,108 +1,283 @@ -use crate::core; 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)] -pub struct Alias<'a> { - /// Where this `alias` was defined. +/// 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 this alias. - pub target: AliasTarget<'a>, - /// The kind of item that's being aliased. - pub kind: AliasKind, + /// The target of the alias. + pub target: CoreAliasTarget<'a>, + /// The kind of item being aliased. + pub kind: CoreAliasKind, } -/// 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 { +impl<'a> Parse<'a> for CoreAlias<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + parser.parse::()?; + let target = parser.parse()?; + let (kind, id, name) = parser.parens(|parser| { + let kind = parser.parse()?; + let id = parser.parse()?; + let name = parser.parse()?; + Ok((kind, id, name)) + })?; + + Ok(Self { + span, + target, + id, + name, + kind, + }) + } +} + +/// 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, + }, +} + +impl<'a> Parse<'a> for CoreAliasTarget<'a> { + fn parse(parser: Parser<'a>) -> Result { + // Right now only export aliases are supported. + parser.parse::()?; + Ok(Self::Export { + instance: parser.parse()?, + name: parser.parse()?, + }) + } +} + +/// Represents the kind of a core alias. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CoreAliasKind { + /// The alias is to a core function. + Func, + /// The alias is to a table. + Table, + /// The alias is to a module. + Memory, + /// The alias is to a global. + Global, + /// The alias is to a tag. + Tag, + /// The alias is to a core type. + Type, + /// The alias is to a module. Module, - Component, + /// The alias is to a module instance. Instance, - Value, - ExportKind(core::ExportKind), } -impl<'a> Parse<'a> for AliasKind { +impl<'a> Parse<'a> for CoreAliasKind { 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) - } else if l.peek::() { - parser.parse::()?; - Ok(AliasKind::Component) - } else if l.peek::() { - parser.parse::()?; - Ok(AliasKind::Instance) - } else if l.peek::() { - parser.parse::()?; - Ok(AliasKind::Value) + // Note: this intentionally does not parse + // type, module, or instance; those are only + // valid in `AliasKind` and they are parsed there + // instead. + if l.peek::() { + parser.parse::()?; + Ok(Self::Func) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Table) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Memory) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Global) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Tag) } else { Err(l.error()) } } } -/// aliastarget ::= export -/// | outer -#[derive(Debug, Clone)] -#[allow(missing_docs)] +/// An alias to a component item. +#[derive(Debug)] +pub struct Alias<'a> { + /// Where this `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 this alias. + pub target: AliasTarget<'a>, + /// The kind of item that's being aliased. + pub kind: AliasKind, +} + +impl<'a> Alias<'a> { + /// Parses only an outer alias. + pub fn parse_outer(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let target = AliasTarget::parse_outer(parser)?; + let (kind, id, name) = + parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?; + + Ok(Self { + span, + target, + id, + name, + kind, + }) + } +} + +impl<'a> Parse<'a> for Alias<'a> { + fn parse(parser: Parser<'a>) -> Result { + let span = parser.parse::()?.0; + let target = parser.parse()?; + let (kind, id, name) = + parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?; + + Ok(Self { + span, + target, + id, + name, + kind, + }) + } +} + +/// 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 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>, }, } -impl<'a> Parse<'a> for Alias<'a> { +impl<'a> AliasTarget<'a> { + /// Parses only an outer alias target. + pub fn parse_outer(parser: Parser<'a>) -> Result { + parser.parse::()?; + Ok(Self::Outer { + outer: parser.parse()?, + index: parser.parse()?, + }) + } +} + +impl<'a> Parse<'a> for AliasTarget<'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()?, - } + if parser.peek::() { + Self::parse_outer(parser) } 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(Self::Export { + instance: parser.parse()?, + name: parser.parse()?, + }) + } + } +} - Ok(Alias { - span, - id, - name, - kind, - target, - }) +/// Represents the kind of item being aliased. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum AliasKind { + /// The item is a core item. + Core(CoreAliasKind), + /// The item is a function. + Func, + /// The item is a value. + Value, + /// The item is a type. + Type, + /// The item is a component. + Component, + /// The item is a component instance. + Instance, +} + +impl<'a> Parse<'a> for AliasKind { + fn parse(parser: Parser<'a>) -> Result { + let mut l = parser.lookahead1(); + if l.peek::() { + parser.parse::()?; + if parser.peek::() { + parser.parse::()?; + Ok(Self::Core(CoreAliasKind::Module)) + } else if parser.peek::() { + parser.parse::()?; + Ok(Self::Core(CoreAliasKind::Instance)) + } else if parser.peek::() { + parser.parse::()?; + Ok(Self::Core(CoreAliasKind::Type)) + } else { + Ok(Self::Core(parser.parse()?)) + } + } 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(Self::Component) + } else if l.peek::() { + parser.parse::()?; + Ok(Self::Instance) + } else { + Err(l.error()) + } } } diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 590e4db734..0f8f12642c 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -1,632 +1,783 @@ 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, + InstanceSection, NestedComponentSection, RawSection, SectionId, TypeEncoder, TypeSection, +}; 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: TypeEncoder, 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: TypeSection, + + // 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| (e.name, (&e.item).into()))); } - 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 } => { + self.core_aliases + .instance_export((*instance).into(), alias.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| (arg.name, (&arg.kind).into())), + ); + } + InstanceKind::BundleOfExports(exports) => { + self.instances + .export_items(exports.iter().map(|e| (e.name, (&e.kind).into()))); + } + } + + 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 } => { + self.aliases + .instance_export((*instance).into(), alias.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); + self.aliases + .outer((*outer).into(), alias.kind.into(), (*index).into()); } } + + self.flush(Some(self.aliases.id())); } -} -impl Encode for CanonLower<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x01); - 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); + + self.component.section(&ComponentStartSection { + function_index: start.func.into(), + args: start.args.iter().map(|a| a.idx.into()).collect::>(), + }); } -} -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_type(&mut self, ty: &Type) { + encode_type(self.types.ty(), &ty.def); + self.flush(Some(self.types.id())); } -} -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); + 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), + ); + } + 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 ModuleType<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x4f); - self.defs.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 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); - } - ModuleTypeDef::Export(name, x) => { - e.push(0x07); - name.encode(e); - x.encode(e); + fn encode_export(&mut self, export: &ComponentExport) { + self.exports.export(export.name, (&export.kind).into()); + 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 ComponentType<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x4e); - self.fields.encode(e); + self.current_section_id = section_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); - } +// 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 InstanceType<'_> { - fn encode(&self, e: &mut Vec) { - e.push(0x4d); - self.fields.encode(e); +impl wasm_encoder::ComponentSection for Custom<'_> { + fn id(&self) -> u8 { + SectionId::Custom.into() } } -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); +// 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 ComponentExportType<'_> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - self.item.encode(e); - } -} -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), +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 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<&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 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> 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 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::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 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::GlobalType { + fn from(ty: core::GlobalType) -> Self { + Self { + val_type: ty.ty.into(), + mutable: ty.mutable, } } } -impl<'a> Encode for Record<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x71); - self.fields.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 Field<'a> { - fn encode(&self, e: &mut Vec) { - self.name.encode(e); - self.type_.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 Variant<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x70); - self.cases.encode(e); +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 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<&CoreItemRef<'_, core::ExportKind>> for wasm_encoder::Export { + fn from(item: &CoreItemRef<'_, core::ExportKind>) -> Self { + match &item.kind { + core::ExportKind::Func => wasm_encoder::Export::Func(item.idx.into()), + core::ExportKind::Table => wasm_encoder::Export::Table(item.idx.into()), + core::ExportKind::Memory => wasm_encoder::Export::Memory(item.idx.into()), + core::ExportKind::Global => wasm_encoder::Export::Global(item.idx.into()), + core::ExportKind::Tag => wasm_encoder::Export::Tag(item.idx.into()), } } } -impl<'a> Encode for List<'a> { - fn encode(&self, e: &mut Vec) { - e.push(0x6f); - self.element.encode(e); +impl From for wasm_encoder::CoreAliasKind { + fn from(kind: CoreAliasKind) -> Self { + match kind { + CoreAliasKind::Func => Self::Func, + CoreAliasKind::Table => Self::Table, + CoreAliasKind::Memory => Self::Memory, + CoreAliasKind::Global => Self::Global, + CoreAliasKind::Tag => Self::Tag, + CoreAliasKind::Type => Self::Type, + CoreAliasKind::Module => Self::Module, + CoreAliasKind::Instance => Self::Instance, + } } } -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: CoreAliasKind) -> Self { + match kind { + CoreAliasKind::Func => Self::Func, + CoreAliasKind::Table => Self::Table, + CoreAliasKind::Memory => Self::Memory, + CoreAliasKind::Global => Self::Global, + CoreAliasKind::Tag => Self::Tag, + // These forms should only be used from component aliases + CoreAliasKind::Type | CoreAliasKind::Module | CoreAliasKind::Instance => { + unreachable!("unparsable core alias kind") + } + } } } -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::Named(..) => unreachable!("should be expanded by now"), + Refinement::Index(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::Export { .. } => { + unreachable!("cannot encode export aliases for types") + } + AliasTarget::Outer { outer, index } => { + encoded.alias_outer_type(u32::from(*outer), u32::from(*index)); + } + }, + 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::Export { .. } => { + unreachable!("cannot encode export aliases for types") + } + AliasTarget::Outer { outer, index } => { + encoded.alias_outer_type(u32::from(*outer), u32::from(*index)); + } + }, + 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::ComponentExport { + 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::ComponentExport { + fn from(kind: &ComponentExportKind) -> Self { + match kind { + ComponentExportKind::CoreModule(m) => { + wasm_encoder::ComponentExport::Module(m.idx.into()) + } + ComponentExportKind::Func(f) => wasm_encoder::ComponentExport::Func(f.idx.into()), + ComponentExportKind::Value(v) => wasm_encoder::ComponentExport::Value(v.idx.into()), + ComponentExportKind::Type(t) => wasm_encoder::ComponentExport::Type(t.idx.into()), + ComponentExportKind::Component(c) => { + wasm_encoder::ComponentExport::Component(c.idx.into()) + } + ComponentExportKind::Instance(i) => { + wasm_encoder::ComponentExport::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::ComponentAliasKind { + fn from(kind: AliasKind) -> Self { + match kind { + AliasKind::Core(k) => Self::Core(k.into()), + AliasKind::Func => Self::Func, + AliasKind::Value => Self::Value, + AliasKind::Type => Self::Type, + AliasKind::Component => Self::Component, + AliasKind::Instance => Self::Instance, } } } -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: AliasKind) -> Self { + match kind { + AliasKind::Core(CoreAliasKind::Module) => Self::Module, + AliasKind::Core(_) => unreachable!("only modules may be aliased for instance exports"), + AliasKind::Func => Self::Func, + AliasKind::Value => Self::Value, + AliasKind::Type => Self::Type, + AliasKind::Component => Self::Component, + AliasKind::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..d434122b88 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: CoreAliasKind::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: AliasKind::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 = 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_names: Vec::new(), + }; + *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); - *ty = InterTypeRef::Ref(idx); + let ret = CoreItemRef { + idx, + kind: kw::r#type(span), + export_names: Vec::new(), + }; + + *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_names: Default::default(), }); } - 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..fee43e29a1 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_names: Vec::new(), + }, + 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..eca4d99d05 100644 --- a/crates/wast/src/component/item_ref.rs +++ b/crates/wast/src/component/item_ref.rs @@ -1,98 +1,115 @@ 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, + } +} + +fn parse<'a, K: Parse<'a>>(parser: Parser<'a>) -> Result<(K, Index<'a>, Vec<&'a str>)> { + // 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 mut names = Vec::new(); + while !parser.is_empty() { + names.push(parser.parse()?); + } + Ok((kind, idx, names)) +} + +/// 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>, + /// Export names to resolve the item from. pub export_names: Vec<&'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, - }) + let (kind, idx, export_names) = parse(parser)?; + Ok(Self { + kind, + idx, + export_names, }) } } -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, idx, export_names) = parse(parser)?; + 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..d4dc033de7 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,136 +148,142 @@ 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: _ } => { + self.resolve_ns(instance, Ns::CoreInstance) + } } } fn alias(&mut self, alias: &mut Alias<'a>) -> Result<(), Error> { match &mut alias.target { - AliasTarget::Export { - instance, - export: _, - } => self.resolve_ns(instance, Ns::Instance), + AliasTarget::Export { instance, name: _ } => self.resolve_ns(instance, Ns::Instance), AliasTarget::Outer { outer, index } => { // Short-circuit when both indices are already resolved as this // helps to write tests for invalid modules where wasmparser should @@ -282,139 +324,179 @@ 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(alias.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) => { + let names: Vec<_> = v.cases.iter().map(|c| c.name).collect(); + for case in v.cases.iter_mut() { - self.intertype_ref(&mut case.type_)?; + self.component_val_type(&mut case.ty)?; + if let Some(refines) = &mut case.refines { + if let Refinement::Named(span, name) = refines { + if *name == case.name { + return Err(Error::new( + *span, + "variant case cannot refine itself".to_string(), + )); + } + + let index = names.iter().position(|n| n == name).ok_or_else(|| { + Error::new(*span, format!("variant case `{}` not found", name)) + })?; + + *refines = Refinement::Index(index as u32); + } + } } } - 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 core_ty(&mut self, field: &mut CoreType<'a>) -> Result<(), Error> { + match &mut field.def { + CoreTypeDef::Def(_) => Ok(()), + CoreTypeDef::Module(t) => self.module_type(t), } } - fn type_field(&mut self, field: &mut TypeField<'a>) -> Result<(), Error> { + fn ty(&mut self, field: &mut Type<'a>) -> Result<(), Error> { match &mut field.def { - ComponentTypeDef::DefType(DefType::Func(f)) => { + 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 +505,111 @@ 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(); - - // 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. + // 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(); - self.resolve_ns(&mut index, Ns::Instance)?; + // This is a reference to a core instance export + let mut index = item.idx; + self.resolve_ns(&mut index, Ns::CoreInstance)?; + 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 alias to reference the export + let alias = CoreAlias { + span, + id: None, + name: None, + target: CoreAliasTarget::Export { + instance: index, + name: export_name, + }, + kind: if pos == item.export_names.len() - 1 { + item.kind.ns() + } else { + Ns::Instance + } + .into(), }; - // Record an outer alias to be inserted in front of the current - // definition. - let mut alias = Alias { + index = Index::Num(self.current().register_core_alias(None, alias.kind)?, span); + self.aliases_to_insert.push(AnyAlias::Core(alias)); + } + + item.idx = index; + item.export_names = Vec::new(); + + 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, item.kind.ns())?; + return Ok(()); + } + + // 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() { + // 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() + } else { + Ns::Instance + } + .into(), }; - 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 +621,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,14 +637,23 @@ 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 { + + if !ns.can_alias_outer() { + return Err(Error::new( + span, + "outer aliases can only be made to modules, components, and component types" + .to_string(), + )); + } + + let alias = Alias { span, id: Some(id), name: None, @@ -543,21 +661,10 @@ impl<'a> Resolver<'a> { 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 +675,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,40 +709,57 @@ 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.id, a.kind)?, + 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(()) @@ -643,84 +767,171 @@ impl<'a> ComponentState<'a> { fn register_alias(&mut self, alias: &Alias<'a>) -> Result { match alias.kind { - AliasKind::Module => self.modules.register(alias.id, "module"), + AliasKind::Core(k) => self.register_core_alias(alias.id, k), + AliasKind::Func => self.funcs.register(alias.id, "func"), + AliasKind::Value => self.values.register(alias.id, "value"), + AliasKind::Type => self.types.register(alias.id, "type"), 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") - } - AliasKind::ExportKind(core::ExportKind::Memory) => { - self.memories.register(alias.id, "memory") - } - AliasKind::ExportKind(core::ExportKind::Global) => { - self.globals.register(alias.id, "global") - } - AliasKind::ExportKind(core::ExportKind::Tag) => self.tags.register(alias.id, "tag"), - AliasKind::ExportKind(core::ExportKind::Type) => self.types.register(alias.id, "type"), + } + } + + fn register_core_alias( + &mut self, + id: Option>, + kind: CoreAliasKind, + ) -> Result { + match kind { + CoreAliasKind::Func => self.core_funcs.register(id, "core func"), + CoreAliasKind::Table => self.core_tables.register(id, "core table"), + CoreAliasKind::Memory => self.core_memories.register(id, "core memory"), + CoreAliasKind::Global => self.core_globals.register(id, "core global"), + CoreAliasKind::Tag => self.core_tags.register(id, "core tag"), + CoreAliasKind::Type => self.core_types.register(id, "core type"), + CoreAliasKind::Module => self.core_modules.register(id, "core module"), + CoreAliasKind::Instance => self.core_instances.register(id, "core instance"), } } } #[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 { +impl Ns { + fn can_alias_outer(&self) -> bool { + match self { + Ns::Type | Ns::CoreModule | Ns::Component => true, + _ => false, + } + } +} + +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 CoreAliasKind { + fn from(ns: Ns) -> Self { + match ns { + Ns::CoreFunc => CoreAliasKind::Func, + Ns::CoreGlobal => CoreAliasKind::Global, + Ns::CoreTable => CoreAliasKind::Table, + Ns::CoreMemory => CoreAliasKind::Memory, + Ns::CoreType => CoreAliasKind::Type, + Ns::CoreTag => CoreAliasKind::Tag, + Ns::CoreInstance => CoreAliasKind::Instance, + Ns::CoreModule => CoreAliasKind::Module, + _ => unreachable!("not a core 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 AliasKind { + fn from(ns: Ns) -> Self { + match ns { + Ns::CoreFunc + | Ns::CoreGlobal + | Ns::CoreTable + | Ns::CoreMemory + | Ns::CoreType + | Ns::CoreTag + | Ns::CoreInstance + | Ns::CoreModule => Self::Core(ns.into()), + Ns::Func => Self::Func, + Ns::Type => Self::Type, + Ns::Instance => Self::Instance, + Ns::Component => Self::Component, + Ns::Value => Self::Value, + } + } } -impl From for Ns { - fn from(kind: DefTypeKind) -> Self { +impl From for Ns { + fn from(kind: CoreAliasKind) -> Self { match kind { - DefTypeKind::Module => Ns::Module, - DefTypeKind::Component => Ns::Component, - DefTypeKind::Instance => Ns::Instance, - DefTypeKind::Value => Ns::Value, - DefTypeKind::Func => Ns::Func, + CoreAliasKind::Func => Ns::CoreFunc, + CoreAliasKind::Table => Ns::CoreTable, + CoreAliasKind::Memory => Ns::CoreMemory, + CoreAliasKind::Global => Ns::CoreGlobal, + CoreAliasKind::Tag => Ns::CoreTag, + CoreAliasKind::Type => Ns::CoreType, + CoreAliasKind::Module => Ns::CoreModule, + CoreAliasKind::Instance => Ns::CoreInstance, } } } -impl From for Ns { - fn from(kind: core::ExportKind) -> Self { +impl From for Ns { + fn from(kind: AliasKind) -> 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, + AliasKind::Core(kind) => kind.into(), + AliasKind::Func => Ns::Func, + AliasKind::Value => Ns::Value, + AliasKind::Type => Ns::Type, + AliasKind::Instance => Ns::Instance, + AliasKind::Component => Ns::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..e897870c0c 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -1,73 +1,802 @@ 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())?) - } else { - ComponentTypeDef::InterType(parser.parse()?) - }; - Ok(TypeField { + 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> { + /// The name of the case. + pub name: &'a str, + /// Where this `case` was defined + pub span: Span, + /// 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 name = parser.parse()?; + let ty = parser.parse()?; + let refines = if !parser.is_empty() { + Some(parser.parse()?) + } else { + None + }; + Ok(Self { + name, + span, + ty, + refines, + }) + } +} + +/// A refinement for a variant case. +#[derive(Debug)] +pub enum Refinement<'a> { + /// The refinement is named. + Named(Span, &'a str), + /// The refinement has been resolved to an index into + /// the cases of the variant. + Index(u32), +} + +impl<'a> Parse<'a> for Refinement<'a> { + fn parse(parser: Parser<'a>) -> Result { + parser.parens(|parser| { + let span = parser.parse::()?.0; + let name = parser.parse()?; + Ok(Self::Named(span, name)) + }) + } +} + +/// 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(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(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_names: Vec::new(), + }) + } +} + /// A reference to a type defined in this component. /// /// This is the same as `TypeUse`, but accepts `$T` as shorthand for @@ -82,10 +811,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)?; From 29a4687fc71e897aaaf446c56598dfc225bb7e73 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Fri, 3 Jun 2022 13:43:55 -0700 Subject: [PATCH 20/33] Update wat tests. This commit updates the component model wat tests to the current text format. It also removes FIXMEs where appropriate and attempts to convert the remaining "fixme" holdover test files from the module linking proposal. --- tests/dump/alias.wat | 19 ++ tests/dump/alias.wat.dump | 88 +++-- tests/dump/alias.wat.fixme | 10 - tests/dump/alias2.wat | 82 +++++ tests/dump/alias2.wat.dump | 241 ++++++++++---- tests/dump/alias2.wat.fixme | 28 -- tests/dump/bundled.wat | 49 +++ tests/dump/bundled.wat.dump | 309 ++++++++++-------- tests/dump/bundled.wat.fixme | 32 -- tests/dump/component-expand-bundle.wat | 10 +- tests/dump/component-expand-bundle.wat.dump | 24 +- tests/dump/component-expand-bundle2.wat | 12 +- tests/dump/component-expand-bundle2.wat.dump | 50 +-- tests/dump/component-inline-export-import.wat | 2 +- .../component-inline-export-import.wat.dump | 30 +- tests/dump/component-inline-type.wat | 2 +- tests/dump/component-inline-type.wat.dump | 44 +-- tests/dump/component-instance-type.wat.dump | 19 +- tests/dump/component-linking.wat | 25 ++ tests/dump/component-linking.wat.dump | 67 ++++ tests/dump/component-outer-alias.wat | 12 +- tests/dump/component-outer-alias.wat.dump | 68 ++-- tests/dump/import-modules.wat | 10 + tests/dump/import-modules.wat.dump | 63 ++-- tests/dump/import-modules.wat.fixme | 9 - ...e-expand.wat.fixme => instance-expand.wat} | 2 +- tests/dump/instance-expand.wat.dump | 27 +- ...tance-type.wat.fixme => instance-type.wat} | 2 +- tests/dump/instance-type.wat.dump | 20 +- ...nce-type2.wat.fixme => instance-type2.wat} | 2 +- tests/dump/instance-type2.wat.dump | 27 +- tests/dump/instantiate.wat | 11 + tests/dump/instantiate.wat.dump | 86 +---- tests/dump/instantiate.wat.fixme | 21 -- tests/dump/instantiate2.wat | 4 + tests/dump/instantiate2.wat.dump | 28 +- tests/dump/instantiate2.wat.fixme | 4 - tests/dump/module-linking.wat.dump | 72 ---- tests/dump/module-linking.wat.fixme | 28 -- tests/dump/module-types.wat | 9 + tests/dump/module-types.wat.dump | 47 ++- tests/dump/module-types.wat.fixme | 11 - tests/dump/nested-component.wat | 23 ++ tests/dump/nested-component.wat.dump | 59 ++++ tests/dump/nested-module.wat.dump | 64 ---- tests/dump/nested-module.wat.fixme | 23 -- tests/local/component-model/a.wast | 2 +- tests/local/component-model/adapt.wast | 253 ++++++++------ tests/local/component-model/alias.wast | 112 +++---- tests/local/component-model/big.wast | 40 +-- .../{intertypes.wast => definedtypes.wast} | 34 +- tests/local/component-model/example.wast | 8 +- tests/local/component-model/export.wast | 13 +- tests/local/component-model/import.wast | 51 +-- .../component-model/imports-exports.wast | 7 +- .../local/component-model/instance-type.wast | 57 ++-- tests/local/component-model/instantiate.wast | 293 ++++++++--------- tests/local/component-model/invalid.wast | 4 +- tests/local/component-model/link.wast | 8 +- tests/local/component-model/memory64.wast | 16 +- tests/local/component-model/module-link.wast | 95 +++--- .../local/component-model/nested-modules.wast | 30 +- tests/local/component-model/start.wast | 8 - tests/local/component-model/string.wast | 21 +- tests/local/component-model/types.wast | 47 ++- tests/local/component-model/very-nested.wast | 142 ++++---- tests/local/component-model/virtualize.wast | 216 ++++++------ tests/roundtrip.rs | 2 +- 68 files changed, 1771 insertions(+), 1563 deletions(-) create mode 100644 tests/dump/alias.wat delete mode 100644 tests/dump/alias.wat.fixme create mode 100644 tests/dump/alias2.wat delete mode 100644 tests/dump/alias2.wat.fixme create mode 100644 tests/dump/bundled.wat delete mode 100644 tests/dump/bundled.wat.fixme create mode 100644 tests/dump/component-linking.wat create mode 100644 tests/dump/component-linking.wat.dump create mode 100644 tests/dump/import-modules.wat delete mode 100644 tests/dump/import-modules.wat.fixme rename tests/dump/{instance-expand.wat.fixme => instance-expand.wat} (88%) rename tests/dump/{instance-type.wat.fixme => instance-type.wat} (89%) rename tests/dump/{instance-type2.wat.fixme => instance-type2.wat} (93%) create mode 100644 tests/dump/instantiate.wat delete mode 100644 tests/dump/instantiate.wat.fixme create mode 100644 tests/dump/instantiate2.wat delete mode 100644 tests/dump/instantiate2.wat.fixme delete mode 100644 tests/dump/module-linking.wat.dump delete mode 100644 tests/dump/module-linking.wat.fixme create mode 100644 tests/dump/module-types.wat delete mode 100644 tests/dump/module-types.wat.fixme create mode 100644 tests/dump/nested-component.wat create mode 100644 tests/dump/nested-component.wat.dump delete mode 100644 tests/dump/nested-module.wat.dump delete mode 100644 tests/dump/nested-module.wat.fixme rename tests/local/component-model/{intertypes.wast => definedtypes.wast} (80%) 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..88e1f1ed72 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 | type section + 0x46 | 01 | 1 count + 0x47 | 50 00 | [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..e852876694 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 | type section + 0x15 | 01 | 1 count + 0x16 | 50 00 | [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..f86e008569 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 | type section + 0x15 | 01 | 1 count + 0x16 | 50 00 | [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..c94bd1462d --- /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 | type section + 0x46 | 01 | 1 count + 0x47 | 50 00 | [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..b66875b082 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 | type section + 0xa | 01 | 1 count + 0xb | 50 02 01 60 | [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..f4e0964181 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 | type section + 0xa | 01 | 1 count + 0xb | 50 05 01 60 | [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..4d01302237 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")) @@ -118,14 +109,14 @@ (alias outer $outer $i (instance)) ) - (instance (instantiate (component $m) (with "" (component $local)))) + (instance (instantiate $m (with "" (component $local)))) ) - "invalid leading byte (0xff) for outer alias") + "outer aliases may only be made to types, modules, and components") (assert_invalid (component (import "" (instance (export "" (func)))) - (export "" (module 0 "")) + (export "" (core module 0 "")) ) "export `` for instance 0 is not a module") @@ -134,44 +125,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 +196,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 +207,6 @@ ) ;; multiple projections in alias sugar -;; FIXME(#588) should be valid -(assert_invalid (component $a (import "" (instance $a (export "b" (instance @@ -233,11 +220,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 +237,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 +254,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 80% rename from tests/local/component-model/intertypes.wast rename to tests/local/component-model/definedtypes.wast index 82de5f98a7..16d4c4ece4 100644 --- a/tests/local/component-model/intertypes.wast +++ b/tests/local/component-model/definedtypes.wast @@ -22,9 +22,7 @@ (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 $A15d (variant (case "x" unit (refines "y")) (case "y" string))) (type $A16a (list unit)) (type $A16b (list $A3)) @@ -54,31 +52,39 @@ (assert_invalid (component - (type $t (module)) - (type (func (param $t))) + (type $t (variant (case "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 string) + (type $v (variant (case "x" $t (refines "z")))) + ) + "variant case `z` not found" +) + +(assert_invalid + (component + (type $t (func)) + (type (func (param $t))) ) - "not an interface type") + "type index 0 is not a defined type") (assert_invalid (component - (type $t (module)) - (type (value $t)) + (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..cf3dcaace2 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") ;) + "outer aliases can only be made to modules, components, and component types") -(; (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..cd554b018a 100644 --- a/tests/local/component-model/invalid.wast +++ b/tests/local/component-model/invalid.wast @@ -1,6 +1,6 @@ (assert_invalid (component - (type (module + (core type (module (import "" "" (func (type 1))) )) (type (func)) @@ -14,7 +14,7 @@ (alias outer 1 $f (func $f)) ) ) - "invalid leading byte") + "outer aliases may only be made to types, modules, and components") (assert_malformed (component quote 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..c901940a00 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") ;) + "outer aliases can only be made to modules, components, and component types") -(; (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..72798b6619 100644 --- a/tests/local/component-model/virtualize.wast +++ b/tests/local/component-model/virtualize.wast @@ -1,110 +1,134 @@ -;; 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) - ) - (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 +(component + ;; TODO: ideally share this same core libc instance between all subcomponents + ;; this isn't currently possible with the component model proposal + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable ) ) - - (instance $libc (instantiate (module $libc))) - (func $wasi_file_read - (canon.lower (into $libc) (func $wasi-file "read")) - ) - (instance $i (instantiate (module $m) - (with "libc" (instance $libc)) - (with "wasi-file" (instance - (export "read" (func $wasi_file_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))) )) - )) - (func (export "play") - (canon.lift (func) (func $i "play")) - ) -) -"instance 0 is not a module instance") + ;; TODO: see comment above + (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 $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")) + ) + ) -(; (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")) ;) -(; ) ;) + (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")) + ) -(; ;; 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)))) ;) + (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)))) -(; (func (export "work") ;) -(; call (func $child "play") ;) -(; ) ;) -(; ) ;) + (export "work" (func $child "play")) + ) + (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))) -(; ;; 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))) ;) + ;; TODO: see comment above + (core module $libc + (memory (export "mem") 0) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable + ) + ) + + (core instance $libc (instantiate $libc)) -(; (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 ;) -(; ) ;) -(; ) ;) + (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 + ) + ) -(; (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 ;) -(; ) ;) -(; ) ;) + (core func $real-wasi-read + (canon lower (func $real-wasi "read") + (memory (core memory $libc "mem")) + (realloc (core func $libc "realloc")) + ) + ) -(; (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") ;) -(; ) ;) -(; ) ;) + (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/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"); From e6025b80e3fdd2c4604a484e3009014ab9649887 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Sun, 5 Jun 2022 18:21:52 -0700 Subject: [PATCH 21/33] Fix doc comment relating to `post-return` option. Update doc comments relating to the `post-return` option to match the spec. --- crates/wasm-encoder/src/component/canonicals.rs | 4 +--- crates/wasmparser/src/readers/component/canonicals.rs | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/crates/wasm-encoder/src/component/canonicals.rs b/crates/wasm-encoder/src/component/canonicals.rs index 374defa16c..e81819c44e 100644 --- a/crates/wasm-encoder/src/component/canonicals.rs +++ b/crates/wasm-encoder/src/component/canonicals.rs @@ -18,10 +18,8 @@ pub enum CanonicalOption { /// /// 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 or lowering of a function requires + /// The post-return function to use if the lifting of a function requires /// cleanup after the function returns. - /// - /// The value is an index to a core function of type `(func)`. PostReturn(u32), } diff --git a/crates/wasmparser/src/readers/component/canonicals.rs b/crates/wasmparser/src/readers/component/canonicals.rs index 2864a428ca..321e63fad0 100644 --- a/crates/wasmparser/src/readers/component/canonicals.rs +++ b/crates/wasmparser/src/readers/component/canonicals.rs @@ -19,10 +19,8 @@ pub enum CanonicalOption { /// /// 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 or lowering of a function requires + /// The post-return function to use if the lifting of a function requires /// cleanup after the function returns. - /// - /// The value is an index to a core function of type `(func)`. PostReturn(u32), } From e0f491281460b18f2f79e3621e68073b95cf8ea4 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 6 Jun 2022 16:54:21 -0700 Subject: [PATCH 22/33] wasm-encoder: move component-related core sections. This commit moves the component-related "core" sections out of the core module and into the component module in `wasm-encoder`. Originally these were put in the core module in anticipation of one day having the sections be part of core, but that's a long way off and may not occur. Until that time, it makes more sense to keep these sections grouped with the other component sections. This also replaces `ComponentAliasKind` with `ComponentOuterAliasKind`, which should only allow types, modules, and components to be aliased according to the current spec. Updated `wast` based on these API changes (the other crates will have similar changes soon). --- crates/wasm-encoder/src/component.rs | 19 +-- crates/wasm-encoder/src/component/aliases.rs | 129 +++++++++++------- crates/wasm-encoder/src/component/exports.rs | 66 ++------- .../wasm-encoder/src/component/instances.rs | 128 +++++++++++++++-- crates/wasm-encoder/src/component/types.rs | 8 +- crates/wasm-encoder/src/core.rs | 7 - crates/wasm-encoder/src/core/aliases.rs | 60 -------- crates/wasm-encoder/src/core/instances.rs | 99 -------------- crates/wasm-encoder/src/core/types.rs | 2 + crates/wast/src/component/binary.rs | 56 ++++---- tests/local/component-model/alias.wast | 16 --- tests/local/component-model/invalid.wast | 9 -- 12 files changed, 240 insertions(+), 359 deletions(-) delete mode 100644 crates/wasm-encoder/src/core/aliases.rs delete mode 100644 crates/wasm-encoder/src/core/instances.rs diff --git a/crates/wasm-encoder/src/component.rs b/crates/wasm-encoder/src/component.rs index d2d0647f01..87520da391 100644 --- a/crates/wasm-encoder/src/component.rs +++ b/crates/wasm-encoder/src/component.rs @@ -19,7 +19,12 @@ pub use self::start::*; pub use self::types::*; use crate::TypeSection; -use crate::{AliasSection, CustomSection, Encode, InstanceSection}; +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; @@ -132,18 +137,6 @@ impl ComponentSection for CustomSection<'_> { } } -impl ComponentSection for InstanceSection { - fn id(&self) -> u8 { - ComponentSectionId::CoreInstance.into() - } -} - -impl ComponentSection for AliasSection { - fn id(&self) -> u8 { - ComponentSectionId::CoreAlias.into() - } -} - impl ComponentSection for TypeSection { fn id(&self) -> u8 { ComponentSectionId::CoreType.into() diff --git a/crates/wasm-encoder/src/component/aliases.rs b/crates/wasm-encoder/src/component/aliases.rs index fa1f6a1060..9a681d668e 100644 --- a/crates/wasm-encoder/src/component/aliases.rs +++ b/crates/wasm-encoder/src/component/aliases.rs @@ -1,76 +1,99 @@ +use super::{COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, CORE_TYPE_SORT, TYPE_SORT}; use crate::{ - encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, - CORE_FUNCTION_SORT, CORE_GLOBAL_SORT, CORE_INSTANCE_SORT, CORE_MEMORY_SORT, CORE_MODULE_SORT, - CORE_TABLE_SORT, CORE_TAG_SORT, CORE_TYPE_SORT, + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, }; -use super::{COMPONENT_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT}; +/// An encoder for the core alias section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, AliasSection, ExportKind}; +/// +/// let mut aliases = AliasSection::new(); +/// aliases.instance_export(0, ExportKind::Func, "f"); +/// +/// let mut component = Component::new(); +/// component.section(&aliases); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct AliasSection { + bytes: Vec, + num_added: u32, +} -/// Represents the kinds of aliasable core items. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum CoreAliasKind { - /// 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, - /// The alias is to a core type. - Type, - /// The alias is to a core module. - Module, - /// The alias is to a core instance. - Instance, +impl AliasSection { + /// Create a new core 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: ExportKind, + name: &str, + ) -> &mut Self { + kind.encode(&mut self.bytes); + self.bytes.push(0x00); + instance_index.encode(&mut self.bytes); + name.encode(&mut self.bytes); + self.num_added += 1; + self + } } -impl Encode for CoreAliasKind { +impl Encode for AliasSection { fn encode(&self, sink: &mut Vec) { - match self { - Self::Func => sink.push(CORE_FUNCTION_SORT), - Self::Table => sink.push(CORE_TABLE_SORT), - Self::Memory => sink.push(CORE_MEMORY_SORT), - Self::Global => sink.push(CORE_GLOBAL_SORT), - Self::Tag => sink.push(CORE_TAG_SORT), - Self::Type => sink.push(CORE_TYPE_SORT), - Self::Module => sink.push(CORE_MODULE_SORT), - Self::Instance => sink.push(CORE_INSTANCE_SORT), - } + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl ComponentSection for AliasSection { + fn id(&self) -> u8 { + ComponentSectionId::CoreAlias.into() } } -/// Represents the kinds of aliasable component items. +/// Represents the kinds of outer aliasable items in a component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum ComponentAliasKind { - /// The alias is to a core item. - Core(CoreAliasKind), - /// The alias is to a function. - Func, - /// The alias is to a value. - Value, +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, - /// The alias is to an instance. - Instance, } -impl Encode for ComponentAliasKind { +impl Encode for ComponentOuterAliasKind { fn encode(&self, sink: &mut Vec) { match self { - Self::Core(kind) => { + Self::CoreModule => { + sink.push(CORE_SORT); + sink.push(CORE_MODULE_SORT); + } + Self::CoreType => { sink.push(CORE_SORT); - kind.encode(sink); + sink.push(CORE_TYPE_SORT); } - Self::Func => sink.push(FUNCTION_SORT), - Self::Value => sink.push(VALUE_SORT), Self::Type => sink.push(TYPE_SORT), Self::Component => sink.push(COMPONENT_SORT), - Self::Instance => sink.push(INSTANCE_SORT), } } } @@ -80,11 +103,11 @@ impl Encode for ComponentAliasKind { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, ComponentAliasSection, ComponentExportKind, ComponentAliasKind}; +/// use wasm_encoder::{Component, ComponentAliasSection, ComponentExportKind, ComponentOuterAliasKind}; /// /// let mut aliases = ComponentAliasSection::new(); /// aliases.instance_export(0, ComponentExportKind::Func, "f"); -/// aliases.outer(0, ComponentAliasKind::Instance, 1); +/// aliases.outer(0, ComponentOuterAliasKind::Type, 1); /// /// let mut component = Component::new(); /// component.section(&aliases); @@ -132,7 +155,7 @@ impl ComponentAliasSection { /// /// 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: ComponentAliasKind, index: u32) -> &mut Self { + 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); diff --git a/crates/wasm-encoder/src/component/exports.rs b/crates/wasm-encoder/src/component/exports.rs index cd6670a350..eefd3ca0ec 100644 --- a/crates/wasm-encoder/src/component/exports.rs +++ b/crates/wasm-encoder/src/component/exports.rs @@ -1,5 +1,8 @@ -use super::{COMPONENT_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT, VALUE_SORT}; -use crate::{encode_section, ComponentSection, ComponentSectionId, Encode, CORE_MODULE_SORT}; +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 the kind of an export from a WebAssembly component. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -44,66 +47,16 @@ impl Encode for ComponentExportKind { } } -/// Represents an export from a WebAssembly component. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum ComponentExport { - /// The export is a core module. - Module(u32), - /// The export is a function. - Func(u32), - /// The export is a value. - Value(u32), - /// The export is a type. - Type(u32), - /// The export is an instance. - Instance(u32), - /// The export is a component. - Component(u32), -} - -impl ComponentExport { - /// Gets the kind of the export. - 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, - } - } - - /// Gets the index of the export. - fn index(&self) -> u32 { - match self { - Self::Module(idx) - | Self::Func(idx) - | Self::Value(idx) - | Self::Type(idx) - | Self::Instance(idx) - | Self::Component(idx) => *idx, - } - } -} - -impl Encode for ComponentExport { - fn encode(&self, sink: &mut Vec) { - self.kind().encode(sink); - self.index().encode(sink); - } -} - /// 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 a function named "foo" /// let mut exports = ComponentExportSection::new(); -/// exports.export("foo", ComponentExport::Func(0)); +/// exports.export("foo", ComponentExportKind::Func, 0); /// /// let mut component = Component::new(); /// component.section(&exports); @@ -133,9 +86,10 @@ impl ComponentExportSection { } /// Define an export in the export section. - pub fn export(&mut self, name: &str, export: ComponentExport) -> &mut Self { + pub fn export(&mut self, name: &str, kind: ComponentExportKind, 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 } diff --git a/crates/wasm-encoder/src/component/instances.rs b/crates/wasm-encoder/src/component/instances.rs index 6a50e178f4..34f7d94998 100644 --- a/crates/wasm-encoder/src/component/instances.rs +++ b/crates/wasm-encoder/src/component/instances.rs @@ -1,15 +1,121 @@ -use crate::{encode_section, ComponentExport, ComponentSection, ComponentSectionId, Encode}; +use super::CORE_INSTANCE_SORT; +use crate::{ + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, Export, +}; + +/// Represents an argument to a module instantiation. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ModuleArg { + /// The argument is an instance. + Instance(u32), +} + +impl Encode for ModuleArg { + fn encode(&self, sink: &mut Vec) { + let (sort, idx) = match self { + Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx), + }; + sink.push(sort); + idx.encode(sink); + } +} + +/// An encoder for the core instance section of WebAssembly components. +/// +/// # Example +/// +/// ```rust +/// use wasm_encoder::{Component, InstanceSection, Export, ModuleArg}; +/// +/// let mut instances = InstanceSection::new(); +/// instances.export_items([("foo", Export::Func(0))]); +/// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]); +/// +/// let mut component = Component::new(); +/// component.section(&instances); +/// +/// let bytes = component.finish(); +/// ``` +#[derive(Clone, Debug, Default)] +pub struct InstanceSection { + bytes: Vec, + num_added: u32, +} + +impl InstanceSection { + /// Create a new core 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 core module. + pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self + where + A: IntoIterator, + A::IntoIter: ExactSizeIterator, + { + let args = args.into_iter(); + 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.encode(&mut self.bytes); + } + self.num_added += 1; + self + } + + /// Define an instance by exporting core WebAssembly items. + pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self + where + 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 { + name.encode(&mut self.bytes); + export.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, ComponentExport}; +/// use wasm_encoder::{Component, ComponentInstanceSection, ComponentExportKind}; /// /// let mut instances = ComponentInstanceSection::new(); -/// instances.export_items([("foo", ComponentExport::Func(0))]); -/// instances.instantiate(1, [("foo", ComponentExport::Instance(0))]); +/// instances.export_items([("foo", ComponentExportKind::Func, 0)]); +/// instances.instantiate(1, [("foo", ComponentExportKind::Instance, 0)]); /// /// let mut component = Component::new(); /// component.section(&instances); @@ -41,16 +147,17 @@ impl ComponentInstanceSection { /// Define an instance by instantiating a component. pub fn instantiate<'a, A>(&mut self, component_index: u32, args: A) -> &mut Self where - A: IntoIterator, + A: IntoIterator, A::IntoIter: ExactSizeIterator, { let args = args.into_iter(); self.bytes.push(0x00); component_index.encode(&mut self.bytes); args.len().encode(&mut self.bytes); - for (name, export) in args { + for (name, kind, index) in args { 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 @@ -59,15 +166,16 @@ impl ComponentInstanceSection { /// Define an instance by exporting items. pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self where - E: IntoIterator, + 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.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); } self.num_added += 1; self diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index a57ac36b13..4744a482e6 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -1,6 +1,6 @@ use crate::{ - encode_section, ComponentAliasKind, ComponentSection, ComponentSectionId, ComponentTypeRef, - Encode, TypeEncoder, + encode_section, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, + ComponentTypeRef, Encode, TypeEncoder, }; /// Represents a component type. @@ -43,7 +43,7 @@ impl ComponentType { /// Defines an alias in this component type. pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { self.bytes.push(0x02); - ComponentAliasKind::Type.encode(&mut self.bytes); + ComponentOuterAliasKind::Type.encode(&mut self.bytes); self.bytes.push(0x01); count.encode(&mut self.bytes); index.encode(&mut self.bytes); @@ -129,7 +129,7 @@ impl InstanceType { /// Defines an alias in this instance type. pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { self.bytes.push(0x02); - ComponentAliasKind::Type.encode(&mut self.bytes); + ComponentOuterAliasKind::Type.encode(&mut self.bytes); self.bytes.push(0x01); count.encode(&mut self.bytes); index.encode(&mut self.bytes); diff --git a/crates/wasm-encoder/src/core.rs b/crates/wasm-encoder/src/core.rs index ceba1d18b0..e03bd9363e 100644 --- a/crates/wasm-encoder/src/core.rs +++ b/crates/wasm-encoder/src/core.rs @@ -1,4 +1,3 @@ -mod aliases; mod code; mod custom; mod data; @@ -7,7 +6,6 @@ mod exports; mod functions; mod globals; mod imports; -mod instances; mod linking; mod memories; mod names; @@ -16,7 +14,6 @@ mod tables; mod tags; mod types; -pub use aliases::*; pub use code::*; pub use custom::*; pub use data::*; @@ -25,7 +22,6 @@ pub use exports::*; pub use functions::*; pub use globals::*; pub use imports::*; -pub use instances::*; pub use linking::*; pub use memories::*; pub use names::*; @@ -41,9 +37,6 @@ 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; -pub(crate) const CORE_TYPE_SORT: u8 = 0x10; -pub(crate) const CORE_MODULE_SORT: u8 = 0x11; -pub(crate) const CORE_INSTANCE_SORT: u8 = 0x12; /// A WebAssembly module section. /// diff --git a/crates/wasm-encoder/src/core/aliases.rs b/crates/wasm-encoder/src/core/aliases.rs deleted file mode 100644 index 4b5801e215..0000000000 --- a/crates/wasm-encoder/src/core/aliases.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::{encode_section, Encode, ExportKind}; - -/// An encoder for the core alias section of WebAssembly components. -/// -/// # Example -/// -/// ```rust -/// use wasm_encoder::{Component, AliasSection, ExportKind}; -/// -/// let mut aliases = AliasSection::new(); -/// aliases.instance_export(0, ExportKind::Func, "f"); -/// -/// let mut component = Component::new(); -/// component.section(&aliases); -/// -/// let bytes = component.finish(); -/// ``` -#[derive(Clone, Debug, Default)] -pub struct AliasSection { - bytes: Vec, - num_added: u32, -} - -impl AliasSection { - /// Create a new core 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: ExportKind, - name: &str, - ) -> &mut Self { - kind.encode(&mut self.bytes); - self.bytes.push(0x00); - instance_index.encode(&mut self.bytes); - name.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); - } -} diff --git a/crates/wasm-encoder/src/core/instances.rs b/crates/wasm-encoder/src/core/instances.rs deleted file mode 100644 index 6c82e074fd..0000000000 --- a/crates/wasm-encoder/src/core/instances.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::CORE_INSTANCE_SORT; -use crate::{encode_section, Encode, Export}; - -/// Represents an argument to a module instantiation. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum ModuleArg { - /// The argument is an instance. - Instance(u32), -} - -impl Encode for ModuleArg { - fn encode(&self, sink: &mut Vec) { - let (sort, idx) = match self { - Self::Instance(idx) => (CORE_INSTANCE_SORT, *idx), - }; - sink.push(sort); - idx.encode(sink); - } -} - -/// An encoder for the core instance section of WebAssembly components. -/// -/// # Example -/// -/// ```rust -/// use wasm_encoder::{Component, InstanceSection, Export, ModuleArg}; -/// -/// let mut instances = InstanceSection::new(); -/// instances.export_items([("foo", Export::Func(0))]); -/// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]); -/// -/// let mut component = Component::new(); -/// component.section(&instances); -/// -/// let bytes = component.finish(); -/// ``` -#[derive(Clone, Debug, Default)] -pub struct InstanceSection { - bytes: Vec, - num_added: u32, -} - -impl InstanceSection { - /// Create a new core 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 core module. - pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self - where - A: IntoIterator, - A::IntoIter: ExactSizeIterator, - { - let args = args.into_iter(); - 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.encode(&mut self.bytes); - } - self.num_added += 1; - self - } - - /// Define an instance by exporting core WebAssembly items. - pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self - where - 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 { - name.encode(&mut self.bytes); - export.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); - } -} diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs index 9a03cc85ce..6a216def65 100644 --- a/crates/wasm-encoder/src/core/types.rs +++ b/crates/wasm-encoder/src/core/types.rs @@ -122,6 +122,8 @@ impl<'a> TypeEncoder<'a> { } /// Define a module type. + /// + /// Currently this is only used for core type sections in components. pub fn module(self, ty: &ModuleType) { ty.encode(self.0); } diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 0f8f12642c..d6864d590a 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -224,12 +224,17 @@ impl Encoder { InstanceKind::Instantiate { component, args } => { self.instances.instantiate( (*component).into(), - args.iter().map(|arg| (arg.name, (&arg.kind).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| (e.name, (&e.kind).into()))); + self.instances.export_items(exports.iter().map(|e| { + let (kind, index) = (&e.kind).into(); + (e.name, kind, index) + })); } } @@ -290,7 +295,8 @@ impl Encoder { } fn encode_export(&mut self, export: &ComponentExport) { - self.exports.export(export.name, (&export.kind).into()); + let (kind, index) = (&export.kind).into(); + self.exports.export(export.name, kind, index); self.flush(Some(self.exports.id())); } @@ -510,21 +516,6 @@ impl From<&CoreItemRef<'_, core::ExportKind>> for wasm_encoder::Export { } } -impl From for wasm_encoder::CoreAliasKind { - fn from(kind: CoreAliasKind) -> Self { - match kind { - CoreAliasKind::Func => Self::Func, - CoreAliasKind::Table => Self::Table, - CoreAliasKind::Memory => Self::Memory, - CoreAliasKind::Global => Self::Global, - CoreAliasKind::Tag => Self::Tag, - CoreAliasKind::Type => Self::Type, - CoreAliasKind::Module => Self::Module, - CoreAliasKind::Instance => Self::Instance, - } - } -} - impl From for wasm_encoder::ExportKind { fn from(kind: CoreAliasKind) -> Self { match kind { @@ -714,7 +705,7 @@ impl From<&ModuleType<'_>> for wasm_encoder::ModuleType { } } -impl From<&InstantiationArgKind<'_>> for wasm_encoder::ComponentExport { +impl From<&InstantiationArgKind<'_>> for (wasm_encoder::ComponentExportKind, u32) { fn from(kind: &InstantiationArgKind) -> Self { match kind { InstantiationArgKind::Item(i) => i.into(), @@ -723,34 +714,35 @@ impl From<&InstantiationArgKind<'_>> for wasm_encoder::ComponentExport { } } -impl From<&ComponentExportKind<'_>> for wasm_encoder::ComponentExport { +impl From<&ComponentExportKind<'_>> for (wasm_encoder::ComponentExportKind, u32) { fn from(kind: &ComponentExportKind) -> Self { match kind { ComponentExportKind::CoreModule(m) => { - wasm_encoder::ComponentExport::Module(m.idx.into()) + (wasm_encoder::ComponentExportKind::Module, m.idx.into()) } - ComponentExportKind::Func(f) => wasm_encoder::ComponentExport::Func(f.idx.into()), - ComponentExportKind::Value(v) => wasm_encoder::ComponentExport::Value(v.idx.into()), - ComponentExportKind::Type(t) => wasm_encoder::ComponentExport::Type(t.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::ComponentExport::Component(c.idx.into()) + (wasm_encoder::ComponentExportKind::Component, c.idx.into()) } ComponentExportKind::Instance(i) => { - wasm_encoder::ComponentExport::Instance(i.idx.into()) + (wasm_encoder::ComponentExportKind::Instance, i.idx.into()) } } } } -impl From for wasm_encoder::ComponentAliasKind { +impl From for wasm_encoder::ComponentOuterAliasKind { fn from(kind: AliasKind) -> Self { match kind { - AliasKind::Core(k) => Self::Core(k.into()), - AliasKind::Func => Self::Func, - AliasKind::Value => Self::Value, + AliasKind::Core(CoreAliasKind::Module) => Self::CoreModule, + AliasKind::Core(CoreAliasKind::Type) => Self::CoreType, AliasKind::Type => Self::Type, AliasKind::Component => Self::Component, - AliasKind::Instance => Self::Instance, + _ => unreachable!("not representable as an outer alias ({:?})", kind), } } } diff --git a/tests/local/component-model/alias.wast b/tests/local/component-model/alias.wast index 4d01302237..99ae4e6e38 100644 --- a/tests/local/component-model/alias.wast +++ b/tests/local/component-model/alias.wast @@ -97,22 +97,6 @@ )))) ) -(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 $m (with "" (component $local)))) - ) - "outer aliases may only be made to types, modules, and components") - (assert_invalid (component (import "" (instance (export "" (func)))) diff --git a/tests/local/component-model/invalid.wast b/tests/local/component-model/invalid.wast index cd554b018a..471a61085f 100644 --- a/tests/local/component-model/invalid.wast +++ b/tests/local/component-model/invalid.wast @@ -7,15 +7,6 @@ ) "type index out of bounds") -(assert_invalid - (component - (import "" (func $f)) - (component - (alias outer 1 $f (func $f)) - ) - ) - "outer aliases may only be made to types, modules, and components") - (assert_malformed (component quote "(export \"\" (func $foo))" From 0e2b1c8acfa41adb571a34680c51d65588c4eeb9 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 6 Jun 2022 17:58:42 -0700 Subject: [PATCH 23/33] wasmparser: move component-related core sections. This commit moves the component-related core section parsing out of the `core` module and into the `component` module in `wasmparser`. Originally these were put in the core module in anticipation of one day having the sections be part of core, but that's a long way off and may not occur. Until that time, it makes sense to keep these sections grouped with the other component sections. This commit also removes the extensions to the `ExternalKind` enumeration in core. It updates alias parsing to limit outer alias kind to only the supported kinds (core module, types, and components). This helps reduce confusion between what's implemented for export aliasing and what's supported for outer aliasing. By doing so, this also enables the ability to reference outer core types in nested components. --- crates/dump/src/lib.rs | 56 ++++++-- .../wasm-mutate/src/mutators/remove_item.rs | 2 - crates/wasmparser/src/binary_reader.rs | 128 ++++++++++++------ .../src/readers/component/aliases.rs | 110 ++++++++++++++- .../src/readers/component/instances.rs | 123 ++++++++++++++++- crates/wasmparser/src/readers/core.rs | 4 - crates/wasmparser/src/readers/core/aliases.rs | 96 ------------- crates/wasmparser/src/readers/core/exports.rs | 8 -- .../wasmparser/src/readers/core/instances.rs | 119 ---------------- crates/wasmparser/src/validator/component.rs | 104 ++++++++------ crates/wasmparser/src/validator/core.rs | 14 -- crates/wasmprinter/src/lib.rs | 50 +++---- 12 files changed, 441 insertions(+), 373 deletions(-) delete mode 100644 crates/wasmparser/src/readers/core/aliases.rs delete mode 100644 crates/wasmparser/src/readers/core/instances.rs diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index d0f3141dc1..0855658a89 100644 --- a/crates/dump/src/lib.rs +++ b/crates/dump/src/lib.rs @@ -265,8 +265,6 @@ impl<'a> Dump<'a> { ExternalKind::Memory => ("memory", inc(&mut i.core_memories)), ExternalKind::Global => ("global", inc(&mut i.core_globals)), ExternalKind::Tag => ("tag", inc(&mut i.core_tags)), - ExternalKind::Module => ("module", inc(&mut i.core_modules)), - ExternalKind::Instance => ("instance", inc(&mut i.core_instances)), }, }; write!(me.state, "core alias [{} {}] {:?}", kind, num, a)?; @@ -294,21 +292,49 @@ impl<'a> Dump<'a> { Payload::ComponentAliasSection(s) => { self.section(s, "component alias", |me, end, a| { - let kind = match a { - ComponentAlias::InstanceExport { kind, .. } => kind, - ComponentAlias::Outer { kind, .. } => kind, - }; - - let (kind, num) = match kind { - ComponentExternalKind::Module => ("module", inc(&mut i.core_modules)), - ComponentExternalKind::Func => ("func", inc(&mut i.funcs)), - ComponentExternalKind::Value => ("value", inc(&mut i.values)), - ComponentExternalKind::Type => ("type", inc(&mut i.types)), - ComponentExternalKind::Instance => ("instance", inc(&mut i.instances)), - ComponentExternalKind::Component => { - ("component", inc(&mut i.components)) + 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) })? diff --git a/crates/wasm-mutate/src/mutators/remove_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 9cdb7b3c26..14547f142a 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -267,8 +267,6 @@ impl RemoveItem { ExternalKind::Global => { Export::Global(self.remap(Item::Global, item.index)?) } - ExternalKind::Module => return Err(Error::unsupported("module exports are not supported")), - ExternalKind::Instance => return Err(Error::unsupported("instance exports are not supported")), }; result.export(item.name, e); } diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index e9be0c74d2..c78d84127d 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -216,28 +216,51 @@ impl<'a> BinaryReader<'a> { 0x02 => Ok(ExternalKind::Memory), 0x03 => Ok(ExternalKind::Global), 0x04 => Ok(ExternalKind::Tag), - 0x11 => Ok(ExternalKind::Module), - 0x12 => Ok(ExternalKind::Instance), 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 { - match self.read_u8()? { - 0x00 => match self.read_external_kind()? { - ExternalKind::Module => Ok(ComponentExternalKind::Module), - _ => Err(BinaryReaderError::new( - "only core modules are allowed for component external kind", - self.original_position() - 1, - )), - }, - 0x01 => Ok(ComponentExternalKind::Func), - 0x02 => Ok(ComponentExternalKind::Value), - 0x03 => Ok(ComponentExternalKind::Type), - 0x04 => Ok(ComponentExternalKind::Component), - 0x05 => Ok(ComponentExternalKind::Instance), - x => self.invalid_leading_byte(x, "component external kind"), - } + 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 { @@ -595,21 +618,17 @@ impl<'a> BinaryReader<'a> { }) } - pub(crate) fn read_instantiation_arg(&mut self) -> Result> { - let name = self.read_string()?; - let kind = match self.read_external_kind()? { - ExternalKind::Instance => ExternalKind::Instance, - _ => { - return Err(BinaryReaderError::new( - "only instances are supported for module instantiation arguments", - self.original_position() - 1, - )) - } - }; + 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, - kind, + name: self.read_string()?, + kind: self.read_instantiation_arg_kind()?, index: self.read_var_u32()?, }) } @@ -637,17 +656,53 @@ impl<'a> BinaryReader<'a> { }) } + 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, + )) + } + }) + } + pub(crate) fn read_component_alias(&mut self) -> Result> { - let kind = self.read_component_external_kind()?; + // 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, + kind: Self::component_external_kind_from_bytes(byte1, byte2, offset)?, instance_index: self.read_var_u32()?, name: self.read_string()?, }, 0x01 => ComponentAlias::Outer { - kind, + kind: Self::component_outer_alias_kind_from_bytes(byte1, byte2, offset)?, count: self.read_var_u32()?, index: self.read_var_u32()?, }, @@ -662,13 +717,6 @@ impl<'a> BinaryReader<'a> { ExternalKind::Memory => TypeRef::Memory(self.read_memory_type()?), ExternalKind::Global => TypeRef::Global(self.read_global_type()?), ExternalKind::Tag => TypeRef::Tag(self.read_tag_type()?), - ExternalKind::Module => TypeRef::Module(self.read_var_u32()?), - ExternalKind::Instance => { - return Err(BinaryReaderError::new( - "references to core instances is not currently supported", - self.original_position() - 1, - )) - } }) } diff --git a/crates/wasmparser/src/readers/component/aliases.rs b/crates/wasmparser/src/readers/component/aliases.rs index ebf471e49a..93848de754 100644 --- a/crates/wasmparser/src/readers/component/aliases.rs +++ b/crates/wasmparser/src/readers/component/aliases.rs @@ -1,9 +1,113 @@ use crate::{ - BinaryReader, ComponentExternalKind, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, + BinaryReader, ComponentExternalKind, ExternalKind, Result, SectionIteratorLimited, + SectionReader, SectionWithLimitedItems, }; use std::ops::Range; +/// Represents a core alias for a WebAssembly module. +#[derive(Debug, Clone)] +pub enum Alias<'a> { + /// The alias is to an export of a module instance. + InstanceExport { + /// The alias kind. + kind: ExternalKind, + /// The instance index. + instance_index: u32, + /// The export name. + name: &'a str, + }, +} + +/// A reader for the core alias section of a WebAssembly component. +#[derive(Clone)] +pub struct AliasSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> AliasSectionReader<'a> { + /// Constructs a new `AliasSectionReader` 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 core alias section. + /// + /// # Examples + /// ``` + /// use wasmparser::AliasSectionReader; + /// 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"); + /// println!("Alias: {:?}", alias); + /// } + /// ``` + pub fn read(&mut self) -> Result> { + self.reader.read_alias() + } +} + +impl<'a> SectionReader for AliasSectionReader<'a> { + type Item = Alias<'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 AliasSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for AliasSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited; + + fn into_iter(self) -> Self::IntoIter { + 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> { @@ -19,7 +123,7 @@ pub enum ComponentAlias<'a> { /// The alias is to an outer item. Outer { /// The alias kind. - kind: ComponentExternalKind, + kind: ComponentOuterAliasKind, /// The outward count, starting at zero for the current component. count: u32, /// The index of the item within the outer component. diff --git a/crates/wasmparser/src/readers/component/instances.rs b/crates/wasmparser/src/readers/component/instances.rs index 10da93e5aa..79cacfbe94 100644 --- a/crates/wasmparser/src/readers/component/instances.rs +++ b/crates/wasmparser/src/readers/component/instances.rs @@ -1,9 +1,130 @@ use crate::{ - BinaryReader, ComponentExport, ComponentExternalKind, Result, SectionIteratorLimited, + BinaryReader, ComponentExport, ComponentExternalKind, Export, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, }; use std::ops::Range; +/// 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 module. +#[derive(Debug, Clone)] +pub struct InstantiationArg<'a> { + /// The name of the module argument. + pub name: &'a str, + /// The kind of the module argument. + pub kind: InstantiationArgKind, + /// The index of the argument item. + pub index: u32, +} + +/// Represents an instance of a WebAssembly module. +#[derive(Debug, Clone)] +pub enum Instance<'a> { + /// The instance is from instantiating a WebAssembly module. + Instantiate { + /// The module index. + module_index: u32, + /// The module's instantiation arguments. + args: Box<[InstantiationArg<'a>]>, + }, + /// The instance is a from exporting local items. + FromExports(Box<[Export<'a>]>), +} + +/// A reader for the core instance section of a WebAssembly component. +#[derive(Clone)] +pub struct InstanceSectionReader<'a> { + reader: BinaryReader<'a>, + count: u32, +} + +impl<'a> InstanceSectionReader<'a> { + /// Constructs a new `InstanceSectionReader` 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::InstanceSectionReader; + /// # 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"); + /// println!("Instance: {:?}", instance); + /// } + /// ``` + pub fn read(&mut self) -> Result> { + self.reader.read_instance() + } +} + +impl<'a> SectionReader for InstanceSectionReader<'a> { + type Item = Instance<'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 InstanceSectionReader<'a> { + fn get_count(&self) -> u32 { + Self::get_count(self) + } +} + +impl<'a> IntoIterator for InstanceSectionReader<'a> { + type Item = Result>; + type IntoIter = SectionIteratorLimited; + + /// Implements iterator over the instance section. + /// + /// # Examples + /// + /// ``` + /// use wasmparser::InstanceSectionReader; + /// # 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")); + /// } + /// ``` + fn into_iter(self) -> Self::IntoIter { + SectionIteratorLimited::new(self) + } +} + /// Represents an argument to instantiating a WebAssembly component. #[derive(Debug, Clone)] pub struct ComponentInstantiationArg<'a> { diff --git a/crates/wasmparser/src/readers/core.rs b/crates/wasmparser/src/readers/core.rs index f99ac87b8d..941f208548 100644 --- a/crates/wasmparser/src/readers/core.rs +++ b/crates/wasmparser/src/readers/core.rs @@ -1,4 +1,3 @@ -mod aliases; mod code; mod custom; mod data; @@ -8,7 +7,6 @@ mod functions; mod globals; mod imports; mod init; -mod instances; mod linking; mod memories; mod names; @@ -19,7 +17,6 @@ mod tables; mod tags; mod types; -pub use self::aliases::*; pub use self::code::*; pub use self::custom::*; pub use self::data::*; @@ -29,7 +26,6 @@ pub use self::functions::*; pub use self::globals::*; pub use self::imports::*; pub use self::init::*; -pub use self::instances::*; pub use self::linking::*; pub use self::memories::*; pub use self::names::*; diff --git a/crates/wasmparser/src/readers/core/aliases.rs b/crates/wasmparser/src/readers/core/aliases.rs deleted file mode 100644 index d8ce3fa9b7..0000000000 --- a/crates/wasmparser/src/readers/core/aliases.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::{ - BinaryReader, ExternalKind, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, -}; -use std::ops::Range; - -/// Represents a core alias for a WebAssembly module. -#[derive(Debug, Clone)] -pub enum Alias<'a> { - /// The alias is to an export of a module instance. - InstanceExport { - /// The alias kind. - kind: ExternalKind, - /// The instance index. - instance_index: u32, - /// The export name. - name: &'a str, - }, -} - -/// A reader for the core alias section of a WebAssembly component. -#[derive(Clone)] -pub struct AliasSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> AliasSectionReader<'a> { - /// Constructs a new `AliasSectionReader` 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 core alias section. - /// - /// # Examples - /// ``` - /// use wasmparser::AliasSectionReader; - /// 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"); - /// println!("Alias: {:?}", alias); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_alias() - } -} - -impl<'a> SectionReader for AliasSectionReader<'a> { - type Item = Alias<'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 AliasSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for AliasSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} diff --git a/crates/wasmparser/src/readers/core/exports.rs b/crates/wasmparser/src/readers/core/exports.rs index 88805f57bd..5aa8e7316f 100644 --- a/crates/wasmparser/src/readers/core/exports.rs +++ b/crates/wasmparser/src/readers/core/exports.rs @@ -31,14 +31,6 @@ pub enum ExternalKind { Global, /// The external kind is a tag. Tag, - /// The external kind is a module. - /// - /// This is used with the component model proposal. - Module, - /// The external kind is an instance of a module. - /// - /// This is used with the component model proposal. - Instance, } /// Represents an export in a WebAssembly module. diff --git a/crates/wasmparser/src/readers/core/instances.rs b/crates/wasmparser/src/readers/core/instances.rs deleted file mode 100644 index a2505adb57..0000000000 --- a/crates/wasmparser/src/readers/core/instances.rs +++ /dev/null @@ -1,119 +0,0 @@ -use crate::{ - BinaryReader, Export, ExternalKind, Result, SectionIteratorLimited, SectionReader, - SectionWithLimitedItems, -}; -use std::ops::Range; - -/// Represents an argument to instantiating a WebAssembly module. -#[derive(Debug, Clone)] -pub struct InstantiationArg<'a> { - /// The name of the module argument. - pub name: &'a str, - /// The kind of the module argument. - pub kind: ExternalKind, - /// The index of the argument item. - pub index: u32, -} - -/// Represents an instance of a WebAssembly module. -#[derive(Debug, Clone)] -pub enum Instance<'a> { - /// The instance is from instantiating a WebAssembly module. - Instantiate { - /// The module index. - module_index: u32, - /// The module's instantiation arguments. - args: Box<[InstantiationArg<'a>]>, - }, - /// The instance is a from exporting local items. - FromExports(Box<[Export<'a>]>), -} - -/// A reader for the core instance section of a WebAssembly component. -#[derive(Clone)] -pub struct InstanceSectionReader<'a> { - reader: BinaryReader<'a>, - count: u32, -} - -impl<'a> InstanceSectionReader<'a> { - /// Constructs a new `InstanceSectionReader` 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::InstanceSectionReader; - /// # 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"); - /// println!("Instance: {:?}", instance); - /// } - /// ``` - pub fn read(&mut self) -> Result> { - self.reader.read_instance() - } -} - -impl<'a> SectionReader for InstanceSectionReader<'a> { - type Item = Instance<'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 InstanceSectionReader<'a> { - fn get_count(&self) -> u32 { - Self::get_count(self) - } -} - -impl<'a> IntoIterator for InstanceSectionReader<'a> { - type Item = Result>; - type IntoIter = SectionIteratorLimited; - - /// Implements iterator over the instance section. - /// - /// # Examples - /// - /// ``` - /// use wasmparser::InstanceSectionReader; - /// # 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")); - /// } - /// ``` - fn into_iter(self) -> Self::IntoIter { - SectionIteratorLimited::new(self) - } -} diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 0bcacaac00..646347285a 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -15,9 +15,9 @@ use crate::{ ComponentDefinedType, ComponentEntityType, InstanceTypeKind, TupleType, UnionType, VariantType, }, - BinaryReaderError, CanonicalOption, ComponentExternalKind, ComponentTypeRef, ExternalKind, - FuncType, GlobalType, MemoryType, PrimitiveValType, Result, TableType, TypeBounds, ValType, - WasmFeatures, + BinaryReaderError, CanonicalOption, ComponentExternalKind, ComponentOuterAliasKind, + ComponentTypeRef, ExternalKind, FuncType, GlobalType, InstantiationArgKind, MemoryType, + PrimitiveValType, Result, TableType, TypeBounds, ValType, WasmFeatures, }; use std::{collections::HashMap, mem}; @@ -398,19 +398,16 @@ impl ComponentState { offset, ), crate::ComponentAlias::Outer { kind, count, index } => match kind { - ComponentExternalKind::Module => { + ComponentOuterAliasKind::CoreModule => { Self::alias_module(components, count, index, offset) } - ComponentExternalKind::Type => Self::alias_type(components, count, index, offset), - ComponentExternalKind::Component => { + 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) } - ComponentExternalKind::Func - | ComponentExternalKind::Value - | ComponentExternalKind::Instance => Err(BinaryReaderError::new( - "outer aliases may only be made to types, modules, and components", - offset, - )), }, } } @@ -757,9 +754,18 @@ impl ComponentState { crate::ComponentTypeDeclaration::Alias(alias) => { match alias { crate::ComponentAlias::Outer { kind, count, index } - if kind == ComponentExternalKind::Type => + if kind == ComponentOuterAliasKind::CoreType + || kind == ComponentOuterAliasKind::Type => { - Self::alias_type(components, count, index, offset)?; + 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", @@ -791,29 +797,41 @@ impl ComponentState { for decl in decls { match decl { crate::InstanceTypeDeclaration::CoreType(ty) => { - components.last_mut().unwrap().add_core_type(ty, features, types, offset, true)?; + components + .last_mut() + .unwrap() + .add_core_type(ty, features, types, offset, true)?; } crate::InstanceTypeDeclaration::Type(ty) => { Self::add_type(components, ty, features, types, offset, true)?; } - crate::InstanceTypeDeclaration::Export{ name, ty } => { + 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 == ComponentExternalKind::Type => - { - Self::alias_type(components, count, index, offset)?; + 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 component instance type declarations", + } + _ => { + return Err(BinaryReaderError::new( + "only outer type aliases are allowed in instance type declarations", offset, - )), + )) } - } + }, }; } @@ -900,7 +918,7 @@ impl ComponentState { // Populate the arguments for module_arg in module_args { match module_arg.kind { - ExternalKind::Instance => { + InstantiationArgKind::Instance => { let instance_type = types[self.core_instance_at(module_arg.index, offset)?] .as_instance_type() .unwrap(); @@ -908,12 +926,6 @@ impl ComponentState { insert_arg(module_arg.name, name, *ty, &mut args, offset)?; } } - _ => { - return Err(BinaryReaderError::new( - "only instance instantiation arguments are allowed", - offset, - )); - } } } @@ -1304,12 +1316,6 @@ impl ComponentState { &mut type_size, offset, )?, - ExternalKind::Module | ExternalKind::Instance => { - return Err(BinaryReaderError::new( - "cannot create a core instance from a module or instance export", - offset, - )) - } } } @@ -1395,10 +1401,6 @@ impl ComponentState { check_max(self.core_tags.len(), 1, MAX_WASM_TAGS, "tags", offset)?; push_module_export!(EntityType::Tag, core_tags, "tag") } - ExternalKind::Module | ExternalKind::Instance => Err(BinaryReaderError::new( - "aliases to core modules or instances is not supported", - offset, - )), } } @@ -1535,6 +1537,22 @@ 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, false, offset)?; diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 80bf231fcf..e2d86aa72c 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -806,20 +806,6 @@ impl Module { check("tag", export.index, self.tags.len())?; EntityType::Tag(self.tags[export.index as usize]) } - ExternalKind::Module => { - // May be supported with a module linking proposal in the future - return Err(BinaryReaderError::new( - "module exports are not allowed in core modules", - offset, - )); - } - ExternalKind::Instance => { - // May be supported with a module linking proposal in the future - return Err(BinaryReaderError::new( - "instance exports are not allowed in core modules", - offset, - )); - } }) } diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 8af597465b..9c69fdf215 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -2063,14 +2063,6 @@ impl Printer { self.print_idx(&state.core.memory_names, index)?; } ExternalKind::Tag => write!(self.result, "tag {}", index)?, - ExternalKind::Module => { - self.result.push_str("module "); - self.print_idx(&state.core.module_names, index)?; - } - ExternalKind::Instance => { - self.result.push_str("instance "); - self.print_idx(&state.core.instance_names, index)?; - } } self.result.push(')'); Ok(()) @@ -2559,7 +2551,7 @@ impl Printer { fn print_outer_alias( &mut self, states: &mut [State], - kind: ComponentExternalKind, + kind: ComponentOuterAliasKind, count: u32, index: u32, ) -> Result<()> { @@ -2574,7 +2566,21 @@ impl Printer { } self.result.push(' '); let index = match kind { - ComponentExternalKind::Type => { + ComponentOuterAliasKind::CoreModule => { + self.print_idx(&outer.core.module_names, index)?; + self.result.push(' '); + self.start_group("core module "); + self.print_name(&state.core.module_names, state.core.modules)?; + None + } + ComponentOuterAliasKind::CoreType => { + self.print_idx(&outer.core.type_names, index)?; + self.result.push(' '); + self.start_group("core type "); + self.print_name(&state.core.type_names, state.core.types.len() as u32)?; + Some(outer.core_ty(index)?) + } + ComponentOuterAliasKind::Type => { self.print_idx(&outer.component.type_names, index)?; self.result.push(' '); self.start_group("type "); @@ -2584,14 +2590,7 @@ impl Printer { )?; Some(outer.ty(index)?) } - ComponentExternalKind::Module => { - self.print_idx(&outer.core.module_names, index)?; - self.result.push(' '); - self.start_group("core module "); - self.print_name(&state.core.module_names, state.core.modules)?; - None - } - ComponentExternalKind::Component => { + ComponentOuterAliasKind::Component => { self.print_idx(&outer.component.component_names, index)?; self.result.push(' '); self.start_group("component "); @@ -2601,7 +2600,6 @@ impl Printer { )?; Some(outer.component(index)?) } - _ => bail!("invalid outer alias kind"), }; self.end_group(); // kind self.end_group(); // alias @@ -2610,10 +2608,10 @@ impl Printer { let state = states.last_mut().unwrap(); match kind { - ComponentExternalKind::Type => state.component.types.push(index.unwrap()), - ComponentExternalKind::Module => state.core.modules += 1, - ComponentExternalKind::Component => state.component.components.push(index.unwrap()), - _ => unreachable!(), + 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(()) @@ -3108,12 +3106,11 @@ impl Printer { self.print_str(arg.name)?; self.result.push(' '); match arg.kind { - ExternalKind::Instance => { + InstantiationArgKind::Instance => { self.start_group("instance "); self.print_idx(&state.core.instance_names, arg.index)?; self.end_group(); } - _ => bail!("only instances are supported for module instantiation arguments"), } self.end_group(); Ok(()) @@ -3231,9 +3228,6 @@ impl Printer { self.end_group(); state.core.tags += 1; } - ExternalKind::Module | ExternalKind::Instance => { - bail!("core export alias for modules and instances is not supported") - } } self.end_group(); // alias export } From ab81b9f392c0c06689810fac42a3aafe7d807034 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 6 Jun 2022 20:09:50 -0700 Subject: [PATCH 24/33] wast: fix parsing and encoding of aliases. This commit fixes the parsing and encoding of aliases such that the grammar is restricted to what's actually supported for both instance export aliases and for outer aliases. It also addresses the inability to reference and encode outer core type aliases. `CoreItemRef` was fixed to only have a single export name supported as core instances cannot export other core instances, so there can be at most one string parsed for the export name. --- crates/wasm-encoder/src/component/types.rs | 26 +- crates/wast/src/component/alias.rs | 286 +++++++++--------- crates/wast/src/component/binary.rs | 98 +++--- crates/wast/src/component/expand.rs | 10 +- crates/wast/src/component/func.rs | 2 +- crates/wast/src/component/item_ref.rs | 33 +- crates/wast/src/component/resolve.rs | 233 +++++++------- crates/wast/src/component/types.rs | 6 +- .../local/component-model/instance-type.wast | 2 +- tests/local/component-model/invalid.wast | 4 +- tests/local/component-model/types.wast | 2 +- tests/local/component-model/virtualize.wast | 23 +- 12 files changed, 367 insertions(+), 358 deletions(-) diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index 4744a482e6..f23a1ef885 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -40,7 +40,19 @@ impl ComponentType { ComponentTypeEncoder(&mut self.bytes) } - /// Defines an alias in this component type. + /// 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); @@ -126,6 +138,18 @@ impl InstanceType { ComponentTypeEncoder(&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 in this instance type. pub fn alias_outer_type(&mut self, count: u32, index: u32) -> &mut Self { self.bytes.push(0x02); diff --git a/crates/wast/src/component/alias.rs b/crates/wast/src/component/alias.rs index 790500279f..86dfcc3313 100644 --- a/crates/wast/src/component/alias.rs +++ b/crates/wast/src/component/alias.rs @@ -1,3 +1,4 @@ +use crate::core::ExportKind; use crate::kw; use crate::parser::{Parse, Parser, Result}; use crate::token::{Id, Index, NameAnnotation, Span}; @@ -17,7 +18,6 @@ impl<'a> Parse<'a> for InlineExportAlias<'a> { parser.parse::()?; let instance = parser.parse()?; let name = parser.parse()?; - Ok(Self { instance, name }) } } @@ -34,28 +34,29 @@ pub struct CoreAlias<'a> { pub name: Option>, /// The target of the alias. pub target: CoreAliasTarget<'a>, - /// The kind of item being aliased. - pub kind: CoreAliasKind, } impl<'a> Parse<'a> for CoreAlias<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; parser.parse::()?; - let target = parser.parse()?; - let (kind, id, name) = parser.parens(|parser| { - let kind = parser.parse()?; - let id = parser.parse()?; - let name = parser.parse()?; - Ok((kind, id, name)) - })?; + + // 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, + target: CoreAliasTarget::Export { + instance, + name: export_name, + kind, + }, id, name, - kind, }) } } @@ -69,69 +70,11 @@ pub enum CoreAliasTarget<'a> { instance: Index<'a>, /// The name of the exported item being aliased. name: &'a str, + /// The export kind of the alias. + kind: ExportKind, }, } -impl<'a> Parse<'a> for CoreAliasTarget<'a> { - fn parse(parser: Parser<'a>) -> Result { - // Right now only export aliases are supported. - parser.parse::()?; - Ok(Self::Export { - instance: parser.parse()?, - name: parser.parse()?, - }) - } -} - -/// Represents the kind of a core alias. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum CoreAliasKind { - /// The alias is to a core function. - Func, - /// The alias is to a table. - Table, - /// The alias is to a module. - Memory, - /// The alias is to a global. - Global, - /// The alias is to a tag. - Tag, - /// The alias is to a core type. - Type, - /// The alias is to a module. - Module, - /// The alias is to a module instance. - Instance, -} - -impl<'a> Parse<'a> for CoreAliasKind { - fn parse(parser: Parser<'a>) -> Result { - let mut l = parser.lookahead1(); - // Note: this intentionally does not parse - // type, module, or instance; those are only - // valid in `AliasKind` and they are parsed there - // instead. - if l.peek::() { - parser.parse::()?; - Ok(Self::Func) - } else if l.peek::() { - parser.parse::()?; - Ok(Self::Table) - } else if l.peek::() { - parser.parse::()?; - Ok(Self::Memory) - } else if l.peek::() { - parser.parse::()?; - Ok(Self::Global) - } else if l.peek::() { - parser.parse::()?; - Ok(Self::Tag) - } else { - Err(l.error()) - } - } -} - /// An alias to a component item. #[derive(Debug)] pub struct Alias<'a> { @@ -144,24 +87,31 @@ 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, } impl<'a> Alias<'a> { - /// Parses only an outer alias. - pub fn parse_outer(parser: Parser<'a>) -> Result { + /// Parses only an outer type alias. + pub fn parse_outer_type_alias(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; - let target = AliasTarget::parse_outer(parser)?; - let (kind, id, name) = - parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?; + 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, + target: AliasTarget::Outer { outer, index, kind }, id, name, - kind, }) } } @@ -169,97 +119,74 @@ impl<'a> Alias<'a> { impl<'a> Parse<'a> for Alias<'a> { fn parse(parser: Parser<'a>) -> Result { let span = parser.parse::()?.0; - let target = parser.parse()?; - let (kind, id, name) = - parser.parens(|parser| Ok((parser.parse()?, parser.parse()?, parser.parse()?)))?; + + 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, - kind, - }) - } -} - -/// 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>, - /// The name of the exported item to alias. - name: &'a str, - }, - /// The alias is to an item from an outer component. - Outer { - /// The number of enclosing components to skip. - outer: Index<'a>, - /// The index of the item being aliased. - index: Index<'a>, - }, -} - -impl<'a> AliasTarget<'a> { - /// Parses only an outer alias target. - pub fn parse_outer(parser: Parser<'a>) -> Result { - parser.parse::()?; - Ok(Self::Outer { - outer: parser.parse()?, - index: parser.parse()?, }) } } -impl<'a> Parse<'a> for AliasTarget<'a> { - fn parse(parser: Parser<'a>) -> Result { - if parser.peek::() { - Self::parse_outer(parser) - } else { - parser.parse::()?; - Ok(Self::Export { - instance: parser.parse()?, - name: parser.parse()?, - }) - } - } -} - -/// Represents the kind of item being aliased. +/// Represents the kind of instance export alias. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum AliasKind { - /// The item is a core item. - Core(CoreAliasKind), - /// The item is a function. +pub enum ComponentExportAliasKind { + /// The alias is to a core module export. + CoreModule, + /// The alias is to a function export. Func, - /// The item is a value. + /// The alias is to a value export. Value, - /// The item is a type. + /// The alias is to a type export. Type, - /// The item is a component. + /// The alias is to a component export. Component, - /// The item is a component instance. + /// The alias is to an instance export. Instance, } -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::() { parser.parse::()?; - if parser.peek::() { + let mut l = parser.lookahead1(); + if l.peek::() { parser.parse::()?; - Ok(Self::Core(CoreAliasKind::Module)) - } else if parser.peek::() { - parser.parse::()?; - Ok(Self::Core(CoreAliasKind::Instance)) - } else if parser.peek::() { - parser.parse::()?; - Ok(Self::Core(CoreAliasKind::Type)) + Ok(Self::CoreModule) } else { - Ok(Self::Core(parser.parse()?)) + Err(l.error()) } } else if l.peek::() { parser.parse::()?; @@ -281,3 +208,66 @@ impl<'a> Parse<'a> for AliasKind { } } } + +/// 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>, + /// 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>, + /// The index of the item being aliased. + index: Index<'a>, + /// The outer alias kind. + kind: ComponentOuterAliasKind, + }, +} diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index d6864d590a..bc15b80248 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -187,9 +187,13 @@ impl Encoder { fn encode_core_alias(&mut self, alias: &CoreAlias) { match &alias.target { - CoreAliasTarget::Export { instance, name } => { + CoreAliasTarget::Export { + instance, + name, + kind, + } => { self.core_aliases - .instance_export((*instance).into(), alias.kind.into(), name); + .instance_export((*instance).into(), (*kind).into(), name); } } @@ -243,13 +247,17 @@ impl Encoder { fn encode_alias(&mut self, alias: &Alias) { match &alias.target { - AliasTarget::Export { instance, name } => { + AliasTarget::Export { + instance, + name, + kind, + } => { self.aliases - .instance_export((*instance).into(), alias.kind.into(), name); + .instance_export((*instance).into(), (*kind).into(), name); } - AliasTarget::Outer { outer, index } => { + AliasTarget::Outer { outer, index, kind } => { self.aliases - .outer((*outer).into(), alias.kind.into(), (*index).into()); + .outer((*outer).into(), (*kind).into(), (*index).into()); } } @@ -516,18 +524,14 @@ impl From<&CoreItemRef<'_, core::ExportKind>> for wasm_encoder::Export { } } -impl From for wasm_encoder::ExportKind { - fn from(kind: CoreAliasKind) -> Self { +impl From for wasm_encoder::ExportKind { + fn from(kind: core::ExportKind) -> Self { match kind { - CoreAliasKind::Func => Self::Func, - CoreAliasKind::Table => Self::Table, - CoreAliasKind::Memory => Self::Memory, - CoreAliasKind::Global => Self::Global, - CoreAliasKind::Tag => Self::Tag, - // These forms should only be used from component aliases - CoreAliasKind::Type | CoreAliasKind::Module | CoreAliasKind::Instance => { - unreachable!("unparsable core alias 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, } } } @@ -627,12 +631,21 @@ impl From<&ComponentType<'_>> for wasm_encoder::ComponentType { encode_type(encoded.ty(), &t.def); } ComponentTypeDecl::Alias(a) => match &a.target { - AliasTarget::Export { .. } => { - unreachable!("cannot encode export aliases for types") + AliasTarget::Outer { + outer, + index, + kind: ComponentOuterAliasKind::CoreType, + } => { + encoded.alias_outer_core_type(u32::from(*outer), u32::from(*index)); } - AliasTarget::Outer { outer, 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()); @@ -660,12 +673,21 @@ impl From<&InstanceType<'_>> for wasm_encoder::InstanceType { encode_type(encoded.ty(), &t.def); } InstanceTypeDecl::Alias(a) => match &a.target { - AliasTarget::Export { .. } => { - unreachable!("cannot encode export aliases for types") + AliasTarget::Outer { + outer, + index, + kind: ComponentOuterAliasKind::CoreType, + } => { + encoded.alias_outer_core_type(u32::from(*outer), u32::from(*index)); } - AliasTarget::Outer { outer, 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()); @@ -735,28 +757,26 @@ impl From<&ComponentExportKind<'_>> for (wasm_encoder::ComponentExportKind, u32) } } -impl From for wasm_encoder::ComponentOuterAliasKind { - fn from(kind: AliasKind) -> Self { +impl From for wasm_encoder::ComponentOuterAliasKind { + fn from(kind: ComponentOuterAliasKind) -> Self { match kind { - AliasKind::Core(CoreAliasKind::Module) => Self::CoreModule, - AliasKind::Core(CoreAliasKind::Type) => Self::CoreType, - AliasKind::Type => Self::Type, - AliasKind::Component => Self::Component, - _ => unreachable!("not representable as an outer alias ({:?})", kind), + ComponentOuterAliasKind::CoreModule => Self::CoreModule, + ComponentOuterAliasKind::CoreType => Self::CoreType, + ComponentOuterAliasKind::Type => Self::Type, + ComponentOuterAliasKind::Component => Self::Component, } } } -impl From for wasm_encoder::ComponentExportKind { - fn from(kind: AliasKind) -> Self { +impl From for wasm_encoder::ComponentExportKind { + fn from(kind: ComponentExportAliasKind) -> Self { match kind { - AliasKind::Core(CoreAliasKind::Module) => Self::Module, - AliasKind::Core(_) => unreachable!("only modules may be aliased for instance exports"), - AliasKind::Func => Self::Func, - AliasKind::Value => Self::Value, - AliasKind::Type => Self::Type, - AliasKind::Component => Self::Component, - AliasKind::Instance => Self::Instance, + ComponentExportAliasKind::CoreModule => Self::Module, + ComponentExportAliasKind::Func => Self::Func, + ComponentExportAliasKind::Value => Self::Value, + ComponentExportAliasKind::Type => Self::Type, + ComponentExportAliasKind::Component => Self::Component, + ComponentExportAliasKind::Instance => Self::Instance, } } } diff --git a/crates/wast/src/component/expand.rs b/crates/wast/src/component/expand.rs index d434122b88..9fe32212eb 100644 --- a/crates/wast/src/component/expand.rs +++ b/crates/wast/src/component/expand.rs @@ -259,8 +259,8 @@ impl<'a> Expander<'a> { target: CoreAliasTarget::Export { instance: a.instance, name: a.name, + kind: core::ExportKind::Func, }, - kind: CoreAliasKind::Func, })), CoreFuncKind::Lower(info) => Some(ComponentField::CanonicalFunc(CanonicalFunc { span: func.span, @@ -314,8 +314,8 @@ impl<'a> Expander<'a> { target: AliasTarget::Export { instance: a.instance, name: a.name, + kind: ComponentExportAliasKind::Func, }, - kind: AliasKind::Func, })), } } @@ -566,7 +566,7 @@ impl<'a> Expander<'a> { let ret = CoreItemRef { idx, kind: kw::r#type(span), - export_names: Vec::new(), + export_name: None, }; *item = CoreTypeUse::Ref(ret.clone()); return ret; @@ -582,7 +582,7 @@ impl<'a> Expander<'a> { let ret = CoreItemRef { idx, kind: kw::r#type(span), - export_names: Vec::new(), + export_name: None, }; *item = CoreTypeUse::Ref(ret.clone()); @@ -658,7 +658,7 @@ impl<'a> Expander<'a> { *arg = CoreInstantiationArgKind::Instance(CoreItemRef { kind: kw::instance(span), idx: Index::Id(id), - export_names: Default::default(), + export_name: None, }); } diff --git a/crates/wast/src/component/func.rs b/crates/wast/src/component/func.rs index fee43e29a1..f655d4b8b4 100644 --- a/crates/wast/src/component/func.rs +++ b/crates/wast/src/component/func.rs @@ -255,7 +255,7 @@ impl Default for CanonLift<'_> { func: CoreItemRef { kind: kw::func(span), idx: Index::Num(0, span), - export_names: Vec::new(), + export_name: None, }, opts: Vec::new(), } diff --git a/crates/wast/src/component/item_ref.rs b/crates/wast/src/component/item_ref.rs index eca4d99d05..6b2632ea46 100644 --- a/crates/wast/src/component/item_ref.rs +++ b/crates/wast/src/component/item_ref.rs @@ -37,19 +37,6 @@ fn peek(cursor: Cursor) -> bool { } } -fn parse<'a, K: Parse<'a>>(parser: Parser<'a>) -> Result<(K, Index<'a>, Vec<&'a str>)> { - // 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 mut names = Vec::new(); - while !parser.is_empty() { - names.push(parser.parse()?); - } - Ok((kind, idx, names)) -} - /// Parses core item references. #[derive(Clone, Debug)] pub struct CoreItemRef<'a, K> { @@ -57,17 +44,22 @@ pub struct CoreItemRef<'a, K> { 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>, + /// Export name to resolve the item from. + pub export_name: Option<&'a str>, } impl<'a, K: Parse<'a>> Parse<'a> for CoreItemRef<'a, K> { fn parse(parser: Parser<'a>) -> Result { - let (kind, idx, export_names) = parse(parser)?; + // 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_names, + export_name, }) } } @@ -95,7 +87,12 @@ pub struct ItemRef<'a, K> { impl<'a, K: Parse<'a>> Parse<'a> for ItemRef<'a, K> { fn parse(parser: Parser<'a>) -> Result { - let (kind, idx, export_names) = parse(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(Self { kind, idx, diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index d4dc033de7..df049d0eef 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -275,16 +275,22 @@ impl<'a> Resolver<'a> { fn core_alias(&mut self, alias: &mut CoreAlias<'a>) -> Result<(), Error> { match &mut alias.target { - CoreAliasTarget::Export { instance, name: _ } => { - self.resolve_ns(instance, Ns::CoreInstance) - } + CoreAliasTarget::Export { + instance, + name: _, + kind: _, + } => self.resolve_ns(instance, Ns::CoreInstance), } } fn alias(&mut self, alias: &mut Alias<'a>) -> Result<(), Error> { match &mut alias.target { - AliasTarget::Export { instance, name: _ } => self.resolve_ns(instance, Ns::Instance), - AliasTarget::Outer { outer, index } => { + AliasTarget::Export { + instance, + name: _, + kind: _, + } => self.resolve_ns(instance, Ns::Instance), + 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. @@ -325,7 +331,7 @@ impl<'a> Resolver<'a> { // Resolve `index` within the computed scope depth. let computed = self.stack.len() - 1 - depth as usize; - self.stack[computed].resolve(alias.kind.into(), index)?; + self.stack[computed].resolve((*kind).into(), index)?; Ok(()) } @@ -535,7 +541,7 @@ impl<'a> Resolver<'a> { K: CoreItem + Copy, { // Check for not being an instance export reference - if item.export_names.is_empty() { + if item.export_name.is_none() { self.resolve_ns(&mut item.idx, item.kind.ns())?; return Ok(()); } @@ -544,31 +550,24 @@ impl<'a> Resolver<'a> { let mut index = item.idx; self.resolve_ns(&mut index, Ns::CoreInstance)?; + // Record an alias to reference the export let span = item.idx.span(); - for (pos, export_name) in item.export_names.iter().enumerate() { - // Record an alias to reference the export - let alias = CoreAlias { - span, - id: None, - name: None, - target: CoreAliasTarget::Export { - instance: index, - name: export_name, - }, - kind: if pos == item.export_names.len() - 1 { - item.kind.ns() - } else { - Ns::Instance - } - .into(), - }; + 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(None, alias.kind)?, span); - self.aliases_to_insert.push(AnyAlias::Core(alias)); - } + index = Index::Num(self.current().register_core_alias(&alias)?, span); + self.aliases_to_insert.push(AnyAlias::Core(alias)); item.idx = index; - item.export_names = Vec::new(); + item.export_name = None; Ok(()) } @@ -597,13 +596,12 @@ impl<'a> Resolver<'a> { target: AliasTarget::Export { instance: index, name: export_name, + kind: if pos == item.export_names.len() - 1 { + item.kind.ns().into() + } else { + ComponentExportAliasKind::Instance + }, }, - kind: if pos == item.export_names.len() - 1 { - item.kind.ns() - } else { - Ns::Instance - } - .into(), }; index = Index::Num(self.current().register_alias(&alias)?, span); @@ -644,15 +642,6 @@ impl<'a> Resolver<'a> { // When resolution succeeds in a parent then an outer alias is // automatically inserted here in this component. let span = idx.span(); - - if !ns.can_alias_outer() { - return Err(Error::new( - span, - "outer aliases can only be made to modules, components, and component types" - .to_string(), - )); - } - let alias = Alias { span, id: Some(id), @@ -660,8 +649,8 @@ impl<'a> Resolver<'a> { target: AliasTarget::Outer { outer: Index::Num(depth, span), index: Index::Num(found, span), + kind: ns.into(), }, - kind: ns.into(), }; let local_index = self.current().register_alias(&alias)?; self.aliases_to_insert.push(AnyAlias::Component(alias)); @@ -732,7 +721,7 @@ impl<'a> ComponentState<'a> { ComponentField::CoreInstance(i) => { self.core_instances.register(i.id, "core instance")? } - ComponentField::CoreAlias(a) => self.register_core_alias(a.id, a.kind)?, + 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")?, @@ -766,30 +755,59 @@ impl<'a> ComponentState<'a> { } fn register_alias(&mut self, alias: &Alias<'a>) -> Result { - match alias.kind { - AliasKind::Core(k) => self.register_core_alias(alias.id, k), - AliasKind::Func => self.funcs.register(alias.id, "func"), - AliasKind::Value => self.values.register(alias.id, "value"), - AliasKind::Type => self.types.register(alias.id, "type"), - AliasKind::Component => self.components.register(alias.id, "component"), - AliasKind::Instance => self.instances.register(alias.id, "instance"), - } - } - - fn register_core_alias( - &mut self, - id: Option>, - kind: CoreAliasKind, - ) -> Result { - match kind { - CoreAliasKind::Func => self.core_funcs.register(id, "core func"), - CoreAliasKind::Table => self.core_tables.register(id, "core table"), - CoreAliasKind::Memory => self.core_memories.register(id, "core memory"), - CoreAliasKind::Global => self.core_globals.register(id, "core global"), - CoreAliasKind::Tag => self.core_tags.register(id, "core tag"), - CoreAliasKind::Type => self.core_types.register(id, "core type"), - CoreAliasKind::Module => self.core_modules.register(id, "core module"), - CoreAliasKind::Instance => self.core_instances.register(id, "core instance"), + match alias.target { + AliasTarget::Export { + kind: ComponentExportAliasKind::Component, + .. + } + | AliasTarget::Outer { + kind: ComponentOuterAliasKind::Component, + .. + } => self.components.register(alias.id, "component"), + AliasTarget::Export { + kind: ComponentExportAliasKind::CoreModule, + .. + } + | AliasTarget::Outer { + kind: ComponentOuterAliasKind::CoreModule, + .. + } => self.core_modules.register(alias.id, "core module"), + AliasTarget::Export { + kind: ComponentExportAliasKind::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"), + }, } } } @@ -811,15 +829,6 @@ enum Ns { Value, } -impl Ns { - fn can_alias_outer(&self) -> bool { - match self { - Ns::Type | Ns::CoreModule | Ns::Component => true, - _ => false, - } - } -} - trait ComponentItem { fn ns(&self) -> Ns; } @@ -860,66 +869,52 @@ core_item!(kw::memory, CoreMemory); core_item!(kw::r#type, CoreType); core_item!(kw::r#instance, CoreInstance); -impl From for CoreAliasKind { +impl From for ComponentExportAliasKind { fn from(ns: Ns) -> Self { match ns { - Ns::CoreFunc => CoreAliasKind::Func, - Ns::CoreGlobal => CoreAliasKind::Global, - Ns::CoreTable => CoreAliasKind::Table, - Ns::CoreMemory => CoreAliasKind::Memory, - Ns::CoreType => CoreAliasKind::Type, - Ns::CoreTag => CoreAliasKind::Tag, - Ns::CoreInstance => CoreAliasKind::Instance, - Ns::CoreModule => CoreAliasKind::Module, - _ => unreachable!("not a core namespace"), + 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"), } } } -impl From for AliasKind { +impl From for ComponentOuterAliasKind { fn from(ns: Ns) -> Self { match ns { - Ns::CoreFunc - | Ns::CoreGlobal - | Ns::CoreTable - | Ns::CoreMemory - | Ns::CoreType - | Ns::CoreTag - | Ns::CoreInstance - | Ns::CoreModule => Self::Core(ns.into()), - Ns::Func => Self::Func, + Ns::CoreModule => Self::CoreModule, + Ns::CoreType => Self::CoreType, Ns::Type => Self::Type, - Ns::Instance => Self::Instance, Ns::Component => Self::Component, - Ns::Value => Self::Value, + _ => unreachable!("not an outer alias namespace"), } } } -impl From for Ns { - fn from(kind: CoreAliasKind) -> Self { - match kind { - CoreAliasKind::Func => Ns::CoreFunc, - CoreAliasKind::Table => Ns::CoreTable, - CoreAliasKind::Memory => Ns::CoreMemory, - CoreAliasKind::Global => Ns::CoreGlobal, - CoreAliasKind::Tag => Ns::CoreTag, - CoreAliasKind::Type => Ns::CoreType, - CoreAliasKind::Module => Ns::CoreModule, - CoreAliasKind::Instance => Ns::CoreInstance, +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: AliasKind) -> Self { +impl From for Ns { + fn from(kind: ComponentOuterAliasKind) -> Self { match kind { - AliasKind::Core(kind) => kind.into(), - AliasKind::Func => Ns::Func, - AliasKind::Value => Ns::Value, - AliasKind::Type => Ns::Type, - AliasKind::Instance => Ns::Instance, - AliasKind::Component => Ns::Component, + ComponentOuterAliasKind::CoreModule => Self::CoreModule, + ComponentOuterAliasKind::CoreType => Self::CoreType, + ComponentOuterAliasKind::Type => Self::Type, + ComponentOuterAliasKind::Component => Self::Component, } } } diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index e897870c0c..2c7f22641d 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -686,7 +686,7 @@ impl<'a> Parse<'a> for ComponentTypeDecl<'a> { } else if l.peek::() { Ok(Self::Type(parser.parse()?)) } else if l.peek::() { - Ok(Self::Alias(Alias::parse_outer(parser)?)) + Ok(Self::Alias(Alias::parse_outer_type_alias(parser)?)) } else if l.peek::() { Ok(Self::Import(parser.parse()?)) } else if l.peek::() { @@ -744,7 +744,7 @@ impl<'a> Parse<'a> for InstanceTypeDecl<'a> { } else if l.peek::() { Ok(Self::Type(parser.parse()?)) } else if l.peek::() { - Ok(Self::Alias(Alias::parse_outer(parser)?)) + Ok(Self::Alias(Alias::parse_outer_type_alias(parser)?)) } else if l.peek::() { Ok(Self::Export(parser.parse()?)) } else { @@ -792,7 +792,7 @@ impl Default for CoreTypeUse<'_, T> { Self::Ref(CoreItemRef { idx: Index::Num(0, span), kind: kw::r#type(span), - export_names: Vec::new(), + export_name: None, }) } } diff --git a/tests/local/component-model/instance-type.wast b/tests/local/component-model/instance-type.wast index cf3dcaace2..dd597dacc2 100644 --- a/tests/local/component-model/instance-type.wast +++ b/tests/local/component-model/instance-type.wast @@ -196,7 +196,7 @@ (type (instance (export "" (core module (type $t))) ))) - "outer aliases can only be made to modules, components, and component types") + "core type index 0 is not a module type") (assert_invalid (component diff --git a/tests/local/component-model/invalid.wast b/tests/local/component-model/invalid.wast index 471a61085f..85b60d9493 100644 --- a/tests/local/component-model/invalid.wast +++ b/tests/local/component-model/invalid.wast @@ -15,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/types.wast b/tests/local/component-model/types.wast index c901940a00..eb41231e0c 100644 --- a/tests/local/component-model/types.wast +++ b/tests/local/component-model/types.wast @@ -35,7 +35,7 @@ (import "" (core module (type $t))) )) ) - "outer aliases can only be made to modules, components, and component types") + "core type index 0 is not a module type") (assert_invalid (component diff --git a/tests/local/component-model/virtualize.wast b/tests/local/component-model/virtualize.wast index 72798b6619..538866fa27 100644 --- a/tests/local/component-model/virtualize.wast +++ b/tests/local/component-model/virtualize.wast @@ -1,6 +1,4 @@ (component - ;; TODO: ideally share this same core libc instance between all subcomponents - ;; this isn't currently possible with the component model proposal (core module $libc (memory (export "mem") 0) (func (export "realloc") (param i32 i32 i32 i32) (result i32) @@ -8,23 +6,15 @@ ) ) (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))) )) - ;; TODO: see comment above - (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 $m (import "wasi-file" "read" (func $read (param i32 i32))) (func $play (export "play") @@ -75,6 +65,7 @@ (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)))) @@ -88,14 +79,6 @@ )) (import "wasi_file" (instance $real-wasi (type $WasiFile))) - ;; TODO: see comment above - (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 From a30fed61cd7d8dc15093dc68b59ef1c480e74ab2 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 6 Jun 2022 22:38:54 -0700 Subject: [PATCH 25/33] wasm-smith: encode arbitrary outer aliases for core types. This commit encodes arbitrary outer aliases to core types when creating arbitrary component and instance types in the component type section. It also fixes a bug where `scalar_component_funcs` were storing indexes into `funcs` and not `component_funcs`, causing lowered functions to encode with potentially out-of-bounds component function indexes. --- crates/wasm-smith/src/component.rs | 89 ++++++++++++++--------- crates/wasm-smith/src/component/encode.rs | 14 ++++ 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/crates/wasm-smith/src/component.rs b/crates/wasm-smith/src/component.rs index 8db475b464..712741a118 100644 --- a/crates/wasm-smith/src/component.rs +++ b/crates/wasm-smith/src/component.rs @@ -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)] @@ -123,7 +130,7 @@ struct ComponentContext { // Which entries in `funcs` are component functions? component_funcs: Vec, - // Which entries in `funcs` are component functions that only use scalar + // Which entries in `component_funcs` are component functions that only use scalar // types? scalar_component_funcs: Vec, @@ -1049,19 +1056,24 @@ impl ComponentBuilder { } // 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 { + kind: OuterAliasKind::Type(ty), + .. + } => me.current_type_scope_mut().push(ty.clone()), Alias::Outer { - count, - i, - kind: OuterAliasKind::Type(_), - } => (count, i), + 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)) }); } @@ -1090,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(), @@ -1099,17 +1111,22 @@ 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( @@ -1369,16 +1386,18 @@ impl ComponentBuilder { Type::Func(ty) => ty.clone(), _ => unreachable!(), }; - let is_scalar = func_ty.is_scalar(); + + 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(func_ty)); self.component_mut().component_funcs.push(func_index); - if is_scalar { - self.component_mut().scalar_component_funcs.push(func_index); - } } ComponentTypeRef::Value(ty) => { self.total_values += 1; @@ -1406,11 +1425,14 @@ impl ComponentBuilder { } } + 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 { - match &self.component().funcs[func_index as usize] { - ComponentOrCoreFuncType::Component(ty) => ty, - ComponentOrCoreFuncType::Core(_) => panic!("not a component function"), - } + self.component().funcs[self.component().component_funcs[func_index as usize] as usize] + .as_component() } fn push_func(&mut self, func: Func) { @@ -1427,11 +1449,12 @@ impl ComponentBuilder { let ty = match &func { Func::CanonLift { func_ty, .. } => { - self.component_mut().component_funcs.push(func_index); let ty = Rc::clone(self.current_type_scope().get_func(*func_ty)); if ty.is_scalar() { + 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 { @@ -1540,11 +1563,8 @@ impl ComponentBuilder { let core_func_index = u.int_in_range( 0..=u32::try_from(c.component().core_funcs.len() - 1).unwrap(), )?; - let core_func_ty = c.component().funcs - [c.component().core_funcs[core_func_index as usize] as usize] - .clone() - .unwrap_core(); - let comp_func_ty = inverse_scalar_canonical_abi_for(u, &core_func_ty)?; + 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() @@ -1825,6 +1845,7 @@ enum InstanceExportAliasKind { enum OuterAliasKind { Module, Component, + CoreType(Rc), Type(Rc), } diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index 8a6b534780..eee6100c94 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -178,6 +178,13 @@ 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!(), } } @@ -203,6 +210,13 @@ 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!(), } } From e3325ca2f0f1920936fc3e0c12da9e730c87e8fb Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 6 Jun 2022 22:57:30 -0700 Subject: [PATCH 26/33] wasm-encoder: remove unnecessary `Export` type. This commit removes the core `Export` type, which is simply the same enumeration as `ExportKind`, but paired with the exported item's index. Instead, encoding takes both the kind and index rather than an `Export`. With this change, encoding core exports functions like component exports in `wasm-encoder`. Also fixed where `Export` was used in the other tools. --- .../wasm-encoder/src/component/instances.rs | 13 ++--- crates/wasm-encoder/src/core/exports.rs | 53 ++----------------- crates/wasm-encoder/src/lib.rs | 4 +- .../wasm-mutate/src/mutators/remove_export.rs | 10 ++-- .../wasm-mutate/src/mutators/remove_item.rs | 14 ++--- .../wasm-mutate/src/mutators/rename_export.rs | 10 ++-- crates/wasm-smith/src/core.rs | 38 ++++++------- crates/wasm-smith/src/core/encode.rs | 4 +- crates/wast/src/component/binary.rs | 18 ++++--- 9 files changed, 62 insertions(+), 102 deletions(-) diff --git a/crates/wasm-encoder/src/component/instances.rs b/crates/wasm-encoder/src/component/instances.rs index 34f7d94998..000a872d6b 100644 --- a/crates/wasm-encoder/src/component/instances.rs +++ b/crates/wasm-encoder/src/component/instances.rs @@ -1,6 +1,6 @@ use super::CORE_INSTANCE_SORT; use crate::{ - encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, Export, + encode_section, ComponentExportKind, ComponentSection, ComponentSectionId, Encode, ExportKind, }; /// Represents an argument to a module instantiation. @@ -25,10 +25,10 @@ impl Encode for ModuleArg { /// # Example /// /// ```rust -/// use wasm_encoder::{Component, InstanceSection, Export, ModuleArg}; +/// use wasm_encoder::{Component, InstanceSection, ExportKind, ModuleArg}; /// /// let mut instances = InstanceSection::new(); -/// instances.export_items([("foo", Export::Func(0))]); +/// instances.export_items([("foo", ExportKind::Func, 0)]); /// instances.instantiate(1, [("foo", ModuleArg::Instance(0))]); /// /// let mut component = Component::new(); @@ -79,15 +79,16 @@ impl InstanceSection { /// Define an instance by exporting core WebAssembly items. pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self where - E: IntoIterator, + 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.encode(&mut self.bytes); + kind.encode(&mut self.bytes); + index.encode(&mut self.bytes); } self.num_added += 1; self diff --git a/crates/wasm-encoder/src/core/exports.rs b/crates/wasm-encoder/src/core/exports.rs index 46da9aecb9..0b8006655f 100644 --- a/crates/wasm-encoder/src/core/exports.rs +++ b/crates/wasm-encoder/src/core/exports.rs @@ -30,59 +30,15 @@ impl Encode for ExportKind { } } -/// Represents an export from a WebAssembly module. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum Export { - /// The export is a function. - Func(u32), - /// The export is a table. - Table(u32), - /// The export is a memory. - Memory(u32), - /// The export is a global. - Global(u32), - /// The export is a tag. - /// - /// This variant is used with the exception handling proposal. - Tag(u32), -} - -impl Export { - /// Gets the kind of the export. - pub fn kind(&self) -> ExportKind { - match self { - Self::Func(_) => ExportKind::Func, - Self::Table(_) => ExportKind::Table, - Self::Memory(_) => ExportKind::Memory, - Self::Global(_) => ExportKind::Global, - Self::Tag(_) => ExportKind::Tag, - } - } - - /// Gets the index of the export. - fn index(&self) -> u32 { - match self { - Self::Func(i) | Self::Table(i) | Self::Memory(i) | Self::Global(i) | Self::Tag(i) => *i, - } - } -} - -impl Encode for Export { - fn encode(&self, sink: &mut Vec) { - self.kind().encode(sink); - self.index().encode(sink); - } -} - /// An encoder for the export section of WebAssembly module. /// /// # Example /// /// ```rust -/// use wasm_encoder::{Module, ExportSection, Export}; +/// use wasm_encoder::{Module, ExportSection, ExportKind}; /// /// let mut exports = ExportSection::new(); -/// exports.export("foo", Export::Func(0)); +/// exports.export("foo", ExportKind::Func, 0); /// /// let mut module = Module::new(); /// module.section(&exports); @@ -112,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 } diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs index b17261214d..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::Func(0)); +//! exports.export("f", ExportKind::Func, 0); //! module.section(&exports); //! //! // Encode the code section. diff --git a/crates/wasm-mutate/src/mutators/remove_export.rs b/crates/wasm-mutate/src/mutators/remove_export.rs index ebed27132d..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::Func(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 14547f142a..77d8c1f08b 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -253,22 +253,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::Func(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 e0be9ccc09..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::Func(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-smith/src/core.rs b/crates/wasm-smith/src/core.rs index 284238fe4e..85c8ef773b 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, @@ -700,16 +700,16 @@ impl Module { Ok(true) } - fn type_of(&self, item: &Export) -> EntityType { - match *item { - Export::Global(idx) => EntityType::Global(self.globals[idx as usize]), - Export::Memory(idx) => EntityType::Memory(self.memories[idx as usize]), - Export::Table(idx) => EntityType::Table(self.tables[idx as usize]), - Export::Func(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()), } } @@ -897,25 +897,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::Func(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(), ); @@ -932,7 +932,7 @@ 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.is_empty()); if choices.is_empty() { @@ -943,10 +943,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) }, ) 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/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index bc15b80248..28c8ae410e 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -177,8 +177,10 @@ impl Encoder { ); } CoreInstanceKind::BundleOfExports(exports) => { - self.core_instances - .export_items(exports.iter().map(|e| (e.name, (&e.item).into()))); + self.core_instances.export_items(exports.iter().map(|e| { + let (kind, index) = (&e.item).into(); + (e.name, kind, index) + })); } } @@ -512,14 +514,14 @@ impl From<&CoreInstantiationArgKind<'_>> for wasm_encoder::ModuleArg { } } -impl From<&CoreItemRef<'_, core::ExportKind>> for wasm_encoder::Export { +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::Export::Func(item.idx.into()), - core::ExportKind::Table => wasm_encoder::Export::Table(item.idx.into()), - core::ExportKind::Memory => wasm_encoder::Export::Memory(item.idx.into()), - core::ExportKind::Global => wasm_encoder::Export::Global(item.idx.into()), - core::ExportKind::Tag => wasm_encoder::Export::Tag(item.idx.into()), + 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()), } } } From 14c1a3e323b84db28145b36ed42e32c2664c057d Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 6 Jun 2022 23:07:58 -0700 Subject: [PATCH 27/33] wast: add missing version for wasm-encoder reference. --- crates/wast/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index e529a1bd8b..cb8a5c874f 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -16,7 +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 = { path = "../wasm-encoder" } +wasm-encoder = { version = "0.12.0", path = "../wasm-encoder" } [dev-dependencies] anyhow = "1.0" From 2e1f7365aad1383cb29ae02304b6aaf05d02f753 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Mon, 6 Jun 2022 23:27:06 -0700 Subject: [PATCH 28/33] wasmparser: remove `Module` from `TypeRef`. This commit removes the `Module` variant from `TypeRef` as it is no longer needed to support the component model proposal. --- crates/dump/src/lib.rs | 3 --- crates/wasm-mutate/src/info.rs | 5 +---- crates/wasm-mutate/src/mutators/remove_item.rs | 1 - crates/wasm-smith/src/core.rs | 2 -- crates/wasmparser/src/readers/core/imports.rs | 6 ------ crates/wasmparser/src/validator/core.rs | 8 -------- crates/wasmprinter/src/lib.rs | 2 -- 7 files changed, 1 insertion(+), 26 deletions(-) diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index 0855658a89..0c6e8421c9 100644 --- a/crates/dump/src/lib.rs +++ b/crates/dump/src/lib.rs @@ -108,9 +108,6 @@ impl<'a> Dump<'a> { TypeRef::Global(_) => { write!(me.state, "[global {}]", inc(&mut i.core_globals))? } - TypeRef::Module(_) => { - write!(me.state, "[module {}]", inc(&mut i.core_modules))? - } } write!(me.state, " {:?}", imp)?; me.print(end) diff --git a/crates/wasm-mutate/src/info.rs b/crates/wasm-mutate/src/info.rs index fb21ffb2b0..50e7d12cd6 100644 --- a/crates/wasm-mutate/src/info.rs +++ b/crates/wasm-mutate/src/info.rs @@ -1,6 +1,6 @@ use crate::{ module::{PrimitiveTypeInfo, TypeInfo}, - Error, Result, + Result, }; use std::collections::HashSet; use std::convert::TryFrom; @@ -130,9 +130,6 @@ impl<'a> ModuleInfo<'a> { info.tag_count += 1; info.imported_tags_count += 1; } - wasmparser::TypeRef::Module(_) => { - return Err(Error::unsupported("module imports are not supported")) - } } } } diff --git a/crates/wasm-mutate/src/mutators/remove_item.rs b/crates/wasm-mutate/src/mutators/remove_item.rs index 77d8c1f08b..2d953c2624 100644 --- a/crates/wasm-mutate/src/mutators/remove_item.rs +++ b/crates/wasm-mutate/src/mutators/remove_item.rs @@ -191,7 +191,6 @@ impl RemoveItem { } tag += 1; } - wasmparser::TypeRef::Module(_) => return Err(Error::unsupported("module imports are not supported")), } } module.section(&result); diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index 85c8ef773b..f440cc12f0 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -682,8 +682,6 @@ impl Module { self.globals.push(global_ty); entity } - - wasmparser::TypeRef::Module(_) => unimplemented!(), }; new_imports.push(Import { module: import.module.to_string(), diff --git a/crates/wasmparser/src/readers/core/imports.rs b/crates/wasmparser/src/readers/core/imports.rs index db97b530cc..a8a7a5d5ae 100644 --- a/crates/wasmparser/src/readers/core/imports.rs +++ b/crates/wasmparser/src/readers/core/imports.rs @@ -38,12 +38,6 @@ pub enum TypeRef { /// /// The value is an index in the types index space. Tag(TagType), - /// The type is a module. - /// - /// The value is an index into the the type section. - /// - /// This variant is currently only used with the component model proposal. - Module(u32), } /// Represents an import in a WebAssembly module. diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index e2d86aa72c..02ea87df35 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -450,7 +450,6 @@ impl Module { self.num_imported_globals += 1; (self.globals.len(), MAX_WASM_GLOBALS, "globals") } - TypeRef::Module(_) => unreachable!(), }; check_max(len, 0, max, desc, offset)?; @@ -593,13 +592,6 @@ impl Module { self.check_global_type(t, features, offset)?; EntityType::Global(*t) } - TypeRef::Module(_) => { - // Currently an error, but may be supported with a future module linking proposal. - return Err(BinaryReaderError::new( - "modules cannot import other modules", - offset, - )); - } }) } diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 9c69fdf215..b0b8c1080e 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -761,7 +761,6 @@ impl Printer { TypeRef::Memory(_) => state.core.memories += 1, TypeRef::Tag(_) => state.core.tags += 1, TypeRef::Global(_) => state.core.globals += 1, - TypeRef::Module(_) => bail!("core module imports are not supported"), } } Ok(()) @@ -804,7 +803,6 @@ impl Printer { 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)?, - TypeRef::Module(_) => bail!("core module imports are not supported"), } self.end_group(); Ok(()) From 31e4eade6718afd7128c92415af639d29fb9bc00 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Tue, 7 Jun 2022 00:04:48 -0700 Subject: [PATCH 29/33] Replace any references to "defaults_to" with "refines". This commit updates any remaining place that used the old "defaults to" terminology for variant cases in the component model. --- crates/wasm-encoder/src/component/types.rs | 4 ++-- crates/wasm-smith/src/component/encode.rs | 2 +- crates/wasmparser/src/binary_reader.rs | 2 +- crates/wasmparser/src/readers/component/types.rs | 4 ++-- crates/wasmparser/src/validator/component.rs | 8 ++++---- crates/wasmparser/src/validator/types.rs | 10 +++++----- crates/wasmprinter/src/lib.rs | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index f23a1ef885..c8041e4343 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -355,10 +355,10 @@ impl ComponentDefinedTypeEncoder<'_> { 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 { diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index eee6100c94..0fdab06046 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -237,7 +237,7 @@ impl DefinedType { enc.variant( ty.cases .iter() - .map(|(ty, default_to)| (ty.name.as_str(), ty.ty, *default_to)), + .map(|(ty, refines)| (ty.name.as_str(), ty.ty, *refines)), ); } Self::List(ty) => { diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index c78d84127d..c14e2f3941 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -412,7 +412,7 @@ impl<'a> BinaryReader<'a> { Ok(VariantCase { name: self.read_string()?, ty: self.read_component_val_type()?, - default_to: match self.read_u8()? { + refines: match self.read_u8()? { 0x0 => None, 0x1 => Some(self.read_var_u32()?), x => return self.invalid_leading_byte(x, "variant case default"), diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 8c6b2d145c..074982a8da 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -155,8 +155,8 @@ pub struct VariantCase<'a> { pub name: &'a str, /// The value type of the variant case. pub ty: ComponentValType, - /// The default-to case index to use when this case is not present. - pub default_to: Option, + /// The index of the variant case that is refined by this one. + pub refines: Option, } /// Represents a defined type in a WebAssembly component. diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index 646347285a..bd24452515 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -1651,10 +1651,10 @@ impl ComponentState { .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, )); } @@ -1665,7 +1665,7 @@ impl ComponentState { 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()), }, )) }) diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs index faf59eb968..e079ea8fae 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -703,8 +703,8 @@ impl ComponentFuncType { pub struct VariantCase { /// The variant case type. pub ty: ComponentValType, - /// The value of the variant to default to. - pub default_to: Option, + /// The name of the variant case refined by this one. + pub refines: Option, } /// Represents a record type. @@ -815,9 +815,9 @@ impl ComponentDefinedType { 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 { diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index b0b8c1080e..71ee76c9de 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -2297,7 +2297,7 @@ impl Printer { self.result.push(' '); self.print_component_val_type(state, &case.ty)?; - if let Some(default) = case.default_to { + if let Some(default) = case.refines { match cases.get(default as usize) { Some(default) => { self.start_group("refines "); @@ -2305,7 +2305,7 @@ impl Printer { self.end_group(); } None => { - bail!("variant case default index out of bounds"); + bail!("variant case refines index out of bounds"); } } } From a3e18e70b428e8e54700eac01ea3fd87613980c1 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Tue, 7 Jun 2022 11:37:21 -0700 Subject: [PATCH 30/33] wast: implement identifier resolution for variant cases. This commit updates the parsing and resolution of variant cases for the `refines` clause. Variant cases may now have an optional identifier on them, which is referred to in a `refines` clause, rather than having to use the variant name string. This makes it clearer to users of the text format that a resolution is taking place. --- crates/wasmprinter/src/lib.rs | 21 +++++++--------- crates/wast/src/component/binary.rs | 2 +- crates/wast/src/component/resolve.rs | 17 +++++++------ crates/wast/src/component/types.rs | 19 +++++++++------ tests/local/component-model/definedtypes.wast | 24 +++++++++++++++---- 5 files changed, 49 insertions(+), 34 deletions(-) diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 71ee76c9de..06d6137411 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -2290,24 +2290,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_component_val_type(state, &case.ty)?; - if let Some(default) = case.refines { - match cases.get(default as usize) { - Some(default) => { - self.start_group("refines "); - self.print_str(default.name)?; - self.end_group(); - } - None => { - bail!("variant case refines index out of bounds"); - } - } + 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() } diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 28c8ae410e..c59a2f40c7 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -599,7 +599,7 @@ impl From for wasm_encoder::PrimitiveValType { impl From<&Refinement<'_>> for u32 { fn from(r: &Refinement) -> Self { match r { - Refinement::Named(..) => unreachable!("should be expanded by now"), + Refinement::Id(..) => unreachable!("should be resolved by now"), Refinement::Index(i) => *i, } } diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index df049d0eef..97ecaad226 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -393,24 +393,23 @@ impl<'a> Resolver<'a> { } } ComponentDefinedType::Variant(v) => { - let names: Vec<_> = v.cases.iter().map(|c| c.name).collect(); - + // Namespace for case identifier resolution + let mut ns = Namespace::default(); for case in v.cases.iter_mut() { + 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::Named(span, name) = refines { - if *name == case.name { + if let Refinement::Id(span, id) = refines { + let resolved = ns.resolve(&mut Index::Id(*id), "variant case")?; + if resolved == index { return Err(Error::new( *span, "variant case cannot refine itself".to_string(), )); } - let index = names.iter().position(|n| n == name).ok_or_else(|| { - Error::new(*span, format!("variant case `{}` not found", name)) - })?; - - *refines = Refinement::Index(index as u32); + *refines = Refinement::Index(resolved); } } } diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index 2c7f22641d..ab5139f0f1 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -399,10 +399,13 @@ impl<'a> Parse<'a> for Variant<'a> { /// A case of a variant type. #[derive(Debug)] pub struct VariantCase<'a> { - /// The name of the case. - pub name: &'a str, /// 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. @@ -412,6 +415,7 @@ pub struct VariantCase<'a> { 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() { @@ -420,8 +424,9 @@ impl<'a> Parse<'a> for VariantCase<'a> { None }; Ok(Self { - name, span, + id, + name, ty, refines, }) @@ -431,8 +436,8 @@ impl<'a> Parse<'a> for VariantCase<'a> { /// A refinement for a variant case. #[derive(Debug)] pub enum Refinement<'a> { - /// The refinement is named. - Named(Span, &'a str), + /// The refinement is referenced by identifier. + Id(Span, Id<'a>), /// The refinement has been resolved to an index into /// the cases of the variant. Index(u32), @@ -442,8 +447,8 @@ impl<'a> Parse<'a> for Refinement<'a> { fn parse(parser: Parser<'a>) -> Result { parser.parens(|parser| { let span = parser.parse::()?.0; - let name = parser.parse()?; - Ok(Self::Named(span, name)) + let id = parser.parse()?; + Ok(Self::Id(span, id)) }) } } diff --git a/tests/local/component-model/definedtypes.wast b/tests/local/component-model/definedtypes.wast index 16d4c4ece4..7edf11f17c 100644 --- a/tests/local/component-model/definedtypes.wast +++ b/tests/local/component-model/definedtypes.wast @@ -21,8 +21,7 @@ (type $A15a (variant)) (type $A15b (variant (case "x" unit))) (type $A15c (variant (case "x" $A1))) - - (type $A15d (variant (case "x" unit (refines "y")) (case "y" string))) + (type $A15e (variant (case $x "x" unit) (case $y "y" string (refines $x)) (case "z" string (refines $y)))) (type $A16a (list unit)) (type $A16b (list $A3)) @@ -52,17 +51,32 @@ (assert_invalid (component - (type $t (variant (case "x" string (refines "x")))) + (type $t (variant (case $x "x" string (refines $x)))) ) "variant case cannot refine itself" ) +(assert_invalid + (component + (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 "z")))) + (type $v (variant (case $x "x" $t) (case $x "y" $t))) ) - "variant case `z` not found" + "duplicate variant case identifier" ) (assert_invalid From db1f4685323ba7963a018de366ec7e29e494835a Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Tue, 7 Jun 2022 12:16:26 -0700 Subject: [PATCH 31/33] wasmparser: move component core type reading to a separate reader. This commit moves the component core type reading from `TypeSectionReader` into a new reader called `CoreTypeSectionReader`. By doing so, we prevent the parsing of modules from supporting core types currently only supported in components. --- crates/dump/src/lib.rs | 5 + crates/wasm-mutate/src/module.rs | 7 +- crates/wasm-mutate/src/mutators/add_type.rs | 5 - crates/wasm-mutate/src/mutators/translate.rs | 1 - crates/wasm-smith/src/core.rs | 1 - crates/wasm-smith/tests/core.rs | 1 - crates/wasmparser/benches/benchmark.rs | 5 + crates/wasmparser/src/binary_reader.rs | 15 +- crates/wasmparser/src/parser.rs | 10 +- .../wasmparser/src/readers/component/types.rs | 121 ++++++- crates/wasmparser/src/readers/core/types.rs | 33 +- crates/wasmparser/src/validator.rs | 320 +++++++++--------- crates/wasmparser/src/validator/component.rs | 6 +- crates/wasmparser/src/validator/core.rs | 7 - crates/wasmprinter/src/lib.rs | 78 +++-- src/bin/wasm-tools/objdump.rs | 5 +- tests/dump/alias2.wat.dump | 4 +- .../component-inline-export-import.wat.dump | 4 +- tests/dump/component-inline-type.wat.dump | 4 +- tests/dump/component-linking.wat.dump | 4 +- tests/dump/import-modules.wat.dump | 4 +- tests/dump/module-types.wat.dump | 4 +- 22 files changed, 380 insertions(+), 264 deletions(-) diff --git a/crates/dump/src/lib.rs b/crates/dump/src/lib.rs index 0c6e8421c9..0ebef3a498 100644 --- a/crates/dump/src/lib.rs +++ b/crates/dump/src/lib.rs @@ -268,6 +268,11 @@ impl<'a> Dump<'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, diff --git a/crates/wasm-mutate/src/module.rs b/crates/wasm-mutate/src/module.rs index 0e1efded95..024cb6c1f6 100644 --- a/crates/wasm-mutate/src/module.rs +++ b/crates/wasm-mutate/src/module.rs @@ -40,10 +40,10 @@ impl From for PrimitiveTypeInfo { } } -impl TryFrom> for TypeInfo { +impl TryFrom for TypeInfo { type Error = Error; - fn try_from(value: wasmparser::Type<'_>) -> Result { + fn try_from(value: wasmparser::Type) -> Result { match value { wasmparser::Type::Func(ft) => Ok(TypeInfo::Func(FuncInfo { params: ft @@ -57,9 +57,6 @@ impl TryFrom> for TypeInfo { .map(|&t| PrimitiveTypeInfo::from(t)) .collect(), })), - wasmparser::Type::Module(_) => Err(Error::unsupported( - "module types in core sections are not supported", - )), } } } diff --git a/crates/wasm-mutate/src/mutators/add_type.rs b/crates/wasm-mutate/src/mutators/add_type.rs index 22ee398cba..67e6ea59d0 100644 --- a/crates/wasm-mutate/src/mutators/add_type.rs +++ b/crates/wasm-mutate/src/mutators/add_type.rs @@ -70,11 +70,6 @@ impl Mutator for AddTypeMutator { .collect::, _>>()?; types.function(params, results); } - wasmparser::Type::Module(_) => { - return Err(crate::Error::unsupported( - "module types in core sections are not supported", - )); - } } } // And then add our new type. diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index ca186481c0..e108b6ac10 100644 --- a/crates/wasm-mutate/src/mutators/translate.rs +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -131,7 +131,6 @@ pub fn type_def(t: &mut dyn Translator, ty: Type, s: &mut TypeSection) -> Result ); Ok(()) } - Type::Module(_) => Err(Error::unsupported("module types are not supported")), } } diff --git a/crates/wasm-smith/src/core.rs b/crates/wasm-smith/src/core.rs index f440cc12f0..43edf8c626 100644 --- a/crates/wasm-smith/src/core.rs +++ b/crates/wasm-smith/src/core.rs @@ -591,7 +591,6 @@ impl Module { new_types.push(Type::Func(Rc::clone(&func_type))); new_index } - Some((wasmparser::Type::Module(_), _)) => unimplemented!(), }; match &new_types[serialized_sig_idx - first_type_index] { Type::Func(f) => Some((serialized_sig_idx as u32, Rc::clone(f))), diff --git a/crates/wasm-smith/tests/core.rs b/crates/wasm-smith/tests/core.rs index 84d30b16e0..1acff647a6 100644 --- a/crates/wasm-smith/tests/core.rs +++ b/crates/wasm-smith/tests/core.rs @@ -132,7 +132,6 @@ fn smoke_test_imports_config() { while let Ok(ty) = rdr.read() { match ty { wasmparser::Type::Func(ft) => sig_types.push(ft), - wasmparser::Type::Module(_) => unreachable!(), } } } else if let wasmparser::Payload::ImportSection(mut rdr) = payload { diff --git a/crates/wasmparser/benches/benchmark.rs b/crates/wasmparser/benches/benchmark.rs index 789ba1c9ef..4cf2411d21 100644 --- a/crates/wasmparser/benches/benchmark.rs +++ b/crates/wasmparser/benches/benchmark.rs @@ -168,6 +168,11 @@ fn read_all_wasm(wasm: &[u8]) -> Result<()> { item?; } } + CoreTypeSection(s) => { + for item in s { + item?; + } + } ComponentSection { .. } => {} ComponentInstanceSection(s) => { for item in s { diff --git a/crates/wasmparser/src/binary_reader.rs b/crates/wasmparser/src/binary_reader.rs index c14e2f3941..5cdc72b00c 100644 --- a/crates/wasmparser/src/binary_reader.rs +++ b/crates/wasmparser/src/binary_reader.rs @@ -280,18 +280,25 @@ impl<'a> BinaryReader<'a> { }) } - pub(crate) fn read_type(&mut self) -> Result> { + pub(crate) fn read_type(&mut self) -> Result { Ok(match self.read_u8()? { 0x60 => Type::Func(self.read_func_type()?), + x => return self.invalid_leading_byte(x, "type"), + }) + } + + pub(crate) fn read_core_type(&mut self) -> Result> { + Ok(match self.read_u8()? { + 0x60 => CoreType::Func(self.read_func_type()?), 0x50 => { let size = self.read_size(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")?; - Type::Module( + CoreType::Module( (0..size) .map(|_| self.read_module_type_decl()) .collect::>()?, ) } - x => return self.invalid_leading_byte(x, "type"), + x => return self.invalid_leading_byte(x, "core type"), }) } @@ -377,7 +384,7 @@ impl<'a> BinaryReader<'a> { pub(crate) fn read_instance_type_decl(&mut self) -> Result> { Ok(match self.read_u8()? { - 0x00 => InstanceTypeDeclaration::CoreType(self.read_type()?), + 0x00 => InstanceTypeDeclaration::CoreType(self.read_core_type()?), 0x01 => InstanceTypeDeclaration::Type(self.read_component_type()?), 0x02 => InstanceTypeDeclaration::Alias(self.read_component_alias()?), 0x04 => InstanceTypeDeclaration::Export { diff --git a/crates/wasmparser/src/parser.rs b/crates/wasmparser/src/parser.rs index 5ff7a15145..4a148029b1 100644 --- a/crates/wasmparser/src/parser.rs +++ b/crates/wasmparser/src/parser.rs @@ -1,3 +1,4 @@ +use crate::CoreTypeSectionReader; use crate::{ limits::MAX_WASM_MODULE_SIZE, AliasSectionReader, BinaryReader, BinaryReaderError, ComponentAliasSectionReader, ComponentCanonicalSectionReader, ComponentExportSectionReader, @@ -213,6 +214,11 @@ pub enum Payload<'a> { /// /// 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. /// @@ -400,6 +406,7 @@ impl Parser { /// ModuleSection { .. } => { /* ... */ } /// InstanceSection(_) => { /* ... */ } /// AliasSection(_) => { /* ... */ } + /// CoreTypeSection(_) => { /* ... */ } /// ComponentSection { .. } => { /* ... */ } /// ComponentInstanceSection(_) => { /* ... */ } /// ComponentAliasSection(_) => { /* ... */ } @@ -626,7 +633,7 @@ impl Parser { section(reader, len, AliasSectionReader::new, AliasSection) } (Encoding::Component, 4) => { - section(reader, len, TypeSectionReader::new, TypeSection) + section(reader, len, CoreTypeSectionReader::new, CoreTypeSection) } // Section 5 handled above (Encoding::Component, 6) => section( @@ -985,6 +992,7 @@ impl fmt::Debug for Payload<'_> { .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) diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index 074982a8da..8dc09d4967 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -1,9 +1,122 @@ use crate::{ - BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, Result, - SectionIteratorLimited, SectionReader, SectionWithLimitedItems, Type, + BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, FuncType, Import, Result, + SectionIteratorLimited, SectionReader, SectionWithLimitedItems, Type, TypeRef, }; use std::ops::Range; +/// Represents a core type in a WebAssembly component. +#[derive(Debug, Clone)] +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 declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ModuleTypeDeclaration<'a> { + /// The module type definition is for a type. + Type(Type), + /// The module type definition is for an export. + Export { + /// The name of the exported item. + name: &'a str, + /// The type reference of the export. + ty: TypeRef, + }, + /// The module type definition is for an import. + Import(Import<'a>), +} + +/// A reader for the core type section of a WebAssembly component. +#[derive(Clone)] +pub struct CoreTypeSectionReader<'a> { + reader: BinaryReader<'a>, + count: 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() + } +} + +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 value type in a WebAssembly component. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ComponentValType { @@ -105,7 +218,7 @@ pub enum ComponentType<'a> { #[derive(Debug, Clone)] pub enum ComponentTypeDeclaration<'a> { /// The component type declaration is for a core type. - CoreType(Type<'a>), + CoreType(CoreType<'a>), /// The component type declaration is for a type. Type(ComponentType<'a>), /// The component type declaration is for an alias. @@ -125,7 +238,7 @@ pub enum ComponentTypeDeclaration<'a> { #[derive(Debug, Clone)] pub enum InstanceTypeDeclaration<'a> { /// The component type declaration is for a core type. - CoreType(Type<'a>), + CoreType(CoreType<'a>), /// The instance type declaration is for a type. Type(ComponentType<'a>), /// The instance type declaration is for an alias. diff --git a/crates/wasmparser/src/readers/core/types.rs b/crates/wasmparser/src/readers/core/types.rs index 91e80fb449..bff2079ea3 100644 --- a/crates/wasmparser/src/readers/core/types.rs +++ b/crates/wasmparser/src/readers/core/types.rs @@ -13,10 +13,7 @@ * limitations under the License. */ -use crate::{ - BinaryReader, Import, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems, - TypeRef, -}; +use crate::{BinaryReader, Result, SectionIteratorLimited, SectionReader, SectionWithLimitedItems}; use std::ops::Range; /// Represents the types of values in a WebAssembly module. @@ -40,29 +37,9 @@ pub enum ValType { /// Represents a type in a WebAssembly module. #[derive(Debug, Clone)] -pub enum Type<'a> { +pub enum Type { /// The type is for a function. Func(FuncType), - /// The type is for a module. - /// - /// Currently this variant is only used when parsing components. - Module(Box<[ModuleTypeDeclaration<'a>]>), -} - -/// Represents a module type declaration in a WebAssembly component. -#[derive(Debug, Clone)] -pub enum ModuleTypeDeclaration<'a> { - /// The module type definition is for a type. - Type(Type<'a>), - /// The module type definition is for an export. - Export { - /// The name of the exported item. - name: &'a str, - /// The type reference of the export. - ty: TypeRef, - }, - /// The module type definition is for an import. - Import(Import<'a>), } /// Represents a type of a function in a WebAssembly module. @@ -188,13 +165,13 @@ impl<'a> TypeSectionReader<'a> { /// println!("Type {:?}", ty); /// } /// ``` - pub fn read(&mut self) -> Result> { + pub fn read(&mut self) -> Result { self.reader.read_type() } } impl<'a> SectionReader for TypeSectionReader<'a> { - type Item = Type<'a>; + type Item = Type; fn read(&mut self) -> Result { Self::read(self) @@ -220,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/validator.rs b/crates/wasmparser/src/validator.rs index 7193b19a6b..f965af3d72 100644 --- a/crates/wasmparser/src/validator.rs +++ b/crates/wasmparser/src/validator.rs @@ -418,6 +418,7 @@ impl Validator { } 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())); @@ -495,55 +496,29 @@ impl Validator { /// Validates [`Payload::TypeSection`](crate::Payload). pub fn type_section(&mut self, section: &crate::TypeSectionReader<'_>) -> Result<()> { - self.state.ensure_parsable(section.range().start)?; - - match self.state { - State::Module => { - self.process_module_section( - Order::Type, - section, - "type", - |state, _, types, count, offset| { - check_max( - state.module.types.len(), - count, - MAX_WASM_TYPES, - "types", - offset, - )?; - types.reserve(count as usize); - state.module.assert_mut().types.reserve(count as usize); - Ok(()) - }, - |state, features, types, def, offset| { - state - .module - .assert_mut() - .add_type(def, features, types, offset, false /* checked above */) - }, - ) - } - State::Component => { - self.process_component_section( - section, - "core 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.core_types.reserve(count as usize); - Ok(()) - }, - |components, types, features, ty, offset| { - let current = components.last_mut().unwrap(); - current.add_core_type( - ty, features, types, offset, false, /* checked above */ - ) - }, - ) - } - _ => unreachable!(), - } + self.process_module_section( + Order::Type, + section, + "type", + |state, _, types, count, offset| { + check_max( + state.module.types.len(), + count, + MAX_WASM_TYPES, + "types", + offset, + )?; + types.reserve(count as usize); + state.module.assert_mut().types.reserve(count as usize); + Ok(()) + }, + |state, features, types, def, offset| { + state + .module + .assert_mut() + .add_type(def, features, types, offset, false /* checked above */) + }, + ) } /// Validates [`Payload::ImportSection`](crate::Payload). @@ -887,6 +862,118 @@ impl Validator { ) } + /// 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("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, + "core instance", + |components, _, count, offset| { + let current = components.last_mut().unwrap(); + check_max( + current.instance_count(), + count, + MAX_WASM_INSTANCES, + "instances", + offset, + )?; + current.core_instances.reserve(count as usize); + Ok(()) + }, + |components, types, _, instance, offset| { + components + .last_mut() + .unwrap() + .add_core_instance(instance, types, offset) + }, + ) + } + + /// Validates [`Payload::AliasSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + pub fn alias_section(&mut self, section: &crate::AliasSectionReader) -> Result<()> { + self.process_component_section( + section, + "core alias", + |_, _, _, _| Ok(()), // maximums checked via `add_alias` + |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { + components + .last_mut() + .unwrap() + .add_core_alias(alias, types, offset) + }, + ) + } + + /// Validates [`Payload::CoreTypeSection`](crate::Payload). + /// + /// This method should only be called when parsing a component. + pub fn core_type_section(&mut self, section: &crate::CoreTypeSectionReader<'_>) -> Result<()> { + self.process_component_section( + section, + "core 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.core_types.reserve(count as usize); + Ok(()) + }, + |components, types, features, ty, offset| { + let current = components.last_mut().unwrap(); + current.add_core_type(ty, features, types, offset, false /* checked above */) + }, + ) + } + + /// 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("component", range.start)?; + + let current = self.components.last_mut().unwrap(); + check_max( + current.components.len(), + 1, + MAX_WASM_COMPONENTS, + "components", + range.start, + )?; + + match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) { + State::Component => {} + _ => unreachable!(), + } + + Ok(()) + } + /// Validates [`Payload::ComponentInstanceSection`](crate::Payload). /// /// This method should only be called when parsing a component. @@ -960,26 +1047,6 @@ impl Validator { ) } - /// Validates [`Payload::ComponentImportSection`](crate::Payload). - /// - /// This method should only be called when parsing a component. - pub fn component_import_section( - &mut self, - section: &crate::ComponentImportSectionReader, - ) -> Result<()> { - self.process_component_section( - section, - "import", - |_, _, _, _| Ok(()), // add_import will check limits - |components, types, _, import, offset| { - components - .last_mut() - .unwrap() - .add_import(import, types, offset) - }, - ) - } - /// Validates [`Payload::ComponentCanonicalSection`](crate::Payload). /// /// This method should only be called when parsing a component. @@ -1025,76 +1092,42 @@ impl Validator { ) } - /// Validates [`Payload::ModuleSection`](crate::Payload). + /// Validates [`Payload::ComponentStartSection`](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("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(()) - } + pub fn component_start_section( + &mut self, + section: &crate::ComponentStartSectionReader, + ) -> Result<()> { + let range = section.range(); + self.state.ensure_component("start", range.start)?; - /// 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("component", range.start)?; + let f = section.clone().read()?; - let current = self.components.last_mut().unwrap(); - check_max( - current.components.len(), - 1, - MAX_WASM_COMPONENTS, - "components", + self.components.last_mut().unwrap().add_start( + f.func_index, + &f.arguments, + &self.types, range.start, - )?; - - match mem::replace(&mut self.state, State::Unparsed(Some(Encoding::Component))) { - State::Component => {} - _ => unreachable!(), - } - - Ok(()) + ) } - /// Validates [`Payload::InstanceSection`](crate::Payload). + /// Validates [`Payload::ComponentImportSection`](crate::Payload). /// /// This method should only be called when parsing a component. - pub fn instance_section(&mut self, section: &crate::InstanceSectionReader) -> Result<()> { + pub fn component_import_section( + &mut self, + section: &crate::ComponentImportSectionReader, + ) -> Result<()> { self.process_component_section( section, - "core instance", - |components, _, count, offset| { - let current = components.last_mut().unwrap(); - check_max( - current.instance_count(), - count, - MAX_WASM_INSTANCES, - "instances", - offset, - )?; - current.core_instances.reserve(count as usize); - Ok(()) - }, - |components, types, _, instance, offset| { + "import", + |_, _, _, _| Ok(()), // add_import will check limits + |components, types, _, import, offset| { components .last_mut() .unwrap() - .add_core_instance(instance, types, offset) + .add_import(import, types, offset) }, ) } @@ -1129,43 +1162,6 @@ impl Validator { ) } - /// Validates [`Payload::ComponentStartSection`](crate::Payload). - /// - /// This method should only be called when parsing a component. - pub fn component_start_section( - &mut self, - section: &crate::ComponentStartSectionReader, - ) -> Result<()> { - let range = section.range(); - self.state.ensure_component("start", range.start)?; - - let f = section.clone().read()?; - - self.components.last_mut().unwrap().add_start( - f.func_index, - &f.arguments, - &self.types, - range.start, - ) - } - - /// Validates [`Payload::AliasSection`](crate::Payload). - /// - /// This method should only be called when parsing a component. - pub fn alias_section(&mut self, section: &crate::AliasSectionReader) -> Result<()> { - self.process_component_section( - section, - "core alias", - |_, _, _, _| Ok(()), // maximums checked via `add_alias` - |components, types, _, alias, offset| -> Result<(), BinaryReaderError> { - components - .last_mut() - .unwrap() - .add_core_alias(alias, types, offset) - }, - ) - } - /// Validates [`Payload::UnknownSection`](crate::Payload). /// /// Currently always returns an error. diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index bd24452515..0168fb734b 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -60,15 +60,15 @@ impl ComponentState { pub fn add_core_type( &mut self, - ty: crate::Type, + ty: crate::CoreType, features: &WasmFeatures, types: &mut TypeList, offset: usize, check_limit: bool, ) -> Result<()> { let ty = match ty { - crate::Type::Func(ty) => Type::Func(ty), - crate::Type::Module(decls) => { + crate::CoreType::Func(ty) => Type::Func(ty), + crate::CoreType::Module(decls) => { Type::Module(self.create_module_type(decls.into_vec(), features, types, offset)?) } }; diff --git a/crates/wasmparser/src/validator/core.rs b/crates/wasmparser/src/validator/core.rs index 02ea87df35..3727d667b3 100644 --- a/crates/wasmparser/src/validator/core.rs +++ b/crates/wasmparser/src/validator/core.rs @@ -391,13 +391,6 @@ impl Module { } Type::Func(t) } - crate::Type::Module(_) => { - // Currently an error, but may be supported with a future module linking proposal. - return Err(BinaryReaderError::new( - "module types are not currently supported in core modules", - offset, - )); - } }; if check_limit { diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index 06d6137411..3333b11ea5 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -392,7 +392,6 @@ impl Printer { self.printers = printers; } Payload::TypeSection(s) => { - // This section is supported by both modules and components. self.print_types(states.last_mut().unwrap(), &mut types, s)? } Payload::ImportSection(s) => { @@ -472,6 +471,9 @@ impl Printer { 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); @@ -608,32 +610,51 @@ impl Printer { Ok(()) } - fn print_type( + fn print_core_type( &mut self, - core: bool, state: &mut State, types: &mut Vec, - ty: wasmparser::Type, + ty: wasmparser::CoreType, ) -> Result<()> { - if core { - self.start_group("core type "); - } else { - self.start_group("type "); - } + 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::Type::Func(ty) => { + wasmparser::CoreType::Func(ty) => { self.start_group("func"); self.print_func_type(state, &ty, None)?; self.end_group(); Type::Func(Some(ty)) } - wasmparser::Type::Module(decls) => { + 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.core.type_names, state.core.types.len() as u32)?; + self.result.push(' '); + let ty = match ty { + wasmparser::Type::Func(ty) => { + self.start_group("func"); + self.print_func_type(state, &ty, None)?; + self.end_group(); + Type::Func(Some(ty)) + } + }; self.end_group(); // `type` itself state.core.types.push(types.len()); @@ -641,6 +662,20 @@ impl Printer { 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, @@ -649,15 +684,7 @@ impl Printer { ) -> Result<()> { for ty in parser { self.newline(); - self.print_type( - match state.encoding { - Encoding::Component => true, - Encoding::Module => false, - }, - state, - types, - ty?, - )?; + self.print_type(state, types, ty?)?; } Ok(()) @@ -2411,12 +2438,7 @@ impl Printer { for decl in decls { self.newline(); match decl { - ModuleTypeDeclaration::Type(ty) => match ty { - wasmparser::Type::Func(ty) => { - self.print_type(false, &mut state, types, wasmparser::Type::Func(ty))? - } - wasmparser::Type::Module(_) => bail!("invalid nested module type"), - }, + ModuleTypeDeclaration::Type(ty) => self.print_type(&mut state, types, ty)?, ModuleTypeDeclaration::Export { name, ty } => { self.start_group("export "); self.print_str(name)?; @@ -2446,7 +2468,7 @@ impl Printer { self.newline(); match decl { ComponentTypeDeclaration::CoreType(ty) => { - self.print_type(true, states.last_mut().unwrap(), types, ty)? + self.print_core_type(states.last_mut().unwrap(), types, ty)? } ComponentTypeDeclaration::Type(ty) => { self.print_component_type_def(states, types, ty)? @@ -2498,7 +2520,7 @@ impl Printer { self.newline(); match decl { InstanceTypeDeclaration::CoreType(ty) => { - self.print_type(true, states.last_mut().unwrap(), types, ty)? + self.print_core_type(states.last_mut().unwrap(), types, ty)? } InstanceTypeDeclaration::Type(ty) => { self.print_component_type_def(states, types, ty)? diff --git a/src/bin/wasm-tools/objdump.rs b/src/bin/wasm-tools/objdump.rs index 4027773701..4b55fab293 100644 --- a/src/bin/wasm-tools/objdump.rs +++ b/src/bin/wasm-tools/objdump.rs @@ -48,8 +48,9 @@ impl Opts { printer.section_raw(range, 1, "module")?; printer.start(Encoding::Module)?; } - InstanceSection(s) => printer.section(s, "instances")?, - AliasSection(s) => printer.section(s, "aliases")?, + 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()); diff --git a/tests/dump/alias2.wat.dump b/tests/dump/alias2.wat.dump index 88e1f1ed72..c0347983a3 100644 --- a/tests/dump/alias2.wat.dump +++ b/tests/dump/alias2.wat.dump @@ -19,9 +19,9 @@ 0x3a | 05 3e | [component 0] inline size 0x3c | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x44 | 04 03 | type section + 0x44 | 04 03 | core type section 0x46 | 01 | 1 count - 0x47 | 50 00 | [type 0] Module([]) + 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) } diff --git a/tests/dump/component-inline-export-import.wat.dump b/tests/dump/component-inline-export-import.wat.dump index e852876694..4c892ee58d 100644 --- a/tests/dump/component-inline-export-import.wat.dump +++ b/tests/dump/component-inline-export-import.wat.dump @@ -6,9 +6,9 @@ 0xd | 0b 04 | component import section 0xf | 01 | 1 count 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x13 | 04 03 | type section + 0x13 | 04 03 | core type section 0x15 | 01 | 1 count - 0x16 | 50 00 | [type 0] Module([]) + 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) } diff --git a/tests/dump/component-inline-type.wat.dump b/tests/dump/component-inline-type.wat.dump index f86e008569..f2d6ee74c8 100644 --- a/tests/dump/component-inline-type.wat.dump +++ b/tests/dump/component-inline-type.wat.dump @@ -6,9 +6,9 @@ 0xd | 0b 04 | component import section 0xf | 01 | 1 count 0x10 | 00 04 00 | [component 0] ComponentImport { name: "", ty: Component(0) } - 0x13 | 04 03 | type section + 0x13 | 04 03 | core type section 0x15 | 01 | 1 count - 0x16 | 50 00 | [type 0] Module([]) + 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) } diff --git a/tests/dump/component-linking.wat.dump b/tests/dump/component-linking.wat.dump index c94bd1462d..52fc4a9ff9 100644 --- a/tests/dump/component-linking.wat.dump +++ b/tests/dump/component-linking.wat.dump @@ -19,9 +19,9 @@ 0x3a | 05 3e | [component 0] inline size 0x3c | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x44 | 04 03 | type section + 0x44 | 04 03 | core type section 0x46 | 01 | 1 count - 0x47 | 50 00 | [type 0] Module([]) + 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) } diff --git a/tests/dump/import-modules.wat.dump b/tests/dump/import-modules.wat.dump index b66875b082..782811c4f1 100644 --- a/tests/dump/import-modules.wat.dump +++ b/tests/dump/import-modules.wat.dump @@ -1,8 +1,8 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 04 0d | type section + 0x8 | 04 0d | core type section 0xa | 01 | 1 count - 0xb | 50 02 01 60 | [type 0] Module([Type(Func(FuncType { params: [], returns: [] })), Import(Import { module: "", name: "f", ty: Func(0) })]) + 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 diff --git a/tests/dump/module-types.wat.dump b/tests/dump/module-types.wat.dump index f4e0964181..fd66f96a75 100644 --- a/tests/dump/module-types.wat.dump +++ b/tests/dump/module-types.wat.dump @@ -1,8 +1,8 @@ 0x0 | 00 61 73 6d | version 65546 (Component) | 0a 00 01 00 - 0x8 | 04 23 | type section + 0x8 | 04 23 | core type section 0xa | 01 | 1 count - 0xb | 50 05 01 60 | [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 }) })]) + 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 From 654489167b667ae02c09aea0b196dccad69a98c5 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Tue, 7 Jun 2022 12:42:56 -0700 Subject: [PATCH 32/33] wasm-encoder: move component core type encoding to a separate section. Similar to the previous commit, this moves component core type encoding to a `CoreTypeSection` rather than extending `TypeSection` to encode for both modules and components. This helps make the distinction between a "type section" (module) and a "core type section" (component) a little more clear until such type that modules and components can share a core type section format. --- crates/wasm-encoder/src/component.rs | 7 - crates/wasm-encoder/src/component/types.rs | 177 ++++++++++++++++++++- crates/wasm-encoder/src/core/types.rs | 116 ++------------ crates/wasm-smith/src/component/encode.rs | 4 +- crates/wast/src/component/binary.rs | 7 +- 5 files changed, 187 insertions(+), 124 deletions(-) diff --git a/crates/wasm-encoder/src/component.rs b/crates/wasm-encoder/src/component.rs index 87520da391..fbac178bf2 100644 --- a/crates/wasm-encoder/src/component.rs +++ b/crates/wasm-encoder/src/component.rs @@ -18,7 +18,6 @@ pub use self::modules::*; pub use self::start::*; pub use self::types::*; -use crate::TypeSection; use crate::{CustomSection, Encode}; // Core sorts extended by the component model @@ -136,9 +135,3 @@ impl ComponentSection for CustomSection<'_> { ComponentSectionId::CoreCustom.into() } } - -impl ComponentSection for TypeSection { - fn id(&self) -> u8 { - ComponentSectionId::CoreType.into() - } -} diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index c8041e4343..6b9ef489ba 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -1,8 +1,175 @@ use crate::{ encode_section, ComponentOuterAliasKind, ComponentSection, ComponentSectionId, - ComponentTypeRef, Encode, TypeEncoder, + ComponentTypeRef, Encode, EntityType, ValType, }; +/// Represents the type of a core module. +#[derive(Debug, Clone, Default)] +pub struct ModuleType { + bytes: Vec, + num_added: u32, + types_added: u32, +} + +impl ModuleType { + /// Creates a new core module type. + pub fn new() -> Self { + Self::default() + } + + /// Defines an import in this module type. + pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { + self.bytes.push(0x00); + module.encode(&mut self.bytes); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + 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(0x03); + name.encode(&mut self.bytes); + ty.encode(&mut self.bytes); + self.num_added += 1; + self + } + + /// Gets the number of types that have been added to this module type. + pub fn type_count(&self) -> u32 { + self.types_added + } +} + +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 { @@ -22,11 +189,11 @@ impl ComponentType { /// /// 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) -> TypeEncoder { + pub fn core_type(&mut self) -> CoreTypeEncoder { self.bytes.push(0x00); self.num_added += 1; self.core_types_added += 1; - TypeEncoder(&mut self.bytes) + CoreTypeEncoder(&mut self.bytes) } /// Define a type in this component type. @@ -120,11 +287,11 @@ impl InstanceType { /// /// 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) -> TypeEncoder { + pub fn core_type(&mut self) -> CoreTypeEncoder { self.bytes.push(0x00); self.num_added += 1; self.core_types_added += 1; - TypeEncoder(&mut self.bytes) + CoreTypeEncoder(&mut self.bytes) } /// Define a type in this instance type. diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs index 6a216def65..d99e22ea94 100644 --- a/crates/wasm-encoder/src/core/types.rs +++ b/crates/wasm-encoder/src/core/types.rs @@ -1,4 +1,4 @@ -use crate::{encode_section, Encode, EntityType, Section, SectionId}; +use crate::{encode_section, Encode, Section, SectionId}; /// The type of a core WebAssembly value. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] @@ -40,95 +40,6 @@ impl Encode for ValType { } } -/// Represents the type of a core module. -#[derive(Debug, Clone, Default)] -pub struct ModuleType { - bytes: Vec, - num_added: u32, - types_added: u32, -} - -impl ModuleType { - /// Creates a new core module type. - pub fn new() -> Self { - Self::default() - } - - /// Defines an import in this module type. - pub fn import(&mut self, module: &str, name: &str, ty: EntityType) -> &mut Self { - self.bytes.push(0x00); - module.encode(&mut self.bytes); - name.encode(&mut self.bytes); - ty.encode(&mut self.bytes); - self.num_added += 1; - 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) -> TypeEncoder { - self.bytes.push(0x01); - self.num_added += 1; - self.types_added += 1; - TypeEncoder(&mut self.bytes) - } - - /// Defines an export in this module type. - pub fn export(&mut self, name: &str, ty: EntityType) -> &mut Self { - self.bytes.push(0x03); - name.encode(&mut self.bytes); - ty.encode(&mut self.bytes); - self.num_added += 1; - self - } - - /// Gets the number of types that have been added to this module type. - pub fn type_count(&self) -> u32 { - self.types_added - } -} - -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 TypeEncoder<'a>(pub(crate) &'a mut Vec); - -impl<'a> TypeEncoder<'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. - /// - /// Currently this is only used for core type sections in components. - pub fn module(self, ty: &ModuleType) { - ty.encode(self.0); - } -} - /// An encoder for the type section of WebAssembly modules. /// /// # Example @@ -167,15 +78,6 @@ impl TypeSection { 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) -> TypeEncoder<'_> { - self.num_added += 1; - TypeEncoder(&mut self.bytes) - } - /// Define a function type in this type section. pub fn function(&mut self, params: P, results: R) -> &mut Self where @@ -184,15 +86,15 @@ impl TypeSection { R: IntoIterator, R::IntoIter: ExactSizeIterator, { - self.ty().function(params, results); - self - } + let params = params.into_iter(); + let results = results.into_iter(); - /// 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.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 } } diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index 0fdab06046..ebe1a7b725 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -104,7 +104,7 @@ impl CanonicalSection { impl CoreTypeSection { fn encode(&self, component: &mut wasm_encoder::Component) { - let mut sec = wasm_encoder::TypeSection::new(); + let mut sec = wasm_encoder::CoreTypeSection::new(); for ty in &self.types { ty.encode(sec.ty()); } @@ -113,7 +113,7 @@ impl CoreTypeSection { } impl CoreType { - fn encode(&self, enc: wasm_encoder::TypeEncoder<'_>) { + fn encode(&self, enc: wasm_encoder::CoreTypeEncoder<'_>) { match self { Self::Module(mod_ty) => { let mut enc_mod_ty = wasm_encoder::ModuleType::new(); diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index c59a2f40c7..a22ce4b4da 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -5,7 +5,8 @@ use wasm_encoder::{ AliasSection, CanonicalFunctionSection, ComponentAliasSection, ComponentDefinedTypeEncoder, ComponentExportSection, ComponentImportSection, ComponentInstanceSection, ComponentSection, ComponentSectionId, ComponentStartSection, ComponentTypeEncoder, ComponentTypeSection, - InstanceSection, NestedComponentSection, RawSection, SectionId, TypeEncoder, TypeSection, + CoreTypeEncoder, CoreTypeSection, InstanceSection, NestedComponentSection, RawSection, + SectionId, }; pub fn encode(component: &Component<'_>) -> Vec { @@ -54,7 +55,7 @@ fn encode_fields( e.component } -fn encode_core_type(encoder: TypeEncoder, ty: &CoreTypeDef) { +fn encode_core_type(encoder: CoreTypeEncoder, ty: &CoreTypeDef) { match ty { CoreTypeDef::Def(core::TypeDef::Func(f)) => { encoder.function( @@ -132,7 +133,7 @@ struct Encoder { // Note: module sections are written immediately core_instances: InstanceSection, core_aliases: AliasSection, - core_types: TypeSection, + core_types: CoreTypeSection, // Component sections // Note: custom, component, start sections are written immediately From 314509c98b0e6c47a5d14b4a352bd81f82f92ea2 Mon Sep 17 00:00:00 2001 From: Peter Huene Date: Tue, 7 Jun 2022 12:51:24 -0700 Subject: [PATCH 33/33] wast: allow variant case refines clause to reference by index. This commit updates the parsing of variant case refines clauses to allow them to explicitly reference another case by index rather than identifier alone. --- crates/wast/src/component/binary.rs | 4 ++-- crates/wast/src/component/resolve.rs | 6 +++--- crates/wast/src/component/types.rs | 8 ++++---- tests/local/component-model/definedtypes.wast | 9 +++++++++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index a22ce4b4da..60ac5cf5ce 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -600,8 +600,8 @@ impl From for wasm_encoder::PrimitiveValType { impl From<&Refinement<'_>> for u32 { fn from(r: &Refinement) -> Self { match r { - Refinement::Id(..) => unreachable!("should be resolved by now"), - Refinement::Index(i) => *i, + Refinement::Index(..) => unreachable!("should be resolved by now"), + Refinement::Resolved(i) => *i, } } } diff --git a/crates/wast/src/component/resolve.rs b/crates/wast/src/component/resolve.rs index 97ecaad226..0bb22cfc45 100644 --- a/crates/wast/src/component/resolve.rs +++ b/crates/wast/src/component/resolve.rs @@ -400,8 +400,8 @@ impl<'a> Resolver<'a> { self.component_val_type(&mut case.ty)?; if let Some(refines) = &mut case.refines { - if let Refinement::Id(span, id) = refines { - let resolved = ns.resolve(&mut Index::Id(*id), "variant case")?; + if let Refinement::Index(span, idx) = refines { + let resolved = ns.resolve(idx, "variant case")?; if resolved == index { return Err(Error::new( *span, @@ -409,7 +409,7 @@ impl<'a> Resolver<'a> { )); } - *refines = Refinement::Index(resolved); + *refines = Refinement::Resolved(resolved); } } } diff --git a/crates/wast/src/component/types.rs b/crates/wast/src/component/types.rs index ab5139f0f1..2aea8979ec 100644 --- a/crates/wast/src/component/types.rs +++ b/crates/wast/src/component/types.rs @@ -436,11 +436,11 @@ impl<'a> Parse<'a> for VariantCase<'a> { /// A refinement for a variant case. #[derive(Debug)] pub enum Refinement<'a> { - /// The refinement is referenced by identifier. - Id(Span, Id<'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. - Index(u32), + Resolved(u32), } impl<'a> Parse<'a> for Refinement<'a> { @@ -448,7 +448,7 @@ impl<'a> Parse<'a> for Refinement<'a> { parser.parens(|parser| { let span = parser.parse::()?.0; let id = parser.parse()?; - Ok(Self::Id(span, id)) + Ok(Self::Index(span, id)) }) } } diff --git a/tests/local/component-model/definedtypes.wast b/tests/local/component-model/definedtypes.wast index 7edf11f17c..91fe642b31 100644 --- a/tests/local/component-model/definedtypes.wast +++ b/tests/local/component-model/definedtypes.wast @@ -22,6 +22,7 @@ (type $A15b (variant (case "x" unit))) (type $A15c (variant (case "x" $A1))) (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)) @@ -71,6 +72,14 @@ "failed to find variant case named `$z`" ) +(assert_invalid + (component + (type $t string) + (type $v (variant (case "x" $t (refines 1)))) + ) + "variant case refines index 1 is out of bounds" +) + (assert_invalid (component (type $t string)