Improve Browser performance using Bytecode Caching

Bytecode Compilation can reduce JavaScript Execution Time on an Embedded Platform

Improve Browser performance using Bytecode Caching
Bytecode caching flow

Web Browsing is one of the most important software for computing devices like Smartphones, Tablets, and Laptops, etc. The user visits a set of websites and it dominates the total browsing times. Modern Browsers cache downloaded resources in local disks such as HTML, JavaScript, and Image files. While saving network bandwidth, resource caching does not eliminate redundant computation for processing these files and it does not improve browser performance.

Bytecode Caching:

Most Common usage pattern of Browser is that a small number of web pages visited repeatedly and it made an opportunity for cross execution program optimization via data reuse since most downloaded resources for a website are reusable. Moderns exploit this by caching these resources in local disks or memory. It reduces the amount of network traffic to the server but doesn’t eliminate redundant computation.

Efficient memory bytecode caching technique can significantly improve web browser performance and reduce memory footprint.

Augmented Bytecode in Background:

JavaScript engine is a virtual machine, executes scripts written in JavaScript, which is an account for a large portion of web browser execution time. JavaScript is a dynamic language for which is exact variable is known only on runtime and it is difficult for a static compiler to produce efficient codes. Thus, bytecode interpreters which augmented with Just-In-Time compilation are widely used. JIT compiler invoked to produce an optimized native binary for caching. At the next time of execution, the program control jumps directly to the native binary instead of running the interpreter loop. So it performs far better than interpreted bytecode and significant in terms of CPU cycles and memory footprint.



JavaScript also provides an eval function that evaluates an arbitrary expression represented in String and increases the flexibility of execution. It can be useful in several tasks like adding and removing fields, trapping errors, deserializing JSON objects, etc but it has some bad side effects for Performance and Security. Eval function can change dynamically, so dynamic compiler should generate bytecodes at every invocation of the function. This makes it slow to execute and an adversary can make the browser execute malicious script through eval to compromise the browser.

Implementation:

First, JavaScript methods or eval function is parsed to generate an abstract syntax tree(AST), which is compiled into bytecodes. In JavaScript engine, if the compiled code is executed over 10 times, the bytecode would be translated into a simple native code by JIT compiling. If the code executed over 1000 times, the hot code would be translated into a more optimized native code. This structure used by most popular JS engines like SpiderMonkey, Apple engine, V8, etc.

Improve Browser performance using Bytecode Caching
Augmented engine with In-memory cache

Each JavaScript method compiled into bytecodes which are encapsulated in an object in the JS engine. To serialize and deserialize this object, and external data representation (XDR) API is used for the JavaScript engine, similar mechanisms exist for other JavaScript engines.

The scope of an eval function is determined dynamically, SpiderMonkey generates bytecodes for eval functions and ordinary JavaScript methods differently. It compiles into bytecode only at the first invocation and reused trough in-memory cache in every session.

In-memory caching is not beneficial for every JavaScript methods, it needs to be devised to determine which methods to reuse. The basic principle is that a method is cached only if it takes a significantly longer time to compile than deserialize.

Evaluation:

To compare the performance difference with and without I/O accesses, all bytecode files are flushed from the buffer cache (using blockdev -flushbufs command) before measurement for file caching. In-memory caching reduces the total JavaScript execution time by 24.9% over the out-of-the-box engine on embedded platforms.

Improve Browser performance using Bytecode Caching
Compilation time for caching heuristic

Both eval functions and JavaScript methods are relatively insensitive to a change of threshold value as they feature a large flat region in the performance curve on the embedded platform.

In-memory bytecode caching significantly improves the performance by amortizing the compilation cost via cross-invocation data reuse. To reuse efficiently specific methods that can benefit from code caching. Read more here.

Let me know your thoughts about this article as a response.

Leave a Reply

Your email address will not be published.