.NET JIT是否优化嵌套的try/catch语句?

Ste*_*idi 0 .net optimization jit exception-handling try-catch

我一直在考虑嵌套的try/catch语句,并开始考虑JIT可以在哪些条件下执行编译IL的优化或简化.

为了说明,请考虑以下功能等效的异常处理程序表示.

// Nested try/catch
try
{
  try
  {
    try
    {
      foo();
    }
    catch(ExceptionTypeA) { }
  }
  catch(ExceptionTypeB) { }
}
catch(ExceptionTypeC) { }

// Linear try/catch
try
{
  foo();
}
catch(ExceptionTypeA) { }
catch(ExceptionTypeB) { }
catch(ExceptionTypeC) { }
Run Code Online (Sandbox Code Playgroud)

假设在嵌套的try语句的堆栈帧中没有额外的变量引用或函数调用,JIT可以断定堆栈帧可能会折叠为线性示例吗?

现在下面的例子怎么样?

void Try<TException>(Action action)
{
  try
  {
    action();
  }
  catch (TException) { }
}

void Main()
{
  Try<ExceptionC>(Try<ExceptionB>(Try<ExceptionA>(foo)));
}
Run Code Online (Sandbox Code Playgroud)

我认为JIT没有任何方法可以内联委托调用,所以这个例子不能简化为前一个.然而,在foo()投掷的情况下ExceptionC,与线性示例相比,此解决方案的性能是否更差?我怀疑从委托调用中拆除堆栈帧需要额外的成本,即使帧中包含的额外数据很少.

Jon*_*eet 8

值得注意的是,在第一种情况下,当你在catch区块内什么也不做时,它们只是在功能上是等价的.否则,考虑一下:

try
{
    foo();
}
catch (IOException)
{
    throw new ArgumentException(); // Bubbles up to caller
}
catch (ArgumentException)
{
    Console.WriteLine("Caught");
}
Run Code Online (Sandbox Code Playgroud)

VS

try
{
    try
    {
        foo();
    }
    catch (IOException)
    {
        throw new ArgumentException(); // Caught by other handler
    }
}
catch (ArgumentException)
{
    Console.WriteLine("Caught");
}
Run Code Online (Sandbox Code Playgroud)

现在在这种情况下,差异是显而易见的,但如果catch块调用一些任意方法,JIT如何知道可能抛出什么?最好要小心.

这让我们可以选择JIT对空捕获块执行优化 - 这种做法首先是强烈劝阻的.我不希望JIT花时间尝试检测错误的代码并使其运行得更快 - 如果确实首先存在任何性能差异.