From 4df0423c5e3ffd45cd9d80c47941b873a6ad6bd6 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 1 Oct 2024 14:22:40 -0700 Subject: [PATCH 1/4] Add a crate feature for component-model support to wast/wat In case folks depend on these crates but aren't interested in the component support this enables compiling it all out. --- .github/workflows/main.yml | 4 ++++ crates/wast/Cargo.toml | 6 +++++- crates/wast/src/component/binary.rs | 23 +------------------- crates/wast/src/component/component.rs | 1 + crates/wast/src/component_disabled.rs | 30 ++++++++++++++++++++++++++ crates/wast/src/core/binary.rs | 26 ++++++++++++++++++++++ crates/wast/src/core/resolve/mod.rs | 1 + crates/wast/src/lib.rs | 4 ++++ crates/wast/src/wast.rs | 26 ++++++++++++++++++---- crates/wat/Cargo.toml | 5 +++++ 10 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 crates/wast/src/component_disabled.rs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d96f9d4897..4fe3564b1b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -247,6 +247,10 @@ jobs: - run: cargo check --no-default-features -p wasmparser --features serde,no-hash-maps - run: cargo check --no-default-features -p wast - run: cargo check --no-default-features -p wast --features wasm-module + - run: cargo check --no-default-features -p wast --features wasm-module,component-model + - run: cargo check --no-default-features -p wat + - run: cargo check --no-default-features -p wat --features component-model + - run: cargo check --no-default-features -p wat --features dwarf - run: | if cargo tree -p wasm-smith --no-default-features -e no-dev | grep wasmparser; then echo wasm-smith without default features should not depend on wasmparser diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index ea72785d5b..3697f86a0f 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -35,7 +35,7 @@ wat = { path = "../wat" } rand = { workspace = true } [features] -default = ['wasm-module'] +default = ['wasm-module', 'component-model'] # Includes default parsing support for `*.wat` and `*.wast` files (wasm # modules). This isn't always needed though if you're parsing just an @@ -50,6 +50,10 @@ wasm-module = [] # source. dwarf = ["dep:gimli"] +# On-by-default this builds in support for parsing the text format of +# components. +component-model = ['wasm-module'] + [[test]] name = "parse-fail" harness = false diff --git a/crates/wast/src/component/binary.rs b/crates/wast/src/component/binary.rs index 078c3477d3..b38863192c 100644 --- a/crates/wast/src/component/binary.rs +++ b/crates/wast/src/component/binary.rs @@ -1,7 +1,7 @@ use crate::component::*; use crate::core; use crate::core::EncodeOptions; -use crate::token::{Id, Index, NameAnnotation}; +use crate::token::{Id, NameAnnotation}; use wasm_encoder::{ CanonicalFunctionSection, ComponentAliasSection, ComponentCoreTypeEncoder, ComponentDefinedTypeEncoder, ComponentExportSection, ComponentImportSection, @@ -587,27 +587,6 @@ impl From<&CoreItemRef<'_, core::ExportKind>> for (wasm_encoder::ExportKind, u32 } } -impl From for wasm_encoder::ExportKind { - fn from(kind: core::ExportKind) -> Self { - match kind { - core::ExportKind::Func => Self::Func, - core::ExportKind::Table => Self::Table, - core::ExportKind::Memory => Self::Memory, - core::ExportKind::Global => Self::Global, - core::ExportKind::Tag => Self::Tag, - } - } -} - -impl From> for u32 { - fn from(i: Index<'_>) -> Self { - match i { - Index::Num(i, _) => i, - Index::Id(_) => unreachable!("unresolved index in encoding: {:?}", i), - } - } -} - impl From<&ItemRef<'_, T>> for u32 { fn from(i: &ItemRef<'_, T>) -> Self { assert!(i.export_names.is_empty()); diff --git a/crates/wast/src/component/component.rs b/crates/wast/src/component/component.rs index f6d9f5b7e3..30f60154c5 100644 --- a/crates/wast/src/component/component.rs +++ b/crates/wast/src/component/component.rs @@ -8,6 +8,7 @@ use crate::token::{Id, NameAnnotation, Span}; /// A parsed WebAssembly component module. #[derive(Debug)] +#[non_exhaustive] pub struct Component<'a> { /// Where this `component` was defined pub span: Span, diff --git a/crates/wast/src/component_disabled.rs b/crates/wast/src/component_disabled.rs new file mode 100644 index 0000000000..86c2d25620 --- /dev/null +++ b/crates/wast/src/component_disabled.rs @@ -0,0 +1,30 @@ +//! Disabled support for the component model. + +use crate::parser::{Parse, Parser, Result}; +use crate::token::{Id, Span}; + +#[derive(Debug)] +enum Uninhabited {} + +/// Empty definition of a component that cannot be created. +#[derive(Debug)] +pub struct Component<'a> { + /// Where this `component` was defined + pub span: Span, + /// An optional identifier this component is known by + pub id: Option>, + + x: Uninhabited, +} + +impl Component<'_> { + pub(crate) fn validate(&self, _parser: Parser<'_>) -> Result<()> { + match self.x {} + } +} + +impl<'a> Parse<'a> for Component<'a> { + fn parse(parser: Parser<'a>) -> Result { + Err(parser.error("support for parsing components disabled at compile time")) + } +} diff --git a/crates/wast/src/core/binary.rs b/crates/wast/src/core/binary.rs index 69314d375a..726691bb7f 100644 --- a/crates/wast/src/core/binary.rs +++ b/crates/wast/src/core/binary.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "component-model")] use crate::component::Component; use crate::core::*; use crate::encode::Encode; @@ -77,6 +78,7 @@ impl<'a> EncodeOptions<'a> { /// Encodes the given [`Component`] with these options. /// /// For more information see [`Component::encode`]. + #[cfg(feature = "component-model")] pub fn encode_component( &self, component: &mut Component<'_>, @@ -91,7 +93,10 @@ impl<'a> EncodeOptions<'a> { pub fn encode_wat(&self, wat: &mut Wat<'_>) -> std::result::Result, crate::Error> { match wat { Wat::Module(m) => self.encode_module(m), + #[cfg(feature = "component-model")] Wat::Component(c) => self.encode_component(c), + #[cfg(not(feature = "component-model"))] + Wat::Component(_) => unreachable!(), } } } @@ -574,6 +579,15 @@ impl Index<'_> { } } +impl From> for u32 { + fn from(i: Index<'_>) -> Self { + match i { + Index::Num(i, _) => i, + Index::Id(_) => unreachable!("unresolved index in encoding: {:?}", i), + } + } +} + impl SectionItem for Table<'_> { type Section = wasm_encoder::TableSection; const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Table; @@ -636,6 +650,18 @@ impl SectionItem for Export<'_> { } } +impl From for wasm_encoder::ExportKind { + fn from(kind: ExportKind) -> Self { + match kind { + ExportKind::Func => Self::Func, + ExportKind::Table => Self::Table, + ExportKind::Memory => Self::Memory, + ExportKind::Global => Self::Global, + ExportKind::Tag => Self::Tag, + } + } +} + impl SectionItem for Elem<'_> { type Section = wasm_encoder::ElementSection; const ANCHOR: CustomPlaceAnchor = CustomPlaceAnchor::Elem; diff --git a/crates/wast/src/core/resolve/mod.rs b/crates/wast/src/core/resolve/mod.rs index a5bcf623db..63c6729db9 100644 --- a/crates/wast/src/core/resolve/mod.rs +++ b/crates/wast/src/core/resolve/mod.rs @@ -6,6 +6,7 @@ mod deinline_import_export; mod names; pub(crate) mod types; +#[cfg(feature = "component-model")] pub(crate) use names::ResolveCoreType; #[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] diff --git a/crates/wast/src/lib.rs b/crates/wast/src/lib.rs index 518ec2fb58..b197ed33b1 100644 --- a/crates/wast/src/lib.rs +++ b/crates/wast/src/lib.rs @@ -377,6 +377,10 @@ id! { pub mod core; // Support for component model parsing + #[cfg(feature = "component-model")] + pub mod component; + #[cfg(not(feature = "component-model"))] + #[path = "component_disabled.rs"] pub mod component; } diff --git a/crates/wast/src/wast.rs b/crates/wast/src/wast.rs index 4b7d16330c..0112c56251 100644 --- a/crates/wast/src/wast.rs +++ b/crates/wast/src/wast.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "component-model")] use crate::component::WastVal; use crate::core::{WastArgCore, WastRetCore}; use crate::kw; @@ -358,10 +359,13 @@ fn parse_wast_module<'a>(parser: Parser<'a>) -> Result> { crate::core::Module::parse_without_module_keyword(span, parser)?, )) } - fn parse_component(span: Span, parser: Parser<'_>) -> Result> { - Ok(Wat::Component( - crate::component::Component::parse_without_component_keyword(span, parser)?, - )) + fn parse_component(_span: Span, parser: Parser<'_>) -> Result> { + #[cfg(feature = "component-model")] + return Ok(Wat::Component( + crate::component::Component::parse_without_component_keyword(_span, parser)?, + )); + #[cfg(not(feature = "component-model"))] + return Err(parser.error("component model support disabled at compile time")); } let (span, ctor) = if parser.peek::()? { ( @@ -496,16 +500,25 @@ pub enum QuoteWatTest { #[allow(missing_docs)] pub enum WastArg<'a> { Core(WastArgCore<'a>), + // TODO: technically this isn't cargo-compliant since it means that this + // isn't and additive feature by defining this conditionally. That being + // said this seems unlikely to break many in practice so this isn't a shared + // type, so fixing this is left to a future commit. + #[cfg(feature = "component-model")] Component(WastVal<'a>), } impl<'a> Parse<'a> for WastArg<'a> { fn parse(parser: Parser<'a>) -> Result { + #[cfg(feature = "component-model")] if parser.peek::>()? { Ok(WastArg::Core(parser.parse()?)) } else { Ok(WastArg::Component(parser.parse()?)) } + + #[cfg(not(feature = "component-model"))] + Ok(WastArg::Core(parser.parse()?)) } } @@ -513,16 +526,21 @@ impl<'a> Parse<'a> for WastArg<'a> { #[allow(missing_docs)] pub enum WastRet<'a> { Core(WastRetCore<'a>), + #[cfg(feature = "component-model")] Component(WastVal<'a>), } impl<'a> Parse<'a> for WastRet<'a> { fn parse(parser: Parser<'a>) -> Result { + #[cfg(feature = "component-model")] if parser.peek::>()? { Ok(WastRet::Core(parser.parse()?)) } else { Ok(WastRet::Component(parser.parse()?)) } + + #[cfg(not(feature = "component-model"))] + Ok(WastRet::Core(parser.parse()?)) } } diff --git a/crates/wat/Cargo.toml b/crates/wat/Cargo.toml index 56285a71e2..303333b747 100644 --- a/crates/wat/Cargo.toml +++ b/crates/wat/Cargo.toml @@ -23,7 +23,12 @@ workspace = true wast = { workspace = true } [features] +default = ['component-model'] + # Off-by-default feature to support emitting DWARF debugging information in # parsed binaries pointing back to source locations in the original `*.wat` # source. dwarf = ['wast/dwarf'] + +# On-by-default feature to support parsing the component model text format. +component-model = [] From f0d3a091f919801232655a77ce3bb0a83cc18217 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 1 Oct 2024 14:26:59 -0700 Subject: [PATCH 2/4] Add a Cargo feature for components in wasm-encoder If users are interested it can be used to reduce the compile-time of the crate and amount of code brought in by removing much of it at compile time. Support remains enabled by default, however. --- .github/workflows/main.yml | 3 +++ Cargo.toml | 2 +- crates/wasm-encoder/Cargo.toml | 7 +++++++ crates/wasm-encoder/src/lib.rs | 2 ++ crates/wasm-encoder/src/raw.rs | 5 +++-- crates/wasm-encoder/src/reencode.rs | 2 ++ crates/wast/Cargo.toml | 2 +- 7 files changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4fe3564b1b..2a4ee5e091 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -251,6 +251,9 @@ jobs: - run: cargo check --no-default-features -p wat - run: cargo check --no-default-features -p wat --features component-model - run: cargo check --no-default-features -p wat --features dwarf + - run: cargo check --no-default-features -p wasm-encoder + - run: cargo check --no-default-features -p wasm-encoder --features component-model + - run: cargo check --no-default-features -p wasm-encoder --features wasmparser - run: | if cargo tree -p wasm-smith --no-default-features -e no-dev | grep wasmparser; then echo wasm-smith without default features should not depend on wasmparser diff --git a/Cargo.toml b/Cargo.toml index 73bab177e8..5f5292abf5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,7 +97,7 @@ gimli = "0.30.0" id-arena = "2" wasm-compose = { version = "0.218.0", path = "crates/wasm-compose" } -wasm-encoder = { version = "0.218.0", path = "crates/wasm-encoder" } +wasm-encoder = { version = "0.218.0", path = "crates/wasm-encoder", default-features = false } wasm-metadata = { version = "0.218.0", path = "crates/wasm-metadata" } wasm-mutate = { version = "0.218.0", path = "crates/wasm-mutate" } wasm-shrink = { version = "0.218.0", path = "crates/wasm-shrink" } diff --git a/crates/wasm-encoder/Cargo.toml b/crates/wasm-encoder/Cargo.toml index b8b85f980a..d4722e51f5 100644 --- a/crates/wasm-encoder/Cargo.toml +++ b/crates/wasm-encoder/Cargo.toml @@ -31,3 +31,10 @@ anyhow = { workspace = true } tempfile = "3.2.0" wasmparser = { path = "../wasmparser" } wasmprinter = { path = "../wasmprinter" } + +[features] +default = ['component-model'] + +# On-by-default: conditional support for emitting components in addition to +# core modules. +component-model = [] diff --git a/crates/wasm-encoder/src/lib.rs b/crates/wasm-encoder/src/lib.rs index 3ea386625f..5b436b3f8b 100644 --- a/crates/wasm-encoder/src/lib.rs +++ b/crates/wasm-encoder/src/lib.rs @@ -71,12 +71,14 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![deny(missing_docs, missing_debug_implementations)] +#[cfg(feature = "component-model")] mod component; mod core; mod raw; #[cfg(feature = "wasmparser")] pub mod reencode; +#[cfg(feature = "component-model")] pub use self::component::*; pub use self::core::*; pub use self::raw::*; diff --git a/crates/wasm-encoder/src/raw.rs b/crates/wasm-encoder/src/raw.rs index a1323ca88e..e7b4a5b5b8 100644 --- a/crates/wasm-encoder/src/raw.rs +++ b/crates/wasm-encoder/src/raw.rs @@ -1,4 +1,4 @@ -use crate::{ComponentSection, Encode, Section}; +use crate::{Encode, Section}; /// A section made up of uninterpreted, raw bytes. /// @@ -23,7 +23,8 @@ impl Section for RawSection<'_> { } } -impl ComponentSection for RawSection<'_> { +#[cfg(feature = "component-model")] +impl crate::ComponentSection for RawSection<'_> { fn id(&self) -> u8 { self.id } diff --git a/crates/wasm-encoder/src/reencode.rs b/crates/wasm-encoder/src/reencode.rs index 83ee26847e..e356395af8 100644 --- a/crates/wasm-encoder/src/reencode.rs +++ b/crates/wasm-encoder/src/reencode.rs @@ -6,8 +6,10 @@ use crate::CoreTypeEncoder; use std::convert::Infallible; +#[cfg(feature = "component-model")] mod component; +#[cfg(feature = "component-model")] pub use self::component::*; #[allow(missing_docs)] // FIXME diff --git a/crates/wast/Cargo.toml b/crates/wast/Cargo.toml index 3697f86a0f..ee78017dbc 100644 --- a/crates/wast/Cargo.toml +++ b/crates/wast/Cargo.toml @@ -52,7 +52,7 @@ dwarf = ["dep:gimli"] # On-by-default this builds in support for parsing the text format of # components. -component-model = ['wasm-module'] +component-model = ['wasm-module', 'wasm-encoder/component-model'] [[test]] name = "parse-fail" From 0f70fbfdbd11d06be909c61f81f3f71ab729ebed Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 6 Oct 2024 14:04:21 -0700 Subject: [PATCH 3/4] Fix standalone build of wasm-smith --- crates/wasm-smith/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wasm-smith/Cargo.toml b/crates/wasm-smith/Cargo.toml index 4595e250e6..46c229334d 100644 --- a/crates/wasm-smith/Cargo.toml +++ b/crates/wasm-smith/Cargo.toml @@ -28,7 +28,7 @@ indexmap = { workspace = true } leb128 = { workspace = true } serde = { workspace = true, optional = true } serde_derive = { workspace = true, optional = true } -wasm-encoder = { workspace = true } +wasm-encoder = { workspace = true, features = ['component-model'] } wasmparser = { workspace = true, optional = true, features = ['validate'] } wat = { workspace = true, optional = true } From cd938a369025aa0aa868b00d96adb4977ffe7dd7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sun, 6 Oct 2024 14:07:23 -0700 Subject: [PATCH 4/4] Fix standalone build of wasm-metadata --- crates/wasm-metadata/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/wasm-metadata/Cargo.toml b/crates/wasm-metadata/Cargo.toml index 8809575ad0..f6d5a65701 100644 --- a/crates/wasm-metadata/Cargo.toml +++ b/crates/wasm-metadata/Cargo.toml @@ -14,7 +14,7 @@ workspace = true clap = { workspace = true, optional = true } anyhow = { workspace = true } wasmparser = { workspace = true } -wasm-encoder = { workspace = true } +wasm-encoder = { workspace = true, features = ['component-model'] } indexmap = { workspace = true, features = ["serde"] } serde = { workspace = true } serde_derive = { workspace = true }