Inside the JavaScript Engine

A brief explanation of the JavaScript Engine

Aditya Yaduvanshi
Dev Genius

--

A couple of days ago we started a series aimed at digging deeper into JavaScript and how it actually works: we thought that by knowing the building blocks of JavaScript and how they come to play together you’ll be able to write better code and apps.

The first post of the series focused on providing an overview of the engine, the runtime and the call stack. This second post will be diving into the internal parts of the JavaScript engine. In this article, we will also know why JavaScript is not an Interpreted Language anymore.

What is JavaScript Engine?

So a JavaScript Engine is simply a computer program that executes JavaScript code. There are a lot of steps involved in doing that, but essentially executing JavaScript code is what an engine does. Now every browser has its own JavaScript Engine but the most well-known engine is Google’s V8. The V8 engine powers Google Chrome, but also Node.js which is the JavaScript Runtime that we talked about in the last article, the one that we can use to build server-side applications with JavaScript, so outside of any browser. Anyway, it’s quite easy to understand what an engine is but the most is to actually understand its composition and how it works.

The Engine consists of two main components:
* Memory Heap — this is where the memory allocation happens
* Call Stack — this is where your stack frames are as your code executes

Memory Heap & Call Stack

So any JavaScript engine always contains a Call Stack and a Heap. The Call Stack is where our code is actually executed using something called execution contexts. Then the heap is an unstructured memory pool that stores all the objects that our application needs. Alright, so with this look at the engine, we have answered where our code is executed. But now the question is how the code is compiled to machine code so that it actually can be executed afterward. So let’s find out.

Compilation & Interpretation

First, we need a quick computer side note and talk about the difference between compilation and interpretation. We know that the computer’s processor only understands 0’s and 1’s. That’s therefore every single computer program ultimately needs to be converted into machine code and this can happen using compilation or interpretation.

Compilation

So in Compilation, the entire source code is converted into machine code at once. And this machine code is then written into a portable file that can be executed on any computer. So we have two steps here. First, machine code is built and then it is executed in the CPU so in the processor. And the execution can happen way after the compilation. For example, any application that you are using on your computer right now has been compiled before and you are now executing it way after its compilation.

Compilation

Interpretation

On the other hand, in Interpretation, there is an interpreter which runs through the source code and executes it line by line. So we do not have the same two steps as before. Instead, the code is read and executed all at the same time. Of course, the source code still needs to be converted into machine code, but it simply happens right before it’s executed and not ahead of time.

Interpretation

Just-in-time Compilation

JavaScript used to be a purely interpreted language but the problem with interpreted languages is that they are much, much slower than compiled languages. This used to be okay for JavaScript, but now with modern JavaScript and fully-fledged web applications that we built and use today, low performance is no longer acceptable. Just imagine you were using Google Maps in your browser and you were dragging the map and each time you dragged it would take one second for it to move. That would be unacceptable, right?

Now many people still think that JavaScript is interpreted language, but that’s not really true anymore. So instead of simple interpretation, Modern JavaScript engine now uses a mix between compilation and interpretation which is called Just-in-time(JIT) compilation.

Just-in-time compilation

This approach basically compiles the entire code into machine code at once and then executes it right away. So we will have two steps of regular ahead of time compilation, but there is no portable file to execute. And the execution happens immediately after the compilation. And this is perfect for JavaScript as it’s really a lot faster than just execution code line by line. And now we know JavaScript has not interpreted language anymore.

MODERN JUST-IN-TIME COMPILATION OF JAVASCRIPT

So as a piece of JavaScript code enters the engine. The first step is to parse the code which essentially means to read the code. During the parsing process, the code is parsed into a data structure called the Abstract Syntax Tree (AST). This works by first splitting up each line of code into pieces that are meaningful to the language like const or function keywords and then saving all these pieces into the tree in a structured way. This step also checks if there are any syntax errors and the resulting tree will later be used to generate the machine code.

Now let’s say we have a very simple program. All it does is declare a variable in shown example and on the right-hand side, it is an AST for just one line of code looks like. So we have a variable declaration that should be constant with the name “a” and the value of “23”. And besides that, there is lots of stuff here as you can see. So just imagine what it would look like for a large real application.

The next step is a compilation which takes the generated AST and compiles it into machine code just we learned before in this article. This machine code is executed right away because Modern JavaScript uses Just-in-time compilation. And remember execution happens in the JavaScript engine’s Call Stack. We will dig deeper into this in the next article.

Just-in-time compilation for JavaScript

All right, so far so good. We have our code running so we can finish here Right? Well, not so fast because Modern JavaScript engines actually have some pretty clever optimization strategies. What they do is to create a very unoptimized version of machine code in the beginning just so that it can start executing as fast as possible. Then in the background, this code is being optimized and recompiled during the already running program execution. This can be done most of the time and after each optimization. The unoptimized code is simply swept for the new more optimized code without ever stopping execution. And this process is what makes modern engines such as V8 so fast.

And all this parsing, compilation and optimization happens in some special threads inside the engine that we can not access from our code. So, separate from the main thread that is basically running into the call stack executing our code. Now different engines implement in slightly different ways, but in a nutshell, this is what Modern Just-in-time compilation looks like for JavaScript. Next time someone tells you JavaScript is an Interpreted language, you just show them this article so that they can learn how it really works.

Alright, so we looked at the JavaScript Engine and how it really works behind the scenes in quite some detail. I hope the article above helps you with understanding the JavaScript Engine. For now, let’s end it here. There will be the next article on JavaScript Runtime and other components as well which are very important. So to keep following this series, follow me on Twitter or Medium.

I would suggest you to take Jonas Schmedtmann’s JavaScript course. It is the best JavaScript course i have linked it below.

https://www.udemy.com/share/101WeY3@3pMWHQSgN9D9VC3dOQ1MFS9rnDNm-QIvj0yc_HPaIcxhsmXJcvwnk7eNy_HNeIr2/

Don’t forget to read the first post of this series, I have linked it below.

If you enjoyed this article, kindly spread the word. To get updates for my new stories, follow me on Medium and twitter.

--

--