66 Commits

Author SHA1 Message Date
Alex Crichton
6e8c3e88f8 Directly import __wrap functions if possible
These can have similar optimizations as importing a value directly.
2019-06-05 07:52:14 -07:00
Alex Crichton
cfd3e0406f Split symbol intrinsics into two
This allows using WebIDL bindings types to describe both of them instead
of having a custom ABI, allowing for more direct and rich bindings
eventually!
2019-06-05 07:52:14 -07:00
Alex Crichton
4eafaeae2d Handle the function table export on-demand
Don't delay processing until `finalize`, but instead process it as soon
as it's requested to avoid doing too much logic in `finalize`.
2019-06-05 07:52:14 -07:00
Alex Crichton
3b5e3edd18 Fix anyref closure transformations
* Catch all closures by walking all `Descriptor` values and looking for
  either `Function` or `Closure`.
* Update the correct arguments for wasm by ensuring that the closure
  modifications skip the first two arguments.
2019-06-05 07:52:14 -07:00
Alex Crichton
b51df39bc9 Reimplement anyref processing and passes
This commit reimplements the `anyref` transformation pass tasked with
taking raw rustc output and enhancing the module to use `anyref`. This
was disabled in the previous commits during refactoring, and now the
pass is re-enabled in the manner originally intended.

Instead of being tangled up in the `js/mod.rs` pass, the anyref
transformation now happens locally within one module,
`cli-support/src/anyref.rs`, which exclusively uses the output of the
`webidl` module which produces a WebIDL bindings section as well as an
auxiliary wasm-bindgen specific section. This makes the anyref transform
much more straightforward and local, ensuring that it doesn't propagate
elsewhere and can be a largely local concern during the transformation.

The main addition needed to support this pass was detailed knowledge of
the ABI of a `Descriptor`. This knowledge is already implicitly
hardcoded in `js2rust.rs` and `rust2js.rs` through the ABI shims
generated. This was previously used for the anyref transformation to
piggy-back what was already there, but as a separate pass we are unable
to reuse the knowledge in the binding generator.

Instead `Descriptor` now has two dedicated methods describing the
various ABI properties of a type. This is then asserted to be correct
(all the time) when processing bindings, ensuring that the two are kept
in sync.
2019-06-05 07:52:14 -07:00
Alex Crichton
55fc5367a5 Fix a typo in the JsvalEq intrinsic
This is supposed to be `===`, not `==`.
2019-06-05 07:52:14 -07:00
Alex Crichton
3e28e6ea46 Fix web, no-modules, and bundler output types
Make sure the wasm import definition map is hooked up correctly!
2019-06-05 07:52:14 -07:00
Alex Crichton
68c5233f80 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-06-05 07:52:14 -07:00
Gus Caplan
2cc40a27d2
Run fmt and clippy 2019-05-28 09:52:44 -05:00
Nick Fitzgerald
805aaa2273 Log stacks of imported JS functions that throw but are not marked catch
Particularly useful in our tests, where we don't have the regular console
logging with post-facto object inspection, and instead need to provide all this
info up front.
2019-04-17 13:16:48 -07:00
Alex Crichton
ff1addbbaa Run cargo fmt 2019-04-16 10:52:27 -07:00
Alex Crichton
0160f6af45 Fix handling of u32 between Rust and JS
All numbers in WebAssembly are signed and then each operation on them
may optionally have an unsigned version. This means that when we pass
large signed numbers to JS they actually show up as large negative
numbers even though JS numbers can faithfully represent the type.

This is fixed by adding `>>>0` in a few locations in the generated
bindings to coerce the JS value into an unsigned value.

Closes #1388
2019-03-27 13:37:14 -07:00
Ingvar Stepanyan
a5f5c7a9e8 Consistently expose is_like_none
Aside from visual deduplication, this actually fixes a bug in js2rust.rs where it didn't call `expose_is_like_none` but used `isLikeNone` inside of `arg.get_64()` branch.
2019-03-26 18:53:55 +00:00
Alex Crichton
72672ff42a
Merge pull request #1397 from RReverser/option-char-abi
Simplify ABI for Option<char>
2019-03-26 13:50:59 -05:00
Ingvar Stepanyan
5f742ca4c4 Simplify ABI for Option<char>
Flatten None to a special u32 value instead of using an intermediate pointer.
2019-03-26 18:12:24 +00:00
Alex Crichton
a6fe0cefa8 Migrate all crates to the 2018 edition
Most of the CLI crates were already in the 2018 edition, and it turns
out that one of the macro crates was already in the 2018 edition so we
may as well move everything to the 2018 edition!

Always nice to remove those `extern crate` statements nowadays!

This commit also does a `cargo fmt --all` to make sure we're conforming
with style again.
2019-03-26 08:10:53 -07:00
Caio
70f5373348 Preserve argument names 2019-03-14 08:46:42 -03:00
Alex Crichton
4181fb311a 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.
2019-02-20 07:28:54 -08:00
Alex Crichton
f831711f5d Support Option<RustStruct> in arguments/returns
Add all the necessary support in a few locations and we should be good
to go!

