Общая схема работы движка
Как V8 подготавливает код, выполняет функции и управляет памятью.
Подведём итог раздела «Движок JavaScript»: повторим, как движок подготавливает и выполняет код, хранит объекты и освобождает память.
V8 получает текст JavaScript и подготавливает инструкции для его выполнения. Рассмотрим функцию, которая создаёт объект врага:
function spawnEnemy() {
return { hp: 100 };
}
От текста к выполнению
Интерактивная схема для примера выше. Каждый этап передаёт результат следующему. В V8 парсер получает токены от сканера по мере разбора; здесь эти действия разделены. Дерево и байткод показаны упрощённо.
-
Сканер выделяет токены
Разбивает текст на части: слово
return, имя свойстваhp, число100, скобки и другие знаки.Текст → токеныОжидает исходный текст.
Токены → парсеруfunctionspawnEnemy(){return{hp:100};} -
Парсер строит AST
По токенам собирает дерево, описывающее структуру программы. Здесь дерево показывает: функция возвращает объект со свойством
hp: 100.Токены → дерево программыОжидает токены от сканера.
AST → генератору байткода- Функция
spawnEnemy- Тело функции
- Возврат
return- Объект
- Свойство
hp- Число
100
- Число
- Свойство
- Объект
- Возврат
- Тело функции
- Функция
-
Генератор байткода создаёт инструкции
Обходит AST и записывает операции для интерпретатора. В нашем примере их смысл: создать объект, затем вернуть его.
AST → байткодОжидает AST от парсера.
Байткод → IgnitionCREATE_OBJECT { hp: 100 }Создать объектRETURNВернуть егоУчебный псевдобайткод: названия инструкций условные. Объект появится при вызове функции.
-
Ignition выполняет байткод
Читает инструкции и выполняет соответствующие операции. CPU при этом исполняет машинный код самого интерпретатора.
Байткод → выполнение операцийОжидает байткод от генератора.
Результат вызова spawnEnemy(){ hp: 100 }Ignition выполнил инструкции: объект создан и возвращён из функции.
V8 также может с помощью JIT-компилятора создать машинный код функции. Тогда CPU выполняет эту версию функции напрямую. В обоих случаях программа должна получить тот же результат.
Что происходит с вызовом и объектом
Когда программа выполняет const enemy = spawnEnemy(), происходит следующее:
- Начинается вызов. Движок сохраняет данные вызова в стеке: какую функцию выполняем и куда вернуться после неё.
- Создаётся объект. V8 выделяет для него память в куче и записывает
hp: 100. - Функция возвращает результат. Вызов завершается, а переменная
enemyполучает ссылку на созданный объект.
Программа продолжает работу после вызова.
enemy → { hp: 100 }Объект доступен через ссылку из переменной.
Если объект сохранён ещё и в массиве врагов, доступ к нему остаётся через массив. Когда путей от корней к объекту больше нет, сборщик мусора сможет освободить его память.