Опубликован: 13.10.2008 | Уровень: специалист | Доступ: платный
Лекция 3:

Phoenix

< Лекция 2 || Лекция 3: 12 || Лекция 4 >
Аннотация: Платформа Microsoft для построения компиляторов, средств анализа, оптимизации и верификации кода. Обзор составляющих

Введение в компиляцию

Компилятор - это программа, которая считывает текст на одном языке (исходном) и переводит (транслирует) его в эквивалентный текст на другом языке (целевом). Одним из важных моментов такого преобразования является сообщение пользователю о наличии ошибок в исходной программе.

Концептуально компилятор работает пофазно, причем в процессе каждой фазы происходит преобразование исходной программы из одного представления в другое. На рис. 1 приведено типичное разбиение компилятора на фазы.

Поясним фазы компиляции. Лексический анализ - анализ исходной программы, при котором поток символов исходной программы считывается слева направо и группируется в токены (token), представляющие собой последовательности символов с определенным совокупным значением.

Синтаксический анализ - анализ, при котором символы или токены иерархически группируются во вложенные конструкции с совокупным значением. Токены исходной программы группируются в грамматически фразы, используемые компилятором для синтеза вывода. Обычно грамматические фразы исходной программы представляются в виде дерева.

В процессе семантического анализа проверяется наличие семантических ошибок в исходной программе и накапливается информация о типах для следующей стадии - генерации кода. При таком анализе используются иерархические структуры, полученные во время синтаксического анализа для идентификации операторов и операндов выражений и инструкций. Важным аспектом семантического анализа является проверка типов, когда компилятор проверяет, что каждый оператор имеет операнды допустимого спецификациями языка типа.

После синтаксического и семантического анализа некоторые компиляторы генерируют явное промежуточное представление исходной программы, которое можно рассматривать как программу для абстрактной машины. Это представление должно легко создаваться и транслироваться в целевую программу.

При оптимизации кода производятся попытки улучшить промежуточный код, чтобы получить более эффективный машинный код.

Последняя фаза компиляции состоит в генерации целевого кода, обычно перемещаемого машинного кода или ассемблерного кода.

Фазы компилятора

Рис. 3.1. Фазы компилятора

