简体   繁体   中英

How does try-catch works in IL?

Consider this code:

void Main()
{
    try {
        Console.Write("try ");
        throw new NotImplementedException();
    } 
    catch (NotImplementedException) {
        Console.Write("catch");
    }
}

Using LINQPad, I see the code compiles to:

IL_0000:  nop         
IL_0001:  nop         
IL_0002:  ldstr       "try"
IL_0007:  call        System.Console.WriteLine
IL_000C:  nop         
IL_000D:  newobj      System.NotImplementedException..ctor
IL_0012:  throw       
IL_0013:  pop         
IL_0014:  nop         
IL_0015:  ldstr       "catch"
IL_001A:  call        System.Console.WriteLine
IL_001F:  nop         
IL_0020:  nop         
IL_0021:  leave.s

The code above prints try catch , if I throw Exception instead, try is printed and the program exits due to the unhandled exception (as expected), the IL code remains the same, except this line:

IL_000D:  newobj      System.Exception..ctor

What is the logic behind that? I would except for logic that checks the type of the exception to make a decision if to go into the catch block or not.

I little bit of necromancy here. I've spent several hours reading specs on the subject and here are some interesting details that aren't covered in comments. The quotes are taken from Standard ECMA-335 - Common Language Infrastructure (CLI) :

Each method in an executable has associated with it a (possibly empty) array of exception handling information. Each entry in the array describes a protected block, its filter, and its handler. When an exception occurs, the CLI searches the array for the first protected block that

  • Protects a region including the current instruction pointer and
  • Whose filter wishes to handle the exception

If a match is not found in the current method, the calling method is searched, and so on. If no match is found the CLI will dump a stack trace and abort the program

Some things to notice are:

  • Exception handlers can access the local variables and the local memory pool of the routine that catches the exception, but any intermediate results on the evaluation stack at the time the exception was thrown are lost
  • An exception object describing the exception is automatically created by the CLI and pushed onto the evaluation stack as the first item upon entry of a filter or catch clause

So that "a (possibly empty) array of exception handling information" is actually a section that every method has

At the next 4-byte boundary following the method body can be extra method data sections. Currently, the method data sections are only used for exception tables.

And that section consists of clauses which store information about where try block starts, where it ends, where catch starts and there is one particular field — ClassToken which is described as Meta data token for a type-based exception handler which should be the information about exception type that could be handled by that particular catch block.

Unfortunately, ILDASM doesn't show raw method headers and inserts information from there as .try instructions in disassembled code view, but the IL itself has no specific instructions for exception type handling as it does not inserts specific intermediate code for the same purpose.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM