Unveiling the V8 Engine: The Journey of JavaScript from Code to Execution


When the JavaScript code is passed to v8 engine, it goes through different stages before execution those are
NOTE: JavaScript is a JIT Compiled language, i.e. it is a Just in time compiled language means it has both interpreter and compiler. The use of interpreter and compiler to convert the code into byte code and machine code and then execute it is called as JIT compilation.
1. Parsing
In Parsing, the first stage is
Lexical Analysis (Tokenization)
This stage is also known as tokenization.
Code is broken down into tokens.
Syntax Analysis (Parsing)
This stage is also known as parsing or syntax parsing.
Abstract Syntax Tree (AST) is created from the tokens.
You can explore here AST Explorer
2. Interpreter and Compiler
JS has both interpreter and compiler, as it is a JIT-compiled language.
Interpreter
The name of the interpreter is Ignition in the V8 engine.
The AST is given to an interpreter.
The AST is processed by the interpreter and converted to the byte code, and the byte code is executed.
Compiler
The name of the compiler is Turbofan Compiler in the V8 Engine.
Before Turbofan, there was a compiler named CrankShaft, which is no longer used.
When the code is getting interpreted, the interpreter recognizes, identifies, or finds a piece of code that is used a lot or is frequently recurring.
So the above piece of code is given to the Turbofan Compiler, which converts it to optimized machine code. So whenever it runs next time, it executes even faster.
The frequently recurring code that is given to the compiler is called HOT code.
This process is also called optimization.
In this process, there are chances where it might have to de-optimize the code.
In a runtime environment employing Just-In-Time (JIT) compilation, when a function such as sum is frequently invoked with numerical arguments, the compiler optimizes its execution by generating type-specific machine code under the assumption that future invocations will maintain consistent operand types (e.g., numbers). This optimization relies on speculative type inference derived from runtime profiling data.
If the function is later called with operands of a non-conforming type (e.g., strings), the runtime detects a type violation, triggering de-optimization. During this process, the optimized machine code is discarded, and execution reverts to the interpreter.
Garbage Collectors
Orinoco, Oilpan, Scavenger, and MarkCompact are some of the garbage collectors used inside the V8 engine.
All the above garbage collectors have different jobs.
These are working in parallel to the interpreter and compiler.
The Mark and Sweep algorithm is used for garbage collection.
Performance Optimization Techniques
Inline Caching
Inline caching is an optimization technique used in JavaScript engines like V8 to speed up property access. When a property of an object is accessed, the engine initially performs a lookup to find the property. Inline caching optimizes this process by storing the location of the property after the first lookup. On subsequent accesses, the engine can quickly retrieve the property using the cached information, bypassing the need for repeated lookups. This significantly improves performance, especially in cases where the same property is accessed multiple times in a loop or frequently called function.
Copy Elision
Copy elision is an optimization technique used by compilers to eliminate unnecessary copying of objects. In programming languages like C++, when objects are returned from functions or passed as arguments, the compiler might create temporary copies of these objects. Copy elision allows the compiler to optimize away these temporary copies, directly constructing the object in its final location. This reduces the overhead associated with object copying, leading to more efficient code execution. Copy elision is particularly beneficial in scenarios involving large objects or complex data structures, where copying can be costly in terms of performance.
Wrapping Up
In conclusion, the V8 engine's process of executing JavaScript code involves several intricate stages, each playing a crucial role in optimizing performance. The journey begins with parsing, where the code is broken down into tokens and transformed into an Abstract Syntax Tree (AST). This is followed by the dual role of the interpreter and compiler, with the interpreter converting the AST into byte code for execution, and the compiler optimizing frequently used code into machine code for faster execution. The presence of garbage collectors ensures efficient memory management, working in tandem with the interpreter and compiler. This sophisticated orchestration of components within the V8 engine exemplifies the power and efficiency of Just-In-Time (JIT) compilation, enabling JavaScript to run swiftly and effectively in modern applications.
For more in-depth dive in the V8 engine, visit the official docs
Subscribe to my newsletter
Read articles from Anish Tilloo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by