IonMonkey is the name of Mozilla’s new JavaScript JIT compiler, which aims to enable many new optimizations in the SpiderMonkey JavaScript engine. InfoQ had a small Q&A with Lead Developer David Anderson, about this new development that could bring significant improvements in products that use the SpiderMonkey engine like Firefox, Thunderbird, Adobe Acrobat, MongoDB and more.
This new JIT infrastructure, will feature SSA compiler intermediate representations which will facilitate advanced optimizations such as type specialization, function inlining, linear-scan register allocation, dead-code elimination, and loop-invariant code motion.
Main driving forces for IonMonkey are to:
- Provide a backend that can match or beat the Trace JIT or Crankshaft in speed. Sub-goals:
- Fine-grained specialization and de-specialization.
- Integration with type inference.
- Clean, textbook IR so optimization passes can be separated and pipelined with well-known algorithms.
- Document and comment well so the implementation and its side effects can be easily understood.
- Recompilation, debugging, bailouts are all related - and should be solved up-front.
- First SpiderMonkey JIT that starts off with peer reviews!
- (Unknown feasibility) Act as a baseline compiler to replace JM2.
- Manage memory much better, in part to avoid range problems on x64.
InfoQ had a small Q&A with Lead Developer David Anderson, about IonMonkey:
InfoQ: With so much coverage about JIT compilation for languages like Java, what are the main challenges for designing a JIT compiler for a dynamic language like JavaScript?
David: The biggest problem is that, unlike Java, JavaScript is untyped. For example, adding two variables in Java is easy. You know exactly whether those variables are integers, doubles, et cetera, and a JIT can generate one or two machine instructions to add them.
In JavaScript, you don't have this type information. If you want to add two variables, you have to inspect their types dynamically, then use the correct coercion and addition algorithm. All that checking and potential dispatching is really slow, and not knowing what the result will be really inhibits further optimization.
JavaScript JITs tend to solve this by optimistically starting off with common use cases. For example, the generated code for an addition might initially only check for and operate on integers. If those checks fail, it will swap in code for the new types instead. This is still not as good as Java though, because Java wouldn't have those type checks.
Much of the modern work on JavaScript JITs is figuring out how to get more accurate and complete type information. Eliminating those checks is key for things like good register allocation or eliminating redundant code, stuff you'd find in a compiler for a typed language.
The other side of this challenge is getting that type information extremely quickly. Users would be pretty unhappy if the browser froze for a few seconds because a really heavy analysis was running on their webmail app. Even for benchmarks (which are often short-running) the analysis time tradeoff can be delicate.
Info: Are there any advanced optimizations that benefit from JavaScript's dynamic nature and don't make sense for statically-typed languages?
David: Dynamic languages probably don't have any inherent optimization advantages, but they do have interesting optimizations that static languages don't. For example, when you're writing JavaScript, objects appear to the user as hash tables, mapping property names to values. If they were actually implemented like that, they would be slow and use a lot of memory.
A good engine is able to internally group objects that look the same, sort of extracting an internal Java-like class out of them. The JIT can then treat the object as having an actual type, generating super fast code that avoids an expensive property lookup.
InfoQ: What will be the key differences between IonMonkey and Crankshaft which is used by V8?
David: It helps to note that IonMonkey is a long-term investment for us. Firefox already has two JITs, and with IonMonkey that makes a third. V8 also has three. At this rate we'll have added a new JIT every year.
We want to consolidate, and have IonMonkey be the single platform for all our optimization work and research, giving it a "speed" or "scenario" knob that can be adjusted depending on the situation. This also means, like JaegerMonkey, we're paying special attention to sharing almost all our code across x86, x64, and ARM, and I think we're the only open-source engine to do this.
A more interesting difference is Brian Hackett's Type Inference, a really cool project ongoing at Mozilla. It is a hybrid static and dynamic analysis that is able to pinpoint, for certain, the types for every variable and property in a JavaScript program. This allows you to remove all sorts of run-time checks and perform optimizations that would otherwise be impossible. He's made amazing progress with it over the past year and community members are helping out with it now, too, so it's very promising.
InfoQ: How does IonMonkey compare to the compilation infrastructure of other dynamic languages?
David: LuaJIT and PyPy come to mind - both are pursuing trace compilation, which is a very aggressive specialization strategy also featured in TraceMonkey, our first JIT. The problems to solve are very similar. You have to be able to recover the dynamic program state from highly optimized code, and often deoptimize if you were too aggressive. Both LuaJIT and PyPy have a flexible intermediate representations to work with, and that's the foundation we are building.
IonMonkey is currently in the design stages and the process is fairly open to the public, in typical Mozilla tradition. You can find more information about JavaScript, right here on InfoQ!