58355

Does the .NET JIT optimize nested try/catch statements?

Question:

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.

Answer1:

It's worth noting that in the first case they're <em>only</em> functionally equivalent when you're doing nothing within the catch block. Otherwise, consider this:

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

vs

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

Now in this case the difference is obvious, but if the catch block calls some arbitrary method, how is the JIT meant to know what might be thrown? Best to be cautious.

That leaves us with the option of the JIT performing optimisations for empty catch blocks - a practice which is strongly discouraged in the first place. I don't want the JIT to spend time trying to detect bad code and make it run very slightly faster - if indeed there's any performance difference in the first place.

Answer2:

My understanding of try/catch/finally regions with respect to performance is that such regions are transparent to the regular execution of code. That is, if your code does not throw any exceptions to catch, then the try/catch/finally regions have <em>ZERO</em> impact on code execution performance.

However, when an exception is raised, the runtime starts walking up the stack from the site at which it is raised, checking tables of metadata to see whether the site in question is contained within any of the critical try blocks. If one is found (and it has an eligible catch block or a finally block) then the relevant handler is identified and execution branches to this point.

The process of raising and handling exceptions is expensive from a performance perspective. Programmers should not use exceptions as a way of signalling or controlling program flow in anything other than exceptional circumstances (pun intended.)

Recommend

  • JAVA Protected variable not allowed to be access though an object in child class of different packag
  • Why aggregate functions can not be used with DISTINCT ON(…)?
  • How can i make scrapy to process the url sequentially
  • Excel macro to combine workbooks, Runtime Error 1004
  • how to insert new data in an embedded document in MongoDB
  • Data Cleanup, post conversion from ALLCAPS to Title Case
  • init method of a Serlvet without ServletException
  • TCP HL7 message has .(period) as segment terminator
  • Serialize JSON array from a web request
  • ES6 imports in Node with --experimental-modules
  • Given an instance of a Ruby object, how do I get its metaclass?
  • Plot: color all larger than different color
  • Django Admin wont allow me to allocate permissions to Users or Groups
  • linking a static(.a) library with a shared (.so) library, getting error “relocation R_X86_64_32S aga
  • python regex [:alpha:]
  • Model to match this JSON for deserialization, field names with dashes
  • RegularExpressionValidator With DropDownList(asp.net)
  • Filter Values of Current Week with XQuery
  • Find lines in shape
  • C++ mySQL connector LINKER errors (Windows)
  • What is the Performance, Safety, and Alignment of a Data member hidden in an embedded char array in
  • Bundled scripts not working MVC
  • LDA: Why sampling for inference of a new document?
  • How to reduce the time delay to reach run method of Runnable class using ExecutorService Java
  • QVideoWidget: Video is cut off
  • Java Netbeans Error Cannot find symbol, symbol: class out, location: class System, expected, illega
  • css Star-rating html
  • Entity Framework Core: Include many-to-many related objects in WebAPI
  • How to align an image side by side with a heading element?
  • Azure webjobs output logs indexing taking very long
  • how to save the state in userdefaults of accessory checkmark-iphone
  • error importing numpy
  • MonoTouch: How to download pdf incrementally as indicated in the Apple slides “Building Newsstand Ap
  • Ionic 2 storage is not cleaning up on uninstall - Only for signed APK
  • preg_replace Double Spaces to tab (\\t) at the beginning of a line
  • Updated Ionic CLI but shows previous version (Windows)
  • Getting 'uninitialized constant' error when using delegate in belongs_to in model
  • Unanticipated behavior
  • Suggestions to manage Login/Logout transitions
  • Conditional In-Line CSS for IE and Others?