Skip to content

Commit 6da2f74

Browse files
authored
Restrict component import/export overlap (#946)
This commit implements WebAssembly/component-model#164 which moves component imports and exports into the same namespace as opposed to the prior disjoint namespaces. This new restriction is then carried through to WIT parsing as well and all the various tests/resolution.
1 parent efb9316 commit 6da2f74

File tree

89 files changed

+412
-347
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+412
-347
lines changed

crates/wasm-compose/src/graph.rs

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use std::{
1111
};
1212
use wasmparser::{
1313
types::{ComponentEntityType, ComponentInstanceType, Types, TypesRef},
14-
Chunk, ComponentExport, ComponentExternalKind, ComponentImport, ComponentTypeRef, Encoding,
15-
Parser, Payload, ValidPayload, Validator, WasmFeatures,
14+
Chunk, ComponentExternalKind, ComponentTypeRef, Encoding, Parser, Payload, ValidPayload,
15+
Validator, WasmFeatures,
1616
};
1717

1818
pub(crate) fn type_desc(item: ComponentEntityType) -> &'static str {
@@ -262,32 +262,16 @@ impl<'a> Component<'a> {
262262
&self,
263263
index: ExportIndex,
264264
) -> Option<(&str, &str, ComponentEntityType)> {
265-
let (name, url, kind, index) = self.export(index)?;
266-
Some((
267-
name,
268-
url,
269-
self.types
270-
.component_entity_type_from_export(&ComponentExport {
271-
name,
272-
url,
273-
kind,
274-
index,
275-
ty: None,
276-
})?,
277-
))
265+
let (name, url, _kind, _index) = self.export(index)?;
266+
Some((name, url, self.types.component_entity_type_of_extern(name)?))
278267
}
279268

280269
pub(crate) fn import_entity_type(
281270
&self,
282271
index: ImportIndex,
283272
) -> Option<(&str, &str, ComponentEntityType)> {
284-
let (name, url, ty) = self.import(index)?;
285-
Some((
286-
name,
287-
url,
288-
self.types
289-
.component_entity_type_from_import(&ComponentImport { name, url, ty })?,
290-
))
273+
let (name, url, _ty) = self.import(index)?;
274+
Some((name, url, self.types.component_entity_type_of_extern(name)?))
291275
}
292276

293277
/// Finds a compatible instance export on the component for the given instance type.
@@ -918,7 +902,7 @@ mod test {
918902
)?)?;
919903
let b = graph.add_component(Component::from_bytes(
920904
"b",
921-
b"(component (import \"x\" (func)) (export \"x\" (func 0)))".as_ref(),
905+
b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(),
922906
)?)?;
923907
let ai = graph.instantiate(a)?;
924908
let bi = graph.instantiate(b)?;
@@ -951,7 +935,7 @@ mod test {
951935
)?)?;
952936
let b = graph.add_component(Component::from_bytes(
953937
"b",
954-
b"(component (import \"x\" (func)) (export \"x\" (func 0)))".as_ref(),
938+
b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(),
955939
)?)?;
956940
let ai = graph.instantiate(a)?;
957941
let bi = graph.instantiate(b)?;
@@ -976,7 +960,7 @@ mod test {
976960
)?)?;
977961
let b = graph.add_component(Component::from_bytes(
978962
"b",
979-
b"(component (import \"x\" (func)) (export \"x\" (func 0)))".as_ref(),
963+
b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(),
980964
)?)?;
981965
let ai = graph.instantiate(a)?;
982966
let bi = graph.instantiate(b)?;
@@ -1002,7 +986,7 @@ mod test {
1002986
)?)?;
1003987
let b = graph.add_component(Component::from_bytes(
1004988
"b",
1005-
b"(component (import \"x\" (func)) (export \"x\" (func 0)))".as_ref(),
989+
b"(component (import \"x\" (func)) (export \"y\" (func 0)))".as_ref(),
1006990
)?)?;
1007991
let ai = graph.instantiate(a)?;
1008992
let bi = graph.instantiate(b)?;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
(component
2-
(import "a" (instance (export "a" (func))))
2+
(import "b" (instance (export "a" (func))))
33
(alias export 0 "a" (func))
44
(export "a" (func 0))
55
)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
instantiations:
22
$input:
33
arguments:
4-
a: a1
4+
b: a1
55
a1:
66
dependency: a
77
arguments:
8-
a: a2
8+
b: a2
99
a2:
1010
dependency: a
1111
arguments:
12-
a: a1
12+
b: a1
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
(component
2-
(import "a" (instance (export "a" (func))))
2+
(import "b" (instance (export "a" (func))))
33
)

crates/wasm-encoder/src/component/instances.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,34 +59,36 @@ impl InstanceSection {
5959
}
6060

