How Chromium Shares Read-Only V8 Builtins Across Processes

This article explains the "Embedded Builtins" mechanism used by the Chromium web browser to reduce memory consumption across tabs. By moving V8 JavaScript engine builtins out of the dynamic memory heap and embedding them directly into the browser binary's read-only text section, the operating system can share a single physical copy of this executable code across multiple renderer processes.

What Are V8 Builtins?

V8 builtins are pre-compiled chunks of executable code that the V8 JavaScript engine requires to function. They include implementations of standard JavaScript objects (such as Array.prototype.sort or RegExp), internal helper functions, and the bytecode handlers that power the Ignition interpreter. Every V8 instance, known as an Isolate, needs access to these builtins to execute JavaScript.

The Historical Memory Problem

Chromium uses a multi-process architecture where different tabs and sites run in separate renderer processes, each containing its own V8 Isolate.

Historically, V8 stored builtins inside a startup snapshot. When a new renderer process started, V8 deserialized this snapshot directly into the Isolate's private, mutable heap memory. Because the deserialization process patched the builtins with memory addresses specific to that individual Isolate, the operating system treated those memory pages as modified and private. Consequently, every renderer process duplicated hundreds of kilobytes of identical builtin code in physical RAM.

The Solution: Embedded Builtins

The mechanism that allows Chromium to share these builtins across processes is called Embedded Builtins (or off-heap builtins). To achieve memory sharing, V8 engineers extracted the builtins from the mutable V8 heap and placed them into the immutable, read-only section of the Chromium binary itself.

This mechanism relies on three core technical concepts:

1. Isolate-Independent Code

For executable code to be shared across multiple processes, it cannot contain hardcoded memory addresses that point to a specific process's heap. V8 engineers rewrote the builtin generation pipeline to produce Position-Independent Code (PIC) and Isolate-independent code.

Instead of embedding fixed memory pointers into the code, V8 dedicates a specific CPU register—known as the Root Register—to hold the base address of the currently executing Isolate. When an embedded builtin needs to access Isolate-specific data, it calculates the target address dynamically using fixed offsets relative to the Root Register.

2. Embedding into the Binary's .text Section

During the Chromium build process, V8 runs a tool called mksnapshot. This tool generates the machine code for all builtins. Instead of serializing this code into the standard heap snapshot, mksnapshot writes the instructions out as a massive assembly file (embedded.S).

The C++ compiler and linker then compile this assembly file directly into the Chromium executable (or shared library, such as chrome.dll on Windows). The builtins end up in the binary's .text section, which is the standard read-only segment where compiled C++ functions reside.

3. OS-Level Virtual Memory Sharing

Because the builtins are located in the read-only .text section of the binary and are completely free of runtime modifications (relocations), the operating system handles the memory sharing automatically.

When Chromium spawns multiple renderer processes, the operating system's virtual memory manager maps the binary into each process's virtual address space. Since the .text section is marked as read-only and executable, the OS maps the virtual addresses of every renderer process to the exact same physical pages in RAM.

Calling an Embedded Builtin

Because the operating system uses Address Space Layout Randomization (ASLR), the shared .text section might be loaded at different virtual addresses in different processes.

To allow code inside the V8 heap to call a builtin located off-heap in the .text section, each V8 Isolate maintains a small, private "Builtins Constants Table" on its heap. When an Isolate initializes, it populates this table with the actual virtual addresses of the embedded builtins for that specific process. V8 code then calls builtins indirectly by looking up their addresses in this table, keeping the heavy executable code completely untouched and shared in physical memory.