From 7cec276e1a3e600bd8036f672c9483d875f164e8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 17 Jul 2023 14:17:41 -0500 Subject: [PATCH] Remove public deps from `wasm-metadata`'s API (#1130) Currently whenever `wasmparser` or `wasm-encoder` have a major version bump this requires a major revision of `wasm-metadata` to be released due to their appearance in the API of `wasm-metadata`. This in turn forces a major version bump of `wit-component` due to `wit-component`'s usage of `wasm-metadata` in its public API. The `wasmparser` and `wasm-encoder` crates, however, are relatively "unstable" crates in that the amount of features they support for wasm are shifting quite a lot over time meaning that they have a lot of major version bumps. Coupling this rate of change to `wit-component` which is expected to be embedded in many WIT-related bindings generators I'm predicting won't be the best development story. To decouple these crates this commit removes the `wasmparser` and `wasm-encoder` types from the API of `wasm-metadata` by making them internal implementation details. After this it's possible to have a major revision of `wasmparser` without updating the major revision of `wasm-metadata` or `wit-component` for example. --- crates/wasm-encoder/src/component.rs | 8 +++- crates/wasm-encoder/src/core/custom.rs | 18 ++++++++ crates/wasm-metadata/src/lib.rs | 57 +++++++++++++++++--------- crates/wit-component/src/builder.rs | 3 +- crates/wit-component/src/encoding.rs | 9 +++- crates/wit-component/src/gc.rs | 8 ++-- 6 files changed, 75 insertions(+), 28 deletions(-) diff --git a/crates/wasm-encoder/src/component.rs b/crates/wasm-encoder/src/component.rs index 68ee1b6448..82d14438a6 100644 --- a/crates/wasm-encoder/src/component.rs +++ b/crates/wasm-encoder/src/component.rs @@ -20,7 +20,7 @@ pub use self::names::*; pub use self::start::*; pub use self::types::*; -use crate::{CustomSection, Encode, ProducersSection}; +use crate::{CustomSection, Encode, ProducersSection, RawCustomSection}; // Core sorts extended by the component model const CORE_TYPE_SORT: u8 = 0x10; @@ -153,6 +153,12 @@ impl ComponentSection for CustomSection<'_> { } } +impl ComponentSection for RawCustomSection<'_> { + fn id(&self) -> u8 { + ComponentSectionId::CoreCustom.into() + } +} + impl ComponentSection for ProducersSection { fn id(&self) -> u8 { ComponentSectionId::CoreCustom.into() diff --git a/crates/wasm-encoder/src/core/custom.rs b/crates/wasm-encoder/src/core/custom.rs index e05ce01d7b..870ee62617 100644 --- a/crates/wasm-encoder/src/core/custom.rs +++ b/crates/wasm-encoder/src/core/custom.rs @@ -26,6 +26,24 @@ impl Section for CustomSection<'_> { } } +/// A raw custom section where the bytes specified contain the leb-encoded +/// length of the custom section, the custom section's name, and the custom +/// section's data. +#[derive(Clone, Debug)] +pub struct RawCustomSection<'a>(pub &'a [u8]); + +impl Encode for RawCustomSection<'_> { + fn encode(&self, sink: &mut Vec) { + sink.extend(self.0); + } +} + +impl Section for RawCustomSection<'_> { + fn id(&self) -> u8 { + SectionId::Custom.into() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/crates/wasm-metadata/src/lib.rs b/crates/wasm-metadata/src/lib.rs index 44b79f6f02..47d9ca75eb 100644 --- a/crates/wasm-metadata/src/lib.rs +++ b/crates/wasm-metadata/src/lib.rs @@ -51,8 +51,7 @@ impl Producers { ModuleSection { .. } | ComponentSection { .. } => depth += 1, End { .. } => depth -= 1, CustomSection(c) if c.name() == "producers" && depth == 0 => { - let section = ProducersSectionReader::new(c.data(), c.data_offset())?; - let producers = Self::from_reader(section)?; + let producers = Self::from_bytes(c.data(), c.data_offset())?; return Ok(Some(producers)); } _ => {} @@ -61,7 +60,8 @@ impl Producers { Ok(None) } /// Read the producers section from a Wasm binary. - pub fn from_reader(section: ProducersSectionReader) -> Result { + pub fn from_bytes(bytes: &[u8], offset: usize) -> Result { + let section = ProducersSectionReader::new(bytes, offset)?; let mut fields = IndexMap::new(); for field in section.into_iter() { let field = field?; @@ -129,7 +129,7 @@ impl Producers { } /// Serialize into [`wasm_encoder::ProducersSection`]. - pub fn section(&self) -> wasm_encoder::ProducersSection { + fn section(&self) -> wasm_encoder::ProducersSection { let mut section = wasm_encoder::ProducersSection::new(); for (fieldname, fieldvalues) in self.0.iter() { let mut field = wasm_encoder::ProducersField::new(); @@ -141,6 +141,13 @@ impl Producers { section } + /// Serialize into the raw bytes of a wasm custom section. + pub fn raw_custom_section(&self) -> Vec { + let mut ret = Vec::new(); + self.section().encode(&mut ret); + ret + } + /// Merge into an existing wasm module. Rewrites the module with this producers section /// merged into its existing one, or adds this producers section if none is present. pub fn add_to_wasm(&self, input: &[u8]) -> Result> { @@ -288,8 +295,7 @@ fn rewrite_wasm( // Only rewrite the outermost producers section: CustomSection(c) if c.name() == "producers" && stack.len() == 0 => { producers_found = true; - let section = ProducersSectionReader::new(c.data(), c.data_offset())?; - let mut producers = Producers::from_reader(section)?; + let mut producers = Producers::from_bytes(c.data(), c.data_offset())?; // Add to the section according to the command line flags: producers.merge(&add_producers); // Encode into output: @@ -298,8 +304,7 @@ fn rewrite_wasm( CustomSection(c) if c.name() == "name" && stack.len() == 0 => { names_found = true; - let section = NameSectionReader::new(c.data(), c.data_offset()); - let mut names = ModuleNames::from_reader(section)?; + let mut names = ModuleNames::from_bytes(c.data(), c.data_offset())?; names.merge(&ModuleNames::from_name(add_name)); names.section()?.as_custom().append_to(&mut output); @@ -307,8 +312,7 @@ fn rewrite_wasm( CustomSection(c) if c.name() == "component-name" && stack.len() == 0 => { names_found = true; - let section = ComponentNameSectionReader::new(c.data(), c.data_offset()); - let mut names = ComponentNames::from_reader(section)?; + let mut names = ComponentNames::from_bytes(c.data(), c.data_offset())?; names.merge(&ComponentNames::from_name(add_name)); names.section()?.as_custom().append_to(&mut output); } @@ -425,8 +429,7 @@ impl Metadata { } } CustomSection(c) if c.name() == "name" => { - let section = NameSectionReader::new(c.data(), c.data_offset()); - let names = ModuleNames::from_reader(section)?; + let names = ModuleNames::from_bytes(c.data(), c.data_offset())?; if let Some(name) = names.get_name() { metadata .last_mut() @@ -435,8 +438,7 @@ impl Metadata { } } CustomSection(c) if c.name() == "component-name" => { - let section = ComponentNameSectionReader::new(c.data(), c.data_offset()); - let names = ComponentNames::from_reader(section)?; + let names = ComponentNames::from_bytes(c.data(), c.data_offset())?; if let Some(name) = names.get_name() { metadata .last_mut() @@ -445,8 +447,7 @@ impl Metadata { } } CustomSection(c) if c.name() == "producers" => { - let section = ProducersSectionReader::new(c.data(), c.data_offset())?; - let producers = Producers::from_reader(section)?; + let producers = Producers::from_bytes(c.data(), c.data_offset())?; metadata .last_mut() .expect("non-empty metadata stack") @@ -586,7 +587,8 @@ impl<'a> ModuleNames<'a> { } /// Read a name section from a WebAssembly binary. Records the module name, and all other /// contents of name section, for later serialization. - pub fn from_reader(section: NameSectionReader<'a>) -> Result> { + pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result> { + let section = NameSectionReader::new(bytes, offset); let mut s = Self::empty(); for name in section.into_iter() { let name = name?; @@ -621,7 +623,7 @@ impl<'a> ModuleNames<'a> { self.module_name.as_ref() } /// Serialize into [`wasm_encoder::NameSection`]. - pub fn section(&self) -> Result { + fn section(&self) -> Result { let mut section = wasm_encoder::NameSection::new(); if let Some(module_name) = &self.module_name { section.module(&module_name); @@ -643,6 +645,13 @@ impl<'a> ModuleNames<'a> { } Ok(section) } + + /// Serialize into the raw bytes of a wasm custom section. + pub fn raw_custom_section(&self) -> Result> { + let mut ret = Vec::new(); + self.section()?.encode(&mut ret); + Ok(ret) + } } /// Helper for rewriting a component's component-name section with a new component name. @@ -661,7 +670,8 @@ impl<'a> ComponentNames<'a> { } /// Read a component-name section from a WebAssembly binary. Records the component name, as /// well as all other component name fields for later serialization. - pub fn from_reader(section: ComponentNameSectionReader<'a>) -> Result> { + pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result> { + let section = ComponentNameSectionReader::new(bytes, offset); let mut s = Self::empty(); for name in section.into_iter() { let name = name?; @@ -698,7 +708,7 @@ impl<'a> ComponentNames<'a> { self.component_name.as_ref() } /// Serialize into [`wasm_encoder::ComponentNameSection`] - pub fn section(&self) -> Result { + fn section(&self) -> Result { let mut section = wasm_encoder::ComponentNameSection::new(); if let Some(component_name) = &self.component_name { section.component(&component_name); @@ -725,6 +735,13 @@ impl<'a> ComponentNames<'a> { } Ok(section) } + + /// Serialize into the raw bytes of a wasm custom section. + pub fn raw_custom_section(&self) -> Result> { + let mut ret = Vec::new(); + self.section()?.encode(&mut ret); + Ok(ret) + } } fn name_map(map: &wasmparser::NameMap<'_>) -> Result { diff --git a/crates/wit-component/src/builder.rs b/crates/wit-component/src/builder.rs index 68c9c97e71..7ab2b0b512 100644 --- a/crates/wit-component/src/builder.rs +++ b/crates/wit-component/src/builder.rs @@ -41,7 +41,8 @@ impl ComponentBuilder { let mut base = crate::base_producers(); base.merge(&self.producers); // Write producers section as last section: - self.component.section(&base.section()); + self.component + .section(&RawCustomSection(&base.raw_custom_section())); self.flush(); self.component.finish() } diff --git a/crates/wit-component/src/encoding.rs b/crates/wit-component/src/encoding.rs index c9cecb2e69..b714042801 100644 --- a/crates/wit-component/src/encoding.rs +++ b/crates/wit-component/src/encoding.rs @@ -1277,14 +1277,19 @@ impl<'a> EncodingState<'a> { shim.section(&tables); shim.section(&exports); shim.section(&code); - shim.section(&crate::base_producers().section()); + shim.section(&RawCustomSection( + &crate::base_producers().raw_custom_section(), + )); shim.section(&names); let mut fixups = Module::default(); fixups.section(&types); fixups.section(&imports_section); fixups.section(&elements); - fixups.section(&crate::base_producers().section()); + fixups.section(&RawCustomSection( + &crate::base_producers().raw_custom_section(), + )); + let mut names = NameSection::new(); names.module("wit-component:fixups"); fixups.section(&names); diff --git a/crates/wit-component/src/gc.rs b/crates/wit-component/src/gc.rs index a742946c68..b80105dbaf 100644 --- a/crates/wit-component/src/gc.rs +++ b/crates/wit-component/src/gc.rs @@ -7,7 +7,7 @@ use std::{ mem, ops::Deref, }; -use wasm_encoder::{Encode, EntityType, Instruction}; +use wasm_encoder::{Encode, EntityType, Instruction, RawCustomSection}; use wasmparser::*; const PAGE_SIZE: i32 = 64 * 1024; @@ -392,8 +392,8 @@ impl<'a> Module<'a> { } fn parse_producers_section(&mut self, section: &CustomSectionReader<'a>) -> Result<()> { - let section = ProducersSectionReader::new(section.data(), section.data_offset())?; - let producers = wasm_metadata::Producers::from_reader(section)?; + let producers = + wasm_metadata::Producers::from_bytes(section.data(), section.data_offset())?; self.producers = Some(producers); Ok(()) } @@ -963,7 +963,7 @@ impl<'a> Module<'a> { }); } if let Some(producers) = &self.producers { - ret.section(&producers.section()); + ret.section(&RawCustomSection(&producers.raw_custom_section())); } Ok(ret.finish())