Инструкции IL, не предоставляемые C#

Какие инструкции IL не доступны C#?

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

Другие?

РЕДАКТИРОВАТЬ: Причина, по которой я задаю этот вопрос (и, надеюсь, это сделает мой вопрос немного более обоснованным), заключается в том, что я работаю над небольшой библиотекой, которая будет обеспечивать функциональность этих инструкций. sizeof и cpblk уже реализованы — я хотел знать, что еще я мог пропустить, прежде чем двигаться дальше.

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

  • Ломать
  • Джмп
  • Калли
  • Cpobj
  • Ckконечный
  • Префикс[1-7]
  • Префиксссылка
  • Конечный фильтр
  • Невыровненный
  • Хвост
  • Cpblk
  • Initblk

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

  • Лдарг[0-3]
  • Лдлок[0-3]
  • Стлок[0-3]
  • Ldc_[I4_[M1/S/0-8]/I8/R4/R8]
  • Ldind_[I1/U1/I2/U2/I4/U4/I8/R4/R8]
  • Стенд_[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
  • Лделем_[I1/I2/I4/I8/U1/U2/U4/R4/R8]
  • Стелем_[I1/I2/I4/I8/R4/R8]

person YellPika    schedule 18.08.2011    source источник
comment
@ Ганс, я не понимаю, как это не по теме   -  person Earlz    schedule 18.08.2011
comment
Я сделал правку - так лучше? Насколько я знаю, это по крайней мере не субъективно... Было бы лучше, если бы я разместил сообщение на форумах MSDN?   -  person YellPika    schedule 18.08.2011
comment
@ Ханс, я тоже не понимаю, почему это не по теме. Это не вопрос мнения, это простой вопрос о языке программирования с конкретным ответом, и я не знаю, где еще ОП может задать его на stackexchange.   -  person iandotkelly    schedule 18.08.2011
comment
Это на самом деле даже довольно интересный вопрос. Не субъективно, не по теме, оскорбительно, локализовано или что-то еще, что я вижу.   -  person Earlz    schedule 18.08.2011
comment
Ну, редактирование делает его лучше, есть хотя бы намек на практичность. Но ответить - это проблема, для этого требуется кто-то из Microsoft, у которого есть доступ к исходному коду компилятора. Например, он не захочет говорить о недокументированных ключевых словах C#.   -  person Hans Passant    schedule 18.08.2011
comment
@Hans Ну, это примерно то же самое, что сказать, что невозможно сказать, какие инструкции x86 не доступны из gcc, не просматривая источник. Это требует немалых усилий, но, вероятно, кто-то уже пытался реконструировать и задокументировать это раньше.   -  person Earlz    schedule 18.08.2011
comment
Когда нам приходилось демонстрировать практичность? Я видел бесконечные вопросы от людей, «пишущих свой собственный http-сервер» — что, я уверен, просто для развлечения. Что касается ответа, я бы не знал, если бы кто-то здесь не мог ответить на это. Разве C# и MSIL тоже не являются стандартами ECMA?   -  person iandotkelly    schedule 18.08.2011
comment
Я не понимаю, как это вопрос о недокументированных ключевых словах C # - быстрый Google может найти их. Я почти уверен, что на него можно ответить, иначе я бы не узнал о sizeof и cpblk.   -  person YellPika    schedule 18.08.2011
comment
Если он запрашивает список вещей, то вопрос должен быть изменен на вики сообщества, верно?   -  person Brian Gordon    schedule 18.08.2011
comment
Покажите или дайте ссылку на код.   -  person Dour High Arch    schedule 18.08.2011
comment
@Dour Что именно ты просишь? Код инструкции я уже выложил?   -  person YellPika    schedule 18.08.2011
comment
Вы сказали, что я работаю над небольшой библиотекой... Если это коммерческий продукт, я могу понять сохранение конфиденциальности исходного кода, но в противном случае это был бы ценный проект для других людей.   -  person Dour High Arch    schedule 18.08.2011
comment
Я выложу его на Codeplex, когда у меня будет такая возможность :D   -  person YellPika    schedule 18.08.2011
comment
Совершенно правильный вопрос. Я пытаюсь выяснить, можно ли сконструировать Cpblk из программы на C#, и я считаю, что и вопрос, и ответ наиболее актуальны для высокопроизводительной разработки .NET.   -  person Jack Wester    schedule 31.01.2012


Ответы (4)


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

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

Другие?

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

ОБНОВЛЕНИЕ: я только что проверил исходный код, чтобы получить список кодов операций, которые мы определенно делаем. Они есть:

add
add_ovf
add_ovf_un
и
arglist
beq
beq_s
bge
bge_s
bge_un
bge_un_s
bgt
bgt_s< br> 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
box
br
br_s
brfalse
brfalse_s
brtrue
brtrue_s
call
callvirt
castclass
ceq
cgt
cgt_un< br> clt
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
div_un
dup
endfinally
initobj
isinst
ldarg
ldarg_
ldarg_s
ldarga
ldarga_s
ldc_i
ldc_r
ldelem< br> 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< бр> Леа ve
leave_s
localloc
mkrefany
mul
mul_ovf
mul_ovf_un
neg
newarr
newobj
nop
not
or< br> pop
только для чтения
refanytype
refanyval
rem
rem_un
ret
перебросить
shl
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< br> stsfld
sub
sub_ovf
sub_ovf_un
switch
throw
unbox_any
volatile
xor

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

person Eric Lippert    schedule 18.08.2011
comment
Я мог бы добавить, что невозможно выполнить обычный sizeof для универсального типа, и в этом случае использование инструкции напрямую (и я делаю это с помощью DynamicMethods) может обойти это. Calli для меня новинка. Могу я спросить, как это улучшит производительность? - person YellPika; 18.08.2011
comment
@YellPika: Предположим, у вас есть необработанный указатель на виртуальную таблицу объекта C++, и вы хотите вызвать один из методов в этой виртуальной таблице, сигнатура которой вам известна. Сегодня нет возможности сделать это напрямую в C#, даже в небезопасном коде, потому что нет способа выразить понятие this как указателя на область памяти, содержащую код для метода, возвращающего void и принимающего переданное int. стек. Что вам нужно сделать, так это создать объект делегата с этой сигнатурой, а затем указать указатель на конструктор делегата, а затем вызвать делегат. Это очень медленно и много памяти. - person Eric Lippert; 18.08.2011
comment
Вау, это здорово - я хотел бы дважды проголосовать за вас: D. Спасибо за отличный ответ. - person YellPika; 18.08.2011

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

Break

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

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

Cpblk и Cpobj

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

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

Endfilter

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

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

Initblk

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

Я собираюсь еще раз предположить, что это потенциально полезно в небезопасном коде и C++/CLI.

Jmp

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

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

Tailcall

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

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

Unaligned

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

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

Unbox

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

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


Сноска:

Префикс1, Префикс2, Префикс3, Префикс4, Префикс5, Префикс6, Префикс7, префиксссылка

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

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

person ShuggyCoUk    schedule 18.08.2011
comment
Prefix* не являются настоящими инструкциями CLR; они, как следует из их названия, префиксы. Полная инструкция состоит из двух байтов — префикса и следующего за ним байта. Например, prefix1 — это FE, а stloc — это FE 0E. В текущей версии используется только префикс 1, но другие префиксы существуют, чтобы освободить место для (множества) будущих кодов операций. - person configurator; 31.08.2011
comment
@configurator спасибо, мне было интересно, это для инструкций переменной длины. Любая ссылка на то, на что я могу ссылаться в ответе? - person ShuggyCoUk; 01.09.2011
comment
У меня нет ссылок. Если вы посмотрите на два байта Opcodes, вы увидите это. FF для первого байта означает, что байт не выводится (однобайтовые инструкции). Большинство инструкций имеют форму FF XX, двухбайтовые инструкции имеют форму FE XX, а Prefix1 имеет форму FF FE. Prefix1..n не определены как коды операций в спецификации C#, но их байтовые значения определяются как первые байты в многобайтовом коде операции. - person configurator; 01.09.2011
comment
@config круто, если вы хотите добавить эту информацию самостоятельно, я отвечу на вики сообщества. - person ShuggyCoUk; 02.09.2011
comment
Я не уверен, что они действительно принадлежат ответу - ответ касается неиспользуемых инструкций IL, и на самом деле это не инструкции IL (хотя они являются полями класса OpCodes). - person configurator; 02.09.2011

Одним из интересных примеров является tail.call (OpCodes.Tailcall), что сделало бы возможной оптимизацию хвостового вызова для рекурсии.

person Andrey    schedule 18.08.2011
comment
см. stackoverflow.com/questions/7096157/ - person Yahia; 18.08.2011

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

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

person Jordão    schedule 18.08.2011