diff options
Diffstat (limited to 'third_party/rust/wasmparser/src/readers/component')
8 files changed, 1232 insertions, 0 deletions
diff --git a/third_party/rust/wasmparser/src/readers/component/aliases.rs b/third_party/rust/wasmparser/src/readers/component/aliases.rs new file mode 100644 index 0000000000..fb71d579b4 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/aliases.rs @@ -0,0 +1,119 @@ +use crate::{BinaryReader, ComponentExternalKind, ExternalKind, FromReader, Result}; + +/// Represents the kind of an outer alias in a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ComponentOuterAliasKind { + /// The alias is to a core module. + CoreModule, + /// The alias is to a core type. + CoreType, + /// The alias is to a component type. + Type, + /// The alias is to a component. + Component, +} + +/// Represents an alias in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentAlias<'a> { + /// The alias is to an export of a component instance. + InstanceExport { + /// The alias kind. + kind: ComponentExternalKind, + /// The instance index. + instance_index: u32, + /// The export name. + name: &'a str, + }, + /// The alias is to an export of a module instance. + CoreInstanceExport { + /// The alias kind. + kind: ExternalKind, + /// The instance index. + instance_index: u32, + /// The export name. + name: &'a str, + }, + /// The alias is to an outer item. + Outer { + /// The alias kind. + kind: ComponentOuterAliasKind, + /// The outward count, starting at zero for the current component. + count: u32, + /// The index of the item within the outer component. + index: u32, + }, +} + +/// Section reader for the component alias section +pub type ComponentAliasSectionReader<'a> = crate::SectionLimited<'a, ComponentAlias<'a>>; + +impl<'a> FromReader<'a> for ComponentAlias<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + // We don't know what type of alias it is yet, so just read the sort bytes + let offset = reader.original_position(); + let byte1 = reader.read_u8()?; + let byte2 = if byte1 == 0x00 { + Some(reader.read_u8()?) + } else { + None + }; + + Ok(match reader.read_u8()? { + 0x00 => ComponentAlias::InstanceExport { + kind: ComponentExternalKind::from_bytes(byte1, byte2, offset)?, + instance_index: reader.read_var_u32()?, + name: reader.read_string()?, + }, + 0x01 => ComponentAlias::CoreInstanceExport { + kind: BinaryReader::external_kind_from_byte( + byte2.ok_or_else(|| { + BinaryReader::invalid_leading_byte_error( + byte1, + "core instance export kind", + offset, + ) + })?, + offset, + )?, + instance_index: reader.read_var_u32()?, + name: reader.read_string()?, + }, + 0x02 => ComponentAlias::Outer { + kind: component_outer_alias_kind_from_bytes(byte1, byte2, offset)?, + count: reader.read_var_u32()?, + index: reader.read_var_u32()?, + }, + x => reader.invalid_leading_byte(x, "alias")?, + }) + } +} + +fn component_outer_alias_kind_from_bytes( + byte1: u8, + byte2: Option<u8>, + offset: usize, +) -> Result<ComponentOuterAliasKind> { + Ok(match byte1 { + 0x00 => match byte2.unwrap() { + 0x10 => ComponentOuterAliasKind::CoreType, + 0x11 => ComponentOuterAliasKind::CoreModule, + x => { + return Err(BinaryReader::invalid_leading_byte_error( + x, + "component outer alias kind", + offset + 1, + )) + } + }, + 0x03 => ComponentOuterAliasKind::Type, + 0x04 => ComponentOuterAliasKind::Component, + x => { + return Err(BinaryReader::invalid_leading_byte_error( + x, + "component outer alias kind", + offset, + )) + } + }) +} diff --git a/third_party/rust/wasmparser/src/readers/component/canonicals.rs b/third_party/rust/wasmparser/src/readers/component/canonicals.rs new file mode 100644 index 0000000000..e360d029c4 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/canonicals.rs @@ -0,0 +1,95 @@ +use crate::limits::MAX_WASM_CANONICAL_OPTIONS; +use crate::{BinaryReader, FromReader, Result, SectionLimited}; + +/// Represents options for component functions. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CanonicalOption { + /// The string types in the function signature are UTF-8 encoded. + UTF8, + /// The string types in the function signature are UTF-16 encoded. + UTF16, + /// The string types in the function signature are compact UTF-16 encoded. + CompactUTF16, + /// The memory to use if the lifting or lowering of a function requires memory access. + /// + /// The value is an index to a core memory. + Memory(u32), + /// The realloc function to use if the lifting or lowering of a function requires memory + /// allocation. + /// + /// The value is an index to a core function of type `(func (param i32 i32 i32 i32) (result i32))`. + Realloc(u32), + /// The post-return function to use if the lifting of a function requires + /// cleanup after the function returns. + PostReturn(u32), +} + +/// Represents a canonical function in a WebAssembly component. +#[derive(Debug, Clone)] +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 canonical options for the function. + options: Box<[CanonicalOption]>, + }, + /// The function lowers a canonical ABI function to a core WebAssembly function. + Lower { + /// The index of the function to lower. + func_index: u32, + /// The canonical options for the function. + options: Box<[CanonicalOption]>, + }, +} + +/// A reader for the canonical section of a WebAssembly component. +pub type ComponentCanonicalSectionReader<'a> = SectionLimited<'a, CanonicalFunction>; + +impl<'a> FromReader<'a> for CanonicalFunction { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<CanonicalFunction> { + Ok(match reader.read_u8()? { + 0x00 => match reader.read_u8()? { + 0x00 => { + let core_func_index = reader.read_var_u32()?; + let options = reader + .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? + .collect::<Result<_>>()?; + let type_index = reader.read_var_u32()?; + CanonicalFunction::Lift { + core_func_index, + options, + type_index, + } + } + x => return reader.invalid_leading_byte(x, "canonical function lift"), + }, + 0x01 => match reader.read_u8()? { + 0x00 => CanonicalFunction::Lower { + func_index: reader.read_var_u32()?, + options: reader + .read_iter(MAX_WASM_CANONICAL_OPTIONS, "canonical options")? + .collect::<Result<_>>()?, + }, + x => return reader.invalid_leading_byte(x, "canonical function lower"), + }, + x => return reader.invalid_leading_byte(x, "canonical function"), + }) + } +} + +impl<'a> FromReader<'a> for CanonicalOption { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x00 => CanonicalOption::UTF8, + 0x01 => CanonicalOption::UTF16, + 0x02 => CanonicalOption::CompactUTF16, + 0x03 => CanonicalOption::Memory(reader.read_var_u32()?), + 0x04 => CanonicalOption::Realloc(reader.read_var_u32()?), + 0x05 => CanonicalOption::PostReturn(reader.read_var_u32()?), + x => return reader.invalid_leading_byte(x, "canonical option"), + }) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/exports.rs b/third_party/rust/wasmparser/src/readers/component/exports.rs new file mode 100644 index 0000000000..8ce5f43a00 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/exports.rs @@ -0,0 +1,105 @@ +use crate::{BinaryReader, ComponentTypeRef, FromReader, Result, SectionLimited}; + +/// 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, +} + +impl ComponentExternalKind { + pub(crate) fn from_bytes( + byte1: u8, + byte2: Option<u8>, + offset: usize, + ) -> Result<ComponentExternalKind> { + Ok(match byte1 { + 0x00 => match byte2.unwrap() { + 0x11 => ComponentExternalKind::Module, + x => { + return Err(BinaryReader::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(BinaryReader::invalid_leading_byte_error( + x, + "component external kind", + offset, + )) + } + }) + } +} + +/// Represents an export in a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentExport<'a> { + /// The name of the exported item. + pub name: &'a str, + /// The optional URL of the exported item. + pub url: &'a str, + /// The kind of the export. + pub kind: ComponentExternalKind, + /// The index of the exported item. + pub index: u32, + /// An optionally specified type ascribed to this export. + pub ty: Option<ComponentTypeRef>, +} + +/// A reader for the export section of a WebAssembly component. +pub type ComponentExportSectionReader<'a> = SectionLimited<'a, ComponentExport<'a>>; + +impl<'a> FromReader<'a> for ComponentExport<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(ComponentExport { + name: reader.read()?, + url: reader.read()?, + kind: reader.read()?, + index: reader.read()?, + ty: match reader.read_u8()? { + 0x00 => None, + 0x01 => Some(reader.read()?), + other => { + return Err(BinaryReader::invalid_leading_byte_error( + other, + "optional component export type", + reader.original_position() - 1, + )) + } + }, + }) + } +} + +impl<'a> FromReader<'a> for ComponentExternalKind { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + let offset = reader.original_position(); + let byte1 = reader.read_u8()?; + let byte2 = if byte1 == 0x00 { + Some(reader.read_u8()?) + } else { + None + }; + + ComponentExternalKind::from_bytes(byte1, byte2, offset) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/imports.rs b/third_party/rust/wasmparser/src/readers/component/imports.rs new file mode 100644 index 0000000000..c1313c11e2 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/imports.rs @@ -0,0 +1,109 @@ +use crate::{ + BinaryReader, ComponentExternalKind, ComponentValType, FromReader, Result, SectionLimited, +}; + +/// Represents the type bounds for imports and exports. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TypeBounds { + /// The type is bounded by equality. + Eq, +} + +impl<'a> FromReader<'a> for TypeBounds { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x00 => TypeBounds::Eq, + x => return reader.invalid_leading_byte(x, "type bound"), + }) + } +} + +/// 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), +} + +impl ComponentTypeRef { + /// Returns the corresponding [`ComponentExternalKind`] for this reference. + pub fn kind(&self) -> ComponentExternalKind { + match self { + ComponentTypeRef::Module(_) => ComponentExternalKind::Module, + ComponentTypeRef::Func(_) => ComponentExternalKind::Func, + ComponentTypeRef::Value(_) => ComponentExternalKind::Value, + ComponentTypeRef::Type(..) => ComponentExternalKind::Type, + ComponentTypeRef::Instance(_) => ComponentExternalKind::Instance, + ComponentTypeRef::Component(_) => ComponentExternalKind::Component, + } + } +} + +impl<'a> FromReader<'a> for ComponentTypeRef { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read()? { + ComponentExternalKind::Module => ComponentTypeRef::Module(reader.read()?), + ComponentExternalKind::Func => ComponentTypeRef::Func(reader.read()?), + ComponentExternalKind::Value => ComponentTypeRef::Value(reader.read()?), + ComponentExternalKind::Type => ComponentTypeRef::Type(reader.read()?, reader.read()?), + ComponentExternalKind::Instance => ComponentTypeRef::Instance(reader.read()?), + ComponentExternalKind::Component => ComponentTypeRef::Component(reader.read()?), + }) + } +} + +/// 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 optional URL of the imported item. + pub url: &'a str, + /// The type reference for the import. + pub ty: ComponentTypeRef, +} + +impl<'a> FromReader<'a> for ComponentImport<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(ComponentImport { + name: reader.read()?, + url: reader.read()?, + ty: reader.read()?, + }) + } +} + +/// A reader for the import section of a WebAssembly component. +/// +/// # Examples +/// +/// ``` +/// use wasmparser::ComponentImportSectionReader; +/// let data: &[u8] = &[0x01, 0x01, 0x41, 0x00, 0x01, 0x66]; +/// let reader = ComponentImportSectionReader::new(data, 0).unwrap(); +/// for import in reader { +/// let import = import.expect("import"); +/// println!("Import: {:?}", import); +/// } +/// ``` +pub type ComponentImportSectionReader<'a> = SectionLimited<'a, ComponentImport<'a>>; diff --git a/third_party/rust/wasmparser/src/readers/component/instances.rs b/third_party/rust/wasmparser/src/readers/component/instances.rs new file mode 100644 index 0000000000..8166395edc --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/instances.rs @@ -0,0 +1,164 @@ +use crate::limits::{MAX_WASM_INSTANTIATION_ARGS, MAX_WASM_INSTANTIATION_EXPORTS}; +use crate::{ + BinaryReader, ComponentExport, ComponentExternalKind, Export, FromReader, Result, + SectionLimited, +}; + +/// 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. +/// +/// # 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")); +/// } +/// ``` +pub type InstanceSectionReader<'a> = SectionLimited<'a, Instance<'a>>; + +impl<'a> FromReader<'a> for Instance<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x00 => Instance::Instantiate { + module_index: reader.read_var_u32()?, + args: reader + .read_iter(MAX_WASM_INSTANTIATION_ARGS, "core instantiation arguments")? + .collect::<Result<_>>()?, + }, + 0x01 => Instance::FromExports( + reader + .read_iter(MAX_WASM_INSTANTIATION_ARGS, "core instantiation arguments")? + .collect::<Result<_>>()?, + ), + x => return reader.invalid_leading_byte(x, "core instance"), + }) + } +} + +impl<'a> FromReader<'a> for InstantiationArg<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(InstantiationArg { + name: reader.read()?, + kind: reader.read()?, + index: reader.read()?, + }) + } +} + +impl<'a> FromReader<'a> for InstantiationArgKind { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x12 => InstantiationArgKind::Instance, + x => return reader.invalid_leading_byte(x, "instantiation arg kind"), + }) + } +} + +/// Represents an argument to instantiating a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentInstantiationArg<'a> { + /// The name of the component argument. + pub name: &'a str, + /// The kind of the component argument. + pub kind: ComponentExternalKind, + /// The index of the argument item. + pub index: u32, +} + +/// Represents an instance in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentInstance<'a> { + /// The instance is from instantiating a WebAssembly component. + Instantiate { + /// The component index. + component_index: u32, + /// The component's instantiation arguments. + args: Box<[ComponentInstantiationArg<'a>]>, + }, + /// The instance is a from exporting local items. + FromExports(Box<[ComponentExport<'a>]>), +} + +/// A reader for the component instance section of a WebAssembly component. +/// +/// # Examples +/// +/// ``` +/// use wasmparser::ComponentInstanceSectionReader; +/// # let data: &[u8] = &[0x01, 0x00, 0x00, 0x01, 0x03, b'f', b'o', b'o', 0x01, 0x00]; +/// let mut reader = ComponentInstanceSectionReader::new(data, 0).unwrap(); +/// for inst in reader { +/// println!("Instance {:?}", inst.expect("instance")); +/// } +/// ``` +pub type ComponentInstanceSectionReader<'a> = SectionLimited<'a, ComponentInstance<'a>>; + +impl<'a> FromReader<'a> for ComponentInstance<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x00 => ComponentInstance::Instantiate { + component_index: reader.read_var_u32()?, + args: reader + .read_iter(MAX_WASM_INSTANTIATION_ARGS, "instantiation arguments")? + .collect::<Result<_>>()?, + }, + 0x01 => ComponentInstance::FromExports( + (0..reader.read_size(MAX_WASM_INSTANTIATION_EXPORTS, "instantiation exports")?) + .map(|_| { + Ok(ComponentExport { + name: reader.read()?, + url: "", + kind: reader.read()?, + index: reader.read()?, + ty: None, + }) + }) + .collect::<Result<_>>()?, + ), + x => return reader.invalid_leading_byte(x, "instance"), + }) + } +} +impl<'a> FromReader<'a> for ComponentInstantiationArg<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(ComponentInstantiationArg { + name: reader.read()?, + kind: reader.read()?, + index: reader.read()?, + }) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/names.rs b/third_party/rust/wasmparser/src/readers/component/names.rs new file mode 100644 index 0000000000..19de2752d0 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/names.rs @@ -0,0 +1,102 @@ +use crate::{BinaryReader, BinaryReaderError, NameMap, Result, Subsection, Subsections}; +use std::ops::Range; + +/// Type used to iterate and parse the contents of the `component-name` custom +/// section in compnents, similar to the `name` section of core modules. +pub type ComponentNameSectionReader<'a> = Subsections<'a, ComponentName<'a>>; + +/// Represents a name read from the names custom section. +#[derive(Clone)] +#[allow(missing_docs)] +pub enum ComponentName<'a> { + Component { + name: &'a str, + name_range: Range<usize>, + }, + CoreFuncs(NameMap<'a>), + CoreGlobals(NameMap<'a>), + CoreMemories(NameMap<'a>), + CoreTables(NameMap<'a>), + CoreModules(NameMap<'a>), + CoreInstances(NameMap<'a>), + CoreTypes(NameMap<'a>), + Types(NameMap<'a>), + Instances(NameMap<'a>), + Components(NameMap<'a>), + Funcs(NameMap<'a>), + Values(NameMap<'a>), + + /// An unknown [name subsection](https://webassembly.github.io/spec/core/appendix/custom.html#subsections). + Unknown { + /// The identifier for this subsection. + ty: u8, + /// The contents of this subsection. + data: &'a [u8], + /// The range of bytes, relative to the start of the original data + /// stream, that the contents of this subsection reside in. + range: Range<usize>, + }, +} + +impl<'a> Subsection<'a> for ComponentName<'a> { + fn from_reader(id: u8, mut reader: BinaryReader<'a>) -> Result<Self> { + let data = reader.remaining_buffer(); + let offset = reader.original_position(); + Ok(match id { + 0 => { + let name = reader.read_string()?; + if !reader.eof() { + return Err(BinaryReaderError::new( + "trailing data at the end of a name", + reader.original_position(), + )); + } + ComponentName::Component { + name, + name_range: offset..offset + reader.position, + } + } + 1 => { + let ctor: fn(NameMap<'a>) -> ComponentName<'a> = match reader.read_u8()? { + 0x00 => match reader.read_u8()? { + 0x00 => ComponentName::CoreFuncs, + 0x01 => ComponentName::CoreTables, + 0x02 => ComponentName::CoreMemories, + 0x03 => ComponentName::CoreGlobals, + 0x10 => ComponentName::CoreTypes, + 0x11 => ComponentName::CoreModules, + 0x12 => ComponentName::CoreInstances, + _ => { + return Ok(ComponentName::Unknown { + ty: 1, + data, + range: offset..offset + data.len(), + }); + } + }, + 0x01 => ComponentName::Funcs, + 0x02 => ComponentName::Values, + 0x03 => ComponentName::Types, + 0x04 => ComponentName::Components, + 0x05 => ComponentName::Instances, + _ => { + return Ok(ComponentName::Unknown { + ty: 1, + data, + range: offset..offset + data.len(), + }); + } + }; + ctor(NameMap::new( + reader.remaining_buffer(), + reader.original_position(), + )?) + } + ty => ComponentName::Unknown { + ty, + data, + range: offset..offset + data.len(), + }, + }) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/start.rs b/third_party/rust/wasmparser/src/readers/component/start.rs new file mode 100644 index 0000000000..dc01fa4340 --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/start.rs @@ -0,0 +1,30 @@ +use crate::limits::{MAX_WASM_FUNCTION_RETURNS, MAX_WASM_START_ARGS}; +use crate::{BinaryReader, FromReader, Result}; + +/// Represents the start function in a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentStartFunction { + /// The index to the start function. + pub func_index: u32, + /// The start function arguments. + /// + /// The arguments are specified by value index. + pub arguments: Box<[u32]>, + /// The number of expected results for the start function. + pub results: u32, +} + +impl<'a> FromReader<'a> for ComponentStartFunction { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + let func_index = reader.read_var_u32()?; + let arguments = reader + .read_iter(MAX_WASM_START_ARGS, "start function arguments")? + .collect::<Result<_>>()?; + let results = reader.read_size(MAX_WASM_FUNCTION_RETURNS, "start function results")? as u32; + Ok(ComponentStartFunction { + func_index, + arguments, + results, + }) + } +} diff --git a/third_party/rust/wasmparser/src/readers/component/types.rs b/third_party/rust/wasmparser/src/readers/component/types.rs new file mode 100644 index 0000000000..b0e9687a4d --- /dev/null +++ b/third_party/rust/wasmparser/src/readers/component/types.rs @@ -0,0 +1,508 @@ +use crate::limits::*; +use crate::{ + BinaryReader, ComponentAlias, ComponentImport, ComponentTypeRef, FromReader, FuncType, Import, + Result, SectionLimited, Type, TypeRef, +}; + +/// Represents the kind of an outer core alias in a WebAssembly component. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum OuterAliasKind { + /// The alias is to a core type. + Type, +} + +/// 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>]>), +} + +impl<'a> FromReader<'a> for CoreType<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x60 => CoreType::Func(reader.read()?), + 0x50 => CoreType::Module( + reader + .read_iter(MAX_WASM_MODULE_TYPE_DECLS, "module type declaration")? + .collect::<Result<_>>()?, + ), + x => return reader.invalid_leading_byte(x, "core type"), + }) + } +} + +/// 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 declaration is for an outer alias. + OuterAlias { + /// The alias kind. + kind: OuterAliasKind, + /// The outward count, starting at zero for the current type. + count: u32, + /// The index of the item within the outer type. + index: u32, + }, + /// The module type definition is for an import. + Import(Import<'a>), +} + +impl<'a> FromReader<'a> for ModuleTypeDeclaration<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x00 => ModuleTypeDeclaration::Import(reader.read()?), + 0x01 => ModuleTypeDeclaration::Type(reader.read()?), + 0x02 => { + let kind = match reader.read_u8()? { + 0x10 => OuterAliasKind::Type, + x => { + return reader.invalid_leading_byte(x, "outer alias kind"); + } + }; + match reader.read_u8()? { + 0x01 => ModuleTypeDeclaration::OuterAlias { + kind, + count: reader.read()?, + index: reader.read()?, + }, + x => { + return reader.invalid_leading_byte(x, "outer alias target"); + } + } + } + 0x03 => ModuleTypeDeclaration::Export { + name: reader.read()?, + ty: reader.read()?, + }, + x => return reader.invalid_leading_byte(x, "type definition"), + }) + } +} + +/// A reader for the core type section of a WebAssembly component. +/// +/// # 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")); +/// } +/// ``` +pub type CoreTypeSectionReader<'a> = SectionLimited<'a, CoreType<'a>>; + +/// 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), +} + +impl<'a> FromReader<'a> for ComponentValType { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + if let Some(ty) = PrimitiveValType::from_byte(reader.peek()?) { + reader.position += 1; + return Ok(ComponentValType::Primitive(ty)); + } + + Ok(ComponentValType::Type(reader.read_var_s33()? as u32)) + } +} + +impl<'a> FromReader<'a> for Option<ComponentValType> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + match reader.read_u8()? { + 0x0 => Ok(None), + 0x1 => Ok(Some(reader.read()?)), + x => reader.invalid_leading_byte(x, "optional component value type"), + } + } +} + +/// Represents a primitive value type. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PrimitiveValType { + /// The type is a boolean. + Bool, + /// The type is a signed 8-bit integer. + S8, + /// The type is an unsigned 8-bit integer. + U8, + /// The type is a signed 16-bit integer. + S16, + /// The type is an unsigned 16-bit integer. + U16, + /// The type is a signed 32-bit integer. + S32, + /// The type is an unsigned 32-bit integer. + U32, + /// The type is a signed 64-bit integer. + S64, + /// The type is an unsigned 64-bit integer. + U64, + /// The type is a 32-bit floating point number. + Float32, + /// The type is a 64-bit floating point number. + Float64, + /// The type is a Unicode character. + Char, + /// The type is a string. + String, +} + +impl PrimitiveValType { + fn from_byte(byte: u8) -> Option<PrimitiveValType> { + Some(match byte { + 0x7f => PrimitiveValType::Bool, + 0x7e => PrimitiveValType::S8, + 0x7d => PrimitiveValType::U8, + 0x7c => PrimitiveValType::S16, + 0x7b => PrimitiveValType::U16, + 0x7a => PrimitiveValType::S32, + 0x79 => PrimitiveValType::U32, + 0x78 => PrimitiveValType::S64, + 0x77 => PrimitiveValType::U64, + 0x76 => PrimitiveValType::Float32, + 0x75 => PrimitiveValType::Float64, + 0x74 => PrimitiveValType::Char, + 0x73 => PrimitiveValType::String, + _ => return None, + }) + } + + pub(crate) fn requires_realloc(&self) -> bool { + matches!(self, Self::String) + } + + /// Determines if primitive value type `a` is a subtype of `b`. + pub fn is_subtype_of(a: Self, b: Self) -> bool { + // Note that this intentionally diverges from the upstream specification + // at this time and only considers exact equality for subtyping + // relationships. + // + // More information can be found in the subtyping implementation for + // component functions. + a == b + } +} + +/// 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>]>), +} + +impl<'a> FromReader<'a> for ComponentType<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x40 => { + let params = reader + .read_iter(MAX_WASM_FUNCTION_PARAMS, "component function parameters")? + .collect::<Result<_>>()?; + let results = reader.read()?; + ComponentType::Func(ComponentFuncType { params, results }) + } + 0x41 => ComponentType::Component( + reader + .read_iter(MAX_WASM_COMPONENT_TYPE_DECLS, "component type declaration")? + .collect::<Result<_>>()?, + ), + 0x42 => ComponentType::Instance( + reader + .read_iter(MAX_WASM_INSTANCE_TYPE_DECLS, "instance type declaration")? + .collect::<Result<_>>()?, + ), + x => { + if let Some(ty) = PrimitiveValType::from_byte(x) { + ComponentType::Defined(ComponentDefinedType::Primitive(ty)) + } else { + ComponentType::Defined(ComponentDefinedType::read(reader, x)?) + } + } + }) + } +} + +/// Represents part of a component type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum ComponentTypeDeclaration<'a> { + /// The component type declaration is for a core type. + CoreType(CoreType<'a>), + /// The component type declaration is for a type. + Type(ComponentType<'a>), + /// The component type declaration is for an alias. + Alias(ComponentAlias<'a>), + /// The component type declaration is for an export. + Export { + /// The name of the export. + name: &'a str, + /// The optional URL of the export. + url: &'a str, + /// The type reference for the export. + ty: ComponentTypeRef, + }, + /// The component type declaration is for an import. + Import(ComponentImport<'a>), +} + +impl<'a> FromReader<'a> for ComponentTypeDeclaration<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + // Component types are effectively instance types with the additional + // variant of imports; check for imports here or delegate to + // `InstanceTypeDeclaration` with the appropriate conversions. + if reader.peek()? == 0x03 { + reader.position += 1; + return Ok(ComponentTypeDeclaration::Import(reader.read()?)); + } + + Ok(match reader.read()? { + InstanceTypeDeclaration::CoreType(t) => ComponentTypeDeclaration::CoreType(t), + InstanceTypeDeclaration::Type(t) => ComponentTypeDeclaration::Type(t), + InstanceTypeDeclaration::Alias(a) => ComponentTypeDeclaration::Alias(a), + InstanceTypeDeclaration::Export { name, url, ty } => { + ComponentTypeDeclaration::Export { name, url, ty } + } + }) + } +} + +/// Represents an instance type declaration in a WebAssembly component. +#[derive(Debug, Clone)] +pub enum InstanceTypeDeclaration<'a> { + /// The component type declaration is for a core type. + CoreType(CoreType<'a>), + /// The instance type declaration is for a type. + Type(ComponentType<'a>), + /// The instance type declaration is for an alias. + Alias(ComponentAlias<'a>), + /// The instance type declaration is for an export. + Export { + /// The name of the export. + name: &'a str, + /// The URL for the export. + url: &'a str, + /// The type reference for the export. + ty: ComponentTypeRef, + }, +} + +impl<'a> FromReader<'a> for InstanceTypeDeclaration<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x00 => InstanceTypeDeclaration::CoreType(reader.read()?), + 0x01 => InstanceTypeDeclaration::Type(reader.read()?), + 0x02 => InstanceTypeDeclaration::Alias(reader.read()?), + 0x04 => InstanceTypeDeclaration::Export { + name: reader.read()?, + url: reader.read()?, + ty: reader.read()?, + }, + x => return reader.invalid_leading_byte(x, "component or instance type declaration"), + }) + } +} + +/// Represents the result type of a component function. +#[derive(Debug, Clone)] +pub enum ComponentFuncResult<'a> { + /// The function returns a singular, unnamed type. + Unnamed(ComponentValType), + /// The function returns zero or more named types. + Named(Box<[(&'a str, ComponentValType)]>), +} + +impl<'a> FromReader<'a> for ComponentFuncResult<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(match reader.read_u8()? { + 0x00 => ComponentFuncResult::Unnamed(reader.read()?), + 0x01 => ComponentFuncResult::Named( + reader + .read_iter(MAX_WASM_FUNCTION_RETURNS, "component function results")? + .collect::<Result<_>>()?, + ), + x => return reader.invalid_leading_byte(x, "component function results"), + }) + } +} + +impl ComponentFuncResult<'_> { + /// Gets the count of types returned by the function. + pub fn type_count(&self) -> usize { + match self { + Self::Unnamed(_) => 1, + Self::Named(vec) => vec.len(), + } + } + + /// Iterates over the types returned by the function. + pub fn iter(&self) -> impl Iterator<Item = (Option<&str>, &ComponentValType)> { + enum Either<L, R> { + Left(L), + Right(R), + } + + impl<L, R> Iterator for Either<L, R> + where + L: Iterator, + R: Iterator<Item = L::Item>, + { + type Item = L::Item; + + fn next(&mut self) -> Option<Self::Item> { + match self { + Either::Left(l) => l.next(), + Either::Right(r) => r.next(), + } + } + } + + match self { + Self::Unnamed(ty) => Either::Left(std::iter::once(ty).map(|ty| (None, ty))), + Self::Named(vec) => Either::Right(vec.iter().map(|(n, ty)| (Some(*n), ty))), + } + } +} + +/// Represents a type of a function in a WebAssembly component. +#[derive(Debug, Clone)] +pub struct ComponentFuncType<'a> { + /// The function parameters. + pub params: Box<[(&'a str, ComponentValType)]>, + /// The function result. + pub results: ComponentFuncResult<'a>, +} + +/// 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 value type of the variant case. + pub ty: Option<ComponentValType>, + /// The index of the variant case that is refined by this one. + pub refines: Option<u32>, +} + +impl<'a> FromReader<'a> for VariantCase<'a> { + fn from_reader(reader: &mut BinaryReader<'a>) -> Result<Self> { + Ok(VariantCase { + name: reader.read()?, + ty: reader.read()?, + refines: match reader.read_u8()? { + 0x0 => None, + 0x1 => Some(reader.read_var_u32()?), + x => return reader.invalid_leading_byte(x, "variant case refines"), + }, + }) + } +} + +/// Represents a defined type in a WebAssembly component. +#[derive(Debug, Clone, PartialEq, Eq)] +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, ComponentValType)]>), + /// The type is a variant with the given cases. + Variant(Box<[VariantCase<'a>]>), + /// 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 value types. + Union(Box<[ComponentValType]>), + /// The type is an option of the given value type. + Option(ComponentValType), + /// The type is a result type. + Result { + /// The type returned for success. + ok: Option<ComponentValType>, + /// The type returned for failure. + err: Option<ComponentValType>, + }, +} + +impl<'a> ComponentDefinedType<'a> { + fn read(reader: &mut BinaryReader<'a>, byte: u8) -> Result<ComponentDefinedType<'a>> { + Ok(match byte { + 0x72 => ComponentDefinedType::Record( + reader + .read_iter(MAX_WASM_RECORD_FIELDS, "record field")? + .collect::<Result<_>>()?, + ), + 0x71 => ComponentDefinedType::Variant( + reader + .read_iter(MAX_WASM_VARIANT_CASES, "variant cases")? + .collect::<Result<_>>()?, + ), + 0x70 => ComponentDefinedType::List(reader.read()?), + 0x6f => ComponentDefinedType::Tuple( + reader + .read_iter(MAX_WASM_TUPLE_TYPES, "tuple types")? + .collect::<Result<_>>()?, + ), + 0x6e => ComponentDefinedType::Flags( + reader + .read_iter(MAX_WASM_FLAG_NAMES, "flag names")? + .collect::<Result<_>>()?, + ), + 0x6d => ComponentDefinedType::Enum( + reader + .read_iter(MAX_WASM_ENUM_CASES, "enum cases")? + .collect::<Result<_>>()?, + ), + 0x6c => ComponentDefinedType::Union( + reader + .read_iter(MAX_WASM_UNION_TYPES, "union types")? + .collect::<Result<_>>()?, + ), + 0x6b => ComponentDefinedType::Option(reader.read()?), + 0x6a => ComponentDefinedType::Result { + ok: reader.read()?, + err: reader.read()?, + }, + x => return reader.invalid_leading_byte(x, "component defined type"), + }) + } +} + +/// A reader for the type section of a WebAssembly component. +/// +/// # Examples +/// +/// ``` +/// use wasmparser::ComponentTypeSectionReader; +/// let data: &[u8] = &[0x01, 0x40, 0x01, 0x03, b'f', b'o', b'o', 0x73, 0x00, 0x73]; +/// let mut reader = ComponentTypeSectionReader::new(data, 0).unwrap(); +/// for ty in reader { +/// println!("Type {:?}", ty.expect("type")); +/// } +/// ``` +pub type ComponentTypeSectionReader<'a> = SectionLimited<'a, ComponentType<'a>>; |