Compilers – CreativeJS http://creativejs.com The very best of creative JavaScript and HTML5 Wed, 03 Jun 2015 20:19:39 +0000 en-US hourly 1 https://wordpress.org/?v=4.4.1 The race for speed part 4: The future for JavaScript http://creativejs.com/2013/06/the-race-for-speed-part-4-the-future-for-javascript/ http://creativejs.com/2013/06/the-race-for-speed-part-4-the-future-for-javascript/#comments Thu, 06 Jun 2013 12:00:36 +0000 http://creativejs.com/?p=5379 Continue reading ]]> The race for speed - part 4

Browser vendors have ambitious plans for JavaScript. Many of them are making long-term investments in the web as an operating system. To get there they have set themselves the goal of running JavaScript code as fast as native C. If this performance can be achieved it will further blur the difference between native apps and web apps.

So how do you take a dynamic language and make it run anywhere close to native C?

ES.next
The next generation of the JavaScript language is currently being drafted. ES.next will be the sixth edition of ECMAScript, the specification from which JavaScript is derived, and is anticipated sometime later this year.

One of the stated goals of this project is fast compilation. A number of features are being discussed to achieve this including a type system, binary data and typed arrays. Typed data can be sent directly to a typed JIT resulting in much faster compilation and execution time.

Native browser support for ES.next is still poor but you can keep track of it with this ES6 compatibility table and even take it for a test drive with Google’s Traceur project – an ES.next to JavaScript compiler written in JavaScript. If you’re determined to use it now then take a look at the Six Project.

WebGL
JavaScript in the browser isn’t limited to DOM manipulation. The vast majority of modern browser games (those that aren’t using plug-ins) render directly to a single HTML5 Canvas element using the standard 2D Context. Canvas is essentially a big writable bitmap. Using JavaScript you layer, blit and animate other bitmaps onto it to create animation, games, graphs and so on.

The fastest way to render to Canvas is with WebGL – a JavaScript API providing hardware-accelerated graphics. This context greatly improves performance by offloading the computationally expensive process of rendering to the GPU, leaving the CPU free to manage the application logic.

Contrary to popular wisdom WebGL actually has some level of implementation in all modern desktop browsers. It is ready in both Chrome and Firefox but needs to be first enabled by the user in Safari and Opera. Microsoft has been the last holdout but references to WebGL have been found in leaked versions of their forthcoming IE11.

Unfortunately even with browser support you still can’t guarantee WebGL is going to work for all your users as they also must have up to date graphics drivers for their GPU. Google Chrome is currently the only browser to offer a fallback software renderer if those drivers do not exist. WebGL is a very powerful and promising technology but it’s not fully ready for primetime. Aside from some browser vendors security concerns, desktop support has some way to go and mobile support is very patchy indeed. And of course legacy browsers will have no support at all.

Javascript as a compile target
Although all modern web applications rely on Javascript for their client-side logic, not all of them are written in Javascript. Many are authored in completely different languages and then trans-compiled to JavaScript to run in the browser. Some of these, like CoffeeScript and TypeScript were created to make JavaScript development more robust; but others like Java, C++ and C# view JavaScript as just another compile target.

Cross-compilation is not without it’s problems though. Heavily minified output code is difficult to follow and debugging is only really practical in browsers with support for source maps – an intermediary file mapping the runtime Javascript back to it’s source language.

A couple of years ago Microsoft Engineer Scott Hanselman put forward the notion of Javascript as assembly language. His observation that modern minified JavaScript application code is unreadable is hard to dispute, but that post provoked a great deal of interesting debate. Many a web career began with a simple ‘view source’ but when that source is obfuscated are we at risk of losing new developers?

An interesting example of JavaScript as a compile target is Mozilla’s Emscripten project. This takes LLVM bitcode and compiles it to JavaScript. LLVM (Low Level Virtual Machine) is a very popular intermediary compiler format – you’ll find an LLVM compiler for almost any language. This kind of setup would enable you to write code in the language of your choice and then trans-compile it to JavaScript.

It’s still early days for this project but the team have already released some impressive demos. Developers from Epic ported the Unreal Engine 3 to JavaScript and WebGL using the Clang compiler to create LLVM from a native C codebase and then Emscripten to compile asm.js JavaScript from the LLVM.

asm.js
A companion project to Emscripten is asm.js. This takes the concept of JavaScript as machine code quite literally. The specification models assembly language using only a highly restricted subset of the JavaScript language. So although you could write asm.js by hand you really don’t want to. To get the best out of it you’ll need the help of two compilers.

