We already get a huge speed boost on asm.js code, without having to special case it. It's likely that LLVM could do even better on it, but at this time we're not sure that a specific hint that it's asm.js would help.
(1) It requires a pause to compile a bunch of stuff before you even get going. While in our case LLint would have executed it a few times already.
(2) Even for asm.js-style code, dynamic profiling info can help you optimize things more than you could with pure AOT. For example, you can make inlining decisions on the fly, based on what functions are actually called.
(3) Caching compiled code is a good idea for more than just asm.js, no need to make it a special case.
Congratulations on the landing. I've been looking forward to this. Great to see LLVM getting improved to be a better JIT target, too.
On point 3, above.. I've slowly come to the opinion that caching optimized jitcode code is a bad idea in the general case.
Optimized jitcode attaches many constraints across various heap objects (e.g. hidden types), and those constraints would need to be serialized in a way that they can be loaded in a foreign runtime, matched up back to objects in the foreign heap (if those objects even exist). It's pretty complex to build a design that allows you to answer the questions:
1. what piece of JS code in my heap does this cached jitcode correspond to?
2. how do I wire the jitcode into this brand new object graph and attach all the corresponding constraints correctly?
And once you do build that design, the wins would be meager in general. The high-optimization-tier already only runs on very-very-hot code, so it's invoked on only a small fraction of the functions on the heap. Reading the jitcode from disk is slow, and you wouldn't just be reading the code, but the serialized metadata describing how to map that jitcode to the correct set of objects and hidden types that constraints need to be attached to. It's not even clear that the savings on compilation would exceed the costs of reading all this information from disk. Unless you are pulling in, in one go, a large amount of compiled jitcode that you know will be executed.. disk caching has drawbacks that are hard to justify.
The reason asm.js code is a good candidate for targeted caching is because it avoids all of this business. You bake in no heap pointers, and you have no invalidation constraints hanging off of arbitrary heap objects pointing back at your jitcode. Asm is structured so that answering those two questions above is very easy, and it also allows you to cache large amounts of jitcode (a full module) that can then be loaded in one go and be guaranteed to be valid and executable.
Anyway, just food for thought. That said, awesome work and congrats again :)
> (1) It requires a pause to compile a bunch of stuff before you even get going. While in our case LLint would have executed it a few times already.
I think for games you actually want the pause ahead of time, during the loading screen. Having the first few seconds stutter isn't a good experience.
> (2) Even for asm.js-style code, dynamic profiling info can help you optimize things more than you could with pure AOT. For example, you can make inlining decisions on the fly, based on what functions are actually called.
Well, for asm.js code the static inlining is already done by LLVM/Emscripten before the code is even shipped, so I'm not sure how much of a benefit this actually brings in practice—you can only choose to inline functions more aggressively than LLVM already did, not less aggressively. (Might help work around Emscripten's outlining pass, however.) You also eat CPU cycles that could be used for the app by doing non-AOT compilation (though, granted, Emscripten apps of today tend to use only one core, so background compilation will fix this on multicore).
> (3) Caching compiled code is a good idea for more than just asm.js, no need to make it a special case.
No argument there, although it's harder to handle the full generality of JavaScript due to the temptation to bake pointers into the jitcode. If you can make it work though, hey, that's awesome.
The hypothesis of JSC folks is that it will be able to get very good results without any special case handling for code labeled as asm.js just by having a great general compiler, particularly with more tuning. On the things we profiled, there wasn't a case where AOT or even triggering the fourth tier earlier seemed like the most valuable thing to do.
If we turn out to be wrong, though, we will not be religious about it or anything.