Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Оптимизирует ли JIT-компилятор С# проверку на ноль?

Автор вопроса: Massimiliano KrausОтветов: 1

В Интернете есть много статей, в которых перечислены оптимизации, сделанные C# JIT перед выполнением фрагмента кода. Например, в этом сообщении на MSDN говорится о:

Сворачивание констант, Распространение констант и копий, Устранение общих подвыражений, Перемещение кода инвариантов цикла, Мертвое хранилище и устранение мертвого кода, Распределение регистров, Встраивание методов, Развертывание циклов (небольшие циклы с небольшими телами).

Мой вопрос: компилятор JIT также имеет дело с бесполезными нулевыми проверками? Я не могу найти источник, рассматривающий этот вопрос.

В той же статье я прочитал:

поскольку спецификация языка C# гарантирует, что любой вызов нулевой ссылки на объект вызывает исключение NullReferenceException, каждый сайт вызова должен гарантировать, что экземпляр не является нулевым. Это делается путем разыменования ссылки на экземпляр; если он равен нулю, он сгенерирует ошибку, которая превратится в это исключение.

Итак, предположим, я пишу такой фрагмент кода:

if (person != null)
{
    Console.WriteLine(person.Name);
}

person.Name снова вызывает вторую нулевую проверку, которая явно бесполезна, и компилятор может ее удалить. Или не?

Я читал, что в Java это уже сделано (некоторые источники между многими здесь, здесь и здесь).

Если это делает и C#, знаете ли вы какой-нибудь источник или документацию, в которой говорится об этом?

Если вместо этого C# этого не делает, знаете почему? Есть ли внутренняя трудность в реализации такой функции для среды .NET, с которой Java JIT не сталкивается?

  • Только как побочный эффект обычных оптимизаций, таких как устранение мертвого кода. Что должно быть довольно редко. Как правило, оптимизатор джиттера не имеет специальных знаний о коде, выполняющем проверку нулевого указателя, и рассматривает указатели как неустойчивые. Это очень важно для любой виртуальной машины со сборщиком мусора, который произвольно изменяет указатели при сжатии кучи. Примечательно, что сам компилятор C# может устранить проверку, когда вы используете оператор elvis (?.). Hans Passant 07.12.2016

null-checkoptimizationjit

Ответы

Ответ 1 · рейтинг 3 · Dudi Keleti

Null проверьте оптимизацию, выполненную компилятором (Roslyn, а не Jitter) в некоторых случаях, когда это можно сделать полностью.

Например, когда вы используете ? (оператор Элвиса).

IL_0006: stloc.0              // Pop a value from stack into local variable 0
IL_0007: ldloc.0              // Load local variable 0 onto stack
IL_0008: brtrue.s IL_000c     // Branch to target if value is non-zero (true), short form
IL_000a: br.s IL_0013         // Branch to target, short form
IL_000c: ldloc.0              // Load local variable 0 onto stack
IL_000d: call instance void Foo::Bar() // Call method indicated on the stack with arguments

Другой пример - такой код:

new Bar().Foo();

Компилятор генерирует для этой инструкции call, а не callvirt (что означает отсутствие проверки на нулевое значение для this)

В других случаях вы не можете быть уверены, что this не будет нулевым.

Во всяком случае, нулевая проверка действительно очень быстрая.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы