Рабочим названием платформы .NET было |
Common Intermediate Language
Инструкции для организации передачи управления
Инструкции для организации передачи управления можно разделить на пять категорий:
- инструкции безусловного перехода;
- инструкции условного перехода;
- инструкция множественного выбора switch;
- инструкция вызова метода call;
- инструкция возврата из метода ret.
Безусловный переход
Существуют две инструкции безусловного перехода (см. таблицу 3.18), которые различаются только разрядностью встроенного операнда ( int8 и int32 ). При этом встроенный операнд этих инструкций обозначает относительное смещение цели перехода.
Код | Инструкция | Встроенный операнд | Описание |
---|---|---|---|
0x2B | br.s | int8 | Короткий безусловный переход |
0x38 | br. | int32 | Длинный безусловный переход |
Условный переход
Базовые инструкции условного перехода, приведенные в таблице 3.19, потребляют со стека вычислений один операнд и, в зависимости от его значения, осуществляют или не осуществляют переход по указанному во встроенном операнде относительному адресу. Диаграмма стека для этих инструкций выглядит следующим образом:
... , value -> ...
Код | Инструкция | Встроенный операнд | Описание |
---|---|---|---|
0x2C | brfalse.s | int8 | Короткий условный переход, если значение равно 0 или null |
0x2D | brtrue.s | int8 | Короткий условный переход, если значение не равно 0 или null |
0x39 | brfalse | int32 | Длинный условный переход, если значение равно 0 или null |
0x3A | brtrue | int32 | Длинный условный переход, если значение не равно 0 или null |
Как и в случае инструкций безусловного перехода, существуют короткий и длинный варианты инструкций условного перехода, которые отличаются только разрядностью встроенного операнда ( int8 и int32 ).
Инструкции brfalse присвоены два псевдонима: brnull и brzero, имеющих одинаковый с ней код. Аналогично, brfalse.s имеет псевдонимы brnull.s и brzero.s.
Кроме базовых, существуют дополнительные инструкции условного перехода, потребляющие сразу два операнда. Каждая из дополнительных инструкций условного перехода является сокращенной записью последовательности из двух инструкций, первая из которых является бинарной операцией сравнения, а вторая - базовой инструкцией условного перехода.
Таким образом, дополнительные инструкции условного перехода имеют следующую диаграмму стека:
... , value1 , value2 -> ...
Длинные варианты дополнительных инструкций условного перехода перечислены в таблице 3.20, а короткие - в таблице 3.21. В описании каждой инструкции приводится эквивалентная ей комбинация бинарной операции сравнения и базовой инструкции условного перехода. В связи с тем, что семантика операций сравнения для целых чисел существенно отличается от их семантики для чисел с плавающей запятой, для инструкций bge, ble, bge.un и ble.un (и для коротких вариантов этих инструкций) приводится по две эквивалентные им комбинации. Комбинация, помеченная меткой ( int ), используется в случае целых операндов, а комбинация, помеченная меткой ( F ), используется в том случае, если операнды представляют собой числа с плавающей запятой.
Инструкция switch
Инструкция множественного выбора switch представлена в таблице 3.22. Встроенный операнд этой инструкции имеет сложный формат: первое 32-разрядное слово содержит размер N таблицы переходов, после чего следует N 32-рязрядных относительных смещений целей перехода.
Инструкция switch берет со стека вычислений один операнд. Обозначим этот операнд через I. Значение I интерпретируется как целое число без знака и сравнивается с N. Если I < N, то управление передается на I-тую цель в таблице переходов (нумерация целей осуществляется с 0). Если I >= N, то управление передается на инструкцию, непосредственно следующую за инструкцией switch.
Для инструкции switch можно записать следующую диаграмму стека:
... , value -> ...
Код | Инструкция | Встроенный операнд | Описание |
---|---|---|---|
0x45 | switch |
unsigned int32, int32,... int32, |
Осуществляет переход по таблице переходов в соответствии со значением на вершине стека |
Инструкция call
Инструкция call (см. таблицу 3.23) выполняет вызов метода, который указан во встроенном операнде инструкции. Встроенный операнд представляет собой токен метаданных, указывающий на описывающую вызываемый метод запись в таблицах метаданных. Непосредственно перед инструкцией call может стоять префикс .tail, который говорит о том, что состояние текущего метода должно быть освобождено перед передачей управления вызываемому методу (хвостовой вызов).
Код | Инструкция | Встроенный операнд | Описание |
---|---|---|---|
0x28 | call | token | Выполняет вызов метода |
Информация о методе, на которую указывает токен метаданных, позволяет JIT-компилятору определить, является ли вызываемый метод статическим, экземплярным, виртуальным или глобальной функцией. Особенностью инструкции call (по сравнению с инструкцией callvirt, которую мы будем рассматривать далее в этой главе) является то, что адрес вызываемого метода вычисляется статически, то есть еще во время JIT-компиляции.
Параметры вызываемого метода должны быть расположены в стеке слева направо, то есть сначала на стек должен быть загружен первый параметр, затем второй и т.д. При вызове экземплярного метода в качестве первого параметра должна выступать объектная ссылка (параметр this ).
Если вызываемый метод возвращает значение, то оно загружается на стек вызывающего метода.
Инструкция ret
Инструкция ret (см. таблицу 3.24) осуществляет возврат из метода. Если метод возвращает значение, то оно должно быть загружено на вершину стека вычислений.