#specifications #cil #value-type #intermediate-lan&ua&e
#технические характеристики #cil #тип значения #промежуточный язык
Вопрос:
Спецификация ECMA CLI содержит следующее утверждение в описании initobj
инструкции CLI:
«Если typeTok является типом значения, то после выполнения этой инструкции экземпляр готов к вызову метода конструктора».
Однако следующий код на C # (где S
является структурой):
S s = defau<
S s2 = new S();
S s3 = new S(5);
компилируется в IL, который выглядит примерно так:
IL_0001: ldloca.s s
IL_0003: initobj S
IL_0009: ldloca.s s2
IL_000b: initobj S
IL_0011: ldloca.s s3
IL_0013: ldc.i4.5
IL_0014: call instance void S::.ctor(int32)
Мой вопрос в том, когда компилятор когда-либо использовал initobj
с последующим вызовом конструктора типа значения?
Комментарии:
1. Происходит ли то же самое при использовании других местоположений, помимо локальных переменных? Например, статических полей, полей в экземплярах объектов и т.д… Я спрашиваю, потому что все локальные переменные уже обнулены при запуске метода, по крайней мере, в коде, который создает C #.
2. @JoeSewell Да, похоже, что компилятор обрабатывает поля аналогичным образом:
ld[s]flda
,initobj
3. Глава II.13.2 важна, обратите внимание, что в ней указано, что инициализация нулем для типов значений не требуется. Таким образом, компилятор C # должен выдать initobj, чтобы получить гарантию. Конструктор не требуется для инициализации всех полей, примером может служить C / CLI. Этого требует C #, поэтому он может опустить initobj.
4. @HansPassant Это имеет смысл. Однако C # использует
localsinit
флаг, поэтому в контексте моего примера не является ли использованиеinitobj
избыточным?5. Генерация IL компилятором C # вообще не оптимизирована на микроуровне. Задача jitter — превратить это в эффективный машинный код. Она особенно хороша для создания оптимальных типов значений, единственная причина, по которой в .NET была добавлена type system wart, — они хорошо подходят для работы процессора.
Ответ №1:
Если typeTok является типом значения, то после выполнения этой инструкции экземпляр готов к вызову метода конструктора.
Это означает, что конструктор может вызвать конструктор после этой инструкции.
Но, как вы упомянули в комментариях выше, нет необходимости повторно инициализировать локальные файлы перед конструктором из-за localsinit
флага в методе si&.
Мой вопрос в том, когда компилятор когда-либо использовал
initobj
с последующим вызовом конструктора типа значения?
Я могу найти только один случай, когда мне потребуется, чтобы компилятор использовал initobj
, скажите ему не использовать localsinit
флаг. На данный момент SkipLocalsInitAttribute должен помочь вам воспроизвести случай, но реализация этой функции компилятора еще не началась.