Year in review: Spidermonkey in 2014 part 2

In the first part of this series I noted that the major changes in Spidermonkey in 2014 were about EcmaScript 6.0 compliance, JavaScript performance and GC improvements. I also enumerated the major changes that happened starting from Firefox 29 till Firefox 31 related to Spidermonkey. If you haven’t read the first part yet, I would encourage you to do that first. In part two I will continue iterating the major changes  from Firefox 32 till Firefox 34.

<- Year in review: Spidermonkey in 2014 part 1

Firefox 32

Recover instructions

During the Firefox 32 release recover instructions were introduced. This adds the possibility to do more aggressive optimizations in IonMonkey. Before we couldn’t eliminate some instructions since the result was needed if we had to switch back to a lower compiler tier (bailout from IonMonkey to Baseline). This new infrastructure makes it possible to recover the needed result by adding instructions to this bailout path. As a result, we still have the needed results to bailout, but don’t have to keep a normally unused instruction in the code stream.

Read more about this change
Read more about this in the bug report

Irregexp

Internally there has been a lot of discussion around the regular expression engine used in Spidermonkey. We used to use yarr, which is the regular expression engine of Webkit. Though there were some issues here. We sometimes got wrong results, there were security issues and yarr hasn’t been updated in a while. As a result we switched to irregexp, the regular expression engine in v8 (the JS engine in Chrome). In the long run this helps by having a more up to date engine, which has jit to jit support and is more actively tested for security issues.

Read more about this in the bug report

Keep Ion code during GC

Another achievement that landed in Firefox 29 was the ability to keep ionmonkey jit code during GC. This required Type  Inference changes. Type information (TI) was always cleared during GC and since ionmonkey code depends on it, the code became invalid and we had to throw the Ion code away. Since a few releases we can release Type information in chunks and since Firefox 32 we keep ionmonkey code that is active on the stack. This result in less bumps in performance during GC, since we don’t lose the Ion code.

Read more about this in the bug report

Generational GC

Already going back to 2011 Generational GC was announced. But it took a lot of work before finally accomplishing this. In Firefox 29 exact rooting landed, which was a prerequisite. Now we finally use a more advanced GC algorithm to collect the memory and this also paves the way for even more advanced GC algorithms. This narrowed the performance gap we had on the Octane benchmark compared to V8, which already had Generational GC.

Read more about this change

Firefox 33

8 bit strings

Since the first Spidermonkey release strings were always stored as a sequence of UTF-16 code units. So every string takes 16 bits per character. This is quite wasteful, since most of the strings don’t need the extended format and the characters actually fit nicely into 8 bits (Latin1 strings). From this release on strings will be stored in this smaller format when possible. The main idea was to decreases memory, but there were also some performance increases for string intensive tasks, since they now only need to operate over half the length.

Read more about this change

Firefox 34

ES6 template strings

