Looks like `TextEncoder#encodeInto` isn't compatible when the buffer
passed in is backed by a `SharedArrayBuffer`, so if the module has a
shared thread skip the `encodeInto` optimization entirely.
This commit adds support for the recently implemented standard of
[`TextEncoder#encodeInto`][standard]. This new function is a "bring your
own buffer" style function where we can avoid an intermediate allocation
and copy by encoding strings directly into wasm's memory.
Currently we feature-detect whether `encodeInto` exists as it is only
implemented in recent browsers and not in all browsers. Additionally
this commit emits the binding using `encodeInto` by default, but this
requires `realloc` functionality to be exposed by the wasm module.
Measured locally an empty binary which takes `&str` previously took
7.6k, but after this commit takes 8.7k due to the extra code needed for
`realloc`.
[standard]: https://encoding.spec.whatwg.org/#dom-textencoder-encodeintoCloses#1172
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.
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!
This commit updates the `--debug` output of `wasm-bindgen` from the CLI
to catch all JS exceptions from imported functions, log such, and then
rethrow. It's hoped that this can be used when necessary to learn more
information about thrown exceptions and where an uncaught exception
could be causing issues with Rust code.
Closes#1176
Throw it in an `Option` and then `take()` it when we consume it to
ensure that future calls to insert data into it panic instead of
producing inconsistent JS.
We might gc a table away so if we need to export it be sure to do so
before we gc! Additionally remove an extraneous gc that snuck in at some
point, no need to do more than one.
Closes#1130
Turns out `heap.fill(undefined)` is required to ensure it's a dense
array, otherwise we'll accidentally be a sparse array and much slower
than necessary!
This commit switches strategies for storing `JsValue` from a heap/stack
to just one heap. This mirrors the new strategy for `JsValue` storage
in #1002 and should make multiplexing those strategies at
`wasm-bindgen`-time much easier.
Instead of having one array which acts as a stack for borrowed values
and one array for a heap of borrowed values, only one JS array is used
for storage of JS values now. This makes `getObject` far simpler by
simply being an array access, but it means that cloning an object now
reserves a new slot instead of reference counting it. If the old
reference counting behavior is needed it's thought that `Rc<JsValue>`
can be used in Rust.
The new "heap" has an initial stack pointer which grows downwards, and a
heap which grows upwards. The heap is a singly-linked-list which is
allocated/deallocated from. The stack grows downwards to zero and
presumably starts generating errors once it underflows. An initial stack
size of 32 is chosen as that should encompass all use cases today, but
we can eventually probably add configuration for this!
Note that the heap is initialized to all `null` for the stack and then
the initial JS values (`undefined`, `null`, `true`, `false`) are pushed
onto the heap in reserved locations.
Currently closure shims are communicated to JS at runtime, although at
runtime the same constant value is always passed to JS! More pressing,
however, work in #1002 requires knowledge of closure descriptor indices
at `wasm-bindgen` time which is not currently known.
Since the closure descriptor shims and such are already constant values,
this commit moves the descriptor function indices into the *descriptor*
for a closure/function pointer. This way we can learn about these values
at `wasm-bindgen` time instead of only knowing them at runtime.
This should have no semantic change on users of `wasm-bindgen`, although
some closure invocations may be slightly speedier because there's less
arguments being transferred over the boundary. Overall though this will
help #1002 as the closure shims that the Rust compiler generates may not
be the exact ones we hand out to JS, but rather wrappers around them
which do `anyref` business things.
This commit adds a new attribute to `#[wasm_bindgen]`: `start`. The
`start` attribute can be used to indicate that a function should be
executed when the module is loaded, configuring the `start` function of
the wasm executable. While this doesn't necessarily literally configure
the `start` section, it does its best!
Only one crate in a crate graph may indicate `#[wasm_bindgen(start)]`,
so it's not recommended to be used in libraries but only end-user
applications. Currently this still must be used with the `crate-type =
["cdylib"]` annotation in `Cargo.toml`.
The implementation here is somewhat tricky because of the circular
dependency between our generated JS and the wasm file that we emit. This
circular dependency makes running initialization routines (like the
`start` shim) particularly fraught with complications because one may
need to run before the other but bundlers may not necessarily respect
it. Workarounds have been implemented for various emission strategies,
for example calling the start function directly after exports are wired
up with `--no-modules` and otherwise working around what appears to be
a Webpack bug with initializers running in a different order than we'd
like. In any case, this in theory doesn't show up to the end user!
Closes#74
Recently proposed in WebAssembly/tool-conventions#65 each wasm file will
now have an optional `producers` section listing the tooling that went
into producing it. Let's add `wasm-bindgen` in when it processes a wasm
file!
This commit adds an optimization to `wasm-bindgen` to directly import
and invoke other modules' functions from the wasm module, rather than
going through a shim in the imported bindings. This will be an important
optimization in the future for the host bindings proposal, but for now
it's largely just a proof-of-concept to show that we can do it and is
unlikely to bring about many performance benefits.
The implementation in this commit is largely refactoring to reorganize a
bit how functions are imported, but the implementation happens in
`generate_import_function`.
With this commit, 71/287 imports in the `tests/wasm/main.rs` suite get
hooked up directly to the ES modules, no shims needed!
When returning a ptr/length for allocations and such wasm-bindgen's
generated JS would previously return an array with two elements. It
turns out this doesn't optimize well in all engines! (See #1031). It
looks like we can optimize the array destructuring a bit more, but this
is all generated code which doesn't need to be too readable so we can
also remove the temporary allocation entirely and just pass the second
element of this array through a global instead of the return value.
Closes#1031
This fixes a mistake in allowing a `WebAssembly.Module` to be passed to
the initialization function in `--no-modules` mode by ensuring that it
resolves to a map of an instance/module instead of just resolving to an
instance.
This commit adds a `--remove-name-section` flag to the `wasm-bindgen`
command which will remove the `name` section of the wasm file, used to
indicate the names of functions typically used in debugging. This flag
is off-by-default and will primarily be controlled by wasm-pack,
typically being passed by default with `wasm-pack build --release`.
Closes#1021
This commit removes shims, where possible, for `structural` items.
Instead of generating code that looks like:
const target = function() { this.foo(); };
exports.__wbg_thing = function(a) { target.call(getObject(a)); };
we now instead generate:
exports.__wbg_thing = function(a) { getObject(a).foo(); };
Note that this only applies to `structural` bindings, all default
bindings (as of this commit) are still using imported targets to ensure
that their binding can't change after instantiation.
This change was [detailed in RFC #5][link] as an important optimization
for `structural` bindings to ensure they've got performance parity with
today's non-`structural` default bindings.
[link]: https://rustwasm.github.io/rfcs/005-structural-and-deref.html#why-is-it-ok-to-make-structural-the-default