FPC JVM/Internals/ru
│
English (en) │
русский (ru) │
Изменения в компиляторе
Генерация кода во время компиляции
Реализация языка паскаль на уроне JVM потребовал дополнительных обёрток кода:
- все record-ы - становятся классами, с дополнительными скрытыми методами (инициализация, полное копирование);
- для каждого публичного/защищённого свойства (property) или поля (field) класса созданы метод для доступа (если таковых не объявлено явно). …todo…since the property can be used from code that does not have access to the original symbol (resulting in class verification errors);
- перечисляемые типы - так же становятся ява классами, к ним так же добавляются некоторые дополнительные поля и методы;
- в JVM конструкторы не вызывают конструкторы родительских классов. FPC компилятор сам генерирует код для этих вызовов.
- процедурных типов нет в JVM. Компилятор их эмеулирует через классы. Эти классы содержат метод, который сохраняет все параметры и затем вызывает через via.reflect.Method.invoke()
- виртуальных конструкторов и виртуальных класс-методов так же нет в JVM - и эмулируются компилятором через дополнительные классы.
- …
Обёрток достаточно большое количество, и для каждого "обёрточного" случая можно написать дополнительные исключения в компиляторе создав свои описания (definitions) и узлы (nodes). Но если делать обёртки на уровне самого паскаль кода, то их гораздо проще писать и поддерживать. Для генерации динамического паскаль-кода на стадии компиляции используется специальный модуль symcreat. В компилятор позволяет разбирать объявления и реализацию методов а так же объявления типизированных констант в динамически создаваемом коде.
Сразу после того, как объявление метода (method declaration) было распарено или создано каким-либо иным путём для него создаётся структура procdef. Полю synthetickind этой структуры можно задать значение любой из tks_* констант, объявленных в модуле symdef. Это укажет какой год необходимо генерировать для объявленного метода. Функция symcreate.add_synthetic_method_implemementations_for_struct() занимается тем, что создаёт вспомогательный код в исходном Паскаль коде, разбирает его и компилирует в машинный или байт код.
Особенности:
- автоматически генерируемый Паскаль код - всегда в режиме objfpc, вне зависимости от указаго синтаксиса в модуле;
- генерируемый код может делать только то, что и обычный исходный код;
Типизированные константы
В Java-class файлах нет секции данных, как в обычных исполняемых файлах. В результате, инициализация данных должна быть выполнена через явное присваивание значений в секции инициализации (~unit initialization) Основной функционал модуля ptconst был вынесет в модуль ngtcon. Генерация инициализации типизированных констант выполняется классом TTypedConstBuilder. Сам класс - абстрактный, но для него объявлено два дочерних класса-реализации:
- TAsmListTypedConstBuilder - занимается инциализаций костант для нативных платформ (используя .data секцию исполняемого файла).
- TNodeTreeTypedConsBuilder - занимается генерацией инициалирующего кода для JVM платформы, и любой другой платформы, где значение констант нужно задавать явным присваиванием.
Оба класса так же могут быть переопределены для каких-либо специфических требований платформы.
В зависимости от значения константы systems.systems_typed_constants_node_init создаётся класс AsmList или NodeTree.
Вложенные функции
В JVM нет указателя на фрейм, которые можно было бы передавать между процедурами. Для платформы был разработан иной способ доступа к вложенных функций к переменным внешней функции. Для этой цели, во вложенную функцию передаются все используемые переменные внешней функции через дополнительную структуру, передаваемую как скрытый параметр. Структура имеет название parentfpstruct.
В тех случаях, когда вложенная функция вызывает собственную вложенную функцию, параметр parentfpstruct так же передаётся на следующий уровень. Такая цепочная передача переменных позволяет реализовать доступность внешних переменных с любого уровня вложенности.
Для тех платформ, которые не используют стандартный механизм framepointer, необходимо использовать модули ncgnstld (вместо ncgld) и ncgnstmm (вместо ncgmem) и/или переопределить классы, объявленные в этих модулях, чтобы генерировать необходимый для платформы код.