2. IL也是能使用匯編語言來寫的,MicroSoft專門提供了一個名為ILAsm.exe的IL匯編器和一個名為ILDasm.exe的IL反匯編。
3. 高級語言只公開了CLR的所有功能的一個子集,IL匯編語言允許開發人員訪問CLR的所有功能。如果你需要當前使用的語言不支持的CLR功能,可以使用IL語言或者其他CLR語言。
4. 為了執行一個方法,首先必須將它的IL轉換成為本地CPU指令,這是CLR的
JIT(just-in-time或"即時")編譯器的職責。
5. 展示一個方法首次調用發生的事情。
①
在Main方法執行之前,CLR會檢測出Main的代碼引用的所有類型。這會使CLR分配一個內部數據結構,用於管理對所引用的類型的訪問。
圖1-4中,Main方法引用了一個Console類型(或就叫做Console類),這將讓CLR分配一個內部結構。在這個結構中,Console類型定義的每個方法都有一個相對應的記錄項。每一個記錄項都容納一個地址(但目前還是沒有的,還沒到這一步),根據地址即可找到方法的實現。
②
初始化CLR分配了一個內部結構,CLR將每個記錄項都設置成包含在CLR內部的一個未文檔化的函數(就理解成未公開的,只有微軟自己清楚的函數)。姑且就將這個函數命名為JITCompiler(MSDN找不到這個函數,為了說明流程,自己取的函數名,因為真正的函數名微軟沒公開)
③
Main方法首次調用WriteLine時,JITCompiler也就被調用了。JIT函數負責將一個方法的IL代碼編譯成本地CPU指令。由於IL是"即時"編譯的,所有通常將這個組件成為JIT編譯器或JITter。
④
JITCompiler函數被調用時,它知道要調用的是哪個方法,以及具體是什麼類定義了該方法。於是乎,JITCompiler會在定義該類型的程序集的元數據中查找被調用的方法的IL。
⑤
接著就是驗證IL代碼,並將IL編譯成為本地CPU指令。本地CPU指令被保存到了一個動態分配的內存塊中。
⑥
然後,JITCompiler在CLR為類型創建的內部數據結構,找到與被調用的方法對應的那一條記錄項,修改最初對JITCompiler的引用,讓它現在指向內存塊(其中包括了剛才編譯好的本地CPU指令)的地址。
⑦
最後,JITCompiler函數跳轉到內存塊中的代碼,繼續執行裡面的具體的功能代碼,這些代碼執行完後,會返回到Main中,並像往常一樣繼續執行。
⑧現在,Main要執行第二個WriteLine方法了。這一次,由於第一次已對WriteLine的代碼進行了驗證和編譯,所以會直接執行內存塊中的代碼,完全跳過JITCompiler函數。第二個WriteLine方法執行完畢,會再次返回Main。圖1-5展示了第二次調用WriteLine時發生的事。
6. 對於大多數應用程序,因JIT編譯造成的性能損失並不顯著。大多數引用程序會反復調用相同的方法。看到上面,你對.NET的“第一次”是否有了顛覆性的認識了。
7. CLR的JIT編譯器會對本地代碼進行優化,代碼優化後會獲得更出色的性能。
9. IL是基於棧的。這就意味著它的所有執行都要將操作數壓入(push)一個執行棧,並處棧彈出(pop)結果。
10. IL提供的最大優勢在於應用程序的健壯性和安全性。將IL編譯成CPU指令時,CLR會執行一個名為驗證(verfication)的過程。這個過程會檢查高級IL代碼,確定代碼所做的一切都是安全的。
11. C#編譯器默認生成的是安全(safe)代碼,這種代碼是否安全是可驗證的。然而,C#編譯器也允許開發人員寫不安全(unsafe)代碼。
12. 不安全代碼允許直接操作內存地址,並可操作這些地址處的字節,通常只有在與非托管代碼進行互操作,或在提升效率極高的一個算法的性能時,才會這麼做。
13. MicroSoft提供一個名為PEverify.exe的好、程序,它檢查一個程序集的所有方法,並報告其中含有不安全代碼的方法。