Вызывать код как метки или как функции в CIL? - PullRequest
0 голосов
/ 17 февраля 2012

Последние несколько дней я провел в свободное от изучения CIL время и размышлял о переходе на метку (br) по сравнению с вызовом метода (объявление .method).

Я знаю, что если вы объявитеметод, вы сможете получить доступ к нему извне сборки, но как насчет создания меток закрытых методов и просто использования br для перехода к нему?Есть ли какой-то выигрыш в производительности?

Чтобы устранить путаницу, вот упрощенный пример (из-за ограничений пространства и времени):

// calling code
ldc.i4 5
call int32 testmethod(int32)
// other code

// method
.method public int32 testmethod(int32) 
{
    ldc.i4 10
    add
    ldc.i4 20
    mul
    ret
}

Так что вместо того, чтобы делатьэтот метод, я мог бы сделать это с метками и ветвями:

ldc.i4 5
br testlabel
leftoff:
// remaining instructions

testlabel:
.lcd.i4 10
add
ldc.i4 20
mul
br leftoff

Так что метод / метка testlabel берет и int32, а затем добавляет 10 и умножает этот результат на 20. Достаточно просто.Я понимаю, что единственным недостатком (который я не упомянул изначально) является удобочитаемость, но если это генерируется компилятором, читаемость становится менее важной.Итак, используя второй пример, принесет ли использование меток и переходов к коду какие-либо преимущества в производительности?Если нет, то что, если я смогу разместить его в короткой ветке?(Уш)

1 Ответ

2 голосов
/ 23 февраля 2012

То, что вы описываете, это в основном метод встраивания.Хотя возможно, что встраивание метода повысит производительность, есть несколько причин, по которым вы можете не включать метод:

  • Если метод используется несколько раз, то, вероятно, потребуетсянесколько разЭто может привести к общему увеличению размера сгенерированного IL и, возможно, к снижению производительности.
  • Иногда метод не может быть встроенным.Например, рекурсивный метод явно не может быть встроенным (так как его нужно будет снова вставлять в встроенном теле, до бесконечности), как и виртуальный метод (при условии, что вы не знаете тип времени выполнения вызываемого абонента).
  • Даже если вы не включаете метод при написании IL, JIT-компилятор может встроить метод, когда он все равно генерирует машинный код.

UPDATE

Хорошо, учитывая ваш конкретный пример, позвольте мне объяснить связь, которую я вижу с встраиванием.Если метод вызывается несколько раз (например, вызывается testmethod два раза подряд), то ваш подход не будет работать, потому что вам нужно будет вернуться к разным местоположениям в зависимости от того, какой вызов моделировался, но нет простогоспособ сделать это (вы можете добавить локальную переменную для отслеживания дополнительного состояния, а затем использовать условную ветвь, но это достаточно сложно, чтобы, вероятно, отменить любое повышение производительности).Если он вызывается только один раз, то ваше преобразование в основном эквивалентно встраиванию, за исключением дополнительных безусловных переходов в и из встроенного метода.Я думаю, что было бы более логично встроить метод и избавиться от ветвей.То есть, учитывая ваш пример, это выглядело бы так:

ldc.i4 5
// start of inlined call to testmethod
ldc.i4 10
add
ldc.i4 20
mul
// end of inlined call to testmethod
// other code from caller goes here

Тогда применимы мои вышеупомянутые комментарии о встраивании.

...