awesome-everything RU
↑ Back to the climb

Browser & Frontend Runtime

V8''''s four-tier JIT pipeline and profile-guided tiering

Crux How Ignition, Sparkplug, Maglev, and TurboFan cooperate — compile costs, runtime speeds, the FeedbackVector, and operational levers for keeping code on the fast tier.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 14 min

A page feels snappy within 200ms of load. A few seconds later it gets faster still. A third speed-up appears after thousands of user interactions. That is not magic — it is V8’s tiered compiler moving hot code up the ladder while leaving cold code cheap.

The four-tier pipeline

V8 has four execution modes layered by compile-time vs run-time tradeoff.

Ignition — the bytecode interpreter. The parser produces an AST; Ignition lowers it to a compact register-based bytecode and executes that on a virtual machine. While interpreting, Ignition records type feedback into a per-function FeedbackVector — slots for each “interesting” location (property load, function call, arithmetic, comparison). Cheap to enter (no compile cost), ~10× slower per instruction than optimised native code.

Sparkplug — the baseline JIT, added in 2021. Sparkplug emits unspecialised machine code in a single linear pass over the bytecode — no SSA, no real optimisation, just a faithful translation of each bytecode to a small block of machine instructions plus a tail call. Compile cost is essentially free (~1 ms/kB bytecode); speedup over Ignition is 1.5–2×.

Maglev — the mid-tier optimising compiler, added in 2023. Maglev uses observed types from the FeedbackVector and SSA-based optimisations to emit specialised machine code, but skips TurboFan’s heavyweight passes. ~10× slower compile than Sparkplug, ~10× faster compile than TurboFan; code roughly halfway between the two in runtime speed.

TurboFan — the heavy optimising compiler. Aggressive inlining, escape analysis, range analysis, hidden-class-driven specialisation, speculative optimisations that may deopt. Compile cost is high (tens to hundreds of ms for complex functions); runtime code is the fastest V8 produces.

JIT tier compile and runtime costs
Sparkplug compile rate
~1 ms / kB bytecode
Sparkplug vs Ignition speedup
~1.5–2×
Maglev compile time
~10 ms / function
Maglev code quality vs TurboFan
~50–70%
TurboFan compile time
~100 ms / function
Sparkplug promotion threshold
~100 calls
Maglev promotion threshold
low thousands of calls
TurboFan promotion threshold
tens of thousands of calls

Profile-guided tiering

Functions enter Ignition. After execution-count thresholds are crossed (per-function, dynamic), V8 promotes to the next tier. The FeedbackVector tracks not just types but also branch frequencies, so TurboFan can lay out the hot path with optimal branch prediction. Promotion happens off-thread (concurrent compilation) — the JS main thread keeps running on the current tier while a worker thread compiles the next.

Functions can skip tiers: a very hot function seen at startup may jump from Ignition directly to Maglev. Functions whose feedback is unstable (frequent IC transitions) are deferred or skipped — TurboFan on an unstable function would produce code that deoptimizes immediately, wasting 100 ms of compile work.

Operational levers

Eight patterns that keep code on V8’s fast tier:

  1. Constructor pattern — declare all object properties in one place so hidden classes are stable.
  2. Avoid delete — use null or undefined assignment instead; delete forces dictionary mode.
  3. Keep functions monomorphic — do not pass different shapes to the same call site.
  4. Avoid arguments in old code; use rest parameters.
  5. Pre-allocate arrays with known capacity to avoid resize.
  6. Reuse object pools for short-lived workloads (canvas, animation) instead of allocating new objects per frame.
  7. Avoid massive object literals in hot paths — they go megamorphic fast.
  8. For very hot numeric loops, use TypedArrays — V8 has highly tuned paths for Uint32Array and friends that bypass the IC layer entirely.
Trace it
1/5

A React app drops to 20fps after adding a new prop to a component. Trace the JS-perf root cause.

1
Step 1 of 5
Step 1: 20fps means a frame takes >50ms when it should take <16ms. What sub-systems could be eating the budget?
2
Locked
Step 2: Performance shows 40ms of Scripting per frame, was 8ms before. The new prop is involved. What is the V8-level shape?
3
Locked
Step 3: how to confirm hidden-class instability is the issue?
4
Locked
Step 4: structural fix?
5
Locked
Step 5: prevent regression?
Order the steps

Order the steps of a property access at a TurboFan-compiled monomorphic IC:

  1. 1 TurboFan-compiled function receives an object pointer in a register
  2. 2 First instruction: load the hidden-class pointer from the object header
  3. 3 Compare loaded hidden class to the expected hidden class from compile time
  4. 4 If equal: read the property at the precomputed offset (1 MOV instruction)
  5. 5 If not equal: deoptimize — throw away compiled code, fall back to lower tier
  6. 6 Continue execution in the lower tier; IC records the new hidden class and may transition state
  7. 7 Function may be re-optimised later with updated IC information
Quiz

Why does V8 have FOUR compilation tiers instead of two?

Quiz

A function suddenly slows from 50µs to 2ms after a 'small' refactor. Where do you look first?

Why this works

Why not TurboFan everything from the start? Three reasons. First: most functions run once or never — TurboFan compile cost would be pure waste. Second: TurboFan needs type feedback from Ignition to make good speculations; without warm-up it has no information to specialise on. Third: compile latency directly hits perceived load time. A page that boots in 2s because every onload function TurboFan-compiled feels broken. Tiered design front-loads cheap Ignition, reaches expensive TurboFan only for the small subset of code that warrants it.

Recall before you leave
  1. 01
    Why does V8 not just compile every function with TurboFan immediately?
  2. 02
    What is the FeedbackVector and who reads it?
  3. 03
    What are the two main reasons Maglev exists alongside TurboFan?
Recap

V8’s four tiers span the entire compile-cost-vs-runtime-speed axis: Ignition (free compile, 10× slower code), Sparkplug (~1ms compile, 1.5–2× faster), Maglev (~10ms compile, 50–70% of TurboFan speed), TurboFan (~100ms compile, maximum speed). Functions move up the ladder only when they are hot enough and their FeedbackVector is stable enough to justify the compile cost. The FeedbackVector is the key data structure — one slot per call site, tracking observed hidden classes and call frequencies. Concurrent compilation keeps the main thread running on the current tier while a worker thread builds the next. Operational levers — stable constructors, no delete, monomorphic call sites, TypedArrays for numeric loops — keep functions on the fast tier across their lifetime.

Connected lessons
appears again in143
Continue the climb ↑Hidden classes, transition trees, and memory layout
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.