Skip to content

Commit

Permalink
Remove public deps from wasm-metadata's API (#1130)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
alexcrichton committed Jul 17, 2023
1 parent c91f611 commit 7cec276
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 28 deletions.
8 changes: 7 additions & 1 deletion crates/wasm-encoder/src/component.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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()
Expand Down
18 changes: 18 additions & 0 deletions crates/wasm-encoder/src/core/custom.rs
Expand Up @@ -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<u8>) {
sink.extend(self.0);
}
}

impl Section for RawCustomSection<'_> {
fn id(&self) -> u8 {
SectionId::Custom.into()
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
57 changes: 37 additions & 20 deletions crates/wasm-metadata/src/lib.rs
Expand Up @@ -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));
}
_ => {}
Expand All @@ -61,7 +60,8 @@ impl Producers {
Ok(None)
}
/// Read the producers section from a Wasm binary.
pub fn from_reader(section: ProducersSectionReader) -> Result<Self> {
pub fn from_bytes(bytes: &[u8], offset: usize) -> Result<Self> {
let section = ProducersSectionReader::new(bytes, offset)?;
let mut fields = IndexMap::new();
for field in section.into_iter() {
let field = field?;
Expand Down Expand Up @@ -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();
Expand All @@ -141,6 +141,13 @@ impl Producers {
section
}

/// Serialize into the raw bytes of a wasm custom section.
pub fn raw_custom_section(&self) -> Vec<u8> {
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<Vec<u8>> {
Expand Down Expand Up @@ -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:
Expand All @@ -298,17 +304,15 @@ 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);
}

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);
}
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand All @@ -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")
Expand Down Expand Up @@ -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<ModuleNames<'a>> {
pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result<ModuleNames<'a>> {
let section = NameSectionReader::new(bytes, offset);
let mut s = Self::empty();
for name in section.into_iter() {
let name = name?;
Expand Down Expand Up @@ -621,7 +623,7 @@ impl<'a> ModuleNames<'a> {
self.module_name.as_ref()
}
/// Serialize into [`wasm_encoder::NameSection`].
pub fn section(&self) -> Result<wasm_encoder::NameSection> {
fn section(&self) -> Result<wasm_encoder::NameSection> {
let mut section = wasm_encoder::NameSection::new();
if let Some(module_name) = &self.module_name {
section.module(&module_name);
Expand All @@ -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<Vec<u8>> {
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.
Expand All @@ -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<ComponentNames<'a>> {
pub fn from_bytes(bytes: &'a [u8], offset: usize) -> Result<ComponentNames<'a>> {
let section = ComponentNameSectionReader::new(bytes, offset);
let mut s = Self::empty();
for name in section.into_iter() {
let name = name?;
Expand Down Expand Up @@ -698,7 +708,7 @@ impl<'a> ComponentNames<'a> {
self.component_name.as_ref()
}
/// Serialize into [`wasm_encoder::ComponentNameSection`]
pub fn section(&self) -> Result<wasm_encoder::ComponentNameSection> {
fn section(&self) -> Result<wasm_encoder::ComponentNameSection> {
let mut section = wasm_encoder::ComponentNameSection::new();
if let Some(component_name) = &self.component_name {
section.component(&component_name);
Expand All @@ -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<Vec<u8>> {
let mut ret = Vec::new();
self.section()?.encode(&mut ret);
Ok(ret)
}
}

fn name_map(map: &wasmparser::NameMap<'_>) -> Result<wasm_encoder::NameMap> {
Expand Down
3 changes: 2 additions & 1 deletion crates/wit-component/src/builder.rs
Expand Up @@ -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()
}
Expand Down
9 changes: 7 additions & 2 deletions crates/wit-component/src/encoding.rs
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions crates/wit-component/src/gc.rs
Expand Up @@ -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;
Expand Down Expand Up @@ -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(())
}
Expand Down Expand Up @@ -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())
Expand Down

0 comments on commit 7cec276

Please sign in to comment.