Опубликован: 23.07.2006 | Доступ: свободный | Студентов: 2218 / 892 | Оценка: 4.28 / 4.17 | Длительность: 21:37:00
Специальности: Системный архитектор
Лекция 14:

Генерация MSIL

Арифметические команды MSIL

Арифметические команды позволяют выполнять вычисления. Все они берут аргументы со стека и кладут на их место результат.

Команды целочисленной арифметики существуют в знаковом и беззнаковом (с суффиксом .u) вариантах и могут быть записаны с суффиксом обработки переполнения (.ovf), который порождает исключение при возникновении переполнения. К этим командам относятся: ADD, SUB, MUL, DIV, MOD.

Также есть логические операции, которые не могут быть знаковыми или иметь суффикс контроля за переполнением. Логические операции делятся на бинарные ( AND, OR, XOR ) и унарные ( NOT, NEG ).

Наконец, в MSIL есть некоторый набор операций сравнения. Эти операции снимают со стека операнды и помещают на их место результат 0/1. Они могут быть беззнаковыми или знаковыми (с суффиксом .s). Кроме того, существуют специальные варианты сравнения, учитывающие возможность сравнения чисел с плавающей запятой различного порядка (такие операции имеют суффикс .un).

Интересно отметить, что при наличии полного комплекта операций перехода, создатели MSIL не включили в систему команд операций сравнения " <= " и " >= " Это приводит к тому, что для целочисленных значений операцию " <= " приходится эмулировать с помощью следующего набора команд:

cgt; ldc.i4.0; ceq

Соответственно, для вещественных значений операцию " <= " необходимо представлять аналогично, только первая команда должна быть заменена на cgt.un. Тем не менее, с точки зрения конечной программы в машинных кодах это, видимо, несущественно, так как такой набор операций легко соптимизировать в одну ассемблерную команду целевой архитектуры.

Переходы и вызовы в MSIL

Переходы в .NET мало чем отличаются от используемых в обычных ассемблерах. Сразу отметим, что все команды переходов существуют в стандартном и коротком виде (для записи коротких переходов используется суффикс .s). Помимо обычного безусловного перехода ( BR ), в MSIL существует целый ряд условных переходов ( BEQ, BNE, BGT, BRFALSE - переход по false, null или нулю на верхушке стека - и все прочие переходы, включая беззнаковые и неупорядоченные варианты).

Существует две основных команды вызова:

  • вызов статического метода ( CALL )
  • вызов виртуального метода ( CALLVIRT )

Если вызывается метод экземпляра объекта, то объект, которому он принадлежит, должен быть первым параметром; для CALLVIRT этот параметр обязателен, поскольку виртуальных статических методов в .NET не бывает.

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

Помимо основных методов вызова, .NET предоставляет команду CALLI, выполняющую небезопасный вызов процедуры по адресу точки входа.

Возврат осуществляется командой RET, которая для методов, не возвращающих результат, не имеет параметров. Для всех прочих методов эта команда ожидает параметр - возвращаемое значение на верхушке стека.