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

Генерация MSIL

Прочие команды MSIL

Упомянем вкратце некоторые интересные команды MSIL, которые редко встречаются в традиционных ассемблерах.

Во-первых, внимания заслуживают специальные команды BOX и UNBOX, реализующие функциональность упаковки и распаковки значений (см. "лекцию 2" ).

Во-вторых, в MSIL предусмотрена специальная команда для создания нового объекта - NEWOBJ. Семантика этой команды такова: создается новый объект и для него вызывается конструктор. Эта операция является критичной для обеспечения целостности данных, так как при ее выполнении гарантируется инициализация объекта (а иначе появляется потенциальная возможность использования "мусорных" ссылочных значений).

В-третьих, отметим, что MSIL содержит специальные команды для обработки исключений ( THROW, RETHROW, ENDFINALLY, ENDFILTER, LEAVE ), что не очень традиционно для низкоуровневых языков.Общая идея реализации исключений заключается в следующем: транслятором создается специальная таблица обработчиков исключений в данном try -блоке; затем при возникновении исключения виртуальная машина .NET просматривает эти таблицы и вызывает соответствующие обработчики. На самом деле, детали реализации исключений не очень существенны, так как при генерации MSIL можно воспользоваться существующими примитивами более высокого уровня (см. ниже про Reflection.Emit ).

Трансляция в MSIL: исходный текст на C-бемоль

Трансляция в MSIL: исходный текст на C \flat

using System;
class Fib // числа Фибоначчи
{
  public static void Main (String[] args)
    {
      int a = 1, b = 1;
      for (int i = 1; i != 10; ++i)
        {
          Console.WriteLine (a);
          int c = a + b;
          a = b; b = c;
        }
    }
}

Продемонстрируем трансляцию в MSIL на примере следующей программы, написанной на C \flat и вычисляющей числа Фибоначчи:

using System;

class Fib
{
   public static void Main (String[] args)
   {
      int a = 1, b = 1;
      for (int i = 1; i != 10; ++i)
      {
         Console.WriteLine (a);
         int c = a + b;
         a = b; b = c;
      }
   }
}

На следующих слайдах мы покажем результаты трансляции этой программы в MSIL.

Трансляция в MSIL: пример

// объявление имени assembly
.assembly fib as "fib" { /* здесь могут быть параметры */ }.class public Fib {
  .method public static void Main () {
    .entrypoint // означает начало assembly       
       .locals (int32 a, int32 b)
       ldc.i4.1  // загрузка константы 1
       stloc   a // сохранение 1 в a (a = 1)
       ldc.i4.1
       stloc   b // аналогично: b = 1
       ldc.i4.1  // загрузка 1 на стек (счетчик цикла)
Loop:   
        ldloc   a
        call    void System.Console::WriteLine(int32)         
        ldloc   a // stack: 1 a
        ldloc   b // stack: 1 a b
        add       // stack: 1 (a+b)
        ldloc   b
        stloc   a // a = b
        stloc   b // b = (a+b)
        ldc.i4.1
        add     // инкремент счетчика
        dup 
        ldc.i4.s   10
        bne.un.s   Loop // сравнение и переход на новую итерацию
        pop  // удаление счетчика цикла со стека
        ret
  }
}

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

Затем объявляется класс Fib , в котором производятся вычисления. Здесь же находится основная точка входа в сборку ( .entrypoint внутри Main ). Затем объявляются локальные переменные; отметим, что в процессе реальной трансляции имена этих переменных будут утеряны.

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

Затем происходит сравнение счетчика цикла с максимальным значением цикла и в случае выполнения неравенства " счетчик не равен 10 " происходит переход на начало цикла. По окончании цикла происходит удаление счетчика цикла со стека и выход из метода.