Apple integrates LLVM compiler to boost WebKit JavaScript performance

Since compilers already make fast code, why not take advantage?

We looked last week at some of the things that can influence the speed of programming languages and how different approaches to running code can influence program performance. Some work described by Apple this week shows how techniques common in one language can be applied to another.

Modern browsers use a scheme called just-in-time compilation to convert JavaScript into executable code and achieve high performance when they do so. As the optimization process has become more advanced and performance improved, Apple's WebKit developers have realized that they're increasingly building the same capabilities as traditional compiler developers have already built. Feeling that's rather wasteful, they've decided to stop building their own and instead leverage the optimization capabilities of the LLVM compiler.

The work was described earlier this week in a blog post. The WebKit JavaScript engine previously had three different stages that achieved different performance levels for the scripts they ran. The first stage was an interpreter that ran script programs without compiling them. This allows scripts to run "instantly" without having to wait for a compiler.

If a JavaScript function is called more than six times, or loops more than 100 times, it gets fed into the next stage: a basic JIT compiler that produces executable code. This doesn't optimize heavily, but it removes some of the overheads that the interpreter has to produce code in the ballpark of ten times faster than the interpreter.

If the function is then called more than 66 times, or loops more than 1,000 times, it gets fed into the third stage, a JIT compiler that actually spends a relatively long time to optimize the code. The third stage output is about three times faster than the basic JIT, or 30 times faster than the interpreter. It would take too long to optimize every function with this compiler, which is why this staged approach is used.

Though that third stage is much faster than the interpreter, it still doesn't match a typical C or C++ compiler for low-level optimizations: figuring out which values to store into which registers, for example. The WebKit developers wanted to add a fourth stage to perform this kind of work, but while they thought that writing it from scratch would be "super fun," it'd also be a lot of work. A lot of work that existing C and C++ compilers already do. Hence, they decided to investigate the use of LLVM's code generation and optimization.

The LLVM-based fourth tier is called FTL, for Fourth Tier LLVM (and, of course, faster than light). It shares some portions with the third stage, since the third stage already does important work for handling JavaScript's dynamic nature but has a different code generating portion.

The result is a healthy performance boost. FTL produces code that is more than 40 times faster than the interpreter, with benchmarks taking about a third less time to run than the old three-tier system.

One of the downsides of the LLVM compiler is that it's, relatively speaking, quite slow. This isn't altogether surprising, as LLVM is designed to optimize well, rather than optimize quickly, and for ahead-of-time compilation of the kind used for C and C++ it's worth taking the extra time to do a good job. To handle that, WebKit only uses FTL for functions that are taking a long time to run (10 milliseconds) or being called an awful lot—to ensure that it's really worth using FTL—and then it runs FTL on a background thread. It doesn't have to wait for that thread to finish, as it can simply use the code from the third stage in the meantime.

FTL is currently available in WebKit nightly builds and enabled by default.

A decade ago, JavaScript was only ever an interpreted language, and it was quite slow because of it. Since then, it has risen in importance and become the focus of considerable development effort to improve its performance. The use of LLVM and the integration of a traditional compiler's optimizer show how features common to one set of languages can be used in others, making the distinctions between different kinds of language fuzzy.

It's unlikely that Apple will be the only browser developer to do this kind of thing. Browser developers like to crow about the performance of their JavaScript engines, and the likes of Microsoft and Google won't want to let Apple take the lead in this field.

153 Reader Comments

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

I was just about to say it's too bad that Netscape didn't just stick Lisp in the browser back in 1995.Well, at least Javascript can be used as a functional, dynamic language. At least it's not C++.

The use of LLVM, and the integration of a traditional compiler's optimizer, shows how features common to one set of languages can be used in others, making the distinctions between different kinds of language fuzzy.

Obvious. Programming languages don't have speed, their run time implementation do.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

Its an optimized python JIT compiler that has performance in the league of Java.

Umm not really. Java's HotSpot is one of the best JITs - to match it would be no mean feat. PyPy is an option and it is faster in some cases than standard Python but as I just figured out - standard hashlib.sha512() is full one second faster than PyPy's. So there is still a lot of work to do until PyPy becomes consistently faster than standard Python - after that it can dream of catching up to HotSpot

I am a little surprised that some of the other popular languages never ended up being able to be used as an alternative to interact with webpages, like as c/c++, just due to the tons of code out there that could be leveraged. I guess with HTML5 they finally dropped the requirement for type of script to be declared and just set the default to text/javascript

It's not clear to me how this is of much practical value. I fail to see how real life JS code run in a browser will see significant performance boosts from FTL. May be a handful of special case web apps exist that can benefit from FTL's slow compile times and marginally faster run times - but then they are adding LLVM as a dependency on WebKit - that's gotta be a big cost in terms of maintenance.

May be it could be used with nodejs type server side JavaScript apps.

High performance javascript plus HTML5 are already making it possible to run applications in the browser that just a few years ago would have had to have been desktop applications.

In cases where you are running what amounts to a desktop application in your browser, there will be plenty of time for the compilation and optimization to take place while you're using the app. And if the object code can be cached it only has to happen once (until the application is updated).

Two questions, 1) does the number of calls necessary to invoke the LLVM compiler need to happen in a single session or is it tracked across sessions with some sort of history 2) is compiled code stored for later sessions?

If they can compile a commonly used web app (like say gmail) and store it so that every time I fire it up it automatically uses the fast version out of the gate, then this is a real win.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

Its an optimized python JIT compiler that has performance in the league of Java.

Umm not really. Java's HotSpot is one of the best JITs - to match it would be no mean feat. PyPy is an option and it is faster in some cases than standard Python but as I just figured out - standard hashlib.sha512() is full one second faster than PyPy's. So there is still a lot of work to do until PyPy becomes consistently faster than standard Python - after that it can dream of catching up to HotSpot

True. However, Cpython hashlib.sha512() is actually written in C, while PyPy hashlib.sha512() is written in python. The fact that the PyPy hashlib.sha512() is at all comparable in performance to a library written in C is a testament to how good PyPy is.

In short: for the "best" web experience, browsers sometimes need to run JavaScript VERY fast......

Yes, but is there any evidence that asm.js or v8 are miserably slow on any of those apps? Obviously without a JIT those would be subpar but I was curious as to what v8 or asm.js cannot do that FTL can to those apps that makes a significant difference. Asm.js already runs Unity 3D games at great speed for example.

It's not clear to me how this is of much practical value. I fail to see how real life JS code run in a browser will see significant performance boosts from FTL. May be a handful of special case web apps exist that can benefit from FTL's slow compile times and marginally faster run times - but then they are adding LLVM as a dependency on WebKit - that's gotta be a big cost in terms of maintenance.

May be it could be used with nodejs type server side JavaScript apps.

Is maintaining the LLVM interface a bigger maintenance cost than maintaining your javascript compiler? I would guess not.

There are some pretty impressive applications running in pure javascript in the browser, and improved runtime performance makes it likely that we'll see even more of them.

I'm disappointed that we have readers who are complaining about something being made faster. As Peter pointed out, no one is going to let Apple sit up on top with a speed crown, regardless of what it is used or not used for. So Javascript is going to get faster in all browsers. At that point it will have saturation and someone will figure out how to take advantage of it in a way that perhaps wasn't as practical before. Sometimes it's okay to just be better for better's sake, and let the world adjust accordingly.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

I was just about to say it's too bad that Netscape didn't just stick Lisp in the browser back in 1995.Well, at least Javascript can be used as a functional, dynamic language. At least it's not C++.

Yah. LISP would have been better than the mess that is JavaScript. What would be cool is a web programming language that is a LISP optimized for scripting and ease of learning (something like NewLISP?)

True. However, Cpython hashlib.sha512() is actually written in C, while PyPy hashlib.sha512() is written in python. The fact that the PyPy hashlib.sha512() is at all comparable in performance to a library written in C is a testament to how good PyPy is.

Ah - I didn't know that Python's hashlib was C and not pure python - pretty good for PyPy in that case.

Modern C++ (C++11 and later) is actually pretty fun to code at and it performs yet better than older versions (move semantics); if C++ would be chosen from the very beginning, right now with smaller infrastructures we would have native performance in our websites instead of "almost-native" performance.

I'm disappointed that we have readers who are complaining about something being made faster. As Peter pointed out, no one is going to let Apple sit up on top with a speed crown, regardless of what it is used or not used for. So Javascript is going to get faster in all browsers. At that point it will have saturation and someone will figure out how to take advantage of it in a way that perhaps wasn't as practical before. Sometimes it's okay to just be better for better's sake, and let the world adjust accordingly.

Apple sometimes use their resources to push forward on things like this before others do. Now that they've shown the path, others will quickly follow and the early lead will be irrelevant in a few months.

Modern C++ (C++11 and later) is actually pretty fun to code at and it performs yet better than older versions (move semantics); if C++ would be chosen from the very beginning, right now with smaller infrastructures we would have native performance in our websites instead of "almost-native" performance.

I would imagine WebC++ wouldn't resemble most C++ written today though. You'd probably end up without the header/implementation file split and go with only one like Java so it can be more easily incrementally compiled; and you'd also lose things like the preprocessor and such too.

Basically optimising the 'language' to essentially support one-pass-through compiling, rather then the current implementations where it essentially has to compile implementation+all-headers file custom every time (since pre-processor macros can rather dramatically alter include file implementations).

Well even with FTL Apple isn't the fastest JS Engine. According to arewefastyet, But i guess it depends on code and usage.For Asm.js, Mozilla's IonMonkey with its specific path is still the fastest.

On the other notes, I really wish Ars could dig up some news on WebKit front. WebKit 2 were only recently stabilize with OSX Marverick. Before i was crashing like crazy. What happen there? And Apple are now doing Process Per Tab as well which was something they wanted to avoid ( or have the flexibility to avoid ) doing on WebKit 2.

Will external process in hopefully IOS8 means a the UIview gets to use Javascript JIT in apps as well?

Honestly, my first reaction when I read this was "sweet, I can write web apps that aren't in js!".

One of the most awesome aspects of LLVM is that it doesn't have to emit machine code. It can emit just about anything, including javascript, assuming someone writes the emitter for it.

Combine this with something like asm.js, and reduce js to the roll asm currently has: sure people write in it natively, but only rarely, and usually only if they have to. Everything else just compiles down to it.

Well even with FTL Apple isn't the fastest JS Engine. According to arewefastyet, But i guess it depends on code and usage.For Asm.js, Mozilla's IonMonkey with its specific path is still the fastest.

On the other notes, I really wish Ars could dig up some news on WebKit front. WebKit 2 were only recently stabilize with OSX Marverick. Before i was crashing like crazy. What happen there? And Apple are now doing Process Per Tab as well which was something they wanted to avoid ( or have the flexibility to avoid ) doing on WebKit 2.

Will external process in hopefully IOS8 means a the UIview gets to use Javascript JIT in apps as well?

asm.js might as well be C bytecode written in javascript. It's something quite different to compile and optimize the entire javascript language than it is to compile and run the limited subset used by asm.js programs.

They might get something out of it that they didn't get out of squirrelfish extreme or whatever name it's going by these days, and maybe it'll make maintaining things easier, but I think they'll end up having to spend a bunch of time on their JS to LLVM IR front end compiler/interpreter so the difference probably won't be that big in terms of how much code they have to write.

PNaCl is rather irrelevant to JavaScript, though, and given its low level of usage, essentially irrelevant to everything, at the moment.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

The problem with Python is that so many third party modules depend upon bad behavior in CPython that even trying to reform the standard interpreter isn't really going anywhere. People have tried to build new, faster interpreters for Python for years: Jython, IronPython, PyPy, Unladen Swallow, etc. Pretty much all of them ended up being drastically faster than CPython on a lot of tasks, had much better multithreading support due to the lack of a GIL, and ended up completely dead due to lack of use (aside from PyPy).

They might get something out of it that they didn't get out of squirrelfish extreme or whatever name it's going by these days, and maybe it'll make maintaining things easier, but I think they'll end up having to spend a bunch of time on their JS to LLVM IR front end compiler/interpreter so the difference probably won't be that big in terms of how much code they have to write.

PNaCl is rather irrelevant to JavaScript, though, and given its low level of usage, essentially irrelevant to everything, at the moment.

Agreed, for the most part, much like NaCl, it's not going to get used much. ChromeOS apps use them a bit I think, but that's about it. I was just pointing out that LLVM is not a newcomer to the whole web browser world.

Honestly, my first reaction when I read this was "sweet, I can write web apps that aren't in js!".

One of the most awesome aspects of LLVM is that it doesn't have to emit machine code. It can emit just about anything, including javascript, assuming someone writes the emitter for it.

Combine this with something like asm.js, and reduce js to the roll asm currently has: sure people write in it natively, but only rarely, and usually only if they have to. Everything else just compiles down to it.

In fact, why isn't this already happening?

But it is already happening! Examples include :- dart, which can either be executed on its own VM (only available in a specific build of Chromium for now) or compiled to JavaScript- various other JavaScript-replacement languages which are only ever used compiled to JavaScript (Cofeescript, Typescript...)- various solution to generate JavaScript from existing languages, such as GWT for Java, Emscripten for C/C++ (and possibly others, since Emscripten is based on LLVM)...

I wonder what it would be take to bypass the whole javascript part and make LLVM the interface with the outside world? You could than use any language you like with an LLVM compiler and ship the bytecode (or whatever the LLVM equivalent is called).

Umm not really. Java's HotSpot is one of the best JITs - to match it would be no mean feat. PyPy is an option and it is faster in some cases than standard Python but as I just figured out - standard hashlib.sha512() is full one second faster than PyPy's. So there is still a lot of work to do until PyPy becomes consistently faster than standard Python - after that it can dream of catching up to HotSpot

Weird, I've been working with hashlib and hmac recently, and in my experience PyPy is pretty much equal to CPython in SHA-2 performance and faster if you need the HMAC. Also, 1s can be 1% or 1000%.

They might get something out of it that they didn't get out of squirrelfish extreme or whatever name it's going by these days, and maybe it'll make maintaining things easier, but I think they'll end up having to spend a bunch of time on their JS to LLVM IR front end compiler/interpreter so the difference probably won't be that big in terms of how much code they have to write.

PNaCl is rather irrelevant to JavaScript, though, and given its low level of usage, essentially irrelevant to everything, at the moment.

Agreed, for the most part, much like NaCl, it's not going to get used much. ChromeOS apps use them a bit I think, but that's about it. I was just pointing out that LLVM is not a newcomer to the whole web browser world.

Well those are completely different technology. Integrating LLVM into a JIT compiler that can dynamically replace and promote code up tiers is certainly novel. LLVM is designed to be a Ahead Of Time compiler optimized for throughput, while the normal JIT compiler for quick compilation while preserving the dynamism of JavaScript. If you read the article there are quite a few tricks they had to do to be able to accomplish this.

PNaCl, while cool, relies on distributing pre-built binaries. Using LLVM is not the cool part, what's cool is seamlessly integrating it to a JIT compiler for a dynamic language while preserving the low latency of existing system. (I don't think integrating to the "browser" itself means anything at this point. PNaCl can be a plugin like Flash for all I care)

Speaking of which, I do wish something like PNaCl can get more adoption. Ultimately it's a little weird to have the tyranny of a single scripting language that determines the future of the web, while distributing byte code allows us much more flexibility in choosing our compiler, source language etc. Asm.js is basically just byte code in a worse format pretending to be human readable in my opinion.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

The PyPy guys have tried LLVM in the past, but couldn't make it both work and be faster than their JIT at the same time.

I wish this much effort was being put into making something like python fast. In my opinion python is a much better thought out language and I would vastly prefer webdevelopment if it meant I could use python instead of js.

The PyPy guys have tried LLVM in the past, but couldn't make it both work and be faster than their JIT at the same time.

Seems from the link this is the key part that WebKit's FTL has solved that PyPy couldn't...

Quote:

On the other hand, using LLVM as our JIT backend looks interesting as well — but again we made an attempt, and it failed: LLVM has no way to patch the generated machine code.

Seems from the link this is the key part that WebKit's FTL has solved that PyPy couldn't...

Quote:

On the other hand, using LLVM as our JIT backend looks interesting as well — but again we made an attempt, and it failed: LLVM has no way to patch the generated machine code.

Based on the article and the blog post, WebKit doesn't really need that functionality. They aren't using LLVM as the backend, just yet another backend. Maybe PyPy could do similar, but it would mean retaining all their current machinery and adding more LLVM related code.

Modern C++ (C++11 and later) is actually pretty fun to code at and it performs yet better than older versions (move semantics); if C++ would be chosen from the very beginning, right now with smaller infrastructures we would have native performance in our websites instead of "almost-native" performance.

Maybe native performance is not the most important goal in this situation. When the target is to make it possible to create applications on a website and make them indistinguishable from an installed application, the language has just to be fast enough for most people not to notice any difference.

As soon as the UI is similarly responsive as a native app most people will not care about a few seconds processing time for more involved tasks like for example image processing if this means they do not have to install anything and things just work.

I am not sure if we would be looking at a lot of web applications nowadays if the initial language chosen would have been C++.

Of course compiled C++ code was a lot faster but you need to compile it first. With web-apps running on different systems you are forced to compile on the target system when the app is started as you do not know before which processor family is being used. You could store precompile binaries and download these on demand but this would make it more difficult to create applications.

Compare this to a situation with JavaScript where you just download the page as usual and an interpreter bascially starts processing as soon as the code is there and something happens right away, No need to think too much about different target systems and binary code. Sure it is slow but it is good enough for what is has to achieve.

Taking the learning curve for C++ into accont and the numerous ways you can shoot yourself in the foot with the language the chance of getting as many people as possible to write web applications is higher with a "simpler" (in the sense of easier to get something done) language like Javascript as with C++.

With the compiler steps being added, the performance of Javascript is steadliy improving while external add-ons like Typescript make it easier to create stuff that works. If this makes the language close to native performance and I can move my 3d stuff fast enough to the graphics card to do the heavy lifting, that is good enough for me and the few percent performance gained by C++ are not worth the effort.