Подтвердить что ты не робот

IL Инструкции, не выставленные С#

Какие IL-инструкции не отображаются С#?

Я имею в виду инструкции, такие как sizeof и cpblk - нет класса или команды, выполняющих эти инструкции (sizeof в С# вычисляется во время компиляции, а не во время выполнения AFAIK).

Другие?

EDIT: Причина, по которой я прошу об этом (и, надеюсь, это сделает мой вопрос немного более достоверным) заключается в том, что я работаю над небольшой библиотекой, которая обеспечит функциональность этих инструкций. sizeof и cpblk уже реализованы - я хотел знать, что другие, которых я, возможно, пропустил, прежде чем двигаться дальше.

EDIT2: Используя ответ Эрика, я составил список инструкций:

  • Разрыв
  • Jmp
  • Калли
  • Cpobj
  • Ckfinite
  • Префикс [1-7]
  • Prefixref
  • Endfilter
  • Unaligned
  • Tailcall
  • Cpblk
  • Initblk

Было несколько других инструкций, которые не были включены в список, который я разделяю, потому что они в основном являются ярлыками для других инструкций (сжаты для экономии времени и пространства):

  • Ldarg [0-3]
  • Ldloc [0-3]
  • Stloc [0-3]
  • Ldc_ [I4_ [М1/S/0-8]/I8/R4/R8]
  • Ldind_ [I1/U1/I2/U2/I4/U4/I8/R4/R8]
  • Stind_ [I1/I2/I4/I8/R4/R8]
  • Conv_ [I1/I2/I4/I8/R4/R8/U4/U8/U2/U1]
  • Conv_Ovf_ [I1/I2/I4/I8/U1/U2/U4/U8]
  • Conv_Ovf_ [I1/I2/I4/I8/U1/U2/U4/U8] _Un
  • Ldelem_ [I1/I2/I4/I8/U1/U2/U4/R4/R8]
  • Stelem_ [I1/I2/I4/I8/R4/R8]
4b9b3361

Ответ 1

Я имею в виду инструкции, такие как sizeof и cpblk - нет класса или команды, выполняющих эти инструкции (sizeof в С# вычисляется во время компиляции, а не во время выполнения AFAIK).

Это неверно. sizeof(int) будет рассматриваться как константа времени компиляции 4, конечно, но есть много ситуаций (все в коде unsafe), где компилятор полагается на среду выполнения, чтобы определить, какой размер памяти является структурой. Рассмотрим, например, структуру, содержащую два указателя. Он будет иметь размер 8 на 32-битной машине, но 16 на 64-битной машине. В этих обстоятельствах компилятор будет генерировать sizeof opcode.

Другие?

У меня нет списка всех кодов операций, которые мы не создаем - мне никогда не приходилось создавать такой список. Однако, с головы до ног, я могу сказать вам, что нет способа генерировать инструкцию "косвенный вызов" (calli) в С#; нас иногда спрашивают об этой функции, так как это улучшит производительность определенных сценариев взаимодействия.

UPDATE: я просто скопировал исходный код для создания списка кодов операций, которые мы определенно производим. Это:

добавить
add_ovf
add_ovf_un
и

список аргументов BEQ
beq_s
BGE
bge_s
bge_un
bge_un_s
BGT
bgt_s
bgt_un
bgt_un_s
BLE
ble_s
ble_un
ble_un_s
BLT
blt_s
blt_un
blt_un_s
bne_un
bne_un_s
коробка
уш
br_s
brfalse
brfalse_s
brtrue
brtrue_s
звоните
callvirt
castclass
Ceq
ВКТ
cgt_un
сх
clt_un
ограничен
conv_i
conv_ovf_i
conv_ovf_i_un
conv_ovf_u
conv_ovf_u_un
conv_r
conv_r_un
conv_u
ДИВ
div_un
DUP
endfinally
initobj
isinst
ldarg
ldarg_
ldarg_s
ldarga
ldarga_s
ldc_i
ldc_r
ldelem
ldelem_i
ldelem_r
ldelem_ref
ldelem_u
ldelema
ldfld
ldflda
ldftn
ldind_i
ldind_r
ldind_ref
ldind_u
ldlen
ldloc
ldloc_
ldloc_s
ldloca
ldloca_s
ldnull
ldobj
ldsfld
ldsflda
ldstr
ldtoken
ldvirtftn
оставить
leave_s
localloc
mkrefany
мул
mul_ovf
mul_ovf_un
нег
newarr
newobj
NOP
не
или
поп

только для чтения refanytype
refanyval
рем
rem_un
RET
Rethrow
ЗЫ
SHR
shr_un
SizeOf
starg
starg_s
stelem
stelem_i
stelem_r
stelem_ref
stfld
stind_i
stind_r
stind_ref
stloc
stloc_s
stobj
stsfld
суб
sub_ovf
sub_ovf_un
переключатель
бросить
unbox_any
летучий
xor

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

Ответ 2

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

Break

Сообщает об общей инфраструктуре языка (CLI), чтобы сообщить отладчику о том, что точка прерывания была отключена.

Вы сделали бы это, вызвав System.Diagnostics.Debugger.Break(), это, похоже, не использует эту инструкцию напрямую, а вместо этого использует метод BreakInternal(), испеченный в CLR.

Cpblk и Cpobj

Копирует указанное количество байтов из адреса источника в адрес назначения. Копирует тип значения, расположенный по адресу объекта (тип &, * или собственный int) по адресу целевого объекта (тип &, * или собственный int).

Я предполагаю, что они были добавлены для С++/CLI (ранее управляемый С++), но это чисто спекуляция с моей стороны. Они также могут присутствовать в определенных системных вызовах, но не генерируются обычно компилятором и предоставляют некоторые возможности для небезопасных развлечений и игр.

Endfilter

Передает управление из предложения фильтра исключения обратно в обработчик исключений Common Language Infrastructure (CLI).

С# не поддерживает фильтрацию исключений. Возможно, компилятор VB использует это.

Initblk

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

Я снова буду размышлять, что это потенциально полезно для небезопасного кода и С++/CLI

Jmp

Выход из текущего метода и переход к указанному методу.

Я буду предполагать, что такая трамплинка может быть полезна тем, кто хочет избежать хвостовых вызовов. Возможно, DLR использует его?

Tailcall

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

Обсуждаемый в глубине в другом месте, в настоящее время компилятор С# не выделяет этот код операции

Unaligned

Указывает, что адрес, находящийся в настоящее время поверх оценочного стека, может не выровняться по естественному размеру сразу следующих команд ldind, stind, ldfld, stfld, ldobj, stobj, initblk или cpblk.

С# (и CLR) дает немало гарантий относительно согласованного характера большей части полученного в результате кода и данных. Неудивительно, что это не испускается, но я могу понять, почему он будет включен.

Unbox

Преобразует введенное в коробку представление типа значения в его распакованную форму.

Компилятор С# предпочитает использовать инструкцию Unbox_Any исключительно для этой цели. Я предполагаю, что, основываясь на добавлении этого к набору инструкций в версии 2.0, он генерирует либо обобщающие, либо намного более простые. В этот момент, используя его во всем коде для всего, дженериков или других, было либо безопаснее, проще или быстрее (или какая-то комбинация из всех).


Сноска:

Prefix1, Prefix2, Prefix3, Prefix4, Prefix5, Prefix6, Prefix7, Prefixref

Инфраструктура. Это зарезервированная инструкция.

Это не инструкции как таковые, некоторые инструкции IL длиннее других. Эти переменные длины должны начинаться с префиксов, которые никогда не будут действительными сами по себе, чтобы очистить синтаксический анализ. Эти коды префикса зарезервированы для этого, поэтому они не используются в других местах. Несомненно, кто-то, кто использует синтаксический анализатор на основе оператора switch для последовательности IL, оценит их, чтобы они могли захватить их и сохранить состояние.

Ответ 3

Один интересный пример: tail.call (OpCodes.Tailcall), что позволило бы оптимизировать Tail Call для рекурсии.

Ответ 4

Директива .override IL (я не знаю, является ли это правильным термином, но это не является инструкцией) генерируется компилятором С#, но только в специальном случае реализации явного интерфейса.

Было бы интересно иметь возможность использовать его более свободно, как в VB.NET, где элементы-исполнители могут быть псевдонимом или даже иметь другой модификатор доступа, чем член интерфейса.