Inside Mozilla's New JavaScript JIT Compiler 97
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."
Javascript Monkeys (Score:3)
What's different between IonMonkey and JaegerMonkey (the last engine I thought)?
Re: (Score:3)
Good question - it's a shame there's no way to quantitatively determine the relationship between two releases of the same product. Maybe they could use numbers?
What an excellent, useful, non-obvious invention? Have you considered applying for a patent?
Re: (Score:1)
I'm thinking it must be silly o'clock in the United States.
Re:Javascript Monkeys (Score:4, Informative)
Re: (Score:3)
This. It seems to be essentially a pipeline: the old code doesn't get thrown out, just added on. In essence, SpiderMonkey's path to awesome started out with the beginning and the end (TraceMonkey), and now they're going back to fill out the middle (JaegerMonkey and now IonMonkey).
Firefox 3.0 (and lower): SpiderMonkey (JavaScript interpretation
Firefox 3.5: SpiderMonkey -> TraceMonkey (awesome JIT for hot functions only)
Firefox 4.0: SpiderMonkey -> JaegerMonkey -> TraceMonkey (decent JIT for everythi
Re: (Score:3)
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)
Not quite. Traces are sequences of instructions without interior branches. When you write some code, you split it up into functions. A trace flattens this structure - you can think of inlining as a very special case of trace-based optimisation. A trace has a single entry point and (potentially) multiple exit points.
Traces are very useful for JavaScript code, because it tends to be very branch heavy. You can identify a hot path, and then compile a linear sequence of instructions where the branches all
Re: (Score:3, Funny)
-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.
Re: (Score:3)
He was still hung over from the JaegerMonkey party.
Re: (Score:1)
Re: (Score:2)
Actually, I'd simplify that to "if the word sounds German".
Re:Javascript Monkeys (Score:5, Informative)
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).
Re: (Score:2)
Do textbook IR optimizations make a big different with JS code, though? My impression is that the big gains in JS performance don't have much to do with traditional C-compiler optimizations like loop optimization, and have a lot more to do with optimizations derived from the compiling-dynamic-languages literature, like type specialization and class inference.
V8 also goes pretty directly to asm, for example, and gets some big wins from techniques developed in Smalltalk compilers, like compiling code that ass
Re:Javascript Monkeys (Score:5, Informative)
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.
Re: (Score:2)
I was under the impression that the IR optimizations are mostly what makes the difference between gcc -O0 and gcc -O2, and isn't that a minor speed gap compared to the still-existing gap between JS and C that doesn't have all these IR optimizations enabled? I think most people would be overjoyed if JS had performance like C code compiled with gcc -O0, so doesn't that point to different kind of optimizations to target? Or is the argument that bridging the remaining performance gap with unoptimized C is no lo
Re: (Score:2)
> I was under the impression that the IR optimizations
> are mostly what makes the difference between gcc
> -O0 and gcc -O2,
Depends on your code, but yes.
> isn't that a minor speed gap compared to the
> still-existing gap between JS and C that doesn't
> have all these IR optimizations enabled?
No.
> I think most people would be overjoyed if JS had
> performance like C code compiled with gcc -O0
On numeric code, Tracemonkey and Crankshaft have about the same performance as gcc -O0 in my measu
Re: (Score:2)
Hmm, interesting. It's been about a year since I've done any benchmarking of JS stuff, but at the time my attempts at some numerical algorithms in javascript were on the order of 10x-1000x slower than the unoptimized C equivalent. Have JS JITs really improved to the point where a typical double-nested loop over a 2d array doing some standard image-processing kernel will now run at the same speed as gcc -O0? That certainly wasn't the performance I was getting!
Re: (Score:2)
It really depends on the code. In particular, in both Tracemonkey and Crankshaft it's quite possible to end up with code that can't be compiled with the optimizing compiler and then falls back to a less-optimizing JIT (JM and the V8 baseline compiler respectively) .
If you have an example of the sort of code we're talking about here, I'd be happy to see what numbers for it look like.
Re: (Score:2)
Yeah - V8 is really unbelievable for some applications - so much faster (10x) than any of the other JS interpreters (or should we call them compilers at this point?). In other cases it's not really that much, if any, better, but some of the shit those google JS dudes are doing is pretty impressive.
As much as I resent Google sometimes, in a lot of cases they really do have the smartest people in the room.
Re: (Score:2)
IonMonkey compiles from SpiderMonkey's interpretation to an intermediate representation.
JaegerMonkey currently compiles from SpiderMonkey's interpretation to bytecode, which then gets passed to TraceMonkey. It will be changed to compile from IonMonkey's intermediate representation to bytecode instead, though it will still pass that to TraceMonkey.
Re: (Score:1)
LLVM (Score:3, Interesting)
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?
Re:LLVM (Score:5, Informative)
http://blog.mozilla.com/dmandelin/2011/04/22/mozilla-javascript-2011/ [mozilla.com] has some discussion about LLVM in the comments. The short summary is that the LLVM register allocator, for example, is very slow; when doing ahead-of-time compilation you don't care much, but for a JIT that could really hurt. There are various other similar issues with LLVM as it stands.
Re: (Score:2)
So why is the solution to roll your own, rather than fix LLVM or develop a more direct competitor to it? All of the issues mentioned so far seem to be with the current implementation, not with the fundamental idea.
Re: (Score:2)
No idea; you'll have to ask someone familiar with both LLVM and the needs of a JIT for that....
Re: (Score:3, Informative)
Re: (Score:3)
A guy did in fact transplant LLVM in place of Nanojit (in Tamarin rather than SpiderMonkey, but close enough):
http://www.masonchang.com/blog/2011/4/21/tamarin-on-llvm-more-numbers.html [masonchang.com]
And found that LLVM didn't really produce an overall win for this sort of code generation. LLVM is nice for ahead-of-time-compilation, but isn't a good fit for just-in-time.
Re: (Score:2)
Isn't "rolling your own" the same as "developing a more direct competitor to it"?
Re: (Score:2)
"Developing a competitor to LLVM" would imply creating something generic enough to be a backend for many programming languages. Maybe something geared toward dynamic rather than static languages, and tuned better fast compilation, but still comparable in scope to LLVM.
Re: (Score:2)
In other words, something like Parrot.
I mean, I get that Parrot itself probably isn't a good choice, but I still wonder why everyone is so busy reinventing wheels independently and in such a language-specific manner.
Re: (Score:2)
So why is the solution to roll your own, rather than fix LLVM or develop a more direct competitor to it? All of the issues mentioned so far seem to be with the current implementation, not with the fundamental idea.
The goals are somewhat different. LLVM is great for optimizing statically typed code, so it will do e.g. licm that takes into account that kind of code. The IR that would be useful for a JS engine would be higher-level, so it could do licm on higher-level constructs.
.NET. They have very efficient JITs, but they are tuned for the level that makes sense for languages like Java and C#, not JavaScript or Python or Ruby. A
The issue is sort of similar to why dynamic languages don't run very fast on the JVM or
Re: (Score:2)
Re: (Score:2)
Maybe. Maybe not. http://qinsb.blogspot.com/2011/03/unladen-swallow-retrospective.html [blogspot.com] is also worth reading for context here. The "Lessons About LLVM" part.
Re: (Score:3)
I'd be interested to hear why the Mozilla developers don't use an existing compiler framework like LLVM...
LLVM is intended for more static languages than Javascript. The Unladen Swallow [wikipedia.org] project tried to use it for Python, and that was a failure..
Re: (Score:2)
See also http://www.masonchang.com/blog/2011/4/21/tamarin-on-llvm-more-numbers.html [masonchang.com] for a take on trying to use LLVM for ActionScript.
How many JIT engines is this now? (Score:1)
Damn, Mozilla changes JIT engines like every year. Why should be believe this one will last any longer than all the others they have tried?
Javascript is a poorly designed language that is hard to JIT and I imagine that's why we keep seeing people trying to redo things better than the previous JIT engine. It's damn near impossible though, just micro-fractional improvements and a whole lot of wasted effort.
Meanwhile things like LuaJIT [luajit.org] offer a Javascript-like scripting environment with damn near the performa
Re: (Score:2)
LuaJIT is pretty darn quick but then again node.js running on googles V8 engine is right there with it.
Re: (Score:2)
Mozilla doesn't change engines, they just give a different name to each version.
By the way, Julien Danjou's Why not Lua [danjou.info].
Re: (Score:2)
Not quite. More precisely they add new engines, and give them names, then use whichever one does the job best (or is likely to do the job best).
Re: (Score:2)
as far as I can tell Julien Danjou has no clue about Lua programming at all
Uh, he's talking about interfacing Lua with C, not Lua programming. Of course you've never seen anyone pushing or popping in WoW, unless you work for Blizzard and have access to their C++ code.
Maybe you should try reading the article, where he says "integration of Lua into a C program".
Re: (Score:2)
Maybe you could say why is he an idiot, instead of rambling.
From where I'm sitting, as a noob in Lua, I see a guy who has written for the past three years a very nice WM (Awesome [naquadah.org]), which contains a Lua library with thousands of lines, and some random Anonymous Coward who provides no arguments to support his position.
Re: (Score:2)
Could you elaborate on that? Since his problems mirror very much those that I encountered when using Lua. That's not to say that Lua is bad, it is certainty a very small clean language, but I had easier time writing C interface code in other languages (you however run into plenty of slightly different problems with them too).
Re: (Score:2)
> Damn, Mozilla changes JIT engines like every year
Unlike Chrome, who has now had two (more actually, but two that they publicly named) jit engines between December 2008 and December 2010?
> Why should be believe this one will last any longer
> than all the others they have tried?
What does "last longer" mean? Mozilla is still using the very first jit they did (tracemonkey); they're just not trying to use it for code it's not well-suited for.
> just micro-fractional improvements
If a factor of 2-3 i
Re: (Score:3)
Damn, Mozilla changes JIT engines like every year. Why should be believe this one will last any longer than all the others they have tried?
That's not actually what's happening, though Mozilla isn't helping matters with all the confusing names.
What's actually going on is that Mozilla is essentially implementing different parts of a longer pipeline. Even as recently as FF4, SpiderMonkey is still present at the front of that pipeline, and TraceMonkey is still present at the end (actually nanoJIT is at the very end, but it's not named after a monkey so we won't count it here). JaegerMonkey, IonMonkey, and all the other monkeys go in the middle.
Re: (Score:2)
Re: (Score:2)
Re: (Score:2)
Re: (Score:2)
Why don't you use a type declaration?
Re: (Score:2)
And once all that nice code is run through a javascript obfuscator/compressor that renamed all the "str" variables to "a" "b" "c" etc, what then?
Re:types (Score:4, Interesting)
OK. Let's look at http://code.jquery.com/jquery-1.5.2.js [jquery.com] 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.
Re: (Score:2)
So what would be the prefix for variable 'anonymousUser', which holds an object created from the User prototype and with a couple of custom methods added dynamically?
Re: (Score:2)
Optional type annotations (a la ActionScript3) were considered for JavaScript in the ECMAScript4 standard, but the committee decided it didn't want to go in that direction.
Re: (Score:3)
javaScript as a platform (Score:3)
Now javaScript is so fast perhaps other interpreted languages would be "compiled" to JS. I am thinking of Perl6 for one.
Re:javaScript as a platform (Score:5, Informative)
Yup. Python is translated to javascript in pyjamas. http://pyjs.org
Re: (Score:2, Informative)
Check Coffeescript, Objetive J, Pyjamas, Skulpt.
Re: (Score:2)
Google and Mozilla seemed to have got a much faster javascript in a much shorter time.
Re: (Score:2)
You mean like Sprixel [perlgeek.de]? There are already a number of compilers for other languages, such as Java [perlgeek.de], Python [pyjs.org], and Javascript [google.com], oddly enough. List of languages that compile to JS [github.com] has many more.
Dead-code ellimination (Score:3, Informative)
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?
Re:Dead-code ellimination (Score:4, Informative)
No, they just pointed out that IE's dead-code elimination was somewhat narrowly tailored to the Sunspider benchmark. That's quite different from "crying bloody murder".
Tracemonkey does dead-code elimination right now; it has for years. It's just that it's a generic infrastructure, so you don't usually get artifacts with code being eliminated only if you write your script just so. On the other hand, you also don't usually get large chunks of web page dead code eliminated, because that wasn't a design goal. Keep in mind that a lot of the dead code JS JIT compilers eliminate is code they auto-generated themselves (e.g. type guards if it turns out the type doesn't matter, stack syncs it it turns out that no one uses the value, and so forth), not code the JS author wrote.
Re: (Score:1)
Narrowly pointing out and having their lead "evangelist", Asa Dotzler, scream condemning words and making absurd claims is a different thing.
In any case, I haven't seen any proof that the dead-code eliminator is "somewhat narrowly tailored for Sunspider". It could just be that it's quite aggressive, so any code that doesn't touch the DOM or change any variable (like calculating 1M of pi and sending it to null) get elliminated.
Re:Dead-code ellimination (Score:5, Informative)
> Narrowly pointing out and having their lead
> "evangelist", Asa Dotzler
Uh... I think you're confused about Asa's role here. But anyway...
> I haven't seen any proof that the dead-code
> eliminator is "somewhat narrowly tailored for
> Sunspider"
Well, it only elimintated code that restricted itself to the set of operations used in the Sunspider function in question. This is pretty clearly described at http://blog.mozilla.com/rob-sayre/2010/11/17/dead-code-elimination-for-beginners/ [mozilla.com]
For example, it eliminated code that included |TargetAngle > CurrAngle| but not code that was otherwise identical but said |CurrAngle >) was not. Addition and subtraction were eliminated while multiplication and division and % were not.
If it eliminated "any code that doesn't touch the DOM" that would be a perfectly good general-purpose eliminator. That's not what IE9 was doing, though.
There was the side issue that it also produced buggy code; that's been fixed since, so at least IE9 final doesn't dead-code eliminate live code.
Re: (Score:2)
Re: (Score:3)
Turns out, figuring out whether code in JS is dead is hard. See http://blog.mozilla.com/rob-sayre/2010/11/17/dead-code-elimination-for-beginners/ [mozilla.com] for some examples of things that look dead but aren't.
Re: (Score:2)
In my book any creative use of toString or valueOf counts for bonus points...
Re: (Score:3)
Re: (Score:2)
For example, if you have i++ and you then don't use i before it goes out of scope, this is a dead expression and the compiler can remove it.
Fine, then you can tell me what the result of the following code should be, I assume?
for (var n = 0; n < 100; n ++) {
i ++;
}
Now what if I tell you that I had originally defined i like this:
var i = { valueOf: function() { var a = Math.floor(Math.random()*100); document.write(a); return a; } };
Re: (Score:2)
Of course, the variable definition for i would obviously have to go in the opening statement of the for-loop (along with the definition of the loop counter n) in order to demonstrate the variable going out of scope without being used after the i ++ statement..
Re: (Score:2)
I was rather curios about the 'dead code' elimination... That would seem to me to be one of the first things to go solve, if nothing is pointing to that particular code portion, simply do not compile it. I must be missing something where that would not be one of the first targets to eliminate.
Dead code elimination is certainly a worthy goal, though not necessarily easy in a highly dynamic language like Javascript.
Re: (Score:2)
In IE9 beta adding a single useless variable assignment to some modern benchmarks made them take several orders of magnitude longer. An unused variable sounds like the sort of thing that should be optimised out by DCE, but here it's obviously enough to trip up the thing they use to detect common benchmarks and cheat using built-in precompiled code.
Compile it all (Score:1)
Re: (Score:2)
Re: (Score:2)
No, what would happen is we'd end up with sites compiled for some obscure language-version, which nothing but one browser half-understands. Oh, and the compiler's buggy also.
As it is now, when there's a critical error in some obscure website's code, the problem can be diagnosed, and either fixed or worked around with a Greasemonkey script.
(Had to do that last night: Some educational login page had a id='txtpassword' field, which they called as getElementById('txtPassword'). It worked in IE, but not in anyth
hash table lookup optimization (Score:1)
I wonder how do javascript engines optimize hash table lookups. Especially since it is faster to access a member of an object than to access a variable of an outer function. It seems to me that the former requires a hash table lookup with a string key while the later suffices with a pointer into the closure of an outer function and the offset of the variable.
Re: (Score:2)
V8 calls this "hidden classes": http://code.google.com/apis/v8/design.html [google.com]
As for closures, they can be represented in a multitude of ways... Some more efficient than others.
2011... (Score:2)
and I still cannot run a mozilla javascript environment inside IE, Opera, or Chrome.
You think I'm joking but I'm plain serious. Why are we so dependent on each particular javascript implementation?
Re: (Score:2)
Because each browser's JS engine is closely tied with its DOM, which is in turn closely tied with its layout engine. Otherwise it would be difficult to have efficient DOM calls and complete garbage collection.
Re: (Score:2)
Okay so take it a step further...
The question now becomes: why can't I run mozilla's DOM and layout engine inside IE, Opera, or Chrome or any other browser?
So your html could start like: /> ... etc ...
<HTML>
<HEAD>
<META browser="my_browser.so"
Where "my_browser.so" is a platform-independent shared object file which you may have compiled yourself (from Mozilla's code).
See the advantage? Your javascript, DOM manipulation, css layout, etcetera will work on ANY browser. No more cross-browser mis
Re: (Score:1)
This is basically what Chrome Frame does. It's a bad idea. Why is it a bad idea? Well, either "my_browser.so" is downloadable from the internets, or it isn't. If it is, that's a security hole you can drive a truck through (basically the same problem as ActiveX controls). If it isn't, then everyone whose operating system doesn't ship "mshtml.dll" is screwed.