1
0
mirror of https://github.com/fluencelabs/wasm-bindgen synced 2025-06-20 08:16:31 +00:00

Add tests for the interface types output of wasm-bindgen ()

* 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.
This commit is contained in:
Alex Crichton
2019-12-04 15:19:48 -06:00
committed by GitHub
parent b9c93a3c24
commit 203d86f343
22 changed files with 699 additions and 168 deletions

@ -227,7 +227,7 @@ impl<'a> Context<'a> {
} => {
js.push_str("let wasm;\n");
for (id, js) in sorted_iter(&self.wasm_import_definitions) {
for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) {
let import = self.module.imports.get_mut(*id);
import.module = format!("./{}.js", module_name);
footer.push_str("\nmodule.exports.");
@ -254,7 +254,7 @@ impl<'a> Context<'a> {
"import * as wasm from './{}_bg.wasm';\n",
module_name
));
for (id, js) in sorted_iter(&self.wasm_import_definitions) {
for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) {
let import = self.module.imports.get_mut(*id);
import.module = format!("./{}.js", module_name);
footer.push_str("\nexport const ");
@ -328,7 +328,7 @@ impl<'a> Context<'a> {
OutputMode::Node {
experimental_modules: false,
} => {
for (module, items) in sorted_iter(&self.js_imports) {
for (module, items) in crate::sorted_iter(&self.js_imports) {
imports.push_str("const { ");
for (i, (item, rename)) in items.iter().enumerate() {
if i > 0 {
@ -351,7 +351,7 @@ impl<'a> Context<'a> {
experimental_modules: true,
}
| OutputMode::Web => {
for (module, items) in sorted_iter(&self.js_imports) {
for (module, items) in crate::sorted_iter(&self.js_imports) {
imports.push_str("import { ");
for (i, (item, rename)) in items.iter().enumerate() {
if i > 0 {
@ -450,7 +450,7 @@ impl<'a> Context<'a> {
imports_init.push_str(module_name);
imports_init.push_str(" = {};\n");
}
for (id, js) in sorted_iter(&self.wasm_import_definitions) {
for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) {
let import = self.module.imports.get_mut(*id);
import.module = module_name.to_string();
imports_init.push_str("imports.");
@ -1852,7 +1852,7 @@ impl<'a> Context<'a> {
}
pub fn generate(&mut self) -> Result<(), Error> {
for (id, adapter) in sorted_iter(&self.wit.adapters) {
for (id, adapter) in crate::sorted_iter(&self.wit.adapters) {
let instrs = match &adapter.kind {
AdapterKind::Import { .. } => continue,
AdapterKind::Local { instructions } => instructions,
@ -3055,21 +3055,6 @@ impl ExportedClass {
}
}
/// Returns a sorted iterator over a hash map, sorted based on key.
///
/// The intention of this API is to be used whenever the iteration order of a
/// `HashMap` might affect the generated JS bindings. We want to ensure that the
/// generated output is deterministic and we do so by ensuring that iteration of
/// hash maps is consistently sorted.
fn sorted_iter<K, V>(map: &HashMap<K, V>) -> impl Iterator<Item = (&K, &V)>
where
K: Ord,
{
let mut pairs = map.iter().collect::<Vec<_>>();
pairs.sort_by_key(|(k, _)| *k);
pairs.into_iter()
}
#[test]
fn test_generate_identifier() {
let mut used_names: HashMap<String, usize> = HashMap::new();