Skip to content

Commit 203d86f

Browse files
authored
Add tests for the interface types output of wasm-bindgen (#1898)
* Add tests for the interface types output of wasm-bindgen This commit expands the test suite with assertions about the output of the interface types pass in wasm-bindgen. The goal here is to actually assert that we produce the right output and have a suite of reference files to show how the interface types output is changing over time. The `reference` test suite added in the previous PR has been updated to work for interface types as well, generating `*.wit` file assertions which are printed via the `wit-printer` crate on crates.io. Along the way a number of bugs were fixed with the interface types output, such as: * Non-determinism in output caused by iteration of a `HashMap` * Avoiding JS generation entirely in interface types mode, ensuring that we don't export extraneous intrinsics that aren't otherwise needed. * Fixing location of the stack pointer for modules where it's GC'd out. It's now rooted in the aux section of wasm-bindgen so it's available to later passes, like the multi-value pass. * Interface types emission now works in debug mode, meaning the `--release` flag is no longer required. This previously did not work because the `__wbindgen_throw` intrinsic was required in debug mode. This comes about because of the `malloc_failure` and `internal_error` functions in the anyref pass. The purpose of these functions is to signal fatal runtime errors, if any, in a way that's usable to the user. For wasm interface types though we can replace calls to these functions with `unreachable` to avoid needing to import the intrinsic. This has the accidental side effect of making `wasm_bindgen::throw_str` "just work" with wasm interface types by aborting the program, but that's not actually entirely intended. It's hoped that a split of a `wasm-bindgen-core` crate would solve this issue for the future. * Run the wasm interface types validator in tests * Add more gc roots for adapter gc * Improve stack pointer detection The stack pointer is never initialized to zero, but some other mutable globals are (TLS, thread ID, etc), so let's filter those out.
1 parent b9c93a3 commit 203d86f

22 files changed

+697
-166
lines changed

crates/cli-support/src/js/mod.rs

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ impl<'a> Context<'a> {
227227
} => {
228228
js.push_str("let wasm;\n");
229229

230-
for (id, js) in sorted_iter(&self.wasm_import_definitions) {
230+
for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) {
231231
let import = self.module.imports.get_mut(*id);
232232
import.module = format!("./{}.js", module_name);
233233
footer.push_str("\nmodule.exports.");
@@ -254,7 +254,7 @@ impl<'a> Context<'a> {
254254
"import * as wasm from './{}_bg.wasm';\n",
255255
module_name
256256
));
257-
for (id, js) in sorted_iter(&self.wasm_import_definitions) {
257+
for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) {
258258
let import = self.module.imports.get_mut(*id);
259259
import.module = format!("./{}.js", module_name);
260260
footer.push_str("\nexport const ");
@@ -328,7 +328,7 @@ impl<'a> Context<'a> {
328328
OutputMode::Node {
329329
experimental_modules: false,
330330
} => {
331-
for (module, items) in sorted_iter(&self.js_imports) {
331+
for (module, items) in crate::sorted_iter(&self.js_imports) {
332332
imports.push_str("const { ");
333333
for (i, (item, rename)) in items.iter().enumerate() {
334334
if i > 0 {
@@ -351,7 +351,7 @@ impl<'a> Context<'a> {
351351
experimental_modules: true,
352352
}
353353
| OutputMode::Web => {
354-
for (module, items) in sorted_iter(&self.js_imports) {
354+
for (module, items) in crate::sorted_iter(&self.js_imports) {
355355
imports.push_str("import { ");
356356
for (i, (item, rename)) in items.iter().enumerate() {
357357
if i > 0 {
@@ -450,7 +450,7 @@ impl<'a> Context<'a> {
450450
imports_init.push_str(module_name);
451451
imports_init.push_str(" = {};\n");
452452
}
453-
for (id, js) in sorted_iter(&self.wasm_import_definitions) {
453+
for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) {
454454
let import = self.module.imports.get_mut(*id);
455455
import.module = module_name.to_string();
456456
imports_init.push_str("imports.");
@@ -1852,7 +1852,7 @@ impl<'a> Context<'a> {
18521852
}
18531853

18541854
pub fn generate(&mut self) -> Result<(), Error> {
1855-
for (id, adapter) in sorted_iter(&self.wit.adapters) {
1855+
for (id, adapter) in crate::sorted_iter(&self.wit.adapters) {
18561856
let instrs = match &adapter.kind {
18571857
AdapterKind::Import { .. } => continue,
18581858
AdapterKind::Local { instructions } => instructions,
@@ -3055,21 +3055,6 @@ impl ExportedClass {
30553055
}
30563056
}
30573057

3058-
/// Returns a sorted iterator over a hash map, sorted based on key.
3059-
///
3060-
/// The intention of this API is to be used whenever the iteration order of a
3061-
/// `HashMap` might affect the generated JS bindings. We want to ensure that the
3062-
/// generated output is deterministic and we do so by ensuring that iteration of
3063-
/// hash maps is consistently sorted.
3064-
fn sorted_iter<K, V>(map: &HashMap<K, V>) -> impl Iterator<Item = (&K, &V)>
3065-
where
3066-
K: Ord,
3067-
{
3068-
let mut pairs = map.iter().collect::<Vec<_>>();
3069-
pairs.sort_by_key(|(k, _)| *k);
3070-
pairs.into_iter()
3071-
}
3072-
30733058
#[test]
30743059
fn test_generate_identifier() {
30753060
let mut used_names: HashMap<String, usize> = HashMap::new();

0 commit comments

Comments
 (0)