Ignition: Reducing JavaScript Memory in Chromium
This article provides an overview of how the Ignition interpreter drastically reduces memory consumption during JavaScript execution in the Chromium web browser. Introduced as a core component of Chromium's V8 JavaScript engine, Ignition replaces older, memory-heavy baseline compilers by translating JavaScript code into a compact bytecode format. By avoiding the immediate generation of bulky native machine code, reducing parsing overhead, and seamlessly integrating with the TurboFan optimizing compiler, Ignition significantly lowers the memory footprint of web applications, particularly benefiting mobile and low-end devices.
The Machine Code Problem
Before Ignition was introduced, Chromium’s V8 engine relied on a two-tiered compilation pipeline that compiled all JavaScript directly into native machine code. The baseline compiler, known as Full-codegen, quickly generated unoptimized machine code so the script could run immediately.
While this approach offered fast execution, native machine code is extremely verbose and takes up a massive amount of memory. Web pages often contain large libraries of JavaScript where many functions are only executed once during startup. Compiling all of this code into heavy machine instructions wasted megabytes of RAM per browser tab.
The Shift to Compact Bytecode
Ignition solves the machine code bloat by acting as an interpreter. Instead of compiling JavaScript directly into native machine code, V8 parses the JavaScript into an Abstract Syntax Tree (AST) and Ignition translates that tree into bytecode.
Bytecode is a highly concise, abstract representation of the code. Ignition’s bytecode is roughly 25% to 50% the size of the equivalent baseline machine code generated by the older V8 architecture. By holding this compact bytecode in memory rather than sprawling machine instructions, Chromium immediately slashes the memory overhead required to load and run complex websites.
Register-Based Efficiency
To keep the bytecode as small as possible, Ignition is designed as a register-based interpreter rather than a traditional stack-based interpreter.
Stack-based interpreters require numerous push and pop instructions to move data around, which increases the overall size of the bytecode. Ignition’s register-based design operates on virtual registers, allowing it to express complex operations in fewer instructions. Fewer instructions mean smaller bytecode arrays, directly translating to lower memory usage.
Eliminating Redundant Source Code Storage
In the pre-Ignition era, when a function became "hot" (executed frequently), V8's optimizing compiler had to re-parse the original JavaScript source code to generate optimized machine code. This meant Chromium had to keep the original JavaScript source or the memory-heavy AST in RAM just in case it needed to be optimized later.
Ignition eliminates this requirement. Its bytecode serves as the single source of truth for execution. When a function becomes hot, the bytecode itself is fed directly into V8's optimizing compiler, TurboFan. Because TurboFan optimizes directly from the bytecode, V8 can aggressively discard the AST and avoid re-parsing the JavaScript source, freeing up substantial amounts of memory.
Smarter Deoptimization
When optimized code makes assumptions that turn out to be false during execution, the engine must "deoptimize" and fall back to a safer state. Previously, V8 fell back to the bulky, unoptimized machine code. With Ignition, when TurboFan deoptimizes code, it falls directly back to the lightweight Ignition bytecode. This removes the need to ever keep unoptimized machine code in memory as a safety net, permanently lowering the baseline memory cost of running JavaScript in Chromium.