The edge over asm.js is a subset of this. Obviously, asm.js neither has JIT reoptimisation overhead, nor garbage collection to worry about.
However, a weird, highly-annotated strict subset of JS is not the ideal representation of what is basically portable assembly language. WebAssembly's big strength over asm.js is it has smaller executables and they can be rapidly decoded and verified in binary IR form, rather than having to shove megabytes of ungzipped bracket-fest through a JS parser.
> WebAssembly's big strength over asm.js is it has smaller executables
It's not about the "smallness" as measured in the number of bytes, the minimized (that is, short variable names, no comments and whitespaces) asm.js code with the "bracket-fest" can actually be quite compact.
It is about the form which does save some lexing, parsing, searching and allocation steps in the run-time. Which matters when the code is measured in megabytes and the goal is to run it as soon as possible and save as much battery as possible on the mobile devices. From the FAQ:
"The kind of binary format being considered for WebAssembly can be natively decoded much faster than JavaScript can be parsed (experiments show more than 20× faster). On mobile, large compiled codes can easily take 20–40 seconds just to parse, so native decoding" "is critical to providing a good cold-load user experience."
A big part of the advantage is more consistent adoption by browsers. All the major browsers have experimental WebAssembly support already, and Firefox and Chrome are already shipping it (although it's off by default). Firefox/SpiderMonkey and Edge/Chakra have AOT compilation for asm.js, but notably Chrome/V8 doesn't (although they did optimize its performance significantly). Asm.js also still hasn't become a formal spec, while WebAssembly is already very close.
> A big part of the advantage is more consistent adoption by browsers. […] Firefox/SpiderMonkey and Edge/Chakra have AOT compilation for asm.js, but notably Chrome/V8 doesn't
Not quite. SpiderMonkey has AOT compilation, whereas Chakra and V8 throw it at the JIT, though Chakra's compiler is specially optimised for asm.js AIUI.
Thing is, specific support for asm.js is unnecessary, a sufficiently good JIT is good enough. V8 hasn't implemented asm.js AOT because it doesn't need to. I assume the same would be true of WebAssembly.
V8 hasn't implemented asm.js AOT because the authors claim not to need to; but if you compare the performance of a Unity3D WebGL export vs FireFox the gap is very wide.
> Obviously, asm.js neither has JIT reoptimisation overhead
Why does it never need to re-optimise the JITed code? I know WebAssembly and asm.js are more static than JS, but even very static languages like C benefit from speculative optimisations which may need to be reversed. For example asm.js and WebAssembly have branches don't they? Does the JIT always compile both branches even if one has never been taken in practice?
And what is the reoptimisation overhead anyway? If deoptimisation is caused by a bad speculation on the same thread, it's zero overhead on the fast path until it's used isn't it?
> For example asm.js and WebAssembly have branches don't they? Does the JIT always compile both branches even if one has never been taken in practice?
WebAssembly is treated just like other "real binaries" produced for the "real" OS. Whatever survived the static optimizations while producing the binaries is converted, at the end, to the pure machine code, you don't "trace" it in run-time by the user.
> even very static languages like C benefit from speculative optimisations which may need to be reversed.
I'm not aware of "speculative optimisations which may need to be reversed" in C, and I'd be very interested to read what you mean when you write that, possibly with some links and references. Do you mean run-time, by the user, or something else?
I think that is left open to the implementation. _If_ an implementer thinks there is a benefit in doing so, he's free to do so.
In fact, that's similar to how a CPU runs "real binaries". Modern CPUs use _some_ runtime information to make code run faster. Examples include branch predictors and the recognition of stride lengths to move data into the cache before the instructions being executed need it.
That's only small bits, but it _is_ runtime information. I do not rule out that WebAssembly developers, similarly, will find hat there are ways to use runtime information that speed up WebAssembly code.
I think you confuse the tracing during the interpretation of JavaScript with asm.js&WebAsm. Namely asm.js&WebAsm are designed to avoid as much as possible anything deciding in the run-time, except for verifying and generating the machine code, exactly because these "let's see what the code is doing in the run-time" were already implemented and were used for "plain" JavaScript, but had too much overhead, compared to what asm.js&WebAsm does (or avoids to do), for the kind of uses where asm.js&WebAsm are desired.
For the "plain" JavaScript, there are the run-time decisions.
> Modern CPUs use _some_ runtime information to make code run faster. Examples include branch predictors and the recognition of stride lengths to move data into the cache before the instructions being executed need it.
Sure. But that run-time information is internal to the CPU. And the CPU will use it for the native binary code that is the final result of asm.js or WebAsm, just like any other. But that native binary code is "static," it's explicitly not "small traced chunks" the way "plain" JavaScript is handled.
> I do not rule out that WebAssembly developers, similarly, will find hat there are ways to use runtime information that speed up WebAssembly code.
Think about that: it they would find something like that, exactly the same technique could be used to speed any native code, including Linux kernel and anything native you imagine.
If you manage to develop software method that actually improves the execution speed of the native code in run-time, you'd be famous and (if you know how to market it) rich.
> I do not rule out that WebAssembly developers, similarly, will find hat there are ways to use runtime information that speed up WebAssembly code.
Think about that: it they would find something like that, exactly the same technique could be used to speed any native code, including Linux kernel and anything native you imagine.
That's exactly what profile-guided optimization does. It's not a new invention, it's working technology. And it's far from inconceivable that PGO could be applied to the intermediate code that web assembly effectively is.
Specific example: a common tradeoff made in compilation is between space and speed, and there are some cases - like padding to align a jump target - that can win big speed improvements in inner loops, but are pessimal when used liberally (because code size inflates and doesn't fit in cache). Realigning jump targets is something that can be done to compiled code, in particular compiled code before it has been linked, when all the relocations and fixups are still available. Having information about hot code can make a big difference here.
(BTW: optimizing linkers are surprisingly involved here, particularly for targets that have a bunch of addressing modes, like x86. Some ways of writing in fixups can result in smaller code (e.g. 1 byte offsets rather than 2 byte offsets), but this effect cascades: making code smaller can make what used to be a 2 byte offset possible to fit in 1 byte. Don't underestimate the amount of optimization that your linker does with native code (if you have a smart linker; my experience is from the Delphi compiler source).)
> it's far from inconceivable that PGO could be applied to the intermediate code that web assembly effectively is.
A developer could do some kind of PGO before he produces the final binary, I can imagine that. But then it's still just a static binary.
And I personally can't imagine PGO being done in the user's browser and not being slower than the alternative of not doing it, just like I've never heard of some OS which does PGO on the native binaries when user runs them. Maybe you know of something like that? The PGO I know is always a slow process, done only before shipping the binary to the user, it's a kind of "post-processing" step of compiling, not of the normal execution at the user's computer.
The target model of the asm.js (and therefore WebAsm) intentionally doesn't assume the "VM" features that Java VM has. It's much, much lower level. No classes. Even no strings.
Java VM receives the classes, methods, strings, has GC and all that, but it has to JIT to reach that lower level to be efficient and has to do a kind of establishing what's actually used, similarly to what tracing JIT engines for classic JavaScript do.
I believe that kind of run-time measurements and then code generation and optimization is what some Java people call PGO, and what asm.js at the moment intentionally (by design) avoids.
In short, Java's PGO on the user side is not what PGO for static languages like C is (by the developer). And asm.js is even lower than C. It's really closer to... asm.
Exactly because asm.js avoided these decisions was Firefox with asm.js support faster than Chrome at the time the later treated all js code the same.
>Why does it never need to re-optimise the JITed code? I know WebAssembly and asm.js are more static than JS, but even very static languages like C benefit from speculative optimisations which may need to be reversed.
However, a weird, highly-annotated strict subset of JS is not the ideal representation of what is basically portable assembly language. WebAssembly's big strength over asm.js is it has smaller executables and they can be rapidly decoded and verified in binary IR form, rather than having to shove megabytes of ungzipped bracket-fest through a JS parser.