The Emscripten compiler can emit asm.js. The resulting JavaScript maybe unreadable but it’s valid and backwardly compatible, meaning it’ll still run in any browser. The big speed boost comes when modern engines recognise the asm.js format and can push that code through a dedicated compiler. For this Mozilla are working on OdinMonkey, an asm.js-optimising compiler built on top of IonMonkey, and Google have also pledged to support it in Chrome.

Any JavaScript conforming to the specification negates the need for garbage collection, boxed values or dynamic types. Early tests show performance around half that of compiled C++; a phenomenal achievement and comparable to the speed of languages like Java or C#. The team even believe this can be improved upon.

Mozilla Research are really on fire at the moment. In addition to Emscripten and asm.js they also have LLJS (JavaScript as C) and are working with Intel on River Trail – ECMAScript extensions for multi-core parallel processing. With this much innovation happening it’s not hard to believe that JavaScript running at native speeds might actually be possible.

and finally… ORBX.js
One leftfield solution to the native performance problem is to sidestep it entirely through virtualisation. Instead of running an application on your machine you run it in the cloud and stream the results as video to your machine. This is the solution being put forward by Mozilla and Otoy with ORBX.js, a video codec capable of delivering 1080p entirely through JavaScript.

In the video above you’ll see 3D Studio Max running natively and in the browser via ORBX.js. While the technology is certainly impressive it may well create more problems than it solves. When everything is virtualised the bottlenecks become connectivity, latency and bandwidth, and any outage is fatal.

Whichever way it goes it seems that JavaScript has a very bright and interesting future.

]]>
http://creativejs.com/2013/06/the-race-for-speed-part-4-the-future-for-javascript/feed/ 8
The race for speed part 3: JavaScript compiler strategies http://creativejs.com/2013/06/the-race-for-speed-part-3-javascript-compiler-strategies/ http://creativejs.com/2013/06/the-race-for-speed-part-3-javascript-compiler-strategies/#comments Wed, 05 Jun 2013 12:00:51 +0000 http://creativejs.com/?p=5376 Continue reading ]]> The race for speed - part 3

The JavaScript language is hugely popular for a number of reasons. Broad reach is certainly a factor, and from a developer’s perspective it’s very quick and flexible. Everything in the language is an Object so creating structures on the fly is simple and there’s no need to datatype anything because those types are all inferred. It is however exactly this versatility that makes it a challenge to compile.

Hidden classes
Although Objects and hierarchies are very easy to build in JavaScript, navigating these complex structures can be very slow for a compiler. A common way in C to store and retrieve properties and their values is with a hashtable or Dictionary; an Array-like structure where the value of a property can be looked up by searching for a unique String identifying it’s name. The problem with looking up a property on a very large hashtable is it can be very slow.

To speed this up both V8 and SpiderMonkey implement what’s called hidden classes – a behind the scenes representation of your JavaScript objects. Google call them maps and Mozilla calls them shapes but they’re pretty much the same thing. These structures are much quicker to find and work with than a standard Dictionary lookup.

Type inference
Dynamic typing in JavaScript is what allows the same property to be a Number in one place and then a String in the next. Unfortunately this versatility requires the compiler to create a lot more type-checking conditions, and conditional code is much larger and slower than type-specific code.

The solution to this problem is called type inference and all modern JavaScript compilers do it. The compiler inspects your code and makes an assumption about the datatype of a property. If this inference proves correct it executes a typed JIT that emits a fast (datatype-specific) machine code stub. If the type is not what was expected then that code “misses” and is passed off to an un-typed JIT to be fulfilled with conditional slower code.

Inline caches
The most common optimisation in modern JavaScript compilers is inline-caching. This is not a new technique (it was first implemented 30 years ago for the Smalltalk compiler) but it is very useful.

To work, Inline caching requires both the techniques we’ve just looked at: type inference and hidden classes. When the compiler encounters a new object it caches its hidden class along with any inferred datatypes. If that structure is encountered again anywhere else in the code then it can be quickly compared to the cached version. If a match is found then the previously generated stub of optimised machine code can be reused. If the structure or type has changed then it may fall back to slower generic code, or in some modern compilers can even perform polymorphic inline caching – i.e generate additional stubs on the same structure, but for each datatype.

If you are interested in learning more about inline caching in JavaScript then I would recommend reading this article from Google V8 engineer Vyacheslav Egorov. In it he builds a Lua parser in JavaScript and explains inline caches in a lot more detail.

