Support for Reference Types

WebAssembly recently has gained support for a new value type called externref. Proposed in the WebAssembly reference types repo 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:


# #![allow(unused_variables)]
#fn main() {
#[wasm_bindgen]
pub fn takes_js_value(a: &JsValue) {
    // ...
}
#}

generates this JS glue without reference types support:

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 compile with -Ctarget-feature=+reference-types (by default since Rust v1.82), however, the generated JS looks like:

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.