Знай свой JIT: ближе к машине / Андрей Мелихов (Яндекс.Деньги)
Движки:
- Chakra (JScript, not Javascript!) — in IE
- ChakraCore (JavaScript)
- SpiderMonkey — Firefox
- JavaScriptCore — Webkit, RN
- V8 — Node
- Rhine, Nashorn — Java
- JerryScript
JIT
- спекулятивная оптимизация;
- оптимистичная;
- если догадка неверна, код будет деоптимизирован.
Интерпретатор и компилятор:
- Ignition — interpreter
- Turbofan — compiler
Задачи интерпретатора (9:02):
- уменьшить накладные расходы на парсинг
- уменьшить потребление памяти
Холодные и горячие функции (10:35):
- интерпретатор собирает информацию о типах и горячих функциях
- отдаёт оптимизатору
- оптимизатор исполняет
- если что-то пошло не так, деоптимизирует и сообщает об этом в интерпретатор
Мономорфность (11:40): если функция всегда оперирует одними и теми же типами; в этом случае оптимизируется.
Hidden classes (12:05)
- все объекты имеют скрытые классы (в V8 они называются “Map”)
- описывают структуру объектов
- меняются при удалении или добавлении проперти объектов
Специальный синтаксис в Node (14:19):
$ node --allow-native-syntax
и
%HasSameMap({ a: 1 }, { b: 1 }); // -> false
Inline cache (14:30):
- каждый аргумент функции имеет один и тот же тип при вызове в рантайме — мономорфное состояние,
- тип аргументов поменялся — полиморфное состояние,
- снова поменялся — мегаморфное состояние, неоптимально.

Разные типы массивов (16:30):
- PACKED_SMI_ELEMENTS 〜
[smallint]
- PACKED_DOUBLE_ELEMENTS 〜
[double]
- PACKED_ELEMENTS 〜
[any]
- HOLEY_SMI_ELEMENTS 〜
[int | undefined ]
- HOLEY_DOUBLE_ELEMENTS
- HOLEY_ELEMENTS
Массивы деградируют в типах и не улучшаются обратно, HOLEY_ELEMENTS
не будет оптимизирован обратно в PACKED_•
в рантайме!
Примеры массивоподобных типов (19:00): arguments
и document.querySelectorAll(•)
. Возвращают типы, похожие на массивы, но не массивы. Оптимизированы не будут.
const map = f => x => Array.prototype.map.call(x, f); // <- не оптимизирован
const args = Array.prototype.slice.call(arguments); // <- оптимизирован
(…args) = arguments; // <- оптимизирован
Большие массивы (20:15):
new Array(1000)
— сразу создаём массив с тысячей дырок HOLEY_ELEMENTS, он не будет оптимизирован: быстро пишем, медленно работаем
array = []
— создаём пустой массив: медленно пишем, быстро работаем.
Сборщик мусора (20:50):
- пространство молодых объектов — Scavenge
- пространство старых объектов — Mark-Sweep
WASM (23:00)
- статически типизирован
- оптимизирован на этапе компиляции — не нужно оптимизировать в рантайме — быстрее работает
- ручное управление памятью — не нужен GC — быстрее работает
- сам код более оптимален — исполнение быстрее работает
Три вида оптимизаций (25:10):
- Алгоритмические — написать более эффективный алгоритм
- Специфические для языка — правильно управлять типами в рантайме
- Специфические для движка — самые опасные (интересная заметка: если сделаны оптимизации для движка, их нужно покрывать перфоманс-тестами, которые будут доказывать, что и в будущих версиях движка код работает быстрее, чем без оптимизаций)