Skip to content
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
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ wit-bindgen = "0.62.0"
wit-component = "0.261.0"
wit-parser = "0.261.0"

# release builds are only published as components, smaller beats faster. "s" over "z" keeps the
# parsers in wac-loader and wit-tools fast.
[profile.release]
opt-level = "s"
lto = true
codegen-units = 1
strip = "debuginfo"

# wasmtime compiles components in the native tests, an unoptimized cranelift is very slow. These
# crates are only built for the host, the components are unaffected.
[profile.dev.package.cranelift-codegen]
Expand Down
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,21 @@ relpath = $(if $(filter $(CURDIR),$(abspath $(1))),.,$(patsubst $(CURDIR)/%,%,$(
all: tools wit components test

.PHONY: clean
clean: clean-wit
clean: clean-components clean-wit
@:

.PHONY: clean-all
clean-all: clean-components clean-tools clean-wit
cargo clean

.PHONY: clean-components
clean-components: clean-wit
rm -rf ${COMPONENTS_DIR}

.PHONY: clean-tools
clean-tools:
rm -rf ${TOOLS_DIR}

.PHONY: clean-wit ## Remove the fetched wit dependencies, fetched again by `make wit`
clean-wit:
rm -rf $(WIT_DEPS)
Expand Down
2 changes: 0 additions & 2 deletions components/wac-loader/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@ license = "Apache-2.0"
crate-type = ["cdylib"]

[dependencies]
anyhow = { workspace = true }
indexmap = { workspace = true }
wac-graph = { workspace = true }
wac-parser = { workspace = true }
wasmparser = { workspace = true }
wit-bindgen = { workspace = true }

[dev-dependencies]
Expand Down
51 changes: 22 additions & 29 deletions components/wac-loader/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use indexmap::IndexMap;
use wac_graph::{
CompositionGraph, EncodeOptions,
types::{BorrowedPackageKey, Package},
types::{BorrowedPackageKey, Package, Types},
};
use wac_parser::Document;

Expand All @@ -17,19 +17,13 @@ impl Guest for WacLoader {
async fn plug(socket: Wasm, plugs: Vec<Wasm>) -> Result<Wasm, ErrorCode> {
let mut graph = CompositionGraph::new();

let socket = Package::from_bytes(
"socket",
None,
component("socket", socket)?,
graph.types_mut(),
)?;
let socket = package("socket", socket, graph.types_mut())?;
let socket = graph.register_package(socket)?;

let mut graph_plugs = Vec::new();
for (i, plug) in plugs.into_iter().enumerate() {
let name = format!("plug:{i}");
let plug = component(&name, plug)?;
let plug = Package::from_bytes(&name, None, plug, graph.types_mut())?;
let plug = package(&name, plug, graph.types_mut())?;
let plug = graph.register_package(plug)?;
graph_plugs.push(plug);
}
Expand All @@ -46,11 +40,15 @@ impl Guest for WacLoader {
Plan::Wac(script) => {
let document = Document::parse(&script)?;

// the resolution only parses the packages the script uses, each dependency is
// parsed up front so a malformed one is reported even when it is unused
let mut types = Types::default();
let (names, components): (Vec<String>, Vec<Wasm>) = deps.into_iter().unzip();
let mut dependencies = IndexMap::new();
for (pkg, wasm) in names.iter().zip(components) {
let key = BorrowedPackageKey::from_name_and_version(pkg, None);
dependencies.insert(key, component(pkg, wasm)?);
let package = package(pkg, wasm, &mut types)?;
dependencies.insert(key, package.bytes().to_vec());
}
let resolution = document.resolve(dependencies)?;
let component = resolution.encode(EncodeOptions::default())?;
Expand All @@ -61,27 +59,22 @@ impl Guest for WacLoader {
}
}

/// The wasm when it is a valid component, otherwise a `not-component` or `malformed` error naming
/// it.
fn component(name: &str, wasm: Wasm) -> Result<Wasm, ErrorCode> {
if !wasmparser::Parser::is_component(&wasm) {
return Err(ErrorCode::NotComponent(Some(name.to_string())));
}
wasmparser::Validator::new_with_features(wasmparser::WasmFeatures::all())
.validate_all(&wasm)
.map_err(|error| {
ErrorCode::Malformed(Malformed {
name: Some(name.to_string()),
message: error.to_string(),
})
})?;
Ok(wasm)
}
/// The header of a binary-encoded component, the wasm magic number followed by the component
/// version and layer.
const COMPONENT_HEADER: [u8; 8] = *b"\0asm\x0d\x00\x01\x00";

impl From<anyhow::Error> for ErrorCode {
fn from(err: anyhow::Error) -> Self {
Self::Other(Some(err.to_string()))
/// Parses and validates the wasm as a package, otherwise a `not-component` or `malformed` error
/// naming it.
fn package(name: &str, wasm: Wasm, types: &mut Types) -> Result<Package, ErrorCode> {
if !wasm.starts_with(&COMPONENT_HEADER) {
return Err(ErrorCode::NotComponent(Some(name.to_string())));
}
Package::from_bytes(name, None, wasm, types).map_err(|error| {
ErrorCode::Malformed(Malformed {
name: Some(name.to_string()),
message: format!("{error:#}"),
})
})
}

impl From<wac_graph::EncodeError> for ErrorCode {
Expand Down
4 changes: 2 additions & 2 deletions components/wac-loader/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::{
};

use crate::{
WacLoader,
COMPONENT_HEADER, WacLoader,
componentized::component::types::{ErrorCode, Malformed},
exports::componentized::component::wac_loader::{Guest, Plan},
};
Expand Down Expand Up @@ -73,7 +73,7 @@ fn compose_components() {
))
.expect("composes");

assert!(wasmparser::Parser::is_component(&composed));
assert!(composed.starts_with(&COMPONENT_HEADER));
}

/// A component header followed by an invalid section.
Expand Down
Loading