Деоптимизация в V8
Функция была оптимизирована TurboFan в машинный код — но предположения о типах сломались. V8 откатывает её обратно в байт-код Ignition. Это дорого: повторная оптимизация может не случиться вовсе.
Когда происходит deopt
- В функцию пришёл объект с другим hidden class.
- Число перестало быть SMI (вышло за диапазон или стало float).
- Массив перешёл между типами elements (SMI → Double → Object).
deleteсвойства,Object.freeze, изменение прототипа.- Внутри функции изменился набор переменных (
with,eval).
Цена
- Откат в Ignition — мгновенно.
- Повторная оптимизация — только если функция снова станет «горячей».
- Если функция деоптимизируется регулярно (bailout cycle) — V8 навсегда оставит её в Ignition.
Как смотреть deopt
node --trace-deopt --trace-opt script.js
d8 --trace-deopt --allow-natives-syntax script.js
Внутри кода:
%OptimizeFunctionOnNextCall(fn);
%DeoptimizeFunction(fn);
%HaveSameMap(a, b);
Типичные причины «случайной» деоптимизации
- В горячий цикл прилетел
null/undefinedчерез guard. - Функция, написанная универсально под несколько форм.
try/catchвокруг горячего кода (в старых V8 — гарантированный bailout).- Аргументы через
argumentsилиFunction.prototype.applyс разными arity.
Подводные камни
- Не пиши «универсальных» функций для горячего кода — лучше дублировать.
- Стабилизируй типы аргументов на границе.
- Замеряй
--trace-deoptперед оптимизацией наугад.
Источники
- Live Coding Инструмент для удобной работы с V8 Native Syntax · AsForJS · 2025-02-14
- Производительность JS Switch против IF · AsForJS · 2025-02-01
- Производительность for, forEach и reduce · AsForJS · 2026-04-14
- Тезис: деоптимизация на SMI — числа в бенчмарке прыгают именно из-за этого