diff --git a/crates/wasm-compose/src/encoding.rs b/crates/wasm-compose/src/encoding.rs index daa2bd98a9..468ceb9782 100644 --- a/crates/wasm-compose/src/encoding.rs +++ b/crates/wasm-compose/src/encoding.rs @@ -68,7 +68,7 @@ impl Encodable { } } - fn core_type(&mut self) -> CoreTypeEncoder { + fn core_type(&mut self) -> ComponentCoreTypeEncoder { match self { Encodable::Component(t) => t.core_type(), Encodable::Instance(t) => t.core_type(), diff --git a/crates/wasm-encoder/src/component/builder.rs b/crates/wasm-encoder/src/component/builder.rs index 66f5fe41cf..12e73ca464 100644 --- a/crates/wasm-encoder/src/component/builder.rs +++ b/crates/wasm-encoder/src/component/builder.rs @@ -299,7 +299,7 @@ impl ComponentBuilder { } /// Creates a new encoder for the next core type in this component. - pub fn core_type(&mut self) -> (u32, CoreTypeEncoder<'_>) { + pub fn core_type(&mut self) -> (u32, ComponentCoreTypeEncoder<'_>) { (inc(&mut self.core_types), self.core_types().ty()) } diff --git a/crates/wasm-encoder/src/component/types.rs b/crates/wasm-encoder/src/component/types.rs index aa79d69c94..39853d5f7b 100644 --- a/crates/wasm-encoder/src/component/types.rs +++ b/crates/wasm-encoder/src/component/types.rs @@ -1,7 +1,7 @@ use super::CORE_TYPE_SORT; use crate::{ encode_section, Alias, ComponentExportKind, ComponentOuterAliasKind, ComponentSection, - ComponentSectionId, ComponentTypeRef, Encode, EntityType, ValType, + ComponentSectionId, ComponentTypeRef, CoreTypeEncoder, Encode, EntityType, ValType, }; /// Represents the type of a core module. @@ -36,7 +36,10 @@ impl ModuleType { self.bytes.push(0x01); self.num_added += 1; self.types_added += 1; - CoreTypeEncoder(&mut self.bytes) + CoreTypeEncoder { + push_prefix_if_component_core_type: false, + bytes: &mut self.bytes, + } } /// Defines an outer core type alias in this module type. @@ -76,31 +79,22 @@ impl Encode for ModuleType { /// 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); - params.for_each(|p| p.encode(self.0)); - results.len().encode(self.0); - results.for_each(|p| p.encode(self.0)); - } +pub struct ComponentCoreTypeEncoder<'a>(pub(crate) &'a mut Vec); +impl<'a> ComponentCoreTypeEncoder<'a> { /// Define a module type. pub fn module(self, ty: &ModuleType) { ty.encode(self.0); } + + /// Define any core type other than a module type. + #[must_use = "the encoder must be used to encode the type"] + pub fn core(self) -> CoreTypeEncoder<'a> { + CoreTypeEncoder { + bytes: self.0, + push_prefix_if_component_core_type: true, + } + } } /// An encoder for the core type section of WebAssembly components. @@ -112,7 +106,7 @@ impl<'a> CoreTypeEncoder<'a> { /// /// let mut types = CoreTypeSection::new(); /// -/// types.module(&ModuleType::new()); +/// types.ty().module(&ModuleType::new()); /// /// let mut component = Component::new(); /// component.section(&types); @@ -145,29 +139,9 @@ impl CoreTypeSection { /// /// 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<'_> { + pub fn ty(&mut self) -> ComponentCoreTypeEncoder<'_> { 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 + ComponentCoreTypeEncoder(&mut self.bytes) } } @@ -203,11 +177,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) -> CoreTypeEncoder { + pub fn core_type(&mut self) -> ComponentCoreTypeEncoder { self.bytes.push(0x00); self.num_added += 1; self.core_types_added += 1; - CoreTypeEncoder(&mut self.bytes) + ComponentCoreTypeEncoder(&mut self.bytes) } /// Define a type in this component type. @@ -316,7 +290,7 @@ 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) -> CoreTypeEncoder { + pub fn core_type(&mut self) -> ComponentCoreTypeEncoder { self.0.core_type() } diff --git a/crates/wasm-encoder/src/core/code.rs b/crates/wasm-encoder/src/core/code.rs index 6b23235b54..f954c5bd8f 100644 --- a/crates/wasm-encoder/src/core/code.rs +++ b/crates/wasm-encoder/src/core/code.rs @@ -14,7 +14,7 @@ use std::borrow::Cow; /// }; /// /// let mut types = TypeSection::new(); -/// types.function(vec![], vec![ValType::I32]); +/// types.ty().function(vec![], vec![ValType::I32]); /// /// let mut functions = FunctionSection::new(); /// let type_index = 0; diff --git a/crates/wasm-encoder/src/core/types.rs b/crates/wasm-encoder/src/core/types.rs index 8b05ac4f66..bca27f8780 100644 --- a/crates/wasm-encoder/src/core/types.rs +++ b/crates/wasm-encoder/src/core/types.rs @@ -5,24 +5,13 @@ use crate::{encode_section, Encode, Section, SectionId}; pub struct SubType { /// Is the subtype final. pub is_final: bool, - /// The list of supertype indexes. As of GC MVP, there can be at most one supertype. + /// The list of supertype indexes. As of GC MVP, there can be at most one + /// supertype. pub supertype_idx: Option, /// The composite type of the subtype. pub composite_type: CompositeType, } -impl Encode for SubType { - fn encode(&self, sink: &mut Vec) { - // We only need to emit a prefix byte before the actual composite type - // when either the type is not final or it has a declared super type. - if self.supertype_idx.is_some() || !self.is_final { - sink.push(if self.is_final { 0x4f } else { 0x50 }); - self.supertype_idx.encode(sink); - } - self.composite_type.encode(sink); - } -} - /// Represents a composite type in a WebAssembly module. #[derive(Debug, Clone)] pub struct CompositeType { @@ -33,27 +22,6 @@ pub struct CompositeType { pub shared: bool, } -impl Encode for CompositeType { - fn encode(&self, sink: &mut Vec) { - if self.shared { - sink.push(0x65); - } - match &self.inner { - CompositeInnerType::Func(ty) => TypeSection::encode_function( - sink, - ty.params().iter().copied(), - ty.results().iter().copied(), - ), - CompositeInnerType::Array(ArrayType(ty)) => { - TypeSection::encode_array(sink, &ty.element_type, ty.mutable) - } - CompositeInnerType::Struct(ty) => { - TypeSection::encode_struct(sink, ty.fields.iter().cloned()) - } - } - } -} - /// A [`CompositeType`] can contain one of these types. #[derive(Debug, Clone)] pub enum CompositeInnerType { @@ -506,7 +474,7 @@ impl Encode for AbstractHeapType { /// /// let mut types = TypeSection::new(); /// -/// types.function([ValType::I32, ValType::I32], [ValType::I64]); +/// types.ty().function([ValType::I32, ValType::I32], [ValType::I64]); /// /// let mut module = Module::new(); /// module.section(&types); @@ -535,31 +503,61 @@ impl TypeSection { self.num_added == 0 } + /// Encode a function type in this type section. + #[must_use = "the encoder must be used to encode the type"] + pub fn ty(&mut self) -> CoreTypeEncoder { + self.num_added += 1; + CoreTypeEncoder { + bytes: &mut self.bytes, + push_prefix_if_component_core_type: false, + } + } +} + +impl Encode for TypeSection { + fn encode(&self, sink: &mut Vec) { + encode_section(sink, self.num_added, &self.bytes); + } +} + +impl Section for TypeSection { + fn id(&self) -> u8 { + SectionId::Type.into() + } +} + +/// A single-use encoder for encoding a type; this forces all encoding for a +/// type to be done in a single shot. +#[derive(Debug)] +pub struct CoreTypeEncoder<'a> { + pub(crate) bytes: &'a mut Vec, + // For the time being, this flag handles an ambiguous encoding in the + // component model: the `0x50` opcode represents both a core module type as + // well as a GC non-final `sub` type. To avoid this, the component model + // specification requires us to prefix a non-final `sub` type with `0x00` + // when it is used as a top-level core type of a component. Eventually + // (prior to the component model's v1.0 release), a module type will get a + // new opcode and this special logic can go away. + pub(crate) push_prefix_if_component_core_type: bool, +} +impl<'a> CoreTypeEncoder<'a> { /// Define a function type in this type section. - pub fn function(&mut self, params: P, results: R) -> &mut Self + pub fn function(mut self, params: P, results: R) where P: IntoIterator, P::IntoIter: ExactSizeIterator, R: IntoIterator, R::IntoIter: ExactSizeIterator, { - Self::encode_function(&mut self.bytes, params, results); - self.num_added += 1; - self + self.encode_function(params, results); } /// Define a function type in this type section. - pub fn func_type(&mut self, ty: &FuncType) -> &mut Self { - Self::encode_function( - &mut self.bytes, - ty.params().iter().cloned(), - ty.results().iter().cloned(), - ); - self.num_added += 1; - self + pub fn func_type(mut self, ty: &FuncType) { + self.encode_function(ty.params().iter().cloned(), ty.results().iter().cloned()); } - fn encode_function(sink: &mut Vec, params: P, results: R) + fn encode_function(&mut self, params: P, results: R) where P: IntoIterator, P::IntoIter: ExactSizeIterator, @@ -569,85 +567,101 @@ impl TypeSection { let params = params.into_iter(); let results = results.into_iter(); - sink.push(0x60); - params.len().encode(sink); - params.for_each(|p| p.encode(sink)); - results.len().encode(sink); - results.for_each(|p| p.encode(sink)); + self.bytes.push(0x60); + params.len().encode(self.bytes); + params.for_each(|p| p.encode(self.bytes)); + results.len().encode(self.bytes); + results.for_each(|p| p.encode(self.bytes)); } /// Define an array type in this type section. - pub fn array(&mut self, ty: &StorageType, mutable: bool) -> &mut Self { - Self::encode_array(&mut self.bytes, ty, mutable); - self.num_added += 1; - self + pub fn array(mut self, ty: &StorageType, mutable: bool) { + self.encode_array(ty, mutable); } - fn encode_array(sink: &mut Vec, ty: &StorageType, mutable: bool) { - sink.push(0x5e); - Self::encode_field(sink, ty, mutable); + fn encode_array(&mut self, ty: &StorageType, mutable: bool) { + self.bytes.push(0x5e); + self.encode_field(ty, mutable); } - fn encode_field(sink: &mut Vec, ty: &StorageType, mutable: bool) { - ty.encode(sink); - sink.push(mutable as u8); + fn encode_field(&mut self, ty: &StorageType, mutable: bool) { + ty.encode(self.bytes); + self.bytes.push(mutable as u8); } /// Define a struct type in this type section. - pub fn struct_(&mut self, fields: F) -> &mut Self + pub fn struct_(mut self, fields: F) where F: IntoIterator, F::IntoIter: ExactSizeIterator, { - Self::encode_struct(&mut self.bytes, fields); - self.num_added += 1; - self + self.encode_struct(fields); } - fn encode_struct(sink: &mut Vec, fields: F) + fn encode_struct(&mut self, fields: F) where F: IntoIterator, F::IntoIter: ExactSizeIterator, { let fields = fields.into_iter(); - sink.push(0x5f); - fields.len().encode(sink); + self.bytes.push(0x5f); + fields.len().encode(self.bytes); for f in fields { - Self::encode_field(sink, &f.element_type, f.mutable); + self.encode_field(&f.element_type, f.mutable); } } /// Define an explicit subtype in this type section. - pub fn subtype(&mut self, ty: &SubType) -> &mut Self { - ty.encode(&mut self.bytes); - self.num_added += 1; - self + pub fn subtype(mut self, ty: &SubType) { + self.encode_subtype(ty) + } + + /// Define an explicit subtype in this type section. + fn encode_subtype(&mut self, ty: &SubType) { + // We only need to emit a prefix byte before the actual composite type + // when either the `sub` type is not final or it has a declared super + // type (see notes on `push_prefix_if_component_core_type`). + if ty.supertype_idx.is_some() || !ty.is_final { + if ty.is_final { + self.bytes.push(0x4f); + } else { + if self.push_prefix_if_component_core_type { + self.bytes.push(0x00); + } + self.bytes.push(0x50); + } + ty.supertype_idx.encode(self.bytes); + } + if ty.composite_type.shared { + self.bytes.push(0x65); + } + match &ty.composite_type.inner { + CompositeInnerType::Func(ty) => { + self.encode_function(ty.params().iter().copied(), ty.results().iter().copied()) + } + CompositeInnerType::Array(ArrayType(ty)) => { + self.encode_array(&ty.element_type, ty.mutable) + } + CompositeInnerType::Struct(ty) => self.encode_struct(ty.fields.iter().cloned()), + } } /// Define an explicit recursion group in this type section. - pub fn rec(&mut self, types: T) -> &mut Self + pub fn rec(mut self, types: T) where T: IntoIterator, T::IntoIter: ExactSizeIterator, { + // When emitting a `rec` group, we will never emit `sub`'s special + // `0x00` prefix; that is only necessary when `sub` is not wrapped by + // `rec` (see notes on `push_prefix_if_component_core_type`). + self.push_prefix_if_component_core_type = false; let types = types.into_iter(); self.bytes.push(0x4e); - types.len().encode(&mut self.bytes); - types.for_each(|t| t.encode(&mut self.bytes)); - self.num_added += 1; - self - } -} - -impl Encode for TypeSection { - fn encode(&self, sink: &mut Vec) { - encode_section(sink, self.num_added, &self.bytes); - } -} - -impl Section for TypeSection { - fn id(&self) -> u8 { - SectionId::Type.into() + types.len().encode(self.bytes); + types.for_each(|t| { + self.encode_subtype(&t); + }); } } @@ -660,7 +674,7 @@ mod tests { #[test] fn func_types_dont_require_wasm_gc() { let mut types = TypeSection::new(); - types.subtype(&SubType { + types.ty().subtype(&SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs index 756bf517d0..3ea386625f 100644 --- a/crates/wasm-encoder/src/lib.rs +++ b/crates/wasm-encoder/src/lib.rs @@ -36,7 +36,7 @@ //! let mut types = TypeSection::new(); //! let params = vec![ValType::I32, ValType::I32]; //! let results = vec![ValType::I32]; -//! types.function(params, results); +//! types.ty().function(params, results); //! module.section(&types); //! //! // Encode the function section. diff --git a/crates/wasm-encoder/src/reencode.rs b/crates/wasm-encoder/src/reencode.rs index 83fc5286b2..918a8fb42e 100644 --- a/crates/wasm-encoder/src/reencode.rs +++ b/crates/wasm-encoder/src/reencode.rs @@ -3,6 +3,7 @@ //! The [`RoundtripReencoder`] allows encoding identical wasm to the parsed //! input. +use crate::CoreTypeEncoder; use std::convert::Infallible; mod component; @@ -421,10 +422,10 @@ pub trait Reencode { /// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section. fn parse_recursive_type_group( &mut self, - types: &mut crate::TypeSection, + encoder: CoreTypeEncoder, rec_group: wasmparser::RecGroup, ) -> Result<(), Error> { - utils::parse_recursive_type_group(self, types, rec_group) + utils::parse_recursive_type_group(self, encoder, rec_group) } fn parse_unknown_section( @@ -568,7 +569,7 @@ impl Reencode for RoundtripReencoder { #[allow(missing_docs)] // FIXME pub mod utils { use super::{Error, Reencode}; - use crate::Encode; + use crate::{CoreTypeEncoder, Encode}; pub fn parse_core_module( reencoder: &mut T, @@ -992,7 +993,7 @@ pub mod utils { section: wasmparser::TypeSectionReader<'_>, ) -> Result<(), Error> { for rec_group in section { - reencoder.parse_recursive_type_group(types, rec_group?)?; + reencoder.parse_recursive_type_group(types.ty(), rec_group?)?; } Ok(()) } @@ -1000,7 +1001,7 @@ pub mod utils { /// Parses a single [`wasmparser::RecGroup`] and adds it to the `types` section. pub fn parse_recursive_type_group( reencoder: &mut T, - types: &mut crate::TypeSection, + encoder: CoreTypeEncoder, rec_group: wasmparser::RecGroup, ) -> Result<(), Error> { if rec_group.is_explicit_rec_group() { @@ -1008,10 +1009,10 @@ pub mod utils { .into_types() .map(|t| reencoder.sub_type(t)) .collect::, _>>()?; - types.rec(subtypes); + encoder.rec(subtypes); } else { let ty = rec_group.into_types().next().unwrap(); - types.subtype(&reencoder.sub_type(ty)?); + encoder.subtype(&reencoder.sub_type(ty)?); } Ok(()) } diff --git a/crates/wasm-encoder/src/reencode/component.rs b/crates/wasm-encoder/src/reencode/component.rs index b0d7139a53..771b9c2e96 100644 --- a/crates/wasm-encoder/src/reencode/component.rs +++ b/crates/wasm-encoder/src/reencode/component.rs @@ -162,7 +162,7 @@ pub trait ReencodeComponent: Reencode { fn parse_component_core_type( &mut self, - ty: crate::CoreTypeEncoder<'_>, + ty: crate::ComponentCoreTypeEncoder<'_>, core: wasmparser::CoreType<'_>, ) -> Result<(), Error> { component_utils::parse_component_core_type(self, ty, core) @@ -221,14 +221,6 @@ pub trait ReencodeComponent: Reencode { component_utils::component_alias(self, alias) } - fn parse_component_sub_type( - &mut self, - ty: crate::CoreTypeEncoder<'_>, - sub: wasmparser::SubType, - ) -> Result<(), Error> { - component_utils::parse_component_sub_type(self, ty, sub) - } - fn parse_component_import_section( &mut self, imports: &mut crate::ComponentImportSection, @@ -668,11 +660,13 @@ pub mod component_utils { pub fn parse_component_core_type( reencoder: &mut T, - ty: crate::CoreTypeEncoder<'_>, + ty: crate::ComponentCoreTypeEncoder<'_>, decl: wasmparser::CoreType<'_>, ) -> Result<(), Error> { match decl { - wasmparser::CoreType::Sub(core) => reencoder.parse_component_sub_type(ty, core)?, + wasmparser::CoreType::Rec(rec) => { + reencoder.parse_recursive_type_group(ty.core(), rec)?; + } wasmparser::CoreType::Module(decls) => { ty.module(&reencoder.component_module_type(decls)?); } @@ -821,8 +815,8 @@ pub mod component_utils { decl: wasmparser::ModuleTypeDeclaration<'_>, ) -> Result<(), Error> { match decl { - wasmparser::ModuleTypeDeclaration::Type(ty) => { - reencoder.parse_component_sub_type(module.ty(), ty)? + wasmparser::ModuleTypeDeclaration::Type(rec) => { + reencoder.parse_recursive_type_group(module.ty(), rec)?; } wasmparser::ModuleTypeDeclaration::Export { name, ty } => { module.export(name, reencoder.entity_type(ty)?); @@ -890,34 +884,6 @@ pub mod component_utils { } } - pub fn parse_component_sub_type( - reencoder: &mut T, - ty: crate::CoreTypeEncoder<'_>, - sub: wasmparser::SubType, - ) -> Result<(), Error> { - if !sub.is_final || sub.supertype_idx.is_some() || sub.composite_type.shared { - return Err(Error::UnsupportedCoreTypeInComponent); - } - - let func = match sub.composite_type.inner { - wasmparser::CompositeInnerType::Func(f) => f, - _ => return Err(Error::UnsupportedCoreTypeInComponent), - }; - - ty.function( - func.params() - .iter() - .map(|t| reencoder.val_type(*t)) - .collect::, _>>()?, - func.results() - .iter() - .map(|t| reencoder.val_type(*t)) - .collect::, _>>()?, - ); - - Ok(()) - } - pub fn parse_component_import_section( reencoder: &mut T, imports: &mut crate::ComponentImportSection, diff --git a/crates/wasm-mutate/src/mutators/add_type.rs b/crates/wasm-mutate/src/mutators/add_type.rs index f007c75783..3bbdbc4041 100644 --- a/crates/wasm-mutate/src/mutators/add_type.rs +++ b/crates/wasm-mutate/src/mutators/add_type.rs @@ -70,16 +70,16 @@ impl Mutator for AddTypeMutator { .copied() .map(map_type) .collect::, _>>()?; - types.function(params, results); + types.ty().function(params, results); } // And then add our new type. - types.function(params, results); + types.ty().function(params, results); let types_section_index = config.info().types.unwrap(); Ok(Box::new(iter::once(Ok(config .info() .replace_section(types_section_index, &types))))) } else { - types.function(params, results); + types.ty().function(params, results); Ok(Box::new(iter::once(Ok(config .info() .insert_section(0, &types))))) diff --git a/crates/wasm-mutate/src/mutators/translate.rs b/crates/wasm-mutate/src/mutators/translate.rs index d1ac04c532..db60a0e5f3 100644 --- a/crates/wasm-mutate/src/mutators/translate.rs +++ b/crates/wasm-mutate/src/mutators/translate.rs @@ -134,7 +134,7 @@ pub fn func_type( ty: wasmparser::FuncType, s: &mut TypeSection, ) -> Result<()> { - s.function( + s.ty().function( ty.params() .iter() .map(|ty| t.translate_ty(ty)) diff --git a/crates/wasm-smith/src/component/encode.rs b/crates/wasm-smith/src/component/encode.rs index 3d53f2bfb5..5579e8e5cd 100644 --- a/crates/wasm-smith/src/component/encode.rs +++ b/crates/wasm-smith/src/component/encode.rs @@ -117,10 +117,11 @@ impl CoreTypeSection { } impl CoreType { - fn encode(&self, enc: wasm_encoder::CoreTypeEncoder<'_>) { + fn encode(&self, enc: wasm_encoder::ComponentCoreTypeEncoder<'_>) { match self { Self::Func(ty) => { - enc.function(ty.params.iter().copied(), ty.results.iter().copied()); + enc.core() + .function(ty.params.iter().copied(), ty.results.iter().copied()); } Self::Module(mod_ty) => { let mut enc_mod_ty = wasm_encoder::ModuleType::new(); diff --git a/crates/wasm-smith/src/core/encode.rs b/crates/wasm-smith/src/core/encode.rs index fc408e9c44..b7727996f8 100644 --- a/crates/wasm-smith/src/core/encode.rs +++ b/crates/wasm-smith/src/core/encode.rs @@ -36,21 +36,19 @@ impl Module { for group in &self.rec_groups { if group.end - group.start == 1 { let ty = &self.types[group.start]; - section.subtype(&wasm_encoder::SubType { + section.ty().subtype(&wasm_encoder::SubType { is_final: ty.is_final, supertype_idx: ty.supertype, composite_type: (&ty.composite_type).into(), }); } else { - section.rec( - self.types[group.clone()] - .iter() - .map(|ty| wasm_encoder::SubType { - is_final: ty.is_final, - supertype_idx: ty.supertype, - composite_type: (&ty.composite_type).into(), - }), - ); + section.ty().rec(self.types[group.clone()].iter().map(|ty| { + wasm_encoder::SubType { + is_final: ty.is_final, + supertype_idx: ty.supertype, + composite_type: (&ty.composite_type).into(), + } + })); } } diff --git a/crates/wasmparser/src/readers/component/types.rs b/crates/wasmparser/src/readers/component/types.rs index d707cb1b37..152c1c17d2 100644 --- a/crates/wasmparser/src/readers/component/types.rs +++ b/crates/wasmparser/src/readers/component/types.rs @@ -1,8 +1,9 @@ use crate::limits::*; use crate::prelude::*; +use crate::RecGroup; use crate::{ BinaryReader, ComponentAlias, ComponentExportName, ComponentImport, ComponentTypeRef, - FromReader, Import, Result, SectionLimited, SubType, TypeRef, ValType, + FromReader, Import, Result, SectionLimited, TypeRef, ValType, }; use core::fmt; @@ -17,19 +18,30 @@ pub enum OuterAliasKind { #[derive(Debug, Clone, Eq, PartialEq)] pub enum CoreType<'a> { /// The type is for a core subtype. - Sub(SubType), + Rec(RecGroup), /// 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 { + // For the time being, this special logic handles an ambiguous encoding + // in the component model: the `0x50` opcode represents both a core + // module type as well as a GC non-final `sub` type. To avoid this, the + // component model specification requires us to prefix a non-final `sub` + // type with `0x00` when it is used as a top-level core type of a + // component. Eventually (prior to the component model's v1.0 release), + // a module type will get a new opcode and this special logic can go + // away. Ok(match reader.peek()? { - 0x60 => CoreType::Sub(reader.read()?), - 0x5e | 0x5f => bail!( - reader.current_position(), - "no support for GC types in the component model yet" - ), + 0x00 => { + reader.read_u8()?; + let x = reader.peek()?; + if x != 0x50 { + return reader.invalid_leading_byte(x, "non-final sub type"); + } + CoreType::Rec(reader.read()?) + } 0x50 => { reader.read_u8()?; CoreType::Module( @@ -38,7 +50,7 @@ impl<'a> FromReader<'a> for CoreType<'a> { .collect::>()?, ) } - x => return reader.invalid_leading_byte(x, "core type"), + _ => CoreType::Rec(reader.read()?), }) } } @@ -47,7 +59,7 @@ impl<'a> FromReader<'a> for CoreType<'a> { #[derive(Debug, Clone, Eq, PartialEq)] pub enum ModuleTypeDeclaration<'a> { /// The module type definition is for a type. - Type(SubType), + Type(RecGroup), /// The module type definition is for an export. Export { /// The name of the exported item. diff --git a/crates/wasmparser/src/validator/component.rs b/crates/wasmparser/src/validator/component.rs index d29f896d74..7b4524fabc 100644 --- a/crates/wasmparser/src/validator/component.rs +++ b/crates/wasmparser/src/validator/component.rs @@ -266,13 +266,8 @@ impl ComponentState { check_max(current.type_count(), 1, MAX_WASM_TYPES, "types", offset)?; } match ty { - crate::CoreType::Sub(sub) => { - current.canonicalize_and_intern_rec_group( - features, - types, - RecGroup::implicit(offset, sub), - offset, - )?; + crate::CoreType::Rec(rec) => { + current.canonicalize_and_intern_rec_group(features, types, rec, offset)?; } crate::CoreType::Module(decls) => { let mod_ty = Self::create_module_type( @@ -1506,14 +1501,8 @@ impl ComponentState { for decl in decls { match decl { - crate::ModuleTypeDeclaration::Type(ty) => { - state.add_types( - RecGroup::implicit(offset, ty), - features, - types, - offset, - true, - )?; + crate::ModuleTypeDeclaration::Type(rec) => { + state.add_types(rec, features, types, offset, true)?; } crate::ModuleTypeDeclaration::Export { name, mut ty } => { let ty = state.check_type_ref(&mut ty, features, types, offset)?; diff --git a/crates/wasmparser/src/validator/types.rs b/crates/wasmparser/src/validator/types.rs index 2ed69c8fa3..aa0ace0166 100644 --- a/crates/wasmparser/src/validator/types.rs +++ b/crates/wasmparser/src/validator/types.rs @@ -257,7 +257,7 @@ pub enum CoreType { } /// Represents a unique identifier for a core type type known to a -/// [`crate::Validator`] +/// [`crate::Validator`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct CoreTypeId { diff --git a/crates/wasmparser/tests/big-module.rs b/crates/wasmparser/tests/big-module.rs index 06cf02d630..68d4d7f0ab 100644 --- a/crates/wasmparser/tests/big-module.rs +++ b/crates/wasmparser/tests/big-module.rs @@ -6,7 +6,7 @@ fn big_type_indices() { let mut module = Module::new(); let mut types = TypeSection::new(); for _ in 0..N { - types.function([], []); + types.ty().function([], []); } module.section(&types); let mut funcs = FunctionSection::new(); diff --git a/crates/wasmprinter/src/lib.rs b/crates/wasmprinter/src/lib.rs index c682e92d58..40422e9fae 100644 --- a/crates/wasmprinter/src/lib.rs +++ b/crates/wasmprinter/src/lib.rs @@ -744,61 +744,59 @@ impl Printer<'_, '_> { } fn print_core_type(&mut self, states: &mut Vec, ty: CoreType) -> Result<()> { - self.start_group("core type ")?; - self.print_name( - &states.last().unwrap().core.type_names, - states.last().unwrap().core.types.len() as u32, - )?; - let ty = match ty { - CoreType::Sub(ty) => { - let ty = match &ty.composite_type.inner { - CompositeInnerType::Func(f) => f, - CompositeInnerType::Array(_) | CompositeInnerType::Struct(_) => { - unreachable!("Wasm GC types cannot appear in components yet") - } - }; - self.result.write_str(" ")?; - self.start_group("func")?; - self.print_func_type(states.last().unwrap(), &ty, None)?; - self.end_group()?; - let composite_type = CompositeType { - inner: CompositeInnerType::Func(ty.clone()), - shared: false, - }; - Some(SubType { - is_final: true, - supertype_idx: None, - composite_type, - }) + match ty { + CoreType::Rec(rec) => { + self.print_rec(states.last_mut().unwrap(), None, rec, true)?; } CoreType::Module(decls) => { + self.start_group("core type ")?; + self.print_name( + &states.last().unwrap().core.type_names, + states.last().unwrap().core.types.len() as u32, + )?; self.print_module_type(states, decls.into_vec())?; - None + self.end_group()?; // `core type` itself + states.last_mut().unwrap().core.types.push(None); } - }; - self.end_group()?; // `core type` itself - - states.last_mut().unwrap().core.types.push(ty); + } Ok(()) } fn print_rec( &mut self, state: &mut State, - offset: usize, - types: impl Iterator, + offset: Option, + rec: RecGroup, + is_component: bool, ) -> Result<()> { - self.start_group("rec")?; - for ty in types { - self.newline(offset + 2)?; - self.print_type(state, ty)?; + if rec.is_explicit_rec_group() { + if is_component { + self.start_group("core rec")?; + } else { + self.start_group("rec")?; + } + for ty in rec.into_types() { + match offset { + Some(offset) => self.newline(offset + 2)?, + None => self.newline_unknown_pos()?, + } + self.print_type(state, ty, false)?; + } + self.end_group()?; // `rec` + } else { + assert_eq!(rec.types().len(), 1); + let ty = rec.into_types().next().unwrap(); + self.print_type(state, ty, is_component)?; } - self.end_group()?; // `rec` Ok(()) } - fn print_type(&mut self, state: &mut State, ty: SubType) -> Result<()> { - self.start_group("type ")?; + fn print_type(&mut self, state: &mut State, ty: SubType, is_component: bool) -> Result<()> { + if is_component { + self.start_group("core type ")?; + } else { + self.start_group("type ")?; + } let ty_idx = state.core.types.len() as u32; self.print_name(&state.core.type_names, ty_idx)?; self.result.write_str(" ")?; @@ -869,15 +867,8 @@ impl Printer<'_, '_> { for ty in parser.into_iter_with_offsets() { let (offset, rec_group) = ty?; self.newline(offset)?; - if rec_group.is_explicit_rec_group() { - self.print_rec(state, offset, rec_group.into_types())? - } else { - assert_eq!(rec_group.types().len(), 1); - let ty = rec_group.into_types().next().unwrap(); - self.print_type(state, ty)?; - } + self.print_rec(state, Some(offset), rec_group, false)?; } - Ok(()) } @@ -1831,8 +1822,8 @@ impl Printer<'_, '_> { for decl in decls { self.newline_unknown_pos()?; match decl { - ModuleTypeDeclaration::Type(ty) => { - self.print_type(states.last_mut().unwrap(), ty)? + ModuleTypeDeclaration::Type(rec) => { + self.print_rec(states.last_mut().unwrap(), None, rec, false)? } ModuleTypeDeclaration::OuterAlias { kind, count, index } => { self.print_outer_alias(states, kind, count, index)?; diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index db1b8b5343..58bec50fa2 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -3,11 +3,12 @@ use crate::core; use crate::core::EncodeOptions; use crate::token::{Id, Index, NameAnnotation, Span}; use wasm_encoder::{ - CanonicalFunctionSection, ComponentAliasSection, ComponentDefinedTypeEncoder, - ComponentExportSection, ComponentImportSection, ComponentInstanceSection, ComponentNameSection, - ComponentSection, ComponentSectionId, ComponentStartSection, ComponentTypeEncoder, - ComponentTypeSection, CoreTypeEncoder, CoreTypeSection, InstanceSection, NameMap, - NestedComponentSection, RawSection, SectionId, + CanonicalFunctionSection, ComponentAliasSection, ComponentCoreTypeEncoder, + ComponentDefinedTypeEncoder, ComponentExportSection, ComponentImportSection, + ComponentInstanceSection, ComponentNameSection, ComponentSection, ComponentSectionId, + ComponentStartSection, ComponentTypeEncoder, ComponentTypeSection, CompositeType, + CoreTypeSection, InstanceSection, NameMap, NestedComponentSection, RawSection, SectionId, + SubType, }; pub fn encode(component: &Component<'_>, options: &EncodeOptions) -> Vec { @@ -55,23 +56,18 @@ fn encode_fields( e.component } -fn encode_core_type(encoder: CoreTypeEncoder, ty: &CoreTypeDef) { +fn encode_core_type(encoder: ComponentCoreTypeEncoder, ty: &CoreTypeDef) { match ty { CoreTypeDef::Def(def) => { - if def.shared { - todo!("encoding of shared types not yet implemented") - } - match &def.kind { - core::InnerTypeKind::Func(f) => { - encoder.function( - f.params.iter().map(|(_, _, ty)| (*ty).into()), - f.results.iter().copied().map(Into::into), - ); - } - core::InnerTypeKind::Struct(_) | core::InnerTypeKind::Array(_) => { - todo!("encoding of GC proposal types not yet implemented") - } - } + let sub_type = SubType { + is_final: true, + supertype_idx: None, + composite_type: CompositeType { + shared: def.shared, + inner: (&def.kind).into(), + }, + }; + encoder.core().subtype(&sub_type); } CoreTypeDef::Module(t) => { encoder.module(&t.into()); @@ -884,15 +880,17 @@ impl From<&ModuleType<'_>> for wasm_encoder::ModuleType { for decl in &ty.decls { match decl { - ModuleTypeDecl::Type(t) => match &t.def.kind { - core::InnerTypeKind::Func(f) => encoded.ty().function( - f.params.iter().map(|(_, _, ty)| (*ty).into()), - f.results.iter().copied().map(Into::into), - ), - core::InnerTypeKind::Struct(_) | core::InnerTypeKind::Array(_) => { - todo!("encoding of GC proposal types not yet implemented") - } - }, + ModuleTypeDecl::Type(t) => { + let sub_type = SubType { + is_final: t.final_type.unwrap_or(true), + supertype_idx: t.parent.map(u32::from), + composite_type: CompositeType { + shared: t.def.shared, + inner: (&t.def.kind).into(), + }, + }; + encoded.ty().subtype(&sub_type); + } ModuleTypeDecl::Alias(a) => match &a.target { AliasTarget::Outer { outer, diff --git a/crates/wast/src/core/binary.rs b/crates/wast/src/core/binary.rs index 8758270936..b68f4cf410 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -312,6 +312,15 @@ impl Encode for FunctionType<'_> { } } +impl From<&FunctionType<'_>> for wasm_encoder::FuncType { + fn from(ft: &FunctionType) -> Self { + wasm_encoder::FuncType::new( + ft.params.iter().map(|(_, _, ty)| (*ty).into()), + ft.results.iter().map(|ty| (*ty).into()), + ) + } +} + impl Encode for StructType<'_> { fn encode(&self, e: &mut Vec) { self.fields.len().encode(e); @@ -322,6 +331,23 @@ impl Encode for StructType<'_> { } } +impl From<&StructType<'_>> for wasm_encoder::StructType { + fn from(st: &StructType) -> wasm_encoder::StructType { + wasm_encoder::StructType { + fields: st.fields.iter().map(|f| f.into()).collect(), + } + } +} + +impl From<&StructField<'_>> for wasm_encoder::FieldType { + fn from(f: &StructField) -> wasm_encoder::FieldType { + wasm_encoder::FieldType { + element_type: f.ty.into(), + mutable: f.mutable, + } + } +} + impl Encode for ArrayType<'_> { fn encode(&self, e: &mut Vec) { self.ty.encode(e); @@ -329,6 +355,16 @@ impl Encode for ArrayType<'_> { } } +impl From<&ArrayType<'_>> for wasm_encoder::ArrayType { + fn from(at: &ArrayType) -> Self { + let field = wasm_encoder::FieldType { + element_type: at.ty.into(), + mutable: at.mutable, + }; + wasm_encoder::ArrayType(field) + } +} + impl Encode for ExportType<'_> { fn encode(&self, e: &mut Vec) { self.name.encode(e); @@ -392,6 +428,17 @@ impl Encode for Type<'_> { } } +impl From<&InnerTypeKind<'_>> for wasm_encoder::CompositeInnerType { + fn from(kind: &InnerTypeKind) -> Self { + use wasm_encoder::CompositeInnerType::*; + match kind { + InnerTypeKind::Func(ft) => Func(ft.into()), + InnerTypeKind::Struct(st) => Struct(st.into()), + InnerTypeKind::Array(at) => Array(at.into()), + } + } +} + impl Encode for Rec<'_> { fn encode(&self, e: &mut Vec) { e.push(0x4e); @@ -507,6 +554,17 @@ impl<'a> Encode for StorageType<'a> { } } +impl From> for wasm_encoder::StorageType { + fn from(st: StorageType) -> Self { + use wasm_encoder::StorageType::*; + match st { + StorageType::I8 => I8, + StorageType::I16 => I16, + StorageType::Val(vt) => Val(vt.into()), + } + } +} + impl Encode for Import<'_> { fn encode(&self, e: &mut Vec) { self.module.encode(e); diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index 2124d80cf2..17f68972bd 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -1247,7 +1247,7 @@ impl<'a> EncodingState<'a> { let i = i as u32; let type_index = *sigs.entry(sig).or_insert_with(|| { let index = types.len(); - types.function( + types.ty().function( sig.params.iter().map(to_val_type), sig.results.iter().map(to_val_type), ); @@ -1724,7 +1724,7 @@ impl<'a> EncodingState<'a> { ); let mut shim = Module::default(); let mut section = TypeSection::new(); - section.function([], []); + section.ty().function([], []); shim.section(§ion); let mut section = ImportSection::new(); section.import("", "", EntityType::Function(0)); diff --git a/crates/wit-component/src/gc.rs b/crates/wit-component/src/gc.rs index de87da4521..045ff424bd 100644 --- a/crates/wit-component/src/gc.rs +++ b/crates/wit-component/src/gc.rs @@ -551,7 +551,7 @@ impl<'a> Module<'a> { map.types.push(i); let ty = map.func_type(ty.clone())?; - types.func_type(&ty); + types.ty().func_type(&ty); // Keep track of the "empty type" to see if we can reuse an // existing one or one needs to be injected if a `start` @@ -645,7 +645,7 @@ impl<'a> Module<'a> { let add_realloc_type = |types: &mut wasm_encoder::TypeSection| { let type_index = types.len(); - types.function( + types.ty().function( [ wasm_encoder::ValType::I32, wasm_encoder::ValType::I32, @@ -659,7 +659,7 @@ impl<'a> Module<'a> { let add_empty_type = |types: &mut wasm_encoder::TypeSection| { let type_index = types.len(); - types.function([], []); + types.ty().function([], []); type_index }; @@ -788,7 +788,7 @@ impl<'a> Module<'a> { // Generate a function type for this start function, adding a new // function type to the module if necessary. let empty_type = empty_type.unwrap_or_else(|| { - types.function([], []); + types.ty().function([], []); types.len() - 1 }); funcs.function(empty_type); diff --git a/crates/wit-component/src/linking.rs b/crates/wit-component/src/linking.rs index 0ba89cbe0b..1bae4105f6 100644 --- a/crates/wit-component/src/linking.rs +++ b/crates/wit-component/src/linking.rs @@ -289,7 +289,7 @@ fn make_env_module<'a>( Type::Function(ty) => { let index = get_and_increment(&mut function_count); entry.insert(index); - types.function( + types.ty().function( ty.parameters.iter().copied().map(ValType::from), ty.results.iter().copied().map(ValType::from), ); @@ -314,7 +314,7 @@ fn make_env_module<'a>( } let index = get_and_increment(&mut function_count); - types.function(vec![], vec![]); + types.ty().function(vec![], vec![]); imports.import(metadata.name, "_start", EntityType::Function(index)); wasi_start = Some(index); @@ -332,7 +332,7 @@ fn make_env_module<'a>( if let Some(exporter) = cabi_realloc_exporter { let index = get_and_increment(&mut function_count); - types.function([ValType::I32; 4], [ValType::I32]); + types.ty().function([ValType::I32; 4], [ValType::I32]); imports.import(exporter, "cabi_realloc", EntityType::Function(index)); exports.export("cabi_realloc", ExportKind::Func, index); } @@ -423,7 +423,7 @@ fn make_env_module<'a>( let mut code = CodeSection::new(); for (name, ty, _) in function_exports { let index = get_and_increment(&mut function_count); - types.function( + types.ty().function( ty.parameters.iter().copied().map(ValType::from), ty.results.iter().copied().map(ValType::from), ); @@ -515,9 +515,9 @@ fn make_init_module( // TODO: deduplicate types let mut types = TypeSection::new(); - types.function([], []); + types.ty().function([], []); let thunk_ty = 0; - types.function([ValType::I32], []); + types.ty().function([ValType::I32], []); let one_i32_param_ty = 1; let mut type_offset = 2; @@ -525,7 +525,7 @@ fn make_init_module( if metadata.dl_openable { for export in &metadata.exports { if let Type::Function(ty) = &export.key.ty { - types.function( + types.ty().function( ty.parameters.iter().copied().map(ValType::from), ty.results.iter().copied().map(ValType::from), ); @@ -534,7 +534,7 @@ fn make_init_module( } } for (_, ty, _) in function_exports { - types.function( + types.ty().function( ty.parameters.iter().copied().map(ValType::from), ty.results.iter().copied().map(ValType::from), ); @@ -1139,7 +1139,7 @@ fn make_stubs_module(missing: &[(&str, Export)]) -> Vec { unreachable!(); }; - types.function( + types.ty().function( ty.parameters.iter().copied().map(ValType::from), ty.results.iter().copied().map(ValType::from), ); diff --git a/src/bin/wasm-tools/component.rs b/src/bin/wasm-tools/component.rs index f9813c632b..adfd394567 100644 --- a/src/bin/wasm-tools/component.rs +++ b/src/bin/wasm-tools/component.rs @@ -880,7 +880,7 @@ impl UnbundleOpts { } let module_type_idx = module_ty.component.section.len(); - module_ty.component.section.module(&module_ty.module); + module_ty.component.section.ty().module(&module_ty.module); let name = format!("unbundled-module{}", imports.len()); imports.import( &name, @@ -943,7 +943,7 @@ impl CoreTypeInterner { }; let ret = self.section.len(); - self.section.function( + self.section.ty().core().function( f.params() .iter() .map(|p| RoundtripReencoder.val_type(*p)) diff --git a/tests/cli/dump/import-modules.wat.stdout b/tests/cli/dump/import-modules.wat.stdout index a128f8a5b1..6ce5dff9f5 100644 --- a/tests/cli/dump/import-modules.wat.stdout +++ b/tests/cli/dump/import-modules.wat.stdout @@ -2,7 +2,7 @@ | 0d 00 01 00 0x8 | 03 0d | core type section 0xa | 01 | 1 count - 0xb | 50 02 01 60 | [core type 0] Module([Type(SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } }), Import(Import { module: "", name: "f", ty: Func(0) })]) + 0xb | 50 02 01 60 | [core type 0] Module([Type(RecGroup { inner: Implicit((14, SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } })) }), Import(Import { module: "", name: "f", ty: Func(0) })]) | 00 00 00 00 | 01 66 00 00 0x17 | 0a 07 | component import section diff --git a/tests/cli/dump/module-types.wat.stdout b/tests/cli/dump/module-types.wat.stdout index 1e36b9d1b7..46fe586c58 100644 --- a/tests/cli/dump/module-types.wat.stdout +++ b/tests/cli/dump/module-types.wat.stdout @@ -2,7 +2,7 @@ | 0d 00 01 00 0x8 | 03 23 | core type section 0xa | 01 | 1 count - 0xb | 50 05 01 60 | [core type 0] Module([Type(SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } }), Import(Import { module: "", name: "f", ty: Func(0) }), Import(Import { module: "", name: "g", ty: Global(GlobalType { content_type: I32, mutable: false, shared: false }) }), Import(Import { module: "", name: "t", ty: Table(TableType { element_type: funcref, table64: false, initial: 1, maximum: None, shared: false }) }), Import(Import { module: "", name: "m", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None, page_size_log2: None }) })]) + 0xb | 50 05 01 60 | [core type 0] Module([Type(RecGroup { inner: Implicit((14, SubType { is_final: true, supertype_idx: None, composite_type: CompositeType { inner: Func(FuncType { params: [], results: [] }), shared: false } })) }), Import(Import { module: "", name: "f", ty: Func(0) }), Import(Import { module: "", name: "g", ty: Global(GlobalType { content_type: I32, mutable: false, shared: false }) }), Import(Import { module: "", name: "t", ty: Table(TableType { element_type: funcref, table64: false, initial: 1, maximum: None, shared: false }) }), Import(Import { module: "", name: "m", ty: Memory(MemoryType { memory64: false, shared: false, initial: 1, maximum: None, page_size_log2: None }) })]) | 00 00 00 00 | 01 66 00 00 | 00 00 01 67 diff --git a/tests/local/component-model/gc.wast b/tests/local/component-model/gc.wast new file mode 100644 index 0000000000..5496b7454d --- /dev/null +++ b/tests/local/component-model/gc.wast @@ -0,0 +1,54 @@ +(component binary + "\00asm" "\0d\00\01\00" ;; component header + "\03\07" ;; core type section, 7 bytes large + "\01" ;; 1 count + "\00\50" ;; sub type + "\00" ;; no supertypes + "\60" ;; function type + "\00\00" ;; no parameters, no results +) + +(component binary + "\00asm" "\0d\00\01\00" ;; component header + "\03\06" ;; core type section, 6 bytes large + "\02" ;; 2 count + "\50" ;; module type + "\00" ;; empty + "\60" ;; function type + "\00\00" ;; no parameters, no results +) + +(component binary + "\00asm" "\0d\00\01\00" ;; component header + "\03\09" ;; core type section, 9 bytes large + "\01" ;; 1 count + "\50" ;; module type + "\01" ;; 1 count + "\01" ;; core type in module + "\50" ;; sub type + "\00" ;; no supertypes + "\60" ;; function type + "\00\00" ;; no parameters, no results +) + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\03\06" ;; core type section, 6 bytes large + "\01" ;; 1 count + "\50" ;; attempted sub type, but actually a module type + "\00" ;; attempted zero super types, but actually empty + "\60" ;; function type + "\00\00" ;; no parameters, no results + ) +"unexpected data at the end of the section") + +(assert_malformed + (component binary + "\00asm" "\0d\00\01\00" ;; component header + "\03\05" ;; core type section, 5 bytes large + "\01" ;; 1 count + "\00\60" ;; attempted function type with invalid prefix + "\00\00" ;; no parameters, no results + ) +"invalid leading byte (0x60) for non-final sub type") diff --git a/tests/snapshots/local/component-model/gc.wast.json b/tests/snapshots/local/component-model/gc.wast.json new file mode 100644 index 0000000000..8f91052e09 --- /dev/null +++ b/tests/snapshots/local/component-model/gc.wast.json @@ -0,0 +1,34 @@ +{ + "source_filename": "tests/local/component-model/gc.wast", + "commands": [ + { + "type": "module", + "line": 1, + "filename": "gc.0.wasm" + }, + { + "type": "module", + "line": 11, + "filename": "gc.1.wasm" + }, + { + "type": "module", + "line": 21, + "filename": "gc.2.wasm" + }, + { + "type": "assert_malformed", + "line": 35, + "filename": "gc.3.wasm", + "text": "unexpected data at the end of the section", + "module_type": "binary" + }, + { + "type": "assert_malformed", + "line": 47, + "filename": "gc.4.wasm", + "text": "invalid leading byte (0x60) for non-final sub type", + "module_type": "binary" + } + ] +} \ No newline at end of file diff --git a/tests/snapshots/local/component-model/gc.wast/0.print b/tests/snapshots/local/component-model/gc.wast/0.print new file mode 100644 index 0000000000..c6b16f991b --- /dev/null +++ b/tests/snapshots/local/component-model/gc.wast/0.print @@ -0,0 +1,3 @@ +(component + (core type (;0;) (sub (func))) +) diff --git a/tests/snapshots/local/component-model/gc.wast/1.print b/tests/snapshots/local/component-model/gc.wast/1.print new file mode 100644 index 0000000000..e2b5d6ef42 --- /dev/null +++ b/tests/snapshots/local/component-model/gc.wast/1.print @@ -0,0 +1,6 @@ +(component + (core type (;0;) + (module) + ) + (core type (;1;) (func)) +) diff --git a/tests/snapshots/local/component-model/gc.wast/2.print b/tests/snapshots/local/component-model/gc.wast/2.print new file mode 100644 index 0000000000..b68d01c884 --- /dev/null +++ b/tests/snapshots/local/component-model/gc.wast/2.print @@ -0,0 +1,7 @@ +(component + (core type (;0;) + (module + (type (;0;) (sub (func))) + ) + ) +)