Once the compiler has understood the structure of your code and the datatypes within it, it becomes possible to perform a whole range of other optimisations. Here are just a few examples:

inline expansion. aka “inlining”
Function calls are computationally expensive because they require some kind of lookup, and lookups can be slow. The idea behind inline expansion is to take the body of the function being called and drop that code into where it was called. This avoids branching and produces faster code, but at the expense of additional memory.

loop-invariant code motion. aka “hoisting”
Loops are a prime candidate for optimisation. Moving unnecessary computation out of a loop can greatly improve performance. The most common example of this would be a for-loop iterating over the contents of an Array. It is computationally redundant to calculate the length of the Array every time you loop through it. The length can be pre-computed into a variable and “hoisted” out of the loop.

constant folding
This is the practice of pre-computing the values of constants or variables that do not change throughout the lifetime of the program.

common-subexpression elimination
Similar to constant folding, this optimisation works by scanning your code for expressions that evaluate to the same value. Those expressions can then be replaced with a variable holding the pre-computed value.

dead-code elimination
Dead code is defined as unused or unreachable code. If there is a function in your program that is never called then there’s absolutely no point in optimising it. In fact it can be safely eliminated, which also reduces the overall size of the program.

These kinds of optimisations are really just the start of what has become an ambitious objective. To run JavaScript code as fast as native C code. Is that really an achievable goal? In the last part of this series we’ll look at some projects at the bleeding edge of fast JavaScript.

]]>
http://creativejs.com/2013/06/the-race-for-speed-part-3-javascript-compiler-strategies/feed/ 6
The race for speed part 2: How JavaScript compilers work http://creativejs.com/2013/06/the-race-for-speed-part-2-how-javascript-compilers-work/ http://creativejs.com/2013/06/the-race-for-speed-part-2-how-javascript-compilers-work/#comments Tue, 04 Jun 2013 12:00:23 +0000 http://creativejs.com/?p=5371 Continue reading ]]> The race for speed - part 2

When we talk about a JavaScript engine what we’re usually referring to is the compiler; a program that takes human-readable source code (in our case JavaScript) and from it generates machine-readable instructions for your computer. If you haven’t considered what happens to your code when it runs this can all sound rather magical and clever but it’s essentially a translation exercise. Making that code run fast is what’s clever.

How a simple compiler works
JavaScript is considered a high level language, meaning it is human readable and has a high degree of flexibility. The job of the compiler is to turn that high level code into native computer instructions.

Compiler architecture

A simple compiler might have a four-step process: a lexer, a parser, a translator and an interpreter.

  1. The lexer, or lexical analyser (or scanner, or tokeniser) scans your source code and turns it into atomic units called tokens. This is most commonly achieved by pattern matching using regular expressions.
  2. The tokenised code is then passed through a parser to identify and encode its structure and scope into what’s called a syntax tree.
  3. This graph-like structure is then passed through a translator to be turned into bytecode. The simplest implementation of which would be a huge switch statement mapping tokens to their bytecode equivalent.
  4. The bytecode is then passed to a bytecode interpreter to be turned into native code and rendered.

This is a classic compiler design and it’s been around for many years. The requirements of the desktop are very different however from those of the browser. This classic architecture is deficient in a number of ways. The innovative way in which these issues were resolved is the story of the race for speed in the browser.

Fast, Slim, Correct
The JavaScript language is very flexible and quite tolerant of obtuse programmatic constructs. So how do you write a compiler for a late-binding, loosely-typed, dynamic language? Before you make it fast you must first make it accurate, or as Brendan Eich puts it,

“Fast, Slim, Correct. Pick any two, so long as one is ‘Correct’”

An innovative way to test the correctness of a compiler is to “fuzz” it. Mozilla’s Jesse Ruderman created jsfunfuzz for exactly this purpose. Brendan calls it a “JavaScript travesty generator” because it’s purpose is to create weird but valid syntactic JavaScript constructs that can then be fed to a compiler to see if it copes. This kind of tool has been incredibly helpful in identifying compiler bugs and edge cases.

JIT compilers
The principle problem with the classic architecture is that runtime bytecode interpretation is slow. The performance can be improved with the addition of a compilation step to convert the bytecode into machine code. Unfortunately waiting several minutes for a web page to fully compile isn’t going to make your browser very popular.

