JavaScript V8 Engine Internals: Complete Guide
V8's internals include hidden classes, inline caching, and a generational garbage collector. Learn how these mechanisms make JavaScript execution fast.
V8 is not just a compiler. It is a complete execution environment that manages object representation, property access, and memory. These V8 engine internals are the hidden machinery that makes JavaScript run fast despite being a dynamically typed language.
Three internal systems work together: hidden classes for fast property access, inline caching for repeated lookups, and a generational garbage collector for memory management. Understanding them helps you write code that V8 can optimize.
Hidden Classes: How V8 Represents Objects
JavaScript objects look simple on the surface. In reality, V8 cannot treat them as simple dictionaries. Dictionary lookups are slow because the engine must search for the right key every time.
V8 solves this with hidden classes.
A hidden class, also called a Map in V8's source code, is an internal structure that describes the shape of an object: which properties it has and in what order. Objects with the same properties in the same order share the same hidden class.
const a = { x: 1, y: 2 };
const b = { x: 3, y: 4 };Both objects share the same hidden class. When V8 accesses a.x or b.x, it knows the exact memory offset of the property x because the hidden class stores it. No dictionary search is needed.
When you add a new property, V8 creates a new hidden class that extends the previous one. The object transitions to the new class.
const obj = { x: 1 };
// Hidden class HC0: { x }
obj.y = 2;
// Hidden class HC1: { x, y } -- transitioned from HC0V8 remembers the transition path. When another object goes through the same sequence, it follows the same hidden class transitions and gets the same fast property access.
Why Property Order Matters
Hidden classes depend on property creation order, not just which properties exist. Two objects with the same properties created in different orders get different hidden classes.
const a = { x: 1, y: 2 };
const b = { y: 2, x: 1 };Object a gets hidden class HC_x_then_y. Object b gets HC_y_then_x. They have different shapes even though they have the same properties.
V8 cannot share property offset information between them.
For consistent hidden classes, always create object properties in the same order. This is especially important in constructors where many objects are created from the same template.
Inline Caching: Remembering Property Lookups
Every time V8 accesses a property like obj.x, it must find the property's memory location. With hidden classes, the location is predictable. Inline caching makes it even faster by remembering the result.
The first time V8 encounters obj.x at a particular code location, it looks up the property through the hidden class and records the result. The result is cached directly in the compiled code at that call site. Next time the same code runs on an object with the same hidden class, V8 skips the lookup entirely.
If the hidden class changes, the cached result is stale. V8 falls back to a full lookup and updates the cache. This is called a polymorphic inline cache: it can store results for multiple hidden classes at the same call site.
But if too many different hidden classes appear in the same cache, V8 gives up and uses a slow global lookup.
Generational Garbage Collection
V8 manages memory with a generational garbage collector. The key insight is that most objects die young. A temporary string or intermediate calculation result is created and discarded quickly.
Objects that survive for a while tend to survive much longer.
V8 splits the heap into two generations. The young generation, called the nursery, holds recently created objects. It is small and collected frequently using a fast copying collector called Scavenge.
Surviving objects are promoted to the old generation after surviving a few collections.
The old generation holds long-lived objects. It is larger and collected less frequently using a mark-and-sweep algorithm. V8 also compacts memory in the old generation to reduce fragmentation.
The garbage collector is stop-the-world: JavaScript execution pauses during collection. V8 minimizes pause time by collecting the nursery quickly and doing old-generation collection incrementally.
For a deeper look at garbage collection mechanics, see /javascript/javascript-garbage-collection-complete-guide.
Object Representation in Memory
V8 represents JavaScript objects using a combination of hidden classes and property arrays. Named properties are stored in a fixed array at offsets determined by the hidden class. Numerically indexed properties (like array elements) are stored in a separate elements array.
This split allows V8 to optimize both patterns. Named property access uses the hidden class for offset-based lookup. Array index access uses the elements array for direct indexing.
Large arrays with holes (missing indices like [1, , 3]) are stored differently from dense arrays. V8 uses different internal representations depending on how the array is used, switching between them as the array's content changes.
How V8 Handles Function Calls
Function calls in V8 involve more than pushing a stack frame. The engine must set up the correct hidden class context, allocate a new scope for local variables, and handle the this binding.
V8 can inline small functions directly into their call sites. If a function is called many times and its body is small, TurboFan replaces the function call with the function's body. This eliminates the call overhead entirely.
For constructors called with new, V8 tracks which hidden class the constructor produces. When many objects are created from the same constructor, they all start with the same hidden class, enabling fast property access from the first use.
Writing Code That V8 Can Optimize
V8's optimizations work best when your code is predictable. A few guidelines help the engine generate fast code.
Keep object property order consistent. Initialize all properties in the constructor rather than adding them later. Avoid deleting properties because it breaks hidden class chains and forces dictionary mode.
Use consistent parameter types. A function that always receives numbers gets optimized for numeric operations. A function that receives numbers, strings, and objects at different call sites cannot be specialized.
Avoid polymorphism beyond a few types. Inline caches can handle a handful of different hidden classes, but performance degrades beyond three or four. If a polymorphic operation is unavoidable, consider restructuring the code to use a monomorphic path for the common case.
For more on V8's compilation pipeline, see /javascript/how-the-google-v8-engine-compiles-javascript.
Rune AI
Key Insights
- V8 uses hidden classes to give objects fast property access, similar to C++ structs.
- Inline caching remembers property lookup results, turning dynamic lookups into direct memory reads.
- The generational garbage collector splits objects into young and old generations, collecting young objects more frequently.
- Consistent object shapes and stable parameter types help V8 optimize your code.
- Deleting properties or adding them in different orders forces V8 to deoptimize.
Frequently Asked Questions
What is the difference between V8 and the JavaScript language?
Why does deleting an object property slow down V8?
Conclusion
V8's internals are built around a few key ideas: hidden classes for fast property access, inline caching for repeated lookups, and a generational garbage collector for efficient memory management. Understanding these mechanisms helps you write JavaScript that works with V8's optimizer rather than against it.
More in this topic
Using Decorators for Logging in JS Architecture
Learn how JavaScript decorators wrap class methods to add logging without touching the original code, including setup with Babel and how execution order works.
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.