Компиляторы весьма разнообразны. Используются тысячи исходных языков, от традиционных языков высокого уровня (таких как С# или Pascal) до специализированных, возникающих во всех областях компьютерных приложений. Целевые языки не менее разнообразны: это могут быть другие языки программирования, различные машинные языки - от языков микропроцессоров до суперкомпьютеров.

Иногда компиляторы классифицируют как однопроходные, многопроходные, исполняющие (load-and-go), отлаживающие, оптимизирующие - в зависимости от предназначения, принципов и технологий создания. Несмотря на разнообразие, основные задачи, выполняемые компиляторами, по сути одни и те же. Понимая эти задачи, можно создавать компиляторы для различных исходных языков и целевых машин с использованием одних и тех же базовых технологий.

Основы Phoenix

Phoenix - это инфраструктура для разработки компиляторов, средств анализа кода, его оптимизации и тестирования.

Phoenix предоставляет множество строительных блоков, реализованных на основе промежуточного представления - Common Intermediate Representation (CIR), для создания перечисленных инструментальных средств. Phoenix может быть использован в задачах генерации кода для различных архитектур процессоров.

Промежуточное представление (Intermediate Representation - IR)

IR представляет собой строго типизированное линейное представление потока инструкций. IR представляет функции на нескольких уровнях абстракции: от высокого машинно-независимого (HIR) до низкого машинно-зависимого (LIR).

Инфраструктура Phoenix использует промежуточное представление, чтобы представить поток функций в виде наборов операций передачи данных и/или управления.

Инфраструктура хранит промежуточное представление функции в виде двусвязного списка инструкций. Каждая инструкция содержит оператор, список исходных и результирующих операндов. На основе промежуточного представления строятся все остальные представления кода - граф потока управления, синтаксические деревья и др.

IR строго типизировано. Тип результата определяется операндом и типами входных операндов. Инфраструктура Phoenix предоставляет средства для проверки соответствия типов.

Во время обработки HIR Phoenix предоставляет информацию о потоках данных в виде дерева выражений. В процессе обработки эти деревья преобразуются. То есть преобразование промежуточного представления кода выглядит как последовательность деревьев выражений.

Код на языках высокого уровня (таких как C++, C# или J#) преобразуется в промежуточное представление при помощи компонент Phoenix. Инструментальные средства на основе Phoenix используют промежуточное представление. Таким образом, они могут обрабатывать код, изначально написанный на разных языках. Например, компоненты анализа, оптимизации или верификации, работающие с IR, могут быть повторно использованы в компиляторах различных языков высокого уровня.

Промежуточное представление позволяет абстрагироваться от конкретного типа процессора, что делает код переносимым.

Кроме того, применение промежуточного представления позволяет легче интегрировать код на разных языках.

Фазы компиляции

Phoenix представляет процесс работы с кодом (компиляции или анализа) в виде последовательности фаз. На каждой фазе выполняется группа действий, тесно связных между собой. Фазы хранятся в виде упорядоченного списка и выполняются одна за другой. При этом возможны ситуации межфазового взаимодействия, это требуется для выполнения действия перед началом одной из фаз или после ее завершения.

Средство, разрабатываемое на основе Phoenix, создает список фаз. Инфраструктура Phoenix и различные расширения (plug-in) могут изменять этот список.

В Phoenix существует контейнер для списков фаз. Кроме списков фаз, он содержит список обработчиков окончания соответствующих фаз, список обработчиков, исполняемых перед началом фаз, и указатель на память, используемую объектом Lifetime. Все фазы и объекты, обрабатывающие завершение и начало фаз, получают память при помощи Lifetime.

Сборки и модули

Сборка является основной программной единицей Phoenix. Сборка содержит логически связанные модули и файлы ресурсов. Сборка является наименьшей единицей компиляции, которой может быть присвоена версия и к которой применяются механизмы защиты.

Сборка может содержать управляемые и неуправляемые модули. В нее также могут входить файлы, написанные на разных языках программирования.

Сборка всегда содержит манифест. Манифест - структура данных, содержащая имя сборки, номер версии, данные о региональной принадлежности, список файлов, формирующих сборку, а также общедоступные типы, реализованные в файлах сборки.

Сборка позволяет разделить логическое и физическое понятия повторно используемого компонента с управляемыми версиями. Сборки содержат сведения о других сборках, на которые они ссылаются, включая номера версий. Это делает сборку самоописываемой. То есть общеязыковая исполняющая среда (CLR) знает о сборке все, что нужно для ее выполнения. Значит, развертывать сборки проще, чем неуправляемые компоненты.

Помимо сборки существуют другие единицы компиляции. Инфраструктура Phoenix создает скомпилированные модули на разных фазах компиляции. В этих модулях содержатся код и структуры данных, используемые при анализе кода. В таблице приведены описания модулей в иерархии модулей IR.

Модуль IR Описание
FuncUnit Содержит информацию, требуемую для компиляции одной функции
DataUnit Представляет коллекцию взаимосвязанных данных (например, коллекция инициализированных переменных)
ModuleUnit Содержит коллекцию функций
PEModuleUnit Содержит результат компиляции в виде PE-образа (portable executable image), например в виде EXE или DLL
AssemblyUnit Содержит скомпилированную сборку .NET Framework
ProgramUnit Представляет собой исполняемый образ, например EXE или DLL
GlobalUnit Представляет собой единицу компиляции самого верхнего уровня

Система типов

Система типов Phoenix служит основой для генерации кода, отслеживания указателей (pointer tracking), высокоуровневой оптимизации и отладки объектного кода. Компиляторы и другие средства, основанные на Phoenix, используют систему типов для проверки соответствия типов в промежуточном представлении кода.

Система типов Phoenix предоставляет средства для создания правил проверки типов (контекст, ограничения и др.). Компилятор или другое средство может создать собственное множество типов и определить правила проверки. Система типов предоставляет высокоуровневые и машинно-зависимые типы данных.

Управляемый и неуправляемый режимы компиляции

Инфраструктура Phoenix поддерживает как управляемый, так и неуправляемый режимы.

В управляемом режиме исходный код компилируется в сборки .NET Framework, содержащие код на промежуточном языке (Microsoft intermediate language - MSIL). При запуске такой код преобразуется по запросу (on demand) в машинный код и исполняется в рамках общеязыковой исполняющей среды (common language runtime).Преобразование по запросу, как правило, означает, что при первом вызове определенного участка кода (например, метода) этот код преобразуется из MSIL в машинный код, исполняется и кэшируется на случай повторного вызова.

В неуправляемом режиме исходный код компилируется напрямую в машинный код.

Выбор режима компиляции определяется множеством факторов. Управляемый код позволяет напрямую использовать инфраструктуру .NET Framework, автоматическое управление памятью, управление версиями и возможности защиты кода. Поскольку неуправляемый код не должен проходить проверку на безопасность типов и получать одобрение на каждое действие со стороны общеязыковой исполняющей среды .NET Framework, такой код может работать быстрее. Однако, в случае неуправляемого кода задачи управления памятью будет решать разрабатываемое на основе Phoenix инструментальное средство или программист.

< Лекция 2 || Лекция 3: 12 || Лекция 4 >
Ринат Гатауллин
Ринат Гатауллин

Здравствуйте. Интересует возможность получения диплома( https://intuit.ru/sites/default/files/diploma/examples/P/955/Nekommerch-2-1-PRF-example.jpg ). Курс пройден. Сертификат не подходит. В сертификате ошибка, указано по датам время прохождения около 14 дней, хотя написано 576 часов.

Вячеслав Кузнецов
Вячеслав Кузнецов

Здравствуйте.

Как оплатить курс?

Дмитрий Черкасов
Дмитрий Черкасов
Россия, Москва
Иван Герасимов
Иван Герасимов
Россия, калининград, Балтийский институт экономики и финансов, 2013