ES6 will introduce something called template strings. These template strings are surrounded by backticks ( ` ) and among others will allow to create multi-line strings, which weren’t possible before. Template strings also enable to embed expressions into strings without using concatenation. Support for this feature has been introduced in Firefox 34.

Read more about ES6 template strings.

Copy on write

Some new optimization has been added regarding arrays. Before, when you copied an array, the JavaScript Engine had to copy every single item from the original array to the new array. Which can be an intensive operation for big arrays. In this release this pain has been decreased with the introduction of “Copy on write” arrays. In that case we only copy the content of an array when we start modifying the new array. That way we don’t need to allocate and copy the contents for arrays that get copied but not modified.

Read more about this in the bug report.

Inline global variable

A second optimization was about inlining constant global names and constant name access from singleton scope objects. This optimization will help performance for people having constant variables defined in the global scope. Instead of reading the constants out of memory every time the constant will get embedded into the code, just like if you would have written that constant. So now it is possible to have a “var DEBUG = false” and everywhere you test for DEBUG it will get replaced with ‘false’ and that branch will be removed.

Read more about this in the bug report

SIMD in asm.js

SIMD or Single Instruction Multiple Data makes it possible to execute the same operations on multiple inputs at the same time. Modern cpu’s already have support for this using 128-bits long vectors, but currently we don’t really have access to these speedups in JavaScript. SIMD.js is a proposition to expose this to JavaScript. In Firefox 34 experimental support (only available in Firefox Nightly builds) for these instructions in asm.js code were added. As a result making it possible to create code that can run up to 4x faster (Amdahl’s law) using SIMD. Now work is underway to fully optimize SIMD.js in all Ion-compiled JS. When this work is complete, and assuming continued progress in the standards committee, SIMD.js will be released to all Firefox users in a future version.

Read more about this change
Read more about this in the bug report
View the SIMD.js demos

Update: The next post in this series has been published:
Read part 3 of ‘Year in review: spidermonkey in 2014′ ->

Year in review: Spidermonkey in 2014 part 1

Spidermonkey, the JavaScript engine used in Mozilla Firefox, has undergone big changes in 2014. Just like I did last year I’ll go over the major changes that landed throughout the year. Though this time I’ll split the post into a series of three or four posts. This will allow me to explain the changes a bit more in depth and also keep the posts lighter.

Looking back at 2014 most changes that happened were to improve to the Garbage collection (GC) algorithm, improve our second (Baseline) and third tier compiler (IonMonkey) and implement the EcmaScript 6 (ES6) specification. After months of preparation 2014 was the year for our GC team. We finally came to a state where we improved the Garbage Collection algorithm dramatically.  We also still kept looking to the Octane 2.0 benchmark while also other benchmarks started to get on our examination table more often (BrowserMark, jsbench, dromaeo …). Throughout the year we achieved again a 40% improvement to our Octane score and Browsermark 2.1 improved with 5%, showing the huge effort of everybody involved. Nexto performance improvements we also increased our efforts implementing the ES6 standard. While the standard isn’t released yet, it will get released soon and we want to support most things before that happens.

In this first part I will look at the first three releases that were developed in 2014: Firefox 29 to Firefox 31.

Firefox 29 a.k.a Australis

ARM simulator

Our JavaScript engine is tested quite elaborately on desktop machines (i686 and x86_64 chipset), but less extensively on phones (ARM chipset). Most developers don’t have spare systems running these chips and if they have it is quite hard to set up a testing environment. To improve the situation the ARM simulator of Chrome has been ported to Mozilla. This makes it possible to test, run or debug the biggest and most error prone part of the JavaScript engine (JIT code) on a regular desktop by simulating the ARM instructions. As a result phones should now experience an even more stable JavaScript engine.

Read more about this in the bug report.

Recompile without invalidation

Our highest and fastest tier to run JavaScript code, IonMonkey, was not able to recompile (Ion) code for a JS function while the old Ion code was still present. One had to first throw the old Ion code away, before starting a new IonMonkey compilation for that particular JS function. This was mostly not an issue since recompilation mostly happens when the old Ion code is not correct anymore (E.g. when we observed a new type). For a few cases this was not optimal. Therefore since this release we can recompile a JS function while keeping the old Ion code, until the compilation is finished. The benefits are twofold here. Recompiling a function with an entry at a loop nexto the function entry (OSR) is now less expensive. Secondly this might brings us closer to “Optimization levels” where we want to recompile a JS function with more optimizations, taking longer to compile, and in the meantime run the current old ion code.

Read more about this in the bug report.

EcmaScript 6: Promises

In Firefox 29 ES6 Promises were also enabled by default. Though this is not really the work of the Spidermonkey team, but from the DOM team. Firefox is already using this improvement to the Javascript language, proposed for Harmony (ECMAScript 6) in the frontend extensively and now it was deemed that the specification about Promises wouldn’t change much anymore, making it safe to release on the web.

Read more about Promises.

Exact Stack Rooting

Most higher level languages, just like JavaScript, provide automatic memory management (Garbage collection). This removes the need for developers to free resources themself when they are not needed anymore. (I.e. when they are dead). Our current Garbage collection (GC) algorithm was approximate as it didn’t know exactly which objects were alive, so it had to be conservative. Exact stack rooting was all about changing that to make sure we now exactly which objects are live. This brings some overhead since we now must keep track of every object using a container (rooting), but it also is the most important thing needed before we can start experimenting with more advanced GC schemas like Generational GC and Compacting GC.

Read more about this in the bug report.

Firefox 30

EcmaScript 6: Generators

Basic support of ES6 generators has landed. This new feature adds the support of generator functions and the yield statement and got many people excited. Normally a function runs to completion and returns the result. This is different for generators. Such a function will stop at a yield instruction and upon next execution go further at that yield till the next yield or termination of that function. In this release the support for the Interpreter, our lowest tier, has landed.

Read more about Generators.

Improve type information at branches

JavaScript is a weakly typed or even untyped language. So every instructions has to work with every type. In order to specialize an instruction and make it faster the instructions get annotated with observed types (Type Inference). This works mostly fine, except at branches. It happens a lot at branches that a variable gets tested for being not null and undefined or having a specific type. This information gets lost and we keep using the full type information of that variable in the succeeding code. With this release an infrastructure has been added to reason about these branches in our highest optimization tier, IonMonkey and decrease the types accordingly.

Read more about this in the bug report.

Enable IonMonkey for chrome scripts by default.

IonMonkey was introduced in Firefox 18, more than a year ago, and it has been enabled  by default for quite some time for normal scripts. But it wasn’t enabled for Firefox its own UI and addons (chrome content). Firefox only used the interpreter and baseline in that case. Since this release IonMonkey and TI sort of graduated and TI and IonMonkey for chrome scripts is now enabled by default. A huge win for addons, since they now can get the full JavaScript performance potential of IonMonkey.

Read more about this in the bug report.

Firefox 31

EcmaScript 6: more math methods

ES6 proposes a lot of new Math methods like Math.sign, Math.log2, Math.imul, Math.trunc, Math.cosh, Math.hypot … Most things were already possible to do in JS with some extra code, but now there are functions standardized, making it easier to perform such operations.

Faster ES6 arrow functions

This release also brought performance improvements to the arrow function introduced by ES6. Using arrow functions should now have a similar performance as normal functions, which means an improvement of up to 64 times. This is important since having bad performance for new ES6 features will also decrease the uptake of these new features and apparently our frontend Firefox developers already use this new feature a lot.

Read more about this.

Backtracking register allocator

Just like a regular compiler IonMonkey needs to fit the used variables into a limited set of registers. This is done using a register allocator.  IonMonkey has the ability to run with different register allocators. It uses by default LSRA, but also acquired a backtracking register allocator. This new allocator, based on the new register allocator used in LLVM 3.0, should be faster and improve the allocated registers. For octane-zlib this was an improvement of 21%. In this release this new allocator is enabled by default for asm.js code. Pending some bugs and performance issues on regular code, it will also get enabled by default in normal IonMonkey code in 2015.

Read more about the LLVM 3.0 register allocator.
Read more about this in the bug report.

Update: The next post in this series has been published:
Read part 2 of ‘Year in review: spidermonkey in 2014’ ->