Запуск интерпретатора Ignition
V8 и другие современные движки JavaScript достигают своей скорости благодаря компиляции "на лету" (JIT) скриптов в нативный машинный код непосредственно перед выполнением. Код сначала компилируется базовым компилятором, который может быстро генерировать неоптимизированный машинный код. Скомпилированный код анализируется во время выполнения и при необходимости динамически перекомпилируется с использованием более продвинутого оптимизирующего компилятора для максимальной производительности. В V8 этот процесс выполнения скриптов имеет множество специальных случаев и условий, которые требуют сложной логики для переключения между базовым компилятором и двумя оптимизирующими компиляторами, Crankshaft и TurboFan.
Одна из проблем с этим подходом (помимо архитектурной сложности) заключается в том, что сгенерированный JIT машинный код может занимать значительное количество памяти, даже если код выполняется только один раз. Чтобы уменьшить эти накладные расходы, команда V8 разработала новый интерпретатор JavaScript под названием Ignition, который может заменить базовый компилятор V8, выполняя код с меньшими накладными расходами памяти и упрощая процесс выполнения скриптов.
С помощью Ignition V8 компилирует функции JavaScript в компактный байткод, который занимает от 25% до 50% от размера эквивалентного машинного кода начального уровня. Этот байткод затем исполняется высокопроизводительным интерпретатором, который обеспечивает скорости выполнения, близкие к скорости кода, сгенерированного существующим базовым компилятором V8, на реальных веб-сайтах.
В Chrome 53 Ignition будет включен для Android-устройств с ограниченным объемом оперативной памяти (512 МБ или меньше), где особенно важна экономия памяти. Результаты ранних экспериментов показывают, что Ignition снижает объем памяти каждой вкладки Chrome примерно на 5%.
Детали
При разработке интерпретатора байткода Ignition команда рассмотрела несколько потенциальных подходов к реализации. Традиционный интерпретатор, написанный на C++, не смог бы эффективно взаимодействовать с остальным сгенерированным кодом V8. Альтернативой могло бы быть ручное кодирование интерпретатора на машинном языке, однако, учитывая, что V8 поддерживает девять архитектур, это потребовало бы значительных затрат на инженерию.
Вместо этого мы выбрали подход, использующий возможности TurboFan, нашего нового оптимизирующего компилятора, который уже настроен для оптимального взаимодействия с V8 runtime и другим сгенерированным кодом. Интерпретатор Ignition использует низкоуровневые, архитектурно-независимые макроинструкции TurboFan для генерации обработчиков байткода для каждой операции. TurboFan компилирует эти инструкции в целевую архитектуру, выполняя низкоуровневый выбор инструкций и распределение регистров при этом. Это приводит к созданию высокооптимизированного кода интерпретатора, который может выполнять инструкции байткода и взаимодействовать с остальной виртуальной машиной V8 с минимальными затратами.
Ignition использует регистровую модель, где каждый байткод задает свои входные и выходные операнды как явные регистры, в отличие от стековой модели, где каждый байткод использует стек для обработки входов и выходов. Специальный регистр аккумулятора используется как явный входной и выходной регистр для многих байткодов. Это сокращает размер байткодов, избегая необходимости указывать конкретные регистры. Поскольку многие выражения JavaScript включают цепочки операций, оцениваемых слева направо, промежуточные результаты этих операций часто могут оставаться в аккумуляторе на протяжении всей цепочки вычислений, минимизируя необходимость операций загрузки и сохранения в явные регистры.
В процессе генерации байткода он проходит через серию этапов встроенных оптимизаций. Эти этапы выполняют простой анализ потока байткодов, заменяя общие шаблоны на более быстрые последовательности, удаляют некоторые избыточные операции и минимизируют количество ненужных загрузок и передач между регистрами. Вместе эти оптимизации дополнительно уменьшают размер байткодов и улучшают производительность.
Для получения дополнительной информации о реализации Ignition смотрите наш доклад на BlinkOn:
Будущее
До сих пор наше внимание в Ignition было сосредоточено на сокращении памяти, используемой V8. Однако добавление Ignition в наш процесс выполнения скриптов открывает множество возможностей на будущее. Процесс Ignition был разработан таким образом, чтобы мы могли принимать более умные решения о том, когда выполнять и оптимизировать код для ускорения загрузки веб-страниц, уменьшения задержек и повышения эффективности взаимодействия между различными компонентами V8.
Следите за будущими обновлениями в Ignition и V8.