Перейти к основному содержимому

Релиз V8 v7.9

· 5 мин. чтения
Сантьяго Абой Соланес, мастер компрессии указателей

Каждые шесть недель мы создаем новую ветку V8 в рамках нашего процесса релиза. Каждая версия отделяется от главной ветки Git V8 непосредственно перед выпуском Chrome Beta. Сегодня мы рады объявить о нашей новой ветке, V8 версии 7.9, которая будет в бете до своего релиза в координации с Chrome 79 Stable через несколько недель. V8 v7.9 содержит множество улучшений для разработчиков. Этот пост предоставляет обзор некоторых ключевых моментов в преддверии релиза.

Производительность (размер и скорость)

Удаление устаревания для переходов Double ⇒ Tagged

Вы, возможно, помните из предыдущих записей в блоге, что V8 отслеживает, как представляются поля в формах объектов. Когда представление поля меняется, текущая форма объекта должна быть «устаревшей», и создается новая форма с новым представлением поля.

Исключение составляют случаи, когда старые значения поля гарантированно совместимы с новым представлением. В таких случаях мы можем просто заменить новое представление непосредственно в форме объекта, и оно будет работать для старых значений полей объектов. В V8 v7.6 мы включили эти изменения представления на месте для переходов Smi ⇒ Tagged и HeapObject ⇒ Tagged, но не могли избежать Double ⇒ Tagged из-за нашей оптимизации MutableHeapNumber.

В V8 v7.9 мы избавились от MutableHeapNumber и вместо этого используем HeapNumbers, которые по умолчанию являются изменяемыми, если они принадлежат полю с представлением Double. Это означает, что нам нужно немного внимательнее относиться к работе с HeapNumbers (которые теперь изменяемы, если находятся в поле с представлением Double, и неизменяемы в противном случае), но HeapNumbers совместимы с представлением Tagged, а значит, мы можем также избежать устаревания в случае Double ⇒ Tagged.

Это относительно простое изменение улучшило показатель Speedometer AngularJS на 4%.

Улучшение показателей Speedometer AngularJS

Обработка API-геттеров во встроенных функциях

Ранее V8 всегда обращался к C++-runtime при обработке геттеров, определенных встроенным API (например, Blink). Сюда включены геттеры, определенные в спецификации HTML, такие как Node.nodeType, Node.nodeName и т.д.

V8 проходил по всей цепочке прототипов во встроенной функции, чтобы загрузить геттер, а затем переходил в runtime, когда обнаруживал, что геттер определен API. В C++-runtime снова проходился по цепочке прототипов, чтобы повторно получить геттер перед его выполнением, дублируя множество операций.

В целом, механизм кеширования на месте (IC) может смягчить это, поскольку V8 устанавливает обработчик IC после первого обращения в C++-runtime. Но с новой ленивой аллокацией обратной связи V8 не устанавливает обработчики IC, пока функция не выполнится несколько раз.

Теперь в V8 v7.9 эти геттеры обрабатываются во встроенных функциях без необходимости перехода в C++-runtime даже в случае отсутствия обработчиков IC, благодаря использованию специальных заглушек API, которые могут обращаться напрямую к геттеру API. Это приводит к 12%-му снижению времени, потраченного на IC runtime, в тестах Backbone и jQuery от Speedometer.

Улучшение показателей Speedometer Backbone и jQuery

Кэширование OSR

Когда V8 определяет, что определенные функции являются «горячими», он отмечает их для оптимизации при следующем вызове. Когда функция выполняется повторно, V8 компилирует функцию с использованием оптимизирующего компилятора и начинает использовать оптимизированный код с последующего вызова. Однако для функций с длительными циклами этого недостаточно. V8 использует технику, называемую заменой в стеке (OSR), чтобы установить оптимизированный код для текущей выполняемой функции. Это позволяет нам начать использование оптимизированного кода уже при первом выполнении функции, если она застряла в горячем цикле.

Если функция выполняется второй раз, очень вероятно, что OSR сработает снова. До V8 v7.9 нам нужно было повторно оптимизировать функцию для OSR. Однако, начиная с v7.9 мы добавили кэширование OSR, чтобы сохранять оптимизированный код для замен OSR, связанный с заголовком цикла, который использовался как точка входа в функцию OSR. Это улучшило производительность некоторых тестов на пиковую производительность на 5–18%.

Улучшение кэширования OSR

WebAssembly

Поддержка нескольких пространств кода

До сих пор каждый модуль WebAssembly состоял ровно из одного пространства кода на 64-битных архитектурах, которое резервировалось при создании модуля. Это позволяло использовать близкие вызовы внутри модуля, но ограничивало нас 128 МБ пространства кода на arm64 и требовало зарезервировать 1 ГБ заранее на x64.

В версии v7.9 V8 появилась поддержка нескольких пространств кода на 64-битных архитектурах. Это позволяет резервировать только оценочное необходимое пространство кода и добавлять дополнительные пространства позже, если это потребуется. Для вызовов между пространствами кода, которые находятся слишком далеко друг от друга для близких переходов, используется дальний переход. Вместо ~1000 модулей WebAssembly на процесс V8 теперь поддерживает несколько миллионов, ограниченных только фактическим доступным объемом памяти.

API V8

Пожалуйста, используйте git log branch-heads/7.8..branch-heads/7.9 include/v8.h, чтобы получить список изменений в API.

Разработчики с активной копией V8 могут использовать git checkout -b 7.9 -t branch-heads/7.9, чтобы экспериментировать с новыми функциями в V8 версии v7.9. В качестве альтернативы вы можете подписаться на Beta-канал Chrome и вскоре самостоятельно опробовать новые функции.