Javascript Engine Demystified

Javascript Engine Demystified

Deep dive into Javascript engine

Namastey🙏 to all the readers, namaste.gif Let's start the article with a positive note👇

motivational_quote.jpg Have you ever wondered🤔 how the javascript code we write runs on the machine. javascript_engine_working.gif If you don't know no problem, today we will discuss it in this article. In this article, we will discuss how the Javascript code gets converted into machine code so that it can run on the machine. As a javascript developer, having a deeper understanding of how Javascript code runs on the machine helps you to write efficient Javascript code.

What we will cover in this article

agenda.jpg

  • Explanation of Javascript runtime environment.

  • Working of Javascript engine

  • Popular Javascript engines

  • Explanation of V8 Javascript engine

  • Explanation of SpiderMonkey Javascript Engine

Explanation of Javascript runtime environment

JavascriptEngine alone can't run the Javascript code. For example, we can't run asynchronous javascript code directly inside the javascript engine, we need some components like WebAPI environment, event loop, callback queue, and microtask queue. All the above components worked together inside a container known as Javascript Runtime Environment(JRE). So to run a piece of Javascript code inside any machine we need a Javascript runtime environment. In the case of the web the JRE is browser and outside of the web, the JRE is Node js.

Now we will briefly understand the components of JRE

Javascript Engine

What you think about Javascript engine Like this👇 javascript_engine_definition.jpg No, it is not hardware instead it is also software that is written by developers like us. It is responsible to convert Javascript code to optimized machine code and then execute it. If you are not familiar with machine code then just remember that it is the language that CPU💻 understands. Machinecode👇

machine_code.jpg We will understand the Javascript engine in-depth in the coming sections of the article.

WebAPI

It helps in performing asynchronous operations in Javascript. It provides access to functions performing asynchronous operations inside Javascript code.

Callback queue

Stores the callback associated with WebAPI.

Microtask queue

Store those callbacks coming from promises and mutation observers.

Event loop

The above callback coming from either callback or microtask queue is provided to Javascript engine with the help of Event loop.

Below is the block diagram of the javascript runtime environment created after connecting all the components discussed above. Javascript runtime environment.png If you are curious in reading more about asynchronous Javascript, callback queue, event loop, and WebAPI then read this article.

Now we are familiar with Javascript engine and Javascript runtime environment so let's now understand the working of Javascript engine.

Working of Javascript engine

First, we will understand each component of the Javascript engine. To understand the working of the Javascript engine we will use the below javascript code snippet which is also used in the latter part of the article to explain different topics.

function add(a, b) {
  return a + b;
}

add(2, 3);

Intialisation environment

This component is used to initialize the Javascript runtime environment with the help of the renderer process. Each browser tab has a renderer process.

Parser

It is responsible to convert javascript code into an abstract syntax tree. The code in the above code snippet is broken down into tokens.

tokens.JPG After breaking the code into tokens it is passed to syntax parser which converts it into an Abstract Syntax Tree(AST). It is a tree representation of javascript code. Below is the Abstract syntax tree generated for the above code snippet

AST.JPG

Interpreter

The interpreter receives the AST then analyzes the code line by line and converts it into bytecode. Command to generate bytecode in node js for a particular function, in our context for add function

node --print-bytecode --print-bytecode-filter=<function name> <javascript filename>

Below is the generated bytecode for the above code snippet

bytecode.png

Optimizing compiler

To make Javascript code run faster, the bytecode can be sent to the optimizing compiler along with profiling data. The optimizing compiler makes certain assumptions based on the profiling data it has and then produces highly-optimized machine code. If at some point one of the assumptions turns out to be incorrect, the optimizing compiler deoptimizes and goes back to the interpreter.

Execution

The bytecode is executed by using the Memory heap and the Callstack. The memory heap is the place where all the functions and variables are assigned to memory. Callstack is the place where each individual functions, when called are pushed to the stack and popped out after their execution. Any unused memory found during the program is freed by the garbage collector

After understanding each component we are in a better position to understand the full picture of the javascript engine. Below is the high-level block diagram of the javascript engine.

Higher level view of JavaScript Engine.JPG Summarising the working of the javascript engine with the help of the following steps:-

  • The parser converts the javascript code into an abstract syntax tree.

  • Interpreter takes the abstract syntax tree as input and converts it into bytecode.

  • Optimizing compiler optimizes bytecode based on certain assumptions by using profiling data and deoptimizes if the assumption is wrong

  • The bytecode generated by the interpreter is finally executed by the callstack and memory heap.

We have seen the working of the javascript engine. Now, let's check what are the popular JavaScript engines available.

Popular javascript engines

V8 - V8 is an open-source engine developed by Google and it is written in C++. It is used inside Google chrome,Node.js and Deno.

Spider Monkey - It is the first javascript engine created by Brendan Eich founder of javascript. Initially, it powered the Netscape Navigator browser and today powers Firefox and SpiderNode.

Chakra - It is Microsoft's javascript engine used in Microsoft Edge browser and Node-ChakraCore.

JavaScriptCore - It is an open-source engine developed by Apple for the Safari browser.

JerryScript - It is a lightweight engine that is used in applications based on the Internet of Things.

In this article, we will discuss only V8 and SpiderMonkey as V8 is the fastest javascript engine available today and SpiderMonkey is the first javascript engine.

V8 Javascript Engine

V8_engine_logo.png V8 compiles Javascript code into machine code at execution by implementing a JIT(Just-In-Time) compiler. The V8 engine initially uses an interpreter, to interpret the code. On further executions, the V8 engine finds patterns such as frequently executed functions, frequently used variables, and compiles them to improve performance. Suppose the performance degrades or the parameters passed to the function change their type, then the V8 simply decompiles the compiled code and falls back to the interpreter.

Working of the V8 engine

working_of_v8_engine.JPG When V8 compiles Javascript code, the parser generates an Abstract syntax tree. The AST is passed to the ignition interpreter which is responsible for generating and executing bytecode. While it runs the bytecode, it collects profiling data, which can be used to speed up the execution later. When a function becomes hot i.e when it's run often, the generated bytecode and the profiling data are passed on to TurboFan optimizing compiler, which generates highly optimized machine code based on the profiling data and feedback. The V8 engine is provided with the Orinoco Garbage Collector which internally uses the Mark and Sweep Algorithm to free up space from the memory heap.

How the TurboFan compiler generates optimized machine code?

The compiler uses the Inline caching technique for optimization. Inline caching is a technique used to prevent generating bytecode for repeated function calls. Check below code snippet to understand inline caching

inline_caching.JPG Now to further strengthen our knowledge of javascript engines, we will also look into another javascript engine.

Spider Monkey javascript engine

spider monkey logo.png The working of Spider Monkey javascript engine is mostly the same as V8 but instead of using one optimizing compiler, it uses two optimizing compilers. The baseline compiler optimizes those portions of bytecode that are marked as hot . The generated optimized code is passed to the IonMonkey compiler with profiling data to generate highly optimized code. If the assumption made for optimization by the IonMonkey compiler fails, it falls back to the baseline compiler.

working_of_spider_monkey_engine.JPG

Conclusion

Congratulations on reading until the end👍

well_done.gif In this article, you've learned

  • what is the Javascript runtime environment and explanation of its different components
  • what is Javascript engine and a block diagram to explain it
  • V8 javascript engine explanation
  • Spider monkey javascript engine explanation

I hope you enjoyed😃 reading the article. Thanks for reading!!

thank_you1.gif Please provide feedback on the content of the article. You can connect with me on social media👇

LinkedIn || Twitter

For further information related to this article check below resources👇

Resources and Credits