Деоптимизация в 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 перед оптимизацией наугад.

Источники

См. также