6161
/// Define an instance by instantiating a core module.
62-
pub fn instantiate<'a, A>(&mut self, module_index: u32, args: A) -> &mut Self
62+
pub fn instantiate<A, S>(&mut self, module_index: u32, args: A) -> &mut Self
6363
where
64-
A: IntoIterator<Item = (&'a str, ModuleArg)>,
64+
A: IntoIterator<Item = (S, ModuleArg)>,
6565
A::IntoIter: ExactSizeIterator,
66+
S: AsRef<str>,
6667
{
6768
let args = args.into_iter();
6869
self.bytes.push(0x00);
6970
module_index.encode(&mut self.bytes);
7071
args.len().encode(&mut self.bytes);
7172
for (name, arg) in args {
72-
name.encode(&mut self.bytes);
73+
name.as_ref().encode(&mut self.bytes);
7374
arg.encode(&mut self.bytes);
7475
}
7576
self.num_added += 1;
7677
self
7778
}
7879

7980
/// Define an instance by exporting core WebAssembly items.
80-
pub fn export_items<'a, E>(&mut self, exports: E) -> &mut Self
81+
pub fn export_items<E, S>(&mut self, exports: E) -> &mut Self
8182
where
82-
E: IntoIterator<Item = (&'a str, ExportKind, u32)>,
83+
E: IntoIterator<Item = (S, ExportKind, u32)>,
8384
E::IntoIter: ExactSizeIterator,
85+
S: AsRef<str>,
8486
{
8587
let exports = exports.into_iter();
8688
self.bytes.push(0x01);
8789
exports.len().encode(&mut self.bytes);
8890
for (name, kind, index) in exports {
89-
name.encode(&mut self.bytes);
91+
name.as_ref().encode(&mut self.bytes);
9092
kind.encode(&mut self.bytes);
9193
index.encode(&mut self.bytes);
9294
}
@@ -146,17 +148,18 @@ impl ComponentInstanceSection {
146148
}
147149

148150
/// Define an instance by instantiating a component.
149-
pub fn instantiate<'a, A>(&mut self, component_index: u32, args: A) -> &mut Self
151+
pub fn instantiate<A, S>(&mut self, component_index: u32, args: A) -> &mut Self
150152
where
151-
A: IntoIterator<Item = (&'a str, ComponentExportKind, u32)>,
153+
A: IntoIterator<Item = (S, ComponentExportKind, u32)>,
152154
A::IntoIter: ExactSizeIterator,
155+
S: AsRef<str>,
153156
{
154157
let args = args.into_iter();
155158
self.bytes.push(0x00);
156159
component_index.encode(&mut self.bytes);
157160
args.len().encode(&mut self.bytes);
158161
for (name, kind, index) in args {
159-
name.encode(&mut self.bytes);
162+
name.as_ref().encode(&mut self.bytes);
160163
kind.encode(&mut self.bytes);
161164
index.encode(&mut self.bytes);
162165
}

crates/wasmparser/src/validator.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,13 +1187,13 @@ impl Validator {
11871187
|components, _, count, offset| {
11881188
let current = components.last_mut().unwrap();
11891189
check_max(
1190-
current.exports.len(),
1190+
current.externs.len(),
11911191
count,
11921192
MAX_WASM_EXPORTS,
1193-
"exports",
1193+
"imports and exports",
11941194
offset,
11951195
)?;
1196-
current.exports.reserve(count as usize);
1196+
current.externs.reserve(count as usize);
11971197
Ok(())
11981198
},
11991199
|components, types, _, export, offset| {

crates/wasmparser/src/validator/component.rs

Lines changed: 67 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ pub(crate) struct ComponentState {
6464
pub instances: Vec<TypeId>,
6565
pub components: Vec<TypeId>,
6666

67-
pub imports: IndexMap<KebabString, (Option<Url>, ComponentEntityType)>,
68-
pub exports: IndexMap<KebabString, (Option<Url>, ComponentEntityType)>,
67+
/// A set of all imports and exports since they share the same namespace.
68+
pub externs: IndexMap<KebabString, (Option<Url>, ComponentEntityType, ExternKind)>,
6969

7070
// Note: URL validation requires unique URLs by byte comparison, so
7171
// strings are used here and the URLs are not normalized.
@@ -76,6 +76,20 @@ pub(crate) struct ComponentState {
7676
type_size: u32,
7777
}
7878

79+
pub enum ExternKind {
80+
Import,
81+
Export,
82+
}
83+
84+
impl ExternKind {
85+
fn desc(&self) -> &'static str {
86+
match self {
87+
ExternKind::Import => "import",
88+
ExternKind::Export => "export",
89+
}
90+
}
91+
}
92+
7993
impl ComponentState {
8094
pub fn type_count(&self) -> usize {
8195
self.core_types.len() + self.types.len()
@@ -218,13 +232,14 @@ impl ComponentState {
218232
self.add_entity(entity, false, offset)?;
219233
let name = to_kebab_str(import.name, "import", offset)?;
220234

221-
match self.imports.entry(name.to_owned()) {
235+
match self.externs.entry(name.to_owned()) {
222236
Entry::Occupied(e) => {
223237
bail!(
224238
offset,
225-
"import name `{name}` conflicts with previous import name `{prev}`",
239+
"import name `{name}` conflicts with previous {desc} name `{prev}`",
226240
name = import.name,
227-
prev = e.key()
241+
prev = e.key(),
242+
desc = e.get().2.desc(),
228243
);
229244
}
230245
Entry::Vacant(e) => {
@@ -236,7 +251,7 @@ impl ComponentState {
236251
}
237252

238253
self.type_size = combine_type_sizes(self.type_size, entity.type_size(), offset)?;
239-
e.insert((url, entity));
254+
e.insert((url, entity, ExternKind::Import));
240255
}
241256
}
242257

@@ -289,18 +304,25 @@ impl ComponentState {
289304
check_limit: bool,
290305
) -> Result<()> {
291306
if check_limit {
292-
check_max(self.exports.len(), 1, MAX_WASM_EXPORTS, "exports", offset)?;
307+
check_max(
308+
self.externs.len(),
309+
1,
310+
MAX_WASM_EXPORTS,
311+
"imports and exports",
312+
offset,
313+
)?;
293314
}
294315
self.add_entity(ty, true, offset)?;
295316

296317
let name = to_kebab_str(name, "export", offset)?;
297318

298-
match self.exports.entry(name.to_owned()) {
319+
match self.externs.entry(name.to_owned()) {
299320
Entry::Occupied(e) => {
300321
bail!(
301322
offset,
302-
"export name `{name}` conflicts with previous export name `{prev}`",
303-
prev = e.key()
323+
"export name `{name}` conflicts with previous {desc} name `{prev}`",
324+
prev = e.key(),
325+
desc = e.get().2.desc(),
304326
);
305327
}
306328
Entry::Vacant(e) => {
@@ -312,7 +334,7 @@ impl ComponentState {
312334
}
313335

314336
self.type_size = combine_type_sizes(self.type_size, ty.type_size(), offset)?;
315-
e.insert((url, ty));
337+
e.insert((url, ty, ExternKind::Export));
316338
}
317339
}
318340

@@ -388,12 +410,7 @@ impl ComponentState {
388410
}
389411

390412
pub fn add_component(&mut self, component: &mut Self, types: &mut TypeAlloc) {
391-
let ty = Type::Component(ComponentType {
392-
type_size: component.type_size,
393-
imports: mem::take(&mut component.imports),
394-
exports: mem::take(&mut component.exports),
395-
});
396-
413+
let ty = Type::Component(component.take_component_type());
397414
let id = types.push_anon(ty);
398415
self.components.push(id);
399416
}
@@ -848,13 +865,9 @@ impl ComponentState {
848865
};
849866
}
850867

851-
let state = components.pop().unwrap();
868+
let mut state = components.pop().unwrap();
852869

853-
Ok(ComponentType {
854-
type_size: state.type_size,
855-
imports: state.imports,
856-
exports: state.exports,
857-
})
870+
Ok(state.take_component_type())
858871
}
859872

860873
fn create_instance_type(
@@ -889,7 +902,16 @@ impl ComponentState {
889902

890903
Ok(ComponentInstanceType {
891904
type_size: state.type_size,
892-
kind: ComponentInstanceTypeKind::Defined(state.exports),
905+
kind: ComponentInstanceTypeKind::Defined(
906+
state
907+
.externs
908+
.into_iter()
909+
.filter_map(|(name, (url, ty, kind))| match kind {
910+
ExternKind::Export => Some((name, (url, ty))),
911+
ExternKind::Import => None,
912+
})
913+
.collect(),
914+
),
893915
})
894916
}
895917

@@ -2032,6 +2054,25 @@ impl ComponentState {
20322054
None => bail!(offset, "unknown memory {idx}: memory index out of bounds"),
20332055
}
20342056
}
2057+
2058+
fn take_component_type(&mut self) -> ComponentType {
2059+
let mut ty = ComponentType {
2060+
type_size: self.type_size,
2061+
imports: Default::default(),
2062+
exports: Default::default(),
2063+
};
2064+
2065+
for (name, (url, t, kind)) in mem::take(&mut self.externs) {
2066+
let map = match kind {
2067+
ExternKind::Import => &mut ty.imports,
2068+
ExternKind::Export => &mut ty.exports,
2069+
};
2070+
let prev = map.insert(name, (url, t));
2071+
assert!(prev.is_none());
2072+
}
2073+
2074+
ty
2075+
}
20352076
}
20362077

20372078
impl Default for ComponentState {
@@ -2050,10 +2091,9 @@ impl Default for ComponentState {
20502091
values: Default::default(),
20512092
instances: Default::default(),
20522093
components: Default::default(),
2053-
imports: Default::default(),
2054-
exports: Default::default(),
2055-
import_urls: Default::default(),
2094+
externs: Default::default(),
20562095
export_urls: Default::default(),
2096+
import_urls: Default::default(),
20572097
has_start: Default::default(),
20582098
type_size: 1,
20592099
}

0 commit comments

Comments
 (0)