24

I have been researching Interpreters/Compilers, then I stumbled across JIT-Compilation - specifically Google Chrome's V8 Javascript Engine.

My questions are -

  1. How can it be faster than standard Interpretation?
  2. Why wasn't JIT-Compilation used in the first place?


My Current Understanding

  1. Every Javascript Program starts out as source code, then, regardless of the method of execution, is ultimately is translated to machine code.
    Both JIT-Compilation and Interpretation must follow this path , so how can JIT-Compilation be faster (also because JIT is time-constrained, unlike AOT-Compilation) ?

  2. It seems that JIT-Compilation is a relatively old innovation, based off of Wikipedia's JIT-Compilation Article.

"The earliest published JIT compiler is generally attributed to work on LISP by McCarthy in 1960."

"Smalltalk (c. 1983) pioneered new aspects of JIT compilations. For example, translation to machine code was done on demand, and the result was cached for later use. When memory became scarce, the system would delete some of this code and regenerate it when it was needed again."

So why was Javascript Interpreted to begin with?


I'm very confused, and I've done a lot of research on this, but I haven't found satisfactory answers.

So clear, concise answers would be appreciated. And if additional explanation about Interpreters, JIT-Compilers, etc. needs to be brought in, that's appreciated as well.

4
  • 2
    #2 and #3 are answerable, but "How does the Chrome V8 Engine Work?" without any qualification is far too broad; the only correct answer is a link to the V8 source code. Did you mean to ask something more specific about V8? (if not it'd be best to remove that part of the question)
    – Ixrec
    Jul 29, 2015 at 22:14
  • On second glance, the only point of me asking #1 was to understand #2, so I will remove it. Thanks for the input.
    – b0yfriend
    Jul 29, 2015 at 23:24
  • This is not mentioned in the other answers but JIT compilation is hard. It's not a simple thing to do because errors resulting from JIT compilation results in segfaults instead of errors - the program crashes instead of throwing an error in the console. Yes, for a competent C programmer comfortable with gdb this is not a problem. But almost all competent C programmer comfortable with gdb get paid to work on other projects. Some other languages like Perl and Ruby still don't have mainstream JIT interpreters.
    – slebetman
    Nov 13, 2015 at 4:19
  • In case you're wondering. I'm talking about this from the perspective of a core developer/maintainer for a programming language. For a couple of years I was hired to maintain the Ferite programming language. One of the wish list we had was to implement a JIT. It never happened - we moved to go instead. PHP has only recently got a JIT compiler (HVVM) thanks to Facebook pouring enough money into it to make it happen.
    – slebetman
    Nov 13, 2015 at 4:21

4 Answers 4

50

The short answer is that JIT has longer initialization times, but is a lot faster in the long run, and JavaScript wasn't originally intended for the long run.

In the 90s, typical JavaScript on a web site would amount to one or two functions in the header, and a handful of code embedded directly in onclick properties and the like. It would typically get run right when the user was expecting a huge page load delay anyway. Think extremely basic form validation or tiny math utilities like mortgage interest calculators.

Interpreting as needed was a lot simpler and provided perfectly adequate performance for the use cases of the day. If you wanted something with long-run performance, you used flash or a java applet.

Google maps in 2004 was one of the first killer apps for heavy JavaScript use. It was eye-opening to the possibilities of JavaScript, but also highlighted its performance problems. Google spent some time trying to encourage browsers to improve their JavaScript performance, then eventually decided competition would be the best motivator, and would also give them the best seat at the browser-standards table. Chrome and V8 were released in 2008 as a result. Now, 11 years after Google Maps came on the scene, we have new developers who don't remember JavaScript ever being considered inadequate for that sort of task.

Say you have a function animateDraggedMap. It might take 500 ms to interpret it, and 700 ms to JIT compile it. However, after JIT compilation, it might take only 100 ms to actually run. If it's the 90s and you're only calling a function once then reloading the page, JIT is not worth it at all. If it's today and you're calling animateDraggedMap hundreds or thousands of times, that extra 200 ms at initialization is nothing, and it can be done behind the scenes before the user even tries to drag the map.

5

JITs are fast for JavaScript, because it's impossible to generate fast machine code when you do not know the type of your variables.

When you do not have type information, computations are expensive. For example,

x + y

is quite complicated if you don't know anything about x and y. They could be integers, doubles, strings, or even objects where this calculation has side effects. Since we do not have static typing, this is an expensive calculation.