The solution to this is “lazy compilation” by a JIT, or Just In Time compiler. As the name would suggest, it compiles parts of your code into machine code, just in time for you to need it. JIT compilers come in a variety of categories, each with their own strategies for optimisation. Some like say a Regular Expression compiler are dedicated to optimising a single task; whereas others may optimise common operations such as loops or functions. A modern JavaScript engine will employ several of these compilers, all working together to improve the performance of your code.

JavaScript JIT compilers
The first JavaScript JIT compiler was Mozilla’s TraceMonkey. This was a tracing JIT so-called because it traces a path through your code looking for commonly executed code loops. These “hot loops” are then compiled into machine code. With this optimisation alone Mozilla were able to achieve performance gains of 20% to 40% over their previous engine.

Shortly after TraceMonkey launched Google debuted its Chrome browser along with it’s new V8 JavaScript engine. V8 had been designed specifically to execute at speed. A key design decision was to skip bytecode generation entirely and instead have the translator emit native code. Within a year of launch the V8 team had implemented register allocation, improved inline caching and rewritten their regex engine to be ten times faster. This increased the overall speed of their JavaScript execution by 150%. The race for speed was on!

More recently browser vendors have introduced optimising compilers with an additional step. After the Directed Flow Graph (DFG) or syntax tree has been generated the compiler can use this knowledge to perform further optimisations prior to the generation of machine code. Mozilla’s IonMonkey and Google’s Crankshaft are examples of these DFG compilers.

The ambitious objective of all this ingenuity is to run JavaScript code as fast as native C code. A goal that even a few years ago seemed laughable but has been edging closer and closer every since. In part 3 we’ll look at some of the strategies compiler designers are using to produce even faster JavaScript.

]]>
http://creativejs.com/2013/06/the-race-for-speed-part-2-how-javascript-compilers-work/feed/ 20
The race for speed part 1: The JavaScript engine family tree http://creativejs.com/2013/06/the-race-for-speed-part-1-the-javascript-engine-family-tree/ http://creativejs.com/2013/06/the-race-for-speed-part-1-the-javascript-engine-family-tree/#comments Mon, 03 Jun 2013 12:15:59 +0000 http://creativejs.com/?p=5367 Continue reading ]]> The Javascript Engine Family Tree

These days we take it for granted that JavaScript execution in modern browsers is fast. The pages of creativejs.com are full of inspiring examples of what that speed can deliver; but it wasn’t always so…

A web browser is made up of many different components, all working together to deliver you a fast and efficient web browsing experience. Some of these components will interpret code, others will render the display, others manage plug-ins and so on. In this series of articles we’re going to look at the Javascript engine; a component responsible for compiling your Javascript code into the native instructions your computer can run.

The earliest JavaScript engine was SpiderMonkey and it arrived in 1995 with the Netscape Navigator 2.0 browser. The mythology of its rapid birth is well documented; Brendan Eich had just ten days to design the language and build it’s compiler. The Javascript language was immediately popular and by August of the following year had been adopted by Microsoft as JScript in Internet Explorer 3.0. By the end of 1996 the language was submitted for formal standardisation and arrived as ECMA-262 in June of the following year.

Support for JavaScript became a standard feature in every browser, with each vendor building an engine of their own to support it. Over the years these engines have evolved, been replaced, renamed and forked into other engines. Keeping track of all these versions, branches and code-names is not for the faint hearted.

Take for example KDE’s Konqueror browser, which made use of their open source KJS Javascript engine. Developers at Apple forked this project into what became JavaScriptCore for WebKit. This was rewritten under the codename Squirrelfish, then Squirrelfish Extreme and eventually marketed as Nitro.

The opposite also happened. There are engines where the names have remained the same but everything has changed under the hood. The JavaScript engine in Mozilla Firefox for example, is still called SpiderMonkey, but the modern engine is unrecognisable from the one that debuted in Netscape in 1995.

Javascript engine family tree

By the mid-2000’s JavaScript was standardised and prolific but code execution was still slow. A race for speed began in 2008 with a slew of new engines. At the beginning of that year the fastest engine around was Opera’s Futhark. By the summer Mozilla had introduced Tracemonkey and Google had launched its Chrome browser with a new JavaScript engine they called V8.

Despite this confusing proliferation of names, what all of these engines have in common is that they parse and execute JavaScript. What then is the difference between all these engines? Well these days they compete for speed.

What followed after 2008 were a succession of creative and innovative speed improvements in JavaScript engine design, and a race to build the fastest browser. In part 2 we’ll look at those innovations in detail and find out how your JavaScript engine works.

]]>
http://creativejs.com/2013/06/the-race-for-speed-part-1-the-javascript-engine-family-tree/feed/ 8