Skip to content

Commit

Permalink
Add a --reference-types CLI flag (#2257)
Browse files Browse the repository at this point in the history
This proposal is now shipping in browsers!
  • Loading branch information
alexcrichton committed Jul 28, 2020
1 parent b72678a commit ebc1e92
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 0 deletions.
5 changes: 5 additions & 0 deletions crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ impl Bindgen {
self
}

pub fn reference_types(&mut self, enable: bool) -> &mut Bindgen {
self.externref = enable;
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();
Expand Down
5 changes: 5 additions & 0 deletions crates/cli/src/bin/wasm-bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Options:
--web Deprecated, use `--target web`
--no-modules Deprecated, use `--target no-modules`
--weak-refs Enable usage of the JS weak references proposal
--reference-types Enable usage of WebAssembly reference types
-V --version Print the version number of wasm-bindgen
";

Expand All @@ -61,6 +62,7 @@ struct Args {
flag_remove_name_section: bool,
flag_remove_producers_section: bool,
flag_weak_refs: Option<bool>,
flag_reference_types: Option<bool>,
flag_keep_debug: bool,
flag_encode_into: Option<String>,
flag_target: Option<String>,
Expand Down Expand Up @@ -119,6 +121,9 @@ fn rmain(args: &Args) -> Result<(), Error> {
if let Some(true) = args.flag_weak_refs {
b.weak_refs(true);
}
if let Some(true) = args.flag_reference_types {
b.reference_types(true);
}
if let Some(ref name) = args.flag_no_modules_global {
b.no_modules_global(name)?;
}
Expand Down
1 change: 1 addition & 0 deletions guide/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
- [Supported Rust Targets](./reference/rust-targets.md)
- [Supported Browsers](./reference/browser-support.md)
- [Support for Weak References](./reference/weak-references.md)
- [Support for Reference Types](./reference/reference-types.md)
- [Supported Types](./reference/types.md)
- [Imported JavaScript Types](./reference/types/imported-js-types.md)
- [Exported Rust Types](./reference/types/exported-rust-types.md)
Expand Down
8 changes: 8 additions & 0 deletions guide/src/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,11 @@ memory is eventually deallocated regardless of whether you're calling `free` or
not. This is off-by-default while we're waiting for support to percolate into
all major browsers. For more information see the [documentation about weak
references](./weak-references.md).

### `--reference-types`

Enables usage of the [WebAssembly References Types
proposal](https://github.com/webassembly/reference-types) proposal, meaning that
the WebAssembly binary will use `externref` when importing and exporting
functions that work with `JsValue`. For more information see the [documentation
about reference types](./reference-types.md).
59 changes: 59 additions & 0 deletions guide/src/reference/reference-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Support for Reference Types

WebAssembly recently has gained support for a new value type called `externref`.
Proposed in the [WebAssembly reference types
repo](https://github.com/webassembly/reference-types) this feature of
WebAssembly is hoped to enable more efficient communication between the host
(JS) and the wasm module. This feature removes the need for much of the JS glue
generated by `wasm-bindgen` because it can natively call APIs with JS values.

For example, this Rust function:

```rust
#[wasm_bindgen]
pub fn takes_js_value(a: &JsValue) {
// ...
}
```

generates this JS glue *without* reference types support:

```js
const heap = new Array(32).fill(undefined);

heap.push(undefined, null, true, false);

let stack_pointer = 32;

function addBorrowedObject(obj) {
if (stack_pointer == 1) throw new Error('out of js stack');
heap[--stack_pointer] = obj;
return stack_pointer;
}

export function takes_js_value(a) {
try {
wasm.takes_js_value(addBorrowedObject(a));
} finally {
heap[stack_pointer++] = undefined;
}
}
```

We can see here how under the hood the JS is managing a table of JS values which
are passed to the wasm binary, so wasm actually only works in indices. If we
pass the `--reference-types` flag to the CLI, however, the generated JS looks like:

```js
export function takes_js_value(a) {
wasm.takes_js_value(a);
}
```

And that's it! The WebAssembly binary takes the JS value directly and manages it
internally.

Currently this feature is supported in Firefox 79+ and Chrome. Support in other
browsers is likely coming soon! In Node.js this feature is behind the
`--experimental-wasm-anyref` flag, although the support does not currently align
with the upstream specification as of 14.6.0.

0 comments on commit ebc1e92

Please sign in to comment.