簡體   English   中英

try-catch 在 IL 中是如何工作的?

[英]How does try-catch works in IL?

考慮這個代碼:

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

使用 LINQPad,我看到代碼編譯為:

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

上面的代碼打印try catch ,如果我拋出Exception ,則打印try並且程序由於未處理的異常而退出(如預期的那樣), IL代碼保持不變,除了這一行:

IL_000D:  newobj      System.Exception..ctor

這背后的邏輯是什么? 除了檢查異常類型以決定是否進入 catch 塊的邏輯。

我這里有點死靈法。 我花了幾個小時閱讀關於這個主題的規范,這里有一些有趣的細節沒有包含在評論中。 引用來自標准 ECMA-335 - 公共語言基礎設施 (CLI)

可執行文件中的每個方法都關聯了一個(可能是空的)異常處理信息數組。 數組中的每個條目都描述了一個受保護的塊、它的過濾器和它的處理程序。 發生異常時,CLI 在數組中搜索第一個受保護的塊

  • 保護一個區域,包括當前指令指針和
  • 誰的過濾器希望處理異常

如果在當前方法中找不到匹配項,則搜索調用方法,依此類推。 如果未找到匹配項,CLI 將轉儲堆棧跟蹤並中止程序

需要注意的一些事項是:

  • 異常處理程序可以訪問捕獲異常的例程的局部變量和局部內存池,但在拋出異常時計算堆棧上的任何中間結果都將丟失
  • 描述異常的異常對象由 CLI 自動創建,並在過濾器或 catch 子句進入時作為第一項推送到計算堆棧上

所以“一個(可能是空的)異常處理信息數組”實際上是每個方法都有的一個部分

在方法主體之后的下一個 4 字節邊界可以是額外的方法數據部分。 目前,方法數據部分僅用於異常表。

該部分包含的clauses存儲有關try塊從哪里開始、從哪里結束、從哪里開始catch以及一個特定字段的信息ClassToken ,它被描述為Meta data token for a type-based exception handler它應該是關於可以由該特定 catch 塊處理的異常類型。

不幸的是,ILDASM 不顯示原始方法頭並從那里插入信息作為反匯編代碼視圖中的.try指令,但 IL 本身沒有用於異常類型處理的特定指令,因為它沒有插入特定的中間代碼用於相同目的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM