SOOT
Компилятор и виртуальная машина для строго типизированного языка с интерактивной разработкой
| English | Русский |
О проекте
Я уже довольно давно разрабатываю компилятор и виртуальную машину (VM) для его рантайма. В основном в одиночку, и в первую очередь потому, что хотела с самых основ разобраться, как такие сложные системы устроены изнутри.
Проект давно перерос рамки простого компилятора. Теперь в нём есть:
- сборщик мусора;
- инкрементальный REPL;
- планировщик для выполнения скриптовых конечных автоматов с фиксированной частотой 60 Гц.
Происхождение
Сам компилятор вырос из кода OpenGOAL (открытого проекта по переработке Jak & Daxter). Архитектура виртуальной машины основана на моих собственных исследованиях: с помощью написанных на Python утилит я проанализировала форматы байткода скриптов игры и объединила эти данные с публичными докладами студии и технической документацией.
Прямой бинарной совместимости я не добиваюсь. Там, где оригинальное устройство было неясным или недокументированным, я проектировала собственные архитектурные решения.
Какие вопросы приходится решать
Каждая мелочь требует осознанного решения, и даже самый незначительный нюанс каскадом увеличивает общую сложность системы. Например:
- Как REPL должен компилировать новое выражение в контексте всего, что было введено до него?
- Каковы компромиссы использования сборщика мусора в рантайме реального времени?
- Что значит «кадр 10»: 10-й тик или 11-й?
Ни один из этих вопросов не тривиален, и каждый ответ напрямую определяет поведение всего движка.
Цикл статей
В этом цикле я рассказываю об инженерных решениях, которые стоят за проектом: об альтернативах, которые я рассматривала, о логике, которая привела к итоговому выбору, и о компромиссах, с которыми пришлось согласиться.
- Обзор архитектуры SOOT
История разработки SOOT и обзор его архитектуры: путь от нескольких запусков на разных языках до системы типов, интерпретатора и компилятора на C++; почему код генерируется для виртуальной машины, а не для процессора; устройство VM (32-битные инструкции, дерево
StackFrame) и формат бинарного файла. - Инкрементальная интерактивная компиляция: как совместить строгий компилятор и REPL
Как REPL использует тот же компилятор, что и сборка проекта: модуль на каждый ввод, глобальная таблица имён, инициализация
top-levelи сознательный отказ от выгрузки модулей. - Управление памятью в SOOT: от reference count к простому сборщику мусора Как менялась модель памяти: от передачи значений и reference count через данные на один кадр к простому неперемещающему сборщику мусора; дескрипторы типов, которые отделяют менеджер памяти от VM, арены и size-class, номер прохода вместо сброса меток, инкрементальный sweep, известные ограничения и планы по улучшению.
- Анатомия интерпретатора SOOT: три инженерных решения
Как интерпретатор помогает находить ошибки:
TextDbсвязывает S-выражения с местом в исходном коде,vararg_checkописывает контракт аргументов встроенных функций в одну строку, а накопление трассировки и обработчики ошибок на самом языке дают управляемое выполнение; происхождение этих механизмов от GOOS и их цена. - Variant: универсальный контейнер данных виртуальной машины
Как устроены регистры виртуальной машины: тег плюс union из трёх типов (целое, вещественное, указатель); почему идея хранить тип в виде CRC оказалась тупиковой; почему от суррогатных типов (булево значение,
StringId, строка) пришлось отказаться, раз система команд не гарантирует их правильную установку; как показывать значения в терминале на стороне инструментов; связь с сборщиком мусора и передача аргументов в нативные функции. - Глобальная область видимости: почему в SOOT нет приватных имён
Почему все определения всех модулей живут в одной глобальной области: во что обошлась бы изоляция модулей виртуальной машине, где каждый вызов начинается с поиска по имени, как устроен индекс
Globals, чем приходится платить (коллизии имён, нет настоящей инкапсуляции) и как это компенсируется дисциплиной именования, а также планируемыйdefine privateи формат файла с разделением определений на публичные и приватные. - Полиморфизм в SOOT
Как один и тот же вызов
(-> obj method)работает для разных типов объектов: почему методы у структур сами по себе полиморфизма не дают, зачем нужен типbasicс идентификатором типа в заголовке, почему там лежит SID, а не указатель (ради перезагрузки модулей), как инструкцияCallMethodрешает проблему нехватки операндов, и какую цену это стоит; с разбором примера от Lisp до ассемблера. - Модульная система SOOT: полное руководство
Как компилятор и runtime работают с именами, чем
requireотличается отload-module, что сохраняютsave-sessionиsave-module, работа с SIDBase и типичные подводные камни.
Следующие статьи цикла будут добавляться сюда по мере выхода.
Статус
SOOT — молодой проект, он продолжает активно развиваться. Недавно репозиторий был выбран для включения в публичный индекс кода для ИИ-агентов.
Контакты
Сейчас я ищу работу на полную занятость в сферах разработки компиляторов (Compiler Development), инструментария для языков (Language Tooling) и системного программирования (Systems Programming). Если вы работаете в этих областях, буду рада пообщаться.