C#JIT编译器是否优化了空检查?

时间:2016-12-06 20:16:53

标签: c# .net optimization jit null-check

在线上有很多文章列出了在执行一段代码之前C#JIT所做的优化。例如,MSDN上的this post谈论:

  

常量折叠,常量和复制传播,公共子表达式   消除,循环不变量的代码运动,死存储和死代码   消除,寄存器分配,方法内联,循环展开   (小身体的小环)。

我的问题是:JIT编译器是否还处理无用的空值检查?我找不到任何来源来处理这个问题。

在同一篇文章中我读到:

  

因为C#语言规范确保对null的任何调用   对象引用抛出NullReferenceException,每个调用站点都必须   确保实例不为null。这是通过解除引用来完成的   实例参考;如果为null,则会产生故障   变成了这个例外。

所以,假设我写了一段这样的代码:

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

person.Name再次调用第二个无效的空检查,编译器可以删除它。或者不是?

我在Java中读到这已经完成了(很多hereherehere之间的某些来源。)

如果C#也这样做了,你知道一些谈论这个的来源或文档吗?

如果C#没有这样做,你知道为什么吗?在Java JIT没有遇到的.NET环境中实现这样的功能是否存在内在的困难?

1 个答案:

答案 0 :(得分:3)

Null检查编译器完成的优化(Roslyn,而不是Jitter)in several cases,当它完全保存时。

例如,当您使用?(Elvis运算符)时。

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不会为空。

无论如何,空检查真的很快。

相关问题