Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a component-model feature to wat/wast/wasm-encoder #1844

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,13 @@ 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: 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
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
7 changes: 7 additions & 0 deletions crates/wasm-encoder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
2 changes: 2 additions & 0 deletions crates/wasm-encoder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down
5 changes: 3 additions & 2 deletions crates/wasm-encoder/src/raw.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{ComponentSection, Encode, Section};
use crate::{Encode, Section};

/// A section made up of uninterpreted, raw bytes.
///
Expand All @@ -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
}
Expand Down
2 changes: 2 additions & 0 deletions crates/wasm-encoder/src/reencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-smith/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
6 changes: 5 additions & 1 deletion crates/wast/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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', 'wasm-encoder/component-model']

[[test]]
name = "parse-fail"
harness = false
23 changes: 1 addition & 22 deletions crates/wast/src/component/binary.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -587,27 +587,6 @@ impl From<&CoreItemRef<'_, core::ExportKind>> for (wasm_encoder::ExportKind, u32
}
}

impl From<core::ExportKind> 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<Index<'_>> for u32 {
fn from(i: Index<'_>) -> Self {
match i {
Index::Num(i, _) => i,
Index::Id(_) => unreachable!("unresolved index in encoding: {:?}", i),
}
}
}

impl<T> From<&ItemRef<'_, T>> for u32 {
fn from(i: &ItemRef<'_, T>) -> Self {
assert!(i.export_names.is_empty());
Expand Down
1 change: 1 addition & 0 deletions crates/wast/src/component/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
30 changes: 30 additions & 0 deletions crates/wast/src/component_disabled.rs
Original file line number Diff line number Diff line change
@@ -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<Id<'a>>,

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<Self> {
Err(parser.error("support for parsing components disabled at compile time"))
}
}
26 changes: 26 additions & 0 deletions crates/wast/src/core/binary.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(feature = "component-model")]
use crate::component::Component;
use crate::core::*;
use crate::encode::Encode;
Expand Down Expand Up @@ -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<'_>,
Expand All @@ -91,7 +93,10 @@ impl<'a> EncodeOptions<'a> {
pub fn encode_wat(&self, wat: &mut Wat<'_>) -> std::result::Result<Vec<u8>, 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!(),
}
}
}
Expand Down Expand Up @@ -574,6 +579,15 @@ impl Index<'_> {
}
}

impl From<Index<'_>> 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;
Expand Down Expand Up @@ -636,6 +650,18 @@ impl SectionItem for Export<'_> {
}
}

impl From<ExportKind> 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;
Expand Down
1 change: 1 addition & 0 deletions crates/wast/src/core/resolve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
4 changes: 4 additions & 0 deletions crates/wast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
26 changes: 22 additions & 4 deletions crates/wast/src/wast.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(feature = "component-model")]
use crate::component::WastVal;
use crate::core::{WastArgCore, WastRetCore};
use crate::kw;
Expand Down Expand Up @@ -358,10 +359,13 @@ fn parse_wast_module<'a>(parser: Parser<'a>) -> Result<WastDirective<'a>> {
crate::core::Module::parse_without_module_keyword(span, parser)?,
))
}
fn parse_component(span: Span, parser: Parser<'_>) -> Result<Wat<'_>> {
Ok(Wat::Component(
crate::component::Component::parse_without_component_keyword(span, parser)?,
))
fn parse_component(_span: Span, parser: Parser<'_>) -> Result<Wat<'_>> {
#[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::<kw::component>()? {
(
Expand Down Expand Up @@ -496,33 +500,47 @@ 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<Self> {
#[cfg(feature = "component-model")]
if parser.peek::<WastArgCore<'_>>()? {
Ok(WastArg::Core(parser.parse()?))
} else {
Ok(WastArg::Component(parser.parse()?))
}

#[cfg(not(feature = "component-model"))]
Ok(WastArg::Core(parser.parse()?))
}
}

#[derive(Debug)]
#[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<Self> {
#[cfg(feature = "component-model")]
if parser.peek::<WastRetCore<'_>>()? {
Ok(WastRet::Core(parser.parse()?))
} else {
Ok(WastRet::Component(parser.parse()?))
}

#[cfg(not(feature = "component-model"))]
Ok(WastRet::Core(parser.parse()?))
}
}

Expand Down
5 changes: 5 additions & 0 deletions crates/wat/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []