Skip to content

Commit

Permalink
Implement export type ascription (#913)
Browse files Browse the repository at this point in the history
This commit implements the change described in
WebAssembly/component-model#155 and accounts for the update in
WebAssembly/component-model#161. The internal plumbing for this change
was relatively easy to implement and shouldn't cause too much of a
burden even on Wasmtime as a consumer (it may not have to change at
all). I'll be working on a follow-up for `wit-component` to use this new
construct to fix the original underlying issue.
  • Loading branch information
alexcrichton authored Feb 7, 2023
1 parent 02291c7 commit 49d3adc
Show file tree
Hide file tree
Showing 37 changed files with 307 additions and 177 deletions.
2 changes: 1 addition & 1 deletion crates/wasm-compose/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1225,7 +1225,7 @@ impl<'a> CompositionGraphEncoder<'a> {
}
};

export_section.export(export_name, export_url, kind, index);
export_section.export(export_name, export_url, kind, index, None);
}

if !alias_section.is_empty() {
Expand Down
1 change: 1 addition & 0 deletions crates/wasm-compose/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ impl<'a> Component<'a> {
url,
kind,
index,
ty: None,
})?,
))
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-encoder/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ impl Component {
Self {
bytes: vec![
0x00, 0x61, 0x73, 0x6D, // magic (`\0asm`)
0x0b, 0x00, 0x01, 0x00, // version
0x0c, 0x00, 0x01, 0x00, // version
],
}
}
Expand Down
14 changes: 12 additions & 2 deletions crates/wasm-encoder/src/component/exports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::{
COMPONENT_SORT, CORE_MODULE_SORT, CORE_SORT, FUNCTION_SORT, INSTANCE_SORT, TYPE_SORT,
VALUE_SORT,
};
use crate::{encode_section, ComponentSection, ComponentSectionId, Encode};
use crate::{encode_section, ComponentSection, ComponentSectionId, ComponentTypeRef, Encode};

/// Represents the kind of an export from a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -56,7 +56,7 @@ impl Encode for ComponentExportKind {
///
/// // This exports a function named "foo"
/// let mut exports = ComponentExportSection::new();
/// exports.export("foo", "", ComponentExportKind::Func, 0);
/// exports.export("foo", "", ComponentExportKind::Func, 0, None);
///
/// let mut component = Component::new();
/// component.section(&exports);
Expand Down Expand Up @@ -92,11 +92,21 @@ impl ComponentExportSection {
url: &str,
kind: ComponentExportKind,
index: u32,
ty: Option<ComponentTypeRef>,
) -> &mut Self {
name.encode(&mut self.bytes);
url.encode(&mut self.bytes);
kind.encode(&mut self.bytes);
index.encode(&mut self.bytes);
match ty {
Some(ty) => {
self.bytes.push(0x01);
ty.encode(&mut self.bytes);
}
None => {
self.bytes.push(0x00);
}
}
self.num_added += 1;
self
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wasm-encoder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,6 @@ mod test {
#[test]
fn it_encodes_an_empty_component() {
let bytes = Component::new().finish();
assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0b, 0x00, 0x01, 0x00]);
assert_eq!(bytes, [0x00, b'a', b's', b'm', 0x0c, 0x00, 0x01, 0x00]);
}
}
5 changes: 3 additions & 2 deletions crates/wasmparser/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ pub(crate) const WASM_MODULE_VERSION: u16 = 0x1;
//
// * [????-??-??] 0xa - original version
// * [2022-01-05] 0xb - `export` introduces an alias
pub(crate) const WASM_COMPONENT_VERSION: u16 = 0xb;
// * [2022-02-06] 0xc - `export` has an optional type ascribed to it
pub(crate) const WASM_COMPONENT_VERSION: u16 = 0xc;

/// The supported encoding formats for the parser.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
Expand Down Expand Up @@ -1166,7 +1167,7 @@ mod tests {
fn parser_after_component_header() -> Parser {
let mut p = Parser::default();
assert_matches!(
p.parse(b"\0asm\x0b\0\x01\0", false),
p.parse(b"\0asm\x0c\0\x01\0", false),
Ok(Chunk::Parsed {
consumed: 8,
payload: Payload::Version {
Expand Down
15 changes: 14 additions & 1 deletion crates/wasmparser/src/readers/component/exports.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{BinaryReader, FromReader, Result, SectionLimited};
use crate::{BinaryReader, ComponentTypeRef, FromReader, Result, SectionLimited};

/// Represents the kind of an external items of a WebAssembly component.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -61,6 +61,8 @@ pub struct ComponentExport<'a> {
pub kind: ComponentExternalKind,
/// The index of the exported item.
pub index: u32,
/// An optionally specified type ascribed to this export.
pub ty: Option<ComponentTypeRef>,
}

/// A reader for the export section of a WebAssembly component.
Expand All @@ -73,6 +75,17 @@ impl<'a> FromReader<'a> for ComponentExport<'a> {
url: reader.read()?,
kind: reader.read()?,
index: reader.read()?,
ty: match reader.read_u8()? {
0x00 => None,
0x01 => Some(reader.read()?),
other => {
return Err(BinaryReader::invalid_leading_byte_error(
other,
"optional component export type",
reader.original_position() - 1,
))
}
},
})
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/wasmparser/src/readers/component/instances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ impl<'a> FromReader<'a> for ComponentInstance<'a> {
url: "",
kind: reader.read()?,
index: reader.read()?,
ty: None,
})
})
.collect::<Result<_>>()?,
Expand Down
19 changes: 17 additions & 2 deletions crates/wasmparser/src/validator/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ impl ComponentState {
types: &mut TypeAlloc,
offset: usize,
) -> Result<ComponentEntityType> {
Ok(match export.kind {
let actual = match export.kind {
ComponentExternalKind::Module => {
ComponentEntityType::Module(self.module_at(export.index, offset)?)
}
Expand All @@ -739,7 +739,21 @@ impl ComponentState {
ComponentExternalKind::Component => {
ComponentEntityType::Component(self.component_at(export.index, offset)?)
}
})
};

let ascribed = match &export.ty {
Some(ty) => self.check_type_ref(ty, types, offset)?,
None => return Ok(actual),
};

if !ComponentEntityType::internal_is_subtype_of(&actual, types, &ascribed, types) {
bail!(
offset,
"ascribed type of export is not compatible with item's type"
);
}

Ok(ascribed)
}

fn create_module_type(
Expand Down Expand Up @@ -1206,6 +1220,7 @@ impl ComponentState {
let mut type_size = 1;
let mut inst_exports = IndexMap::new();
for export in exports {
assert!(export.ty.is_none());
match export.kind {
ComponentExternalKind::Module => {
insert_export(
Expand Down
4 changes: 4 additions & 0 deletions crates/wasmprinter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,10 @@ impl Printer {
}
self.result.push(' ');
self.print_component_external_kind(state, export.kind, export.index)?;
if let Some(ty) = &export.ty {
self.result.push(' ');
self.print_component_import_ty(state, &ty, false)?;
}
self.end_group();
Ok(())
}
Expand Down
9 changes: 7 additions & 2 deletions crates/wast/src/component/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,13 @@ impl<'a> Encoder<'a> {
fn encode_export(&mut self, export: &ComponentExport<'a>) {
let name = get_name(&export.id, &export.debug_name);
let (kind, index) = (&export.kind).into();
self.exports
.export(export.name, export.url.unwrap_or(""), kind, index);
self.exports.export(
export.name,
export.url.unwrap_or(""),
kind,
index,
export.ty.as_ref().map(|ty| (&ty.0.kind).into()),
);
match &export.kind {
ComponentExportKind::CoreModule(_) => self.core_module_names.push(name),
ComponentExportKind::Func(_) => self.func_names.push(name),
Expand Down
16 changes: 12 additions & 4 deletions crates/wast/src/component/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,13 @@ impl<'a> Expander<'a> {
self.expand_item_sig(&mut i.item);
None
}
ComponentField::Start(_)
| ComponentField::Alias(_)
| ComponentField::Export(_)
| ComponentField::Custom(_) => None,
ComponentField::Export(e) => {
if let Some(sig) = &mut e.ty {
self.expand_item_sig(&mut sig.0);
}
None
}
ComponentField::Start(_) | ComponentField::Alias(_) | ComponentField::Custom(_) => None,
};

if let Some(expanded) = expanded {
Expand All @@ -143,6 +146,7 @@ impl<'a> Expander<'a> {
name,
url,
kind: ComponentExportKind::module(module.span, id),
ty: None,
}));
}
match &mut module.kind {
Expand Down Expand Up @@ -190,6 +194,7 @@ impl<'a> Expander<'a> {
name,
url,
kind: ComponentExportKind::component(component.span, id),
ty: None,
}));
}
match &mut component.kind {
Expand Down Expand Up @@ -225,6 +230,7 @@ impl<'a> Expander<'a> {
name,
url,
kind: ComponentExportKind::instance(instance.span, id),
ty: None,
}));
}
match &mut instance.kind {
Expand Down Expand Up @@ -293,6 +299,7 @@ impl<'a> Expander<'a> {
name,
url,
kind: ComponentExportKind::func(func.span, id),
ty: None,
}));
}
match &mut func.kind {
Expand Down Expand Up @@ -374,6 +381,7 @@ impl<'a> Expander<'a> {
name,
url,
kind: ComponentExportKind::ty(field.span, id),
ty: None,
}));
}
}
Expand Down
10 changes: 9 additions & 1 deletion crates/wast/src/component/export.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::ItemRef;
use super::{ItemRef, ItemSigNoName};
use crate::kw;
use crate::parser::{Cursor, Parse, Parser, Peek, Result};
use crate::token::{Id, Index, NameAnnotation, Span};
Expand All @@ -18,6 +18,8 @@ pub struct ComponentExport<'a> {
pub url: Option<&'a str>,
/// The kind of export.
pub kind: ComponentExportKind<'a>,
/// The kind of export.
pub ty: Option<ItemSigNoName<'a>>,
}

