Javascript Just In Time Compilation (jit)

BRIEF SUMMARY ON HOW THE JIT WORKS

Javascript Just In Time Compilation (jit)

As you may already know, JavaScript is a web programming language that is high-level, dynamic, and interpreted or as you will learn at the conclusion of this article "Just- in-time Compiled". You should at least have the basic knowledge on how interpreters and compilers work, if you don't i've got you. An interpreter converts a single program statement into machine code at a time while the compiler scans the entire program and instantly converts it all to machine code. Screenshot 2022-09-26 at 07.58.29.png

What is the JIT

Just in time compilation (JIT) is a hybrid of compilation and interpretation that converts all of the source code into machine code before immediately executing it. Because of this, we can compile ahead of time, but there isn't a portable file to run, therefore execution occurs right away.

JavaScript before JIT

JavaScript has changed and grown through time and its always a good practice to know and have an idea of what was, what is and finally what is to come. So let us flashback briefly to how the javascript was before the JIT. First implemented in 1995, JavaScript was with a design that wasn't optimized for speed but as time passed speed became a necessity. Next competition among browsers became fiercer, in the early 2008 High performance was no more optional but now mandatory to stay in business, Just-In-Time (JIT) compilers have been implemented in several browsers. The JIT was able to analyze the running JavaScript for patterns and optimize the code accordingly. An important tipping point in JavaScript performance occurred when these JITs were introduced. The speed with which JavaScript was executed was increased tremendously. As a result of this enhanced speed JavaScript is now being utilized in contexts where it was never before considered viable such as server-side programming using Node.js. Thanks to the enhanced speed a broader range of issues are now being solved using JavaScript.

The Javascript Engine

To understand how the GIT works a basic knowledge on the JavaScript Engine is required The computer only understands machine language while the programmer writes their program in a high level language (JS) which the computer doesn't understand until it is transformed by the JavaScript engine. In essence, the JavaScript engine's task is to translate javascript source code into a form that computers can understand.

To illustrate. You speak only English and you are in Germany with friend who speaks both german and english and you two visit a restaurant, the waitress speaks only german. What ever you will have to order in the restaurant you will have to tell your friend so he interprets to the waiter so she can take your order. In this case you are programmer, english is your high-level language the waiter is the computer and german is the machine code your friend is the JS engine because he serves as the middle man between the waiter and you.

Detail on what goes on in the JavaScript Engine in line with the JIT

In the JavaScript engine this is the order of execution of a program.

  • Parsing

  • Compilation

  • Execution

  • Optimization

Screenshot 2022-09-26 at 07.20.06.png

Parsing

As a piece of JavaScript gets to the engine the code is first read (Parsing) while being read it is passed into the Abstract syntax tree(AST), firstly split all the meaningful data (function, variables), which are then placed in a data structure that contains all the information about a specific data.

Compilation

This takes the AST that was created and converts it into machine code ( zeros and ones ) this machine code is executed right away hence the name Just In Time (JIT) in the javaScript Engine call stack.

A more detailed explanation

As a solution to the JavaScript interpreters inefficiency where the interpreter must continually translate the code each time they traverse the loop, browsers adopted a new future called the Monitor. This component will profile it and record the frequency with which various statements are used. The same lines of code are referred to as warm if they are executed a few times and is referred to as hot if it is often run. Warm code are sent by the JIT to the Baseline compilers while hot code to the optimizing compiler.

Baseline compilers The warm section of codes are compiled into Bytecode which is run by an interpreter also the baseline compiler optimizes code producing "stubs" for each instruction that is being inspected, the baseline compilation will also make an effort to optimize the code.

Optimizing compilers When a code becomes extremely hot, the monitor sends it to the optimizing compiler. This will generate a faster version of the function. Ok as you know a stub is created for every function, for the hot code it contains a whole lot of element hence multiple stubs for each of the specific function is created which have quite some similarities, so for the optimizing compiler to work faster it makes some presumption, some examples of such presumptions are

  • Weather or weather not an element is an array.

  • Weather or weather not the values of giving data structure are integers, alphabets or alpha-numeric data.

  • If the returned value from certain functions are strings or any other data type.

Of course this assumption aren't always right, an array might have 200 data the 190 being strings and the remaining 10 numbers, so the compiled code are checked before they run to see whether the assumptions are correct. If true the compiled code runs else the JIT discards the optimized code and the execution is reversed back to the baseline Compiler. Normally optimization makes a code faster but its like taking a shortcut, if the gates to the short cuts are closed and you have to turn back to take the normal route making your journey much longer than it actually was.

To further let me give you a common example (Type specialization)

Screenshot 2022-09-26 at 06.24.28.png

As regards the image above we have a variable arr which is an array that is undefined, if it was array with 1000 integers immediately the code is warm the baseline compiler starts creating stubs for that operations. The sum += arr[i] will have its own stub too but this line is polymorphic by polymorphic i mean the value of arr[i] could be any value of any type and not just an integer so a stub is created for every possible type combination. This implies that the JIT must ask several questions before creating a stub. Is i an integer? Is sum an integer? Is the result a string? Is arr actually an array? Is arr[i] a string? The above is a set of question which each iteration of the loop will ask and we would agree this will be slow especially when dealing with a lot of data and thats where the optimizing compiler comes in so you don't have to repeat those checks in order for your code to be much quicker. Is arr an array? YES Is i an integer? YES (all data in arr is confirmed to be an integer) now everything is stubbed So any question which isn't stubbed by the optimized compiler is then ran singly for each ilteration.

Execution

After compilation immediately comes execution and this happens in the call stack of the JavaScript engine just in time. this is above the scope of this article, i might write about it later.

Conclusion

Now You know why JavaScript is a Just in time compiled language and how it works. With the monitor as the name implies monitoring your javaScript code, sorting them into warm code and hot code and using the baseline and optimizing compiler respectively to provide better and faster performance, as a Javascript developer knowing the science behind this will help you understand different coding patterns and how it affects the performance of your projects so you always keep good practice.

Thanks for making it to the end of this article, feel free to ask any question and if there is a topic you would need me to write on do well to contact me on Twitter or Linkedin.

Do well to like and Share this article if you found it helpful✌️.