Closes #1252
2019-02-19 09:08:37 -08:00
Alex Crichton
894b479213 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-02-12 07:25:53 -08:00
Pauan
e4294babeb Simplifying the error handling code 2019-02-04 02:08:08 +01:00
Alex Crichton
9224455077 Support Option with custom enums in JS
Find a hole automatically to use a sentinel value for `None`, and then
just wire everything up!

Closes #1198
2019-01-28 14:27:57 -08:00
Alex Crichton
f2f11a01a2 In debug mode log all imported uncaught exceptions
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
2019-01-14 15:59:31 -08:00
Alex Crichton
29531c0abf Run rustfmt 2018-11-30 13:04:27 -08:00
Alex Crichton
07b148789d Defer exposing methods until they're needed
Previously `catch` and `variadic` would exopse methods in our JS shims,
but they did so earlier than necessary. Turns out `variadic` didn't
actually need to expose anything and `catch` could do so much later!
2018-11-29 17:50:13 -08:00
Alex Crichton
42053ddd4e Move closure shims into the descriptor
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.
2018-11-29 12:42:44 -08:00
Alex Crichton
48f4adfa8c Run rustfmt over everything 2018-11-27 12:07:59 -08:00
Alex Crichton
992fad85ab
Merge pull request #1030 from alexcrichton/wire-up-directly
Add an optimization to directly wire up imported functions
2018-11-14 09:05:47 -06:00
Alex Crichton
68537b9649 Add an optimization to directly wire up imported functions
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!
2018-11-13 13:16:38 -08:00
Alex Crichton
c915870526 Remove temporary object allocation
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
2018-11-13 08:10:05 -08:00
Alex Crichton
6093fd29d1 Don't convert boolean arguments going to wasm
The wasm spec defines boolean conversion when crossing to the wasm type
i32 as 1 for `true` and 0 for `false`, so no need for us to do it
ourselves!
2018-11-08 13:06:03 -08:00
Alex Crichton
a16b4dd9a4 Optimize shim generation for structural items
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
2018-11-08 13:04:38 -08:00
Alex Crichton
7ecf4aae87 cargo +nightly fmt --all
Rustfmt all the things!
2018-09-26 08:26:00 -07:00
Alex Crichton
7b495468f6 Implement support for Uint8ClampedArray
This commit implements support for binding APIs that take
`Uint8ClampedArray` in JS. This is pretty rare but comes up in a
`web-sys` binding or two, and we're now able to bind these APIs instead
of having to omit the bindings.

The `Uint8ClampedArray` type is bound by using the `Clamped` marker
struct in Rust. For example this is declaring a JS API that takes
`Uint8ClampedArray`:

    use wasm_bindgen::Clamped;

    #[wasm_bindgen]
    extern {
        fn takes_clamped(a: Clamped<&[u8]>);
    }

The `Clamped` type currently only works when wrapping the `&[u8]`, `&mut
[u8]`, and `Vec<u8>` types. Everything else will produce an error at
`wasm-bindgen` time.

Closes #421
2018-09-24 13:58:37 -07:00
Alex Crichton
3f85d7db9f Remove the need for a ConstructorToken
This commit removes the need for an injected `ConstructorToken` type and
also cleans up the story we have for generating constructors a bit.
After this commit a `constructor()` is omitted entirely if we're in
non-debug mode and there's no actual listed constructor. Additionally we
don't deal with splat arguments and rerouting constructors, Nick was
kind enough to enlighten me about `Object.create` which is creating an
instance without running the constructor!

Instances of an exported type are now created through one of two
methods:

* If `#[wasm_bindgen(constructor)]` is present, then a `constructor` is
  generated with the appropriate signature. If a constructor is not
  present and we're in debug mode, a throwing constructor is generated.
  If we're in release mode and there's no constructor, no constructor is
  generated.

