Как компилирует V8

Полный пайплайн от текста JS до машинного кода: Scanner → Parser → AST → BytecodeGenerator → Ignition → TurboFan → MachineCode. И всё это с пре-парсером, кэшем байт-кода и фоновыми потоками.

Конвейер

JS source
   ↓
Scanner (Lexer) → токены
   ↓
PreParser (быстро, неточно) — границы функций
   ↓
Parser (по требованию, lazy) → AST
   ↓
BytecodeGenerator (Ignition) → Bytecode
   ↓
Ignition VM — интерпретация + сбор type feedback
   ↓ функция стала горячей
TurboFan
   ↓ оптимизатор: inline, escape analysis, type spec, redundancy
Machine Code
   ↓ feedback не сбылся → deopt → откат в Ignition

Что делает TurboFan на каждой фазе

  1. Graph building — строит sea-of-nodes IR из байт-кода + type feedback.
  2. Typer — выводит типы для каждого узла.
  3. Specialization — заменяет общие операции типизированными (addint32_add).
  4. Inlining — вставляет тела горячих коллбэков.
  5. Escape analysis — устраняет аллокации, если объект не утекает.
  6. Lowering — спуск к машинному IR.
  7. Code generation — машинный код под архитектуру.

Background compilation

  • Парсинг и компиляция идут в отдельных потоках.
  • Main thread не блокируется парсингом большого JS.
  • В Chrome — Streaming Compilation поверх сети: парсит, пока скачивается.

Подводные камни

  • TurboFan не оптимизирует функцию, если она вызывается редко.
  • Code caching сохраняет байт-код, но не машинный (для V8 < 9, после — может).
  • Парсер до Ignition нужен дважды: один раз pre-parser, второй — full.

Источники

См. также