轉載請標明出處:http://www.cnblogs.com/zblade/
一、IOS對DLL熱更新的禁止
緊接上文,繼續對C#熱更新的研究。上文中,已經說了如何基於appDomain來實現對DLL的加載和卸載,進一步,可以在unity工程中,將Dll打包成資源,通過Assembly.Load的方式加載DLL來實現更新。那么為什么IOS中就不能這樣操作了呢?
推薦閱讀文章:
這兩篇文章,對整個IOS不能熱更新的緣由,有詳細的講解,對於Mono的JIT編譯模式和AOT編譯模式也有講解。總結來說,就是由於IOS的Full AOT編譯模式,不允許在IOS系統中動態生成代碼(代碼是可以在IOS中動態生成的,只是IOS為了安全性的考慮,禁止了內存的操作權限),所以JIT這種編譯模式被Mono自己就禁止了(IOS下)。
既然不能JIT的編譯,那么我們就不能基於Assembly.Load來加載DLL的bytes了。如何解決這個問題?讓我們看看ILRuntime的解決思路。
二、ILRuntime基於IL虛擬機實現對DLL的熱更新
首先看看ILRuntime對於其實現原理的解釋:
ILRuntime借助Mono.Cecil庫來讀取DLL的PE信息,以及當中類型的所有信息,最終得到方法的IL匯編碼,然后通過內置的IL解譯執行虛擬機來執行DLL中的代碼
那么,我們逐步來分析這些操作過程是如何執行的。
1、借助Mono.Ceil庫來讀取DLL的PE信息以及當中類型的所有信息
這一步是如何實現的,跟隨源代碼做一個詳細的跟蹤。
首先,是構建一個全局的appDomain(這兒不是程序域的意思,只是取其名字意思來表示)

基於WWW的方式加載AssetBundle或者DLL/PDB后,接下來是將其封入到MemoryStream中,將dll和pdb的bytes都存入到內存流中后,執行其內部實現的LoadAssembly方法。

關鍵的是第一行,從Mono中加載模塊:

進一步跟蹤:
ReadImageFrom的操作:

其中ImageReader最終來自BinaryReader:

那么接下來的ReadImage操作:
這四個操作,是最核心的操作,分別讀取DLL的PE的各個信息,這樣我們就進入下一個步驟。
2、最終得到方法的IL匯編碼
讓我們分拆來看看這幾個讀取函數的實現
1)ReadOptionalHeaders
主要讀取PE的相關信息,不做過多解釋,可以參看源碼閱讀理解;
2)ReadSections
讀取分塊數據

封裝一個Section,然后去執行讀取,然后賦值給section的Data,注意回退了Index
3)ReadCLIHeader
這步比較簡單
4) ReadMetadata
核心是兩個操作,一個是ReadMetadataStream,就是根據不同的標識符來新建不同的存儲結構;一個是ReadTableHeap:
初始化heap中的Table后,進行一次Compute,獲取size:
然后填充size:

基於這四步操作,我們可以將IL的匯編碼存儲到Image中,然后進一步執行后續的CreateModule操作:

具體到,就是:

其中的ReadModule為:

具體的讀取manifest和Module內部數據,可以參看源碼。
讀取完module后,我們下一篇文章再詳細講解如何執行IL語句,這篇文章先寫到這兒吧 :D