* Otherwise if a binding returns an instance of a type (or otherwise
  needs to manfuacture an instance, then it will cause an internal
  `__wrap` function to be generated. This function will use
  `Object.create` to create an instance without running the constructor.

This should ideally clean up our generated JS for classes quite a bit,
making it much more lean-and-mean!
2018-09-21 17:42:06 -07:00
Alex Crichton
7cf4213283 Allow returning Result from functions
This commit adds support for exporting a function defined in Rust that returns a
`Result`, translating the `Ok` variant to the actual return value and the `Err`
variant to an exception that's thrown in JS.

The support for return types and descriptors was rejiggered a bit to be a bit
more abstract and more well suited for this purpose. We no longer distinguish
between functions with a return value and those without a return value.
Additionally a new trait, `ReturnWasmAbi`, is used for converting return values.
This trait is an internal implementation detail, however, and shouldn't surface
itself to users much (if at all).

Closes #841
2018-09-18 13:13:59 -07:00
Anton Danilkin
14eb317509 Merge remote-tracking branch 'upstream/master' 2018-09-07 13:46:20 +03:00
Alex Crichton
5a3cd893e0 Implement AsRef<JsValue> for Closure<T>
This commit adds an implementation of `AsRef<JsValue>` for the `Closure<T>`
type. Previously this was not possible because the `JsValue` didn't actually
exist until the closure was passed to JS, but the implementation has been
changed to ... something a bit more unconventional. The end result, however, is
that `Closure<T>` now always contains a `JsValue`.

The end result of this work is intended to be a precursor to binding callbacks
in `web-sys` as `JsValue` everywhere but still allowing usage with `Closure<T>`.
2018-09-06 14:46:59 -07:00
Anton Danilkin
1c0a34ff8e Add support for variadic arguments in WebIDL 2018-09-06 20:02:12 +03:00
Richard Dodd
5c7e638b8c Handle variadic no args more gracefully. 2018-09-03 09:50:26 +01:00
Richard Dodd
385e805509 Work on review comments 2018-08-21 12:55:09 +01:00
Richard Dodd
7c83c73919 Comment typo 2018-08-19 13:41:23 +01:00
Richard Dodd
a4835304eb Add codegen to make test work. 2018-08-19 13:39:16 +01:00
Anton Danilkin
afaf94a428 Add support for optional chars 2018-08-03 15:59:27 -05:00
Anton Danilkin
4a0c69ffed Add support for optional bools 2018-08-03 15:59:27 -05:00
Anton Danilkin
0ef528165f Rename functions, remove escaped newlines 2018-08-03 15:59:27 -05:00
Anton Danilkin
c49c18826d Add support for optional numbers 2018-08-03 15:59:27 -05:00
Alex Crichton
88db12669f Add support for Option<&T> in imported argument lists
Closes #619
2018-08-02 22:40:42 -07:00
Alex Crichton
eee71de0ce
Support asynchronous tests (#600)
* Tweak the implementation of heap closures

This commit updates the implementation of the `Closure` type to internally store
an `Rc` and be suitable for dropping a `Closure` during the execution of the
closure. This is currently needed for promises but may be generally useful as
well!

* Support asynchronous tests

This commit adds support for executing tests asynchronously. This is modeled
by tests returning a `Future` instead of simply executing inline, and is
signified with `#[wasm_bindgen_test(async)]`.

Support for this is added through a new `wasm-bindgen-futures` crate which is a
binding between the `futures` crate and JS `Promise` objects.

Lots more details can be found in the details of the commit, but one of the end
results is that the `web-sys` tests are now entirely contained in the same test
suite and don't need `npm install` to be run to execute them!

* Review tweaks

* Add some bindings for `Function.call` to `js_sys`

Name them `call0`, `call1`, `call2`, ... for the number of arguments being
passed.

* Use oneshots channels with `JsFuture`

It did indeed clean up the implementation!
2018-08-01 15:52:24 -05:00
Alex Crichton
cbeb301371
Add support for optional slice types (#507)
* Shard the `convert.rs` module into sub-modules

Hopefully this'll make the organization a little nicer over time!

* Start adding support for optional types

This commit starts adding support for optional types to wasm-bindgen as
arguments/return values to functions. The strategy here is to add two new
traits, `OptionIntoWasmAbi` and `OptionFromWasmAbi`. These two traits are used
as a blanket impl to implement `IntoWasmAbi` and `FromWasmAbi` for `Option<T>`.

Some consequences of this design:

* It should be possible to ensure `Option<SomeForeignType>` implements to/from
  wasm traits. This is because the option-based traits can be implemented for
  foreign types.
* A specialized implementation is possible for all types, so there's no need for
  `Option<T>` to introduce unnecessary overhead.
* Two new traits is a bit unforutnate but I can't currently think of an
  alternative design that works for the above two constraints, although it
  doesn't mean one doesn't exist!
* The error messages for "can't use this type here" is actually halfway decent
  because it says these new traits need to be implemented, which provides a good
  place to document and talk about what's going on here!
* Nested references like `Option<&T>` can't implement `FromWasmAbi`. This means
  that you can't define a function in Rust which takes `Option<&str>`. It may be
  possible to do this one day but it'll likely require more trait trickery than
  I'm capable of right now.

* Add support for optional slices

This commit adds support for optional slice types, things like strings and
arrays. The null representation of these has a pointer value of 0, which should
never happen in normal Rust. Otherwise the various plumbing is done throughout
the tooling to enable these types in all locations.

* Fix `takeObject` on global sentinels

These don't have a reference count as they're always expected to work, so avoid
actually dropping a reference on them.

* Remove some no longer needed bindings

* Add support for optional anyref types

This commit adds support for optional imported class types. Each type imported
with `#[wasm_bindgen]` automatically implements the relevant traits and now
supports `Option<Foo>` in various argument/return positions.

* Fix building without the `std` feature

* Actually fix the build...

* Add support for optional types to WebIDL

Closes #502
2018-07-19 14:44:23 -05:00