我可以阻止.NET 4执行尾部调用消除吗?

jon*_*ten 13 .net c# compiler-construction optimization .net-4.0

我们正在将应用程序迁移到.NET 4.0(从3.5开始).我们遇到的一个问题只能在非常特殊的条件下重现:

  • 仅在发布版本中
  • 仅在启用优化和/或调试信息设置为仅pdb的情况下启用.

我的意思是,如果我禁用优化并将调试信息设置为完整,问题就会消失.

有问题的代码在.NET 3.5上工作正常,在发布模式下启用了优化等,并且已经做了很长时间.

我真的不想暗示C#编译器中存在错误,所以我的问题是我是否有任何技术可以用来追踪我们可能做错的导致错误优化的方法?

我正在尝试将此问题缩小到一个小的测试用例,所以我可以在这里发布一些代码.

编辑:

我已将问题追溯到以下问题:

我们在Form的构造函数中有这个代码:

public ConnectionForm()
{
    LocalControlUtil.Configure("ConnectionForm", "Username", usernameLabel);
    LocalControlUtil.Configure("ConnectionForm", "Password", passwordLabel);
    LocalControlUtil.Configure("ConnectionForm", "Domain", domainLabel);
    LocalControlUtil.Configure("ConnectionForm", "Cancel", cancelButton);
    LocalControlUtil.Configure("ConnectionForm", "OK", okButton);
}
Run Code Online (Sandbox Code Playgroud)

这些调用是一些自定义本地化代码.从另一个程序集调用此表单的构造函数.该LocalControlUtil.Configure方法调用Assembly.GetCallingAssembly(),它返回上述所有通话的正确值,除了最后一个.

我可以重新排序上面的行,添加新行或删除当前行,每次它是最后一行不起作用.

我假设这是JIT内联调用构造函数的地方的最后一个方法调用(在另一个程序集中).添加[MethodImpl(MethodImplOptions.NoInlining)]到上面的构造函数可以解决问题.

有人知道为什么会这样吗?对我来说似乎很奇怪,最后一行只能内联.这是.NET 4.0中的新行为吗?

编辑2:

我现在把它缩小到尾部调用消除,我假设是由.NET 4中新的尾调用引起的.

在上面的代码LocalControlUtil.Configure中,构造函数中的最后一次调用被消除并放入调用方法,该方法位于另一个程序集中.当方法调用时Assembly.GetCallingAssembly,我们没有得到正确的程序集.

有没有办法阻止编译器(或JIT或其他任何东西)消除尾调用?

Jon*_*nna 5

如果不是太长,我只是将其放在评论中,但是您是否尝试过:

public ConnectionForm()
{
  try
  {
    LocalControlUtil.Configure("ConnectionForm", "Username", usernameLabel);
    LocalControlUtil.Configure("ConnectionForm", "Password", passwordLabel);
    LocalControlUtil.Configure("ConnectionForm", "Domain", domainLabel);
    LocalControlUtil.Configure("ConnectionForm", "Cancel", cancelButton);
    LocalControlUtil.Configure("ConnectionForm", "OK", okButton);
  }
  catch
  {
    throw;
  }
}
Run Code Online (Sandbox Code Playgroud)

抛出任何异常的事实使得这在编写的代码方面几乎是一个空的变化,但 try-catch 边界通常会阻止编译器和抖动方面的优化。


jon*_*ten 0

不,你不能。

.NET 4.0 比 3.5 优化了更多的尾部调用,这是一件好事。我们的代码非常愚蠢。