![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 1 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 1](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94.jpg)
Привет, меня зовут Мялкин Максим, я занимаюсь мобильной разработкой в KTS.
Не за горами выпуск новой версии Kotlin 2.0, основной частью которого является изменение компилятора на K2.
По замерам JB, K2 ускоряет компиляцию на 94%. Также он позволит ускорить разработку новых языковых фич и унифицировать все платформы, предоставляя улучшенную архитектуру для мультиплатформенных проектов.
Но мало кто погружался в то, как работает K2, и чем он отличается от K1.
Эта статья более освещает нюансы работы компилятора, которые будут полезны разработчикам для понимания, что же JB улучшают под капотом, и как это работает.
Контент статьи основывается на выступлении и овервью, но с добавлением дополнительной информации.
Оглавление
Как работает компилятор
Для начала поговорим о компиляторах в целом. По сути, компилятор — это программа. Она принимает код на языке программирования и превращает его в машинный код, который компьютер может исполнить.
Чтобы превратить исходный код в машинный, компилятор проводит несколько промежуточных преобразований. Если очень упростить, то компилятор делает две вещи:
-
меняет формат данных (compiling)
-
упрощает его (lowering)
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 2 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 2](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-2.png)
Иногда стандартных функций Kotlin недостаточно. В таких случаях разработчики выходят за рамки стандартных инструментов и используют плагины компилятора.
Плагины встраиваются в работу компилятора Kotlin на различных фазах компиляции и меняют стандартное преобразование кода компилятором.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 3 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 3](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-3.png)
Плагины компилятора используют такие библиотек как Jetpack Compose, Kotlinx serialization.
Kotlin компилятор состоит из 2 частей:
-
Frontend
-
отвечает за построение синтаксического дерева (структуры кода) и добавление семантической информации (смысл кода)
-
-
Backend
-
отвечает за генерацию кода для целевой (target) платформы: JVM, JS, Native, WASM (экспериментальный)
-
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 4 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 4](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-4.png)
Остановимся подробнее на каждой из частей.
Frontend
У компилятора Kotlin есть две фронтенд-реализации:
-
K1 (FE10-)
-
K2 (Fir-)
Упрощенно весь процесс работы фронтенда выглядит так:
-
Компилятор принимает исходный код
-
Производит синтаксический и семантический анализ кода
-
Отправляет данные на бэкенд для последующей генерации IR (Intermediate representation) и целевого кода платформы (target)
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 5 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 5](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-5.png)
Обе реализации похожи, но K2 вводит дополнительное форматирование данных перед тем, как отправить преобразованный код на бэкенд.
Реализация K1
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 6 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 6](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-6.png)
Реализация K1 работает c:
-
PSI (Programming Structure Interface)
-
PSI — это слой платформы IntelliJ, который занимается парсингом файлов и созданием синтаксических и семантических моделей кода (что такое синтаксис и семантика рассмотрим позже)
-
-
-
В зависимости от типа элемента дескрипторы могут содержать разную информацию о нем. Например дескриптор класса: контент класса, overrides, companion object и тд.
-
-
BindingContext — это Map, которая содержит информацию о программе и дополняет PSI.
Во время обработки K1 отправляет PSI и BindingContext на Backend, который на входе использует преобразование PSI в IR (Psi2Ir) для дальнейшей работы.
Как работает K1
Общая схема работы выглядит следующим образом
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 7 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 7](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-7.png)
Есть 2 фазы:
-
Parsing Phase — разбирает что именно написал разработчик. На этой фазе еще неизвестно, будет ли компилироваться написанный код. Здесь проверяется, что код написан синтаксически верно.
-
Resolution Phase — производит анализ, необходимый для понимания, будет ли код компилироваться и является ли он семантически правильным (более детальный разбор Resolution Phase).
Разберём дальше разницу между синтаксисом и семантикой.
Чтобы разобраться в работе компилятора K1, предположим, что у нас есть исходный код
fun two() = 2
Пока что для компилятора это только строка текста.
Parsing Phase
Задача синтаксического парсинга
Задача парсинга — проверить структуру программы и убедиться, что она верная и следует грамматическим правилам языка.
Пример:
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 8 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 8](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-8.png)
Этапы Parsing phase
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 9 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 9](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-9.png)
-
Все начинается с лексического анализа (Lexer Analysis). Сначала Kotlin Parser сканирует исходный код (строку) и разбивает его на лексические части (KtTokens). Например:
-
(
—>KtSingleValueToken.LPAR
-
)
—>KtSingleValueToken.RPAR
-
=
—>KtSingleValueToken.EQ
В нашем примере разбиение на токены выглядит так:
Пробелы тоже превращаются в токены. Но они не обозначены, чтобы не перегружать лишней информацией.
-
-
Далее начинается синтаксический анализ (Syntax Analysis). Его первый этап — это построение абстрактного синтаксического дерева (AST), которое состоит из лексических токенов. Важная особенность: дерево уже представляет из себя не последовательность символов, а имеет структуру.
Обратите внимание, что структура этого дерева совпадает со структурой нашего исходного кода. В нашем примере это выглядит так:
-
Следующим этапом мы накладываем PSI на узлы абстрактного синтаксического дерева. Теперь у нас есть PSI-дерево, которое содержит дополнительную информацию по каждому элементу:
На этом этапе мы ищем только синтаксические ошибки. Другими словами, мы видим правильно написанный код, но пока не можем предсказать, скомпилируется он или нет и самое главное не понимаем смысл этого кода.
В IntelliJ IDEA, вы можете загрузить плагин PSIViewer чтобы смотреть PSI для кода, написанного вами.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 13 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 13](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-13.png)
Resolution Phase
Задача семантического парсинга
Чтобы понять смысл написанного кода используется Resolution Phase.
Здесь PSI-дерево проходит набор этапов, в процессе которых генерируется семантическая информация, позволяющая понять (resolving) имена функций, типов, переменных и откуда они взялись.
Все мы в коде видели ошибки из этой стадии.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 14 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 14](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-14.png)
Семантическая информация содержит данные о:
Переменных и параметрах
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 15 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 15](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-15.jpg)
На стадии семантического анализа нужно понять, что, используя pet внутри функции play, мы используем параметр функции, объявленный в первой строке
Типах
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 16 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 16](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-16.png)
Семантическая информация содержит данные о том, на какие типы ссылается код, в каком месте они объявлены.
Вызовах функций
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 17 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 17](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-17.png)
Может существовать много функций meow, и требуется определить, какую именно функцию нужно вызвать. Эта стадия занимает большую часть семантического анализа. Тк meow может быть: обычной функцией внутри класса, extension, property. Функция может находиться внутри текущего модуля, другого модуля или в библиотеке. На этапе семантического анализа нужно найти все функции с нужным названием и выбрать наиболее подходящую функцию для конкретной ситуации.
Эта стадия отвечает на похожие вопросы:
-
Откуда появилась эта функция/переменная/тип для использования
-
Точно ли две строки относятся к одной и той же переменной или это разные переменные в зависимости от контекста где они используются?
-
Какой тип у конкретного объекта?
Производится выведение типов
val list1 = listOf(1, 2, 3)
val list2 = listOf("one", "two", "three")
Представим, что у нас есть такая запись.
Тут используется generic-функция listOf
public fun <T> listOf(vararg elements: T): List<T>
Задача семантического анализа — вывести аргументы типа для каждого использования
val list1 = listOf(1, 2, 3)
В первом случае T = Int
val list2 = listOf("one", "two", "three")
Во втором — T = String.
Этапы Resolution Phase
Реализация K1 выполняет вычисление на PSI-дереве, создает дескрипторы и BindingContext map, а затем передает все это на бэкенд. В итоге бэкенд преобразует полученную информацию в IR с помощью Psi2Ir.
Вся эта информация будет использоваться дальше на бэкенде:
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 18 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 18](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-18.png)
Пример с деревом PSI и семантической информацией BindingContext
В этом примере можно увидеть как исходный код (строка) преобразуется в структуру (дерево) и по каждому узлу дерева добавляется дополнительная информация (семантика).
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 19 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 19](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-19.png)
Проблемы K1
Мы разобрались с тем, как работает фронтенд-реализация K1. Обозначим этот процесс на схеме K1:
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 20 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 20](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-20.png)
У этой реализации есть свои недостатки (объяснение Дмитрия Новожилова в kotlin slack). Преобразование через PSI и BindingContext приводит к проблемам с производительностью компилятора.
Тк компилятор работает с ленивыми дескрипторами, то выполнение постоянно прыгает между разными частями кода, это сводит на нет некоторые JIT-оптимизации. Кроме этого много информации resolution phase хранится в большом BindingContext, из-за этого ЦП не может хорошо кэшировать объекты.
Все это ведет к проблемам с производительностью.
Реализация K2
Чтобы повысить производительность компилятора и улучшить архитектуру решения, JB создала новую фронтенд-реализацию K2 (Fir frontend).
Изменение произошло в структурах данных. Вместо старых структур (PSI + BindingContext) реализация K2 использует Fir (Frontend Intermediate Representation). Это семантическое дерево (дерево, в узлах которого к структуре кода добавлена семантическая информация). Оно представляет исходный код.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 21 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 21](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-21.png)
Как работает K2
Вместо того, чтобы как раньше отправлять PSI и BindingContext в Backend, в K2 на Frontend происходят дополнительные преобразования:
В случае с K2, мы рассмотрим более сложный случай и пропустим те фазы, в которых K1 и K2 работают одинаково.
Для примера возьмем исходный код
private val kotlinFiles = mutableListOf(1, 2, 3)
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 22 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 22](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-22.png)
Parsing
Начнем с уровня PSI (до этого K1 и K2 схожи):
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 23 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 23](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-23.png)
В этом случае, реализация K1 просто генерировала бы дополнительные данные для отправки PSI на бэкенд.
Psi2Fir
В отличие от нее, K2 компилирует этот промежуточный формат данных перед созданием Ir. В итоге получается Fir — это mutable-дерево, построенное из результатов парсера (PSI-дерева):
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 24 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 24](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-24.png)
Тут видно сходство между PSI и raw Fir.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 25 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 25](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-25.png)
Resolution
Итак, мы создаем raw FIR и пересылаем его нескольким обработчикам. Они представляют собой различные этапы пайплайна компилятора и заполняют дерево семантической информацией:
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 26 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 26](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-26.png)
Все файлы в модуле проходят эти этапы одновременно.
В это время выполняются такие действия, как:
-
Вычисление import’ов
-
Поиск идентификаторов класса для супертипов и наследников sealed классов
-
Вычисление модификаторов видимости
-
Вычисление контрактов функций
-
Выведение типов возвращаемого значения
-
Анализ тел функций и свойств
На стадии Resolution компилятор преобразует сгенерированное raw Fir, заполняя дерево семантической информацией:
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 27 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 27](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-27.png)
На этих этапах компилятор выполняет desugaring. Например, `if` можно заменить на `when` или `for` — на `while`.
Раньше мы делали все это на Backend, но благодаря K2 то же самое можно делать на Frontend.
Checking
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 28 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 28](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-28.png)
Мы пришли к последней стадии — стадии проверки. Здесь компилятор берет Fir и проводит диагностику на предмет предупреждений и ошибок.
Если ошибки появились, данные отправляются плагину IDEA — именно он подчеркивает ошибку красной линией. Компиляция останавливается, чтобы не отправлять неверный код на бэкенд.
Fir2Ir
Если ошибок нет
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 29 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 29](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-29.png)
FIR трансформируется в IR
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 30 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 30](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-30.png)
В итоге мы получаем входные данные для бэкенда
Визуальное сравнение результатов K1 и K2
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 31 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 31](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-31.png)
Итого в K2 мы получили Fir (одну структуру данных вместо двух в K1 версии)
Backend
Цели улучшения Backend
Изначально при разработке Kotlin компилятор не использовал промежуточное представление (IR). Тк это необязательная стадия при разработке компиляторов.
Каноничная архитектура компилятора
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 32 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 32](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-32.png)
Отсутствие IR позволило Kotlin быстрее эволюционировать на ранних стадиях. Kotlin компилировался не только в JVM, но так же и в JS. JS высокоуровневый язык и он похож больше на Kotlin, чем на JVM байткод. Поэтому IR бы только тормозило разработку преобразования.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 33 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 33](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-33.png)
Но вскоре появился еще 1 native backend.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 34 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 34](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-34.png)
Стало понятно что все 3 бэкенда могут использовать общую логику по трансформации и упрощению кода, что позволит поддерживать фичи для разных бекендов проще. Поэтому начиная с native-backend команда Kotlin решила использовать IR, сначала только для него самого.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 35 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 35](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-35.png)
Итак, в качестве целей разработки новой версии можно выделить:
-
переиспользование логики между разными бекендами
-
упрощение поддержки новых языковых возможностей
Необходимо отметить, что ускорение Backend не являлось целью. В отличие от ускорения Frontend-части.
Новая реализация Backend позволила расширять компилятор с помощью компиляторных плагинов. В частности реализация Jetpack Compose полагается на новую версию бекенда c использованием IR.
Как работает Backend
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 36 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 36](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-36.png)
Сейчас в Kotlin есть четыре реализации backend:
-
JVM
-
JS
-
Native
-
WASM
Какой бы бэкенд вы ни использовали, обработка в нем всегда начинается с генератора IR и оптимизатора. Затем выбранная конфигурация запускает сгенерированный код:
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 37 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 37](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-37.png)
Для примера выберем бэкенд JVM и продолжим работу с mutableList
IR
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 38 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 38](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-38.png)
IR это также дерево. В IR добавлена вся семантическая информация. Для человека IR на выглядит не очень читабельно, но зато такой вид гораздо понятнее для компилятора. В момент анализа IR создаются поток управления и стеки вызовов.
Можно рассматривать IR как представление кода в виде дерева, которое разработано специально для генерации кода target-платформы. В отличие от Fir на фронтенде, который проверяет смысл написанного кода.
IR lowering
Затем на IR выполняются оптимизации и упрощения это называется lowering. Таким образом упрощается сложность Kotlin. Например в IR отсутствуют local и internal классы, они заменены отдельными классами со специальными именами. С помощью упрощений разным backend’ам не нужно бороться со сложностью языка Kotlin и реализация становится проще.
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 39 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 39](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-39.png)
Также на этом этапе упрощаются операции, улучшается производительность и качество машинного кода, особенно с точки зрения многопоточности.
Target code
Теперь у нас есть сгенерированный код целевой платформы. В нашем примере это JVM байт-код. Далее он отправляется на виртуальную машину, где он и будет исполняться:
![Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 40 Как новый компилятор K2 ускоряет компиляцию Kotlin на 94% - 40](https://www.pvsm.ru/images/2024/05/12/kak-novyi-kompilyator-K2-uskoryaet-kompilyaciyu-Kotlin-na-94-40.png)
На этом задачи компилятора считаются выполненными.
Выводы
Что дает новый компилятор:
-
Единая структура данных Fir для представления кода и семантики
-
Возможность добавления плагинов компилятора
-
Упрощение поддержки новых языковых возможностей для разных target-платформ.
-
Улучшение производительности компилятора и IDE (плагин Kotlin в IDE использует Frontend компилятора). По результатам замеров JB:
-
ускорение компиляции на 94%
-
ускорение фазы инициализации на 488%
-
ускорение фазы анализа на 376%
-
В этой статье мы рассмотрели как работают разные версии компилятора Kotlin. Непосредственно в эту тему редко углубляются разработчики. Я надеюсь, что материал позволил заглянуть вам под капот и узнать, что же там происходит, когда вы каждый день собираете приложения на работе.
Дополнительные материалы
-
Видео Crash Course on the Kotlin Compiler by Amanda Hinchman-Dominguez
-
Видео KotlinConf 2018 - Writing Your First Kotlin Compiler Plugin by Kevin Most
-
Видео What Everyone Must Know About The NEW Kotlin K2 Compiler
-
Видео A Hitchhiker's Guide to Compose Compiler: Composers, Compiler Plugins, and Snapshots
-
Репозиторий Kotlin-Compiler-Crash-Course с заметками об отладке, тестировании и настройке компилятора Kotlin
-
Цикл статей Crash course on the Kotlin compiler
Автор: Мялкин Максим