Design: Inline wasm in regular js code

Created on 11 May 2018  路  10Comments  路  Source: WebAssembly/design

In C, especially in embedded systems, it's not uncommon to drop down to inline assembly when you need precise control, timing or performance.

I think there's a parallel there with wasm, there are many places where having the ability to drop into inline wasm would be a massive performance boost to overall js execution.

Because of the way wasm and js interop, this might be tough to do exactly the way C does, i.e. in the middle of a code block or something, but is there a way that the syntax could be sugared so that a function could be exported and used, possibly at the module scope using a magic sigil like C does?

Something like:

function foo(arg) { ... }
var importObject = {
  imports: { imported_func: foo }
};

##__wasm__##
(module
  (func $i (import "imports" "imported_func") (param i32))
  (func (export "bar")
    i32.const 42
    call $i))
##__endwasm__##

export default {foo: foo, bar: bar}

My motivation is that I'm currently implementing some high performance algorithms in js and I have small pieces of code that could really benefit from the wasm performance boost, but the overall driving api doesn't need it.

While very cool, the current hoops I'd have to jump through to implement these in wasm are burdensome, if I could just drop down to inline, I'd use wasm all the time.

Most helpful comment

Hi Clay! Another idea is to use a pure library solution based on tagged templates literals, which would also bring along nice interpolation features for free. Reusing wabt's wat2wasm (compiled to wasm, of course ;), this probably wouldn't be too hard to build or too big (once the unneeded wabt tools were stripped). Moreover, a build tool could precompile these tagged template literals, generating the .wasm ahead of time when they don't depend on runtime values.

Building the wat2wasm parser into the browser would be a much bigger thing to standardize and so far the CG has specifically avoided doing that. A library would also give a lot of flexibility for how to manage instantiation and imports, since there's a lot of options to explore.

All 10 comments

See also the JS module integration proposal, which would simplify a lot of interop scenarios: https://github.com/WebAssembly/design/issues/1087

I think you're proposing something where the imports of the module would be taken from local scope in a JS function, though, which would be different from the module-loading-time import resolution of that proposal.

This would mean that you have to instantiate the module at the position where the ##__wasm__##...##__endwasm__## appear in the source, and load/compile it somewhere earlier in the source (potentially synchronously).

Hi Clay! Another idea is to use a pure library solution based on tagged templates literals, which would also bring along nice interpolation features for free. Reusing wabt's wat2wasm (compiled to wasm, of course ;), this probably wouldn't be too hard to build or too big (once the unneeded wabt tools were stripped). Moreover, a build tool could precompile these tagged template literals, generating the .wasm ahead of time when they don't depend on runtime values.

Building the wat2wasm parser into the browser would be a much bigger thing to standardize and so far the CG has specifically avoided doing that. A library would also give a lot of flexibility for how to manage instantiation and imports, since there's a lot of options to explore.

Good point @lukewagner ! I initially started down the "I can do this as a library" path, but gave up when I saw the wat2wasm tool was command line, for some reason it didn't occur to me to compile that down to wasm and use it. Interesting. I might scratch and sniff a bit at that, see if I can some up with something.

@brion yes, I think that's precisely what I was thinking, very similar to the way you can do inline asm with C. I grokked that it would involve adding a wat/wast compiler to the browser, but didn't know the thoughts/status of doing that - @lukewagner has enough fun just getting everyone on board with wasm, I can see how adding a wat/wast compiler to the mix is a big ask.

wat2wasm already has an asm.js version, you can try it out here: https://github.com/WebAssembly/wabt#online-demos

Building the wasm version _should_ be as straightforward as adding -s WASM=1 to the compile flags. :-)

Just wanted to point out that the reference interpreter also provides a parsing/printing library for JS and you can readily grab a build as a self-contained JS file from the repo. See the documentation for usage.

Thanks all! @xtuc I saw that lib, it's pretty close to what I was thinking using template strings. I banged together a quick example that was similar to that, and it still left me itching a bit. I'm starting to think about going down the preprocessor (webpack plugin) route instead. Doing a preprocessor would eliminate the wast.js payload and would work well with the webpack flow. I'm sort of scratching my head about how it would work though.

At first blush, it might do something like look for functions with an \@wasm decorator, extract them all into a single wast, compile that, then rewrite the original file to import the module and have it expose the functions in place.

There are a lot of details and a lot of devils there, but if I get some time while I'm job searching I'll try to knock up a POC, if you guys think it's an interesting direction.

That would be trivial in a Babel plugin, but that would force you to inline the wasm format in the JavaScript file (which might be fine, depends on the use-case). It will also probably require sync instantiation.

I'm working on the WebAssembly integration in Webpack and i'm looking for a good/safe way for plugins/loaders to emit WebAssembly.
Basically you could something like: each time you encounter a template literal, transform it to wasm and emit it in Webpack. Webpack will then do the linking for you.

@xtuc I think that's exactly what I was leaning toward, the ability to drop down into wasm the same way you can do __asm__ in C.

For simplicity, rather than trying to actually do wasm inline, I think it's a reasonable compromise to use a special decorator like @@wasm@@ to tag a function - and yes, you'd just parse this out in webpack, add it all to a generated wasm module, build it, and then inject the exposed function back into the JS file, probably with some sort of little wrapper function so that it could be used anywhere and maintain context.

I'm curious to see where you are with the webpack/wasm loader, I'd like to piggyback off your work, for sure.

I'm hoping to get to this pretty soon, unfortunately most of my time right now is being used up job hunting (grrr).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

thysultan picture thysultan  路  4Comments

nikhedonia picture nikhedonia  路  7Comments

bobOnGitHub picture bobOnGitHub  路  6Comments

konsoletyper picture konsoletyper  路  6Comments

Artur-A picture Artur-A  路  3Comments