Языки программирования Лекция 10

реклама
Лекция 10
• Генерация CIL
• Генерация Java bytecode
• Оптимизация
Common Intermediate Language
• Common Intermediate Language (CIL) —
промежуточный язык, разработанный фирмой
Microsoft для платформы .NET Framework.
• JIT-компилятор CIL является частью так
называемой CLR (Common Language Runtime) —
общей среды выполнения языков .NET.
• Ранее язык назывался Microsoft Intermediate
Language (MSIL), однако был переименован для
создания стандарта ECMA-335.
Жизненный цикл кода .Net
• Процесс выполнения:
1. Исходный код транслируется в CIL
2. CIL транслируется в объектный код и
генерируется .NET assembly
3. В момент исполнения объектный код
передается JIT-компилятору и
транслируется в машинный код (native
code). Возможна замена этапа на Aheadof-time compilation
4. Исполнение машинного кода
Виртуальная машина CIL
• Машина является стековой. Стек - статически типизирован (в
каждой точке программы JIT-compiler может статически
определить типы содержимого всех ячеек стека). В результате
- невозможен код, пишущий в цикле значения на стек
• Ячейки стека представлены как 4-байтовые или 8-байтовые
знаковые целовые (обозначаемые как I4 и I8, соответственно;
более короткие значения представляются как 4-байтовые);
• Стек используется в основном для хранения промежуточных
результатов вычисления (т.е. не рекомендуется хранить на
стеке временные переменные, такие, как счетчик цикла и т.п.)
• Большинство команд CIL получают свои аргументы на стеке,
удаляют их со стека и помещают вместо них результат.
• Машина является объектно-ориентированной: структура CIL
отражает разбиение кода на классы, методы и т.п.
Группы инструкций в CIL
•
•
•
•
•
•
•
•
•
Загрузка и хранение значений
Арифметические
Преобразование типов
Создание и управление объектами
Управление стеком операндов (push / pop)
Контроль за исполнением (ветвление)
Вызов методов и возврат значений
Вызов исключений
Синхронизация на основе Монитора
Хранении переменных в СIL
• в статической области памяти,
существующей все время выполнения
программы
• в локальной области, которая выделяется
при входе в метод;
• внутри объекта, размещенного в куче.
Пример кода
• Пример программы Hello, World, написанной
на CIL. Она выводит строку «Hello, world!».
C#
CIL
JVM как backend
•
•
•
•
Трансляция в язык Java
Генерация в байт-кода напрямую в JVM Class
Ассемблер Jasmin с трансляцией в JVM Class
Генерация байт-кода через ASM framework
или BCEL(Byte Code Engineering Library)
Java Virtual Machine
• Java Virtual Machine (Java VM, JVM) —
виртуальная машина Java — основная часть
исполняющей системы Java, так
называемой Java Runtime Environment (JRE).
• Java VM интерпретирует и исполняет Байткод Java (Java bytecode), предварительно
созданный из исходного текста Javaпрограммы компилятором Java (javac)
Java bytecode
• Java bytecode - это инструкции, которые
исполняются JVM
• Каждая инструкция(опкод) длинной один байт.
При наличии параметров – более 1 байта
• Из 256 возможных опкодов 51
зарезервированы для будущего
использования. 3 значения в реализации от
Sun Microsystems считаются не допустимыми и
не будут реализованы в будущем.
Пример байт-кода
public class Foo {
private String bar;
public String getBar(){
return bar;
}
public void setBar(String bar)
{
this.bar = bar;
}
}
public class Foo extends java.lang.Object {
public Foo();
Code:
0: aload_0
1: invokespecial #1; //Method
java/lang/Object."<init>":()V
4: return
public java.lang.String getBar();
Code:
0: aload_0
1: getfield
#2; //Field bar:Ljava/lang/String;
4: areturn
public void setBar(java.lang.String);
Code:
0: aload_0
1: aload_1
2: putfield
#2; //Field bar:Ljava/lang/String;
5: return
}
Группы инструкций в Java bytecode
•
•
•
•
•
•
•
•
Загрузка и хранение значений (aload_0,istore)
Арифметические и логические (ladd,fcmpl)
Преобразование типов (i2b,d2i)
Создание и управление объектами
(new,putfield)
Управление стеком (swap,dup2)
Контроль за исполнением (ifeq,goto)
Вызов методов и возврат значений
(invokespecial,areturn)
Дополнительно: синхронизация и исключения
Префиксы операций для
определения типа операнда
Префикс/Суфикс
Тип опреранда
i
integer
l
long
s
short
b
byte
c
character
f
float
d
double
a
reference
Пример:
Iadd – сложение двух целых чисел
dadd – сложение двух вещественных
Пример
Способы генерации JVM-байткода
• Трансляция в язык Java
• Генерация в байт-кода в виде бинарного
JVM Class файла
• Ассемблер Jasmin с трансляцией в JVM
Class
• Генерация байт-кода через ASM framework
или BCEL(Byte Code Engineering Library)
Генерация в байт-кода в виде
бинарного JVM Class файла
• Необходимо строго соблюдать формат class-файлов,
в котором каждый байт должен быть на своем месте
и несет свои значения;
• Кроме генерации последовательности опкодов
необходимо также предусматривать описание
самого класса, его полей, методов, переменных, а
так же пула констант, внутри которого должны
храниться все литералы, имена классов и методов;
• Каждая из этих констант представляет из себя
сложную структуру, содержащую внутри себя другие
структуры;
• Нужно работать не с ascii-представлением опкодов,
а с их бинарными "номерами“;
• Отладка кодогенерации затруднена.
Ассемблер Jasmin
• Jasmin - открытый опенсорс ассемблер,
позволяющий создавать class-файлы с
использованием синтаксиса наподобие x86ассемблера с помощью набора команд JVM;
• Jasmin принимает ASCII описание JVM классов
и генерирует для них бинарные JVM Class
файлы, совместимые с средой Java Runtime;
• Решает проблемы, связанные с константами,
номерами оппкодов и сложной структурой
файлов.
Фреймворк ASM и библиотека BCEL
• ASM – фреймворк для управление и анализа JB;
• The Byte Code Engineering Library – библиотека,
предоставляющая инструмента для генерации JVM
Class в виде объектно-ориентированной модели;
• Предоставляют удобные (особенно bcel) API для
чтения, изменения, создания и модификации байткода
для JSM;
• Все это удобней, чем даже Jasmin, но интерфейсы есть
только для Java, что не позволяет использовать при
разработке транслятора написанного на других языках.
Оптимизация
• Общая схема фаз компиляции
Исходная
программа
Токен
Лексический
анализатор
запрос
следующего
Синтаксический
анализатор
Дерево
разбора
Семантический
разбор
Интерпретация
Компиляция
Оптимизация
ПЯ
Генерация ПЯ
Оптимизация
Исходная
программа
Пользователь
оптимизирует
программу
Front-end
Промежуточный
код
Компилятор
усовершенствует
циклы, вызовы
процедур, производит
вычисление
Генерация кода
Целевой
код
Компилятор
оптимизирует выбор
регистров, делает
локальные
преобразования
Наилучшее преобразование
программы – те, которые приводят к
максимальному результату при
минимальных усилиях
Оптимизирующий компилятор
Начальная
стадия
Анализ
потока
управления
Оптимизатор
кода
Анализ
потока
данных
Генератор кода
Преобразование
кода
•Удаление общих подвыражений
•Размножение копий кода
•Оптимизация и раскрытие циклов
•Удаление недоступного кода
•Удаление не используемых констант
• Оптимизация − это процесс, связанный с
обработкой промежуточного или уже
порожденного целевого кода и оказывающий
существенное влияние на качество и
эффективность результирующей программы.
• Оптимизация:
– на уровне исходного языка
– машинно-зависимая
– машинно-независимая
o локальная (линейный участок, группа операторов)
o глобальная (процедура целиком)
o межпроцедурная
Стадии оптимизации
Низкоуровневая оптимизация
• Оптимальный выбор (замена,
объединение, разделение) инструкций
• Переупорядочивание инструкций
• Распределение регистров
• Удаление цепочек переходов
• Векторизация
• Понижение силы операций
Def-Use Chains
Операторы:
Ω={ ω1, ω2,…, ωn} - алфавит операторов
I={i1,i2,…,ik} - алфавит входов
O={o1,o2,…,om} - алфавит выходов
input : Ω → 2I - входы операторов,
output : Ω → 2O- выходы операторов
∀ ω1, ω2∈Ω ω1≠ω2 ⇒
input( ω1)∩input( ω2)=∅ & output( ω1)∩output( ω2)=∅
Def-Use разметка:
DU: O → 2I
∀ω∈Ω
def (ω)=output(ω)
use(ω)= ∪i∈input(ω) {o∈O | i∈DU(o)}
Объединение и разделение
инструкций
• Данный метод оптимизации состоит в
замене одной или нескольких инструкций
другим, но функционально эквивалентным
набором, дающим выигрыш для целевой
архитектуры.
• Пример:
Pentium MMX
dec ecx
jnz label1
80286 (x86)
vs
loop label1
Покадровая оптимизация
Удаление пустого оператора
Высокоуровневая оптимизация
• Удаление недосягаемого («мёртвого») кода и
неиспользуемых присвоений
• Оптимизация множественных ветвлений
• Развёртка, свёртка, объединение и разделение циклов
• Вычисление инвариантов циклов, вынесение общих
подвыражений и кода в ветвлениях, вынесение
ветвлений из циклов
• Переключение, объединение и разделение ветвлений
• Предвыборка данных
• Переупорядочевание функций
• Встраивание и извлечение функций
Глобальная оптимизация
• Глобальная оптимизация основывается на
глобальном потоковом анализе, который
выполняется на графе программы и
фактически представляет из себя
преобразование этого графа.
• Дополнительно может быть проведен анализ
отдельных характеристик программы:
– межпроцедурный анализ
– межмодульный анализ
– анализ областей жизни переменных
Локальная оптимизация
• Локальная оптимизация – обработка тела
отдельных подпрограмм.
– излишние загрузки/сохранения
– недостижимый код
– оптимизация потока управления
– алгебраические упрощения
– снижение стоимости вычислений
Скачать