-
Notifications
You must be signed in to change notification settings - Fork 783
Future of wasm2js #1929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
+cc @juj |
Some previous relevant discussion: emscripten-core/emscripten#8085 |
ccing wasm2js/wasm2asm authors for more visibility: @yurydelendik @alexcrichton @dcodeIO @froydnj @tlively |
Does this imply that a compiler that doesn't use LLVM/Emscripten won't be able to output a JS version (we don't care about valid asm.js, just something JS) with just Binaryen / |
I strongly support this direction for wasm2js. Replacing Fastcomp was exactly my goal when I worked on this as an intern in summer 2017, with the motivation of simplifying Rust's dependency on Emscripten. |
@dcodeIO, if I understand correctly, that will still work but the JS you get may be different that what it is today. In fact the JS will be better because wasm2js will be feature-complete enough to support all emscripten tests. |
Yeah, we definitely don't want to remove use cases people care about - @dcodeIO, thanks for mentioning that you use this code path. How much do you care about the external API of the JS code emitted? I might want to change it in minor ways. (Aside from that, my plan is to just improve the quality of the JS emitted.) |
Not really bound to the external API, as long as it can either be run directly or easily postprocessed. A WebAssembly-ish API, similar to how Wasm works in browsers, would be great though :) |
Yeah, a wasm-ish API - almost like a polyfill - is what I was thinking too, heh. |
This all sounds like a great idea to me! FWIW the idea that we might implement wasm2js in Rust was primarily motivated that its maintainership here seemed to be waning. If it picks up though we're happy to help. I'd personally agree that asm.js isn't too important at this point for the reasons mentioned, and the only desire we'd have is that wasm2js emits an ES module (as it does today) for inclusion into apps. Eventually we'd like to include this at least as a default option (if not on by default) in pipelines like Webpack. |
Thanks @alexcrichton, good to know! Yeah, I intend to make this a major focus for myself personally, and it will definitely be a high priority once emscripten depends on it as a fastcomp replacement. I'll have to investigate the JS output format issue - for emscripten and AssemblyScript it seems like a "wasm polyfill" approach is better, and for you an ES6 module is. Probably we can implement one in terms of the other or something like that. |
I have a couple concerns about the "wasm polyfill" approach:
These can probably be resolved by allowing the polyfill to use a custom namespace, and maybe also emitting it as a separate file which can be loaded once. Note also for my case, JS output mostly targets IE 11 and old versions of Safari and Edge, so I need to avoid ES6 modules. |
@kripken that sounds great! And yeah definitely agreed that the output format isn't too too important in that we can translate one way or the other as necessary. I think the polyfill approach is probably more flexible because it's how wasm is always used at the fundamental level today! |
Thanks @Brion, very good points. Yeah, the "polyfill" approach does want to affect the global scope. So it seems like building the polyfill as an extra optional layer on top of the other approach is the better way to do. |
I'm starting on this work now. Anyone interested to review the patches? |
Looks like the current output is close to an ES6 module ( |
According to these docs ES6 modules are still experimental in node, so I guess de-ES6-ing is reasonable. |
@alexcrichton it looks like you added the ES6 module output stuff for wasm2js - do you remember why? I'd like to replace it for the reasons 2 comments back. |
Are people using the C API call |
Yes, that's behind |
Thanks @dcodeIO - I'll keep it working then, shouldn't be a problem. |
I'm totally fine with renaming it or otherwise changing the API ofc, as long as it's still there :) |
IIRC the ES6 output was added to align with the esm-integration proposal which defines how to view a wasm module as an ES module. I also figured it's really the only common unit of compatibility in the JS ecosystem, where if ES6 isn't used it's some invented module format which ES6 can compile down to. Basically it was an attempt at being forward compatible with tooling, while also acknowledging that the output only really works in bundlers today and would require some form of external tooling to process it to be compatible with Node.js |
I see, thanks @alexcrichton. Ok, if this is needed for bundlers then I guess we should keep it around. I'll add an option to emit another variant of the glue (will be easier to do that after my current refactoring). |
Early work for #1929 * Leave core wasm module - the "asm.js function" - to Wasm2JSBuilder, and add Wasm2JSGlue which emits the code before and after that. Currently that's some ES6 code, but we may want to change that later. * Add add AssertionEmitter class for the sole purpose of emitting modules + assertions for testing. This avoids some hacks from before like starting from index 1 (assuming the module at first position was already parsed and printed) and printing of the f32Equal etc. functions not at the very top (which was due to technical limitations before). Logic-wise, there should be no visible change, except some whitespace and reodering, and that I made the exceptions print out the source of the assertion that failed from the wast: -if (!check2()) fail2(); +if (!check2()) throw 'assertion failed: ( assert_return ( call add ( i32.const 1 ) ( i32.const 1 ) ) ( i32.const 2 ) )'; (fail2 etc. did not exist, and seems to just have given a unique number for each assertion?)
Ok, I'm practically done with correctness here - wasm2js passes the emscripten test suite at all opt levels, and the fuzzer didn't find anything overnight. Looking at optimizations now. |
Ok, I'm basically done with wasm2js. It passes almost all tests (see exceptions below), and looks good on code size and perf - it's actually nicely smaller than emscripten's asm.js output in many cases! Unhandled issues, that may be done as followups if there is need:
|
It looks like wasm2js now generates 114 MiB instead of 155 MiB of JS for my 2 MiB wasm file. If I run uglifyjs on it, it gets minified down to 12 MiB. That's still kind of unfortunate compared to the 4 MiB JS file that got emitted by emscripten. It's quite an improvement over earlier versions of wasm2js / wasm2asm though. However I was also not able to run uglifyjs with either I think most of the remaining unoptimized JS code is the fact that pretty long variable names are used. Maybe there is an option in wasm2js that I missed? |
@CryZe wasm2js does accept optimization flags like other tools, so it's important to run it with something like Aside from that, it's still good to run a normal JS minifer on it, emscripten uses its own, and optionally closure: https://github.com/emscripten-core/emscripten/blob/incoming/tools/shared.py#L2644 (Both of those minifers can scale up to massively large amounts of JS.) Are you just running wasm2js directly yourself, and not using it from emscripten? Maybe we should improve the docs for that? |
* disable the big switch and debug info tests there, see WebAssembly/binaryen#1929 (comment) * error on wasm2js + source maps. fixes #8743
I think asm.js is still relevant, there are several uses case. |
@hummeleBop it would be good to know more about KaiOS's status and plans, specifically when they intend to upgrade their JS VM. If you know, or you know someone that does, that would be very useful! |
@kripken some feedback about wasm2js in our app, tested in chrome Speed Code size Details Additionally |
Interesting, thanks @ibaryshnikov! Overall the results look good I think. Is anything used to minify the JS after wasm2js? A standard minifier like terser can improve it a lot (wasm2js doesn't focus on simple stuff normal minifiers do anyhow). I think older wasm2js didn't have optimization flags yet, which is why there is |
@kripken without additional tools, just wasm2js. They'll go to webpack and got minified later |
* disable the big switch and debug info tests there, see WebAssembly/binaryen#1929 (comment) * error on wasm2js + source maps. fixes emscripten-core#8743
I'd like to do some work on wasm2js. Specifically, the use case I have in mind is to integrate it with Emscripten + the LLVM wasm backend. Then we can use that, instead of the current fastcomp asm.js backend, as a solution for emitting non-wasm output. This would have several advantages:
This doesn't need to emit valid asm.js since in practice almost all browsers with asm.js AOT also have wasm anyhow (in fact chrome shipped wasm before asm.js AOT; and firefox did have some releases with just asm.js, but even LTS has had wasm for a while now). So wasm2js is an option here.
Specific work I'd like to do:
This may involve changes to the JS emitted by wasm2js, so I wanted to ask how much current wasm2js users care about the form of the output? I know the Rust people have been using wasm2js, but I heard recently they have plans to write something new (which made me sad to hear, but on the other hand fewer users may mean more flexibility in terms of how we evolve wasm2js). cc @fitzgen
The text was updated successfully, but these errors were encountered: