Inside Mozilla's New JavaScript JIT Compiler
An anonymous reader writes "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."
-JaegerMonkey was dreamt up during a night spent consuming JaegerMiester shooters.
-IronMonkey was designed the morning after, behind iron bars in the slammer, following the JaegerMonkey "JaegerMiester" release party.
This part is one major difference "Clean, textbook IR so optimization passes can be separated and pipelined with well-known algorithms."
The current JM is somewhat goes directly from SpiderMonkey bytecode to assembly, which means any optimizations that happen in the process are ad-hoc (and typically don't happen at all; even basic things like CSE aren't done in JM right now).
I'd be interested to hear why the Mozilla developers don't use an existing compiler framework like LLVM, which already implements many advanced optimization techniques. I am aware that JavaScript-specific problems need to be dealt with anyway, but it seems like they could save themselves a lot of hassle in things like register allocation etc. Those are not so interesting problems that are handled by existing tools like LLVM quite well, so why not use that?
It's a good question, but version numbers would really imply the wrong thing here. SpiderMonkey is the "root" Javascript implementation. TraceMonkey adds trace trees to SpiderMonkey (which apparently means it JIT compiles a type-specialised version of a function if it detects a specific version of a function to be "hot" -- executes very often). Jaeger Monkey uses a more traditional "JIT compile everything" perspective, but then apparently also has the tracing feature in the backend to further optimise hot paths. From skimming TFA, IonMonkey adds to this a first pass that translates all the code into an intermediate representation that makes further optimisations easier. So in reality, all the FooMonkeys seem, to me, to be closer to large-scale plugins into SpiderMonkey than new engine versions per se.
OK. Let's look at http://code.jquery.com/jquery-1.5.2.js very quick. This isn't even a minified version; just the original source. Pretend like you don't know what jquery is doing. The first few functions with arguments here:
> function( selector, context )
What are the types of those?
> function( selector, context, rootjQuery )
And those?
> function( num )
And that one? Hint: the function expects it to be "null" or at least "undefined" sometimes.
> function( elems, name, selector )
And that? Note that the function itself is not sure what to expect in |elems| and has different codepaths depending on what it finds there.
The point is, going from name to type is not really that easy.
Worse yet, "type" in this context also means what JS engines variously call "shape" or "hidden type": two instances of Object are considered the same type if they have the same properties in the same order. Telling _that_ from a variable name is pretty hard.
Didn't Mozilla cry bloody murder when IE9 was discovered to perform dead-code elimination claiming it was "cheating" because it made some outdated JS benchmarks finish in 0 time?
Yup. Python is translated to javascript in pyjamas. http://pyjs.org
The big gains from JS interpreters to most of the current crop of JS JIT compilers (excluding Crankshaft and Tracemonkey, and possibly excluding Carakan's second-pass compiler) come from class infrence, type specialization, ICs, etc. That work is already done. The result is about 30x slower than C code (gcc -O2, say) on numeric manipulation.
To get better performance than that, you need to do more complicated optimizations. For example, Crankshaft does loop-invariant code motion, Crankshaft and Tracemonkey both do common subexpression elimination, both do more complicated register allocation than the baseline jits, both do inlining, both do dead code elimination. For a lot of code the difference is not that big because there are big enough bottlenecks elsewhere. For some types of code (e.g. numeric manipulation) it's a factor of 2-3 difference easily, getting into the range of gcc -O0. And that's without doing the really interesting things like range analysis (so you can eliminate overflow guards), flow analysis so you know when you _really_ need to sync the stack instead of syncing after every arithmetic operation, and so forth.
For code that wants to do image or audio manipulation on the web, the textbook IR optimizations make a gigantic difference. That assumes that you already have the dynamic-language problems of property lookup and whatnot solved via the techniques Smalltalk and Self pioneered.
One end goal here is pretty explicitly to be able to match C or Java in performance on numeric code, at least in Mozilla's case.