Skip to main content
May 20, 2015
Mobile

Delivering fast JavaScript performance in Microsoft Edge



In Windows 10 and Microsoft Edge we’ve made a lot of performance advances in the Chakra JavaScript engine. All with the goal of letting your JavaScript code run faster, taking as much advantage of the underlying hardware as possible, so that the web you create and experience in Microsoft Edge provides consistently delightful user experiences across all form factors. Amongst others, one of the key themes for our team during this release has been to closely look at data from customer feedback and telemetry reports, and tune the engine to run fast on the existing web, i.e. the web as it exists today.

A while back, we detailed some of the performance enhancements that we’ve made in the Chakra JavaScript engine in Windows 10 for Microsoft Edge. Improving performance is a never ending theme. In this post we detail some enhancements that we’ve done to Chakra’s JIT compiler, based on feedback and telemetry data from the web as it exists today.

Cross file script inlining

All modern JavaScript compilers support function inlining as a key optimization. Function inlining occurs when the function body of a called function is inserted, or inlined, into the caller’s body as if it was part of the caller’s source, thereby saving the overhead of function invocation and return (register saving and restore). In performance sensitive code paths, inlining could provide up to 20-30% performance boost.

While inlining, all compilers need to play a balancing act. For example, beyond a particular size threshold, the compiler might end up spending more time providing the inlined code’s contextual information to produce optimized JIT code than the time it actually saves by the reduced call overhead. Similarly, when trying to inline functions that are coming from another context or script file, the cost of work that needs to be done (like providing the contextual information) could outweigh the performance benefits that inlining provides.

During the development of Windows 10 and Microsoft Edge, we gathered some data from the existing web to understand how Chakra’s inlining optimization was working on the web. We looked at a randomly selected sample of 3,000 sites from the list of top 10,000 sites and following is what we found:

 Diagram showing inlining on top 3000+ sites  Diagram showing per-site breakdown of cross-script inline restrictions
Chakra inlined only 31% of function calls; 48% of the functions were not getting inlined as the caller and callee functions lived in separate script files Using another view, more than half of the sites in our sample were not inlining 60% or more functions

In Windows 10 and Microsoft Edge, Chakra’s JIT compiler and the execution pipeline has been optimized such that Chakra can now efficiently inline functions that are defined across JavaScript files, without losing the performance benefits achieved via inlining. This optimization enables a lot more JavaScript code on the existing web to get inlined and run faster in Microsoft Edge.

Speeding up global constants using fixed field optimization

ECMAScript6 brought the concept of const values to the JavaScript language. Apart from the language and tooling benefits that constants bring to JavaScript developers, they allow JavaScript compilers to optimize look-up performance. When a property is declared as a const, compilers are sure that the value of that property would not change over the lifetime of the program. And given this guarantee, compilers can optimize to avoid look-up costs for such properties. Look up cost includes the cost to check the type/shape/internal representation of the property, figuring out the actual value stored in the property, and checking whether the value has changed during the course of program execution. For constants, the compilers don’t need to do any of the abovementioned checks.

While the usage of const is catching up on the web, a majority of the existing web does not use the const construct today. Instead, in today’s web, most of the times constants are defined once as a variable on the global object and then used everywhere in the code. In one of the experiments we did with 10,000+ sites on the web, we found that more than 20% of the sites had occurrence of such patterns for defining integer constants, and the average was more than 4 such occurrences per site.

In Windows 10 and Microsoft Edge, we’ve started optimizing Chakra’s parser and the JIT compiler to identify non const variable declarations of integers that are defined globally and are never changed during the course of the execution time of the program. Once identified, the JIT’ed code produced by Chakra is able to substantially reduce the lookup cost associated with such globally defined variables that do not change their shape and value during the execution lifetime of the program, thus extending the performance oriented value proposition of the const statement in ECMAScript 6 to how constants are often used in the web as it exists today.

Improving performance of code within try-catch blocks

Using try-catch is very common on the web as it exists today. However, using try-catch is typically not a recommended best practice, especially when the code path is performance sensitive. Try-catch code is hard to optimize because most operations inside the try block can cause an exception and go to the catch.  This flow is too expensive to model precisely in a JIT compiler.  Different techniques need to be used to model this, which create an additional overhead that needs to be taken care of by the execution machinery.

In a data gathering experiment we did on a sample of top 4500 sites, we noticed that more than 96% of the sites threw JavaScript exceptions caught by script code. In fact, more than 50% of sites threw more than 10 JavaScript exceptions that were handled by script code.

Until Windows 10, Chakra did not optimize code inside of try-catch blocks. In Windows 10 and Microsoft Edge, Chakra’s compiler now has the capability to abstract out the code defined inside of the try-catch blocks and generate optimized JIT code for it. For cases where an exception is not thrown, Chakra now executes such code inside a try block almost on par with regular JIT’ed code (as if the try-catch never existed).

