Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

wasm-bindgen is writing it's own ABI, but still involves a ton of auto-generated JS stubs running for you in the background. it works great! you would never know it's there, but it has a serious performance hit versus actual host object bridging (what we're working towards) since it has to keep serializing things over MessageChannels. You can read some about the auto-generated shims here, https://rustwasm.github.io/docs/wasm-bindgen/contributing/de... . And you can see that wasm-bindgen doesn't actually send objects into Rust, but instead has shims here: https://rustwasm.github.io/docs/wasm-bindgen/contributing/de...

Component Model is designed to eliminate the need for having this autogenerated rpc system & many of these shims, and let wasm itself actually hold references & invoke/use objects in a genuinely shared fashion.



> but it has a serious performance hit versus actual host object bridging (what we're working towards) since it has to keep serializing things over MessageChannels.

I don't understand what you mean? With the --reference-types flag I mentioned, wasm-bindgen is literally passing the JavaScript objects in and out of the shims with absolutely no serialization or indirection on the JavaScript side: the only indirection is on the module's side, when it stores all the host references in a big table and passes around indices to them.

To give a concrete example, I've attached the entirety of the JavaScript code that wasm-bindgen generates with --reference-types enabled on its WebGL example [0]. You can see how many of the shims do absolutely nothing but call the underlying function, even when they take arbitrary JS objects as arguments:

    imports.wbg.__wbg_attachShader_06c432ad16c8823a = function(arg0, arg1, arg2) {
        arg0.attachShader(arg1, arg2);
    };
    imports.wbg.__wbg_bindBuffer_c0ef32bca575b1bf = function(arg0, arg1, arg2) {
        arg0.bindBuffer(arg1 >>> 0, arg2);
    };
    imports.wbg.__wbg_clear_7f98b4d14a417e94 = function(arg0, arg1) {
        arg0.clear(arg1 >>> 0);
    };
    imports.wbg.__wbg_clearColor_d0e4ba6b3de36fbc = function(arg0, arg1, arg2, arg3, arg4) {
        arg0.clearColor(arg1, arg2, arg3, arg4);
    };
    imports.wbg.__wbg_compileShader_81181e6a219b7098 = function(arg0, arg1) {
        arg0.compileShader(arg1);
    };
So as you can see, we already have direct bridging, as long as the JS objects can be treated as opaque. In fact, the code works just as well if we ditch the anonymous functions entirely, and import the native methods directly into the WASM module (though wasm-bindgen currently doesn't do this on its own, and I have no idea how this affects performance):

    imports.wbg.__wbg_attachShader_06c432ad16c8823a =
        Function.prototype.call.bind(WebGL2RenderingContext.prototype.attachShader),
    imports.wbg.__wbg_bindBuffer_c0ef32bca575b1bf =
        Function.prototype.call.bind(WebGL2RenderingContext.prototype.bindBuffer),
    imports.wbg.__wbg_clear_7f98b4d14a417e94 =
        Function.prototype.call.bind(WebGL2RenderingContext.prototype.clear),
    imports.wbg.__wbg_clearColor_d0e4ba6b3de36fbc =
        Function.prototype.call.bind(WebGL2RenderingContext.prototype.clearColor),
    imports.wbg.__wbg_compileShader_81181e6a219b7098 =
        Function.prototype.call.bind(WebGL2RenderingContext.prototype.compileShader),
Serialization and deserialization are really only needed if we have record types filled with raw data like numbers and strings that we want to ergonomically manipulate on the JavaScript side. If we just need to track opaque handle objects, as with WebGL or WebGPU, then WASM's feature of host references is already sufficient to avoid serialization overhead.

[0] https://gist.github.com/LegionMammal978/9c4ac4de47b3b365a50a...




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: