JIT compilation.
Modern JS engines and the JVM don\'t compile your code ahead of time. They run it slow, watch it, and recompile the hot parts with assumptions specialized to the actual values flowing through. Watch a 2 µs function become a 20 ns function in three tiers, then watch a single mistyped argument knock it back to the interpreter.
A JS function `function f(n) { let s=0; for (let i=0; i<n; i++) s+=i*i; return s; }` runs for the first time. V8's interpreter (Ignition) walks the bytecode, dispatching one op at a time. No assumptions about types. ~2 µs per call. The interpreter also installs counters on this function — call count, loop iterations.
- JIT
- Just-In-Time compilation. The runtime starts by interpreting code, then compiles hot parts to machine code at runtime, with assumptions specialized to the values it has actually seen.
- Tiered compilation
- Most modern JITs have multiple tiers: interpreter → fast baseline JIT → slow optimising JIT. Each tier is faster to run but slower to produce.
Why JITs beat AOT for dynamic languages
An ahead-of-time compiler for JavaScript has no idea what types your variables will hold. So it has to emit conservative code: every + might be number addition or string concatenation, every property access might miss the prototype chain. A JIT watches the program run, observes the actual types, and specializes. i + 1 becomes a single ADD instruction once the JIT has seen i is always an Int32. AOT would have to leave a type check in. JIT removes it and inserts a guard at the function entry instead.
Tiered compilation in real engines
V8 has Ignition (interpreter) → Sparkplug (baseline) → Maglev (mid-tier) → TurboFan (top tier). JVM HotSpot has the interpreter → C1 (client compiler) → C2 (server compiler) → JVM CI in some modes. .NET has the interpreter → Tier 0 → Tier 1 with dynamic PGO. Each tier costs more to produce but emits faster code. Functions tier up based on call counts; rarely-called functions stay at lower tiers because compiling them isn\'t worth the investment.
Writing JIT-friendly code
Don\'t change the shape of objects after construction (V8\'s "hidden classes" depend on stable structure). Keep arrays monomorphic — don\'t mix types in one array. Avoid try/catch inside hot functions (used to disable optimization entirely; less true now but still costly). Avoid arguments; prefer rest parameters. Prefer simple, predictable loops over functional combinators in hot paths. These rules are why some "boring" code is faster than elegant code on V8.
JIT internals →
V8\'s architecture, HotSpot tiers, inline caches, the speculation/guard pattern, on-stack replacement, AOT trade-offs.
Open the Codex →