Skip to content

Commit ebc1e92

Browse files
authored
Add a --reference-types CLI flag (#2257)
This proposal is now shipping in browsers!
1 parent b72678a commit ebc1e92

File tree

5 files changed

+78
-0
lines changed

5 files changed

+78
-0
lines changed

crates/cli-support/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ impl Bindgen {
133133
self
134134
}
135135

136+
pub fn reference_types(&mut self, enable: bool) -> &mut Bindgen {
137+
self.externref = enable;
138+
self
139+
}
140+
136141
/// Explicitly specify the already parsed input module.
137142
pub fn input_module(&mut self, name: &str, module: Module) -> &mut Bindgen {
138143
let name = name.to_string();

crates/cli/src/bin/wasm-bindgen.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Options:
4040
--web Deprecated, use `--target web`
4141
--no-modules Deprecated, use `--target no-modules`
4242
--weak-refs Enable usage of the JS weak references proposal
43+
--reference-types Enable usage of WebAssembly reference types
4344
-V --version Print the version number of wasm-bindgen
4445
";
4546

@@ -61,6 +62,7 @@ struct Args {
6162
flag_remove_name_section: bool,
6263
flag_remove_producers_section: bool,
6364
flag_weak_refs: Option<bool>,
65+
flag_reference_types: Option<bool>,
6466
flag_keep_debug: bool,
6567
flag_encode_into: Option<String>,
6668
flag_target: Option<String>,
@@ -119,6 +121,9 @@ fn rmain(args: &Args) -> Result<(), Error> {
119121
if let Some(true) = args.flag_weak_refs {
120122
b.weak_refs(true);
121123
}
124+
if let Some(true) = args.flag_reference_types {
125+
b.reference_types(true);
126+
}
122127
if let Some(ref name) = args.flag_no_modules_global {
123128
b.no_modules_global(name)?;
124129
}

guide/src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
- [Supported Rust Targets](./reference/rust-targets.md)
4343
- [Supported Browsers](./reference/browser-support.md)
4444
- [Support for Weak References](./reference/weak-references.md)
45+
- [Support for Reference Types](./reference/reference-types.md)
4546
- [Supported Types](./reference/types.md)
4647
- [Imported JavaScript Types](./reference/types/imported-js-types.md)
4748
- [Exported Rust Types](./reference/types/exported-rust-types.md)

guide/src/reference/cli.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,11 @@ memory is eventually deallocated regardless of whether you're calling `free` or
110110
not. This is off-by-default while we're waiting for support to percolate into
111111
all major browsers. For more information see the [documentation about weak
112112
references](./weak-references.md).
113+
114+
### `--reference-types`
115+
116+
Enables usage of the [WebAssembly References Types
117+
proposal](https://github.com/webassembly/reference-types) proposal, meaning that
118+
the WebAssembly binary will use `externref` when importing and exporting
119+
functions that work with `JsValue`. For more information see the [documentation
120+
about reference types](./reference-types.md).
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Support for Reference Types
2+
3+
WebAssembly recently has gained support for a new value type called `externref`.
4+
Proposed in the [WebAssembly reference types
5+
repo](https://github.com/webassembly/reference-types) this feature of
6+
WebAssembly is hoped to enable more efficient communication between the host
7+
(JS) and the wasm module. This feature removes the need for much of the JS glue
8+
generated by `wasm-bindgen` because it can natively call APIs with JS values.
9+
10+
For example, this Rust function:
11+
12+
```rust
13+
#[wasm_bindgen]
14+
pub fn takes_js_value(a: &JsValue) {
15+
// ...
16+
}
17+
```
18+
19+
generates this JS glue *without* reference types support:
20+
21+
```js
22+
const heap = new Array(32).fill(undefined);
23+
24+
heap.push(undefined, null, true, false);
25+
26+
let stack_pointer = 32;
27+
28+
function addBorrowedObject(obj) {
29+
if (stack_pointer == 1) throw new Error('out of js stack');
30+
heap[--stack_pointer] = obj;
31+
return stack_pointer;
32+
}
33+
34+
export function takes_js_value(a) {
35+
try {
36+
wasm.takes_js_value(addBorrowedObject(a));
37+
} finally {
38+
heap[stack_pointer++] = undefined;
39+
}
40+
}
41+
```
42+
43+
We can see here how under the hood the JS is managing a table of JS values which
44+
are passed to the wasm binary, so wasm actually only works in indices. If we
45+
pass the `--reference-types` flag to the CLI, however, the generated JS looks like:
46+
47+
```js
48+
export function takes_js_value(a) {
49+
wasm.takes_js_value(a);
50+
}
51+
```
52+
53+
And that's it! The WebAssembly binary takes the JS value directly and manages it
54+
internally.
55+
56+
Currently this feature is supported in Firefox 79+ and Chrome. Support in other
57+
browsers is likely coming soon! In Node.js this feature is behind the
58+
`--experimental-wasm-anyref` flag, although the support does not currently align
59+
with the upstream specification as of 14.6.0.

0 commit comments

Comments
 (0)