Шрифт:
Как видите, в CIL при размещении локальных переменных сначала используется директива .locals с атрибутом init. При этом в скобках каждая переменная связывается со своим числовым индексом (здесь это [0], [1] и [2]). Каждый индекс идентифицируется типом данных и (необязательно) именем переменной. После определения локальных переменных соответствующее значение загружается в стек (с помощью подходящих кодов операций, связанных с загрузкой) и запоминается в локальной переменной (с помощью подходящих кодов операций для сохранения значений).
Связывание параметров с локальными переменными
Вы только что видели, как в CIL с помощью .local init объявляются локальные переменные, однако нужно еще выяснить, как передать отступающие параметры локальным методом. Рассмотрим следующий статический метод C#.
Этот внешне "невинный" метод в терминах CIL существенно более "многословен". Во-первых, поступающие аргументы (а и b) следует поместить в виртуальный стек выполнение с помощью кода операций ldarg (загрузка аргумента). Затем используется код операции add, чтобы извлечь два значения из стека, найти сумму и снова сохранить значение в стеке. Наконец, эта сумма извлекается из стена и возвращается вызывающей стороне с помощью кода операции ret. Если дизассемблировать указанный метод C# с помощью ildasm.exe, вы обнаружите, что компилятор csc.exe добавляет множество дополнительных лексем, хотя сущность CIL-кода оказывается исключительно простой.
Скрытая ссылка this
Обратите внимание на то, что в рамках программного кода CIL для ссылок на два входных аргумента (а и b) используются их индексы позиции (индекс 0 и индекс 1, поскольку индексация в виртуальном стеке выполнения начинается с нуля).
При анализе программного кода и его создании непосредственно в CIL следует быть очень внимательным, поскольку каждый (нестатический) метод, имеющий входные аргументы, автоматически получает неявный дополнительный параметр, который является ссылкой на текущий объект (это должно вызвать аналогию с ключевым словом C# this). Поэтому, если определить метод Add, как нестатический
то входные аргументы а и b будут загружаться с помощью ldarg.1 и ldarg.2 (а не с помощью ожидаемых ldarg.0 и ldarg.1). Причина как раз в том, что ячейка 0 будет содержать неявную ссылку this. Рассмотрите следующий псевдокод.
Представление итерационных конструкций
Итерационные конструкции в языке программирования C# представляются с помощью ключевых слов for, foreach, while и do, каждое из которых имеет свое специальное представление в CIL. Рассмотрим классический цикл for.