[英]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 將轉儲堆棧跟蹤並中止程序
需要注意的一些事項是:
所以“一個(可能是空的)異常處理信息數組”實際上是每個方法都有的一個部分
在方法主體之后的下一個 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.