I've been thinking about nested try/catch statements and started to think about under which conditions, if any, the JIT can perform an optimization or simplification of the compiled IL.
To illustrate, consider the following functionally-equivalent representations of an exception handler.
// Nested try/catch
try
{
try
{
try
{
foo();
}
catch(ExceptionTypeA) { }
}
catch(ExceptionTypeB) { }
}
catch(ExceptionTypeC) { }
// Linear try/catch
try
{
foo();
}
catch(ExceptionTypeA) { }
catch(ExceptionTypeB) { }
catch(ExceptionTypeC) { }
Assuming there are no additional variable references or function calls within the stack frames of the nested try statement, can the JIT conclude that the stack frames may be collapsed to the linear example?
Now how about the following example?
void Try<TException>(Action action)
{
try
{
action();
}
catch (TException) { }
}
void Main()
{
Try<ExceptionC>(Try<ExceptionB>(Try<ExceptionA>(foo)));
}
I don't think there is any way for the JIT to inline the delegate invocations, so this example can't be reduced to the previous one. However in the event of foo()
throwing ExceptionC
, does this solution perform poorer when compared to the linear example? I suspect there is an extra cost to tear down the stack frames from the delegate invocations, even though the extra data contained in the frames is minimal.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…