Разработка компиляторов

       

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


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

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

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

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

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

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

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



Содержание раздела