impl<'a> Parse<'a> for ComponentExport<'a> {
Expand All @@ -28,13 +30,19 @@ impl<'a> Parse<'a> for ComponentExport<'a> {
let name = parser.parse()?;
let url = parser.parse()?;
let kind = parser.parse()?;
let ty = if !parser.is_empty() {
Some(parser.parens(|p| p.parse())?)
} else {
None
};
Ok(ComponentExport {
span,
id,
debug_name,
name,
url,
kind,
ty,
})
}
}
Expand Down
7 changes: 6 additions & 1 deletion crates/wast/src/component/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,12 @@ impl<'a> Resolver<'a> {
ComponentField::Func(_) => unreachable!("should be expanded already"),
ComponentField::Start(s) => self.start(s),
ComponentField::Import(i) => self.item_sig(&mut i.item),
ComponentField::Export(e) => self.export(&mut e.kind),
ComponentField::Export(e) => {
if let Some(ty) = &mut e.ty {
self.item_sig(&mut ty.0)?;
}
self.export(&mut e.kind)
}
ComponentField::Custom(_) => Ok(()),
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/wit-component/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl ComponentBuilder {
}

pub fn export(&mut self, name: &str, url: &str, kind: ComponentExportKind, idx: u32) -> u32 {
self.exports().export(name, url, kind, idx);
self.exports().export(name, url, kind, idx, None);
match kind {
ComponentExportKind::Type => inc(&mut self.types),
ComponentExportKind::Func => inc(&mut self.funcs),
Expand Down
4 changes: 2 additions & 2 deletions tests/cli/dump/alias.wat.stdout
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
0x0 | 00 61 73 6d | version 11 (Component)
| 0b 00 01 00
0x0 | 00 61 73 6d | version 12 (Component)
| 0c 00 01 00
0x8 | 07 1f | component type section
0xa | 01 | 1 count
0xb | 42 04 01 40 | [type 0] Instance([Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: "f1", url: "", ty: Func(0) }, Type(Func(ComponentFuncType { params: [("p1", Primitive(String))], results: Named([]) })), Export { name: "f2", url: "", ty: Func(1) }])
Expand Down
14 changes: 7 additions & 7 deletions tests/cli/dump/alias2.wat.stdout
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
0x0 | 00 61 73 6d | version 11 (Component)
| 0b 00 01 00
0x0 | 00 61 73 6d | version 12 (Component)
| 0c 00 01 00
0x8 | 07 30 | component type section
0xa | 01 | 1 count
0xb | 42 09 00 50 | [type 0] Instance([CoreType(Module([])), Export { name: "a", url: "", ty: Module(0) }, Type(Func(ComponentFuncType { params: [], results: Named([]) })), Export { name: "b", url: "", ty: Func(0) }, Export { name: "c", url: "", ty: Value(Primitive(String)) }, Type(Instance([])), Export { name: "d", url: "", ty: Instance(1) }, Type(Component([])), Export { name: "e", url: "", ty: Component(2) }])
Expand All @@ -19,8 +19,8 @@
0x3d | 01 61 00 05 | [instance 0] ComponentImport { name: "a", url: "", ty: Instance(0) }
| 00
0x42 | 04 59 | [component 0] inline size
0x44 | 00 61 73 6d | version 11 (Component)
| 0b 00 01 00
0x44 | 00 61 73 6d | version 12 (Component)
| 0c 00 01 00
0x4c | 03 03 | core type section
0x4e | 01 | 1 count
0x4f | 50 00 | [core type 0] Module([])
Expand Down Expand Up @@ -79,8 +79,8 @@
| 01 64 05 01
| 01 65 04 01
0xd5 | 04 34 | [component 2] inline size
0xd7 | 00 61 73 6d | version 11 (Component)
| 0b 00 01 00
0xd7 | 00 61 73 6d | version 12 (Component)
| 0c 00 01 00
0xdf | 06 05 | component alias section
0xe1 | 01 | 1 count
0xe2 | 03 02 01 00 | alias [type 0] Outer { kind: Type, count: 1, index: 0 }
Expand Down Expand Up @@ -112,7 +112,7 @@
| 65
0x128 | 05 1f | component instance section
0x12a | 02 | 2 count
0x12b | 01 05 01 61 | [instance 4] FromExports([ComponentExport { name: "a", url: "", kind: Module, index: 1 }, ComponentExport { name: "b", url: "", kind: Func, index: 1 }, ComponentExport { name: "c", url: "", kind: Value, index: 1 }, ComponentExport { name: "d", url: "", kind: Instance, index: 3 }, ComponentExport { name: "e", url: "", kind: Component, index: 3 }])
0x12b | 01 05 01 61 | [instance 4] FromExports([ComponentExport { name: "a", url: "", kind: Module, index: 1, ty: None }, ComponentExport { name: "b", url: "", kind: Func, index: 1, ty: None }, ComponentExport { name: "c", url: "", kind: Value, index: 1, ty: None }, ComponentExport { name: "d", url: "", kind: Instance, index: 3, ty: None }, ComponentExport { name: "e", url: "", kind: Component, index: 3, ty: None }])
| 00 11 01 01
| 62 01 01 01
| 63 02 01 01
Expand Down
Loading

0 comments on commit 49d3adc

Please sign in to comment.