802 lines
26 KiB
Rust
Raw Normal View History

#![doc(html_root_url = "https://docs.rs/wasm-bindgen-cli-support/0.2")]
use anyhow::{bail, Context, Error};
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::env;
use std::fs;
use std::mem;
use std::path::{Path, PathBuf};
use std::str;
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
use walrus::Module;
2017-12-14 19:31:01 -08:00
mod anyref;
mod decode;
Overhaul how type information gets to the CLI This commit is a complete overhaul of how the `#[wasm_bindgen]` macro communicates type information to the CLI tool, and it's done in a somewhat... unconventional fashion. Today we've got a problem where the generated JS needs to understand the types of each function exported or imported. This understanding is what enables it to generate the appropriate JS wrappers and such. We want to, however, be quite flexible and extensible in types that are supported across the boundary, which means that internally we rely on the trait system to resolve what's what. Communicating the type information historically was done by creating a four byte "descriptor" and using associated type projections to communicate that to the CLI tool. Unfortunately four bytes isn't a lot of space to cram information like arguments to a generic function, tuple types, etc. In general this just wasn't flexible enough and the way custom references were treated was also already a bit of a hack. This commit takes a radical step of creating a **descriptor function** for each function imported/exported. The really crazy part is that the `wasm-bindgen` CLI tool now embeds a wasm interpreter and executes these functions when the CLI tool is invoked. By allowing arbitrary functions to get executed it's now *much* easier to inform `wasm-bindgen` about complicated structures of types. Rest assured though that all these descriptor functions are automatically unexported and gc'd away, so this should not have any impact on binary sizes A new internal trait, `WasmDescribe`, is added to represent a description of all types, sort of like a serialization of the structure of a type that `wasm-bindgen` can understand. This works by calling a special exported function with a `u32` value a bunch of times. This means that when we run a descriptor we effectively get a `Vec<u32>` in the `wasm-bindgen` CLI tool. This list of integers can then be parsed into a rich `enum` for the JS generation to work with. This commit currently only retains feature parity with the previous implementation. I hope to soon solve issues like #123, #104, and #111 with this support.
2018-04-13 07:33:46 -07:00
mod descriptor;
First refactor for WebIDL bindings This commit starts the `wasm-bindgen` CLI tool down the road to being a true polyfill for WebIDL bindings. This refactor is probably the first of a few, but is hopefully the largest and most sprawling and everything will be a bit more targeted from here on out. The goal of this refactoring is to separate out the massive `crates/cli-support/src/js/mod.rs` into a number of separate pieces of functionality. It currently takes care of basically everything including: * Binding intrinsics * Handling anyref transformations * Generating all JS for imports/exports * All the logic for how to import and how to name imports * Execution and management of wasm-bindgen closures Many of these are separable concerns and most overlap with WebIDL bindings. The internal refactoring here is intended to make it more clear who's responsible for what as well as making some existing operations much more straightforward. At a high-level, the following changes are done: 1. A `src/webidl.rs` module is introduced. The purpose of this module is to take all of the raw wasm-bindgen custom sections from the module and transform them into a WebIDL bindings section. This module has a placeholder `WebidlCustomSection` which is nowhere near the actual custom section but if you squint is in theory very similar. It's hoped that this will eventually become the true WebIDL custom section, currently being developed in an external crate. Currently, however, the WebIDL bindings custom section only covers a subset of the functionality we export to wasm-bindgen users. To avoid leaving them high and dry this module also contains an auxiliary custom section named `WasmBindgenAux`. This custom section isn't intended to have a binary format, but is intended to represent a theoretical custom section necessary to couple with WebIDL bindings to achieve all our desired functionality in `wasm-bindgen`. It'll never be standardized, but it'll also never be serialized :) 2. The `src/webidl.rs` module now takes over quite a bit of functionality from `src/js/mod.rs`. Namely it handles synthesis of an `export_map` and an `import_map` mapping export/import IDs to exactly what's expected to be hooked up there. This does not include type information (as that's in the bindings section) but rather includes things like "this is the method of class A" or "this import is from module `foo`" and things like that. These could arguably be subsumed by future JS features as well, but that's for another time! 3. All handling of wasm-bindgen "descriptor functions" now happens in a dedicated `src/descriptors.rs` module. The output of this module is its own custom section (intended to be immediately consumed by the WebIDL module) which is in theory what we want to ourselves emit one day but rustc isn't capable of doing so right now. 4. Invocations and generations of imports are completely overhauled. Using the `import_map` generated in the WebIDL step all imports are now handled much more precisely in one location rather than haphazardly throughout the module. This means we have precise information about each import of the module and we only modify exactly what we're looking at. This also vastly simplifies intrinsic generation since it's all simply a codegen part of the `rust2js.rs` module now. 5. Handling of direct imports which don't have a JS shim generated is slightly different from before and is intended to be future-compatible with WebIDL bindings in its full glory, but we'll need to update it to handle cases for constructors and method calls eventually as well. 6. Intrinsic definitions now live in their own file (`src/intrinsic.rs`) and have a separated definition for their symbol name and signature. The actual implementation of each intrinsic lives in `rust2js.rs` There's a number of TODO items to finish before this merges. This includes reimplementing the anyref pass and actually implementing import maps for other targets. Those will come soon in follow-up commits, but the entire `tests/wasm/main.rs` suite is currently passing and this seems like a good checkpoint.
2019-05-23 09:15:26 -07:00
mod descriptors;
2019-06-13 08:30:06 -07:00
mod intrinsic;
2018-06-27 22:42:34 -07:00
mod js;
Rewrite wasm-bindgen with updated interface types proposal (#1882) This commit is a pretty large scale rewrite of the internals of wasm-bindgen. No user-facing changes are expected as a result of this PR, but due to the scale of changes here it's likely inevitable that at least something will break. I'm hoping to get more testing in though before landing! The purpose of this PR is to update wasm-bindgen to the current state of the interface types proposal. The wasm-bindgen tool was last updated when it was still called "WebIDL bindings" so it's been awhile! All support is now based on https://github.com/bytecodealliance/wasm-interface-types which defines parsers/binary format/writers/etc for wasm-interface types. This is a pretty massive PR and unfortunately can't really be split up any more afaik. I don't really expect realistic review of all the code here (or commits), but some high-level changes are: * Interface types now consists of a set of "adapter functions". The IR in wasm-bindgen is modeled the same way not. * Each adapter function has a list of instructions, and these instructions work at a higher level than wasm itself, for example with strings. * The wasm-bindgen tool has a suite of instructions which are specific to it and not present in the standard. (like before with webidl bindings) * The anyref/multi-value transformations are now greatly simplified. They're simply "optimization passes" over adapter functions, removing instructions that are otherwise present. This way we don't have to juggle so much all over the place, and instructions always have the same meaning.
2019-12-03 11:16:44 -06:00
mod multivalue;
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.
2019-12-04 15:19:48 -06:00
mod throw2unreachable;
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub mod wasm2es6js;
Rewrite wasm-bindgen with updated interface types proposal (#1882) This commit is a pretty large scale rewrite of the internals of wasm-bindgen. No user-facing changes are expected as a result of this PR, but due to the scale of changes here it's likely inevitable that at least something will break. I'm hoping to get more testing in though before landing! The purpose of this PR is to update wasm-bindgen to the current state of the interface types proposal. The wasm-bindgen tool was last updated when it was still called "WebIDL bindings" so it's been awhile! All support is now based on https://github.com/bytecodealliance/wasm-interface-types which defines parsers/binary format/writers/etc for wasm-interface types. This is a pretty massive PR and unfortunately can't really be split up any more afaik. I don't really expect realistic review of all the code here (or commits), but some high-level changes are: * Interface types now consists of a set of "adapter functions". The IR in wasm-bindgen is modeled the same way not. * Each adapter function has a list of instructions, and these instructions work at a higher level than wasm itself, for example with strings. * The wasm-bindgen tool has a suite of instructions which are specific to it and not present in the standard. (like before with webidl bindings) * The anyref/multi-value transformations are now greatly simplified. They're simply "optimization passes" over adapter functions, removing instructions that are otherwise present. This way we don't have to juggle so much all over the place, and instructions always have the same meaning.
2019-12-03 11:16:44 -06:00
mod wit;
2017-12-18 12:39:14 -08:00
2017-12-14 19:31:01 -08:00
pub struct Bindgen {
input: Input,
out_name: Option<String>,
mode: OutputMode,
debug: bool,
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
typescript: bool,
2018-04-11 11:43:18 -07:00
demangle: bool,
keep_debug: bool,
remove_name_section: bool,
remove_producers_section: bool,
emit_start: bool,
// Experimental support for weakrefs, an upcoming ECMAScript feature.
// Currently only enable-able through an env var.
weak_refs: bool,
// Support for the wasm threads proposal, transforms the wasm module to be
// "ready to be instantiated on any thread"
threads: wasm_bindgen_threads_xform::Config,
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
anyref: bool,
multi_value: bool,
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
wasm_interface_types: bool,
encode_into: EncodeInto,
2017-12-14 19:31:01 -08:00
}
pub struct Output {
module: walrus::Module,
stem: String,
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.
2019-12-04 15:19:48 -06:00
generated: Generated,
}
enum Generated {
InterfaceTypes,
Js(JsGenerated),
}
struct JsGenerated {
mode: OutputMode,
js: String,
ts: String,
snippets: HashMap<String, Vec<String>>,
local_modules: HashMap<String, String>,
npm_dependencies: HashMap<String, (PathBuf, String)>,
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.
2019-12-04 15:19:48 -06:00
typescript: bool,
}
#[derive(Clone)]
enum OutputMode {
Bundler { browser_only: bool },
Web,
NoModules { global: String },
Node { experimental_modules: bool },
}
enum Input {
Path(PathBuf),
Module(Module, String),
None,
}
pub enum EncodeInto {
Test,
Always,
Never,
}
2017-12-14 19:31:01 -08:00
impl Bindgen {
pub fn new() -> Bindgen {
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
let anyref = env::var("WASM_BINDGEN_ANYREF").is_ok();
let wasm_interface_types = env::var("WASM_INTERFACE_TYPES").is_ok();
let multi_value = env::var("WASM_BINDGEN_MULTI_VALUE").is_ok();
2017-12-14 19:31:01 -08:00
Bindgen {
input: Input::None,
out_name: None,
mode: OutputMode::Bundler {
browser_only: false,
},
debug: false,
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
typescript: false,
2018-04-11 11:43:18 -07:00
demangle: true,
keep_debug: false,
remove_name_section: false,
remove_producers_section: false,
emit_start: true,
weak_refs: env::var("WASM_BINDGEN_WEAKREF").is_ok(),
threads: threads_config(),
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
anyref: anyref || wasm_interface_types,
multi_value: multi_value || wasm_interface_types,
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
wasm_interface_types,
encode_into: EncodeInto::Test,
2017-12-14 19:31:01 -08:00
}
}
pub fn input_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Bindgen {
self.input = Input::Path(path.as_ref().to_path_buf());
self
}
pub fn out_name(&mut self, name: &str) -> &mut Bindgen {
self.out_name = Some(name.to_string());
self
}
/// Explicitly specify the already parsed input module.
pub fn input_module(&mut self, name: &str, module: Module) -> &mut Bindgen {
let name = name.to_string();
self.input = Input::Module(module, name);
return self;
2017-12-14 19:31:01 -08:00
}
fn switch_mode(&mut self, mode: OutputMode, flag: &str) -> Result<(), Error> {
match self.mode {
OutputMode::Bundler { .. } => self.mode = mode,
_ => bail!(
"cannot specify `{}` with another output mode already specified",
flag
),
}
Ok(())
2017-12-14 21:55:21 -08:00
}
pub fn nodejs(&mut self, node: bool) -> Result<&mut Bindgen, Error> {
if node {
self.switch_mode(
OutputMode::Node {
experimental_modules: false,
},
"--target nodejs",
)?;
}
Ok(self)
Speed up Travis by running Webpack in fewer tests (#381) * Reorganize Travis configuration * Add a `JOB` env var descriptor to all matrix entries. Not used anywhere but is useful when viewing the whole build on Travis's web interface. * Reorganize where builds are located, moving slow builds first and fast ones last. * Change checking the CLI builds from `cargo build` to `cargo check` * Use YAML references to reduce some duplication * Print some more timing statistics for each test * Extract `Project` helper in tests to a module This'll help make it a bit more extensible over time. At the same time the methods are also slightly reorganized to read more clearly from top to bottom. * Migrate all tests away from Webpack Wepback can take a significant amount of time to execute and when it's multiplied by hundreds of tests that adds up really quickly! After investigating Node's `--experimental-modules` option it looks like it's suitable for our use so this switches all tests to using JS files (moving away from TypeScript as well) with `--experimental-modules` with Node. Tests will be selectively re-enabled with webpack and node.js specific output (that doesn't require `--experimental-modules`), coming in later commits. * Restore the node test for node.js output Ensures it's workable as-is * Only generate typescript with webpack * Only read wasm files for webpack * Skip package.json/node_modules for now * Only generate webpack config if needed * Start a dedicated test module for typescript Will hopefully verify the generated Typescript compiles OK. * Remove unneeded `node` method * Fixup some rebase conflicts * Don't run asmjs example on travis * Fixup generator tests * Attempt to fix windows * Comment windows fix * More test fixes * More exclusions * More test fixes * Relax eslint regex Catch mjs modules as well * Fix eslint * Speed up travis on examples slightly
2018-07-04 22:37:09 -05:00
}
pub fn nodejs_experimental_modules(&mut self, node: bool) -> Result<&mut Bindgen, Error> {
if node {
self.switch_mode(
OutputMode::Node {
experimental_modules: true,
},
"--nodejs-experimental-modules",
)?;
}
Ok(self)
}
pub fn bundler(&mut self, bundler: bool) -> Result<&mut Bindgen, Error> {
if bundler {
self.switch_mode(
OutputMode::Bundler {
browser_only: false,
},
"--target bundler",
)?;
}
Ok(self)
}
pub fn web(&mut self, web: bool) -> Result<&mut Bindgen, Error> {
if web {
self.switch_mode(OutputMode::Web, "--target web")?;
}
Ok(self)
2018-04-04 20:06:53 +05:45
}
pub fn no_modules(&mut self, no_modules: bool) -> Result<&mut Bindgen, Error> {
if no_modules {
self.switch_mode(
OutputMode::NoModules {
global: "wasm_bindgen".to_string(),
},
"--target no-modules",
)?;
}
Ok(self)
}
pub fn browser(&mut self, browser: bool) -> Result<&mut Bindgen, Error> {
if browser {
match &mut self.mode {
OutputMode::Bundler { browser_only } => *browser_only = true,
_ => bail!("cannot specify `--browser` with other output types"),
}
}
Ok(self)
}
pub fn no_modules_global(&mut self, name: &str) -> Result<&mut Bindgen, Error> {
match &mut self.mode {
OutputMode::NoModules { global } => *global = name.to_string(),
_ => bail!("can only specify `--no-modules-global` with `--target no-modules`"),
}
Ok(self)
}
pub fn debug(&mut self, debug: bool) -> &mut Bindgen {
self.debug = debug;
self
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub fn typescript(&mut self, typescript: bool) -> &mut Bindgen {
self.typescript = typescript;
self
}
2018-04-11 11:43:18 -07:00
pub fn demangle(&mut self, demangle: bool) -> &mut Bindgen {
self.demangle = demangle;
self
}
pub fn keep_debug(&mut self, keep_debug: bool) -> &mut Bindgen {
self.keep_debug = keep_debug;
self
}
pub fn remove_name_section(&mut self, remove: bool) -> &mut Bindgen {
self.remove_name_section = remove;
self
}
pub fn remove_producers_section(&mut self, remove: bool) -> &mut Bindgen {
self.remove_producers_section = remove;
self
}
pub fn emit_start(&mut self, emit: bool) -> &mut Bindgen {
self.emit_start = emit;
self
}
pub fn encode_into(&mut self, mode: EncodeInto) -> &mut Bindgen {
self.encode_into = mode;
self
}
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
pub fn generate<P: AsRef<Path>>(&mut self, path: P) -> Result<(), Error> {
self.generate_output()?.emit(path.as_ref())
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
}
pub fn generate_output(&mut self) -> Result<Output, Error> {
let (mut module, stem) = match self.input {
Input::None => bail!("must have an input by now"),
Input::Module(ref mut m, ref name) => {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let blank_module = Module::default();
(mem::replace(m, blank_module), &name[..])
}
Input::Path(ref path) => {
let wasm = wit_text::parse_file(&path)
.with_context(|| format!("failed to read `{}`", path.display()))?;
wit_validator::validate(&wasm)
.with_context(|| format!("failed to validate `{}`", path.display()))?;
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let module = walrus::ModuleConfig::new()
// Skip validation of the module as LLVM's output is
// generally already well-formed and so we won't gain much
// from re-validating. Additionally LLVM's current output
// for threads includes atomic instructions but doesn't
// include shared memory, so it fails that part of
// validation!
.strict_validate(false)
.generate_dwarf(self.keep_debug)
.generate_name_section(!self.remove_name_section)
.generate_producers_section(!self.remove_producers_section)
Rewrite wasm-bindgen with updated interface types proposal (#1882) This commit is a pretty large scale rewrite of the internals of wasm-bindgen. No user-facing changes are expected as a result of this PR, but due to the scale of changes here it's likely inevitable that at least something will break. I'm hoping to get more testing in though before landing! The purpose of this PR is to update wasm-bindgen to the current state of the interface types proposal. The wasm-bindgen tool was last updated when it was still called "WebIDL bindings" so it's been awhile! All support is now based on https://github.com/bytecodealliance/wasm-interface-types which defines parsers/binary format/writers/etc for wasm-interface types. This is a pretty massive PR and unfortunately can't really be split up any more afaik. I don't really expect realistic review of all the code here (or commits), but some high-level changes are: * Interface types now consists of a set of "adapter functions". The IR in wasm-bindgen is modeled the same way not. * Each adapter function has a list of instructions, and these instructions work at a higher level than wasm itself, for example with strings. * The wasm-bindgen tool has a suite of instructions which are specific to it and not present in the standard. (like before with webidl bindings) * The anyref/multi-value transformations are now greatly simplified. They're simply "optimization passes" over adapter functions, removing instructions that are otherwise present. This way we don't have to juggle so much all over the place, and instructions always have the same meaning.
2019-12-03 11:16:44 -06:00
.on_parse(wit_walrus::on_parse)
.parse(&wasm)
.context("failed to parse input file as wasm")?;
let stem = match &self.out_name {
Some(name) => &name,
None => path.file_stem().unwrap().to_str().unwrap(),
};
(module, stem)
}
2017-12-14 19:31:01 -08:00
};
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
// This isn't the hardest thing in the world too support but we
// basically don't know how to rationalize #[wasm_bindgen(start)] and
// the actual `start` function if present. Figure this out later if it
// comes up, but otherwise we should continue to be compatible with
// LLVM's output today.
//
// Note that start function handling in `js/mod.rs` will need to be
// updated as well, because `#[wasm_bindgen(start)]` is inserted *after*
// a module's start function, if any, because we assume start functions
// only show up when injected on behalf of wasm-bindgen's passes.
if module.start.is_some() {
bail!(
"wasm-bindgen is currently incompatible with modules that \
already have a start function"
);
Add experimental support for the `anyref` type This commit adds experimental support to `wasm-bindgen` to emit and leverage the `anyref` native wasm type. This native type is still in a proposal status (the reference-types proposal). The intention of `anyref` is to be able to directly hold JS values in wasm and pass the to imported functions, namely to empower eventual host bindings (now renamed WebIDL bindings) integration where we can skip JS shims altogether for many imports. This commit doesn't actually affect wasm-bindgen's behavior at all as-is, but rather this support requires an opt-in env var to be configured. Once the support is stable in browsers it's intended that this will add a CLI switch for turning on this support, eventually defaulting it to `true` in the far future. The basic strategy here is to take the `stack` and `slab` globals in the generated JS glue and move them into wasm using a table. This new table in wasm is managed at the fringes via injected shims. At `wasm-bindgen`-time the CLI will rewrite exports and imports with shims that actually use `anyref` if needed, performing loads/stores inside the wasm module instead of externally in the wasm module. This should provide a boost over what we have today, but it's not a fantastic strategy long term. We have a more grand vision for `anyref` being a first-class type in the language, but that's on a much longer horizon and this is currently thought to be the best we can do in terms of integration in the near future. The stack/heap JS tables are combined into one wasm table. The stack starts at the end of the table and grows down with a stack pointer (also injected). The heap starts at the end and grows up (state managed in linear memory). The anyref transformation here will hook up various intrinsics in wasm-bindgen to the runtime functionality if the anyref supoprt is enabled. The main tricky treatment here was applied to closures, where we need JS to use a different function pointer than the one Rust gives it to use a JS function pointer empowered with anyref. This works by switching up a bit how descriptors work, embedding the shims to call inside descriptors rather than communicated at runtime. This means that we're accessing constant values in the generated JS and we can just update the constant value accessed.
2018-10-18 08:43:36 -07:00
}
2019-08-12 11:28:37 -07:00
self.threads
.run(&mut module)
.with_context(|| "failed to prepare module for threading")?;
First refactor for WebIDL bindings This commit starts the `wasm-bindgen` CLI tool down the road to being a true polyfill for WebIDL bindings. This refactor is probably the first of a few, but is hopefully the largest and most sprawling and everything will be a bit more targeted from here on out. The goal of this refactoring is to separate out the massive `crates/cli-support/src/js/mod.rs` into a number of separate pieces of functionality. It currently takes care of basically everything including: * Binding intrinsics * Handling anyref transformations * Generating all JS for imports/exports * All the logic for how to import and how to name imports * Execution and management of wasm-bindgen closures Many of these are separable concerns and most overlap with WebIDL bindings. The internal refactoring here is intended to make it more clear who's responsible for what as well as making some existing operations much more straightforward. At a high-level, the following changes are done: 1. A `src/webidl.rs` module is introduced. The purpose of this module is to take all of the raw wasm-bindgen custom sections from the module and transform them into a WebIDL bindings section. This module has a placeholder `WebidlCustomSection` which is nowhere near the actual custom section but if you squint is in theory very similar. It's hoped that this will eventually become the true WebIDL custom section, currently being developed in an external crate. Currently, however, the WebIDL bindings custom section only covers a subset of the functionality we export to wasm-bindgen users. To avoid leaving them high and dry this module also contains an auxiliary custom section named `WasmBindgenAux`. This custom section isn't intended to have a binary format, but is intended to represent a theoretical custom section necessary to couple with WebIDL bindings to achieve all our desired functionality in `wasm-bindgen`. It'll never be standardized, but it'll also never be serialized :) 2. The `src/webidl.rs` module now takes over quite a bit of functionality from `src/js/mod.rs`. Namely it handles synthesis of an `export_map` and an `import_map` mapping export/import IDs to exactly what's expected to be hooked up there. This does not include type information (as that's in the bindings section) but rather includes things like "this is the method of class A" or "this import is from module `foo`" and things like that. These could arguably be subsumed by future JS features as well, but that's for another time! 3. All handling of wasm-bindgen "descriptor functions" now happens in a dedicated `src/descriptors.rs` module. The output of this module is its own custom section (intended to be immediately consumed by the WebIDL module) which is in theory what we want to ourselves emit one day but rustc isn't capable of doing so right now. 4. Invocations and generations of imports are completely overhauled. Using the `import_map` generated in the WebIDL step all imports are now handled much more precisely in one location rather than haphazardly throughout the module. This means we have precise information about each import of the module and we only modify exactly what we're looking at. This also vastly simplifies intrinsic generation since it's all simply a codegen part of the `rust2js.rs` module now. 5. Handling of direct imports which don't have a JS shim generated is slightly different from before and is intended to be future-compatible with WebIDL bindings in its full glory, but we'll need to update it to handle cases for constructors and method calls eventually as well. 6. Intrinsic definitions now live in their own file (`src/intrinsic.rs`) and have a separated definition for their symbol name and signature. The actual implementation of each intrinsic lives in `rust2js.rs` There's a number of TODO items to finish before this merges. This includes reimplementing the anyref pass and actually implementing import maps for other targets. Those will come soon in follow-up commits, but the entire `tests/wasm/main.rs` suite is currently passing and this seems like a good checkpoint.
2019-05-23 09:15:26 -07:00
// If requested, turn all mangled symbols into prettier unmangled
// symbols with the help of `rustc-demangle`.
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
if self.demangle {
demangle(&mut module);
}
First refactor for WebIDL bindings This commit starts the `wasm-bindgen` CLI tool down the road to being a true polyfill for WebIDL bindings. This refactor is probably the first of a few, but is hopefully the largest and most sprawling and everything will be a bit more targeted from here on out. The goal of this refactoring is to separate out the massive `crates/cli-support/src/js/mod.rs` into a number of separate pieces of functionality. It currently takes care of basically everything including: * Binding intrinsics * Handling anyref transformations * Generating all JS for imports/exports * All the logic for how to import and how to name imports * Execution and management of wasm-bindgen closures Many of these are separable concerns and most overlap with WebIDL bindings. The internal refactoring here is intended to make it more clear who's responsible for what as well as making some existing operations much more straightforward. At a high-level, the following changes are done: 1. A `src/webidl.rs` module is introduced. The purpose of this module is to take all of the raw wasm-bindgen custom sections from the module and transform them into a WebIDL bindings section. This module has a placeholder `WebidlCustomSection` which is nowhere near the actual custom section but if you squint is in theory very similar. It's hoped that this will eventually become the true WebIDL custom section, currently being developed in an external crate. Currently, however, the WebIDL bindings custom section only covers a subset of the functionality we export to wasm-bindgen users. To avoid leaving them high and dry this module also contains an auxiliary custom section named `WasmBindgenAux`. This custom section isn't intended to have a binary format, but is intended to represent a theoretical custom section necessary to couple with WebIDL bindings to achieve all our desired functionality in `wasm-bindgen`. It'll never be standardized, but it'll also never be serialized :) 2. The `src/webidl.rs` module now takes over quite a bit of functionality from `src/js/mod.rs`. Namely it handles synthesis of an `export_map` and an `import_map` mapping export/import IDs to exactly what's expected to be hooked up there. This does not include type information (as that's in the bindings section) but rather includes things like "this is the method of class A" or "this import is from module `foo`" and things like that. These could arguably be subsumed by future JS features as well, but that's for another time! 3. All handling of wasm-bindgen "descriptor functions" now happens in a dedicated `src/descriptors.rs` module. The output of this module is its own custom section (intended to be immediately consumed by the WebIDL module) which is in theory what we want to ourselves emit one day but rustc isn't capable of doing so right now. 4. Invocations and generations of imports are completely overhauled. Using the `import_map` generated in the WebIDL step all imports are now handled much more precisely in one location rather than haphazardly throughout the module. This means we have precise information about each import of the module and we only modify exactly what we're looking at. This also vastly simplifies intrinsic generation since it's all simply a codegen part of the `rust2js.rs` module now. 5. Handling of direct imports which don't have a JS shim generated is slightly different from before and is intended to be future-compatible with WebIDL bindings in its full glory, but we'll need to update it to handle cases for constructors and method calls eventually as well. 6. Intrinsic definitions now live in their own file (`src/intrinsic.rs`) and have a separated definition for their symbol name and signature. The actual implementation of each intrinsic lives in `rust2js.rs` There's a number of TODO items to finish before this merges. This includes reimplementing the anyref pass and actually implementing import maps for other targets. Those will come soon in follow-up commits, but the entire `tests/wasm/main.rs` suite is currently passing and this seems like a good checkpoint.
2019-05-23 09:15:26 -07:00
unexported_unused_lld_things(&mut module);
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
First refactor for WebIDL bindings This commit starts the `wasm-bindgen` CLI tool down the road to being a true polyfill for WebIDL bindings. This refactor is probably the first of a few, but is hopefully the largest and most sprawling and everything will be a bit more targeted from here on out. The goal of this refactoring is to separate out the massive `crates/cli-support/src/js/mod.rs` into a number of separate pieces of functionality. It currently takes care of basically everything including: * Binding intrinsics * Handling anyref transformations * Generating all JS for imports/exports * All the logic for how to import and how to name imports * Execution and management of wasm-bindgen closures Many of these are separable concerns and most overlap with WebIDL bindings. The internal refactoring here is intended to make it more clear who's responsible for what as well as making some existing operations much more straightforward. At a high-level, the following changes are done: 1. A `src/webidl.rs` module is introduced. The purpose of this module is to take all of the raw wasm-bindgen custom sections from the module and transform them into a WebIDL bindings section. This module has a placeholder `WebidlCustomSection` which is nowhere near the actual custom section but if you squint is in theory very similar. It's hoped that this will eventually become the true WebIDL custom section, currently being developed in an external crate. Currently, however, the WebIDL bindings custom section only covers a subset of the functionality we export to wasm-bindgen users. To avoid leaving them high and dry this module also contains an auxiliary custom section named `WasmBindgenAux`. This custom section isn't intended to have a binary format, but is intended to represent a theoretical custom section necessary to couple with WebIDL bindings to achieve all our desired functionality in `wasm-bindgen`. It'll never be standardized, but it'll also never be serialized :) 2. The `src/webidl.rs` module now takes over quite a bit of functionality from `src/js/mod.rs`. Namely it handles synthesis of an `export_map` and an `import_map` mapping export/import IDs to exactly what's expected to be hooked up there. This does not include type information (as that's in the bindings section) but rather includes things like "this is the method of class A" or "this import is from module `foo`" and things like that. These could arguably be subsumed by future JS features as well, but that's for another time! 3. All handling of wasm-bindgen "descriptor functions" now happens in a dedicated `src/descriptors.rs` module. The output of this module is its own custom section (intended to be immediately consumed by the WebIDL module) which is in theory what we want to ourselves emit one day but rustc isn't capable of doing so right now. 4. Invocations and generations of imports are completely overhauled. Using the `import_map` generated in the WebIDL step all imports are now handled much more precisely in one location rather than haphazardly throughout the module. This means we have precise information about each import of the module and we only modify exactly what we're looking at. This also vastly simplifies intrinsic generation since it's all simply a codegen part of the `rust2js.rs` module now. 5. Handling of direct imports which don't have a JS shim generated is slightly different from before and is intended to be future-compatible with WebIDL bindings in its full glory, but we'll need to update it to handle cases for constructors and method calls eventually as well. 6. Intrinsic definitions now live in their own file (`src/intrinsic.rs`) and have a separated definition for their symbol name and signature. The actual implementation of each intrinsic lives in `rust2js.rs` There's a number of TODO items to finish before this merges. This includes reimplementing the anyref pass and actually implementing import maps for other targets. Those will come soon in follow-up commits, but the entire `tests/wasm/main.rs` suite is currently passing and this seems like a good checkpoint.
2019-05-23 09:15:26 -07:00
// We're making quite a few changes, list ourselves as a producer.
module
.producers
.add_processed_by("wasm-bindgen", &wasm_bindgen_shared::version());
// Learn about the type signatures of all wasm-bindgen imports and
// exports by executing `__wbindgen_describe_*` functions. This'll
// effectively move all the descriptor functions to their own custom
// sections.
descriptors::execute(&mut module)?;
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
First refactor for WebIDL bindings This commit starts the `wasm-bindgen` CLI tool down the road to being a true polyfill for WebIDL bindings. This refactor is probably the first of a few, but is hopefully the largest and most sprawling and everything will be a bit more targeted from here on out. The goal of this refactoring is to separate out the massive `crates/cli-support/src/js/mod.rs` into a number of separate pieces of functionality. It currently takes care of basically everything including: * Binding intrinsics * Handling anyref transformations * Generating all JS for imports/exports * All the logic for how to import and how to name imports * Execution and management of wasm-bindgen closures Many of these are separable concerns and most overlap with WebIDL bindings. The internal refactoring here is intended to make it more clear who's responsible for what as well as making some existing operations much more straightforward. At a high-level, the following changes are done: 1. A `src/webidl.rs` module is introduced. The purpose of this module is to take all of the raw wasm-bindgen custom sections from the module and transform them into a WebIDL bindings section. This module has a placeholder `WebidlCustomSection` which is nowhere near the actual custom section but if you squint is in theory very similar. It's hoped that this will eventually become the true WebIDL custom section, currently being developed in an external crate. Currently, however, the WebIDL bindings custom section only covers a subset of the functionality we export to wasm-bindgen users. To avoid leaving them high and dry this module also contains an auxiliary custom section named `WasmBindgenAux`. This custom section isn't intended to have a binary format, but is intended to represent a theoretical custom section necessary to couple with WebIDL bindings to achieve all our desired functionality in `wasm-bindgen`. It'll never be standardized, but it'll also never be serialized :) 2. The `src/webidl.rs` module now takes over quite a bit of functionality from `src/js/mod.rs`. Namely it handles synthesis of an `export_map` and an `import_map` mapping export/import IDs to exactly what's expected to be hooked up there. This does not include type information (as that's in the bindings section) but rather includes things like "this is the method of class A" or "this import is from module `foo`" and things like that. These could arguably be subsumed by future JS features as well, but that's for another time! 3. All handling of wasm-bindgen "descriptor functions" now happens in a dedicated `src/descriptors.rs` module. The output of this module is its own custom section (intended to be immediately consumed by the WebIDL module) which is in theory what we want to ourselves emit one day but rustc isn't capable of doing so right now. 4. Invocations and generations of imports are completely overhauled. Using the `import_map` generated in the WebIDL step all imports are now handled much more precisely in one location rather than haphazardly throughout the module. This means we have precise information about each import of the module and we only modify exactly what we're looking at. This also vastly simplifies intrinsic generation since it's all simply a codegen part of the `rust2js.rs` module now. 5. Handling of direct imports which don't have a JS shim generated is slightly different from before and is intended to be future-compatible with WebIDL bindings in its full glory, but we'll need to update it to handle cases for constructors and method calls eventually as well. 6. Intrinsic definitions now live in their own file (`src/intrinsic.rs`) and have a separated definition for their symbol name and signature. The actual implementation of each intrinsic lives in `rust2js.rs` There's a number of TODO items to finish before this merges. This includes reimplementing the anyref pass and actually implementing import maps for other targets. Those will come soon in follow-up commits, but the entire `tests/wasm/main.rs` suite is currently passing and this seems like a good checkpoint.
2019-05-23 09:15:26 -07:00
// Process and remove our raw custom sections emitted by the
// #[wasm_bindgen] macro and the compiler. In their stead insert a
Rewrite wasm-bindgen with updated interface types proposal (#1882) This commit is a pretty large scale rewrite of the internals of wasm-bindgen. No user-facing changes are expected as a result of this PR, but due to the scale of changes here it's likely inevitable that at least something will break. I'm hoping to get more testing in though before landing! The purpose of this PR is to update wasm-bindgen to the current state of the interface types proposal. The wasm-bindgen tool was last updated when it was still called "WebIDL bindings" so it's been awhile! All support is now based on https://github.com/bytecodealliance/wasm-interface-types which defines parsers/binary format/writers/etc for wasm-interface types. This is a pretty massive PR and unfortunately can't really be split up any more afaik. I don't really expect realistic review of all the code here (or commits), but some high-level changes are: * Interface types now consists of a set of "adapter functions". The IR in wasm-bindgen is modeled the same way not. * Each adapter function has a list of instructions, and these instructions work at a higher level than wasm itself, for example with strings. * The wasm-bindgen tool has a suite of instructions which are specific to it and not present in the standard. (like before with webidl bindings) * The anyref/multi-value transformations are now greatly simplified. They're simply "optimization passes" over adapter functions, removing instructions that are otherwise present. This way we don't have to juggle so much all over the place, and instructions always have the same meaning.
2019-12-03 11:16:44 -06:00
// forward-compatible wasm interface types section as well as an
// auxiliary section for all sorts of miscellaneous information and
// features #[wasm_bindgen] supports that aren't covered by wasm
// interface types.
wit::process(
2019-09-10 11:20:19 -07:00
&mut module,
self.anyref,
self.wasm_interface_types,
self.emit_start,
)?;
First refactor for WebIDL bindings This commit starts the `wasm-bindgen` CLI tool down the road to being a true polyfill for WebIDL bindings. This refactor is probably the first of a few, but is hopefully the largest and most sprawling and everything will be a bit more targeted from here on out. The goal of this refactoring is to separate out the massive `crates/cli-support/src/js/mod.rs` into a number of separate pieces of functionality. It currently takes care of basically everything including: * Binding intrinsics * Handling anyref transformations * Generating all JS for imports/exports * All the logic for how to import and how to name imports * Execution and management of wasm-bindgen closures Many of these are separable concerns and most overlap with WebIDL bindings. The internal refactoring here is intended to make it more clear who's responsible for what as well as making some existing operations much more straightforward. At a high-level, the following changes are done: 1. A `src/webidl.rs` module is introduced. The purpose of this module is to take all of the raw wasm-bindgen custom sections from the module and transform them into a WebIDL bindings section. This module has a placeholder `WebidlCustomSection` which is nowhere near the actual custom section but if you squint is in theory very similar. It's hoped that this will eventually become the true WebIDL custom section, currently being developed in an external crate. Currently, however, the WebIDL bindings custom section only covers a subset of the functionality we export to wasm-bindgen users. To avoid leaving them high and dry this module also contains an auxiliary custom section named `WasmBindgenAux`. This custom section isn't intended to have a binary format, but is intended to represent a theoretical custom section necessary to couple with WebIDL bindings to achieve all our desired functionality in `wasm-bindgen`. It'll never be standardized, but it'll also never be serialized :) 2. The `src/webidl.rs` module now takes over quite a bit of functionality from `src/js/mod.rs`. Namely it handles synthesis of an `export_map` and an `import_map` mapping export/import IDs to exactly what's expected to be hooked up there. This does not include type information (as that's in the bindings section) but rather includes things like "this is the method of class A" or "this import is from module `foo`" and things like that. These could arguably be subsumed by future JS features as well, but that's for another time! 3. All handling of wasm-bindgen "descriptor functions" now happens in a dedicated `src/descriptors.rs` module. The output of this module is its own custom section (intended to be immediately consumed by the WebIDL module) which is in theory what we want to ourselves emit one day but rustc isn't capable of doing so right now. 4. Invocations and generations of imports are completely overhauled. Using the `import_map` generated in the WebIDL step all imports are now handled much more precisely in one location rather than haphazardly throughout the module. This means we have precise information about each import of the module and we only modify exactly what we're looking at. This also vastly simplifies intrinsic generation since it's all simply a codegen part of the `rust2js.rs` module now. 5. Handling of direct imports which don't have a JS shim generated is slightly different from before and is intended to be future-compatible with WebIDL bindings in its full glory, but we'll need to update it to handle cases for constructors and method calls eventually as well. 6. Intrinsic definitions now live in their own file (`src/intrinsic.rs`) and have a separated definition for their symbol name and signature. The actual implementation of each intrinsic lives in `rust2js.rs` There's a number of TODO items to finish before this merges. This includes reimplementing the anyref pass and actually implementing import maps for other targets. Those will come soon in follow-up commits, but the entire `tests/wasm/main.rs` suite is currently passing and this seems like a good checkpoint.
2019-05-23 09:15:26 -07:00
2019-06-04 09:18:48 -07:00
// Now that we've got type information from the webidl processing pass,
// touch up the output of rustc to insert anyref shims where necessary.
// This is only done if the anyref pass is enabled, which it's
// currently off-by-default since `anyref` is still in development in
// engines.
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
//
// If the anyref pass isn't necessary, then we blanket delete the
// export of all our anyref intrinsics which will get cleaned up in the
// GC pass before JS generation.
if self.anyref {
Rewrite wasm-bindgen with updated interface types proposal (#1882) This commit is a pretty large scale rewrite of the internals of wasm-bindgen. No user-facing changes are expected as a result of this PR, but due to the scale of changes here it's likely inevitable that at least something will break. I'm hoping to get more testing in though before landing! The purpose of this PR is to update wasm-bindgen to the current state of the interface types proposal. The wasm-bindgen tool was last updated when it was still called "WebIDL bindings" so it's been awhile! All support is now based on https://github.com/bytecodealliance/wasm-interface-types which defines parsers/binary format/writers/etc for wasm-interface types. This is a pretty massive PR and unfortunately can't really be split up any more afaik. I don't really expect realistic review of all the code here (or commits), but some high-level changes are: * Interface types now consists of a set of "adapter functions". The IR in wasm-bindgen is modeled the same way not. * Each adapter function has a list of instructions, and these instructions work at a higher level than wasm itself, for example with strings. * The wasm-bindgen tool has a suite of instructions which are specific to it and not present in the standard. (like before with webidl bindings) * The anyref/multi-value transformations are now greatly simplified. They're simply "optimization passes" over adapter functions, removing instructions that are otherwise present. This way we don't have to juggle so much all over the place, and instructions always have the same meaning.
2019-12-03 11:16:44 -06:00
anyref::process(&mut module)?;
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
} else {
let ids = module
.exports
.iter()
.filter(|e| e.name.starts_with("__anyref"))
.map(|e| e.id())
.collect::<Vec<_>>();
for id in ids {
module.exports.delete(id);
}
}
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.
2019-12-04 15:19:48 -06:00
// If wasm interface types are enabled then the `__wbindgen_throw`
// intrinsic isn't available but it may be used by our runtime, so
// change all calls to this function to calls to `unreachable` instead.
// See more documentation in the pass documentation itself.
if self.wasm_interface_types {
throw2unreachable::run(&mut module);
}
// Using all of our metadata convert our module to a multi-value using
// module if applicable.
if self.multi_value {
if !self.wasm_interface_types {
anyhow::bail!(
"Wasm multi-value is currently only available when \
Wasm interface types is also enabled"
);
}
multivalue::run(&mut module)
.context("failed to transform return pointers into multi-value Wasm")?;
}
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
// We've done a whole bunch of transformations to the wasm module, many
// of which leave "garbage" lying around, so let's prune out all our
// unnecessary things here.
gc_module_and_adapters(&mut module);
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.
2019-12-04 15:19:48 -06:00
// We're ready for the final emission passes now. If we're in wasm
// interface types mode then we execute the various passes there and
// generate a valid interface typess section into the wasm module.
//
// Otherwise we execute the JS generation passes to actually emit
// JS/TypeScript/etc. The output here is unused in wasm interfac
let generated = if self.wasm_interface_types {
wit::section::add(&mut module)
.context("failed to generate a standard interface types section")?;
Generated::InterfaceTypes
} else {
let aux = module
.customs
.delete_typed::<wit::WasmBindgenAux>()
.expect("aux section should be present");
let adapters = module
.customs
.delete_typed::<wit::NonstandardWitSection>()
.unwrap();
Rewrite wasm-bindgen with updated interface types proposal (#1882) This commit is a pretty large scale rewrite of the internals of wasm-bindgen. No user-facing changes are expected as a result of this PR, but due to the scale of changes here it's likely inevitable that at least something will break. I'm hoping to get more testing in though before landing! The purpose of this PR is to update wasm-bindgen to the current state of the interface types proposal. The wasm-bindgen tool was last updated when it was still called "WebIDL bindings" so it's been awhile! All support is now based on https://github.com/bytecodealliance/wasm-interface-types which defines parsers/binary format/writers/etc for wasm-interface types. This is a pretty massive PR and unfortunately can't really be split up any more afaik. I don't really expect realistic review of all the code here (or commits), but some high-level changes are: * Interface types now consists of a set of "adapter functions". The IR in wasm-bindgen is modeled the same way not. * Each adapter function has a list of instructions, and these instructions work at a higher level than wasm itself, for example with strings. * The wasm-bindgen tool has a suite of instructions which are specific to it and not present in the standard. (like before with webidl bindings) * The anyref/multi-value transformations are now greatly simplified. They're simply "optimization passes" over adapter functions, removing instructions that are otherwise present. This way we don't have to juggle so much all over the place, and instructions always have the same meaning.
2019-12-03 11:16:44 -06:00
let mut cx = js::Context::new(&mut module, self, &adapters, &aux)?;
cx.generate()?;
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.
2019-12-04 15:19:48 -06:00
let (js, ts) = cx.finalize(stem)?;
Generated::Js(JsGenerated {
snippets: aux.snippets.clone(),
local_modules: aux.local_modules.clone(),
mode: self.mode.clone(),
typescript: self.typescript,
npm_dependencies: cx.npm_dependencies.clone(),
js,
ts,
})
};
Rewrite wasm-bindgen with ES6 modules in mind This commit is a mostly-rewrite of the `wasm-bindgen` tool. After some recent discussions it's clear that the previous model wasn't quite going to cut it, and this iteration is one which primarily embraces ES6 modules and the idea that this is a polyfill for host bindings. The overall interface and functionality hasn't changed much but the underlying technology has now changed significantly. Previously `wasm-bindgen` would emit a JS file that acted as an ES6 module but had a bit of a wonky interface. It exposed an async function for instantiation of the wasm module, but that's the bundler's job, not ours! Instead this iteration views each input and output as a discrete ES6 module. The input wasm file is interpreted as "this *should* be an ES6 module with rich types" and the output is "well here's some ES6 modules that fulfill that contract". Notably the tool now replaces the original wasm ES6 module with a JS ES6 module that has the "rich interface". Additionally a second ES6 module is emitted (the actual wasm file) which imports and exports to the original ES6 module. This strategy is hoped to be much more amenable to bundlers and controlling how the wasm itself is instantiated. The emitted files files purely assume ES6 modules and should be able to work as-is once ES6 module integration for wasm is completed. Note that there aren't a ton of tools to pretend a wasm module is an ES6 module at the moment but those should be coming soon! In the meantime a local `wasm2es6js` hack was added to help make *something* work today. The README has also been updated with instructions for interacting with this model.
2018-01-29 21:20:38 -08:00
Ok(Output {
module,
stem: stem.to_string(),
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.
2019-12-04 15:19:48 -06:00
generated,
})
}
Support emitting direct imports in wasm files Support was previously (re-)added in #1654 for importing direct JS values into a WebAssembly module by completely skipping JS shim generation. This commit takes that PR one step further by *also* embedding a direct import in the wasm file, where supported. The wasm file currently largely just imports from the JS shim file that we generate, but this allows it to directly improt from ES modules where supported and where possible. Note that like #1654 this only happens when the function signature doesn't actually require any conversions to happen in JS (such as handling closures). For imports from ES modules, local snippets, or inline JS they'll all have their import directives directly embedded into the final WebAssembly binary without any shims necessary to hook it all up. For imports from the global namespace or possibly vendor-prefixed items these still unconditionally require an import shim to be generated because there's no way to describe that import in an ES-friendly way (yet). There's a few consequences of this commit which are also worth noting: * The logic in `wasm-bindgen` where it gracefully handles (to some degree) not-defined items now only is guaranteed to be applied to the global namespace. If you import from a module, it'll be an instantiation time error rather than today's runtime error when the import is called. * Handling imports in the wasm module not registered with `#[wasm_bindgen]` has become more strict. Previously these imports were basically ignored, leaving them up for interpretation depending on the output format. The changes for each output target are: * `bundler` - not much has changed here. Previously these ignored imports would have been treated as ES module imports, and after this commit there might just be some more of these imports for bundlers to resolve. * `web` - previously the ignored imports would likely cause instantiation failures because the import object never actually included a binding for other imports. After this commit though the JS glue which instantiates the module now interprets all unrecognized wasm module imports as ES module imports, emitting an `import` directive. This matches what we want for the direct import functionality, and is also largely what we want for modules in general. * `nodejs` - previously ignored imports were handled in the translation shim for Node to generate `require` statements, so they were actually "correctly handled" sort of with module imports. The handling of this hasn't changed, and reflects what we want for direct imports of values where loading a wasm module in Node ends up translating the module field of each import to a `require`. * `no-modules` - this is very similar to the `web` target where previously this didn't really work one way or the other because we'd never fill in more fields of the import object when instantiating the module. After this PR though this is a hard-error to have unrecognized imports from `#[wasm_bindgen]` with the `no-modules` output type, because we don't know how to handle the imports. Note that this touches on #1584 and will likely break the current use case being mentioned there. I think though that this tightening up of how we handle imports is what we'll want in the long run where everything is interpreted as modules, and we'll need to figure out best how wasi fits into this. This commit is unlikely to have any real major immediate effects. The goal here is to continue to inch us towards a world where there's less and less JS glue necessary and `wasm-bindgen` is just a polyfill for web standards that otherwise all already exist. Also note that there's no explicitly added tests for this since this is largely just a refactoring of an internal implementation detail of `wasm-bindgen`, but the main `wasm` test suite has many instances of this path being taken, for example having imports like: (import "tests/wasm/duplicates_a.js" "foo" (func $__wbg_foo_969c253238f136f0 (type 1))) (import "tests/wasm/duplicates_b.js" "foo" (func $__wbg_foo_027958cb2e320a94 (type 0))) (import "./snippets/wasm-bindgen-3dff2bc911f0a20c/inline0.js" "trivial" (func $__wbg_trivial_75e27c84882af23b (type 1))) (import "./snippets/wasm-bindgen-3dff2bc911f0a20c/inline0.js" "incoming_bool" (func $__wbg_incomingbool_0f2d9f55f73a256f (type 0)))
2019-07-31 11:35:36 -07:00
fn local_module_name(&self, module: &str) -> String {
format!("./snippets/{}", module)
}
fn inline_js_module_name(
&self,
unique_crate_identifier: &str,
snippet_idx_in_crate: usize,
) -> String {
format!(
"./snippets/{}/inline{}.js",
unique_crate_identifier, snippet_idx_in_crate,
)
}
2017-12-14 19:31:01 -08:00
}
2018-06-15 12:55:37 -05:00
fn reset_indentation(s: &str) -> String {
let mut indent: u32 = 0;
let mut dst = String::new();
2018-06-15 12:55:37 -05:00
for line in s.lines() {
let line = line.trim();
2018-07-09 14:55:25 -05:00
if line.starts_with('}') || (line.ends_with('}') && !line.starts_with('*')) {
indent = indent.saturating_sub(1);
2018-06-15 12:55:37 -05:00
}
let extra = if line.starts_with(':') || line.starts_with('?') {
1
} else {
0
};
if !line.is_empty() {
for _ in 0..indent + extra {
dst.push_str(" ");
}
dst.push_str(line);
2018-06-15 12:55:37 -05:00
}
dst.push_str("\n");
if line.ends_with('{') {
indent += 1;
2018-06-15 12:55:37 -05:00
}
}
return dst;
2018-06-15 12:55:37 -05:00
}
// Eventually these will all be CLI options, but while they're unstable features
// they're left as environment variables. We don't guarantee anything about
// backwards-compatibility with these options.
fn threads_config() -> wasm_bindgen_threads_xform::Config {
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
let mut cfg = wasm_bindgen_threads_xform::Config::new();
if let Ok(s) = env::var("WASM_BINDGEN_THREADS_MAX_MEMORY") {
cfg.maximum_memory(s.parse().unwrap());
}
if let Ok(s) = env::var("WASM_BINDGEN_THREADS_STACK_SIZE") {
cfg.thread_stack_size(s.parse().unwrap());
}
cfg
}
Migrate `wasm-bindgen` to using `walrus` This commit moves `wasm-bindgen` the CLI tool from internally using `parity-wasm` for wasm parsing/serialization to instead use `walrus`. The `walrus` crate is something we've been working on recently with an aim to replace the usage of `parity-wasm` in `wasm-bindgen` to make the current CLI tool more maintainable as well as more future-proof. The `walrus` crate provides a much nicer AST to work with as well as a structured `Module`, whereas `parity-wasm` provides a very raw interface to the wasm module which isn't really appropriate for our use case. The many transformations and tweaks that wasm-bindgen does have a huge amount of ad-hoc index management to carefully craft a final wasm binary, but this is all entirely taken care for us with the `walrus` crate. Additionally, `wasm-bindgen` will ingest and rewrite the wasm file, often changing the binary offsets of functions. Eventually with DWARF debug information we'll need to be sure to preserve the debug information throughout the transformations that `wasm-bindgen` does today. This is practically impossible to do with the `parity-wasm` architecture, but `walrus` was designed from the get-go to solve this problem transparently in the `walrus` crate itself. (it doesn't today, but this is planned work) It is the intention that this does not end up regressing any `wasm-bindgen` use cases, neither in functionality or in speed. As a large change and refactoring, however, it's likely that at least something will arise! We'll want to continue to remain vigilant to any issues that come up with this commit. Note that the `gc` crate has been deleted as part of this change, as the `gc` crate is no longer necessary since `walrus` does it automatically. Additionally the `gc` crate was one of the main problems with preserving debug information as it often deletes wasm items! Finally, this also starts moving crates to the 2018 edition where necessary since `walrus` requires the 2018 edition, and in general it's more pleasant to work within the 2018 edition!
2019-01-31 09:54:23 -08:00
fn demangle(module: &mut Module) {
for func in module.funcs.iter_mut() {
let name = match &func.name {
Some(name) => name,
None => continue,
};
if let Ok(sym) = rustc_demangle::try_demangle(name) {
func.name = Some(sym.to_string());
}
}
}
impl OutputMode {
fn uses_es_modules(&self) -> bool {
match self {
OutputMode::Bundler { .. }
| OutputMode::Web
| OutputMode::Node {
experimental_modules: true,
} => true,
_ => false,
}
}
fn nodejs_experimental_modules(&self) -> bool {
match self {
OutputMode::Node {
experimental_modules,
} => *experimental_modules,
_ => false,
}
}
fn nodejs(&self) -> bool {
match self {
OutputMode::Node { .. } => true,
_ => false,
}
}
fn no_modules(&self) -> bool {
match self {
OutputMode::NoModules { .. } => true,
_ => false,
}
}
fn always_run_in_browser(&self) -> bool {
match self {
OutputMode::Web => true,
OutputMode::NoModules { .. } => true,
OutputMode::Bundler { browser_only } => *browser_only,
_ => false,
}
}
fn web(&self) -> bool {
match self {
OutputMode::Web => true,
_ => false,
}
}
fn bundler(&self) -> bool {
match self {
OutputMode::Bundler { .. } => true,
_ => false,
}
}
}
First refactor for WebIDL bindings This commit starts the `wasm-bindgen` CLI tool down the road to being a true polyfill for WebIDL bindings. This refactor is probably the first of a few, but is hopefully the largest and most sprawling and everything will be a bit more targeted from here on out. The goal of this refactoring is to separate out the massive `crates/cli-support/src/js/mod.rs` into a number of separate pieces of functionality. It currently takes care of basically everything including: * Binding intrinsics * Handling anyref transformations * Generating all JS for imports/exports * All the logic for how to import and how to name imports * Execution and management of wasm-bindgen closures Many of these are separable concerns and most overlap with WebIDL bindings. The internal refactoring here is intended to make it more clear who's responsible for what as well as making some existing operations much more straightforward. At a high-level, the following changes are done: 1. A `src/webidl.rs` module is introduced. The purpose of this module is to take all of the raw wasm-bindgen custom sections from the module and transform them into a WebIDL bindings section. This module has a placeholder `WebidlCustomSection` which is nowhere near the actual custom section but if you squint is in theory very similar. It's hoped that this will eventually become the true WebIDL custom section, currently being developed in an external crate. Currently, however, the WebIDL bindings custom section only covers a subset of the functionality we export to wasm-bindgen users. To avoid leaving them high and dry this module also contains an auxiliary custom section named `WasmBindgenAux`. This custom section isn't intended to have a binary format, but is intended to represent a theoretical custom section necessary to couple with WebIDL bindings to achieve all our desired functionality in `wasm-bindgen`. It'll never be standardized, but it'll also never be serialized :) 2. The `src/webidl.rs` module now takes over quite a bit of functionality from `src/js/mod.rs`. Namely it handles synthesis of an `export_map` and an `import_map` mapping export/import IDs to exactly what's expected to be hooked up there. This does not include type information (as that's in the bindings section) but rather includes things like "this is the method of class A" or "this import is from module `foo`" and things like that. These could arguably be subsumed by future JS features as well, but that's for another time! 3. All handling of wasm-bindgen "descriptor functions" now happens in a dedicated `src/descriptors.rs` module. The output of this module is its own custom section (intended to be immediately consumed by the WebIDL module) which is in theory what we want to ourselves emit one day but rustc isn't capable of doing so right now. 4. Invocations and generations of imports are completely overhauled. Using the `import_map` generated in the WebIDL step all imports are now handled much more precisely in one location rather than haphazardly throughout the module. This means we have precise information about each import of the module and we only modify exactly what we're looking at. This also vastly simplifies intrinsic generation since it's all simply a codegen part of the `rust2js.rs` module now. 5. Handling of direct imports which don't have a JS shim generated is slightly different from before and is intended to be future-compatible with WebIDL bindings in its full glory, but we'll need to update it to handle cases for constructors and method calls eventually as well. 6. Intrinsic definitions now live in their own file (`src/intrinsic.rs`) and have a separated definition for their symbol name and signature. The actual implementation of each intrinsic lives in `rust2js.rs` There's a number of TODO items to finish before this merges. This includes reimplementing the anyref pass and actually implementing import maps for other targets. Those will come soon in follow-up commits, but the entire `tests/wasm/main.rs` suite is currently passing and this seems like a good checkpoint.
2019-05-23 09:15:26 -07:00
/// Remove a number of internal exports that are synthesized by Rust's linker,
/// LLD. These exports aren't typically ever needed and just add extra space to
/// the binary.
fn unexported_unused_lld_things(module: &mut Module) {
let mut to_remove = Vec::new();
for export in module.exports.iter() {
match export.name.as_str() {
"__heap_base" | "__data_end" | "__indirect_function_table" => {
to_remove.push(export.id());
}
_ => {}
}
}
for id in to_remove {
module.exports.delete(id);
}
}
impl Output {
pub fn js(&self) -> &str {
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.
2019-12-04 15:19:48 -06:00
match &self.generated {
Generated::InterfaceTypes => panic!("no js with interface types output"),
Generated::Js(gen) => &gen.js,
}
}
pub fn wasm(&self) -> &walrus::Module {
&self.module
}
pub fn wasm_mut(&mut self) -> &mut walrus::Module {
&mut self.module
}
pub fn emit(&mut self, out_dir: impl AsRef<Path>) -> Result<(), Error> {
self._emit(out_dir.as_ref())
}
fn _emit(&mut self, out_dir: &Path) -> Result<(), Error> {
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.
2019-12-04 15:19:48 -06:00
let wasm_name = match &self.generated {
Generated::InterfaceTypes => self.stem.clone(),
Generated::Js(_) => format!("{}_bg", self.stem),
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
};
2019-09-10 11:20:19 -07:00
let wasm_path = out_dir.join(wasm_name).with_extension("wasm");
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
fs::create_dir_all(out_dir)?;
2019-09-10 11:34:45 -07:00
let wasm_bytes = self.module.emit_wasm();
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
fs::write(&wasm_path, wasm_bytes)
.with_context(|| format!("failed to write `{}`", wasm_path.display()))?;
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
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.
2019-12-04 15:19:48 -06:00
let gen = match &self.generated {
Generated::InterfaceTypes => return Ok(()),
Generated::Js(gen) => gen,
};
Add support for emitting a Wasm Interface Types section This commit adds support to `wasm-bindgen` to emit a WebAssembly module that contains a WebAssembly Interface Types section. As of today there are no native consumers of these WebAssembly modules, and the actual binary format here is basically arbitrary (chosen by the `wasm-webidl-bindings` crate). The intention is that we'll be following the [WebAssembly Interface Types proposal][proposal] very closely and update here as necessary. The main feature added in this PR is that a new experimental environment variable, `WASM_INTERFACE_TYPES=1`, is recognized by the `wasm-bindgen` CLI tool. When present the CLI tool will act differently than it does today: * The `anyref` feature will be implicitly enabled * A WebAssembly interface types section will be emitted in the WebAssembly module * For now, the WebAssembly module is strictly validated to require zero JS glue. This means that `wasm-bindgen` is producing a fully standalone WebAssembly module. The last point here is one that will change before this functionality is stabilized in `wasm-bindgen`. For now it reflects the major use case of this feature which is to produce a standalone WebAssembly module with no support JS glue, and to do that we need to verify properties like it's not using JS global names, nonstandard binding expressions, etc. The error messages here aren't the best but they at least fail compilation at some point instead of silently producing weird wasm modules. Eventually it's envisioned that a WebAssembly module will contain an interface types section but *also* have JS glue so binding expressions can be used when available but otherwise we'd still generate JS glue for things like nonstandard expressions and accessing JS global values. It should be noted that a major feature not implemented in `wasm-bindgen` yet is the multi-value proposal for WebAssembly. This is coming soon (as soon as we can) in `walrus` and later for a pass here, but for now this means that returning multiple values (like a string which has a pointer/length) is a bit of a hack. To enable this use case a `wasm-bindgen`-specific-convention which will never be stabilized is invented here by using binding expression to indicate "this return value is actually returned through an out-ptr as the first argument list". This is a gross hack and is guaranteed to be removed. Eventually we will support multi-value and the wasm module emitted will simply use multi-value and contain internal polyfills for Rust's ABI which returns values through out-ptrs. Overall this should make `wasm-bindgen` usable for playing around with the WebIDL bindings proposal and helping us get a taste of what it looks like to have entirely standalone WebAssembly modules running in multiple environments, no extra fluff necessary! [proposal]: https://github.com/webassembly/webidl-bindings
2019-06-25 01:21:38 -07:00
// Write out all local JS snippets to the final destination now that
// we've collected them from all the programs.
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.
2019-12-04 15:19:48 -06:00
for (identifier, list) in gen.snippets.iter() {
for (i, js) in list.iter().enumerate() {
let name = format!("inline{}.js", i);
let path = out_dir.join("snippets").join(identifier).join(name);
fs::create_dir_all(path.parent().unwrap())?;
fs::write(&path, js)
.with_context(|| format!("failed to write `{}`", path.display()))?;
}
}
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.
2019-12-04 15:19:48 -06:00
for (path, contents) in gen.local_modules.iter() {
let path = out_dir.join("snippets").join(path);
fs::create_dir_all(path.parent().unwrap())?;
fs::write(&path, contents)
.with_context(|| format!("failed to write `{}`", path.display()))?;
}
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.
2019-12-04 15:19:48 -06:00
if gen.npm_dependencies.len() > 0 {
let map = gen
.npm_dependencies
.iter()
.map(|(k, v)| (k, &v.1))
.collect::<BTreeMap<_, _>>();
let json = serde_json::to_string_pretty(&map)?;
fs::write(out_dir.join("package.json"), json)?;
}
// And now that we've got all our JS and TypeScript, actually write it
// out to the filesystem.
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.
2019-12-04 15:19:48 -06:00
let extension = if gen.mode.nodejs_experimental_modules() {
"mjs"
} else {
"js"
};
let js_path = out_dir.join(&self.stem).with_extension(extension);
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.
2019-12-04 15:19:48 -06:00
fs::write(&js_path, reset_indentation(&gen.js))
.with_context(|| format!("failed to write `{}`", js_path.display()))?;
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.
2019-12-04 15:19:48 -06:00
if gen.typescript {
let ts_path = js_path.with_extension("d.ts");
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.
2019-12-04 15:19:48 -06:00
fs::write(&ts_path, &gen.ts)
.with_context(|| format!("failed to write `{}`", ts_path.display()))?;
}
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.
2019-12-04 15:19:48 -06:00
if gen.mode.nodejs() {
let js_path = wasm_path.with_extension(extension);
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.
2019-12-04 15:19:48 -06:00
let shim = gen.generate_node_wasm_import(&self.module, &wasm_path);
fs::write(&js_path, shim)
.with_context(|| format!("failed to write `{}`", js_path.display()))?;
}
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.
2019-12-04 15:19:48 -06:00
if gen.typescript {
let ts_path = wasm_path.with_extension("d.ts");
let ts = wasm2es6js::typescript(&self.module)?;
fs::write(&ts_path, ts)
.with_context(|| format!("failed to write `{}`", ts_path.display()))?;
}
Ok(())
}
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.
2019-12-04 15:19:48 -06:00
}
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.
2019-12-04 15:19:48 -06:00
impl JsGenerated {
fn generate_node_wasm_import(&self, m: &Module, path: &Path) -> String {
let mut imports = BTreeSet::new();
for import in m.imports.iter() {
imports.insert(&import.module);
}
let mut shim = String::new();
if self.mode.nodejs_experimental_modules() {
for (i, module) in imports.iter().enumerate() {
shim.push_str(&format!("import * as import{} from '{}';\n", i, module));
}
// On windows skip the leading `/` which comes out when we parse a
// url to use `C:\...` instead of `\C:\...`
shim.push_str(&format!(
"
import * as path from 'path';
import * as fs from 'fs';
import * as url from 'url';
import * as process from 'process';
let file = path.dirname(url.parse(import.meta.url).pathname);
if (process.platform === 'win32') {{
file = file.substring(1);
}}
const bytes = fs.readFileSync(path.join(file, '{}'));
",
path.file_name().unwrap().to_str().unwrap()
));
} else {
shim.push_str(&format!(
"
const path = require('path').join(__dirname, '{}');
const bytes = require('fs').readFileSync(path);
",
path.file_name().unwrap().to_str().unwrap()
));
}
shim.push_str("let imports = {};\n");
for (i, module) in imports.iter().enumerate() {
if self.mode.nodejs_experimental_modules() {
shim.push_str(&format!("imports['{}'] = import{};\n", module, i));
} else {
shim.push_str(&format!("imports['{0}'] = require('{0}');\n", module));
}
}
shim.push_str(&format!(
"
const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
",
));
if self.mode.nodejs_experimental_modules() {
for entry in m.exports.iter() {
shim.push_str("export const ");
shim.push_str(&entry.name);
shim.push_str(" = wasmInstance.exports.");
shim.push_str(&entry.name);
shim.push_str(";\n");
}
} else {
shim.push_str("module.exports = wasmInstance.exports;\n");
}
reset_indentation(&shim)
}
}
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
fn gc_module_and_adapters(module: &mut Module) {
loop {
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.
2019-12-04 15:19:48 -06:00
// Fist up, cleanup the native wasm module. Note that roots can come
// from custom sections, namely our wasm interface types custom section
// as well as the aux section.
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
walrus::passes::gc::run(module);
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.
2019-12-04 15:19:48 -06:00
// ... and afterwards we can delete any `implements` directives for any
// imports that have been deleted.
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
let imports_remaining = module
.imports
.iter()
.map(|i| i.id())
.collect::<HashSet<_>>();
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.
2019-12-04 15:19:48 -06:00
let mut section = module
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
.customs
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.
2019-12-04 15:19:48 -06:00
.delete_typed::<wit::NonstandardWitSection>()
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
.unwrap();
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.
2019-12-04 15:19:48 -06:00
section
.implements
.retain(|pair| imports_remaining.contains(&pair.0));
// ... and after we delete the `implements` directive we try to
// delete some adapters themselves. If nothing is deleted, then we're
// good to go. If something is deleted though then we may have free'd up
// some functions in the main module to get deleted, so go again to gc
// things.
let aux = module.customs.get_typed::<wit::WasmBindgenAux>().unwrap();
let any_removed = section.gc(aux);
module.customs.add(*section);
if !any_removed {
Add reference output tests for JS operations (#1894) * Add reference output tests for JS operations This commit starts adding a test suite which checks in, to the repository, test assertions for both the JS and wasm file outputs of a Rust crate compiled with `#[wasm_bindgen]`. These aren't intended to be exhaustive or large scale tests, but rather micro-tests to help observe the changes in `wasm-bindgen`'s output over time. The motivation for this commit is basically overhauling how all the GC passes work in `wasm-bindgen` today. The reorganization is also included in this commit as well. Previously `wasm-bindgen` would, in an ad-hoc fashion, run the GC passes of `walrus` in a bunch of places to ensure that less "garbage" was seen by future passes. This not only was a source of slowdown but it also was pretty brittle since `wasm-bindgen` kept breaking if extra iteams leaked through. The strategy taken in this commit is to have one precise location for a GC pass, and everything goes through there. This is achieved by: * All internal exports are removed immediately when generating the nonstandard wasm interface types section. Internal exports, intrinsics, and runtime support are all referenced by the various instructions and/or sections that use them. This means that we now have precise tracking of what an adapter uses. * This in turn enables us to implement the `add_gc_roots` function for `walrus` custom sections, which in turn allows walrus GC passes to do what `unexport_unused_intrinsics` did before. That function is now no longer necessary, but effectively works the same way. All intrinsics are unexported at the beginning and then they're selectively re-imported and re-exported through the JS glue generation pass as necessary and defined by the bindings. * Passes like the `anyref` pass are now much more precise about the intrinsics that they work with. The `anyref` pass also deletes any internal intrinsics found and also does some rewriting of the adapters aftewards now to hook up calls to the heap count import to the heap count intrinsic in the wasm module. * Fix handling of __wbindgen_realloc The final user of the `require_internal_export` function was `__wbindgen_realloc`. This usage has now been removed by updating how we handle usage of the `realloc` function. The wasm interface types standard doesn't have a `realloc` function slot, nor do I think it ever will. This means that as a polyfill for wasm interface types we'll always have to support the lack of `realloc`. For direct Rust to JS, however, we can still optionally handle `realloc`. This is all handled with a few internal changes. * Custom `StringToMemory` instructions now exist. These have an extra `realloc` slot to store an intrinsic, if found. * Our custom instructions are lowered to the standard instructions when generating an interface types section. * The `realloc` function, if present, is passed as an argument like the malloc function when passing strings to wasm. If it's not present we use a slower fallback, but if it's present we use the faster implementation. This should mean that there's little-to-no impact on existing users of `wasm-bindgen`, but this should continue to still work for wasm interface types polyfills and such. Additionally the GC passes now work in that they don't delete `__wbindgen_realloc` which we later try to reference. * Add an empty test for the anyref pass * Precisely track I32FromOptionAnyref's dependencies This depends on the anyref table and a function to allocate an index if the anyref pass is running, so be sure to track that in the instruction itself for GC rooting. * Trim extraneous exports from nop anyref module Or if you're otherwise not using anyref slices, don't force some intrinsics to exist. * Remove globals from reference tests Looks like these values adjust in slight but insignificant ways over time * Update the anyref xform tests
2019-12-04 12:01:39 -06:00
break;
}
}
}
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.
2019-12-04 15:19:48 -06:00
/// 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()
}