Common Intermediate Language и системное программирование в Microsoft .NET

Язык CIL: инструкции для поддержки объектной модели

Разбить на страницы
Показывать лекцию целиком

Язык CIL, в отличие от большинства других ассемблерных языков, содержит богатый набор инструкций, предназначенных для поддержки объектной модели. Этот набор можно разделить на четыре основные категории:

  • инструкции для работы с объектами;
  • инструкции для работы с массивами;
  • инструкции для работы с типами-значениями;
  • инструкции для работы с типизированными ссылками.
  • Инструкции для работы с объектами

    Инструкции для работы с объектами - это базовые инструкции для поддержки объектно-ориентированной парадигмы.

    Создание объектов

    Инструкция newobj (см. таблицу 3.25) выполняет выделение памяти для объекта в куче и затем вызывает для этого объекта конструктор. Операции выделения памяти и вызова конструктора объединены в одной инструкции не случайно, так как это гарантирует отсутствие в куче неинициализированных объектов.

    Инструкция newobj
    Код Инструкция Встроенный операнд Описание
    0x73 newobj token Создает новый объект и вызывает для него конструктор

    Токен метаданных, находящийся во встроенном операнде инструкции, указывает на описатель конструктора в таблицах метаданных. Тип создаваемого объекта определяется через информацию о конструкторе (это тот класс, внутри которого объявлен конструктор).

    Диаграмма стека для инструкции newobj:

    ... , arg1, ... , argN -> ... , obj

    Инструкция newobj потребляет со стека вычислений параметры конструктора и оставляет на стеке ссылку на созданный объект. Параметры вызываемого конструктора должны быть расположены в стеке слева направо, то есть сначала на стек должен быть загружен первый аргумент, затем второй и т.д.

    Хотя первым (неявным) параметром для любого конструктора является ссылка на инициализируемый объект (параметр this ), перед вызовом инструкции newobj этот параметр не должен загружаться на стек вычислений. Дело в том, что ссылка на объект формируется в процессе выполнения инструкции (после выделения памяти в куче и до вызова конструктора) и затем автоматически передается конструктору. Происходит как бы "подкладывание" ссылки this под другие параметры конструктора на стеке вычислений.

    Особый случай применения инструкции newobj связан с созданием экземпляров типов-значений на стеке вычислений. Если указанный во встроенном операнде конструктор принадлежит типу-значению, то новый экземпляр этого типа создается не в куче, а прямо на стеке вычислений.

    Проверка типа объекта

    В таблице 3.26 приведены две инструкции, осуществляющие проверку типа объекта, ссылка на который лежит на вершине стека вычислений. Токен метаданных, находящийся во встроенном операнде инструкции, указывает на описатель типа в таблицах метаданных.

    Инструкции проверки типа объекта
    Код Инструкция Встроенный операнд Описание
    0x74 castclass token Проверяет, соответствует ли тип объекта на вершине стека. В случае несоответствия генерирует исключение InvalidCastException
    0x75 isinst token Проверяет, соответствует ли тип объекта на вершине стека. Если соответствует, то оставляет объект на стеке, в противном случае заменяет объект на null

    Диаграмма стека для инструкций проверки типа объекта:

    ... , obj -> ... , obj

    Через инструкции проверки типа объекта реализуются операции приведения типов в языках высокого уровня.

    Работа с полями объектов

    В таблице 3.27 приведены инструкции, которые загружают на стек вычислений значения и адреса полей объектов, а также сохраняют значения со стека в полях объектов. Токены метаданных во встроенных операндах инструкций указывают на информацию о нужном поле.

    Инструкции для работы с полями объектов
    Код Инструкция Встроенный операнд Описание
    0x7B ldfld token Загружает значение поля объекта. Диаграмма стека:
    ..., obj -> ..., value
    0x7C ldflda token Загружает адрес поля объекта. Диаграмма стека:
    ..., obj -> ..., addr
    0x7D stfld token Сохраняет значение в поле объекта. Диаграмма стека:
    ..., obj, value -> ...
    0x7E ldsfld token Загружает значение статического поля объекта. Диаграмма стека:
    ... -> ..., value
    0x7F ldsflda token Загружает адрес статического поля объекта. Диаграмма стека:
    ...  -> ..., addr
    0x80 stsfld token Сохраняет значение в статическом поле объекта. Диаграмма стека:
    ..., val -> ...

    Вызов виртуальных методов

    Инструкция callvirt (см. таблицу 3.28) отличается от инструкции call главным образом тем, что адрес вызываемого метода определяется во время выполнения программы путем анализа типа объекта, для которого вызывается метод. Тем самым реализуется идея позднего связывания, необходимая для поддержки полиморфизма.

    Диаграмма стека для инструкции callvirt:

    ... , obj, arg1, ... , argN -> ... , retVal
    Инструкция callvirt
    Код Инструкция Встроенный операнд Описание
    0x6F callvirt token Вызов метода с использованием позднего связывания

    Токен метаданных, находящийся во встроенном операнде инструкции, указывает на информацию о вызываемом методе в таблицах метаданных (имя метода, класс и сигнатура). Определение метода, который нужно вызвать, происходит следующим образом. Система выполнения анализирует класс объекта, для которого вызывается метод (на диаграмме стека этот объект обозначен как obj ), выполняя поиск принадлежащего этому классу экземплярного метода, имеющего нужные имя и сигнатуру. Если такой метод отсутствует, аналогичный поиск производится по порядку на всей цепочке суперклассов, от которых наследует класс объекта. Если в результате метод не будет найден, то генерируется исключение MissingMethodException, но эта ситуация невозможна в верифицированном коде.

    Загрузка строковых констант

    Для загрузки на стек вычислений строковых констант предусмотрена отдельная инструкция ldstr, приведенная в таблице 3.29. Токен, находящийся во встроенном операнде инструкции, указывает на образ строки в куче пользовательских строк, находящейся в составе метаданных. Инструкция создает объект класса System.String, копирует в него образ строки и оставляет ссылку на созданный объект на вершине стека вычислений.

    Инструкция ldstr
    Код Инструкция Встроенный операнд Описание
    0x72 ldstr token Создает на вершине стека объект-строку

    Диаграмма стека для инструкции ldstr:

    ... -> ... , obj

    Инструкции для работы с массивами

    В принципе, массивы являются такими же объектами, как и экземпляры других классов. Но для более эффективной реализации и для сокращения размеров CIL-кода в наборе инструкций CLI предусмотрена специальная инструкция для работы с одномерными массивами, индексируемыми с нуля.

    Создание массивов

    Инструкция newarr (см. таблицу 3.30) выделяет память под одномерный массив, индексируемый с нуля. Тип элементов массива указывается через токен метаданных во встроенном операнде инструкции (в качестве типа элементов может выступать тип-значение).

    Инструкция newarr
    Код Инструкция Встроенный операнд Описание
    0x8D newarr token Создает новый массив с элементами указанного типа

    Диаграмма стека для инструкции newarr:

    ... , num -> ... , array

    Инструкция newarr потребляет со стека вычислений размер массива (на диаграмме обозначен как num ) и оставляет объектную ссылку на созданный массив в куче.

    Элементы созданного массива автоматически обнуляются.

    Загрузка длины массива

    Инструкция ldlen (см. таблицу 3.31) загружает размер одномерного массива на стек вычислений.

    Инструкция ldlen
    Код Инструкция Встроенный операнд Описание
    0x8E ldlen - Загружает на стек длину массива

    Диаграмма стека для инструкции ldlen:

    ... , array -> ... , length

    Инструкция потребляет со стека объектную ссылку на массив и оставляет на стеке его размер в виде числа типа native unsigned int.

    Работа с элементами массивов

    Инструкции ldelem (см. таблицу 3.32) предназначены для загрузки значения элемента одномерного массива на стек вычислений.

    Инструкции для загрузки элементов массивов
    Код Инструкция Встроенный операнд Описание
    0x90 ldelem.i1 - Загрузить элемент типа int8
    0x91 ldelem.u1 - Загрузить элемент типа unsigned int8
    0x92 ldelem.i2 - Загрузить элемент типа int16
    0x93 ldelem.u2 - Загрузить элемент типа unsigned int16
    0x94 ldelem.i4 - Загрузить элемент типа int32
    0x95 ldelem.u4 - Загрузить элемент типа unsigned int32
    0x96 ldelem.i8 (ldelem.u8) - Загрузить элемент типа int64 или unsigned int64
    0x97 ldelem.i - Загрузить элемент типа native int или unsigned native int
    0x98 ldelem.r4 - Загрузить элемент типа float32
    0x99 ldelem.r8 - Загрузить элемент типа float64
    0x9A ldelem.ref - Загрузить элемент - объектную ссылку

    Так как в процессе JIT-компиляции не отслеживаются точные типы объектных ссылок на стеке вычислений, то JIT-компилятору требуются указания о том, элементы какого типа содержатся в массиве. Поэтому для разных типов существуют разные варианты инструкции ldelem.

    Следует иметь в виду, что значения целых типов, разрядность которых меньше 32 бит, при загрузке на стек удлиняются. Значения со знаком и значения без знака удлиняются по-разному, поэтому наличие отдельных инструкций для знаковых и беззнаковых целых типов вполне объяснимы. При этом остается неясным, для чего потребовалось определять две инструкции ldelem.i4 и ldelem.u4 для 32-разрядных целых типов, потому что они, очевидно, имеют одинаковый эффект.

    Диаграмма стека для инструкций ldelem выглядит следующим образом:

    ... , array, index -> ... , value

    Инструкция потребляет со стека объектную ссылку на массив и индекс элемента (типа native int ), значение которого надо загрузить.

    Инструкция ldelema (см. таблицу 3.33) загружает на стек вычислений адрес элемента одномерного массива (управляемый указатель). Тип элементов массива указывается через токен метаданных во встроенном операнде инструкции (в качестве типа элементов может выступать тип-значение). Диаграмма стека для нее выглядит следующим образом:

    ... , array, index -> ... , addr
    Инструкция ldelema
    Код Инструкция Встроенный операнд Описание
    0x8F ldelema token Загружает адрес элемента массива с указанным индексом

    Инструкции stelem (см. таблицу 3.34) предназначены для сохранения значения со стека вычислений в элементе одномерного массива. Аналогично инструкциям ldelem, существуют различные варианты stelem для разных типов элементов массива. При этом варианты stelem для беззнаковых целых типов отсутствуют за ненадобностью.

    Диаграмма стека для инструкций stelem:

    ... , array, index, value -> ...
    Инструкции для сохранения значений в элементы массивов
    Код Инструкция Встроенный операнд Описание
    0x9C stelem.i1 - Сохраняет значение типа int8 в элементе массива с указанным индексом
    0x9D stelem.i2 - Сохраняет значение типа int16 в элементе массива с указанным индексом
    0x9E stelem.i4 - Сохраняет значение типа int32 в элементе массива с указанным индексом
    0x9F stelem.i8 - Сохраняет значение типа int64 в элементе массива с указанным индексом
    0xA0 stelem.r4 - Сохраняет значение типа float32 в элементе массива с указанным индексом
    0xA1 stelem.r8 - Сохраняет значение типа float64 в элементе массива с указанным индексом
    0xA2 stelem.ref - Сохраняет значение объектной ссылки в элементе массива с указанным индексом
    0x9B stelem.i - Сохраняет значение типа native int в элементе массива с указанным индексом

    Инструкции для работы с типами-значениями

    Специальный набор инструкций предусмотрен для поддержки операций с типами-значениями.

    Инициализация значения

    Инструкция initobj (см. таблицу 3.35) предназначена для инициализации значения типа-значения. Во встроенном операнде этой инструкции содержится токен метаданных, указывающий на информацию о типе-значении. В отличие от инструкции newobj, инструкция initobj не вызывает конструктор.

    Инструкция initobj потребляет со стека вычислений адрес значения:

    ... , addr -> ...
    Инструкция initobj
    Код Инструкция Встроенный операнд Описание
    0xFE 0x15 initobj token Заполняет все поля значения нулями

    Загрузка размера значения

    Инструкция sizeof (см. таблицу 3.36) загружает на стек вычислений размер в байтах типа-значения (размер представляет собой значение типа unsigned int32 ). Во встроенном операнде этой инструкции содержится токен метаданных, указывающий на информацию о типе-значении.

    Инструкция sizeof
    Код Инструкция Встроенный операнд Описание
    0xFE 0x1C sizeof token Загружает на стек размер значения указанного типа

    Диаграмма стека для инструкций sizeof:

    ... -> ... , size

    Копирование значений

    Инструкции, приведенные в таблице 3.37, выполняют копирование значений типов-значений. Во встроенных операндах этих инструкций содержится токен метаданных, указывающий на информацию о типе-значении в таблицах метаданных.

    Инструкции для копирования значений
    Код Инструкция Встроенный операнд Описание
    0x70 cpobj token Копирует значение. Диаграмма стека:
    ..., destAddr, srcAddr ->...
    (Здесь destAddr - адрес приемника, а srcAddr - адрес источника.)
    0x71 ldobj token Загружает значение на стек вычислений. Диаграмма стека:
    ..., addr, -> ..., val0bj
    (Здесь addr - адрес загружаемого значения.)
    0x81 stobj token Сохраняет значение со стека вычислений в память. Диаграмма стека:
    ..., addr, val0bj ->...
    (Здесь addr - адрес, по которому будет сохранено значение.)

    Инструкция ldobj используется главным образом при вызове методов для загрузки параметров (если вызываемый метод имеет параметры типов-значений). Инструкции cpobj и stobj применяются сравнительно редко, хотя и имеют однобайтовые коды.

    Упаковка и распаковка значений

    Инструкции, приведенные в таблице 3.38, выполняют упаковку и распаковку значений типов-значений. Во встроенных операндах этих инструкций содержится токен метаданных, указывающий на информацию о типе-значении в таблицах метаданных.

    Инструкции для упаковки и распаковки значений
    Код Инструкция Встроенный операнд Описание
    0x79 unbox token Выполняет распаковку значения. Диаграмма стека
    ..., obj ->..., ptr
    0x8C box token Упаковывает значение. Диаграмма стека:
    ..., value ->..., obj

    Выполнение инструкции box заключается в создании в куче "объекта-обертки" для значения, после чего осуществляется побитовое копирование значения внутрь "обертки".

    При распаковке значения с помощью инструкции unbox никакого копирования не происходит. Вместо этого на стек вычислений загружается адрес значения находящегося внутри "обертки".

    Загрузка описателя токена метаданных

    Инструкция ldtoken (см. таблицу 3.39) применяется для работы с библиотекой рефлексии. Фактически она переводит токены метаданных в специальные структуры данных рефлексии. Так как переводимый токен жестко зашит в инструкцию (он находится во встроенном операнде), то можно говорить о том, что инструкция ldtoken представляет собой инструкцию загрузки константы.

    Инструкция ldtoken
    Код Инструкция Встроенный операнд Описание
    0xD0 ldtoken token Загружает описатель токена метаданных (структуру RuntimeTypeHandle, RuntimeMethodHandle, RuntimeFieldHandle )

    Диаграмма стека для инструкций ldtoken:

    ... -> ... , runtimeHandle

    Эта инструкция отнесена к группе инструкций для работы с типами-значениями, потому что описатели токенов представляют собой значения типов-значений.

    Инструкции для работы с типизированными ссылками

    Типизированные ссылки в системе типов .NET реализованы исключительно для поддержки некоторых особенностей синтаксиса и семантики языка Visual Basic .NET. Они представляют собой гибрид управляемого указателя и типа-значения.

    Для работы с типизированными ссылками предусмотрены три инструкции CIL, которые мы рассмотрим в этом разделе.

    Создание типизированной ссылки

    Инструкция mkrefany (см. таблицу 3.40) предназначена для создания типизированных ссылок. Она упаковывает вместе управляемый указатель на некоторое значение и токен метаданных, описывающий тип этого значения. При этом токен содержится во встроенном операнде инструкции.

    Инструкция mkrefany
    Код Инструкция Встроенный операнд Описание
    0xC6 mkrefany token Создает типизированную ссылку на вершине стека вычислений

    Диаграмма стека для инструкций mkrefany:

    ... , ptr -> ... , typedRef

    Загрузка типа типизированной ссылки

    Инструкция refanytype (см. таблицу 3.41) загружает токен метаданных, хранящийся в типизированной ссылке, на вершину стека вычислений.

    Инструкция refanytype
    Код Инструкция Встроенный операнд Описание
    0xFE 0x1D refanytype - Загружает токен, хранящийся в типизированной ссылке

    Диаграмма стека для инструкций refanytype:

    ... , typedRef -> ... , type

    Загрузка значения типизированной ссылки

    Инструкция refanyval (см. таблицу 3.42) загружает управляемый указатель, хранящийся в типизированной ссылке, на вершину стека вычислений.

    Инструкция refanyval
    Код Инструкция Встроенный операнд Описание
    0xC2 refanyval token Загружает адрес, хранящийся в типизированной ссылке

    Диаграмма стека для инструкций refanyval:

    ... , typedRef -> ... , ptr
    Страницы:

    Язык CIL, в отличие от большинства других ассемблерных языков, содержит богатый набор инструкций, предназначенных для поддержки объектной модели. Этот набор можно разделить на четыре основные категории:

  • инструкции для работы с объектами;
  • инструкции для работы с массивами;
  • инструкции для работы с типами-значениями;
  • инструкции для работы с типизированными ссылками.
  • Инструкции для работы с объектами

    Инструкции для работы с объектами - это базовые инструкции для поддержки объектно-ориентированной парадигмы.

    Создание объектов

    Инструкция newobj (см. таблицу 3.25) выполняет выделение памяти для объекта в куче и затем вызывает для этого объекта конструктор. Операции выделения памяти и вызова конструктора объединены в одной инструкции не случайно, так как это гарантирует отсутствие в куче неинициализированных объектов.

    Инструкция newobj
    Код Инструкция Встроенный операнд Описание
    0x73 newobj token Создает новый объект и вызывает для него конструктор

    Токен метаданных, находящийся во встроенном операнде инструкции, указывает на описатель конструктора в таблицах метаданных. Тип создаваемого объекта определяется через информацию о конструкторе (это тот класс, внутри которого объявлен конструктор).

    Диаграмма стека для инструкции newobj:

    ... , arg1, ... , argN -> ... , obj

    Инструкция newobj потребляет со стека вычислений параметры конструктора и оставляет на стеке ссылку на созданный объект. Параметры вызываемого конструктора должны быть расположены в стеке слева направо, то есть сначала на стек должен быть загружен первый аргумент, затем второй и т.д.

    Хотя первым (неявным) параметром для любого конструктора является ссылка на инициализируемый объект (параметр this ), перед вызовом инструкции newobj этот параметр не должен загружаться на стек вычислений. Дело в том, что ссылка на объект формируется в процессе выполнения инструкции (после выделения памяти в куче и до вызова конструктора) и затем автоматически передается конструктору. Происходит как бы "подкладывание" ссылки this под другие параметры конструктора на стеке вычислений.

    Особый случай применения инструкции newobj связан с созданием экземпляров типов-значений на стеке вычислений. Если указанный во встроенном операнде конструктор принадлежит типу-значению, то новый экземпляр этого типа создается не в куче, а прямо на стеке вычислений.

    Проверка типа объекта

    В таблице 3.26 приведены две инструкции, осуществляющие проверку типа объекта, ссылка на который лежит на вершине стека вычислений. Токен метаданных, находящийся во встроенном операнде инструкции, указывает на описатель типа в таблицах метаданных.

    Инструкции проверки типа объекта
    Код Инструкция Встроенный операнд Описание
    0x74 castclass token Проверяет, соответствует ли тип объекта на вершине стека. В случае несоответствия генерирует исключение InvalidCastException
    0x75 isinst token Проверяет, соответствует ли тип объекта на вершине стека. Если соответствует, то оставляет объект на стеке, в противном случае заменяет объект на null

    Диаграмма стека для инструкций проверки типа объекта:

    ... , obj -> ... , obj

    Через инструкции проверки типа объекта реализуются операции приведения типов в языках высокого уровня.

    Работа с полями объектов

    В таблице 3.27 приведены инструкции, которые загружают на стек вычислений значения и адреса полей объектов, а также сохраняют значения со стека в полях объектов. Токены метаданных во встроенных операндах инструкций указывают на информацию о нужном поле.

    Инструкции для работы с полями объектов
    Код Инструкция Встроенный операнд Описание
    0x7B ldfld token Загружает значение поля объекта. Диаграмма стека:
    ..., obj -> ..., value
    0x7C ldflda token Загружает адрес поля объекта. Диаграмма стека:
    ..., obj -> ..., addr
    0x7D stfld token Сохраняет значение в поле объекта. Диаграмма стека:
    ..., obj, value -> ...
    0x7E ldsfld token Загружает значение статического поля объекта. Диаграмма стека:
    ... -> ..., value
    0x7F ldsflda token Загружает адрес статического поля объекта. Диаграмма стека:
    ...  -> ..., addr
    0x80 stsfld token Сохраняет значение в статическом поле объекта. Диаграмма стека:
    ..., val -> ...

    Вызов виртуальных методов

    Инструкция callvirt (см. таблицу 3.28) отличается от инструкции call главным образом тем, что адрес вызываемого метода определяется во время выполнения программы путем анализа типа объекта, для которого вызывается метод. Тем самым реализуется идея позднего связывания, необходимая для поддержки полиморфизма.

    Диаграмма стека для инструкции callvirt:

    ... , obj, arg1, ... , argN -> ... , retVal
    Инструкция callvirt
    Код Инструкция Встроенный операнд Описание
    0x6F callvirt token Вызов метода с использованием позднего связывания

    Токен метаданных, находящийся во встроенном операнде инструкции, указывает на информацию о вызываемом методе в таблицах метаданных (имя метода, класс и сигнатура). Определение метода, который нужно вызвать, происходит следующим образом. Система выполнения анализирует класс объекта, для которого вызывается метод (на диаграмме стека этот объект обозначен как obj ), выполняя поиск принадлежащего этому классу экземплярного метода, имеющего нужные имя и сигнатуру. Если такой метод отсутствует, аналогичный поиск производится по порядку на всей цепочке суперклассов, от которых наследует класс объекта. Если в результате метод не будет найден, то генерируется исключение MissingMethodException, но эта ситуация невозможна в верифицированном коде.

    Загрузка строковых констант

    Для загрузки на стек вычислений строковых констант предусмотрена отдельная инструкция ldstr, приведенная в таблице 3.29. Токен, находящийся во встроенном операнде инструкции, указывает на образ строки в куче пользовательских строк, находящейся в составе метаданных. Инструкция создает объект класса System.String, копирует в него образ строки и оставляет ссылку на созданный объект на вершине стека вычислений.

    Инструкция ldstr
    Код Инструкция Встроенный операнд Описание
    0x72 ldstr token Создает на вершине стека объект-строку

    Диаграмма стека для инструкции ldstr:

    ... -> ... , obj

    Инструкции для работы с массивами

    В принципе, массивы являются такими же объектами, как и экземпляры других классов. Но для более эффективной реализации и для сокращения размеров CIL-кода в наборе инструкций CLI предусмотрена специальная инструкция для работы с одномерными массивами, индексируемыми с нуля.

    Создание массивов

    Инструкция newarr (см. таблицу 3.30) выделяет память под одномерный массив, индексируемый с нуля. Тип элементов массива указывается через токен метаданных во встроенном операнде инструкции (в качестве типа элементов может выступать тип-значение).

    Инструкция newarr
    Код Инструкция Встроенный операнд Описание
    0x8D newarr token Создает новый массив с элементами указанного типа

    Диаграмма стека для инструкции newarr:

    ... , num -> ... , array

    Инструкция newarr потребляет со стека вычислений размер массива (на диаграмме обозначен как num ) и оставляет объектную ссылку на созданный массив в куче.

    Элементы созданного массива автоматически обнуляются.

    Загрузка длины массива

    Инструкция ldlen (см. таблицу 3.31) загружает размер одномерного массива на стек вычислений.

    Инструкция ldlen
    Код Инструкция Встроенный операнд Описание
    0x8E ldlen - Загружает на стек длину массива

    Диаграмма стека для инструкции ldlen:

    ... , array -> ... , length

    Инструкция потребляет со стека объектную ссылку на массив и оставляет на стеке его размер в виде числа типа native unsigned int.

    Работа с элементами массивов

    Инструкции ldelem (см. таблицу 3.32) предназначены для загрузки значения элемента одномерного массива на стек вычислений.

    Инструкции для загрузки элементов массивов
    Код Инструкция Встроенный операнд Описание
    0x90 ldelem.i1 - Загрузить элемент типа int8
    0x91 ldelem.u1 - Загрузить элемент типа unsigned int8
    0x92 ldelem.i2 - Загрузить элемент типа int16
    0x93 ldelem.u2 - Загрузить элемент типа unsigned int16
    0x94 ldelem.i4 - Загрузить элемент типа int32
    0x95 ldelem.u4 - Загрузить элемент типа unsigned int32
    0x96 ldelem.i8 (ldelem.u8) - Загрузить элемент типа int64 или unsigned int64
    0x97 ldelem.i - Загрузить элемент типа native int или unsigned native int
    0x98 ldelem.r4 - Загрузить элемент типа float32
    0x99 ldelem.r8 - Загрузить элемент типа float64
    0x9A ldelem.ref - Загрузить элемент - объектную ссылку

    Так как в процессе JIT-компиляции не отслеживаются точные типы объектных ссылок на стеке вычислений, то JIT-компилятору требуются указания о том, элементы какого типа содержатся в массиве. Поэтому для разных типов существуют разные варианты инструкции ldelem.

    Следует иметь в виду, что значения целых типов, разрядность которых меньше 32 бит, при загрузке на стек удлиняются. Значения со знаком и значения без знака удлиняются по-разному, поэтому наличие отдельных инструкций для знаковых и беззнаковых целых типов вполне объяснимы. При этом остается неясным, для чего потребовалось определять две инструкции ldelem.i4 и ldelem.u4 для 32-разрядных целых типов, потому что они, очевидно, имеют одинаковый эффект.

    Диаграмма стека для инструкций ldelem выглядит следующим образом:

    ... , array, index -> ... , value

    Инструкция потребляет со стека объектную ссылку на массив и индекс элемента (типа native int ), значение которого надо загрузить.

    Инструкция ldelema (см. таблицу 3.33) загружает на стек вычислений адрес элемента одномерного массива (управляемый указатель). Тип элементов массива указывается через токен метаданных во встроенном операнде инструкции (в качестве типа элементов может выступать тип-значение). Диаграмма стека для нее выглядит следующим образом:

    ... , array, index -> ... , addr
    Инструкция ldelema
    Код Инструкция Встроенный операнд Описание
    0x8F ldelema token Загружает адрес элемента массива с указанным индексом

    Инструкции stelem (см. таблицу 3.34) предназначены для сохранения значения со стека вычислений в элементе одномерного массива. Аналогично инструкциям ldelem, существуют различные варианты stelem для разных типов элементов массива. При этом варианты stelem для беззнаковых целых типов отсутствуют за ненадобностью.

    Диаграмма стека для инструкций stelem:

    ... , array, index, value -> ...
    Инструкции для сохранения значений в элементы массивов
    Код Инструкция Встроенный операнд Описание
    0x9C stelem.i1 - Сохраняет значение типа int8 в элементе массива с указанным индексом
    0x9D stelem.i2 - Сохраняет значение типа int16 в элементе массива с указанным индексом
    0x9E stelem.i4 - Сохраняет значение типа int32 в элементе массива с указанным индексом
    0x9F stelem.i8 - Сохраняет значение типа int64 в элементе массива с указанным индексом
    0xA0 stelem.r4 - Сохраняет значение типа float32 в элементе массива с указанным индексом
    0xA1 stelem.r8 - Сохраняет значение типа float64 в элементе массива с указанным индексом
    0xA2 stelem.ref - Сохраняет значение объектной ссылки в элементе массива с указанным индексом
    0x9B stelem.i - Сохраняет значение типа native int в элементе массива с указанным индексом

    Инструкции для работы с типами-значениями

    Специальный набор инструкций предусмотрен для поддержки операций с типами-значениями.

    Инициализация значения

    Инструкция initobj (см. таблицу 3.35) предназначена для инициализации значения типа-значения. Во встроенном операнде этой инструкции содержится токен метаданных, указывающий на информацию о типе-значении. В отличие от инструкции newobj, инструкция initobj не вызывает конструктор.

    Инструкция initobj потребляет со стека вычислений адрес значения:

    ... , addr -> ...
    Инструкция initobj
    Код Инструкция Встроенный операнд Описание
    0xFE 0x15 initobj token Заполняет все поля значения нулями

    Загрузка размера значения

    Инструкция sizeof (см. таблицу 3.36) загружает на стек вычислений размер в байтах типа-значения (размер представляет собой значение типа unsigned int32 ). Во встроенном операнде этой инструкции содержится токен метаданных, указывающий на информацию о типе-значении.

    Инструкция sizeof
    Код Инструкция Встроенный операнд Описание
    0xFE 0x1C sizeof token Загружает на стек размер значения указанного типа

    Диаграмма стека для инструкций sizeof:

    ... -> ... , size

    Копирование значений

    Инструкции, приведенные в таблице 3.37, выполняют копирование значений типов-значений. Во встроенных операндах этих инструкций содержится токен метаданных, указывающий на информацию о типе-значении в таблицах метаданных.

    Инструкции для копирования значений
    Код Инструкция Встроенный операнд Описание
    0x70 cpobj token Копирует значение. Диаграмма стека:
    ..., destAddr, srcAddr ->...
    (Здесь destAddr - адрес приемника, а srcAddr - адрес источника.)
    0x71 ldobj token Загружает значение на стек вычислений. Диаграмма стека:
    ..., addr, -> ..., val0bj
    (Здесь addr - адрес загружаемого значения.)
    0x81 stobj token Сохраняет значение со стека вычислений в память. Диаграмма стека:
    ..., addr, val0bj ->...
    (Здесь addr - адрес, по которому будет сохранено значение.)

    Инструкция ldobj используется главным образом при вызове методов для загрузки параметров (если вызываемый метод имеет параметры типов-значений). Инструкции cpobj и stobj применяются сравнительно редко, хотя и имеют однобайтовые коды.

    Упаковка и распаковка значений

    Инструкции, приведенные в таблице 3.38, выполняют упаковку и распаковку значений типов-значений. Во встроенных операндах этих инструкций содержится токен метаданных, указывающий на информацию о типе-значении в таблицах метаданных.

    Инструкции для упаковки и распаковки значений
    Код Инструкция Встроенный операнд Описание
    0x79 unbox token Выполняет распаковку значения. Диаграмма стека
    ..., obj ->..., ptr
    0x8C box token Упаковывает значение. Диаграмма стека:
    ..., value ->..., obj

    Выполнение инструкции box заключается в создании в куче "объекта-обертки" для значения, после чего осуществляется побитовое копирование значения внутрь "обертки".

    При распаковке значения с помощью инструкции unbox никакого копирования не происходит. Вместо этого на стек вычислений загружается адрес значения находящегося внутри "обертки".

    Загрузка описателя токена метаданных

    Инструкция ldtoken (см. таблицу 3.39) применяется для работы с библиотекой рефлексии. Фактически она переводит токены метаданных в специальные структуры данных рефлексии. Так как переводимый токен жестко зашит в инструкцию (он находится во встроенном операнде), то можно говорить о том, что инструкция ldtoken представляет собой инструкцию загрузки константы.

    Инструкция ldtoken
    Код Инструкция Встроенный операнд Описание
    0xD0 ldtoken token Загружает описатель токена метаданных (структуру RuntimeTypeHandle, RuntimeMethodHandle, RuntimeFieldHandle )

    Диаграмма стека для инструкций ldtoken:

    ... -> ... , runtimeHandle

    Эта инструкция отнесена к группе инструкций для работы с типами-значениями, потому что описатели токенов представляют собой значения типов-значений.

    Инструкции для работы с типизированными ссылками

    Типизированные ссылки в системе типов .NET реализованы исключительно для поддержки некоторых особенностей синтаксиса и семантики языка Visual Basic .NET. Они представляют собой гибрид управляемого указателя и типа-значения.

    Для работы с типизированными ссылками предусмотрены три инструкции CIL, которые мы рассмотрим в этом разделе.

    Создание типизированной ссылки

    Инструкция mkrefany (см. таблицу 3.40) предназначена для создания типизированных ссылок. Она упаковывает вместе управляемый указатель на некоторое значение и токен метаданных, описывающий тип этого значения. При этом токен содержится во встроенном операнде инструкции.

    Инструкция mkrefany
    Код Инструкция Встроенный операнд Описание
    0xC6 mkrefany token Создает типизированную ссылку на вершине стека вычислений

    Диаграмма стека для инструкций mkrefany:

    ... , ptr -> ... , typedRef

    Загрузка типа типизированной ссылки

    Инструкция refanytype (см. таблицу 3.41) загружает токен метаданных, хранящийся в типизированной ссылке, на вершину стека вычислений.

    Инструкция refanytype
    Код Инструкция Встроенный операнд Описание
    0xFE 0x1D refanytype - Загружает токен, хранящийся в типизированной ссылке

    Диаграмма стека для инструкций refanytype:

    ... , typedRef -> ... , type

    Загрузка значения типизированной ссылки

    Инструкция refanyval (см. таблицу 3.42) загружает управляемый указатель, хранящийся в типизированной ссылке, на вершину стека вычислений.

    Инструкция refanyval
    Код Инструкция Встроенный операнд Описание
    0xC2 refanyval token Загружает адрес, хранящийся в типизированной ссылке

    Диаграмма стека для инструкций refanyval:

    ... , typedRef -> ... , ptr
    Вернуться к учебному плану