This commit adds support for closures with arguments like strings and such. In
other words, closures passed to JS can now have the same suite of arguments as
all functions that can be exported from Rust, as one might expect!
At this time due to the way trait objects work closures still cannot use types
with references like `&str`, but bare values like `String` or `ImportedType`
should work just fine.
Closes#104
This commit overhauls the conversion traits used for types crossing the Rust/JS
boundary. Previously there were a few ad-hoc traits but now there've been
slightly reduced and decoupled.
Conversion from Rust values to JS values is now exclusively done through
`IntoWasmAbi` with no special treatment for references. Conversion from JS to
Rust is a bit trickier as we want to create references in Rust which have
implications in terms of safety. As a result there are now three traits for
this, `FromWasmAbi`, `RefFromWasmAbi`, and `RefMutFromWasmAbi`. These three
traits are implemented for various types and specially dispatched to depending
on the type of argument in the code generator.
The goal of this commit is to lay the groundwork for using these traits in
closures with straightforward-ish definitions.
This commit adds support for passing `&mut FnMut(..)` to JS via imports. These
closures cannot be invoked recursively in JS (they invalidate themselves while
they're being invoked) and otherwise work the same as `&Fn(..)` closures.
Closes#123
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.
* Have the global `wasm_bindgen` variable be a function which runs
initialization rather than exporting an `init` function.
* Save off the wasm object on `wasm_bindgen.wasm` so the memory can be accessed
* Tidy up the code slightly
Node's fs APIs resolve relative paths relative to the current working directory:
https://nodejs.org/api/fs.html#fs_file_paths
This creates a problem if you try to require the wasm-bindgen-generated
JavaScript from a different directory. For example, if you have
build/foo.js
build/foo_bg.js
build/foo_bg.wasm
and another script, script/index.js, that requires build/foo.js. We can instead
use __dirname to get the correct path to the file.
Nowadays the compile times are mitigated with incremental compilation and
otherwise it's much more ergonomic to run only one test if they're all in the
same suite.
As soon as we've removed unneeded exports immediately run a gc pass to ensure
that we don't bind functions in JS that don't actually end up getting needed.
This commit starts wasm-bindgen down the path of supporting closures. We
discussed this at the recent Rust All-Hands but I ended up needing to pretty
significantly scale back the ambitions of what closures are supported. This
commit is just the initial support and provides only a small amount of support
but will hopefully provide a good basis for future implementations.
Specifically this commit adds support for passing `&Fn(...)` to an *imported
function*, but nothing elese. The `&Fn` type can have any lifetime and the JS
object is invalidated as soon as the import returns. The arguments and return
value of `Fn` must currently implement the `WasmAbi` trait, aka they can't
require any conversions like strings/types/etc.
I'd like to soon expand this to `&mut FnMut` as well as `'static` closures that
can be passed around for a long time in JS, but for now I'm putting that off
until later. I'm not currently sure how to implement richer argument types, but
hopefully that can be figured out at some point!
This commit starts wasm-bindgen down a path of removing the special
casing it currently has around vectors, slices, and strings. This has
long been a thorn in wasm-bindgen's side as it doesn't handle other
kinds of vectors and otherwise is very inflexible with future additions.
Additionally it leads to a lot of duplicated-ish code throughout various
portions of codegen.
The fundamental reason for this was that two arguments were required to
be passed back to wasm, and I couldn't figure out a way to shove both
those arguments into a function argument. The new strategy here is that
there is one global stack well known to both JS and Rust which arguments
*may* also be transferred between.
By default all ABI arguments pass as literal function arguments, but if
two or more arguments need to be passed then the extra ones are all
passed through this global stack. The stack is effectively temporary
scratch space when crossing the JS/Rust boundary (both ways). No long
term storage is intended here.
The `simple` test is passing as a result of this commit, using strings
internally. The `Vector` type in the AST has been removed (yay!) and the
bulk of the implementation of slices and vectors now resides in the
`wasm-bindgen` crate itself, defining how to pass all these arguments
around. The JS generator, however, still needs to know about all the
sorts of vectors so it can generate appropriate code for JS.
Future commits will continue cleanup and get the rest of the tests
working.
This commit leverages two new attributes in the Rust compiler,
`#[wasm_custom_section]` and `#[wasm_import_module]`. These two attributes allow
removing a lot of hacks found in wasm-bindgen and also allows removing the
requirement of `wasm-opt` to remove the unused data sections.
This does require two new nightly features but we already required the
`proc_macro` nightly feature and these will hopefully be stabilized before that
feature!
This'll allow binding multiple signatures of a JS function as well as otherwise
changing the name of the JS function you're calling from the Rust function that
you're defining.
Closes#72
This attribute indicates that methods are to be accessed in a structural method
rather than through their class. This should allow direct access to properties
embedded on objects rather than forcing all objects to have a class/prototype.
Along the way remove the namespace in Rust as this ended up causing too many
problems, alas! The `js_namespace` attribute now almost exclusively modifies the
JS bindings, hence the "js" in the name now.
This commit renames the `static` attribute to `namespace` and simultaneously
reduces and expands the scope. The `namespace` attribute can now be applied to
all imports in addition to functions, and it no longer recognizes full typed
paths but rather just a bare identifier. The `namespace` attribute will generate
a Rust namespace to invoke the item through if one doesn't already exist (aka
bindign a type).
Looks like LLD implicitly pads data values with zeros at the end rather than
explicitly listing them, this means that we need to read out the last byte, even
if it's not 4-byte aligned, as it could still represent a wasm-bindgen-generated
32-bit value.
Building on the previous commit to invoke not invoke `npm install` this takes
the commit a step further (to hopefully fix some races) to use Webpack's native
bundled wasm support.
It turns out the circular dependencies between the wasm module and the module
using it wasn't quite working out so a number of imports had to be tweaked, but
otherwise it's a nice transition where we don't have to base64 encode anything
in tests any more!
These tend to have one "pretty obvious" definition in JS anyway, so
let's paper over this deficiency in rustc for now by automatically
resolving any imports for these functions.
Closes#28
This'll match more closely what wasm eventually does natively, which is
importing these functions directly and not allowing changing them over time.
Closes#25
Right now this library only works if the static description is the entire data
node, but with upcoming LLD support everything will be in one data node. This
updates the logic for finding/parsing the program to search through the entire
data node and also know how big a program description is when it finds it.
This commit migrates from `wasm_bindgen!`-the-macro to
`#[wasm_bindgen]`-the-attribute. The actual mechanics of the macro are
relatively simple in just generating some shims here and there, but wrapping
everything in one huge macro invocation can often seem intimidating as it gives
off this feeling of "oh dear anything can happen here!" Using an attribute
should curb expectations much more greatly of "oh there's just some extra stuff
happening behind the scenes".
The usage is otherwise relatively straightforward and close to what it was
before, but check out the DESIGN.md/README.md changes for more info!
Cache the `Uint8Array` and `Uint32Array` views into wasm memory as well as the
instances of `TextEncoder` and `TextDecoder`. Should hopefully help cut down on
gc traffic and otherwise convince the engine to keep these as long-lived
objects.
Push the compiler to do trait resolution to figure out what each type is bound
with in JS, and that way we can accept effectively all types (so long as they
implement a trait).
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.
This commit adds an option to "uglify" the wasm module's imports/exports so
those which are controlled by bindgen are renamed to a shorter (probably one
letter) names. This'll hopefully help cut down on both the wasm size slightly
and also the generated JS as the glue we're talking to wasm over won't require
such large names all the time.
* Use a bundled custom `WasmRefCell` instead of the one in the standard library.
This one primarily doesn't panic via libstd which means that its code
footprint is much smaller.
* Add a `throw` function to `wasm_bindgen`-the-crate which can be used to throw
an exception in JS from Rust. This is useful as a cheap way to throw an
exception code-wise (little code bloat) and it's also a great way of reporting
error messages to JS!
* Cut down on the code size of `__wbindgen_malloc` by aborting on huge requests
earlier.
* Use a custom `assert_not_null` function which delegates to `throw` to test for
incoming null pointers