【问题标题】:Would the .NET JIT compiler optimize out a method call?.NET JIT 编译器会优化方法调用吗?
【发布时间】:2013-04-11 17:41:35
【问题描述】:

我从一个由 ArgumentNullException 生成的 ASP.NET 应用程序返回的堆栈跟踪给人的印象是下面代码的最后一行发生了错误。据我所知,这是不可能的,但如果 JIT 优化了对 Bar 的调用,这将导致不同的堆栈跟踪,它会解释一切。我确定它不是 c# 编译器,因为 CIL 看起来像我所期望的那样。 JIT 编译器是否可能删除了对 Bar 的调用?

c#4、.NET 4.0.30319.1、ASP.NET 4.0.30319.1

编辑: 我应该提到这是一个发布配置,Optimize code = on,Debug Info = pdb-only。

Stack Trace:

[ArgumentNullException: Value cannot be null. Parameter name: value]
CreateHiddenField(HtmlTextWriter tr, String name, String value) in Foo.cs:129
Foo(IHttpContext context, HtmlTextWriter writer) in Foo.cs:106

private static void Foo(IHttpContext context, HtmlTextWriter writer)
{ // line 103
  Bar(writer, AuthorizationServerResponseDetailsHttpRequestParser.RequestSAMLFieldName, context);
  Bar(writer, AuthorizationServerResponseDetailsHttpRequestParser.RequestTargetFieldName, context);
  // line 106 - blank line in source code.
  CreateHiddenField(tr, name, string.Empty); // looks like its here
}

private static void Bar(HtmlTextWriter tr,string name, IHttpContext context)
{ // line 116
   #region Sanitation
   if (tr == null) { throw new System.ArgumentNullException("tr"); }
   if (name == null) { throw new System.ArgumentNullException("name"); }
   if (context == null) { throw new System.ArgumentNullException("context"); }
   #endregion

   CreateHiddenField(tr, name, context.RequestQueryString(name));
}

private static void CreateHiddenField(HtmlTextWriter tr, string name, string value)
{ // line 127
   #region Sanitation
   if (tr == null) { throw new System.ArgumentNullException("tr"); }
   if (name == null) { throw new System.ArgumentNullException("name"); }
   if (value == null) { throw new System.ArgumentNullException("value"); }
   #endregion

   // payload...
}

【问题讨论】:

  • 你能提供堆栈跟踪吗?如果 JIT 符合要求,它可以内联一个方法——这可能会导致它从堆栈跟踪中“消失”......我认为。
  • 它在第一个代码块中。我删除了命名空间/文件名以使其可读。
  • 你知道吗,我不认为这是一个堆栈跟踪,因为它太小了。我的猜测是它是内联的,但我不知道编译器是否发出代码来保持“正确”的堆栈跟踪。堆栈跟踪是否带有任何行号或字节偏移量?
  • AuthorizationServerResponseDetailsHttpRequestParser ...不错的一个:)
  • @Joshua 在那里更新了堆栈跟踪中的行号以及代码。

标签: asp.net .net c#-4.0 clr


【解决方案1】:

根据http://www.hanselman.com/blog/ReleaseISNOTDebug64bitOptimizationsAndCMethodInliningInReleaseBuildCallStacks.aspx,如果JITter 内联一个方法调用,它确实会在堆栈跟踪中被折叠。如果您不希望它内联(这可能不是一个好主意),您可以使用

[MethodImpl(MethodImplOptions.NoInlining)] 

关于方法。对于 exe,您还可以使用 INI 文件告诉 JITter 生成跟踪信息(在链接页面的底部),但我不确定这对于 ASP.NET 应用程序如何工作。

【讨论】:

  • 这正是我要找的,但我找不到。
  • 完美。 URL 证实了我的怀疑,但我在搜索时找不到类似那篇文章的内容。
【解决方案2】:

我从未见过 JIT 删除方法调用,只是内联它。通常,它会删除未使用的局部变量,但我相当肯定 JIT 不能静态分析调用方法的所有副作用,所以我认为它永远不会删除方法调用。

我的猜测是空值被传递给在CreateHiddenField 内部调用的方法,该方法恰好也有一个参数value。因为默认情况下在发布模式下启用内联,所以您不能真正信任堆栈跟踪(或发生异常的假定行号)。您的问题很可能在CreateHiddenField 内部或更深的不可见堆栈中。 :)

您可以禁用优化以更好地了解堆栈跟踪。 MSDN has some instructions here

【讨论】:

    猜你喜欢
    • 2010-09-21
    • 1970-01-01
    • 2019-03-06
    • 1970-01-01
    • 1970-01-01
    • 2017-05-29
    • 2015-09-03
    • 1970-01-01
    • 2012-08-23
    相关资源
    最近更新 更多