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

Почему компилятор .NET JIT решит не включать или отключать вызовы для пустых статических методов, которые не имеют побочных эффектов?

Я думаю, что наблюдаю за компилятором .NET JIT, не вставляя или не оптимизируя вызовы на пустые статические методы, которые не имеют побочных эффектов, что несколько удивительно, учитывая некоторые бесплатные онлайн-ресурсы.

Моя среда - это Visual Studio 2013 на x64, Windows 8.1,.NET Framework 4.5.

Учитывая эту простую тестовую программу (https://ideone.com/2BRCpC)

class Program
{
    static void EmptyBody()
    {
    }

    static void Main()
    {
        EmptyBody();
    }
}

Сборка с оптимизацией вышеуказанной программы создает следующий MSIL для Main и EmptyBody:

.method private hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       6 (0x6)
  .maxstack  8
  IL_0000:  call       void Program::EmptyBody()
  IL_0005:  ret
} // end of method Program::Main

.method private hidebysig static void  EmptyBody() cil managed
{
  // Code size       1 (0x1)
  .maxstack  8
  IL_0000:  ret
} // end of method Program::EmptyBody

Неудивительно, что MSIL содержит вызов от Main до EmptyBody, так как компилятор С# не ожидает встроенных или оптимизированных подобных вызовов. Тем не менее, я думал, что компилятор JIT затем включит или оптимизирует этот вызов. Но это, похоже, не происходит.

Если я запустил вышеуказанную программу и перешел в отладчик в Main, сгенерированная сборка:

00572621  mov         ebp,esp  
00572623  cmp         dword ptr ds:[4320B84h],0  
0057262A  je          00572631  
0057262C  call        73E6AF20  
00572631  call        dword ptr ds:[4321578h]  

Указатель инструкции сразу устанавливается в последнюю строку в 00572631, что является вызовом EmptyBody. Выйдя в EmptyBody, создается сгенерированная сборка

00BD2651  mov         ebp,esp  
00BD2653  cmp         dword ptr ds:[4B00B84h],0  
00BD265A  je          00BD2661  
00BD265C  call        73E6AF20  
00BD2661  nop  
00BD2662  pop         ebp  
00BD2663  ret

Указатель инструкции сразу устанавливается в строку nop на 00BD2661, что ничего не делает, и я не могу догадаться, почему он сгенерирован в первую очередь.

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

00BD2653  cmp         dword ptr ds:[4B00B84h],0  
00BD265A  je          00BD2661  
00BD265C  call        73E6AF20  

Во всяком случае, главный вопрос: почему компилятор JIT создает сборку, которая вызывает пустой статический метод EmptyBody?

4b9b3361

Ответ 1

После копания немного дальше, оказывается, я могу ответить на этот вопрос сам. Как объяснено в http://blogs.msdn.com/b/vancem/archive/2006/02/20/535807.aspx, наблюдение за разборкой оптимизированной сборки выпуска под отладчиком по умолчанию будет влиять на компилятор JIT.

Снимите отметку с этих

  • 'Запретить оптимизацию JIT при загрузке модуля
  • 'Включить только мой код

в разделе VS > Инструменты > Отладкa > Общие, отобразит "реальный" результат компиляции JIT, который для вызова EmptyBody в моем Main выше:

004C2620  ret

Значение того, что вызов EmptyBody полностью удален, что и ожидалось, и мир по-прежнему остается счастливым и несколько предсказуемым местом для жизни:)