Hey! Could someone help me understand why the wevaled
StarlingMonkey WASM size is almost the same as the full interpreter without partial evaluation? My reasoning is that after partial evaluation for the given "simple" JS bytecode, only a small portion of the interpreter code should be used. Therefore, wasm-opt
should be able to eliminate unreachable parts and significantly reduce the binary size. However, this doesn't seem to be happening.
hi @Tomasz Andrzejak -- great question, and good insight, yes, in compiled code ideally we should be able to remove all of the JS engine's parsing frontend and interpreter.
The simple answer why we can't in principle today is eval()
. If we ran a subset of the language without that (and any other APIs for dynamic code loading), then we could in theory DCE those bits of the engine away; it would still take a little care to properly mark pieces as unreachable, because of the way that the wizening works (everything is built into the image, and there are two entry points; the init one is not removed today), but doable in theory.
I suppose we could also know that eval()
is not present after wevaling actually -- we can make a closed-world assumption at that point. Then we could unroot the parser frontend. That would take some work to do the analysis/tracking, and again to cut at the right points to make the code statically unreachable (rather than only as as a consequence of data-driven branching) but, again, doable for someone properly motivated
(oh, and one more detail here to braindump: we do rely on the interpreter still even when all code is present at wizening and compiled AOT -- we need it for async functions (because we don't have a way to lower the mid-function restarts to wasm) and for exception catches (again for restarts))
Maybe it could be a hint / configuration via something akin to CSP unsafe-eval settings so even if eval is present it is expected to fail with an exception.
yeah, I like that option as well
Hey @Chris Fallin That's very interesting! What do you imagine is the way forward to reduce the size of the binary? I mean, in an environment where we want to treat the wasm instances as disposable small units, a size of 11MB could be an issue?
what is the way forward
I think my answer above stands as the high level direction. Concretely someone would need to have the time to work on this; I don't at the moment
wasm instances as disposable small units, a size of 11MB could be an issue?
I actually don't think so necessarily; it depends on what is dynamic. If the module itself is loaded once and used many times ("disposable" per request, for example), then it's no problem: we mmap the precompiled code section from disk into memory, and it doesn't really matter if a bunch of code exists that is never touched, it won't even be paged in. Now, if you're dynamically compiling new modules and loading them, that could be an issue...
That makes sense. Thanks for your insight!
Last updated: Dec 23 2024 at 12:05 UTC