Рабочим названием платформы .NET было |
Динамическая генерация кода
Генерация линейных участков кода для стековой машины
В этом разделе мы рассмотрим специфику генерации линейных участков кода на языке CIL.
Линейными участками мы будем называть участки кода, не содержащие развилок и защищенных блоков.
Генерация кода для выражений
Вообще говоря, линейные участки кода получаются, главным образом, в процессе генерации кода для выражений. Естественно, выражения бывают разные, и заранее неизвестно, какого именно типа выражения придется генерировать в различных задачах, связанных с динамической генерацией кода. Поэтому мы рассмотрим некоторый тип выражений, наиболее часто встречающийся на практике, и покажем, как для выражений этого типа порождать линейные последовательности инструкций CIL.
Абстрактный синтаксис выражений
Пусть наши выражения оперируют с константами, переменными и параметрами. Разрешим использование в выражениях как значений примитивных типов, так и объектов (в частности, массивов). В качестве операций мы будем использовать четыре арифметические бинарные операции, унарный минус, обращение к полю объекта, доступ к элементу массива и вызов экземплярного метода объекта.
Пусть абстрактный синтаксис для наших выражений содержит правила, приведенные в таблице 5.2.
Отображение абстрактного синтаксиса выражений в CIL
Определим набор функций, отображающих различные деревья абстрактного синтаксиса в соответствующие им последовательности инструкций CIL.
Будем считать, что каждая функция принимает в качестве параметра дерево абстрактного синтаксиса (оно записывается в квадратных скобках) и возвращает последовательность инструкций (при этом запятые обозначают операцию объединения последовательностей):
GenExpr[const c] = нужный вариант инструкции ldc; GenExpr[local x] = ldloc x; GenExpr[arg x] = ldarg x; GenExpr[Expr1 index Expr2] = GenExpr[Expr1], GenExpr[Expr2], ldelem.нужный тип; GenExpr[Expr field f] = GenExpr[Expr], ldfld f; GenExpr[minus Expr] = GenExpr[Expr], neg; GenExpr[Expr1 BinOp Expr2] = GenExpr[Expr1], GenExpr[Expr2], GenBinOp[BinOp]; GenExpr[local x assign Expr] = GenExpr[Expr], dup, stloc x; GenExpr[arg x assign Expr] = GenExpr[Expr], dup, starg x; GenExpr[Expr1 index Expr2 assign Expr3] = GenExpr[Expr1], GenExpr[Expr2], GenExpr[Expr3], dup, stloc временная переменная, stelem.нужный тип, ldloc временная переменная; GenExpr[Expr1 field f assign Expr2] = GenExpr[Expr1], GenExpr[Expr2], dup, stloc временная переменная, stfld f, ldloc временная переменная; GenExpr[Expr call s ArgList] = GenExpr[Expr], GenArgList[ArgList], call(callvirt) s; GenArgList[Expr ArgList] = GenExpr[Expr], GenArgList[ArgList]; GenArgList[пусто] = ; GenBinOp[plus] = add; GenBinOp[minus] = sub; GenBinOp[mul] = mul; GenBinOp[div] = div;