This issue lays out a possible plan for our wasm2asm tool, based on previous discussions. The big picture:
wasm2js input.wasm > output.js and the JS contains a JS object that looks just like that wasm module.The plan to stability:
Once all those are done, we should be in pretty good shape!
Thoughts?
Sounds great to me! Thanks for writing this up.
Only missing bit I can see, which is maybe an optional nice-to-have, would be differential fuzzing between another wasm implementation and the output of wasm2js.
Ah I should have been more clear, that's what the fuzzing at the end is meant to be: the binaryen fuzzer emits random programs and we'd run them in multiple VMs + through wasm2js, checking for any difference in the output.
Ah, ok! I think it is also valuable just to run random wasm programs through wasm2js as well, without the differential step :)
Oh, yes, definitely :)
+1, sounds like a good plan.
Another reason for "wasm2js" is that I'll bet all the engines that had good asmjs optimizations now also support wasm, so I guess the real target for this is older browsers that don't have good asmjs or wasm support.
Sounds like a great plan to me as well! In wasm-bindgen I've got a was2es6js tool which currently supports a --wasm2asm flag which uses wasm2asm under the hood to replace a wasm file with an ES6 module. Some things I've learned from that which we'll want to do here:
data segments of a wasm module. Currently I've just got it storing base64 strings and then decoding them on the fly to initialize the main memory chunk.--no-modules flag which is intended for directly loading in a browser (no packaging) and otherwise just disallows importing anything. I'm not sure the exact same would work for wasm2js but it may be worth thinking about the import story for wasm2js, e.g. how are we emitting JS with those imports? (maybe like a --amd flag? --commonjs?)wasm2asm would choke if you have, for example, (import "foo" "bar") as well as (import "baz" "bar") (aka the same name from two different modules). It should be fine to handle this all transparently though by renaming everything to a unique name and then reassembling the mapping from the imported items.FWIW I've found that the spec tests are quickly reaching diminishing returns. Most things are working pretty well and most of the remaining spec tests are exercising "interesting" aspects of the harness they're expected to be run under (multiple modules, etc). After https://github.com/WebAssembly/binaryen/pull/1558 I think it might be worthwhile to dive straight into the emscripten test suite or fuzzing without trying to get too many more spec tests working, although I could be wrong!
Also FWIW with #1558 applied as well as https://github.com/WebAssembly/binaryen/issues/1562 implemented I believe wasm-bindgen's entire test suite is passing running through wasm2asm instead of through WebAssembly in node. Additionally I've now taken https://github.com/Hywan/gutenberg-parser-rs as-is and run it through wasm2asm and it works like a charm, so wasm2asm is definitely approaching "pretty ready"!
Agreed that the order doesn't need to be what was listed above. Once we have enough to run the fuzzer, no reason not to do that immediately, etc.
Regarding emitting a module or not, one thought I had was not to emit a wasm or ES6 module for just the wasm, but rather emit a complete polyfill for wasm itself. That is, define the WebAssembly object and polyfills of its compilation methods etc. This seems the easiest for integrating into code that loads and uses a module (like for emscripten output), but maybe not for other use cases?
Hm perhaps yeah! Although I guess it'd be like a oneshot thing where it'd always just "compile" the same module?
I've found that the ES module boundary is at least a pretty easy one to polyfill at, but it definitely means that if you're using wasm2js then you'd have to have some sort of other bundler in play. Most of the time for production use cases that's already the case though?
Most things are working pretty well and most of the remaining spec tests are exercising "interesting" aspects of the harness they're expected to be run under (multiple modules, etc)
None of the spec tests should be testing behavior of the harness, but some of them do require multiple modules to test proper linking behavior, validation, etc.
@binji ah sorry yeah that's what I mean. In the sense that those things aren't too interesting in terms of the feature set of wasm2asm specifically :)
I guess it depends on how you're planning to use wasm2asm/wasm2js. If it's traditional emscripten-style where you're converting a monolithic app to JS, then yeah, probably doesn't matter. But in the future I imagine we'll see a lot more wasm module components, so the proper linking behavior will be important.
@binji Agreed. So maybe wasm2js could compile into something that looks like a wasm Module, and we'd also have a separate JS file which is a polyfill for the WebAssembly object + APIs, and it would know how to use those objects, and eventually also how to use normal wasm objects and even link them.
When I say "module-like" I actually mean more "binary-like", in that it would be an input to a WebAssembly.compile* API.
Additionally I've now taken Hywan/gutenberg-parser-rs as-is and run it through wasm2asm and it works like a charm, so wasm2asm is definitely approaching "pretty ready"!
鉂わ笍
Thinking about optimization in the PRs, it may still be useful to keep an "inner" asm.js module that validates. That would let us run an asm.js optimizer on it. That would mean leaving the other non-asm.js code on the outside. Not sure if it's practical, though.
If we can't do that, then we need to figure out something else for optimization. Closure compiler and others can do a good job on general code shrinking but may not be as good as an asm.js optimizer for what we emit here.
Most helpful comment
Also FWIW with #1558 applied as well as https://github.com/WebAssembly/binaryen/issues/1562 implemented I believe wasm-bindgen's entire test suite is passing running through wasm2asm instead of through
WebAssemblyin node. Additionally I've now taken https://github.com/Hywan/gutenberg-parser-rs as-is and run it throughwasm2asmand it works like a charm, sowasm2asmis definitely approaching "pretty ready"!