With just-in-time compilation, we can use runtime information and turn this into a faster computation. At runtime, V8 keeps track of the type of variables. If the above code is executed several times with, say, strings, the compiler can execute the much simpler instructions for string concatenation. So when the compiler reaches x + y, instead of running lots of code that branches for many different types of x and y, the compiler quickly checks if we have strings again, and then executes just a few lines of machine code that specifically concatenate strings.

In e.g., C++ the compiler knows the types of x and y ahead of time, since we had to declare the variables. So it can generate optimized machine code for concatenating strings before ever running the code.

1
2

With understanding of what is going on at runtime, it is possible to make changes to the code or the interpretation of the code that allow it to be executed faster or compiled better than what is known at the ahead of time compile time.

Quite a bit can be said on this - it is the subject of significant amounts of research. My own explanation here that I began to write pales in comparison with the answer given in Understanding the differences: traditional interpreter, JIT compiler, JIT interpreter and AOT compiler


Quite simply, JavaScript was not initially compiled or looked at for JIT because it was never meant to be anything that complex or important.

The original intent of JavaScript was to link to Java applets on a web page. The ability to click on some button or enter a value in a form field and then do work in a Java applet method can be seen in Invoking Applet Methods From JavaScript Code. It was also possible, through JavaScript to go the other way of invoking JavaScript code from an applet.

JavaScript's original intent was to link applets and the html pages that contained them. For such a small task, one doesn't need great performance (if you wanted performance, invoke the applet method which is JIT'ed).

It was only after Netscape started to do significant work with JavaScript as its own language and promote it for development (including Server Side JavaScript in the Netscape Enterprise Server - which, incidentally did ahead of time compilation) that JavaScript came into light as a serious target. It took many years after that for the necessary tools to make it useful.

7
  • 1
    No, Javascript is not related to Java. And Java applets are JVM bytecode. Jul 30, 2015 at 6:18
  • @BasileStarynkevitch JavaScript was designed to work with Java applets in hamlet pages - acting as the glue between the html dom and the methods contained in the Java objects. It is not and was never intended to be Java.
    – user40980
    Jul 30, 2015 at 11:05
  • 1
    @quickly_now and still is tc39.github.io/ecma262
    – caub
    Jul 30, 2016 at 14:59
  • 1
    @quickly_now You're likely downvoted because it isn't true. JS was indeed originally intended indeed to interface Java, and mimic it's syntax to an extent. And was originally to be called Mocha (variety of coffee bean, much like Java cofee), but it was renamed LiveScript for release. Finally, the marketing wanted to emphasize the Java link and Netscape named it JavaScript. ECMAScript came two years later in 1997, as ECMA International was given "custody" of the language by Netscape, with the main purpose being standardization between Netscape's and Microsoft's (JScript) implementations. Nov 9, 2017 at 13:44
  • 1
    @quickly_now javascript coined 1995, ecmascript coined 1997. So, um, yeah. Javascript came first, that's why we got stuck with that name (by Netscape). You can be glad we don't have any noticeable gopher's running around though.
    – ebyrob
    Dec 3, 2019 at 14:48
0

1) How can it be faster than standard Interpretation? Well, a thought up example would be as follows; suppose we have 2 applications ApplicationCompiled and ApplicationInterpreted. Both of these programs do exactly the same thing, and share the same source code. ApplicationCompiled takes 6 seconds to compile.

Let's say that the timings of Scenario A is:

  • For ApplicationCompiled: 4 seconds
  • For ApplicationInterpreted: 12 seconds

So in total ApplicationCompiled takes 10 seconds to run Scenario A (6 seconds compilation, 4 seconds running) and ApplicationInterpreted takes 12 seconds in total to run. I don't have a specific example to show you, and I'm not sure under which cases the above would be true - it also depends heavily on how intelligent the interpret and compiler are.

Obviously this is very simplified, but imho the same idea can be applied to JIT compiling / interpreting. The next question would then be "how do we determine - with low cost - if this branch should be JIT compiled or interpreted"? I'm out of my league here :)

2) Why wasn't JIT-Compilation used in the first place? Don't know, but I recon it's simply a matter of resources and maturity of the available progress in making a hard-to-optimize language like JavaScript apply advances techniques such as these. There were probably a lot of lower hanging fruits at the time.

Not the answer you're looking for? Browse other questions tagged or ask your own question.