Jeandle JDK или зачем разработчики прикручивают LLVM к виртуальной машине Java
Залезть в кишки компилятора C2 из HotSpot JVM — развлечение не для слабонервных. Си-плюс-плюсный код C2 писался десятилетиями. Он накопил кучу специфичных оптимизаций, но с каждым годом поддерживать его становится все сложнее. В свое время инженерная команда Oracle попыталась облегчить себе жизнь проектом Graal, переписав JIT-компилятор на самой Java. Разработчики проекта Jeandle пошли по другому пути: решили взять готовый фреймворк LLVM и сделать его движком компиляции для OpenJDK.

Что такое Jeandle и зачем ему LLVM
Jeandle — это экспериментальный JIT-компилятор для Java, созданный прямо поверх OpenJDK. Вместо того чтобы полагаться на встроенные компиляторы C1 или C2, он перехватывает выполнение горячего байткода и отдает его на обработку кодогенератору LLVM.
Зачем вообще тащить LLVM в виртуальную машину Java?
Главный плюс LLVM — огромный багаж низкоуровневых оптимизаций, созданный мировым сообществом для C, C++ и Rust. Автоматическая векторизация инструкций, глубокий анализ циклов, оптимизации под особенности конкретных процессоров — все это в LLVM уже есть и регулярно обновляется.
В классическом C2 каждую новую оптимизацию или поддержку свежей процессорной архитектуры (например, RISC-V) приходится выписывать вручную. Скрестив OpenJDK с LLVM, авторы Jeandle рассчитывают получить мощный генератор машинного кода без необходимости переписывать оптимизаторы с нуля.
Как это устроено под капотом
Процесс обработки кода в Jeandle разделен на несколько этапов:
- Виртуальная машина отслеживает часто вызываемые методы приложений.
- Когда байткод метода признается достаточно «горячим», Jeandle транслирует его во внутреннее представление LLVM IR.
- К полученному IR-коду применяются оптимизационные пассы LLVM.
- LLVM компилирует IR в нативный машинный код для целевой платформы (x86_64, AArch64 и др.).
- JVM подменяет ссылку на метод, и дальше выполняется скомпилированный машинный код.
В репозитории проекта авторы уделили внимание документации. В каталоге с гайдами есть описания архитектуры системы, инструкции по сборке и отдельный документ по настройке отладки.
Разработчики вынесли управление поведением компилятора в отдельные JVM-флаги. Через них меняют уровень оптимизаций и запрашивают дамп промежуточного представления LLVM IR прямо во время работы приложения.
Главная проблема JIT на базе LLVM
Идея использовать LLVM в JIT-компиляторах не нова. Ранее подобные попытки предпринимали в проектах Shark для OpenJDK и Falcon от компании Azul. Главное препятствие на этом пути — скорость самой компиляции.
LLVM изначально проектировался для статической компиляции (AOT). В статических компиляторах вроде Clang процесс может идти минуты — главное, чтобы итоговый бинарник работал максимально быстро. В JIT-режиме время компиляции критично. Если LLVM начнет долго и въедливо оптимизировать каждый метод, приложение просто зависнет на этапе разогрева.
Кроме того, перед авторами Jeandle стоит сложная задача по интеграции с рантаймом Java. Компилятору нужно уметь корректно обрабатывать точки остановки для сборщика мусора (Safepoints), работать с барьерами памяти и поддерживать динамическую загрузку классов.
Текущее состояние и перспективы
Сейчас Jeandle находится на стадии активного прототипирования. В репозитории набралось около 460 звезд и свыше 60 открытых задач. Код пока не готов к использованию в продакшене, да и авторы этого не скрывают.
Тем не менее проект будет интересен сразу нескольким категориям инженеров:
- Тем, кто изучает внутреннее устройство JVM и хочет понять работу JIT на реальном примере.
- Разработчикам компиляторов, ищущим практические кейсы интеграции LLVM IR.
- Исследователям, создающим кастомные профили оптимизаций под специфичные процессорные архитектуры.
Исходники открыты под лицензией GPL v2.0. Если вы хотите разобраться, как скрестить виртуальную машину Java с нативным компилятором, загляните в документацию проекта — там детально разобран процесс сборки и архитектурные решения.