Minified code now brings size and speed benefits

Given the advantages of reducing the size of content to be pulled down to a client (browser), usage of minified JavaScript code is common in today’s web. While investigating a particular performance issue during the Windows10 release, one of the things we found was that some instances of minified code (minified using UglifyJS) were not performing as well as their non-minified equivalent were. In some cases minifiers use code patterns that we thought developers typically don’t use, which is why Chakra had not optimized for the same. So we did a quick experiment to see how common minification is on the web. Out of the top 10,000 sites, we took a random sample of around 4,000 sites and below is what we found:

Minification on Top 4000 sites
 Chart showing 95% of sites had some form of minified code  Chart showing that 77% of these sites had code minified using UglifyJS  Chart showing out 47% of those sites used jQuery minified via UglifyJS
95% of the sites had some form of minified code Out of the 95%, 77% sites had some code that was minified using UglifyJS Out of the 95%, 47% of the sites used jQuery minified via UglifyJS

The experiment confirmed that usage of minified code is extremely popular on the web as it exists and amongst others, UglifyJS is very commonly used in today’s web. So in Windows 10 and Microsoft Edge, we’ve added new fast paths, improved inlining and optimized some heuristics in Chakra’s JIT compiler to ensure that minified code runs as fast, if not faster than the non-minified versions. With these changes, the performance of individual code patterns minified using UglifyJS that we tested, improved between 20-50%.

Array#indexOf optimizations

Usage of arrays is pervasive on the web. Apart from providing polyfills and helper functions, a lot of JavaScript libraries out in the wild try to provide faster implementation of some of the standard Array built-ins that come as a part of the JavaScript language. In an ideal world, all browsers should be fast enough on these built-ins such that libraries could focus more on the polyfill and helper API aspect, rather than having to worry about fixing the performance of built-ins across browser implementations. Stating another way, developers should never feel forced to use a library just to make some of the basic built-ins implemented by all JavaScript engines run faster.

Though we are far away from the ideal world mentioned above, in one of the other of data gathering exercises that we recently did, we tried to measure the most used ECMAScript 5 built-ins on the web as it exists today. The experiment was carried out on a random sample of ~4000 of the top 10,000 sites. The top three hits that we found were: Array#indexOf, Array#map and Array#forEach.

Given the popularity of Array built-ins on the web, in Windows10 and Microsoft Edge, Chakra has optimized how values are retrieved, while the engine traverses a given array. This optimization helps remove the extraneous overhead of visiting the prototype chain and looking up the numeric property corresponding to the index, when holes are encountered in an array. This optimization helps improves the performance of ECMAScript5 Array#indexOf built-in in Chakra and Microsoft Edge by more than 5 times.

So, are we fast yet?

Most of the optimizations that we detailed above are based on data from the web as it exists today, and help the existing web run fast in Microsoft Edge. That said, as much as we’d not like to talk about synthetic benchmarks, we often get asked about how (Chakra in) Microsoft Edge performs on popular JavaScript benchmarks. Here’s a look at the performance enhancements that we’ve delivered so far in Microsoft Edge on two JavaScript benchmarks, vis-à-vis IE11 and other popular browsers.

Chart showing Microsoft Edge leading at Octane 2.0 versus IE11, Chrome Canary, and Firefox Alpha, with a score of 23507 Chart showing Microsoft Edge leading at Jet Stream versus IE11, Chrome Canary, and Firefox Alpha, with a score of 154
All measures collected on 64-bit browsers running 64-bit Windows 10 Technical Preview
System Info: HP Compaq 8100 Elite with Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz (4 cores), 12GB RAM

What do these charts tell? Chakra in Microsoft Edge is way faster than IE11. Looking closely, Chakra has made the following improvements across these benchmarks in Microsoft Edge:

Benchmark Owned By Improvements in Microsoft Edge over IE11
Jet Stream Apple More than 1.6 times faster
Octane 2.0 Google More than 2.25 times faster
Note: In case you are curious why these charts measure the performance of 64-bit browsers instead of 32-bit browsers, the reason is that unlike IE11, Microsoft Edge runs the 64-bit web platform underneath whenever possible. While all modern 64-bit JavaScript engines run a tad bit slower than their 32-bit counterparts, choosing a 64-bit web platform provides several security advantages, some of which are outlined in this blog.

While winning on a benchmark that is not created by us does feel nice, the key is that Microsoft Edge has already come a long way from IE11 in terms of improved JavaScript performance on both, benchmarks and real world web as it exists today.  As mentioned in the beginning, performance is a never-ending pursuit. We will continue pushing the performance boundaries for JavaScript in Microsoft Edge. Please keep your feedback coming, as that helps us improve! You can file a bug at Connect , add feedback on UserVoice, or reach out to us on twitter via @MSEdgeDev.

– Gaurav Seth, Principal PM Lead, Chakra