Skip to content

Commit 42e1c77

Browse files
authored
Implement support for the standard mangling scheme in the component model (#1828)
* Use `ExportMap` for naming component exports Use the map's metadata to determine what the core wasm name is for each export instead of recalculating it in the encoder which would duplicate work done in validation. * Decouple import/export encodings from core names This commit decouples the string encodings listed for imports/exports from their core wasm names to instead being registered with WIT-level constructs instead. Previously the parsing phase of a module would register a string encoding for core wasm import/export names but this subverted the logic of validation where detection of how exactly an import lines up with WIT-level items is determined. The goal of this commit is to decouple this relation. Worlds are encoding into custom sections with a known string encoding for all imports/exports of that world. This can possibly differ for different parts of an application to theoretically enable one interface to be imported with UTF-8 and another with UTF-16. This means that encodings are tracked per-import/export rather than per-world. Previously this process would assume that there is a single name for an import's/export's encoding but with new detection and names coming down the line this is no longer going to be the case. For example with the new names in WebAssembly/component-model#378 there are new names to be supported meaning that there's not one single name to register encodings with. To help bridge this gap the abstraction here is changed to where metadata for a module records string encodings on a WIT level, for example per WIT import/export, instead of per core wasm import/export. Then during encoding of a component the WIT level constructs are matched up instead of the core names to determine the string encoding in the lift/lower operation. The end goal is that the connection between core wasm names and WIT names continues to be decoupled where validation is the only location concerned about this. * Remove core wasm name guess in adapter GC This commit removes the need for the GC pass on the adapter module to guess what core wasm export names are needed for WIT. Previously it was assumed that certain exports would have exact core wasm names but that's going to change soon so this refactoring is empowering these future changes. The GC pass for adapters is restructured to run validation over the non-GC'd adapter first. This validation pass will identify WIT export functions and such and then this information is used to determine the set of live exports. These live exports are then used to perform a GC pass, and then afterwards the validation pass is run a second time to recalculate information with possibly-removed imports. * Support the new name mangling scheme for components This commit adds support for WebAssembly/component-model#378 to `wit-component`. Notably a new set of alternative names are registered and recognized during the module-to-component translation process. Support for the previous set of names are all preserved and will continue to be supported for some time. The new names are, for now, recognized in parallel to the old names. This involved some refactoring to the validation part of `wit-component` and further encapsulation of various names to one small location instead of a shared location for everywhere else to use as well. * Update `embed --dummy` with new ABI names This commit updates the `wasm-tools component embed` subcommand, specifically the `--dummy` flag. This flag now uses the new "standard32" names for the core module that is generated. Additionally a new `--dummy-names $FOO` option has been added to enable generating the old names as well as the new names. Utilities have also been added to `Resolve` for bindings generators to avoid hardcoding ABI names and instead use the add categories of imports/exports to name items. * Add a flag to require the new mangling scheme This commit adds a new `--reject-legacy-names` flag to the `wasm-tools component new` subcommand which can be used to disable support for the legacy naming scheme. This is intended to help with testing out the new naming scheme for tools and to help evaluate in the future if it's theoretically possible to remove support for the old naming scheme. * Fix tests * Update some test expectations
1 parent a0004ed commit 42e1c77

24 files changed

+1825
-590
lines changed

crates/wit-component/src/dummy.rs

+112-36
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use wit_parser::abi::{AbiVariant, WasmType};
2-
use wit_parser::{Function, Resolve, TypeDefKind, TypeId, WorldId, WorldItem};
2+
use wit_parser::{
3+
Function, Mangling, Resolve, ResourceIntrinsic, TypeDefKind, TypeId, WasmExport, WasmImport,
4+
WorldId, WorldItem, WorldKey,
5+
};
36

47
/// Generate a dummy implementation core Wasm module for a given WIT document
5-
pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
8+
pub fn dummy_module(resolve: &Resolve, world: WorldId, mangling: Mangling) -> Vec<u8> {
69
let world = &resolve.worlds[world];
710
let mut wat = String::new();
811
wat.push_str("(module\n");
@@ -11,27 +14,41 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
1114
WorldItem::Function(func) => {
1215
let sig = resolve.wasm_signature(AbiVariant::GuestImport, func);
1316

14-
wat.push_str(&format!("(import \"$root\" \"{}\" (func", func.name));
17+
let (module, name) = resolve.wasm_import_name(
18+
mangling,
19+
WasmImport::Func {
20+
interface: None,
21+
func,
22+
},
23+
);
24+
25+
wat.push_str(&format!("(import {module:?} {name:?} (func"));
1526
push_tys(&mut wat, "param", &sig.params);
1627
push_tys(&mut wat, "result", &sig.results);
1728
wat.push_str("))\n");
1829
}
1930
WorldItem::Interface { id: import, .. } => {
20-
let name = resolve.name_world_key(name);
2131
for (_, func) in resolve.interfaces[*import].functions.iter() {
2232
let sig = resolve.wasm_signature(AbiVariant::GuestImport, func);
2333

24-
wat.push_str(&format!("(import \"{name}\" \"{}\" (func", func.name));
34+
let (module, name) = resolve.wasm_import_name(
35+
mangling,
36+
WasmImport::Func {
37+
interface: Some(name),
38+
func,
39+
},
40+
);
41+
wat.push_str(&format!("(import {module:?} {name:?} (func"));
2542
push_tys(&mut wat, "param", &sig.params);
2643
push_tys(&mut wat, "result", &sig.results);
2744
wat.push_str("))\n");
2845
}
2946
for (_, ty) in resolve.interfaces[*import].types.iter() {
30-
push_resource_func_imports(&mut wat, resolve, &name, *ty);
47+
push_resource_func_imports(&mut wat, resolve, Some(name), *ty, mangling);
3148
}
3249
}
3350
WorldItem::Type(id) => {
34-
push_resource_func_imports(&mut wat, resolve, "$root", *id);
51+
push_resource_func_imports(&mut wat, resolve, None, *id, mangling);
3552
}
3653
}
3754
}
@@ -42,77 +59,136 @@ pub fn dummy_module(resolve: &Resolve, world: WorldId) -> Vec<u8> {
4259
WorldItem::Interface { id, .. } => *id,
4360
_ => continue,
4461
};
45-
let module = format!("[export]{}", resolve.name_world_key(name));
46-
for (name, ty) in resolve.interfaces[export].types.iter() {
47-
let ty = &resolve.types[*ty];
62+
for resource in resolve.interfaces[export].types.values().copied() {
63+
let ty = &resolve.types[resource];
4864
match ty.kind {
4965
TypeDefKind::Resource => {}
5066
_ => continue,
5167
}
52-
wat.push_str(&format!(
53-
"\
54-
(import \"{module}\" \"[resource-drop]{name}\" (func (param i32)))
55-
(import \"{module}\" \"[resource-new]{name}\" (func (param i32) (result i32)))
56-
(import \"{module}\" \"[resource-rep]{name}\" (func (param i32) (result i32)))
57-
"
58-
));
68+
let intrinsics = [
69+
(ResourceIntrinsic::ExportedDrop, "(func (param i32))"),
70+
(
71+
ResourceIntrinsic::ExportedNew,
72+
"(func (param i32) (result i32))",
73+
),
74+
(
75+
ResourceIntrinsic::ExportedRep,
76+
"(func (param i32) (result i32))",
77+
),
78+
];
79+
for (intrinsic, sig) in intrinsics {
80+
let (module, name) = resolve.wasm_import_name(
81+
mangling,
82+
WasmImport::ResourceIntrinsic {
83+
interface: Some(name),
84+
resource,
85+
intrinsic,
86+
},
87+
);
88+
wat.push_str(&format!("(import {module:?} {name:?} {sig})\n"));
89+
}
5990
}
6091
}
6192

6293
for (name, export) in world.exports.iter() {
6394
match export {
6495
WorldItem::Function(func) => {
65-
push_func(&mut wat, &func.name, resolve, func);
96+
push_func_export(&mut wat, resolve, None, func, mangling);
6697
}
6798
WorldItem::Interface { id: export, .. } => {
68-
let name = resolve.name_world_key(name);
6999
for (_, func) in resolve.interfaces[*export].functions.iter() {
70-
let name = func.core_export_name(Some(&name));
71-
push_func(&mut wat, &name, resolve, func);
100+
push_func_export(&mut wat, resolve, Some(name), func, mangling);
72101
}
73102

74103
// Feign destructors for any resource that this interface
75104
// exports
76-
for (resource_name, ty) in resolve.interfaces[*export].types.iter() {
77-
let ty = &resolve.types[*ty];
105+
for resource in resolve.interfaces[*export].types.values().copied() {
106+
let ty = &resolve.types[resource];
78107
match ty.kind {
79108
TypeDefKind::Resource => {}
80109
_ => continue,
81110
}
82-
wat.push_str(&format!(
83-
"(func (export \"{name}#[dtor]{resource_name}\") (param i32))"
84-
));
111+
let name = resolve.wasm_export_name(
112+
mangling,
113+
WasmExport::ResourceDtor {
114+
interface: name,
115+
resource,
116+
},
117+
);
118+
wat.push_str(&format!("(func (export {name:?}) (param i32))"));
85119
}
86120
}
87121
WorldItem::Type(_) => {}
88122
}
89123
}
90124

91-
wat.push_str("(memory (export \"memory\") 0)\n");
92-
wat.push_str(
93-
"(func (export \"cabi_realloc\") (param i32 i32 i32 i32) (result i32) unreachable)\n",
94-
);
125+
let memory = resolve.wasm_export_name(mangling, WasmExport::Memory);
126+
wat.push_str(&format!("(memory (export {memory:?}) 0)\n"));
127+
let realloc = resolve.wasm_export_name(mangling, WasmExport::Realloc);
128+
wat.push_str(&format!(
129+
"(func (export {realloc:?}) (param i32 i32 i32 i32) (result i32) unreachable)\n"
130+
));
131+
let initialize = resolve.wasm_export_name(mangling, WasmExport::Initialize);
132+
wat.push_str(&format!("(func (export {initialize:?}))"));
95133
wat.push_str(")\n");
96134

97135
return wat::parse_str(&wat).unwrap();
98136

99-
fn push_resource_func_imports(wat: &mut String, resolve: &Resolve, module: &str, ty: TypeId) {
100-
let ty = &resolve.types[ty];
137+
fn push_resource_func_imports(
138+
wat: &mut String,
139+
resolve: &Resolve,
140+
interface: Option<&WorldKey>,
141+
resource: TypeId,
142+
mangling: Mangling,
143+
) {
144+
let ty = &resolve.types[resource];
101145
match ty.kind {
102146
TypeDefKind::Resource => {}
103147
_ => return,
104148
}
105-
let name = ty.name.as_ref().unwrap();
106-
wat.push_str(&format!("(import \"{module}\" \"[resource-drop]{name}\""));
107-
wat.push_str(" (func (param i32)))\n");
149+
let (module, name) = resolve.wasm_import_name(
150+
mangling,
151+
WasmImport::ResourceIntrinsic {
152+
interface,
153+
resource,
154+
intrinsic: ResourceIntrinsic::ImportedDrop,
155+
},
156+
);
157+
wat.push_str(&format!("(import {module:?} {name:?} (func (param i32)))"));
108158
}
109159

110-
fn push_func(wat: &mut String, name: &str, resolve: &Resolve, func: &Function) {
160+
fn push_func_export(
161+
wat: &mut String,
162+
resolve: &Resolve,
163+
interface: Option<&WorldKey>,
164+
func: &Function,
165+
mangling: Mangling,
166+
) {
111167
let sig = resolve.wasm_signature(AbiVariant::GuestExport, func);
168+
let name = resolve.wasm_export_name(
169+
mangling,
170+
WasmExport::Func {
171+
interface,
172+
func,
173+
post_return: false,
174+
},
175+
);
112176
wat.push_str(&format!("(func (export \"{name}\")"));
113177
push_tys(wat, "param", &sig.params);
114178
push_tys(wat, "result", &sig.results);
115179
wat.push_str(" unreachable)\n");
180+
181+
let name = resolve.wasm_export_name(
182+
mangling,
183+
WasmExport::Func {
184+
interface,
185+
func,
186+
post_return: true,
187+
},
188+
);
189+
wat.push_str(&format!("(func (export \"{name}\")"));
190+
push_tys(wat, "param", &sig.results);
191+
wat.push_str(")\n");
116192
}
117193

118194
fn push_tys(dst: &mut String, desc: &str, params: &[WasmType]) {

0 commit comments

Comments
 (0)