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.
* Add support for #[wasm_bindgen(inspectable)]
This annotation generates a `toJSON` and `toString` implementation for
generated JavaScript classes which display all readable properties
available via the class or its getters
This is useful because wasm-bindgen classes currently serialize to
display one value named `ptr`, which does not model the properties of
the struct in Rust
This annotation addresses rustwasm/wasm-bindgen#1857
* Support console.log for inspectable attr in Nodejs
`#[wasm_bindgen(inspectable)]` now generates an implementation of
`[util.inspect.custom]` for the Node.js target only. This implementation
causes `console.log` and friends to yield the same class-style output,
but with all readable fields of the Rust struct displayed
* Reduce duplication in generated methods
Generated `toString` and `[util.inspect.custom]` methods now call
`toJSON` to reduce duplication
* Store module name in variable
This commit adds support to wasm-bindgen to run over interface
types-enabled modules that use multi-value returns and returns are
loaded from the returned array rather than from memory.
Using Typescript I have this warning:
`./pkg/index.js
Line 52:22: Expected '!==' and instead saw '!=' eqeqeq
Search for the keywords to learn more about each warning.
To ignore, add // eslint-disable-next-line to the line before.
`
I guess this should solve the warning.
Thank you for all the work.
* autodiscover an exported `main` if possible
this allows for first-class support of binary crates
* wrap `main` to zero out arguments and suppress return value
* add test for bin crate support
* process only the export of the generated main wrapper
* skip most of `export` since only one line of that is needed
This commit switches all of `wasm-bindgen` from the `failure` crate to
`anyhow`. The `anyhow` crate should serve all the purposes that we
previously used `failure` for but has a few advantages:
* It's based on the standard `Error` trait rather than a custom `Fail`
trait, improving ecosystem compatibility.
* We don't need a `#[derive(Fail)]`, which means that's less code to
compile for `wasm-bindgen`. This notably helps the compile time of
`web-sys` itself.
* Using `Result<()>` in `fn main` with `anyhow::Error` produces
human-readable output, so we can use that natively.
* Reduce indentation in interface types processing
Just a small stylistic change
* Update `webidl_ty` field in multi-value transform
When we're emitting a bindings section we need to be sure to update the
listed type of the binding in addition to the actual binding
expressions. This should help remove the stray return pointer being
listed there by accident!
This came up during #1760 where `Promise.resolve` must be invoked with
`this` as the `Promise` object, but we were erroneously importing it in
such a way that it didn't have a shim and `this` was `undefined`.
The threads transform is implicitly enabled nowadays when the memory
looks like it's shared, so ensure that's taken into account in the
`is_enabled` check.
Turns out that `JSON.stringify(undefined)` doesn't actually return a
string, it returns `undefined`! If we're requested to serialize
`undefined` into JSON instead just interpret it as `null` which should
have the expected semantics of serving as a placeholder for `None`.
Closes#1778
To benefit users in debug mode we log any unexpected exceptions to help
diagnose any issues that might arise. It turns out, though, we log this
for *every* exception happening for *every* import, including imports
like `__wbindgen_throw` which are explicitly intended to throw an
exception. This can cause distracting debug logs to get emitted to the
console, so let's squelch the debug logging for known imports that we
shouldn't log for, such as intrinsics.
Closes#1785
This hasn't ever actually worked in `wasm-bindgen` but there's been
enough refactorings since the initial implementation that it's actually
quite trivial to implement now!
Closes#1777
This tiny crate provides utilities for working with Wasm codegen
conventions (typically established by LLVM or lld) such as getting the shadow
stack pointer.
It also de-duplicates all the places in the codebase where we were implementing
these conventions in one-off ways.
* Adding ignoreBOM and fatal to TextDecoder
* Minor tweak to expose_text_processor
* Adding in unit tests for BOM
* Adding in comment for expose_text_decoder
* Attempting to fix build failure
* Temporarily disabling unit tests
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
This commit improves our `instantiateStreaming` fallback to only
actually trigger the fallback if the headers look wrong. If the headers
look right then we let through the original error which should help
avoid accidentally papering over bugs with different bugs in
misconfigured situations.
Closes#1696
Turns out #1704 was buggy and ended up never injecting initialization
because the anyref table was never present! This fixes that issue and
this should now be tested on CI to ensure this doesn't regress and
future changes preserve correctness
This commit updates `wasm-bindgen` to the latest version of `walrus`
which transforms all internal IR representations to a list-based IR
instead of a tree-based IR. This isn't a major change other than
cosmetic for `wasm-bindgen` itself, but involves a lot of changes to the
threads/anyref passes.
This commit also updates our CI configuration to actually run all the
anyref tests on CI. This is done by downloading a nightly build of
node.js which is theorized to continue to be there for awhile until the
full support makes its way into releases.
This commit fixes an issue previously introduced around handling the
anyref table, gracefully handling the case where the source module
doesn't actually use the anyref table at all, meaning that the logic
around initializing it can be entirely skipped.
This is currently required by our ABI for wasm-bindgen where `None` js
values going out have an index of 0 and are intended to be `undefined`.
This also refactors initialization a bit to be slightly more generic
over the constants we already have defined in this module.
This functionality got lost in recent refactorings for WebIDL bindings
unfortunately, so this commit touches things up to ensure that the
anyref table initialization in anyref-mode is hooked up correctly, even
when tests are enabled. This invovled moving injection of the start
function to the webidl processing pass and ensuring its intrinsic is
registered in the internal maps of wasm-bindgen.
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)))
This commit adds support to `wasm-bindgen` to be a drop-in polyfill for
the WebIDL bindings proposal. Lots of internal refactoring has happened
previously to `wasm-bindgen` to make this possible, so this actually
ends up being a very small PR!
Most of `wasm-bindgen` is geared towards Rust-specific types and
Rust-specific support, but with the advent of WebIDL bindings this is a
standard way for a WebAssembly module to communicate its intended
interface in terms of higher level types. This PR allows `wasm-bindgen`
to be a polyfill for any WebAssembly module that has a valid WebIDL
bindings section, regardless of its producer. A standard WebIDL bindings
section is recognized in any input wasm module and that is slurped up
into wasm-bindgen's own internal data structures to get processed in the
same way that all Rust imports/exports are already processed.
The workflow for `wasm-bindgen` looks the same way that it does in Rust
today. You'd execute `wasm-bindgen path/to/foo.wasm --out-dir .` which
would output a new wasm file and a JS shim with the desired interface,
and the new wasm file would be suitable for loading in MVP
implementations of WebAssembly.
Note that this isn't super thoroughly tested, so there's likely still
some lingering assumptions that `wasm-bindgen` makes (such as
`__wbindgen_malloc` and others) which will need to be patched in the
future, but the intention of this commit is to start us down a road of
becoming a drop-in polyfill for WebIDL bindings, regardless of the
source. Also note that there's not actually any producer (AFAIK) of a
WebIDL bindings custom section, so it'd be that much harder to write
tests to do so!
Support has landed in rust-lang/rust for full support for LLVM 9's
interpretation of WebAssembly threads. This commit updates our thread
transformation pass to take all this into account, namely:
* The threadign pass now runs by default and is keyed on whether memory
is shared, not off an env var.
* TLS is initialized in addition to memory on each thread.
* Stack pointer finding is tweaked to account for the TLS base also
being a mutable global.
* The build of the parallel raytrace example was updated to use today's
nightly.
Don't necessarily require a filesystem to execute `wasm-bindgen`,
allowing the `wasm-bindgen-cli-support` crate to be compiled to
WebAssembly, for example, and possibly run `wasm-bindgen` in your
browser! For now this is largely just an internal refactoring and won't
result in many use cases, but it felt like a good refactoring to have
regardless.
Instead of assuming names like `URL` and `Request` are defined, instead
check to see if they exist first and otherwise skip the checks that
reference them.
This commit updates the `walrus` dependency with recent upstream API
changes in `walrus` itself, namely updates to passive segements and how
memory data segments are handled