Manifest Stack home

What is JS Engine

Part 1: What is a JS Engine?

A JavaScript engine is a program that takes your JavaScript source code, understands it, and executes it on the machine. Without an engine, your JS is just text — the engine is what gives it life.

Every browser ships with its own engine, and Node.js uses one too:

V8 — Chrome & Node.js

Built by Google. The most widely used engine. Powers Chrome, Edge, and Node.js. Known for its JIT compiler and speed optimisations.

SpiderMonkey — Firefox

Built by Mozilla. The world's first JavaScript engine — created by Brendan Eich (who also created JavaScript) in 1995.

JavaScriptCore — Safari

Built by Apple. Also called Nitro. Used in Safari and all iOS browsers (Apple requires all iOS browsers to use this engine).

Chakra — Old Edge

Built by Microsoft for the original Edge browser. New Edge switched to V8 (Chromium-based) in 2020.

Part 2: What Does the Engine Do?

The engine processes your code through a pipeline. Here's each stage:

Stage 1: Parsing

The engine reads the raw source code and breaks it into a structure it can work with.

javascript
// Source code (just text):
function add(a, b) { return a + b; }

// Step 1: Lexer breaks it into tokens
// [function] [add] [(] [a] [,] [b] [)] [{] [return] [a] [+] [b] [;] [}]

// Step 2: Parser builds an AST (Abstract Syntax Tree)
// FunctionDeclaration
//   ├── id: add
//   ├── params: [a, b]
//   └── body: ReturnStatement
//               └── BinaryExpression (+)
//                     ├── a
//                     └── b

Stage 2: Compilation to Bytecode

V8's Ignition interpreter takes the AST and converts it to bytecode — a compact, lower-level set of instructions that's faster to execute than re-reading the AST every time.

javascript
// Your code:
function add(a, b) { return a + b; }

// Simplified bytecode (not real syntax, just the concept):
// LdaNamedProperty a
// Add b
// Return

// Bytecode is what Ignition (V8's interpreter) actually runs.

Stage 3: JIT Compilation — making hot code fast

V8 watches which code runs often (called hot code). For those parts, its TurboFan compiler converts bytecode directly to optimised native machine code — the same level as C++. This is called JIT (Just-In-Time) compilation.

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

// Called a million times with numbers:
for (let i = 0; i < 1_000_000; i++) {
    add(i, 1); // V8 sees this is always number + number
}

// TurboFan optimises: generates machine code assuming
// a and b are always numbers → blazing fast

// But if you then call:
add("hello", "world"); // types changed!
// V8 "deoptimises" — throws away the machine code
// and goes back to bytecode

Part 3: Memory Management

The engine also manages memory for you — you never manually allocate or free memory in JavaScript. It has two memory areas:

Stack

Stores primitive values (number, boolean, string) and references to objects. Fast, automatically managed. Each function call adds a stack frame.

Heap

Stores objects and arrays. Larger and more flexible. Managed by the Garbage Collector, which automatically frees memory when objects are no longer reachable.

Garbage collection

javascript
function createUser() {
    let user = { name: "Arjun", age: 22 }; // allocated on heap
    return user.name;
    // 'user' object is no longer reachable after function returns
    // → Garbage Collector will free that memory
}

let name = createUser();
// 'name' holds "Arjun" (a primitive, on the stack)
// The original object is gone — GC cleaned it up