Какова цель аргумента typeTok для инструкции stelem CIL?

CIL stelem инструкция (III.4.26 в ECMA 335 [pdf]) определяется как

 Формат Сборка Формат Описание
A4  stelem typeTok Заменить элемент массива в индексе на
                                значение в стеке

Переход стека:
…, Массив, индекс, значение,  ->  … 

Я не понимаю, какова цель аргумента typeTok.

Оригинальная спецификация

Ниже приведены все упоминания typeTok в спецификации:

  • В описании:

    Тип значения должен быть совместимым с элементом массива с typeTok в инструкции.

  • В разделе "Корректность":

    typeTok должен быть действительным typedef, typeref, или же typespec токен метаданных.

  • В разделе "Проверяемость":

    • отслеживаемый тип массива T[], для некоторых T;

    • отслеживаемый тип значения совместим с элементами массива с typeTok;

    • typeTok совместим с элементами массива T

Таким образом, typeTok не используется ни для чего; это просто должно быть обеспечено. Другими словами, единственное требование, которое я вижу, это то, что typeTok, который удовлетворяет условиям, должен существовать.

Модифицированная спецификация

Однако требование простого существования такого typeTok эквивалентно 1 изменению вышеупомянутых разделов спецификации на

  • В описании:

    Тип значения должен быть совместимым с элементом массива с типом элемента массива

  • В разделе "Корректность" удалите вышеуказанную часть.

  • В разделе "Проверяемость":

    • отслеживаемый тип массива T[], для некоторых T;

    • отслеживаемый тип значения совместим с элементом массива T


1 Если значение равно aec-с типом элемента массива, то из-за рефлексивности отношения aec-with можно выбрать либо тип значения, либо тип элемента массива в качестве typeTok, который удовлетворяет требованиям "оригинальной спецификации ". И наоборот, если существует typeTok с заданными требованиями, тогда транзитивность отношения aec-with немедленно приводит к требованиям "Модифицированной спецификации".


Так чего мне не хватает? Почему есть аргумент typeTok (и, следовательно, почему stelem.<type> инструкции кроме stelem.ref даже существуют)?

1 ответ

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

Есть семейство стелем.* Элементов. Для примитивов [i,i1,i2,i4,i8,r4,r8 и ref]

примитивные говорят, что он должен ожидать элемент определенного размера в стеке, и он должен быть прочитан, ref говорит, что существует ссылка на объект. Теперь насчет struct это не примитивы. Вы можете сказать, просто используйте один из тех примитивов того же размера. В конце концов, это то, что он делает для массива Enum, Рассматривать DateTimeOffSet, Это 12 байт, и поэтому вы не можете использовать один из существующих примитивов. Было бы плохо иметь бокс для хранения массива этих элементов.

Другой существующий код операции stelem.any и это там для общего кода. Это просто шорткод в случае, когда TypeToken может быть ссылкой на class тип. Вы всегда можете использовать stelem.any но расточительно использовать 4 дополнительных байта, если маркер типа обрабатывается примитивами.

CIL opcodes эта информация о типе всегда принимает их в качестве операндов, даже если это должно быть очевидно на основе других элементов в стеке. Это, вероятно, просто чтобы облегчить жизнь команде CLR. (рассматривать box нужен код операции). Это также может помочь эмитентам избежать ошибок. например

ldc.i4.8
box typetoken(long)
//whoops we clearly need to conv.i8 before we can box this as a long. 

Почему существуют сокращенные версии (например, Stelem.i4 просто stelem typetoken(int32)? Они существуют на 4 байта меньше. Более короткие методы имеют больше шансов быть встроенными. Раньше было так, что если бы метод был больше 32 байтов IL, он не был бы встроен.

Редактировать: я не прав. Кажется, C# обычно получает адрес элементов структуры address и сохраняет их. Технически вы можете использовать stelem TypeToken (поскольку это то, что испускается в общем случае), но кажется, что команда VS не делает.

var dynmethod = new DynamicMethod("test", typeof(void), new[] { typeof(DateTimeOffset[]), typeof(DateTimeOffset) });
        var gen = dynmethod.GetILGenerator();
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldc_I4_0);
        gen.Emit(OpCodes.Ldarg_1);
        gen.Emit(OpCodes.Stelem, typeof(DateTimeOffset));
        gen.Emit(OpCodes.Ret);
        var d=dynmethod.CreateDelegate(typeof(Action<DateTimeOffset[], DateTimeOffset>)) as Action<DateTimeOffset[],DateTimeOffset>;

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

Другие вопросы по тегам