ILRuntime 學習


ILRuntime:  https://github.com/Ourpalm/ILRuntime

Demo:  https://github.com/Ourpalm/ILRuntimeU3D

中文在線文檔:  https://ourpalm.github.io/ILRuntime/public/v1/guide/index.html

Mono:  https://www.mono-project.com/

Mono.Cecil  https://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/ 

 

 

XCode請使用Relase編譯, 使用Debug編譯會出現函數調用層數超過一定數量iOS手機閃退

 

 

 

 

 

ESP: 棧指針寄存器(extended stack pointer), 指向棧頂的指針

EBP: 基址指針寄存器(extended base pointer), 指向棧底的指針

 

var module = ModuleDefinition.ReadModule(stream); //從MONO中加載模塊

foreach(TypeDefinition type in module.Types) {
    UnityEngine.Debug.Log(type.FullName);
}
從Mono中加載模塊
        public RuntimeStack(ILIntepreter intepreter)
        {
            this.intepreter = intepreter;

            // 通過使用指定的字節數,從進程的非托管內存中分配內存
            // sizeof(StackObject) == 12 字節
            // 分配 12 * 1024 * 16 字節
            nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);

            // 將 IntPtr 轉換為  StackObject* 指針
            // pointer 地址為 0x5737F010
            pointer = (StackObject*)nativePointer.ToPointer();
            // endOfMemory 地址為 0x573AF010
            endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
            // valueTypePtr 地址為 0x573AF004
            valueTypePtr = endOfMemory - 1;
        }
RuntimeStack 構造
struct StackObject
{
    public ObjectTypes ObjectType;
    public int Value; //高32位
    public int ValueLow; //低32位
}
enum ObjectTypes
{
    Null,//null
    Integer,
    Long,
    Float,
    Double,
    StackObjectReference,//引用指針,Value = 指針地址, 
    StaticFieldReference,//靜態變量引用,Value = 類型Hash, ValueLow= Field的Index
    Object,//托管對象,Value = 對象Index
    FieldReference,//類成員變量引用,Value = 對象Index, ValueLow = Field的Index
    ArrayReference,//數組引用,Value = 對象Index, ValueLow = 元素的Index
}

 

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ILRuntime.Runtime.Intepreter.OpCodes
{
    enum OpCodeEnum
    {
        /// <summary>
        /// 如果修補操作碼,則填充空間。盡管可能消耗處理周期,但未執行任何有意義的操作。
        /// </summary>
        Nop,
        /// <summary>
        /// 向公共語言結構 (CLI) 發出信號以通知調試器已撞上了一個斷點。
        /// </summary>
        Break,
        /// <summary>
        /// 將索引為 0 的參數加載到計算堆棧上。
        /// </summary>
        Ldarg_0,
        /// <summary>
        /// 將索引為 1 的參數加載到計算堆棧上。
        /// </summary>
        Ldarg_1,
        /// <summary>
        /// 將索引為 2 的參數加載到計算堆棧上。
        /// </summary>
        Ldarg_2,
        /// <summary>
        /// 將索引為 3 的參數加載到計算堆棧上。
        /// </summary>
        Ldarg_3,
        /// <summary>
        /// 將索引 0 處的局部變量加載到計算堆棧上。
        /// </summary>
        Ldloc_0,
        /// <summary>
        /// 將索引 1 處的局部變量加載到計算堆棧上。
        /// </summary>
        Ldloc_1,
        /// <summary>
        /// 將索引 2 處的局部變量加載到計算堆棧上。
        /// </summary>
        Ldloc_2,
        /// <summary>
        /// 將索引 3 處的局部變量加載到計算堆棧上。
        /// </summary>
        Ldloc_3,
        /// <summary>
        /// 從計算堆棧的頂部彈出當前值並將其存儲到索引 0 處的局部變量列表中。
        /// </summary>
        Stloc_0,
        /// <summary>
        /// 從計算堆棧的頂部彈出當前值並將其存儲到索引 1 處的局部變量列表中。
        /// </summary>
        Stloc_1,
        /// <summary>
        /// 從計算堆棧的頂部彈出當前值並將其存儲到索引 2 處的局部變量列表中。
        /// </summary>
        Stloc_2,
        /// <summary>
        /// 從計算堆棧的頂部彈出當前值並將其存儲到索引 3 處的局部變量列表中。
        /// </summary>
        Stloc_3,
        /// <summary>
        /// 將參數(由指定的短格式索引引用)加載到計算堆棧上。
        /// </summary>
        Ldarg_S,
        /// <summary>
        /// 以短格式將參數地址加載到計算堆棧上。
        /// </summary>
        Ldarga_S,
        /// <summary>
        /// 將位於計算堆棧頂部的值存儲在參數槽中的指定索引處(短格式)。
        /// </summary>
        Starg_S,
        /// <summary>
        /// 將特定索引處的局部變量加載到計算堆棧上(短格式)。
        /// </summary>
        Ldloc_S,
        /// <summary>
        /// 將位於特定索引處的局部變量的地址加載到計算堆棧上(短格式)。
        /// </summary>
        Ldloca_S,
        /// <summary>
        /// 從計算堆棧的頂部彈出當前值並將其存儲在局部變量列表中的 index 處(短格式)。
        /// </summary>
        Stloc_S,
        /// <summary>
        /// 將空引用(O 類型)推送到計算堆棧上。
        /// </summary>
        Ldnull,
        /// <summary>
        /// 將整數值 -1 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_M1,
        /// <summary>
        /// 將整數值 0 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_0,
        /// <summary>
        /// 將整數值 1 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_1,
        /// <summary>
        /// 將整數值 2 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_2,
        /// <summary>
        /// 將整數值 3 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_3,
        /// <summary>
        /// 將整數值 4 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_4,
        /// <summary>
        /// 將整數值 5 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_5,
        /// <summary>
        /// 將整數值 6 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_6,
        /// <summary>
        /// 將整數值 7 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_7,
        /// <summary>
        /// 將整數值 8 作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4_8,
        /// <summary>
        /// 將提供的 int8 值作為 int32 推送到計算堆棧上(短格式)。
        /// </summary>
        Ldc_I4_S,
        /// <summary>
        /// 將所提供的 int32 類型的值作為 int32 推送到計算堆棧上。
        /// </summary>
        Ldc_I4,
        /// <summary>
        /// 將所提供的 int64 類型的值作為 int64 推送到計算堆棧上。
        /// </summary>
        Ldc_I8,
        /// <summary>
        /// 將所提供的 float32 類型的值作為 F (float) 類型推送到計算堆棧上。
        /// </summary>
        Ldc_R4,
        /// <summary>
        /// 將所提供的 float64 類型的值作為 F (float) 類型推送到計算堆棧上。
        /// </summary>
        Ldc_R8,
        /// <summary>
        /// 復制計算堆棧上當前最頂端的值,然后將副本推送到計算堆棧上。
        /// </summary>
        Dup,
        /// <summary>
        /// 移除當前位於計算堆棧頂部的值。
        /// </summary>
        Pop,
        /// <summary>
        /// 退出當前方法並跳至指定方法。
        /// </summary>
        Jmp,
        /// <summary>
        /// 調用由傳遞的方法說明符指示的方法。
        /// </summary>
        Call,
        /// <summary>
        /// 通過調用約定描述的參數調用在計算堆棧上指示的方法(作為指向入口點的指針)。
        /// </summary>
        Calli,
        /// <summary>
        /// 從當前方法返回,並將返回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上。
        /// </summary>
        Ret,
        /// <summary>
        /// 無條件地將控制轉移到目標指令(短格式)。
        /// </summary>
        Br_S,
        /// <summary>
        /// 如果 value 為 false、空引用或零,則將控制轉移到目標指令。
        /// </summary>
        Brfalse_S,
        /// <summary>
        /// 如果 value 為 true、非空或非零,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Brtrue_S,
        /// <summary>
        /// 如果兩個值相等,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Beq_S,
        /// <summary>
        /// 如果第一個值大於或等於第二個值,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Bge_S,
        /// <summary>
        /// 如果第一個值大於第二個值,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Bgt_S,
        /// <summary>
        /// 如果第一個值小於或等於第二個值,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Ble_S,
        /// <summary>
        /// 如果第一個值小於第二個值,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Blt_S,
        /// <summary>
        /// 當兩個無符號整數值或不可排序的浮點型值不相等時,將控制轉移到目標指令(短格式)。
        /// </summary>
        Bne_Un_S,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點型值時,如果第一個值大於第二個值,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Bge_Un_S,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點型值時,如果第一個值大於第二個值,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Bgt_Un_S,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點值時,如果第一個值小於或等於第二個值,則將控制權轉移到目標指令(短格式)。
        /// </summary>
        Ble_Un_S,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點型值時,如果第一個值小於第二個值,則將控制轉移到目標指令(短格式)。
        /// </summary>
        Blt_Un_S,
        /// <summary>
        /// 無條件地將控制轉移到目標指令。
        /// </summary>
        Br,
        /// <summary>
        /// 如果 value 為 false、空引用(Visual Basic 中的 Nothing)或零,則將控制轉移到目標指令。
        /// </summary>
        Brfalse,
        /// <summary>
        /// 如果 value 為 true、非空或非零,則將控制轉移到目標指令。
        /// </summary>
        Brtrue,
        /// <summary>
        /// 如果兩個值相等,則將控制轉移到目標指令。
        /// </summary>
        Beq,
        /// <summary>
        /// 如果第一個值大於或等於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Bge,
        /// <summary>
        /// 如果第一個值大於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Bgt,
        /// <summary>
        /// 如果第一個值小於或等於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Ble,
        /// <summary>
        /// 如果第一個值小於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Blt,
        /// <summary>
        /// 當兩個無符號整數值或不可排序的浮點型值不相等時,將控制轉移到目標指令。
        /// </summary>
        Bne_Un,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點型值時,如果第一個值大於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Bge_Un,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點型值時,如果第一個值大於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Bgt_Un,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點型值時,如果第一個值小於或等於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Ble_Un,
        /// <summary>
        /// 當比較無符號整數值或不可排序的浮點型值時,如果第一個值小於第二個值,則將控制轉移到目標指令。
        /// </summary>
        Blt_Un,
        /// <summary>
        /// 實現跳轉表。
        /// </summary>
        Switch,
        /// <summary>
        /// 將 int8 類型的值作為 int32 間接加載到計算堆棧上。
        /// </summary>
        Ldind_I1,
        /// <summary>
        /// 將 unsigned int8 類型的值作為 int32 間接加載到計算堆棧上。
        /// </summary>
        Ldind_U1,
        /// <summary>
        /// 將 int16 類型的值作為 int32 間接加載到計算堆棧上。
        /// </summary>
        Ldind_I2,
        /// <summary>
        /// 將 unsigned int16 類型的值作為 int32 間接加載到計算堆棧上。
        /// </summary>
        Ldind_U2,
        /// <summary>
        /// 將 int32 類型的值作為 int32 間接加載到計算堆棧上。
        /// </summary>
        Ldind_I4,
        /// <summary>
        /// 將 unsigned int32 類型的值作為 int32 間接加載到計算堆棧上。
        /// </summary>
        Ldind_U4,
        /// <summary>
        /// 將 int64 類型的值作為 int64 間接加載到計算堆棧上。
        /// </summary>
        Ldind_I8,
        /// <summary>
        /// 將 native int 類型的值作為 native int 間接加載到計算堆棧上。
        /// </summary>
        Ldind_I,
        /// <summary>
        /// 將 float32 類型的值作為 F (float) 類型間接加載到計算堆棧上。
        /// </summary>
        Ldind_R4,
        /// <summary>
        /// 將 float64 類型的值作為 F (float) 類型間接加載到計算堆棧上。
        /// </summary>
        Ldind_R8,
        /// <summary>
        /// 將對象引用作為 O(對象引用)類型間接加載到計算堆棧上。
        /// </summary>
        Ldind_Ref,
        /// <summary>
        /// 存儲所提供地址處的對象引用值。
        /// </summary>
        Stind_Ref,
        /// <summary>
        /// 在所提供的地址存儲 int8 類型的值。
        /// </summary>
        Stind_I1,
        /// <summary>
        /// 在所提供的地址存儲 int16 類型的值。
        /// </summary>
        Stind_I2,
        /// <summary>
        /// 在所提供的地址存儲 int32 類型的值。
        /// </summary>
        Stind_I4,
        /// <summary>
        /// 在所提供的地址存儲 int64 類型的值。
        /// </summary>
        Stind_I8,
        /// <summary>
        /// 在所提供的地址存儲 float32 類型的值。
        /// </summary>
        Stind_R4,
        /// <summary>
        /// 在所提供的地址存儲 float64 類型的值。
        /// </summary>
        Stind_R8,
        /// <summary>
        /// 將兩個值相加並將結果推送到計算堆棧上。
        /// </summary>
        Add,
        /// <summary>
        /// 從其他值中減去一個值並將結果推送到計算堆棧上。
        /// </summary>
        Sub,
        /// <summary>
        /// 將兩個值相乘並將結果推送到計算堆棧上。
        /// </summary>
        Mul,
        /// <summary>
        /// 將兩個值相除並將結果作為浮點(F 類型)或商(int32 類型)推送到計算堆棧上。
        /// </summary>
        Div,
        /// <summary>
        /// 兩個無符號整數值相除並將結果 ( int32 ) 推送到計算堆棧上。
        /// </summary>
        Div_Un,
        /// <summary>
        /// 將兩個值相除並將余數推送到計算堆棧上。
        /// </summary>
        Rem,
        /// <summary>
        /// 將兩個無符號值相除並將余數推送到計算堆棧上。
        /// </summary>
        Rem_Un,
        /// <summary>
        /// 計算兩個值的按位“與”並將結果推送到計算堆棧上。
        /// </summary>
        And,
        /// <summary>
        /// 計算位於堆棧頂部的兩個整數值的按位求補並將結果推送到計算堆棧上。
        /// </summary>
        Or,
        /// <summary>
        /// 計算位於計算堆棧頂部的兩個值的按位異或,並且將結果推送到計算堆棧上。
        /// </summary>
        Xor,
        /// <summary>
        /// 將整數值左移(用零填充)指定的位數,並將結果推送到計算堆棧上。
        /// </summary>
        Shl,
        /// <summary>
        /// 將整數值右移(保留符號)指定的位數,並將結果推送到計算堆棧上。
        /// </summary>
        Shr,
        /// <summary>
        /// 將無符號整數值右移(用零填充)指定的位數,並將結果推送到計算堆棧上。
        /// </summary>
        Shr_Un,
        /// <summary>
        /// 對一個值執行求反並將結果推送到計算堆棧上。
        /// </summary>
        Neg,
        /// <summary>
        /// 計算堆棧頂部整數值的按位求補並將結果作為相同的類型推送到計算堆棧上。
        /// </summary>
        Not,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 int8,然后將其擴展(填充)為 int32。
        /// </summary>
        Conv_I1,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 int16,然后將其擴展(填充)為 int32。
        /// </summary>
        Conv_I2,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 int32。
        /// </summary>
        Conv_I4,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 int64。
        /// </summary>
        Conv_I8,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 float32。
        /// </summary>
        Conv_R4,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 float64。
        /// </summary>
        Conv_R8,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 unsigned int32,然后將其擴展為 int32。
        /// </summary>
        Conv_U4,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 unsigned int64,然后將其擴展為 int64。
        /// </summary>
        Conv_U8,
        /// <summary>
        /// 對對象調用后期綁定方法,並且將返回值推送到計算堆棧上。
        /// </summary>
        Callvirt,
        /// <summary>
        /// 將位於對象(&、* 或 native int 類型)地址的值類型復制到目標對象(&、* 或 native int 類型)的地址。
        /// </summary>
        Cpobj,
        /// <summary>
        /// 將地址指向的值類型對象復制到計算堆棧的頂部。
        /// </summary>
        Ldobj,
        /// <summary>
        /// 推送對元數據中存儲的字符串的新對象引用。
        /// </summary>
        Ldstr,
        /// <summary>
        /// 創建一個值類型的新對象或新實例,並將對象引用(O 類型)推送到計算堆棧上。
        /// </summary>
        Newobj,
        /// <summary>
        /// 嘗試將引用傳遞的對象轉換為指定的類。
        /// </summary>
        Castclass,
        /// <summary>
        /// 測試對象引用(O 類型)是否為特定類的實例。
        /// </summary>
        Isinst,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號整數值轉換為 float32。
        /// </summary>
        Conv_R_Un,
        /// <summary>
        /// 將值類型的已裝箱的表示形式轉換為其未裝箱的形式。
        /// </summary>
        Unbox,
        /// <summary>
        /// 引發當前位於計算堆棧上的異常對象。
        /// </summary>
        Throw,
        /// <summary>
        /// 查找對象中其引用當前位於計算堆棧的字段的值。
        /// </summary>
        Ldfld,
        /// <summary>
        /// 查找對象中其引用當前位於計算堆棧的字段的地址。
        /// </summary>
        Ldflda,
        /// <summary>
        /// 用新值替換在對象引用或指針的字段中存儲的值。
        /// </summary>
        Stfld,
        /// <summary>
        /// 將靜態字段的值推送到計算堆棧上。
        /// </summary>
        Ldsfld,
        /// <summary>
        /// 將靜態字段的地址推送到計算堆棧上。
        /// </summary>
        Ldsflda,
        /// <summary>
        /// 用來自計算堆棧的值替換靜態字段的值。
        /// </summary>
        Stsfld,
        /// <summary>
        /// 將指定類型的值從計算堆棧復制到所提供的內存地址中。
        /// </summary>
        Stobj,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為有符號 int8 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I1_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為有符號 int16 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I2_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為有符號 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I4_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為有符號 int64,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I8_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為 unsigned int8 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U1_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為 unsigned int16 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U2_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為 unsigned int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U4_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為 unsigned int64,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U8_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為有符號 native int,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I_Un,
        /// <summary>
        /// 將位於計算堆棧頂部的無符號值轉換為 unsigned native int,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U_Un,
        /// <summary>
        /// 將值類轉換為對象引用(O 類型)。
        /// </summary>
        Box,
        /// <summary>
        /// 將對新的從零開始的一維數組(其元素屬於特定類型)的對象引用推送到計算堆棧上。
        /// </summary>
        Newarr,
        /// <summary>
        /// 將從零開始的、一維數組的元素的數目推送到計算堆棧上。
        /// </summary>
        Ldlen,
        /// <summary>
        /// 將位於指定數組索引的數組元素的地址作為 & 類型(托管指針)加載到計算堆棧的頂部。
        /// </summary>
        Ldelema,
        /// <summary>
        /// 將位於指定數組索引處的 int8 類型的元素作為 int32 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_I1,
        /// <summary>
        /// 將位於指定數組索引處的 unsigned int8 類型的元素作為 int32 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_U1,
        /// <summary>
        /// 將位於指定數組索引處的 int16 類型的元素作為 int32 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_I2,
        /// <summary>
        /// 將位於指定數組索引處的 unsigned int16 類型的元素作為 int32 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_U2,
        /// <summary>
        /// 將位於指定數組索引處的 int32 類型的元素作為 int32 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_I4,
        /// <summary>
        /// 將位於指定數組索引處的 unsigned int32 類型的元素作為 int32 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_U4,
        /// <summary>
        /// 將位於指定數組索引處的 int64 類型的元素作為 int64 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_I8,
        /// <summary>
        /// 將位於指定數組索引處的 native int 類型的元素作為 native int 加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_I,
        /// <summary>
        /// 將位於指定數組索引處的 float32 類型的元素作為 F 類型(浮點型)加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_R4,
        /// <summary>
        /// 將位於指定數組索引處的 float64 類型的元素作為 F 類型(浮點型)加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_R8,
        /// <summary>
        /// 將位於指定數組索引處的包含對象引用的元素作為 O 類型(對象引用)加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_Ref,
        /// <summary>
        /// 用計算堆棧上的 native int 值替換給定索引處的數組元素。
        /// </summary>
        Stelem_I,
        /// <summary>
        /// 用計算堆棧上的 int8 值替換給定索引處的數組元素。
        /// </summary>
        Stelem_I1,
        /// <summary>
        /// 用計算堆棧上的 int16 值替換給定索引處的數組元素。
        /// </summary>
        Stelem_I2,
        /// <summary>
        /// 用計算堆棧上的 int32 值替換給定索引處的數組元素。
        /// </summary>
        Stelem_I4,
        /// <summary>
        /// 用計算堆棧上的 int64 值替換給定索引處的數組元素。
        /// </summary>
        Stelem_I8,
        /// <summary>
        /// 用計算堆棧上的 float32 值替換給定索引處的數組元素。
        /// </summary>
        Stelem_R4,
        /// <summary>
        /// 用計算堆棧上的 float64 值替換給定索引處的數組元素。
        /// </summary>
        Stelem_R8,
        /// <summary>
        /// 用計算堆棧上的對象 ref 值(O 類型)替換給定索引處的數組元素。
        /// </summary>
        Stelem_Ref,
        /// <summary>
        /// 按照指令中指定的類型,將指定數組索引中的元素加載到計算堆棧的頂部。
        /// </summary>
        Ldelem_Any,
        /// <summary>
        /// 用計算堆棧中的值替換給定索引處的數組元素,其類型在指令中指定。
        /// </summary>
        Stelem_Any,
        /// <summary>
        /// 將指令中指定類型的已裝箱的表示形式轉換成未裝箱形式。
        /// </summary>
        Unbox_Any,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為有符號 int8 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I1,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為 unsigned int8 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U1,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為有符號 int16 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I2,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為 unsigned int16 並將其擴展為 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U2,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為有符號 int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I4,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為 unsigned int32,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U4,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為有符號 int64,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I8,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為 unsigned int64,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U8,
        /// <summary>
        /// 檢索嵌入在類型化引用內的地址(& 類型)。
        /// </summary>
        Refanyval,
        /// <summary>
        /// 如果值不是有限數,則引發 ArithmeticException。
        /// </summary>
        Ckfinite,
        /// <summary>
        /// 將對特定類型實例的類型化引用推送到計算堆棧上。
        /// </summary>
        Mkrefany,
        /// <summary>
        /// 將元數據標記轉換為其運行時表示形式,並將其推送到計算堆棧上。
        /// </summary>
        Ldtoken,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 unsigned int16,然后將其擴展為 int32。
        /// </summary>
        Conv_U2,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 unsigned int8,然后將其擴展為 int32。
        /// </summary>
        Conv_U1,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 native int。
        /// </summary>
        Conv_I,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為有符號 native int,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_I,
        /// <summary>
        /// 將位於計算堆棧頂部的有符號值轉換為 unsigned native int,並在溢出時引發 OverflowException。
        /// </summary>
        Conv_Ovf_U,
        /// <summary>
        /// 將兩個整數相加,執行溢出檢查,並且將結果推送到計算堆棧上。
        /// </summary>
        Add_Ovf,
        /// <summary>
        /// 將兩個無符號整數值相加,執行溢出檢查,並且將結果推送到計算堆棧上。
        /// </summary>
        Add_Ovf_Un,
        /// <summary>
        /// 將兩個整數值相乘,執行溢出檢查,並將結果推送到計算堆棧上。
        /// </summary>
        Mul_Ovf,
        /// <summary>
        /// 將兩個無符號整數值相乘,執行溢出檢查,並將結果推送到計算堆棧上。
        /// </summary>
        Mul_Ovf_Un,
        /// <summary>
        /// 從另一值中減去一個整數值,執行溢出檢查,並且將結果推送到計算堆棧上。
        /// </summary>
        Sub_Ovf,
        /// <summary>
        /// 從另一值中減去一個無符號整數值,執行溢出檢查,並且將結果推送到計算堆棧上。
        /// </summary>
        Sub_Ovf_Un,
        /// <summary>
        /// 將控制從異常塊的 fault 或 finally 子句轉移回公共語言結構 (CLI) 異常處理程序。
        /// </summary>
        Endfinally,
        /// <summary>
        /// 退出受保護的代碼區域,無條件將控制轉移到特定目標指令。
        /// </summary>
        Leave,
        /// <summary>
        /// 退出受保護的代碼區域,無條件將控制轉移到目標指令(縮寫形式)。
        /// </summary>
        Leave_S,
        /// <summary>
        /// 在所提供的地址存儲 native int 類型的值。
        /// </summary>
        Stind_I,
        /// <summary>
        /// 將位於計算堆棧頂部的值轉換為 unsigned native int,然后將其擴展為 native int。
        /// </summary>
        Conv_U,
        /// <summary>
        /// 返回指向當前方法的參數列表的非托管指針。
        /// </summary>
        Arglist,
        /// <summary>
        /// 比較兩個值。如果這兩個值相等,則將整數值 1 (int32) 推送到計算堆棧上;否則,將 0 (int32) 推送到計算堆棧上。
        /// </summary>
        Ceq,
        /// <summary>
        /// 比較兩個值。如果第一個值大於第二個值,則將整數值 1 (int32) 推送到計算堆棧上;反之,將 0 (int32) 推送到計算堆棧上。
        /// </summary>
        Cgt,
        /// <summary>
        /// 比較兩個無符號的或不可排序的值。如果第一個值大於第二個值,則將整數值 1 (int32) 推送到計算堆棧上;反之,將 0 (int32) 推送到計算堆棧上。
        /// </summary>
        Cgt_Un,
        /// <summary>
        /// 比較兩個值。如果第一個值小於第二個值,則將整數值 1 (int32) 推送到計算堆棧上;反之,將 0 (int32) 推送到計算堆棧上。
        /// </summary>
        Clt,
        /// <summary>
        /// 比較無符號的或不可排序的值 value1 和 value2。如果 value1 小於 value2,則將整數值 1 (int32 ) 推送到計算堆棧上;反之,將 0 ( int32 ) 推送到計算堆棧上。
        /// </summary>
        Clt_Un,
        /// <summary>
        /// 將指向實現特定方法的本機代碼的非托管指針(native int 類型)推送到計算堆棧上。
        /// </summary>
        Ldftn,
        /// <summary>
        /// 將指向實現與指定對象關聯的特定虛方法的本機代碼的非托管指針(native int 類型)推送到計算堆棧上。
        /// </summary>
        Ldvirtftn,
        /// <summary>
        /// 將參數(由指定索引值引用)加載到堆棧上。
        /// </summary>
        Ldarg,
        /// <summary>
        /// 將參數地址加載到計算堆棧上。
        /// </summary>
        Ldarga,
        /// <summary>
        /// 將位於計算堆棧頂部的值存儲到位於指定索引的參數槽中。
        /// </summary>
        Starg,
        /// <summary>
        /// 將指定索引處的局部變量加載到計算堆棧上。
        /// </summary>
        Ldloc,
        /// <summary>
        /// 將位於特定索引處的局部變量的地址加載到計算堆棧上。
        /// </summary>
        Ldloca,
        /// <summary>
        /// 從計算堆棧的頂部彈出當前值並將其存儲到指定索引處的局部變量列表中。
        /// </summary>
        Stloc,
        /// <summary>
        /// 從本地動態內存池分配特定數目的字節並將第一個分配的字節的地址(瞬態指針,* 類型)推送到計算堆棧上。
        /// </summary>
        Localloc,
        /// <summary>
        /// 將控制從異常的 filter 子句轉移回公共語言結構 (CLI) 異常處理程序。
        /// </summary>
        Endfilter,
        /// <summary>
        /// 指示當前位於計算堆棧上的地址可能沒有與緊接的 ldind、stind、ldfld、stfld、ldobj、stobj、initblk 或 cpblk 指令的自然大小對齊。
        /// </summary>
        Unaligned,
        /// <summary>
        /// 指定當前位於計算堆棧頂部的地址可以是易失的,並且讀取該位置的結果不能被緩存,或者對該地址的多個存儲區不能被取消。
        /// </summary>
        Volatile,
        /// <summary>
        /// 執行后綴的方法調用指令,以便在執行實際調用指令前移除當前方法的堆棧幀。
        /// </summary>
        Tail,
        /// <summary>
        /// 將位於指定地址的值類型的每個字段初始化為空引用或適當的基元類型的 0。
        /// </summary>
        Initobj,
        /// <summary>
        /// 約束要對其進行虛方法調用的類型。
        /// </summary>
        Constrained,
        /// <summary>
        /// 將指定數目的字節從源地址復制到目標地址。
        /// </summary>
        Cpblk,
        /// <summary>
        /// 將位於特定地址的內存的指定塊初始化為給定大小和初始值。
        /// </summary>
        Initblk,
        No,
        /// <summary>
        /// 再次引發當前異常。
        /// </summary>
        Rethrow,
        /// <summary>
        /// 將提供的值類型的大小(以字節為單位)推送到計算堆棧上。
        /// </summary>
        Sizeof,
        /// <summary>
        /// 檢索嵌入在類型化引用內的類型標記。
        /// </summary>
        Refanytype,
        /// <summary>
        /// 指定后面的數組地址操作在運行時不執行類型檢查,並且返回可變性受限的托管指針。
        /// </summary>
        Readonly,
    }
}
OpCodeEnum

 

 

using System;
using System.Collections.Generic;


namespace HotFix_Project
{
    public class InstanceClass
    {
        private int id;

        public InstanceClass()
        {
            UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass()");
            this.id = 0;
        }

        public InstanceClass(int id)
        {
            UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass() id = " + id);
            this.id = id;
        }

        public int ID
        {
            get { return id; }
        }

        // static method
        public static void StaticFunTest()
        {
            UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest()");
        }

        public static void StaticFunTest2(int a)
        {
            UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest2(), a=" + a);
        }

        public static void GenericMethod<T>(T a)
        {
            UnityEngine.Debug.Log("!!! InstanceClass.GenericMethod(), a=" + a);
        }
    }


}
HotFix_Project.InstanceClass
System.Void HotFix_Project.InstanceClass::.ctor()
System.Void HotFix_Project.InstanceClass::.ctor(System.Int32)
System.Int32 HotFix_Project.InstanceClass::get_ID()
System.Void HotFix_Project.InstanceClass::StaticFunTest()
System.Void HotFix_Project.InstanceClass::StaticFunTest2(System.Int32)
System.Void HotFix_Project.InstanceClass::GenericMethod(T)
Mono.Cecil.Methods: MethodDifinition(HotFix_Project.InstanceClass)
IType.ArrayRank : 0
IType.ArrayType : 
IType.BaseType : 
IType.ByRefType : 
IType.ElementType : 
IType.FullName : HotFix_Project.InstanceClass
IType.GenericArguments : 
IType.GetActualType() : ILRuntime.CLR.TypeSystem.ILType
IType.HasGenericParameter : False
IType.Implements : 
IType.IsArray : False
IType.IsByRef : False
IType.IsDelegate : False
IType.IsEnum : False
IType.IsGenericInstance : False
IType.IsGenericParameter : False
IType.IsInterface : False
IType.IsPrimitive : False
IType.IsValueType : False
IType.Name : InstanceClass
IType.ReflectionType : Type: InstanceClass
IType.TypeForCLR : ILRuntime.Runtime.Intepreter.ILTypeInstance
HotFix_Project.InstanceClass IType 部分屬性

 

public unsafe AppDomain() {

}

appdomain.LoadAssembly(fs);

appdomain.mapType.Count = 0
[<Module>, <Module>]
[HotFix_Project.InstanceClass, HotFix_Project.InstanceClass]
只加載程序集的 AppDomain 初始狀態
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\mscorlib.dll
UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.dll
UnityEngine.AIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll
UnityEngine.ARModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll
UnityEngine.AccessibilityModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll
UnityEngine.AnimationModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll
UnityEngine.AssetBundleModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll
UnityEngine.AudioModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll
UnityEngine.BaselibModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.BaselibModule.dll
UnityEngine.ClothModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll
UnityEngine.ClusterInputModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll
UnityEngine.ClusterRendererModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll
UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll
UnityEngine.CrashReportingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll
UnityEngine.DirectorModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll
UnityEngine.FileSystemHttpModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.FileSystemHttpModule.dll
UnityEngine.GameCenterModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll
UnityEngine.GridModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll
UnityEngine.HotReloadModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll
UnityEngine.IMGUIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll
UnityEngine.ImageConversionModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll
UnityEngine.InputModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll
UnityEngine.JSONSerializeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll
UnityEngine.LocalizationModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll
UnityEngine.ParticleSystemModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll
UnityEngine.PerformanceReportingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll
UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll
UnityEngine.Physics2DModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll
UnityEngine.ProfilerModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ProfilerModule.dll
UnityEngine.ScreenCaptureModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll
UnityEngine.SharedInternalsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll
UnityEngine.SpatialTrackingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SpatialTrackingModule.dll
UnityEngine.SpriteMaskModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll
UnityEngine.SpriteShapeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll
UnityEngine.StreamingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll
UnityEngine.StyleSheetsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.StyleSheetsModule.dll
UnityEngine.SubstanceModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll
UnityEngine.TLSModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll
UnityEngine.TerrainModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll
UnityEngine.TerrainPhysicsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll
UnityEngine.TextCoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreModule.dll
UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll
UnityEngine.TilemapModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll
UnityEngine.TimelineModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TimelineModule.dll
UnityEngine.UIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll
UnityEngine.UIElementsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll
UnityEngine.UNETModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UNETModule.dll
UnityEngine.UmbraModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll
UnityEngine.UnityAnalyticsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll
UnityEngine.UnityConnectModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll
UnityEngine.UnityTestProtocolModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll
UnityEngine.UnityWebRequestModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll
UnityEngine.UnityWebRequestAssetBundleModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll
UnityEngine.UnityWebRequestAudioModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll
UnityEngine.UnityWebRequestTextureModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll
UnityEngine.UnityWebRequestWWWModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll
UnityEngine.VFXModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll
UnityEngine.VRModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll
UnityEngine.VehiclesModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll
UnityEngine.VideoModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll
UnityEngine.WindModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll
UnityEngine.XRModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll
UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEditor.dll
Unity.Locator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\Unity.Locator.dll
System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Core.dll
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.dll
Mono.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756
    Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\Mono.Security.dll
System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
    Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Configuration.dll
System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Xml.dll
Unity.DataContract, Version=1.0.2.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\Unity.DataContract.dll
Unity.PackageManager, Version=4.5.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\PackageManager\Unity\PackageManager\2018.4.6\Unity.PackageManager.dll
UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\GUISystem\UnityEngine.UI.dll
UnityEditor.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\GUISystem\Editor\UnityEditor.UI.dll
UnityEditor.TestRunner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\TestRunner\Editor\UnityEditor.TestRunner.dll
UnityEngine.TestRunner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\TestRunner\UnityEngine.TestRunner.dll
nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb
    Unity\Editor\Data\UnityExtensions\Unity\TestRunner\net35\unity-custom\nunit.framework.dll
UnityEngine.Timeline, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\Timeline\RuntimeEditor\UnityEngine.Timeline.dll
UnityEditor.Timeline, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\Timeline\Editor\UnityEditor.Timeline.dll
UnityEngine.Networking, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\Networking\UnityEngine.Networking.dll
UnityEditor.Networking, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\Networking\Editor\UnityEditor.Networking.dll
UnityEditor.GoogleAudioSpatializer, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\UnityGoogleAudioSpatializer\Editor\UnityEditor.GoogleAudioSpatializer.dll
UnityEngine.GoogleAudioSpatializer, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\UnityGoogleAudioSpatializer\RuntimeEditor\UnityEngine.GoogleAudioSpatializer.dll
UnityEditor.SpatialTracking, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\UnitySpatialTracking\Editor\UnityEditor.SpatialTracking.dll
UnityEngine.SpatialTracking, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\UnitySpatialTracking\RuntimeEditor\UnityEngine.SpatialTracking.dll
UnityEditor.VR, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\UnityVR\Editor\UnityEditor.VR.dll
UnityEditor.Graphs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\UnityEditor.Graphs.dll
UnityEditor.WindowsStandalone.Extensions, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\PlaybackEngines\windowsstandalonesupport\UnityEditor.WindowsStandalone.Extensions.dll
SyntaxTree.VisualStudio.Unity.Bridge, Version=3.9.0.3, Culture=neutral, PublicKeyToken=null
    C:\Program Files (x86)\Microsoft Visual Studio Tools for Unity\15.0\Editor\SyntaxTree.VisualStudio.Unity.Bridge.dll
Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\ScriptAssemblies\Assembly-CSharp.dll
Assembly-CSharp-Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\ScriptAssemblies\Assembly-CSharp-Editor.dll
Unity.TextMeshPro.Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\ScriptAssemblies\Unity.TextMeshPro.Editor.dll
Unity.PackageManagerUI.Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\ScriptAssemblies\Unity.PackageManagerUI.Editor.dll
Unity.CollabProxy.Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\ScriptAssemblies\Unity.CollabProxy.Editor.dll
Unity.TextMeshPro, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\ScriptAssemblies\Unity.TextMeshPro.dll
Unity.Analytics.DataPrivacy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\ScriptAssemblies\Unity.Analytics.DataPrivacy.dll
ILRuntim.Mono.Cecil, Version=0.10.1.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e
    Assets\Plugins\ILRuntim.Mono.Cecil.dll
ILRuntime.Mono.Cecil.Mdb, Version=0.10.1.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e
    Assets\Plugins\ILRuntime.Mono.Cecil.Mdb.dll
ILRuntime.Mono.Cecil.Pdb, Version=0.10.1.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e
    Assets\Plugins\ILRuntime.Mono.Cecil.Pdb.dll
UnityEditor.Advertisements, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\PackageCache\com.unity.ads@2.0.8\Editor\UnityEditor.Advertisements.dll
Unity.Analytics.Tracker, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\PackageCache\com.unity.analytics@3.2.2\Unity.Analytics.Tracker.dll
Unity.Analytics.StandardEvents, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\PackageCache\com.unity.analytics@3.2.2\Unity.Analytics.StandardEvents.dll
Unity.Analytics.Editor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\PackageCache\com.unity.analytics@3.2.2\Unity.Analytics.Editor.dll
UnityEditor.Purchasing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    Library\PackageCache\com.unity.purchasing@2.0.3\Editor\UnityEditor.Purchasing.dll
Unity.Cecil, Version=0.10.0.0, Culture=neutral, PublicKeyToken=fc15b93552389f74
    Unity\Editor\Data\Managed\Unity.Cecil.dll
System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Xml.Linq.dll
Unity.SerializationLogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\Unity.SerializationLogic.dll
Unity.Legacy.NRefactory, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\Unity.Legacy.NRefactory.dll
ExCSS.Unity, Version=2.0.6.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\ExCSS.Unity.dll
Unity.IvyParser, Version=1.0.3.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\Managed\Unity.IvyParser.dll
UnityEditor.iOS.Extensions.Xcode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Unity\Editor\Data\UnityExtensions\Unity\UnityVR\Editor\UnityEditor.iOS.Extensions.Xcode.dll
SyntaxTree.VisualStudio.Unity.Messaging, Version=3.9.0.3, Culture=neutral, PublicKeyToken=31bf3856ad364e35
    C:\Program Files (x86)\Microsoft Visual Studio Tools for Unity\15.0\Editor\SyntaxTree.VisualStudio.Unity.Messaging.dll
主工程加載的程序集

  

public object Invoke(string type, string method, object instance, params object[] p) {        
    // 通過 HotFix_Project.InstanceClass:string 獲取 HotFix_Project.InstanceClass: ILType
    IType t = GetType(type);
    if (t == null)
        return null;
    // 通過 StaticFunTest:string 獲取 StaticFunTest:ILMethod
    var m = t.GetMethod(method, p != null ? p.Length : 0);

    // 轉型為 ILMethod
    ILMethod ilm = (ILMethod)m;
    ilm.Prewarm();
        // 通過 def.Body.Instructions 轉型為 ILRuntime.Runtime.Intepreter.OpCodes.OpCode 
        InitCodeBody()
            InitToken()
                // 緩存參數 字符串 
                Ldstr: long hashCode = appdomain.CacheString(token);
                // 緩存  UnityEngine.Debug.Log 方法
                Call: var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);

    // 獲取 UnityEngine.Debug.Log 方法
    CLRMethod cm = (CLRMethod)GetMethod(1);
    // System.Reflection.MethodInfo.Invoke
    // Module: UnityEngine.CoreModule.dll
    // Assembly: UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
    // Module.FullyQualifiedName "D:\\Program Files\\Unity\\2018.4.6f1\\Editor\\Data\\Managed\\UnityEngine\\UnityEngine.CoreModule.dll
    cm.def.Invoke(null, new[] { "Hello World" });
}
真正的Hello World
熱更項目

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HotFix_Project {
    public class HelloWorld {
        public int id = 0;

        public HelloWorld() {
            id = 2;
        }
    }
}



主項目

AppDomain.LoadAssembly
    foreach (var t in module.GetTypes()) //獲取所有此模塊定義的類型
    {
        ILType type = new ILType(t, this);

        mapType[t.FullName] = type;
        types.Add(type);

        // 這里 
        // e.g. <"HotFix_Project.HelloWorld": string, HotFix_Project.HelloWorld: TypeDefintion> 
        typeDef[t.FullName] = t;
    }

HelloWorldDemo.OnHotFixLoaded
        TypeDefinition type = appdomain.typeDef["HotFix_Project.HelloWorld"];
        MyInstance ins = new MyInstance(type);
        Assert(ins.id == 2)

// 根據 TypeDefinition 自定義的 實例
// 熱更的項目 System.Type.GetType("HotFix_Project.HelloWorld") 並獲取不到
// 雖然整個類型沒法獲取到, 但是 類型里的 字段,方法,嵌套類 等等 幾乎都能獲取到
// 因此可以通過 類型的 零件 自己組合一個 類型
// 所以 可以把 new MyInstance() 理解為 new object()
public class MyInstance {
    // Mono類型定義
    public TypeDefinition def;
    // Mono字段定義
    public FieldDefinition fieldDef;
    // Mono方法定義
    public MethodDefinition method;

    public int id;
    
    private int dummyStack;

    public MyInstance(TypeDefinition def) {
        this.def = def;
        fieldDef = def.Fields[0];
        method = def.Methods[0];

        // IL 指令
        Collection<Instruction> instructions = this.def.Methods[0].Body.Instructions;

        // HotFix_Project.HelloWorld 構造函數的 IL指令
        // ldarg.0 : 
        // ldc.i4.0 : 
        // stfld : System.Int32 HotFix_Project.HelloWorld::id
        // ldarg.0 : 
        // call : System.Void System.Object::.ctor()
        // nop : 
        // nop : 
        // ldarg.0 : 
        // ldc.i4.2 : 
        // stfld : System.Int32 HotFix_Project.HelloWorld::id
        // ret : 
        foreach (var item in instructions) {
            switch (item.OpCode.Code) {
                // 將整數值 0 作為 int32 推送到計算堆棧上
                case Code.Ldc_I4_0:
                    dummyStack = 0;
                    break;
                // 用新值替換在對象引用或指針的字段中存儲的值
                case Code.Stfld:
                    // stfld: System.Int32 HotFix_Project.HelloWorld::id = 0
                    id = dummyStack;
                    break;
                // 將整數值 0 作為 int32 推送到計算堆棧上
                case Code.Ldc_I4_2:
                    dummyStack = 2;
                    break;
                // case Code.Stfld:
                //    // stfld : System.Int32 HotFix_Project.HelloWorld::id = 2
                //    id = dummyStack;
                //    break;

                // 退出
                case Code.Ret:
                    break;

                default:
                    break;
            }
        }

    }
}
真正的HelloWorld 2.0, 便於理解,簡化處理

 

 

 

主工程:

void OnHotFixLoaded() {
    appdomain.Invoke("HotFix_Project.InstanceClass", "StaticFunText", null, null);
}

熱更工程:

namespace HotFix_Project {
    public class InstanceClass {
        public InstanceClass() {
            UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass()");
        }
    }
}
HotFix_Project.InstanceClass.StaticFunTest 調用無參數靜態方法
// 調用HotFix_Project.InstanceClass.StaticFunTest
[AppDomain].Invoke
    // 獲取HotFix_Project.InstanceClass: ILType
    [AppDomain].GetType
        // 獲取StaticFunTest:ILMethod
        [HotFix_Project.InstanceClass: ILType].GetMethod    
            // 如果 InstanceClass的methods: Dictionary<string, List<ILMethod>> 為空(默認為空,調用之后會緩存)
            [HotFix_Project.InstanceClass: ILType].InitializeMethods
                // 將靜態構造函數添加到 staticConstructor: ILMethod
                // 將構造函數添加到 constructors: List<ILMethod>
                // 將函數添加到 methods: Dictionary<string, List<ILMethod>>
                new ILMethod
                    // 設置 this.def: MethodDefinition
                    this.def = def;
                    // 設置聲明類型 declaringType: ILType
                    declaringType = type;
                    // 設置 返回類型
                    ReturnType = domain.GetType(System.Void, HotFix_Project.InstanceClass, this);
                    // 設置參數數量
                    paramCnt = def.HasParameters ? def.Parameters.Count : 0;
                // 通過方法名字符串 獲取 List<ILMethod>
                if (methods.TryGetValue(name, out lst))
                    // 遍歷ILMethod 列表
                    foreach (var i in lst)
                        // 參數數量相等
                        if (i.ParameterCount == paramCount)
                            // 返回找到的ILMethod
                            return i;
        [AppDomain].Invoke(HotFix_Project.InstanceClass.StaticFunTest(), null, null)
            // 請求解釋器 Interpreter
            [ILIntepreter] inteptreter = [AppDomain].RequestILIntepreter();
                // 鎖定 freeIntepreters: Queue<ILIntepreter>
                lock (freeIntepreters)
                    // new 一個 解釋器
                    inteptreter = new ILIntepreter(this);
                        // new 一個 運行時 堆棧
                        stack = new RuntimeStack();
                            // frames: Stack<StackFrame>
                            Stack<StackFrame> frames = new Stack<StackFrame>();
                                // 通過使用指定的字節數,從進程的非托管內存中分配內存
                                // sizeof(StackObject) == 12 字節
                                // 分配 12 * 1024 * 16 字節
                                nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);

                                // 將 IntPtr 轉換為  StackObject* 指針
                                // e.g. pointer 地址為 0x5737F010
                                pointer = (StackObject*)nativePointer.ToPointer();
                                // e.g. endOfMemory 地址為 0x573AF010
                                endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
                                // e.g. valueTypePtr 地址為 0x573AF004
                                valueTypePtr = endOfMemory - 1;    
                    // 返回解釋器
                    return interpreter
            try {
                // 解釋器運行
                res = [inteptreter].Run((ILMethod)m, instance, p);
                    // 棧頂指針 e.g. 0x4db96010
                    StackObject* esp = stack.StackBase;
                    // 重置 valueTypePtr 
                    stack.ResetValueTypePointer();
                    // 沒有參數 esp 沒有改變 還是 0x4db96010
                    esp = PushParameters(method, esp, p);
                    // 執行方法
                    esp = Execute(method, esp, out unhandledException);    
                        // [Nop: 如果修補操作碼,則填充空間。盡管可能消耗處理周期,但未執行任何有意義的操作]
                        // 0 Code = Nop, TokenInteger = 0, TokenLong = 0
                        // [Ldstr: 推送對元數據中存儲的字符串的新對象引用]
                        // 1 Code = Ldstr, TokenInteger = 0, TokenLong = -1451757320
                        // [Call: 調用由傳遞的方法說明符指示的方法]
                        // 2 Code = Call, TokenInteger = 1, TokenLong = 0
                        // [Nop: 如果修補操作碼,則填充空間。盡管可能消耗處理周期,但未執行任何有意義的操作]
                        // 3 Code = Nop, TokenInteger = 1, TokenLong = 0
                        // [Ret: 從當前方法返回,並將返回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上? 反了吧?]
                        // 4 Code = Ret, TokenInteger = 0, TokenLong = 0
                        OpCode[] body = method.Body;
                            // MethodDefinition.HasBody
                            if (def.HasBody)
                            {
                                
                                localVarCnt = def.Body.Variables.Count;
                                body = new OpCode[def.Body.Instructions.Count];
                                Dictionary<Mono.Cecil.Cil.Instruction, int> addr = new Dictionary<Mono.Cecil.Cil.Instruction, int>();
                                
                                // 根據Mono.Cecil.Cil.Instruction 初始化 ILRuntime.Runtime.Intepreter.OpCodes.OpCode
                                for (int i = 0; i < body.Length; i++)
                                {
                                    // 0 IL_000: nop  Next: IL_0001: ldstr \"!!! InstanceClass.StaticFunTest()\"
                                    // 1 IL_0001: ldstr \"!!! InstanceClass.StaticFunTest()\" Next: IL_0006: call System.Void UnityEngine.Debug::Log(System.Object)
                                    // 2 IL_0006: call System.Void UnityEngine.Debug::Log(System.Object) Next: IL_000b: nop
                                    // 3 IL_000b: nop Next: IL_000c: ret
                                    // 4 IL_000c: ret Next: null
                                    var c = def.Body.Instructions[i];
                                    OpCode code = new OpCode();
                                    // 0 Nop
                                    // 1 Ldstr
                                    // 2 Call
                                    // 3 Nop
                                    // 4 Ret
                                    code.Code = (OpCodeEnum)c.OpCode.Code;
                                    // [IL_0000: nop, 0]
                                    // [IL_0001: ldstr \"!!! InstanceClass.StaticFunTest()\", 1]
                                    // [IL_0006: call System.Void UnityEngine.Debug::Log(System.Object), 2]
                                    // [IL_000b: nop, 3]
                                    // [IL_000c: ret, 4]
                                    addr[c] = i;
                                    // 0, Nop,0,0
                                    // 1, Ldstr,0,0
                                    // 2, Call,0,0
                                    // 3, Nop,0,0
                                    // 4, Ret,0,0
                                    body[i] = code;
                                }
                                
                                
                                for (int i = 0; i < body.Length; i++)
                                {
                                    var c = def.Body.Instructions[i];
                                    
                                    // 根據Mono.Cecil.Cil.Instruction 初始化 ILRuntime.Runtime.Intepreter.OpCodes.OpCode.TokenLong
                                    // Operand: object 操作對象
                                    // 
                                    InitToken(ref body[i], c.Operand, addr);
                                        case OpCodeEnum.Ldstr:
                                        {
                                            // token e.g. "!!! InstanceClass.StaticFunTest()"
                                            // 緩存 string
                                            long hashCode = [appdomain].CacheString(token);
                                                // 獲取原始 hashCode, -1451757320
                                                long oriHash = token.GetHashCode();
                                                long hashCode = oriHash;
                                                string str = (string)token;
                                                lock (mapString)
                                                {
                                                    // 檢測碰撞
                                                    bool isCollision = CheckStringCollision(hashCode, str);
                                                    long cnt = 0;
                                                    while (isCollision)
                                                    {
                                                        cnt++;
                                                        hashCode = cnt << 32 | oriHash;
                                                        isCollision = CheckStringCollision(hashCode, str);
                                                    }
                                                    mapString[hashCode] = (string)token;
                                                }
                                                return hashCode;    
                                            // 將 TokenLong 設置為 字符串的 hash
                                            code.TokenLong = hashCode;

                                        }
                                        case OpCodeEnum.Call:
                                        {
                                            bool invalidToken;
                                            // token = System.Void UnityEngine.Debug::Log(System.Object)
                                            // declaringType = HotFix_Project.InstanceClass
                                            var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
                                                string methodname = null;
                                                string typename = null;
                                                List<IType> paramList = null;
                                                // hashCoede = 1
                                                int hashCode = token.GetHashCode();
                                                IMethod method;
                                                IType[] genericArguments = null;
                                                IType returnType;
                                                invalidToken = false;
                                                bool isConstructor = false;
                                                // 通過 hashCode = 1 找到了 UnityEngine.Debug.Log 方法
                                                if (mapMethod.TryGetValue(hashCode, out method))
                                                    return method;
                                        
                                            if (m != null)
                                            {
                                                if (invalidToken)
                                                    code.TokenInteger = m.GetHashCode();
                                                else
                                                    // TokenInteger = 1
                                                    code.TokenInteger = token.GetHashCode();
                                            }
                                            else
                                            {
                                                //Cannot find method or the method is dummy
                                                MethodReference _ref = (MethodReference)token;
                                                int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
                                                if (_ref.HasThis)
                                                    paramCnt++;
                                                code.TokenLong = paramCnt;
                                            }                                            
                                        }
                                        
                                    if (i > 0 && c.OpCode.Code == Mono.Cecil.Cil.Code.Callvirt && def.Body.Instructions[i - 1].OpCode.Code == Mono.Cecil.Cil.Code.Constrained)
                                    {
                                        body[i - 1].TokenLong = body[i].TokenInteger;
                                    }
                                }
                                
                                // def.Body.ExceptionHandlers.Count = 0
                                for (int i = 0; i < def.Body.ExceptionHandlers.Count; i++)
                                {
                                    var eh = def.Body.ExceptionHandlers[i];
                                    if (exceptionHandler == null)
                                        exceptionHandler = new Method.ExceptionHandler[def.Body.ExceptionHandlers.Count];
                                    ExceptionHandler e = new ExceptionHandler();
                                    e.HandlerStart = addr[eh.HandlerStart];
                                    e.HandlerEnd = addr[eh.HandlerEnd] - 1;
                                    e.TryStart = addr[eh.TryStart];
                                    e.TryEnd = addr[eh.TryEnd] - 1;
                                    switch (eh.HandlerType)
                                    {
                                        case Mono.Cecil.Cil.ExceptionHandlerType.Catch:
                                            e.CatchType = appdomain.GetType(eh.CatchType, declaringType, this);
                                            e.HandlerType = ExceptionHandlerType.Catch;
                                            break;
                                        case Mono.Cecil.Cil.ExceptionHandlerType.Finally:
                                            e.HandlerType = ExceptionHandlerType.Finally;
                                            break;
                                        case Mono.Cecil.Cil.ExceptionHandlerType.Fault:
                                            e.HandlerType = ExceptionHandlerType.Fault;
                                            break;
                                        default:
                                            throw new NotImplementedException();
                                    }
                                    exceptionHandler[i] = e;
                                    //Mono.Cecil.Cil.ExceptionHandlerType.
                                }
                                //Release Method body to save memory
                                // 變量為 0
                                variables = def.Body.Variables;
                                def.Body = null;
                            }
                            else
                                body = new OpCode[0];                        
                        StackFrame frame;
                        // 運行時堆棧 初始化
                        [stack: RuntimeStack].InitializeFrame(method, esp, out frame);
                            // new 一個棧幀
                            res = new StackFrame()
                            // 本地變量指針 = esp 0x4db96010
                            res.LocalVarPointer = esp; 
                            // 設置棧幀 Method
                            res.Method = method;
                            // 設置 BasePointer , 沒參數 所以也是 esp 0x4db96010
                            res.BasePointer = method.LocalVariableCount > 0 ? Add(esp, method.LocalVariableCount) : esp;
                            // 設置 ValueTypeBasePointer 0x4dbc6004
                            res.ValueTypeBasePointer = valueTypePtr;
                        // v1 = 0x4db96010
                        StackObject* v1 = frame.LocalVarPointer;
                        // v2 = 0x4db9601C
                        StackObject* v2 = frame.LocalVarPointer + 1;
                        // v3 = 0x4db96028
                        StackObject* v3 = frame.LocalVarPointer + 1 + 1;
                        // v4 = 0x4db96034
                        StackObject* v4 = Add(frame.LocalVarPointer, 3);
                        int finallyEndAddress = 0;
                        // 設置 esp 為 棧幀的 BasePointer
                        esp = frame.BasePointer;
                        // 設置 參數指針  沒有參數 所以 也是 0x4db96010
                        var arg = Minus(frame.LocalVarPointer, method.ParameterCount);
                        
                        IList<object> mStack = stack.ManagedStack;
                        int paramCnt = method.ParameterCount;
                        if (method.HasThis)//this parameter is always object reference
                        {
                            arg--;
                            paramCnt++;
                        }
                        unhandledException = false;
                        StackObject* objRef, objRef2, dst, val, a, b, arrRef;
                        object obj;
                        IType type;
                        Type clrType;
                        int intVal;    
                        
                        // 沒有參數, 跳過
                        //Managed Stack reserved for arguments(In case of starg)
                        for (int i = 0; i < paramCnt; i++)
                        {
                            a = Add(arg, i);
                            switch (a->ObjectType)
                            {
                                case ObjectTypes.Null:
                                    //Need to reserve place for null, in case of starg
                                    a->ObjectType = ObjectTypes.Object;
                                    a->Value = mStack.Count;
                                    mStack.Add(null);
                                    break;
                                case ObjectTypes.ValueTypeObjectReference:
                                    CloneStackValueType(a, a, mStack);
                                    break;
                                case ObjectTypes.Object:
                                case ObjectTypes.FieldReference:
                                case ObjectTypes.ArrayReference:
                                    frame.ManagedStackBase--;
                                    break;
                            }
                        }    
                        
                        // 將StackFrame 壓入 RuntimeStack
                        stack.PushFrame(ref frame);
                        
                        // 獲取 ValueTypeStackPointer
                        var bp = stack.ValueTypeStackPointer;
                        // 設置 ValueTypeBasePoitner
                        ValueTypeBasePointer = bp;
                        
                        // 獲取 OpCode* 
                        fixed (OpCode* ptr = body)
                        {
                            // 0x44172520
                            OpCode* ip = ptr;
                            // Nop
                            OpCodeEnum code = ip->Code;
                            bool returned = false;
                            while (!returned)
                            {        
                                try {
                                    code = ip->Code;
                                    switch(code) {
                                        case OpCodeEnum.Nop:
                                            break;
                                        case OpCodeEnum.Ldstr:
                                            esp = [ILIntepreter]PushObject(esp, mStack, AppDomain.GetString(ip->TokenLong));
                                                // ip->TokenLong -1451757320
                                                // 返回方法體里的字符串  !!! InstanceClass.StaticFunTest()
                                                [AppDomain].GetString()
                                                
                                                if (obj != null)
                                                {
                                                    
                                                    if (!isBox)
                                                    {
                                                        // Default
                                                        var typeFlags = obj.GetType().GetTypeFlags();

                                                        if ((typeFlags & CLR.Utils.Extensions.TypeFlags.IsPrimitive) != 0)
                                                        {
                                                            UnboxObject(esp, obj, mStack);
                                                        }
                                                        else if ((typeFlags & CLR.Utils.Extensions.TypeFlags.IsEnum) != 0)
                                                        {
                                                            esp->ObjectType = ObjectTypes.Integer;
                                                            esp->Value = Convert.ToInt32(obj);
                                                        }
                                                        else
                                                        {
                                                            // 是Object類型
                                                            esp->ObjectType = ObjectTypes.Object;
                                                            
                                                            esp->Value = mStack.Count;
                                                            // 添加到 List<object> || UncheckedList<object>
                                                            mStack.Add(obj);
                                                        }
                                                    }
                                                    else
                                                    {
                                                        esp->ObjectType = ObjectTypes.Object;
                                                        esp->Value = mStack.Count;
                                                        mStack.Add(obj);
                                                    }
                                                }
                                                else
                                                {
                                                    return PushNull(esp);
                                                }
                                                // 指針+ 1, e.g. 0x4db96010 + 12 = 0x4db9601C
                                                return esp + 1;                                                
                                            break;
                                        case OpCodeEnum.Call:
                                            // 根據 OpCode.TokenInteger = 1 獲取方法
                                            // UnityEngine.Debug.Log
                                            IMethod m = [domain: AppDomain].GetMethod(ip->TokenInteger);
                                            // 轉換成 CLRMethod
                                            CLRMethod cm = (CLRMethod)m;
                                            // CLRMethod.Invoke
                                            object result = cm.Invoke(this, esp, mStack);
                                                
                                                if (parameters == null)
                                                {
                                                    InitParameters();
                                                }
                                                // ParameterCount = 1
                                                int paramCount = ParameterCount;
                                                
                                                if (invocationParam == null)
                                                    invocationParam = new object[paramCount];
                                                object[] param = invocationParam;
                                                for (int i = paramCount; i >= 1; i--)
                                                {
                                                    var p = Minus(esp, i);
                                                    var pt = this.param[paramCount - i].ParameterType;
                                                    var obj = pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
                                                        case ObjectType.Object:
                                                            // 通過 StackObject 指針的 value 獲得 mStack 里的參數值
                                                            // mStack[0] = !!! InstanceClass.StaticFunTest()
                                                            return mStack[esp->Value];
                                                        
                                                        var typeFlags = GetTypeFlags(pt);
                                                        return obj;
                                                    
                                                    obj = ILIntepreter.CheckAndCloneValueType(obj, appdomain);
                                                        if (obj is ILTypeInstance)
                                                        {
                                                            ILTypeInstance ins = obj as ILTypeInstance;
                                                            if (ins.IsValueType)
                                                            {
                                                                return ins.Clone();
                                                            }
                                                        }
                                                        else
                                                        {
                                                            // System.String
                                                            var type = obj.GetType();
                                                            // Default
                                                            var typeFlags = type.GetTypeFlags();
                                                            // false
                                                            var isPrimitive = (typeFlags & CLR.Utils.Extensions.TypeFlags.IsPrimitive) != 0;
                                                            // false
                                                            var isValueType = (typeFlags & CLR.Utils.Extensions.TypeFlags.IsValueType) != 0;

                                                            if (!isPrimitive && isValueType)
                                                            {
                                                                var t = domain.GetType(type);
                                                                return ((CLRType)t).PerformMemberwiseClone(obj);
                                                            }
                                                        }
                                                    }
                                                    return obj;                                                    
                                                    param[paramCount - i] = obj;
                                                }

                                                // System.Reflection.MethodInfo.Invoke
                                                res = [def: MethodInfo].Invoke(instance, param);
                                                
                                                // 無改變
                                                [CLRMethod].FixReference
                                                // res = null;
                                                return res;
                                            // result = null 不是 CrossBindingAdaptorType
                                            if (result is CrossBindingAdaptorType)
                                                result = ((CrossBindingAdaptorType)result).ILInstance;
                                            // 1
                                            int paramCount = cm.ParameterCount;                                                
                                            for (int i = 1; i <= paramCount; i++)
                                            {
                                                // 釋放
                                                Free(Minus(esp, i));
                                                    if (esp->ObjectType >= ObjectTypes.Object)
                                                    {
                                                        var mStack = stack.ManagedStack;
                                                        if (esp->Value == mStack.Count - 1)
                                                            mStack.RemoveAt(esp->Value);
                                                    }                                                
                                            }
                                            // 移動棧頂指針
                                            esp = Minus(esp, paramCount);
                                            if (cm.HasThis)
                                            {
                                                Free(esp - 1);
                                                esp--;
                                            }
                                            if (cm.ReturnType != AppDomain.VoidType && !cm.IsConstructor)
                                            {
                                                esp = PushObject(esp, mStack, result, cm.ReturnType.TypeForCLR == typeof(object));
                                            }                                                
                                            break;
                                        case OpCodeEnum.Ret:
                                            returned = true;
                                            break;
                                    }
                                    ip++;    // 指針++
                                }
                            }
                        }
                        
                        // 清空 RuntimeStack
                        return stack.PopFrame(ref frame, esp);
                            if (frames.Count > 0 && frames.Peek().BasePointer == frame.BasePointer)
                                frames.Pop();    
                    // null        
                    object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - 1), domain, mStack)) : null;
            } finally {
                [AppDomain].FreeILIntepreter(inteptreter);
                    lock (freeIntepreters)
                    {                    
                        // 托管棧 清空
                        inteptreter.Stack.ManagedStack.Clear();
                        // Stack<StackFrame> 清空
                        inteptreter.Stack.Frames.Clear();
                        // 將清空的解釋入隊
                        freeIntepreters.Enqueue(inteptreter);                    
            }
HotFix_Project.InstanceClass.StaticFunTest 調用無參數靜態方法 流程
freeIntepreters: Queue<ILIntepreter> Count: 1
ILRuntime.Runtime.Intepreter.ILIntepreter, type: ILRuntime.Runtime.Intepreter.ILIntepreter

mapType: ThreadSafeDictionary<string, IType> Count: 25
[<Module>, <Module>], type: ILRuntime.CLR.TypeSystem.ILType
[HotFix_Project.InstanceClass, HotFix_Project.InstanceClass], type: ILRuntime.CLR.TypeSystem.ILType
[System.Void, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Void, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int32, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int64, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Boolean, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Single, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Double, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Object, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.ILogger, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.ILogger, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Type, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[System.String, System.String], type: ILRuntime.CLR.TypeSystem.CLRType
[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.String], type: ILRuntime.CLR.TypeSystem.CLRType

clrTypeMapping: Dictionary<Type, IType> Count: 11
[System.Void, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int32, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int64, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Boolean, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Single, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Double, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Object, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.ILogger, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Type, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[System.String, System.String], type: ILRuntime.CLR.TypeSystem.CLRType

mapTypeToken: ThreadSafeDictionary<int, IType> Count: 16
[536870913, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[536870914, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[536870915, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[536870916, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[536870917, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[536870918, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[536870919, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[1, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[2, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[3, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[536870920, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[4, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[5, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[536870921, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[536870922, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[536870923, System.String], type: ILRuntime.CLR.TypeSystem.CLRType

mapMethod: ThreadSafeDictionary<int, IMethod> Count :1
[1, Void Log(System.Object)], type: ILRuntime.CLR.Method.CLRMethod

mapString: ThreadSafeDictionary<long, string> Count : 1
[-1451757320, !!! InstanceClass.StaticFunTest()], type: System.String
各種字典
Debug.Log 流程
[System.Void HotFix_Project.InstanceClass::StaticFunTest(): ILMethod].InitCodeBody
    // ILRuntime.Mono.Cecil.Cil.Instruction.OpCode.Code == Call
    // ILRuntime.Mono.Cecil.Cil.Instruction.Operand == System.Void UnityEngine.Debug::Log(System.Object)
    [ILMethod].InitToken()
        bool invalidToken;
        // token: ILRuntime.Mono.Cecil.Body.Instruction.Operand = System.Void UnityEngine.Debug::Log(System.Object)
        // declaringType: HotFix_Project.InstanceClass
        // this: System.Void HotFix_Project.InstanceClass::StaticFunTest(): ILMethod
        var m = [appdomain].GetMethod(token, declaringType, this, out invalidToken);
            // 獲取 Operand 的 hashCode == 1
            int hashCode = token.GetHashCode();
            // mapMethod字典目前沒有這個方法
            if (mapMethod.TryGetValue(hashCode, out method))
                return method;    
            // object 是 Mono.Cecil.MethodReference
            if (token is Mono.Cecil.MethodReference)
                // token 也就是 UnityEngine.Debug.Log  轉型為 Mono.Cecil.MethodReference
                Mono.Cecil.MethodReference _ref = (token as Mono.Cecil.MethodReference);
                // Log
                methodname = _ref.Name;
                var typeDef = _ref.DeclaringType;
                // 獲取Log 方法所屬類型 
                // typeDef: TypeReference = UnityEngine.Debug
                // contextType: ILType = HotFix_Project.InstanceClass
                // contextMethod: ILMethod = HotFix_Project.InstanceClass.StaticFunTest()
                type = [appdomain].GetType(typeDef, contextType, contextMethod);
                    // 獲取 UnityEngine.Debug hashcode = 4
                    int hash = token.GetHashCode();
                    // mapTypeToken 字典目前沒有這個類型
                    if (mapTypeToken.TryGetValue(hash, out res))
                        return res;        
                    // UnityEngine.Debug 是 TypeReference
                    if (token is Mono.Cecil.TypeReference)
                        // token 也就是 UnityEngine.Debug.Log 轉型為 TypeReference
                        Mono.Cecil.TypeReference _ref = (token as Mono.Cecil.TypeReference);
                        // 獲取 module = HotFix_Project.dll
                        module = _ref.Module;
                        // 獲取 類型全名 UnityEngine.Debug
                        typename = _ref.FullName;
                        // _ref.Scope = UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
                        // scope = UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
                        scope = GetAssemblyName(_ref.Scope);
                    // 獲取  UnityEngine.Debug 的 IType
                    res = GetType(typename);
                        // mapType 字典 目前沒有 這個類型
                        if (mapType.TryGetValue(fullname, out res))
                            return res;    
                        // 通過 UnityEngine.Debug 獲取 Type
                        Type t = Type.GetType(fullname);
                    // 沒有找到 UnityEngine.Debug 
                    if (res == null)
                    {
                        // 將 / 替換成 +
                        typename = typename.Replace("/", "+");
                        res = GetType(typename);
                    }            
                    // res == null    scope == UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
                    if (res == null && scope != null)
                        res = GetType(typename + ", " + scope);    
                            // 獲取 UnityEngine.Debug, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
                            Type t = Type.GetType(fullname);
                            // clrTypeMapping 字典里沒有這個類型
                            if (!clrTypeMapping.TryGetValue(t, out res))
                            {
                                // 通過 Type new 一個 CLRType
                                res = new CLRType(t, this);
                                clrTypeMapping[t] = res;
                            }
                // 獲取參數
                paramList = _ref.GetParamList(this, contextType, contextMethod, genericArguments);        
                    // 有參數
                    if (def.HasParameters)
                        List<IType> param = new List<IType>();
                        // UnityEngine.Debug
                        var dt = appdomain.GetType(def.DeclaringType, contextType, contextMethod);    
                        // 遍歷參數
                        foreach (var i in def.Parameters)
                            // System.Object
                            t = appdomain.GetType(i.ParameterType, dt, null);
                // 獲取返回類型
                // System.Void
                returnType = GetType(_ref.ReturnType, type, null);
            // 獲取方法
            
            // 獲取方法
            // methodname = Log
            method = [UnityEngine.Debug type: CLRType].GetMethod(methodname, paramList, genericArguments, returnType, true);
                // 目前 UnityEngine.Debug 里沒有 方法
                if (methods == null)
                    [CLRType].InitializeMethods();    
                        if (i.IsPrivate)
                            continue;
                        List<CLRMethod> lst;
                        if (!methods.TryGetValue(i.Name, out lst))
                        {
                            lst = new List<CLRMethod>();
                            methods[i.Name] = lst;
                                "[get_unityLogger, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[DrawLine, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[DrawRay, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[Break, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[DebugBreak, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[Log, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogError, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogErrorFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[ClearDeveloperConsole, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[get_developerConsoleVisible, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[set_developerConsoleVisible, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogException, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogPlayerBuildError, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogWarning, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogWarningFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[Assert, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[AssertFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogAssertion, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[LogAssertionFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[get_isDebugBuild, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[OpenConsoleFile, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[GetDiagnosticSwitches, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[GetDiagnosticSwitch, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[SetDiagnosticSwitch, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[get_logger, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[Equals, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[Finalize, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[GetHashCode, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[GetType, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[MemberwiseClone, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                                "[ToString, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
                        }
                        lst.Add(new CLRMethod(i, this, appdomain));        
            
        // UnityEngine.Debug.Log 方法 添加到 全局 mapMethod 字典里
        if (!invalidToken)
            mapMethod[hashCode] = method;
        else
            mapMethod[method.GetHashCode()] = method;
            
        
        // 將 hashcode 復制給 OpCode.TokenInteger, 主要是用於查找方法
        if (m != null)
        {
            if (invalidToken)
                code.TokenInteger = m.GetHashCode();
            else
                code.TokenInteger = token.GetHashCode();
        }
        else
        {
            //Cannot find method or the method is dummy
            MethodReference _ref = (MethodReference)token;
            int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
            if (_ref.HasThis)
                paramCnt++;
            code.TokenLong = paramCnt;
        }    
Debug 調用流程
熱更項目

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace HotFix_Project {
    public class HelloWorldWithDebug {
   
        public HelloWorldWithDebug() {
            Debug.Log("HelloWorldWithDebug");
        }
    }
}

主項目
OnHotFixLoaded()
    // 主項目通過 MethodInfo 調用 UnityEngine.Debug.Log, 和熱更項目沒關系
    System.Type debugType = typeof(Debug);
    System.Reflection.MethodInfo log = null;

    foreach (var item in debugType.GetMethods()) {
        if (item.Name == "Log" && item.GetParameters().Length == 1) {
            log = item;
        }
    }

    log.Invoke(null, new[] { "Hello" });


    // 熱更項目 里 調用 UnityEngine.Debug.Log
    var obj = appdomain.Instantiate("HotFix_Project.HelloWorldWithDebug");
        // 根據 IL 指令 初始化方法
        // ILMethod = "HotFix_Project.HelloWorldWithDebug..ctor()"
        
        OpCode[] body = method.Body;
            [ILMethod].InitCodeBody
                // body[5] = Call, 0, 0
                // c.Operand: MethodReference = "System.Void UnityEngine.Debug::Log(System.Object)"
                // addr = 
                // "IL_0000: ldarg.0"
                // "IL_0001: call System.Void System.Object::.ctor()"
                // "IL_0006: nop"
                // "IL_0007: nop"
                // "IL_0008: ldstr \"HelloWorldWithDebug\""
                // "IL_000d: call System.Void UnityEngine.Debug::Log(System.Object)"
                // "IL_0012: nop"
                // "IL_0013: ret"        
                InitToken(ref body[i], c.Operand, addr);
                    case OpCodeEnum.Call:
                        bool invalidToken;
                        // token: MethodReference = System.Void UnityEngine.Debug::Log(System.Object)
                        // declaringType: ILType = "HotFix_Project.HelloWorldWithDebug"
                        var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
                            // _ref = token
                            // DeclaringType = "UnityEngine.Debug"
                            var typeDef = _ref.DeclaringType;
                            // 獲取 UnityEngine.Debug 的類型
                            type = GetType(typeDef, contextType, contextMethod);
                            //
                            if (token is Mono.Cecil.TypeReference)    
                                // typename = "UnityEngine.Debug"
                                typename = _ref.FullName;
                                // "UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
                                scope = GetAssemblyName(_ref.Scope);
                                // 獲取 UnityEngine.Debug 的類型
                                res = GetType(typename);
                                    // 通過 System.Type.GetType 獲取 UnityEngine.Debug 的類型
                                    // t = null 沒找到
                                    Type t = Type.GetType(fullname);
                                // res = null
                                // scope = "UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
                                if (res == null && scope != null)
                                    // 通過 "UnityEngine.Debug, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" 查找類型
                                    res = GetType(typename + ", " + scope);
                                        // 找到了
                                        Type t = Type.GetType(fullname);
                                        res = new CLRType(t, this);
                                        // [UnityEngine.Debug: Type, UnityEngine.Debug: CLRType]
                                        clrTypeMapping[t] = res;
                            // 通過 type = UnityEngine.Debug, methodname = Log,  查找方法
                            method = type.GetMethod(methodname, paramList, genericArguments, returnType, true);
                                // 初始化 UnityEngine.Debug 的方法
                                InitializeMethods();
                                    // 獲取 UnityEngine.Debug 的方法, 存入 UnityEngine.Debug: CLRType 里
                                    foreach (var i in clrType: Type.GetMethods)
                                        // e.g. Log
                                        new CLRMethod(i, this, appdomain));
                                            this.def: MethodInfo = "Void Log(System.Object)"
                                // 通過 methods 獲取 UnityEngine.Debug.Log
                                if (methods.TryGetValue(name, out lst))
                            
                        if (m != null)
                        {
                            if (invalidToken)
                                code.TokenInteger = m.GetHashCode();
                            else
                                // TokenInteger = 2
                                // token: MethodReference =  "System.Void UnityEngine.Debug::Log(System.Object)"
                                code.TokenInteger = token.GetHashCode();
                        }
                        else
                        {
                            //Cannot find method or the method is dummy
                            MethodReference _ref = (MethodReference)token;
                            int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
                            if (_ref.HasThis)
                                paramCnt++;
                            code.TokenLong = paramCnt;
                        }                
            
            // 執行
            case OpCodeEnum.Call:
                // m: CLRMethod = "Void Log(System.Object)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                CLRMethod cm = (CLRMethod)m;
                // 執行CLRMethod.Invoke
                object result = cm.Invoke(this, esp, mStack);
                    // 從 非托管棧上 獲取 參數
                    // obj = "HelloWorldWithDebug"
                    var obj = pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
                    // def: MethodInfo = "Void Log(System.Object)"
                    // param = HelloWorldWithDebug
                    res = def.Invoke(instance, param);
熱更項目 里 調用 UnityEngine.Debug.Log 2.0
熱更項目

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace HotFix_Project {
    public class HelloWorldWithScene {

        public HelloWorldWithScene() {
            // 熱更項目獲取 主項目當前場景
            Scene scene = SceneManager.GetActiveScene();
            // 熱更項目獲取 當前場景里的第一個 GameObject
            GameObject go = scene.GetRootGameObjects()[0];
            // 熱更項目獲取 主項目里 掛在 GameObject 身上的 HelloWorld 腳本
            HelloWorld hw = go.GetComponent<HelloWorld>();
            // 熱更項目調用 主項目腳本里的方法 Test1
            hw.Test1();
        }
    }
}


主項目

public void Test1() {
    var pos = transform.position;
    pos.x += 10;
    transform.position = pos;
}

void OnHotFixLoaded()
{
    // 主項目調用熱更項目的 構造函數
    ILTypeInstance obj = appdomain.Instantiate("HotFix_Project.HelloWorldWithScene");
        // 獲取構造函數
        var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
            // 初始化 方法
            // 只有一個方法 "System.Void HotFix_Project.HelloWorldWithScene::.ctor()"
            InitializeMethods();
        // m: ILMethod = "HotFix_Project.HelloWorldWithScene..ctor()"
        // res: ILTypeInstacen = "HotFix_Project.HelloWorldWithScene"
        appdomain.Invoke(m, res, null);
            // 在解釋器里 運行
            res = inteptreter.Run((ILMethod)m, instance, p);
                // 執行
                esp = Execute(method, esp, out unhandledException);
                // 原始IL
                // "IL_0000: ldarg.0"
                // "IL_0001: call System.Void System.Object::.ctor()"
                // "IL_0006: nop"
                // "IL_0007: nop"
                // "IL_0008: call UnityEngine.SceneManagement.Scene UnityEngine.SceneManagement.SceneManager::GetActiveScene()"
                // "IL_000d: stloc.0"
                // "IL_000e: ldloca.s V_0"
                // "IL_0010: call UnityEngine.GameObject[] UnityEngine.SceneManagement.Scene::GetRootGameObjects()"
                // "IL_0015: ldc.i4.0"
                // "IL_0016: ldelem.ref"
                // "IL_0017: stloc.1"
                // "IL_0018: ldloc.1"
                // "IL_0019: callvirt !!0 UnityEngine.GameObject::GetComponent<HelloWorld>()"
                // "IL_001e: stloc.2"
                // "IL_001f: ldloc.2"
                // "IL_0020: callvirt System.Void HelloWorld::Test1()"
                // "IL_0025: nop"
                // "IL_0026: ret"
                
                // 自定義IL
                // Ldarg_0, 0, 0
                // 
                
                // 獲取 
                OpCode[] body = method.Body;
                    // 
                    InitCodeBody();
                        // 將 原始 IL 轉換為 自定義的 IL
                        InitToken(ref body[i], c.Operand, addr);
                            // Ldarg_0, 0, 0 無特殊轉換
                            // Call, 0, 1  TokenLong = 1    參數數量 也就是實例自己
                            // Nop, 0, 0 無特殊轉換
                            // Nop, 0, 0 無特殊轉換
                            // Call, 2, 0 TokenInteger = 2    對應的是 "UnityEngine.SceneManagement.Scene UnityEngine.SceneManagement.SceneManager::GetActiveScene()"
                            // Stloc_0, 0, 0 無特殊轉換
                            // Ldloca_S, 0, 0    TokenInteger = 0  局部變量索引
                            // Call, 3, 0    TokenInteger = 3 對應的是 UnityEngine.GameObject[] UnityEngine.SceneManagement.Scene::GetRootGameObjects()
                            // Ldc_I4_0, 0, 0 無特殊轉換
                            // Ldelem_Ref, 0, 0 無特轉換
                            // Stloc_1, 0, 0 無特殊轉換
                            // Ldloc_1, 0, 0 無特殊轉換
                            // Callvirt, 4, 0 TokenInteger = 4 對應的是 "!!0 UnityEngine.GameObject::GetComponent<HelloWorld>()"
                            // Stloc_2, 0, 0 無特殊轉換
                            // Ldloc_2, 0, 0 無特殊轉換 
                            // Callvirt, 5, 0 TokenInteger = 5 對應的是 System.Void HelloWorld::Test1()
                            // Nop, 0, 0 無特殊轉換
                            // Ret, 0, 0 無特殊轉換
                        
                code = ip->Code;
                switch(code)
                    case Ldarg_0:    // 將"HotFix_Project.HelloWorldWithScene" 復制到 非托管棧
                    case Call:    // 平衡棧
                    case Nop:    // 無操作
                    case Nop:    // 無操作
                    case Call:    // 根據 TokenInteger = 2 調用 "UnityEngine.SceneManagement.Scene GetActiveScene()"
                        // instance = null
                        // param = null
                        // def: MethodInfo = "UnityEngine.SceneManagement.Scene GetActiveScene()"
                        // 返回 res: UnityEngine.SceneManagement.Scene
                        res = def.Invoke(instance, param);
                    case Stloc_0: // 從計算堆棧的頂部彈出當前值並將其存儲到索引 0 處的局部變量列表中. 操作 局部變量 scene
                    case Ldloca_S: // 將位於特定索引處的局部變量的地址加載到計算堆棧上(短格式)。操作 局部變量 scene
                    case Call: // 根據 TokenInteger = 3 調用 UnityEngine.GameObject[] UnityEngine.SceneManagement.Scene::GetRootGameObjects()
                        // 返回 res: UnityEngine.GameObject[1]
                        res = def.Invoke(instance, param);
                    case Ldc_I4_0:    // 將整數值 0 作為 int32 推送到計算堆棧上
                    case Ldelem_Ref: // 將位於指定數組索引處的包含對象引用的元素作為 O 類型(對象引用)加載到計算堆棧的頂部。 也就是操作 gameobject
                    case Stloc_1:    // 從計算堆棧的頂部彈出當前值並將其存儲到索引 1 處的局部變量列表中。    也就是操作 gameObject
                    case Ldloc_1:     // 將索引 1 處的局部變量加載到計算堆棧上。 也就是操作 gameobject
                    case Callvirt:    // 對對象調用后期綁定方法,並且將返回值推送到計算堆棧上。
                        // 通過 TokenInteger = 4 調用 "HelloWorld GetComponent[HelloWorld]()"
                        // instance = 主工程 場景里的 GameObject
                        // def: MethodInfo = "HelloWorld GetComponent[HelloWorld]()"
                        // res: HelloWorld 場景里 GameObject 上的 HelloWorld 腳本
                        res = def.Invoke(instance, param);
                    case Stloc_2:    // 從計算堆棧的頂部彈出當前值並將其存儲到索引 2 處的局部變量列表中。    也就是操作 HelloWorld
                    case Ldloc_2:    // 將索引 2 處的局部變量加載到計算堆棧上    也就是操作 HelloWorld
                    case Callvirt:    // 根據 TokenInteger = 2 調用 System.Void HelloWorld::Test1()"
                        // instance = 主工程 HelloWorld 腳本實例
                        // def: MethodInfo = "Void Test1()"
                        // res = null
                        res = def.Invoke(instance, param);
                    case Nop: // 無操作
                    case Ret:    // 返回
}
熱更項目里調用主工程的方法 2.0 簡化處理,便於理解

 

 

 

 

        Debug.Log("通過IMethod調用方法");
        //預先獲得IMethod,可以減低每次調用查找方法耗用的時間
        IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
        //根據方法名稱和參數個數獲取方法
        IMethod method = type.GetMethod("StaticFunTest", 0);

        appdomain.Invoke(method, null, null);
通過IMethod調用方法

 

        //預先獲得IMethod,可以減低每次調用查找方法耗用的時間
        IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];

        Debug.Log("指定參數類型來獲得IMethod");
        IType intType = appdomain.GetType(typeof(int));
        //參數類型列表
        List<IType> paramList = new List<ILRuntime.CLR.TypeSystem.IType>();
        paramList.Add(intType);
        //根據方法名稱和參數類型列表獲取方法
        IMethod method = type.GetMethod("StaticFunTest2", paramList, null);
        appdomain.Invoke(method, null, 456);
指定參數類型來獲得IMethod

 

Debug.Log("實例化熱更里的類");
object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { 233 });
    IType t;
    // 根據 "HotFix_Project.InstanceClass"  HotFix_Project.InstanceClass
    if (mapType.TryGetValue(type, out t))
    {
        ILType ilType = t as ILType;
        if (ilType != null)
        {
            // 有構造函數
            bool hasConstructor = args != null && args.Length != 0;
            // 初始化 "HotFix_Project.InstanceClass"
            var res = ilType.Instantiate(!hasConstructor);
                // 生成 ILTypeInstance
                var res = new [ILTypeInstance](this);
                    this.type = type;
                    // 根據實例字段數量 初始化 StackObject[1]
                    fields = new StackObject[type.TotalFieldCount];
                    // 根據實例字段數量 初始化  List<object>[1]
                    managedObjs = new List<object>(fields.Length);
                    // managedObjs 里的元素 默認為null
                    for (int i = 0; i < fields.Length; i++)
                    {
                        managedObjs.Add(null);
                    }
                    // 初始化 HotFix_Project.InstanceClass 的字段
                    [ILTypeInstance].InitializeFields(type);
                        for (int i = 0; i < type.FieldTypes.Length; i++)
                        {
                            // ILRuntime.CLR.TypeSystem.IType
                            var ft = type.FieldTypes[i];
                            // 
                            StackObject.Initialized(ref fields[type.FieldStartIndex + i], type.FieldStartIndex + i, ft.TypeForCLR, ft, managedObjs);
                                // 是基本類型
                                if (t.IsPrimitive)
                                    if (t == typeof(int) || t == typeof(uint) || t == typeof(short) || t == typeof(ushort) || t == typeof(byte) || t == typeof(sbyte) || t == typeof(char) || t == typeof(bool))
                                    {
                                        StackObject 的 ObjectType 為  int32
                                        esp.ObjectType = ObjectTypes.Integer;
                                        esp.Value = 0;
                                        esp.ValueLow = 0;
                                    }    
                                
                        }
                        if (type.BaseType != null && type.BaseType is ILType)
                            InitializeFields((ILType)type.BaseType);                    
                return res;            
            
            // 如果有構造函數
            if (hasConstructor)
            {                
                // 通過參數數量 獲取 構造函數
                var ilm = ilType.GetConstructor(args.Length);
                    if (constructors == null)
                        InitializeMethods();
                    foreach (var i in constructors)
                    {
                        if (i.ParameterCount == paramCnt)
                        {
                            return i;
                        }
                    }
                    return null;        
                //  根據 ILMethod ILTypeInstance , args 調用方法
                [AppDomain].Invoke(ilm, res, args);
                    // 請求解釋器
                    ILIntepreter inteptreter = RequestILIntepreter();
                    // 解釋器 運行 方法
                    res = inteptreter.Run((ILMethod)m, instance, p);
                        // 有 this
                        if (method.HasThis)
                        {
                            if (instance is CrossBindingAdaptorType)
                                instance = ((CrossBindingAdaptorType)instance).ILInstance;
                            if (instance == null)
                                throw new NullReferenceException("instance should not be null!");
                            // 將實例 壓棧
                            esp = PushObject(esp, mStack, instance);
                        }            
                        // 將參數入棧
                        esp = PushParameters(method, esp, p);
                        bool unhandledException;
                        // 執行方法
                        esp = Execute(method, esp, out unhandledException);                        
            }
            return res;
        }
    }

    return null;

//預先獲得IMethod,可以減低每次調用查找方法耗用的時間
IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
//第二種方式
object obj2 = ((ILType)type).Instantiate();
實例化熱更里的類
熱更項目

using System;
using System.Collections.Generic;

namespace HotFix_Project
{
    private int id;

    public class InstanceClass
    {
        public InstanceClass() {

        }
    }
}

主項目

AppDomain.LoadAssembly
    // t: TypeDefinition
    foreach (var t in module.GetTypes())
        // 通過 TypeDefinition 構造  ILType
        ILType type = new ILType(t, this);
            // this.typeRef: TypeReference = t: TypeDefinition
            this.typeRef = def;
            [ILType].RetriveDefinitino(def);
                // def 不是泛型參數
                if (!def.IsGenericParameter)
                    if (def is TypeSpecification)
                        definition = def as TypeDefinition;

ILTypeInstance obj = appdomain.Instantiate("HotFix_Project.InstanceClass");
    // mapType 通過字符串 獲取 ILType e.g. HotFix_Project.InstanceClass: ILType
    if (mapType.TryGetValue(type, out t))
        // 沒有參數
        bool hasConstructor = args != null && args.Length != 0;
        // res: ILTypeInstance
        var res = ilType.Instantiate(!hasConstructor);
            // res: ILTypeInstance
            var res = new ILTypeInstance(this);
                // type: ILType
                this.type = type;
                // type: TypeDefin
                fields = new StackObject[type.TotalFieldCount];
                    // 第一次獲取 ILType.TotalFieldCount 時, 初始化
                    if (fieldMapping == null)
                        // 初始化 字段類型數組, 字段定義數組, 字段名字典
                        InitializeFields()
                            // 字段類型
                            fieldTypes = new IType[definition.Fields.Count];
                            // 字段定義
                            fieldDefinitions = new FieldDefinition[definition.Fields.Count];
                            // 遍歷 definition.Fields
                            for (int i = 0; i < fields.Count; i++)
                                // 字段不是靜態的
                                if (!field.IsStatic)
                                    // 字段名 = 索引
                                    // "id" = 0
                                    fieldMapping[field.Name] = idx;
                                    // 索引 = FieldDefinition
                                    // 0 = FieldDefinition
                                    fieldDefinitions[idx - FieldStartIndex] = field;
                                    // 字段不是 泛型參數
                                    if (!field.FieldType.IsGenericParameter)
                                        // 獲取這個字段的 CLR類型
                                        // e.g. field.FieldType: TypeReference = System.Int32
                                        fieldTypes[idx - FieldStartIndex] = appdomain.GetType(field.FieldType, this, null);
                                            // 獲取 hashCode
                                            int hash = token.GetHashCode();
                                            // 目前沒有
                                            if (mapTypeToken.TryGetValue(hash, out res))
                                            // 是 TypeRefernece
                                            if (token is Mono.Cecil.TypeReference)
                                                Mono.Cecil.TypeReference _ref = (token as Mono.Cecil.TypeReference);
                                                // System.Int32
                                                typename = _ref.FullName;
                                                // _ref.Scope = "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                                                // scope = "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                                                scope = GetAssemblyName(_ref.Scope);
                                                    return scope is AssemblyNameReference ? ((AssemblyNameReference)scope).FullName : null;                                    
                                                res = GetType(typename);
                                                    // 目前 mapType 里並沒有存 System.Int32 類型
                                                    if (mapType.TryGetValue(fullname, out res))
                                                    // System.Int32 所以能通過 System.Type.GetType 獲取到類型
                                                    Type t = Type.GetType(fullname);
                                                    // clrTypeMapping 里目前也沒有 System.Int32
                                                    if (!clrTypeMapping.TryGetValue(t, out res))
                                                        // 通過 System.Int32: Type 構造 CLRType 
                                                        res = new CLRType(t, this);
                                                            // clrType: Type
                                                            this.clrType = clrType;
                                                        clrTypeMapping[t] = res;
                                                    // "System.Int32" = System.Int32: CLRType
                                                    mapType[fullname] = res;
                                                    // "System.Int32" = System.Int32: CLRType
                                                    mapType[res.FullName] = res;
                                                    // t: Type = "System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" = System.Int32: CLRType
                                                    mapType[t.AssemblyQualifiedName] = res;
                                                    // res: CLRType.GetHashCode = 536870914 
                                                    // res: CLRType = System.Int32
                                                    mapTypeToken[res.GetHashCode()] = res;
                            // 一個字段
                            totalFieldCnt = fieldTypes.Length;    
                // 根據字段個數 初始化 托管對象List
                managedObjs = new List<object>(fields.Length);
                for (int i = 0; i < fields.Length; i++)
                    // 托管對象 默認為空
                    managedObjs.Add(null);
                // 初始化字段
                InitializeFields(type);
                    for (int i = 0; i < type.FieldTypes.Length; i++)
                    {
                        // ft: IType = System.Int32
                        var ft = type.FieldTypes[i];
                        // fields[type.FieldStartIndex + i] 要操作的 StackObject 數組
                        // type.FieldStartIndex + i = 0 數組索引
                        // ft.TypeForCLR: Type = System.Int32  元素的 類型
                        // ft: IType 字段類型
                        // managedObjs:List<object> 托管堆
                        StackObject.Initialized(ref fields[type.FieldStartIndex + i], type.FieldStartIndex + i, ft.TypeForCLR, ft, managedObjs);
                            // 是基本類型
                            if (t.IsPrimitive)
                                if (t == typeof(int) || t == typeof(uint) || t == typeof(short) || t == typeof(ushort) || t == typeof(byte) || t == typeof(sbyte) || t == typeof(char) || t == typeof(bool))
                                    // StackObject的類型 是  int
                                    esp.ObjectType = ObjectTypes.Integer;
                                    esp.Value = 0;    // 值的高32位
                                    esp.ValueLow = 0;    // 值的低32位
                    }
                    // 沒有 BaseType
                    if (type.BaseType != null && type.BaseType is ILType)
                        InitializeFields((ILType)type.BaseType);
                if (initializeCLRInstance)
                    // FirstCLRBaseType 不是 CrossBindingAdaptor
                    if (!type.FirstCLRBaseType is Enviorment.CrossBindingAdaptor)
                        // HotFix_Project.InstanceClass: ILTypeInstance.clrInstance = 自己
                        clrInstance = this;
            // 調用默認構造函數
            if (callDefaultConstructor)
                IMethod m = [ILType].GetConstructor(CLR.Utils.Extensions.EmptyParamList);
                    // constructors 默認為空
                    if (constructors == null)
                        // 第一次調用, 初始化方法
                        InitializeMethods();    
                            // 普通方法 字典
                            methods = new Dictionary<string, List<ILMethod>>();
                            // 構造函數字典
                            constructors = new List<ILMethod>();
                            // TypeDefinition 不為空
                            if (definition == null)
                                return;
                            // 只有一個 "System.Void HotFix_Project.InstanceClass::.ctor()"
                            foreach (var i in definition.Methods)
                            {
                                // 是構造函數
                                if (i.IsConstructor)
                                {
                                    if (i.IsStatic)
                                        staticConstructor = new ILMethod(i, this, appdomain);
                                    else
                                        // 不是 靜態構造函數 new 一個ILMethod 添加到 constructors
                                        constructors.Add(new ILMethod(i, this, appdomain));
                                            // this.def: MethodDefinition
                                            this.def = def;
                                            // declaringType: ILType HotFix_Project.InstanceClass
                                            declaringType = type;
                                            // 返回類型不是 泛型
                                            if (def.ReturnType.IsGenericParameter)
                                            {
                                                ReturnType = FindGenericArgument(def.ReturnType.Name);
                                            }
                                            else
                                                // 獲取 返回類型 System.Void Type hashCode = 3
                                                ReturnType = domain.GetType(def.ReturnType, type, this);
                                            // declaringType 不是委托, MethodDifinition.Name 也不是 Invoke
                                            if (type.IsDelegate && def.Name == "Invoke")
                                                isDelegateInvoke = true;
                                            this.appdomain = domain;
                                            // 參數數量為0
                                            paramCnt = def.HasParameters ? def.Parameters.Count : 0;                                    
                                }
                                else
                                {
                                    List<ILMethod> lst;
                                    if (!methods.TryGetValue(i.Name, out lst))
                                    {
                                        lst = new List<ILMethod>();
                                        methods[i.Name] = lst;
                                    }
                                    var m = new ILMethod(i, this, appdomain);
                                    lst.Add(m);
                                }
                            }    
                    // 遍歷構造函數
                    foreach (var i in constructors)
                        // 參數數量適配
                        if (i.ParameterCount == param.Count)
                            // 返回這個方法
                            return i;
                // m: ILMethod = "HotFix_Project.InstanceClass..ctor()"
                // res: ILTypeInstance = HotFix_Project.InstanceClass
                appdomain.Invoke(m, res, null);
                    // 函數調用結果
                    object res = null;
                    if (m is ILMethod)
                    {
                        // 請求解釋器
                        ILIntepreter inteptreter = RequestILIntepreter();
                            // new 一個解釋器
                            inteptreter = new ILIntepreter(this);
                                // new 一個 運行時堆棧
                                stack = new RuntimeStack(this);
                                    // 沒開調試, 是 UncheckedList<object>
                                    IList<object> managedStack = new UncheckedList<object>(32)
                                    // StackFrame 棧
                                    Stack<StackFrame> frames = new Stack<StackFrame>();
                                    // 通過使用指定的字節數,從進程的非托管內存中分配內存 作為
                                    // sizeof(StackObject) == 12 字節
                                    // 分配 12 * 1024 * 16 字節
                                    nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);
                                    // 起始指針 0x5b4bf030
                                    pointer = (StackObject*)nativePointer.ToPointer();
                                    // 結束指針 = 0x5b4bf030 + 12 * 1024 * 16 = 0x5b4ef030
                                    endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
                                        return (StackObject*)((long)a + sizeof(StackObject) * b);
                                    // 0x5b4ef024 值類型指針
                                    valueTypePtr = endOfMemory - 1;                                    
                        try
                        {
                            // 解釋器 執行這個方法
                            res = inteptreter.Run((ILMethod)m, instance, p);
                                // 獲取 托管對象
                                IList<object> mStack = stack.ManagedStack;
                                // 獲取托管對象數量
                                int mStackBase = mStack.Count;
                                // 獲取 棧對象指針 0x5b4bf030  分配的非托管堆的 起始指針
                                StackObject* esp = stack.StackBase;
                                // 重設 值類型指針 
                                stack.ResetValueTypePointer();
                                // 有 this
                                if (method.HasThis)
                                    // 實例不是 CrossBindingAdaptorType
                                    if (instance is CrossBindingAdaptorType)
                                        instance = ((CrossBindingAdaptorType)instance).ILInstance;
                                    // 實例不為空
                                    if (instance == null)
                                        throw new NullReferenceException("instance should not be null!");
                                    // 將 ILTypeInstance 壓入托管棧, 同時設置 esp 指向的 StackObject的值, 最后 esp += 1
                                    esp = PushObject(esp, mStack, instance);    
                                        // {ILRuntime.Runtime.Intepreter.ILTypeInstance} 不為空
                                        if (obj != null)
                                        {
                                            // 默認 isBox = false
                                            if (!isBox)
                                            {
                                                // typeFalgs = Default
                                                var typeFlags = obj.GetType().GetTypeFlags();

                                                // 不是 基本類型
                                                if ((typeFlags & CLR.Utils.Extensions.TypeFlags.IsPrimitive) != 0)
                                                {
                                                    UnboxObject(esp, obj, mStack);
                                                }
                                                // 不是 枚舉
                                                else if ((typeFlags & CLR.Utils.Extensions.TypeFlags.IsEnum) != 0)
                                                {
                                                    esp->ObjectType = ObjectTypes.Integer;
                                                    esp->Value = Convert.ToInt32(obj);
                                                }
                                                else
                                                {
                                                    // 棧對象里的對象的類型 是 Object
                                                    esp->ObjectType = ObjectTypes.Object;
                                                    // 棧對象里的的值是 托管對象數組的索引
                                                    esp->Value = mStack.Count;
                                                    // 將 HotFix_Project.InstanceClass: {ILRuntime.Runtime.Intepreter.ILTypeInstance} 壓入托管列表
                                                    mStack.Add(obj);
                                                }
                                            }
                                            else
                                            {
                                                esp->ObjectType = ObjectTypes.Object;
                                                esp->Value = mStack.Count;
                                                mStack.Add(obj);
                                            }
                                        }
                                        else
                                        {
                                            return PushNull(esp);
                                        }
                                        // 棧指針 + 1, esp = 起始指針 0x5b4bf030 + 12個字節 = 0x5b4bf03c
                                        return esp + 1;        
                                    // 
                                    esp = PushParameters(method, esp, p);
                                        // 獲取 托管棧, 已經有一個對象了 就是 HotFix_Project.InstanceClass: ILTypeInstance
                                        IList<object> mStack = stack.ManagedStack;
                                        // 獲取 方法的參數列表 Parameters: List<IType>, 目前沒參數
                                        var plist = method.Parameters;
                                        // 參數數量1 = 0
                                        int pCnt = plist != null ? plist.Count : 0;
                                        // 參數數量2 = 0
                                        int pCnt2 = p != null ? p.Length : 0;
                                        // 不匹配 拋出異常
                                        if (pCnt != pCnt2)
                                            throw new ArgumentOutOfRangeException("Parameter mismatch");
                                        if (pCnt2 > 0)
                                        {
                                            for (int i = 0; i < p.Length; i++)
                                            {
                                                bool isBox = false;
                                                if (plist != null && i < plist.Count)
                                                    isBox = plist[i] == AppDomain.ObjectType;
                                                object obj = p[i];
                                                if (obj is CrossBindingAdaptorType)
                                                    obj = ((CrossBindingAdaptorType)obj).ILInstance;
                                                esp = ILIntepreter.PushObject(esp, mStack, obj, isBox);
                                            }
                                        }
                                        // 沒參數, esp 沒有任何操作, 0x5b4bf03c
                                        return esp;    
                                    // 
                                    esp = Execute(method, esp, out unhandledException);
                                        // Ldarg_0, 0, 0
                                        // Call, 0, 1
                                        // Nop, 0, 0
                                        // Nop, 0, 0
                                        // Ret, 0, 0
                                        OpCode[] body = method.Body;
                                        StackFrame frame;
                                        // 初始化運行時棧
                                        stack:RuntimeStack.InitializeFrame(method, esp, out frame);
                                            // esp = 0x5b4bf03c 初始+1 因為 把調用對象 壓入了 非托管棧
                                            // pointer = 0x5b4bf030 初始
                                            if (esp < pointer || esp >= endOfMemory)
                                                // 非托管棧對象指針 超出范圍 拋出異常                                            
                                                throw new StackOverflowException();
                                            // 也是超出范圍的處理
                                            if (frames.Count > 0 && frames.Peek().BasePointer > esp)
                                                throw new StackOverflowException();
                                            // new 一個 棧幀
                                            res = new StackFrame();
                                            // 當前 StackObject* 指向的地址
                                            res.LocalVarPointer = esp;
                                            // 當前的方法 ILMethod
                                            res.Method = method;        
                                            // 如果有參數, 將 esp + 參數的數量, 現在並沒有所以也是 0x5b4bf03c
                                            res.BasePointer = method.LocalVariableCount > 0 ? Add(esp, method.LocalVariableCount) : esp;    
                                            // 非托管幀 指向的 托管對象 列表 索引  = 1
                                            res.ManagedStackBase = managedStack.Count;    
                                            // 0x5b4ef024
                                            res.ValueTypeBasePointer = valueTypePtr;
                                        // v1 = 0x5b4bf03c
                                        StackObject* v1 = frame.LocalVarPointer;
                                        // v2 = 0x5b4bf048
                                        StackObject* v2 = frame.LocalVarPointer + 1;
                                        // v3 = 0x5b4bf054
                                        StackObject* v3 = frame.LocalVarPointer + 1 + 1;
                                        // v4 = 0x5b4bf060
                                        StackObject* v4 = Add(frame.LocalVarPointer, 3);
                                        int finallyEndAddress = 0;                                    
                                        // 棧指針指向  0x5b4bf03c
                                        esp = frame.BasePointer;
                                        // 參數指針指向 0x5b4bf03c 因為沒有參數
                                        var arg = Minus(frame.LocalVarPointer, method.ParameterCount);
                                        // 托管對象 ILTypeInstance
                                        IList<object> mStack = stack.ManagedStack;
                                        // 參數0
                                        int paramCnt = method.ParameterCount;
                                        if (method.HasThis)//this parameter is always object reference
                                        {
                                            // 參數指針-- 0x5b4bf030
                                            arg--;
                                            // 現在參數數量是1  這個1 就是 指向 ILTypeInstance 的stackobject*
                                            paramCnt++;
                                        }
                                        unhandledException = false;
                                        StackObject* objRef, objRef2, dst, val, a, b, arrRef;
                                        object obj;
                                        IType type;
                                        Type clrType;
                                        int intVal;        

                                        //Managed Stack reserved for arguments(In case of starg)
                                        for (int i = 0; i < paramCnt; i++)
                                        {
                                            // a = 0x5b4bf030 a指向 包含 HotFix_Project.InstanceClass 的 StackObject*
                                            a = Add(arg, i);
                                            // 
                                            switch (a->ObjectType)
                                            {
                                                case ObjectTypes.Null:
                                                    //Need to reserve place for null, in case of starg
                                                    a->ObjectType = ObjectTypes.Object;
                                                    a->Value = mStack.Count;
                                                    mStack.Add(null);
                                                    break;
                                                case ObjectTypes.ValueTypeObjectReference:
                                                    CloneStackValueType(a, a, mStack);
                                                    break;
                                                case ObjectTypes.Object:
                                                case ObjectTypes.FieldReference:
                                                case ObjectTypes.ArrayReference:
                                                    // 非托管棧幀指向的 托管棧 索引-- 現在是 0
                                                    frame.ManagedStackBase--;
                                                    break;
                                            }
                                        }
                                        
                                        // 將StackFrame 入棧
                                        stack.PushFrame(ref frame);    
                                        // 1 托管棧 只有1個  HotFix_Project.InstanceClass
                                        int locBase = mStack.Count;
                                        
                                        //Managed Stack reserved for local variable
                                        // LocalVariableCount=0, 沒有局部變量,沒進
                                        for (int i = 0; i < method.LocalVariableCount; i++)
                                        {
                                            mStack.Add(null);
                                        }
                                        // LocalVariableCount=0, 沒有局部變量,沒進
                                        for (int i = 0; i < method.LocalVariableCount; i++)
                                        // 值類型指針 0x5b4ef024
                                        var bp = stack.ValueTypeStackPointer;
                                        ValueTypeBasePointer = bp;
                                        
                                        // body: OpCode[]
                                        // Ldarg_0, 0, 0
                                        // Call, 0, 1
                                        // Nop, 0, 0
                                        // Nop, 0, 0
                                        // Ret, 0, 0                                        
                                        fixed (OpCode* ptr = body)
                                        {
                                            OpCode* ip = ptr;
                                            OpCodeEnum code = ip->Code;
                                            bool returned = false;
                                            // 讀取所有的 OpCode ,直到返回
                                            while (!returned)
                                            {
                                                try
                                                {                                            
                                                    code = ip->Code;
                                                    switch (code)
                                                    {
                                                        // 將索引為 0 的參數加載到計算堆棧上。
                                                        case OpCodeEnum.Ldarg_0:
                                                            // 將托管堆里的 HotFix_Project.InstanceClass 拷貝到 棧幀                                                            
                                                            CopyToStack(esp, arg, mStack);
                                                                // 將 0x5b4bf030 的 StackObject 的值,拷貝到 當前棧幀 指向的 StackObject* 0x5b4bf03c 
                                                                // StackObject.ObjectType = ObjectType.Object 對象
                                                                // StackObject.Value = 0 對應的托管堆里的 索引
                                                                *dst = *src;
                                                                // >= 沒錯
                                                                if (dst->ObjectType >= ObjectTypes.Object)
                                                                {
                                                                    // 棧幀指向的 非托管棧 的 值為 1
                                                                    dst->Value = mStack.Count;
                                                                    // 獲取 被拷貝的 StackObject* 指向的 托管堆的  HotFix_Project.InstanceClass
                                                                    var obj = mStack[src->Value];
                                                                    // 復制這個 obj 到 托管堆
                                                                    // [1] = HotFix_Project.InstanceClass
                                                                    // [0] = HotFix_Project.InstanceClass
                                                                    mStack.Add(obj);
                                                                }    
                                                            // 棧指針++ =  0x5b4bf048
                                                            esp++;
                                                            break;    
                                                        // 調用由傳遞的方法說明符指示的方法。
                                                        case OpCodeEnum.Call:
                                                        // 對對象調用后期綁定方法,並且將返回值推送到計算堆棧上。
                                                        case OpCodeEnum.Callvirt:
                                                            // ip->TokenInteger = 0
                                                            // 沒找到ILMethod
                                                            IMethod m = domain.GetMethod(ip->TokenInteger);
                                                            if (m == null)
                                                                //Irrelevant method
                                                                // ip->TokenLong = 1
                                                                int cnt = (int)ip->TokenLong;
                                                                //Balance the stack
                                                                for (int i = 0; i < cnt; i++)
                                                                {
                                                                    // esp = 0x5b4bf048
                                                                    // esp - 1 = 0x5b4bf03c
                                                                    // 釋放 esp - 1 也就是 0x5b4bf03c StackObject* 指向的 托管對象
                                                                    Free(esp - 1);
                                                                        if (esp->ObjectType >= ObjectTypes.Object)
                                                                        {
                                                                            // [0] = HotFix_Project.InstanceClass
                                                                            // [1] = HotFix_Project.InstanceClass
                                                                            var mStack = stack.ManagedStack;
                                                                            // 非托管指針 指向 托管對象索引0
                                                                            if (esp->Value == mStack.Count - 1)
                                                                                // 現在
                                                                                // [0] = HotFix_Project.InstanceClass
                                                                                mStack.RemoveAt(esp->Value);
                                                                        }    
                                                                    // 非托管棧 下移
                                                                    // 非托管棧指針指向 0x5b4bf03c
                                                                    esp--;
                                                                }
                                                            break;
                                                        // 從當前方法返回,並將返回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上。
                                                        case OpCodeEnum.Ret:
                                                            returned = true;
                                                        break;
                                                    }
                                                    // IL指令索引+1
                                                    ip++
                                                }
                                        // esp = 0x5b4bf03c
                                        return stack.PopFrame(ref frame, esp);    
                                            // 棧幀出棧
                                            if (frames.Count > 0 && frames.Peek().BasePointer == frame.BasePointer)
                                                frames.Pop();
                                            else
                                                throw new NotSupportedException();
                                            // 返回的 StackObject* 臨時變量 returnVal = 0x5b4bf030 起始指針
                                            StackObject* returnVal = esp - 1;
                                            // method = "HotFix_Project.InstanceClass..ctor()"
                                            var method = frame.Method;
                                            // frame.LocalVarPointer = 0x5b4bf03c
                                            // 真正要返回的 StackObject*
                                            StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
                                            // 棧幀存儲的 托管對象索引 = 0
                                            int mStackBase = frame.ManagedStackBase;
                                            // 實例方法 有 this
                                            if (method.HasThis)
                                                // ret = 0x5b4bf03c
                                                ret--;
                                            // 不等於
                                            if(method.ReturnType != intepreter.AppDomain.VoidType)
                                            {
                                                
                                                *ret = *returnVal;
                                                if(ret->ObjectType == ObjectTypes.Object)
                                                {
                                                    // 返回的 StackObject* 的value 指向的托管堆 索引 
                                                    ret->Value = mStackBase;
                                                    // 將 返回的 StackObject* 指向的 托管堆的對象 復制到  托管堆 mStackBase位置
                                                    managedStack[mStackBase] = managedStack[returnVal->Value];
                                                    // 
                                                    mStackBase++;
                                                }
                                                else if(ret->ObjectType == ObjectTypes.ValueTypeObjectReference)
                                                {
                                                    StackObject* oriAddr = frame.ValueTypeBasePointer;
                                                    RelocateValueType(ret, ref frame.ValueTypeBasePointer, ref mStackBase);
                                                    *(long*)&ret->Value = (long)oriAddr;
                                                }
                                                // 0x5b4bf03c, 非托管棧指針上移
                                                ret++;
                                            }    
                                        #if DEBUG && !DISABLE_ILRUNTIME_DEBUG
                                            ((List<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
                                        #else
                                            // 托管堆 清理
                                            // [0] {ILRuntime.Runtime.Intepreter.ILTypeInstance}
                                            ((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
                                        #endif    
                                            // 設置 值類型指針 
                                            valueTypePtr = frame.ValueTypeBasePointer;
                                            // ret = 0x5b4bf03c
                                            return ret;
                                    // result = HotFix_Project.InstanceClass
                                    object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - 1), domain, mStack)) : null;
                                            // esp = 0x5b4bf03c
                                            // esp - 1= 0x5b4bf030
                                            StackObject.ToObject((esp - 1), domain, mStack)
                                                switch (esp->ObjectType)
                                                {
                                                case ObjectTypes.Object:
                                                    // esp->Value = 0
                                                    // 返回托管堆的對象 HotFix_Project.InstanceClass
                                                    return mStack[esp->Value];
                                                }
                                    // 移除托管堆對象
                                    // 現在托管堆空了
                                    ((UncheckedList<object>)mStack).RemoveRange(mStackBase, mStack.Count - mStackBase);
                                    // retuurn  HotFix_Project.InstanceClass
                                    return result;
                        }
                        finally
                        {
                            // 清空解釋器
                            FreeILIntepreter(inteptreter);
                                lock (freeIntepreters)
                                    // 清空托管堆
                                    inteptreter.Stack.ManagedStack.Clear();
                                    // 清空 Stack<StackFrame>
                                    inteptreter.Stack.Frames.Clear();
                                    // 將這個解釋器 放入到 空閑解釋器 隊列
                                    freeIntepreters.Enqueue(inteptreter);
                            
                        }
                    }
                    // res = HotFix_Project.InstanceClass
                    return res;    
實例化熱更里的類2.0 簡化處理,便於理解

 

 

 

        Debug.Log("實例化熱更里的類");
        object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { 233 });

        Debug.Log("調用成員方法");
        int id = (int)appdomain.Invoke("HotFix_Project.InstanceClass", "get_ID", obj, null);
        Debug.Log("!! HotFix_Project.InstanceClass.ID = " + id);
        id = (int)appdomain.Invoke("HotFix_Project.InstanceClass", "get_ID", obj2, null);
        Debug.Log("!! HotFix_Project.InstanceClass.ID = " + id);
調用成員方法

  

Debug.Log("調用泛型方法");
IType stringType = appdomain.GetType(typeof(string));
IType[] genericArguments = new IType[] { stringType };
appdomain.InvokeGenericMethod("HotFix_Project.InstanceClass", "GenericMethod", genericArguments, null, "TestString");
    IType t = GetType(type);
    if (t == null)
        return null;
    // Name: GenericMethod
    // CallingConvention: Generic
    // FullName: System.Void HotFix_Project.InstanceClass::GenericMethod(T)
    // ILRuntime.Mono.Cecil.GenericParameterCollection ["T"]
    var m = t.GetMethod(method, p.Length);

    if (m != null)
    {
        // 生成泛型方法
        m = m.MakeGenericMethod(genericArguments);
            KeyValuePair<string, IType>[] genericParameters = new KeyValuePair<string, IType>[genericArguments.Length];
            for (int i = 0; i < genericArguments.Length; i++)
            {
                string name = def.GenericParameters[i].Name;
                IType val = genericArguments[i];
                genericParameters[i] = new KeyValuePair<string, IType>(name, val);
            }

            ILMethod m = new ILMethod(def, declaringType, appdomain);
            m.genericParameters = genericParameters;
            m.genericArguments = genericArguments;
            if (m.def.ReturnType.IsGenericParameter)
            {
                m.ReturnType = m.FindGenericArgument(m.def.ReturnType.Name);
            }
            return m;        
        return Invoke(m, instance, p);
    }
    return null;
調用泛型方法

 

        IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];

        IType intType = appdomain.GetType(typeof(int));
        //參數類型列表
        List<IType> paramList = new List<ILRuntime.CLR.TypeSystem.IType>();

        IType stringType = appdomain.GetType(typeof(string));
        IType[] genericArguments = new IType[] { stringType };

        Debug.Log("獲取泛型方法的IMethod");
        paramList.Clear();
        paramList.Add(intType);
        genericArguments = new IType[] { intType };

        IMethod method = type.GetMethod("GenericMethod", paramList, genericArguments);
        appdomain.Invoke(method, null, 33333);
獲取泛型方法的IMethod

 

 

主工程
Debug.Log("完全在熱更DLL內部使用的委托,直接可用,不需要做任何處理");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);



熱更工程
using System;
using System.Collections.Generic;

namespace HotFix_Project
{
    public class TestDelegate
    {
        static TestDelegateMethod delegateMethod;

        public static void Initialize()
        {
            delegateMethod = Method;
        }

        public static void RunTest()
        {
            delegateMethod(123);
        }

        static void Method(int a)
        {
            UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
        }
    }
}


流程
new AppDomain()
    dMgr = new DelegateManager(this);
        defaultConverter: Func<Delegate, Delegate> = DefaultConverterStub;
            // 注冊委托轉換器
            dMgr.RegisterDelegateConvertor<Action>((dele) => { return dele; });
                // System.Action
                var type = typeof(T);
                // System.Action 是  Delegate
                if (type.IsSubclassOf(typeof(Delegate)))
                {
                    // action
                    // {
                    //     System.Func`2
                    //           [
                    //               [System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],
                    //               [System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
                    //           ]
                    // }
                    // "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
                    clrDelegates[type] = action;
                }    
    
    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
        // Nop, 0, 0
        // Ldnull, 0, 0
        // Ldfftn, 1, 0
        // Newobj, 2, 0
        // Stsfld, 0, 17179869184
        // Ret, 0, 0
        [ILIntepreter].Execute
            // 將指向實現特定方法的本機代碼的非托管指針(native int 類型)推送到計算堆棧上
            OpCodeEnum.Ldftn:
                // HotFix_Project.TestDelegate.Method(Int32 a)
                IMethod m = domain.GetMethod(ip->TokenInteger);
                // 將這個方法入棧
                esp = PushObject(esp, mStack, m);
            // 創建一個值類型的新對象或新實例,並將對象引用(O 類型)推送到計算堆棧上。
            case OpCodeEnum.Newobj:
                // TestDelegateMethod.Void .ctor(Object, IntPtr)
                IMethod m = domain.GetMethod(ip->TokenInteger);
                if (!m is ILMethod)
                    CLRMethod cm = (CLRMethod)m;
                    // TestDelegateMethod 是委托
                    if (cm.DeclearingType.IsDelegate)
                        // "HotFix_Project.TestDelegate.Method(Int32 a)"
                        var mi = (IMethod)mStack[(esp - 1)->Value];
                        
                        if (((ILMethod)mi).DelegateAdapter == null)
                        {
                            // 設置 DelegateAdapter
                            ((ILMethod)mi).DelegateAdapter = domain.DelegateManager.FindDelegateAdapter(null, (ILMethod)mi);
                                // new 一個 dummyAdapter
                                res = dummyAdapter.Instantiate(appdomain, instance, method);
                                    return new DummyDelegateAdapter(appdomain, instance, method);
                                        DelegateAdapter()
                                            this.appdomain = appdomain;
                                            this.instance: ILTypeInstance = instance;
                                            this.method: ILMethod = method;
                                            CLRInstance: object = this;    
                        }
                        // "HotFix_Project.TestDelegate.Method(Int32 a)"
                        dele: object = ((ILMethod)mi).DelegateAdapter;
                    // 入棧
                    esp = PushObject(esp, mStack, dele);
            // 用來自計算堆棧的值替換靜態字段的值
            case OpCodeEnum.Stsfld:
                // "HotFix_Project.TestDelegate"
                type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                if type is ILType
                    ILType t = type as ILType;
                    val = esp - 1;
                    t.StaticInstance.AssignFromStack((int)ip->TokenLong, val, AppDomain, mStack);    
                        // fieldIndx = 0, fields.Length = 1
                        if (fieldIdx < fields.Length && fieldIdx >= 0)
                            AssignFromStackSub(ref fields[fieldIdx], fieldIdx, esp, managedStack);
                                case ObjectTypes.FieldReference:
                                    field.Value = fieldIdx;
                                    managedObjs[fieldIdx] = ILIntepreter.CheckAndCloneValueType(managedStack[esp->Value], Type.AppDomain);        

    appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);
        // "HotFix_Project.TestDelegate.RunTest()"
        return Invoke(m, instance, p);
            // Nop, 0, 0
            // Ldsfld, 0, 12884901888
            // Ldc_I4_S, 0, 123
            // Callvirt, 3, 0
            // Nop, 0, 0
            // Ret, 0, 0
            res = inteptreter.Run((ILMethod)m, instance, p);
                esp = Execute(method, esp, out unhandledException);
                    case OpCodeEnum.Ldsfld:
                        // "HotFix_Project.TestDelegate"
                        type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                        // t.StaticInstance: ILTypeStaticInstance
                        t.StaticInstance.PushToStack((int)ip->TokenLong, esp, AppDomain, mStack);
                    // 將提供的 int8 值作為 int32 推送到計算堆棧上(短格式)
                    case OpCodeEnum.Ldc_I4_S:
                        esp->Value = ip->TokenInteger;
                        esp->ObjectType = ObjectTypes.Integer;
                    case OpCodeEnum.Callvirt:
                        // TestDelegateMethod.Invoke
                        IMethod m = domain.GetMethod(ip->TokenInteger);
                        LRMethod cm = (CLRMethod)m;
                        if (cm.IsDelegateInvoke)
                            // instance = "HotFix_Project.TestDelegate.Method(Int32 a)"
                            var instance = StackObject.ToObject((Minus(esp, cm.ParameterCount + 1)), domain, mStack);
                            if (instance is IDelegateAdapter)
                                esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);
                                    var ebp = esp;
                                    esp = ILInvokeSub(intp, esp, mStack);
                                        var ebp = esp;
                                        bool unhandled;
                                        if (method.HasThis)
                                            esp = ILIntepreter.PushObject(esp, mStack, instance);
                                        int paramCnt = method.ParameterCount;
                                        for(int i = paramCnt; i > 0; i--)
                                        {
                                            intp.CopyToStack(esp, Minus(ebp, i), mStack);
                                            esp++;
                                        }
                                        // 調用實際方法
                                        // Nop, 0, 0
                                        // Ldstr, 0, -1182677902
                                        // Ldarg_0, 0, 0
                                        // Box, 4, 0
                                        // Call, 5, 0
                                        // Nop, 0, 0
                                        // Ret, 0, 0
                                        var ret = intp.Execute(method, esp, out unhandled);
                                            case Ldarg_0:
                                                // 將 參數 123 拷貝到 棧上
                                                CopyToStack(esp, arg, mStack);
                                            // 裝箱
                                            case OpCodeEnum.Box:
                                                if (type.TypeForCLR.IsPrimitive)
                                                    case ObjectTypes.Integer:
                                                        esp = PushObject(objRef, mStack, objRef->Value, true);
                                                            // 0 "HotFix_Project.TestDelegate.Method(Int32 a)"
                                                            // 1 "!! TestDelegate.Method, a = "
                                                            // 2 123
                                                            mStack
                                            case OpCodeEnum.Call:
                                                // "System.String Concat(System.Object, System.Object)"
                                                IMethod m = domain.GetMethod(ip->TokenInteger);
                                                
                                                object result = cm.Invoke(this, esp, mStack);
                                                    // param
                                                    // 0 "!! TestDelegate.Method, a = "
                                                    // 1 123
                                                    res = def.Invoke(instance, param);
                                            case OpCodeEnum.Call:
                                                // "UnityEngine.Debug.Log"
                                                object result = cm.Invoke(this, esp, mStack);
                                                
                                        if (next != null)
                                        {
                                            if (method.ReturnType != appdomain.VoidType)
                                            {
                                                intp.Free(ret - 1);//Return value for multicast delegate doesn't make sense, only return the last one's value
                                            }
                                            DelegateAdapter n = (DelegateAdapter)next;
                                            ret = n.ILInvokeSub(intp, ebp, mStack);

                                        }
                                        return ret;                                    
                                    return ClearStack(intp, esp, ebp, mStack);                                
                                processed = true;    
完全在熱更DLL內部使用的委托

 

熱更工程

using System;
using System.Collections.Generic;

namespace HotFix_Project
{
    public delegate void MyDelegate(int a);

    public class TestDelegate
    {
        static MyDelegate myDelegate;
        
        public static void Initialize()
        {
            myDelegate = Method;
        }
        
        public static void RunTest()
        {
            myDelegate(456);
        }
        
        static void Method(int a)
        {
            UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
        }
        
主工程

OnHotFixLoaded()
    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
        // method = "HotFix_Project.TestDelegate.Initialize()"
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldnull"
        // "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
        // "IL_0008: newobj System.Void HotFix_Project.MyDelegate::.ctor(System.Object,System.IntPtr)"
        // "IL_000d: stsfld HotFix_Project.MyDelegate HotFix_Project.TestDelegate::myDelegate"
        // "IL_0012: ret"        
        esp = Execute(method, esp, out unhandledException);
            case OpCodeEnum.Newobj:
                // 獲取 "HotFix_Project.MyDelegate..ctor(Object object, IntPtr method)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                // 熱更里的委托是ILMethod
                if (m is ILMethod)
                    // 獲取委托指向的方法 "HotFix_Project.TestDelegate.Method(Int32 a)"
                    var mi = (IMethod)mStack[(esp - 1)->Value];
                    // 是ILMethod
                    if (mi is ILMethod)
                        if (((ILMethod)mi).DelegateAdapter == null)
                            // 去 委托管理器 里查找 委托適配器
                            ((ILMethod)mi).DelegateAdapter = domain.[DelegateManager].FindDelegateAdapter(null, (ILMethod)mi);
                                // 返回類型是 void
                                if (method.ReturnType == appdomain.VoidType)
                                    // 初始化一個 dummyAdapter
                                    res = dummyAdapter.Instantiate(appdomain, instance, method);
                                        return new DummyDelegateAdapter(appdomain, instance, method);
                    // 將 DummyDelegateAdapter 入棧, 這個 委托適配里 包含了 對應的方法
                    esp = PushObject(esp, mStack, dele); 
            case OpCodeEnum.Stsfld:
                // type = "HotFix_Project.TestDelegate"
                type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                // 是 ILType
                if (type is ILType)
                    ILType t = type as ILType;                    
                    val = esp - 1;        
                    // 將 "HotFix_Project.TestDelegate.Method(Int32 a)" 復制給 靜態字段 HotFix_Project.TestDelegate::delegateMethod
                    t.StaticInstance.AssignFromStack((int)ip->TokenLong, val, AppDomain, mStack);    
                
    appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);
        // method = "HotFix_Project.TestDelegate.RunTest()"
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldsfld HotFix_Project.MyDelegate HotFix_Project.TestDelegate::myDelegate"
        // "IL_0006: ldc.i4 456"
        // "IL_000b: callvirt System.Void HotFix_Project.MyDelegate::Invoke(System.Int32)"
        // "IL_0010: nop"
        // "IL_0011: ret"
        esp = Execute(method, esp, out unhandledException);
            case OpCodeEnum.Ldsfld:
                // 獲取"HotFix_Project.TestDelegate"
                type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                // 將 HotFix_Project.TestDelegate 的指向 IDelegateAdapter 的靜態成員 入棧
                t.StaticInstance.PushToStack((int)ip->TokenLong, esp, AppDomain, mStack);
            case OpCodeEnum.Callvirt:
                // m = "HotFix_Project.MyDelegate.Invoke(Int32 a)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                    if (m is ILMethod)
                        if (m.IsDelegateInvoke)
                            // 從棧上獲取 HotFix_Project.TestDelegate.Method(Int32 a):IDelegateAdapter 委托適配器
                            var instance = StackObject.ToObject((Minus(esp, m.ParameterCount + 1)), domain, mStack);
                                if (instance is IDelegateAdapter)
                                    esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);
                                        var ebp = esp;
                                        esp = [DummyDelegateAdapter].ILInvokeSub(intp, esp, mStack);
                                            // 調用委托適配器指向的 方法
                                            // method = "HotFix_Project.TestDelegate.Method(Int32 a)"
                                            var ret = intp.Execute(method, esp, out unhandled);
                                        return ClearStack(intp, esp, ebp, mStack);
熱更里的工程調用熱更里的委托實例(該委托類型在熱更項目里聲明, 該委托實例指向熱更里的函數, 不需要注冊適配器)2.0

 

using System;
using System.Collections.Generic;

namespace HotFix_Project
{

    public class TestDelegate
    {
        static TestDelegateMethod delegateMethod;
        
        public static void Initialize()
        {
            delegateMethod = Method;
        }
        
        public static void RunTest()
        {
            delegateMethod(456);
        }
        
        static void Method(int a)
        {
            UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
        }

主工程

public static TestDelegateMethod TestMethodDelegate;
        
OnHotFixLoaded()
    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
        // method = "HotFix_Project.TestDelegate.Initialize()"
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldnull"
        // "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
        // "IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
        // "IL_000d: stsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
        // "IL_0012: ret"        
        esp = Execute(method, esp, out unhandledException);
            case OpCodeEnum.Newobj:
                // 獲取 TestDelegateMethod."Void .ctor(Object, IntPtr)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                // 主工程里的 委托構造函數 不是ILMethod, 而是 CLRMethod
                if (m is not ILMethod)
                    // 轉型為 CLRMethod
                    CLRMethod cm = (CLRMethod)m;
                    if (cm.DeclearingType.IsDelegate)
                        // 從棧上獲取 mi = "HotFix_Project.TestDelegate.Method(Int32 a)"
                        var mi = (IMethod)mStack[(esp - 1)->Value];
                        // 熱更工程里的 方法是 ILMethod
                        if (mi is ILMethod)
                            if (ins == null)
                                // 委托實際調用的方法 默認是沒有 DelegateAdapter的
                                if (((ILMethod)mi).DelegateAdapter == null)
                                    // 去 委托管理器 里查找 委托適配器
                                    ((ILMethod)mi).DelegateAdapter = domain.[DelegateManager].FindDelegateAdapter(null, (ILMethod)mi);
                                        // 返回類型是 void
                                        if (method.ReturnType == appdomain.VoidType)
                                            // 初始化一個 dummyAdapter
                                            res = dummyAdapter.Instantiate(appdomain, instance, method);
                                                    return new DummyDelegateAdapter(appdomain, instance, method);
                            // 將 DummyDelegateAdapter 入棧, 這個 委托適配里 包含了 對應的方法
                            esp = PushObject(esp, mStack, dele); 
            case OpCodeEnum.Stsfld:
                // type = "HotFix_Project.TestDelegate"
                type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                // 是 ILType
                if (type is ILType)
                    ILType t = type as ILType;                    
                    val = esp - 1;        
                    // 將 "HotFix_Project.TestDelegate.Method(Int32 a)" 復制給 靜態字段 HotFix_Project.TestDelegate::delegateMethod
                    t.StaticInstance.AssignFromStack((int)ip->TokenLong, val, AppDomain, mStack);                    
                
    appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);
        // method = "HotFix_Project.TestDelegate.RunTest()"
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
        // "IL_0006: ldc.i4.s 123"
        // "IL_0008: callvirt System.Void TestDelegateMethod::Invoke(System.Int32)"
        // "IL_0010: nop"
        // "IL_0011: ret"
        esp = Execute(method, esp, out unhandledException);
            case OpCodeEnum.Ldsfld:
                // 獲取"HotFix_Project.TestDelegate"
                type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                // 將 HotFix_Project.TestDelegate 的指向 IDelegateAdapter 的靜態成員 入棧
                t.StaticInstance.PushToStack((int)ip->TokenLong, esp, AppDomain, mStack);
            case OpCodeEnum.Callvirt:
                // m = "TestDelegateMethod Void Invoke(Int32)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                    // 主工程的委托Invoke 不是 ILMethod 而是 CLRMethod
                    if (m is not ILMethod)
                        // 轉型為 CLRMethod
                        CLRMethod cm = (CLRMethod)m;
                        if (m.IsDelegateInvoke)
                            // 從棧上獲取 HotFix_Project.TestDelegate.Method(Int32 a):IDelegateAdapter
                            var instance = StackObject.ToObject((Minus(esp, m.ParameterCount + 1)), domain, mStack);
                                if (instance is IDelegateAdapter)
                                    esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);
                                        var ebp = esp;
                                        esp = [DummyDelegateAdapter].ILInvokeSub(intp, esp, mStack);
                                            // 調用委托適配器指向的 方法
                                            // method = "HotFix_Project.TestDelegate.Method(Int32 a)"
                                            var ret = intp.Execute(method, esp, out unhandled);
                                        return ClearStack(intp, esp, ebp, mStack);    
熱更里的工程調用熱更里的委托實例(該委托類型在主工程項目里聲明, 該委托實例指向熱更里的函數, 不需要注冊適配器)2.0

 

using System;
using System.Collections.Generic;

namespace HotFix_Project
{

    public class TestDelegate
    {
        
        public static void Initialize2()
        {
            DelegateDemo.TestMethodDelegate = Method;
        }
        
        static void Method(int a)
        {
            UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
        }

主工程

public static TestDelegateMethod TestMethodDelegate;
        
OnHotFixLoaded()
    // 委托適配器注冊, 不注冊就會提示沒有找到委托適配器 Cannot find Delegate Adapter for:HotFix_Project.TestDelegate.Method(Int32 a)
    appdomain.DelegateManager.RegisterMethodDelegate<int>();
        DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
        node.Adapter = new MethodDelegateAdapter<T1>();
        node.ParameterTypes = new Type[] { typeof(T1) };
        methods.Add(node);
        RegisterDelegateConvertor<Action<T1>>(defaultConverter);
            // type = System.Action`1[System.Int32]
            var type = typeof(T);
            if (type.IsSubclassOf(typeof(Delegate)))
                // action = null
                clrDelegates[type] = action;
                
    // 委托轉換器注冊, 不注冊就會提示沒有找到委托轉換器 Cannot find convertor for global::TestDelegateMethod
    appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) => {
        // type = {TestDelegateMethod}
        var type = typeof(T);
        if (type.IsSubclassOf(typeof(Delegate)))
            // action = {System.Func`2[[System.Delegate],[System.Delegate]]}
            clrDelegates[type] = action;
    
        //轉換器的目的是把Action或者Func轉換成正確的類型,這里則是把Action<int>轉換成TestDelegateMethod
        return new TestDelegateMethod((a) => {
            //調用委托實例
            ((System.Action<int>)action)(a);
        });
    });    

    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
        // method = "HotFix_Project.TestDelegate.Initialize2()"
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldnull"
        // "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
        // "IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
        // "IL_000d: stsfld TestDelegateMethod DelegateDemo::TestMethodDelegate"
        // "IL_0012: ret"        
        esp = Execute(method, esp, out unhandledException);
            case OpCodeEnum.Newobj:
                // 獲取 TestDelegateMethod."Void .ctor(Object, IntPtr)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                // 主工程里的 委托構造函數 不是ILMethod, 而是 CLRMethod
                if (m is not ILMethod)
                    // 轉型為 CLRMethod
                    CLRMethod cm = (CLRMethod)m;
                    if (cm.DeclearingType.IsDelegate)
                        // 從棧上獲取 mi = "HotFix_Project.TestDelegate.Method(Int32 a)"
                        var mi = (IMethod)mStack[(esp - 1)->Value];
                        // 熱更工程里的 方法是 ILMethod
                        if (mi is ILMethod)
                            if (ins == null)
                                // 委托實際調用的方法 默認是沒有 DelegateAdapter的
                                if (((ILMethod)mi).DelegateAdapter == null)
                                    // 去 委托管理器 里查找 委托適配器
                                    ((ILMethod)mi).DelegateAdapter = domain.[DelegateManager].FindDelegateAdapter(null, (ILMethod)mi);
                                        // 返回類型是 void
                                        if (method.ReturnType == appdomain.VoidType)
                                            // 因為已經注冊過appdomain.DelegateManager.RegisterMethodDelegate<int>();
                                            // 所以現在 methods 有一個 {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
                                            foreach (var i in methods)
                                                // 匹配參數個數
                                                if (i.ParameterTypes.Length == method.ParameterCount)
                                                    // 匹配參數類型
                                                    if (i.ParameterTypes[j] != method.Parameters[j].TypeForCLR)
                                                    // 都匹配
                                                    if (match)
                                                        res = i.Adapter.Instantiate(appdomain, instance, method);
                                                            return new MethodDelegateAdapter<T1>(appdomain, instance, method);
                                                                action = InvokeILMethod;
                                                                    using (var c = appdomain.BeginInvoke(method))
                                                                    {
                                                                        var ctx = c;
                                                                        if (method.HasThis)
                                                                            ctx.PushObject(instance);
                                                                        PushParameter(ref ctx, pType, p1);
                                                                        ctx.Invoke();
                                                                    }                                                                
                                        // 上面沒有匹配, 則初始化一個 dummyAdapter
                                        res = dummyAdapter.Instantiate(appdomain, instance, method);
                                                return new DummyDelegateAdapter(appdomain, instance, method);
                            // 將 DummyDelegateAdapter 入棧, 這個 委托適配里 包含了 對應的方法
                            esp = PushObject(esp, mStack, dele); 
        case OpCodeEnum.Stsfld:
            // type = "DelegateDemo"
            type = AppDomain.GetType((int)(ip->TokenLong >> 32));
            // 主工程里的類型是CLRType
            if (type is not ILType)
                // 轉型
                CLRType t = type as CLRType;
                int idx = (int)ip->TokenLong;
                // 獲取這個委托字段 f = "TestDelegateMethod TestMethodDelegate"
                var f = t.GetField(idx);
                val = esp - 1;
                // 重新設置 TestMethodDelegate 指向 主工程的 委托適配器 而不是 熱更工程里的函數
                t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));                
                    CheckCLRTypes(obj)                    
                        // typeFlags = IsDelegate
                        else if ((typeFlags & TypeFlags.IsDelegate) != 0)
                            // 不是 Delegate
                            if (obj is Delegate)
                                return obj;
                            // 另一種類型運算, 也不是
                            if (pt == typeof(Delegate))
                                return ((IDelegateAdapter)obj).Delegate;
                            // 獲取 HotFix_Project.TestDelegate.Method(Int32 a)  的 真正的委托
                            return ((IDelegateAdapter)obj).GetConvertor(pt);
                                if (converters == null)
                                    converters = new Dictionary<System.Type, Delegate>(new ByReferenceKeyComparer<Type>());
                                Delegate res;
                                // 沒有注冊,所以沒有
                                if (converters.TryGetValue(type, out res))
                                    return res;
                                else
                                    // 將 HotFix_Project.TestDelegate.Method(Int32 a): MethodDelegateAdapter`1[System.Int32] 的 {TestDelegateMethod} 委托轉換為可識別的委托    
                                    res = appdomain.DelegateManager.ConvertToDelegate(type, this);
                                        // 如果是 DummyAdapter 直接報錯, 不是
                                        if(adapter is DummyDelegateAdapter)
                                            DelegateAdapter.ThrowAdapterNotFound(adapter.Method);
                                        // 注冊了 直接返回那個委托
                                        if (clrDelegates.TryGetValue(clrDelegateType, out func))
                                        // 沒有注冊 {TestDelegateMethod} 對應的 Func<Delegate, Delegate> 報錯
                                        else 
                                    converters[type] = res;
                                    return res;
            
                
                
                
                
    appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest2", null, null);
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldsfld TestDelegateMethod DelegateDemo::TestMethodDelegate"
        // "IL_0006: ldc.i4.s 123"
        // "IL_0008: callvirt System.Void TestDelegateMethod::Invoke(System.Int32)"
        // "IL_000d: nop"
        // "IL_000e: ret"
        esp = Execute(method, esp, out unhandledException);
            case OpCodeEnum.Ldsfld:
                // 獲取"DelegateDemo"
                type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                // 主工程的 是 CLRType
                if (type is not ILType)
                    CLRType t = type as CLRType;
                    int idx = (int)ip->TokenLong;                        
                    var f = t.GetField(idx);                        
                    obj = t.GetFieldValue(idx, null);                        
                    if (obj is CrossBindingAdaptorType)                        
                        obj = ((CrossBindingAdaptorType)obj).ILInstance;    
                    // 將委托壓棧
                    PushObject(esp, mStack, obj, f.FieldType == typeof(object));                            
                    
            case OpCodeEnum.Callvirt:
                // m = "TestDelegateMethod Void Invoke(Int32)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                    // 主工程的委托Invoke 不是 ILMethod 而是 CLRMethod
                    if (m is not ILMethod)
                        // 轉型為 CLRMethod
                        CLRMethod cm = (CLRMethod)m;
                        if (cm.IsDelegateInvoke)
                            // 從棧上獲取 instance: TestDelegateMethod
                            var instance = StackObject.ToObject((Minus(esp, m.ParameterCount + 1)), domain, mStack);
                            // 不是
                            if (instance is IDelegateAdapter)
                        
                        // cm: CLRMethod = "TestDelegateMethod Void Invoke(Int32)"
                        object result = cm.Invoke(this, esp, mStack);
                            // def: MethodInfo = "Void Invoke(Int32)"
                            res = def.Invoke(instance, param);
                                return new TestDelegateMethod((a) => {
                                    //調用委托實例
                                    ((System.Action<int>)action)(a);
                                        // {ILRuntime.Runtime.Intepreter.MethodDelegateAdapter`1[System.Int32]}
                                        InvokeILMethod(T1 p1)
                                });
熱更里的工程將熱更里的函數賦值給主工程里的委托實例(該委托類型在主工程項目里聲明,該委托實例指向熱更里的函數)2.0

 

 

  

 

Debug.Log("如果需要跨域調用委托(將熱更DLL里面的委托實例傳到Unity主工程用), 就需要注冊適配器,不然就會像下面這樣");
try {
    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
        [ILIntepreter].Run
            // "DelegateDemo"
            CLRType t = type as CLRType;
            // 1233051648
            int idx = (int)ip->TokenLong;
            // t.Fields
            // "[1233051648, TestDelegateMethod TestMethodDelegate]"
            // "[-628392448, TestDelegateFunction TestFunctionDelegate]"
            // "[1805130752, System.Action`1[System.String] TestActionDelegate]"
            var f = t.GetField(idx);
            val = esp - 1;        
            
            case OpCodeEnum.Newobj:
                // 注冊過委托
                if (match)
                {
                    // method: "HotFix_Project.TestDelegate.Method(Int32 a)"
                    // Adapter: MethodDelegateAdapter<T1>
                    res = i.Adapter.Instantiate(appdomain, instance, method);
                        MethodDelegateAdapter<T1>.Instantiate
                            return new MethodDelegateAdapter<T1>(appdomain, instance, method);
                                // action: {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
                                action = InvokeILMethod;
                                    using (var c = appdomain.BeginInvoke(method))
                                        if (m is ILMethod)
                                        {
                                            ILIntepreter inteptreter = RequestILIntepreter();
                                            return new InvocationContext(inteptreter, (ILMethod)m);
                                        }
                                        else
                                            throw new NotSupportedException("Cannot invoke CLRMethod");            
                                    {
                                        var ctx = c;
                                        if (method.HasThis)
                                            ctx.PushObject(instance);
                                        PushParameter(ref ctx, pType, p1);
                                        ctx.Invoke();
                                    }
                        
                    if (instance != null)
                        instance.SetDelegateAdapter(method, res);
                    return res;
                }                
            
                // 沒有注冊過委托
                if (((ILMethod)mi).DelegateAdapter == null)
                {
                    ((ILMethod)mi).DelegateAdapter = domain.DelegateManager.FindDelegateAdapter(null, (ILMethod)mi);
                    // 生成一個 dummyAdapter
                    res = dummyAdapter.Instantiate(appdomain, instance, method);
                }
                dele = ((ILMethod)mi).DelegateAdapter;                
            
            t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));
                CheckCLRTypes
                    CheckAndCloneValueType
                        StackObject.ToObject
                            case ObjectTypes.Object:
                                // HotFix_Project.TestDelegate.Method(Int32 a)
                                return mStack[esp->Value];
                        // HotFix_Project.TestDelegate.Method(Int32 a)
                        return obj;
                    Type.GetTypeFlags
                        // Default
                        var result = TypeFlags.Default;
                            // typeFlags: Dictionary<Type, TypeFlags>
                            // "[ILRuntime.CLR.Method.ILMethod, Default]"
                            // "[ILRuntime.Runtime.Intepreter.DummyDelegateAdapter, Default]"
                            if (!typeFlags.TryGetValue(pt, out result))
                                if (pt == typeof(Delegate) || pt.IsSubclassOf(typeof(Delegate)))
                                {
                                    
                                    result |= TypeFlags.IsDelegate;
                                }    
                                // typeFlags: Dictionary<Type, TypeFlags>
                                // "[ILRuntime.CLR.Method.ILMethod, Default]"
                                // "[ILRuntime.Runtime.Intepreter.DummyDelegateAdapter, Default]"
                                // "[TestDelegateMethod, IsDelegate]"
                                typeFlags[pt] = result;
                    // pt = {TestDelegateMethod}
                    var typeFlags = GetTypeFlags(pt);
                    else if ((typeFlags & TypeFlags.IsDelegate) != 0)
                        if (obj is Delegate)
                            return obj;
                        if (pt == typeof(Delegate))
                            return ((IDelegateAdapter)obj).Delegate;
                        return ((IDelegateAdapter)obj).GetConvertor(pt);
                            
                            if (converters == null)
                                converters = new Dictionary<System.Type, Delegate>(new ByReferenceKeyComparer<Type>());
                            Delegate res;
                            if (converters.TryGetValue(type, out res))
                                return res;
                            else
                            {
                                
                                res = appdomain.DelegateManager.ConvertToDelegate(type, this);
                                    [DelegateManager].ConvertToDelegate
                                    // 是 DummyDelegateAdapter 拋出異常
                                    if(adapter is DummyDelegateAdapter)
                                    {
                                        DelegateAdapter.ThrowAdapterNotFound(adapter.Method);
                                        return null;
                                    }    
                                    // 如果事先注冊過了
                                    // clrDelegates
                                    // "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
                                    // "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
                                    // "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
                                    // "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
                                    // "[TestDelegateMethod, System.Func`2[System.Delegate,System.Delegate]]"
                                    if (clrDelegates.TryGetValue(clrDelegateType, out func))
                                    {
                                        return func(adapter.Delegate);
                                    }                                    
                                converters[type] = res;
                                return res;
                            }                            
} catch (System.Exception ex) {
    Debug.LogError(ex.ToString());
}
//為了演示,清除適配器緩存,實際使用中不要這么做
ClearDelegateCache();
Debug.Log("這是因為iOS的IL2CPP模式下,不能動態生成類型,為了避免出現不可預知的問題,我們沒有通過反射的方式創建委托實例,因此需要手動進行一些注冊");
Debug.Log("首先需要注冊委托適配器,剛剛的報錯的錯誤提示中,有提示需要的注冊代碼");
//下面這些注冊代碼,正式使用的時候,應該寫在InitializeILRuntime中
//TestDelegateMethod, 這個委托類型為有個參數為int的方法,注冊僅需要注冊不同的參數搭配即可
appdomain.DelegateManager.RegisterMethodDelegate<int>();
    DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
    node.Adapter = new MethodDelegateAdapter<T1>();
        pType: static InvocationTypes = GetInvocationType<T1>();
    node.ParameterTypes = new Type[] { typeof(T1) };
    // {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
    methods.Add(node);
    RegisterDelegateConvertor<Action<T1>>(defaultConverter);
        // "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
        clrDelegates[type] = action;
//帶返回值的委托的話需要用RegisterFunctionDelegate,返回類型為最后一個
appdomain.DelegateManager.RegisterFunctionDelegate<int, string>();
    DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
    node.Adapter = new FunctionDelegateAdapter<T1, TResult>();
    node.ParameterTypes = new Type[] { typeof(T1), typeof(TResult) };
    // {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
    functions.Add(node);
    RegisterDelegateConvertor<Func<T1, TResult>>(defaultConverter);
        // "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"    
        clrDelegates[type] = action;
//Action<string> 的參數為一個string
appdomain.DelegateManager.RegisterMethodDelegate<string>();
    DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
    node.Adapter = new MethodDelegateAdapter<T1>();
    node.ParameterTypes = new Type[] { typeof(T1) };
    // {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
    // {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
    methods.Add(node);
    RegisterDelegateConvertor<Action<T1>>(defaultConverter);
        // "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
        clrDelegates[type] = action;

Debug.Log("注冊完畢后再次運行會發現這次會報另外的錯誤");
try {
    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
} catch (System.Exception ex) {
    Debug.LogError(ex.ToString());
}

Debug.Log("ILRuntime內部是用Action和Func這兩個系統內置的委托類型來創建實例的,所以其他的委托類型都需要寫轉換器");
Debug.Log("將Action或者Func轉換成目標委托類型");

appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) => {
        // "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
        // "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
        // "[TestDelegateMethod, System.Func`2[System.Delegate,System.Delegate]]"
        clrDelegates[type] = action;
    //轉換器的目的是把Action或者Func轉換成正確的類型,這里則是把Action<int>轉換成TestDelegateMethod
    return new TestDelegateMethod((a) => {
        //調用委托實例
        // {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
        // Method: Void InvokeILMethod(Int32)
        // Target: "HotFix_Project.TestDelegate.Method(Int32 a)"
        ((System.Action<int>)action)(a);
    });
});
////對於TestDelegateFunction同理,只是是將Func<int, string>轉換成TestDelegateFunction
//appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) => {
//    return new TestDelegateFunction((a) => {
//        return ((System.Func<int, string>)action)(a);
//    });
//});

////下面再舉一個這個Demo中沒有用到,但是UGUI經常遇到的一個委托,例如UnityAction<float>
//appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<float>>((action) => {
//    return new UnityEngine.Events.UnityAction<float>((a) => {
//        ((System.Action<float>)action)(a);
//    });
//});


Debug.Log("現在我們再來運行一次");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest2", null, null);
//debug.log("運行成功,我們可以看見,用action或者func當作委托類型的話,可以避免寫轉換器,所以項目中在不必要的情況下盡量只用action和func");
//debug.log("另外應該盡量減少不必要的跨域委托調用,如果委托只在熱更dll中用,是不需要進行任何注冊的");
//debug.log("---------");
//debug.log("我們再來在unity主工程中調用一下剛剛的委托試試");
//testmethoddelegate(789);
//var str = testfunctiondelegate(098);
//debug.log("!! onhotfixloaded str = " + str);
//testactiondelegate("hello from unity main project");
委托流程

 

熱更項目

namespace HotFix_Project {
    public class TestDelegate {
        static Action<string> delegateAction;
        
        public static void Initialize() {
            delegateAction = Action;
        }

        public static void RunTest() {
            delegateAction("rrr");
        }
    }
}


主項目

appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
    // 原始IL
    // "IL_0000: nop"
    // "IL_0001: ldnull"
    // "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Action(System.String)"
    // "IL_0008: newobj System.Void System.Action`1<System.String>::.ctor(System.Object,System.IntPtr)"
    // "IL_000d: stsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction"
    // "IL_0012: ret"
    // 自定義OpCode
    // Nop, 0, 0
    // Ldnull, 0, 0
    // Ldftn, 1, 0
    // Newobj, 2, 0
    // Stsfld, 0, 12884901888
    // Ret, 0, 0
    esp = Execute(method, esp, out unhandledException);
        case OpCodeEnum.Ldftn:
            // m = "HotFix_Project.TestDelegate.Action(String a)"
            IMethod m = domain.GetMethod(ip->TokenInteger);
            esp = PushObject(esp, mStack, m);
        case OpCodeEnum.Newobj:
            // "System.Action`1[System.String] Void .ctor(Object, IntPtr)"
            IMethod m = domain.GetMethod(ip->TokenInteger);
            if (m is CLRMethod)
                // Action<string> 當然是Delegate
                if (cm.DeclearingType.IsDelegate)
                    // 獲取托管堆上方法
                    // "HotFix_Project.TestDelegate.Action(String a)"
                    var mi = (IMethod)mStack[(esp - 1)->Value];
                    // 熱更里的類型的方法
                    if (mi is ILMethod)
                        // 調用 Action<string> 沒有注冊DelegateAdapter,所以為null
                        if (((ILMethod)mi).DelegateAdapter == null)
                            // 去委托管理器里面趙 委托適配器
                            ((ILMethod)mi).DelegateAdapter = domain.DelegateManager.FindDelegateAdapter(null, (ILMethod)mi);
                                // 沒有注冊所以直接實例化一個 DummyAdapter
                                res = dummyAdapter.Instantiate(appdomain, instance, method);
                                    return new DummyDelegateAdapter(appdomain, instance, method);
                                        this.appdomain = appdomain;
                                        this.instance = instance;
                                        // DummyAdapter.method = "HotFix_Project.TestDelegate.Action(String a)"
                                        this.method = method;
                                        // CLRInstance 就是 這個 DummyAdapter
                                        CLRInstance = this;
                        dele = ((ILMethod)mi).DelegateAdapter;
        case OpCodeEnum.Stsfld:
            // type = "HotFix_Project.TestDelegate"
            type = AppDomain.GetType((int)(ip->TokenLong >> 32));
            if (type is ILType)
                ILType t = type as ILType;                
                val = esp - 1;            
                // 將 HotFix_Project.TestDelegate.Action(String a): DummyDelegateAdapter 賦值給 靜態字段 delegateAction
                t.StaticInstance.AssignFromStack((int)ip->TokenLong, val, AppDomain, mStack);                
    
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);
    // 原始IL
    // "IL_0000: nop"
    // "IL_0001: ldsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction"
    // "IL_0006: ldstr \"rrr\""
    // "IL_000b: callvirt System.Void System.Action`1<System.String>::Invoke(!0)"
    // "IL_0010: nop"
    // "IL_0011: ret"
    // 自定義OpCode
    // Nop, 0, 0
    // Ldsfld, 0, 12884901888
    // Ldstr, 0, 386853784
    // Callvirt, 5, 0
    // Nop, 0, 0
    // Ret, 0, 0
    esp = Execute(method, esp, out unhandledException);
        case OpCodeEnum.Ldsfld:
            // type = "HotFix_Project.TestDelegate"
            type = AppDomain.GetType((int)(ip->TokenLong >> 32));
            if (type is ILType)
                ILType t = type as ILType;
                // 將 TestDelegate.delegateAction 對應的值 也就是 "HotFix_Project.TestDelegate.Action(String a)":DummyAdapter 入棧
                t.StaticInstance.PushToStack((int)ip->TokenLong, esp, AppDomain, mStack);
        case OpCodeEnum.Ldstr:
            // 將字符串 "rrr" 入棧
            esp = PushObject(esp, mStack, AppDomain.GetString(ip->TokenLong));
        case OpCodeEnum.Callvirt:
            // m = "System.Action`1[System.String] Void Invoke(System.String)"
            IMethod m = domain.GetMethod(ip->TokenInteger);
            if (m is CLRMethod)
                if (cm.IsDelegateInvoke)
                    // "HotFix_Project.TestDelegate.Action(String a)": DummyAdapter
                    var instance = StackObject.ToObject((Minus(esp, cm.ParameterCount + 1)), domain, mStack);                    
                    if (instance is IDelegateAdapter)    
                        // DummyAdapter.ILInvoke
                        esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);    
                            var ebp = esp;
                            esp = ILInvokeSub(intp, esp, mStack);
                                // 將參數入棧
                                for(int i = paramCnt; i > 0; i--)
                                    intp.CopyToStack(esp, Minus(ebp, i), mStack);
                                        *dst = *src;
                                        if (dst->ObjectType >= ObjectTypes.Object)
                                            dst->Value = mStack.Count;
                                            var obj = mStack[src->Value];
                                            mStack.Add(obj);    
                                // 原始IL
                                // "IL_0000: nop"
                                // "IL_0001: ldstr \"!! TestDelegate.Action, a = \""
                                // "IL_0006: ldarg.0"
                                // "IL_0007: call System.String System.String::Concat(System.String,System.String)"
                                // "IL_000c: call System.Void UnityEngine.Debug::Log(System.Object)"
                                // "IL_0011: nop"
                                // "IL_0012: ret"
                                // Nop, 0, 0
                                // Ldstr, 0, 1342813397
                                // Ldarg_0, 0, 0
                                // Call, 4, 0
                                // Call, 5, 0
                                // Nop, 0, 0
                                // Ret, 0, 0
                                var ret = intp.Execute(method, esp, out unhandled);
                                    case OpCodeEnum.Ldstr:
                                        // 將 "!! TestDelegate.Action, a = " 入棧
                                        esp = PushObject(esp, mStack, AppDomain.GetString(ip->TokenLong));
                                        // 將"rrr" 入棧
                                    case OpCodeEnum.Ldarg_0:
                                        CopyToStack(esp, arg, mStack);
                                    case OpCodeEnum.Call:
                                        // m = "System.String Concat(System.String, System.String)"
                                        IMethod m = domain.GetMethod(ip->TokenInteger);
                                        if (m is CLRMethod)
                                            // result = "!! TestDelegate.Action, a = rrr"
                                            object result = cm.Invoke(this, esp, mStack);
                                    case OpCodeEnum.Call:
                                        // m = "UnityEngine.Debug Void Log(System.Object)"
                                        IMethod m = domain.GetMethod(ip->TokenInteger);
                                        if (m is CLRMethod)
                                            // result = "!! TestDelegate.Action, a = rrr"
                                            object result = cm.Invoke(this, esp, mStack);
                                            if (m is CLRMethod)
                                                // 調用 UnityEngine.Debug.Log("!! TestDelegate.Action, a = rrr");
                                                object result = cm.Invoke(this, esp, mStack);
                            return ClearStack(intp, esp, ebp, mStack);
                        processed = true;            
熱更項目調用Action 委托

 

熱更工程


namespace HotFix_Project {

    public delegate void MyTestDelegate(string a);

    public class TestDelegate {
        static Action<string> delegateAction;

        public static void Initialize() {
            delegateAction = Action;
            delegateAction("hahaah");
        }
        
        static void Action(string a) {
            UnityEngine.Debug.Log(a);
        }
    }
}

主工程
    OnHotFixLoaded() {

        TypeDefinition td = appdomain.typeDef["HotFix_Project.TestDelegate"];


        MyType mt = new MyType(td);

        List<object> managedStack = new List<object>(5);

        for (int i = 0; i < 5; i++) {
            managedStack.Add(null);
        }

        System.Delegate dele = null;
        System.Type type = null;
        MyDelegateAdapter da = null;

        foreach (var item in td.Methods[0].Body.Instructions) {
            UnityEngine.Debug.Log(item);
            switch (item.OpCode.Code) {
                //  ldftn System.Void HotFix_Project.TestDelegate::Action(System.String)
                case Code.Ldftn:
                    MethodDefinition md = item.Operand as MethodDefinition;
                    managedStack[0] = md;
                    break;
                // newobj System.Void System.Action`1<System.String>::.ctor(System.Object,System.IntPtr
                case Code.Newobj:
                    MethodReference mr = item.Operand as MethodReference;
                    // System.Action`1<System.String> 替換成 System.Action`1[System.String]
                    type = System.Type.GetType(mr.DeclaringType.FullName.Replace('<', '[').Replace('>',

                    

                    da = new MyDelegateAdapter(managedStack[0] as MethodDefinition);
                    break;
                // stsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction
                case Code.Stsfld:
                    // 將 DelegateAdapter 設置給這個字段
                    mt.staticField = da;
                    managedStack.Remove(0);
                    break;
                // ldsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction
                case Code.Ldsfld:
                    MyDelegateAdapter da1 = (mt.staticField as MyDelegateAdapter);
                    managedStack[0] = da1;
                    break;
                // ldstr "hahaah"
                case Code.Ldstr:
                    managedStack[1] = "hahaah";
                    break;
                // callvirt System.Void System.Action`1<System.String>::Invoke(!0)
                case Code.Callvirt:
                    MyDelegateAdapter da2 = managedStack[0] as MyDelegateAdapter;
                    da2.Invoke();
                    break;
                default:
                    break;
            }
        }

    }

    public class MyType {
        public TypeDefinition td;

        public object staticField;

        public MyType(TypeDefinition td) {
            this.td = td;
        }
    }

    public class MyDelegateAdapter {
        public MethodDefinition md;

        public MyDelegateAdapter(MethodDefinition md) {
            this.md = md;
        }

        public void Invoke() {
            foreach (var item in md.Body.Instructions) {
                Debug.Log(item);
                switch (item.OpCode.Code) {
                    //  ldarg.0
                    case Code.Ldarg_0:
                        // managedStack[2] = "hahaah"
                        break;
                    // call System.Void UnityEngine.Debug::Log(System.Object)
                    case Code.Call:
                        // UnityEngine.Debug.Log(managedStack[2])
                        UnityEngine.Debug.Log("hahaah");
                        break;
                }
            }
        }
    }
委托調用流程自定義

 

System.Func<System.Delegate, System.Delegate> func = new System.Func<System.Delegate, System.Delegate>((dele) => {
    Debug.Log(dele.GetType());

    return dele;
});

System.Action ac = () => {
    Debug.Log("Action");
};

((System.Action)func(ac))();
System.Func<System.Delegate, System.Delegate>

 

 

 

 

主工程

// 主工程要被繼承的類
public abstract class TestClassBase
{
    public virtual int Value
    {
        get
        {
            return 0;
        }
    }

    public virtual void TestVirtual(string str)
    {
        Debug.Log("!! TestClassBase.TestVirtual, str = " + str);
    }

    public abstract void TestAbstract(int gg);
}

// 
public class InheritanceAdapter : CrossBindingAdaptor
{
    public override Type BaseCLRType
    {
        get
        {
            // 獲取 TestClassBase的 type
            return typeof(TestClassBase);//這是你想繼承的那個類
        }
    }

    public override Type AdaptorType
    {
        get
        {
            // 獲取 InheritanceAdapter.Adaptor 嵌套類 的 type
            return typeof(Adaptor);//這是實際的適配器類
        }
    }

    // new 一個 InheritanceAdapter.Adaptor
    public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
    {
        return new Adaptor(appdomain, instance);//創建一個新的實例
    }

    //實際的適配器類需要繼承你想繼承的那個類,並且實現CrossBindingAdaptorType接口
    class Adaptor : TestClassBase, CrossBindingAdaptorType
    {
        ILTypeInstance instance;
        ILRuntime.Runtime.Enviorment.AppDomain appdomain;
        
        // 對應 TestClassBase.TestAbstract
        IMethod mTestAbstract;
        bool mTestAbstractGot;
        
        // 對應 TestClassBase.TestVirtual
        IMethod mTestVirtual;
        bool mTestVirtualGot;
        bool isTestVirtualInvoking = false;
        
        // 對應 TestClassBase.Value
        IMethod mGetValue;
        bool mGetValueGot;
        bool isGetValueInvoking = false;
        
        //緩存這個數組來避免調用時的GC Alloc
        object[] param1 = new object[1];

        public Adaptor()
        {

        }

        public Adaptor(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
        {
            this.appdomain = appdomain;
            this.instance = instance;
        }

        public ILTypeInstance ILInstance { get { return instance; } }

        //你需要重寫所有你希望在熱更腳本里面重寫的方法,並且將控制權轉到腳本里去
        public override void TestAbstract(int ab)
        {
            if (!mTestAbstractGot)
            {
                mTestAbstract = instance.Type.GetMethod("TestAbstract", 1);
                mTestAbstractGot = true;
            }
            if (mTestAbstract != null)
            {
                param1[0] = ab;
                appdomain.Invoke(mTestAbstract, instance, param1);//沒有參數建議顯式傳遞null為參數列表,否則會自動new object[0]導致GC Alloc
            }
        }

        public override void TestVirtual(string str)
        {
            if (!mTestVirtualGot)
            {
                mTestVirtual = instance.Type.GetMethod("TestVirtual", 1);
                mTestVirtualGot = true;
            }
            //對於虛函數而言,必須設定一個標識位來確定是否當前已經在調用中,否則如果腳本類中調用base.TestVirtual()就會造成無限循環,最終導致爆棧
            if (mTestVirtual != null && !isTestVirtualInvoking)
            {
                isTestVirtualInvoking = true;
                param1[0] = str;
                appdomain.Invoke(mTestVirtual, instance, param1);
                isTestVirtualInvoking = false;
            }
            else
                base.TestVirtual(str);
        }

        public override int Value
        {
            get
            {
                if (!mGetValueGot)
                {
                    //屬性的Getter編譯后會以get_XXX存在,如果不確定的話可以打開Reflector等反編譯軟件看一下函數名稱
                    mGetValue = instance.Type.GetMethod("get_Value", 1);
                    mGetValueGot = true;
                }
                //對於虛函數而言,必須設定一個標識位來確定是否當前已經在調用中,否則如果腳本類中調用base.Value就會造成無限循環,最終導致爆棧
                if (mGetValue != null && !isGetValueInvoking)
                {
                    isGetValueInvoking = true;
                    var res = (int)appdomain.Invoke(mGetValue, instance, null);
                    isGetValueInvoking = false;
                    return res;
                }
                else
                    return base.Value;
            }
        }

        public override string ToString()
        {
            IMethod m = appdomain.ObjectType.GetMethod("ToString", 0);
            m = instance.Type.GetVirtualMethod(m);
            if (m == null || m is ILMethod)
            {
                return instance.ToString();
            }
            else
                return instance.Type.FullName;
        }
    }
}


Debug.Log("首先我們來創建熱更里的類實例");
TestClassBase obj;
try
{
    obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
        // type: "HotFix_Project.TestInheritance"
        ILTypeInstance ins = Instantiate(type, args);
            // 
            var res = ilType.Instantiate(!hasConstructor);
                var res = new ILTypeInstance(this);
                    fields = new StackObject[type.TotalFieldCount];
                        ILType.InitializeBaseType
                            // definition.BaseType = "TestClassBase"
                            baseType = appdomain.GetType(definition.BaseType, this, null);
                            // 不是
                            if (baseType.TypeForCLR == typeof(Enum) || baseType.TypeForCLR == typeof(object) || baseType.TypeForCLR == typeof(ValueType) || baseType.TypeForCLR == typeof(System.Enum))
                            // 不是
                            else if (baseType.TypeForCLR == typeof(MulticastDelegate))
                            // 找 CrossBindingAdaptor
                            CrossBindingAdaptor adaptor;
                            if (appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR, out adaptor))
                            {
                                baseType = adaptor;
                            }
                            // 沒注冊就找不到
                            else
                                throw new TypeLoadException("Cannot find Adaptor for:" + baseType.TypeForCLR.ToString());                            
        return (T)ins.CLRInstance;    
}
catch(System.Exception ex)
{
    Debug.LogError(ex.ToString());
}
Debug.Log("Oops, 報錯了,因為跨域繼承必須要注冊適配器。 如果是熱更DLL里面繼承熱更里面的類型,不需要任何注冊。");

Debug.Log("所以現在我們來注冊適配器");
appdomain.RegisterCrossBindingAdaptor(new InheritanceAdapter());
    var bType = adaptor.BaseCLRType;
        // 自己寫的
        return typeof(TestClassBase)
    var t = adaptor.AdaptorType;
        // 自己寫的 {InheritanceAdapter+Adaptor}
        return typeof(Adaptor)
    var res = GetType(t);
        IType res;
        // 沒有 {InheritanceAdapter+Adaptor} 這個類型
        if (clrTypeMapping.TryGetValue(t, out res))
            return res;
        else
            // "InheritanceAdapter+Adaptor, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
            return GetType(t.AssemblyQualifiedName);    
                // 沒有這個類型
                if (!clrTypeMapping.TryGetValue(t, out res))
                    // new 一個 CLRType
                    res = new CLRType(t, this);
                    clrTypeMapping[t] = res;
            // {InheritanceAdapter}.RuntimeType = "InheritanceAdapter+Adaptor" 嵌套類
            adaptor.RuntimeType = res;
            // "[TestClassBase, InheritanceAdapter]"
            crossAdaptors[bType] = adaptor;
Debug.Log("現在再來嘗試創建一個實例");
obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
    // type: "HotFix_Project.TestInheritance"
    ILTypeInstance ins = Instantiate(type, args);
        // 根據 "HotFix_Project.TestInheritance" 查找 HotFix_Project.TestInheritance: IType
        if (mapType.TryGetValue(type, out t))
            // HotFix_Project.TestInheritance: ILType
            var res = ilType.Instantiate(!hasConstructor);
                var res = new ILTypeInstance(this);
                    fields = new StackObject[type.TotalFieldCount];        
                        InitializeBaseType
                            // definition.BaseType = HotFix_Project.TestInheritance."TestClassBase" Module null
                            baseType = appdomain.GetType(definition.BaseType, this, null);
                                // hash = 1, 沒找到
                                if (mapTypeToken.TryGetValue(hash, out res))
                                // token = TestClassBase, 不是 TypeDefinition
                                if (token is Mono.Cecil.TypeDefinition)
                                // token 是 TypeReference
                                // Module "HotFix_Project.dll"
                                // Scope "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
                                else if (token is Mono.Cecil.TypeReference)
                                // 獲取 scope
                                scope = GetAssemblyName(_ref.Scope);
                                    // 獲取引用程序集
                                    return scope is AssemblyNameReference ? ((AssemblyNameReference)scope).FullName : null;
                                // 通過 Type.GetType 獲取 類型
                                Type t = Type.GetType(fullname);
                                    // clrTypeMapping 沒有找到 TestClassBase 
                                    if (!clrTypeMapping.TryGetValue(t, out res))
                                        // new 一個 CLRType
                                        res = new CLRType(t, this);
                            // 是 CLRType
                            if (baseType is CLRType)
                                // 不是
                                if (baseType.TypeForCLR == typeof(Enum) || baseType.TypeForCLR == typeof(object) || baseType.TypeForCLR == typeof(ValueType) || baseType.TypeForCLR == typeof(System.Enum))
                                // 不是
                                else if (baseType.TypeForCLR == typeof(MulticastDelegate))
                                else 
                                    // 以上都不是,根據 TestClassBase: Type 查找 adapter
                                    if (appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR, out adaptor))
                                        // 現在 baseType 是 {InheritanceAdapter}
                                        baseType = adaptor;
                                            var curBase = baseType;
                                
                                var curBase = baseType;
                                // 不是 ILType
                                while (curBase is ILType)
                                {
                                    curBase = curBase.BaseType;
                                }
                    // type.FirstCLRBaseType = HotFix_Project.TestInheritance.InheritanceAdapter 是 CrossBindingAdaptor
                    if (type.FirstCLRBaseType is Enviorment.CrossBindingAdaptor)
                        // {InheritanceAdapter}.CreateCLRInstance
                        clrInstance = ((Enviorment.CrossBindingAdaptor)type.FirstCLRBaseType).CreateCLRInstance(type.AppDomain, this);
                            // new InheritanceAdapter+Adaptor
                            return new Adaptor(appdomain, instance);//創建一個新的實例
                // 獲取 HotFix_Project.TestInheritance 的構造函數
                var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
                    // m: HotFix_Project.TestInheritance..ctor()
                    appdomain.Invoke(m, res, null);
                        res = inteptreter.Run((ILMethod)m, instance, p);
                            // Ldarg_0, 0, 0
                            // Call, 536870913, 0
                            // Nop, 0, 0
                            // Ret, 0, 0
                            esp = Execute(method, esp, out unhandledException);
                                case OpCodeEnum.Ldarg_0:
                                    // 將 HotFix_Project.TestInheritance 壓棧
                                    CopyToStack(esp, arg, mStack);    
                                case OpCodeEnum.Call:
                                    // 通過 StackObject.TokenInteger 獲取 HotFix_Project.TestInheritance.ctor()
                                    IMethod m = domain.GetMethod(ip->TokenInteger);
                                    // 轉換成 CLRMethod
                                    CLRMethod cm = (CLRMethod)m;
                                        cm.Invoke
    return (T)ins.CLRInstance;
Debug.Log("現在來調用成員方法");
obj.TestAbstract(123);
    if (!mTestAbstractGot)
    {
        // instance: "HotFix_Project.TestInheritance"
        // 獲取實際執行的熱更里面的代碼
        mTestAbstract = instance.Type.GetMethod("TestAbstract", 1);
        // 獲取到了 這個方法
        mTestAbstractGot = true;
    }
    if (mTestAbstract != null)
    {
        param1[0] = ab;
        // 調用熱更里的方法
        // mTestAbstract: HotFix_Project.TestInheritance.TestAbstract(Int32 gg)
        // instance: "HotFix_Project.TestInheritance"
        // param1: ab = 123
        appdomain.Invoke(mTestAbstract, instance, param1);//沒有參數建議顯式傳遞null為參數列表,否則會自動new object[0]導致GC Alloc
    }    
obj.TestVirtual("Hello");

Debug.Log("現在換個方式創建實例");
obj = appdomain.Invoke("HotFix_Project.TestInheritance", "NewObject", null, null) as TestClassBase;
obj.TestAbstract(456);
obj.TestVirtual("Foobar");    


熱更工程

namespace HotFix_Project {
    //一定要特別注意,:后面只允許有1個Unity主工程的類或者接口,但是可以有隨便多少個熱更DLL中的接口
    public class TestInheritance : TestClassBase {
        public override void TestAbstract(int gg) {
            UnityEngine.Debug.Log("!! TestInheritance.TestAbstract gg =" + gg);
        }

        public override void TestVirtual(string str) {
            base.TestVirtual(str);
            UnityEngine.Debug.Log("!! TestInheritance.TestVirtual str =" + str);
        }

        public static TestInheritance NewObject() {
            return new HotFix_Project.TestInheritance();
        }
    }
}
Inheritance
熱更項目

using System;
using System.Collections.Generic;

namespace HotFix_Project {
    //一定要特別注意,:后面只允許有1個Unity主工程的類或者接口,但是可以有隨便多少個熱更DLL中的接口
    public class TestInheritance : TestClassBase {
        public override void TestAbstract(int gg) {
            UnityEngine.Debug.Log("!! TestInheritance.TestAbstract gg =" + gg);
        }

        public override void TestVirtual(string str) {
            base.TestVirtual(str);
            UnityEngine.Debug.Log("!! TestInheritance.TestVirtual str =" + str);
        }

        public static TestInheritance NewObject() {
            return new HotFix_Project.TestInheritance();
        }
    }
}

主項目

熱更項目里的 TestInheritance 構造函數 IL 指令
System.Void HotFix_Project.TestInheritance::.ctor()
    IL_0000: ldarg.0
    // 這里並不能調用到
    IL_0001: call System.Void TestClassBase::.ctor()
    IL_0006: nop
    IL_0007: ret

                    
Debug.Log("首先我們來創建熱更里的類實例");
TestClassBase obj;
try
{
    obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
        // type = "HotFix_Project.TestInheritance"
        ILTypeInstance ins = Instantiate(type, args);
            // 有找到
            if (mapType.TryGetValue(type, out t))
                var res = ilType.Instantiate(!hasConstructor);
                    // new 一個ILTypeInstance
                    var res = new ILTypeInstance(this);
                        this.type = type;
                        fields = new StackObject[type.TotalFieldCount];    
                            get
                                if (totalFieldCnt < 0)
                                    if (fieldMapping == null)
                                        // 初始化字段
                                        InitializeFields();
                                            int idx = FieldStartIndex;
                                                get
                                                    if (fieldStartIdx < 0)
                                                         // 獲取 HotFix_Project.TestInheritance的BaseType
                                                         if (BaseType != null)
                                                            // baseType 沒有初始化
                                                            if (!baseTypeInitialized)
                                                                // 初始化 BaseType
                                                                InitializeBaseType();
                                                                    // 不為空
                                                                    if (definition != null && definition.BaseType != null)
                                                                        // 獲取 baseType
                                                                        baseType = appdomain.GetType(definition.BaseType, this, null);
                                                                            // TestClassBase 是 TypeReference
                                                                            // Module = "HotFix_Project.dll"
                                                                            // Scope = "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
                                                                            else if (token is Mono.Cecil.TypeReference)
                                                                            // typename = "TestClassBase"
                                                                            res = GetType(typename);
                                                                                // TestClassBase 是主工程的類型,所以可以使用 System.Type.GetType
                                                                                Type t = Type.GetType(fullname);
                                                                                // 查找 CLRTypeMapping
                                                                                if (!clrTypeMapping.TryGetValue(t, out res))
                                                                                    // 根據 System.Type 構造一個 CLRType
                                                                                    res = new CLRType(t, this);
                                                                                    clrTypeMapping[t] = res;                                                                        
                                                                        
                                                                        
                                                                            // TestClassBase 是 CLRType
                                                                            if (baseType is CLRType) {
                                                                                // 不是基本類型, 也不是 委托, 查找 適配器
                                                                                // 沒有注冊適配器, 報錯
                                                                                CrossBindingAdaptor adaptor;
                                                                                if (appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR, out adaptor))
                                                                                {
                                                                                    baseType = adaptor;
                                                                                }
                                                                                else
                                                                                    throw new TypeLoadException("Cannot find Adaptor for:" + baseType.TypeForCLR.ToString());                                                                            
                                                                            }
        return (T)ins.CLRInstance;
}
catch(System.Exception ex)
{
    Debug.LogError(ex.ToString());
}
Debug.Log("Oops, 報錯了,因為跨域繼承必須要注冊適配器。 如果是熱更DLL里面繼承熱更里面的類型,不需要任何注冊。");

Debug.Log("所以現在我們來注冊適配器");
appdomain.RegisterCrossBindingAdaptor(new InheritanceAdapter());
    new InheritanceAdapter()
        public class InheritanceAdapter : CrossBindingAdaptor
        {
            public override Type BaseCLRType
            {
                get
                {
                    // 手動設置 HotFix_Project.TestInheritance 基類類型為 TestClassBase
                    return typeof(TestClassBase);//這是你想繼承的那個類
                }
            }

            public override Type AdaptorType
            {
                get
                {
                    // 手動設置  HotFix_Project.TestInheritance 相關的 適配器類型為 InheritanceAdapter.Adaptor
                    return typeof(Adaptor);//這是實際的適配器類
                }
            }

            public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
            {
                // 類型為 InheritanceAdapter.Adaptor
                return new Adaptor(appdomain, instance);//創建一個新的實例
            }

            //實際的適配器類需要繼承你想繼承的那個類,並且實現CrossBindingAdaptorType接口
            class Adaptor : TestClassBase, CrossBindingAdaptorType
            {
                // 根據 HotFix_Project.TestInheritance 生成的 ILTypeInstance
                ILTypeInstance instance;
                ILRuntime.Runtime.Enviorment.AppDomain appdomain;
                
                // 對應 TestClassBase.TestAbstract
                IMethod mTestAbstract;
                bool mTestAbstractGot;
                
                // 對應 TestClassBase.TestVirtual
                IMethod mTestVirtual;
                bool mTestVirtualGot;
                bool isTestVirtualInvoking = false;
                
                // 對應 TestClassBase.Value
                IMethod mGetValue;
                bool mGetValueGot;
                bool isGetValueInvoking = false;
                
                
                //緩存這個數組來避免調用時的GC Alloc
                object[] param1 = new object[1];

                public Adaptor()
                {

                }

                public Adaptor(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
                {
                    this.appdomain = appdomain;
                    this.instance = instance;
                }

                public ILTypeInstance ILInstance { get { return instance; } }

                //你需要重寫所有你希望在熱更腳本里面重寫的方法,並且將控制權轉到腳本里去
                public override void TestAbstract(int ab)
                {
                    if (!mTestAbstractGot)
                    {
                        
                        mTestAbstract = instance.Type.GetMethod("TestAbstract", 1);
                        mTestAbstractGot = true;
                    }
                    if (mTestAbstract != null)
                    {
                        param1[0] = ab;
                        appdomain.Invoke(mTestAbstract, instance, param1);//沒有參數建議顯式傳遞null為參數列表,否則會自動new object[0]導致GC Alloc
                    }
                }

                public override void TestVirtual(string str)
                {
                    if (!mTestVirtualGot)
                    {
                        mTestVirtual = instance.Type.GetMethod("TestVirtual", 1);
                        mTestVirtualGot = true;
                    }
                    //對於虛函數而言,必須設定一個標識位來確定是否當前已經在調用中,否則如果腳本類中調用base.TestVirtual()就會造成無限循環,最終導致爆棧
                    if (mTestVirtual != null && !isTestVirtualInvoking)
                    {
                        isTestVirtualInvoking = true;
                        param1[0] = str;
                        appdomain.Invoke(mTestVirtual, instance, param1);
                        isTestVirtualInvoking = false;
                    }
                    else
                        base.TestVirtual(str);
                }

                public override int Value
                {
                    get
                    {
                        if (!mGetValueGot)
                        {
                            //屬性的Getter編譯后會以get_XXX存在,如果不確定的話可以打開Reflector等反編譯軟件看一下函數名稱
                            mGetValue = instance.Type.GetMethod("get_Value", 1);
                            mGetValueGot = true;
                        }
                        //對於虛函數而言,必須設定一個標識位來確定是否當前已經在調用中,否則如果腳本類中調用base.Value就會造成無限循環,最終導致爆棧
                        if (mGetValue != null && !isGetValueInvoking)
                        {
                            isGetValueInvoking = true;
                            var res = (int)appdomain.Invoke(mGetValue, instance, null);
                            isGetValueInvoking = false;
                            return res;
                        }
                        else
                            return base.Value;
                    }
                }

                public override string ToString()
                {
                    IMethod m = appdomain.ObjectType.GetMethod("ToString", 0);
                    m = instance.Type.GetVirtualMethod(m);
                    if (m == null || m is ILMethod)
                    {
                        return instance.ToString();
                    }
                    else
                        return instance.Type.FullName;
                }
            }
        }
    
    RegisterCrossBindingAdaptor()
        // 自己寫的 typeof(TestClassBase)
        var bType = adaptor.BaseCLRType;
        if (bType != null)
        {
            // 目前沒有
            if (!crossAdaptors.ContainsKey(bType))
            {
                // 自己寫的 typeof(Adaptor) = InheritanceAdapter+Adaptor
                var t = adaptor.AdaptorType;
                var res = GetType(t);
                    IType res;
                    // 目前沒有
                    if (clrTypeMapping.TryGetValue(t, out res))
                        return res;
                    else
                        // "InheritanceAdapter+Adaptor, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
                        return GetType(t.AssemblyQualifiedName);
                            // 目前沒有
                            if (mapType.TryGetValue(fullname, out res))
                                return res;        
                            // 通過 System.Type.GetType 獲取類型
                            Type t = Type.GetType(fullname);
                            // 目前沒有
                            if (!clrTypeMapping.TryGetValue(t, out res))
                            {
                                // 通過 InheritanceAdapter+Adaptor 實例化 CLRType
                                res = new CLRType(t, this);
                                clrTypeMapping[t] = res;
                            }    
                            // 各種存
                            mapType[fullname] = res;
                            mapType[res.FullName] = res;
                            mapType[t.AssemblyQualifiedName] = res;
                            mapTypeToken[res.GetHashCode()] = res;                        
            
                if (res == null)
                {
                    res = new CLRType(t, this);
                    mapType[res.FullName] = res;
                    mapType[t.AssemblyQualifiedName] = res;
                    clrTypeMapping[t] = res;
                }
                // InheritanceAdapter 的 運行時 類型 為 InheritanceAdapter+Adaptor: CLRType
                adaptor.RuntimeType = res;
                // TestClassBase 的 適配器類型為 InheritanceAdapter
                crossAdaptors[bType] = adaptor;
            }
            else
                throw new Exception("Crossbinding Adapter for " + bType.FullName + " is already added.");
        }
        else
        {
            var bTypes = adaptor.BaseCLRTypes;
            var t = adaptor.AdaptorType;
            var res = GetType(t);
            if (res == null)
            {
                res = new CLRType(t, this);
                mapType[res.FullName] = res;
                mapType[t.AssemblyQualifiedName] = res;
                clrTypeMapping[t] = res;
            }
            adaptor.RuntimeType = res;

            foreach (var i in bTypes)
            {
                if (!crossAdaptors.ContainsKey(i))
                {
                    crossAdaptors[i] = adaptor;
                }
                else
                    throw new Exception("Crossbinding Adapter for " + i.FullName + " is already added.");
            }
        }            
    
    
    
Debug.Log("現在再來嘗試創建一個實例");
obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
    // 通過 "HotFix_Project.TestInheritance" 實例化一個 ILTypeInstance
    ILTypeInstance ins = Instantiate(type, args);
        var res = ilType.Instantiate(!hasConstructor);
            var res = new ILTypeInstance(this);
                [ILType].TotalFieldCount
                    [ILType].InitializeFields
                        [ILType].FieldStartIndex
                            [ILType].BaseType
                                [ILType].InitializeBaseType
                                    // definition: MethodDefinition = "HotFix_Project.TestInheritance"
                                    // definition.BaseType = "TestClassBase"
                                    // 通過 TestClassBase: TypeReference 的hashcode 在 mapTypeToken 里 查找到 InheritanceAdapter
                                    baseType = appdomain.GetType(definition.BaseType, this, null);
                                    // InheritanceAdapter 是 CLRType
                                    if (baseType is CLRType)
                                        // baseType.TypeForCLR = {InheritanceAdapter+Adaptor}
                                        // 不是下列類型
                                        if (baseType.TypeForCLR == typeof(Enum) || baseType.TypeForCLR == typeof(object) || baseType.TypeForCLR == typeof(ValueType) || baseType.TypeForCLR == typeof(System.Enum))
                                        // 不是 MulticastDelegate
                                        else if (baseType.TypeForCLR == typeof(MulticastDelegate))
                                        // 查找 CrossBindingAdaptor
                                        else 
                                            // adaptor = {InheritanceAdapter}
                                             baseType = adaptor
                 // type.FirstCLRBaseType = {InheritanceAdapter} 
                if (type.FirstCLRBaseType is Enviorment.CrossBindingAdaptor) 
                    // type = "HotFix_Project.TestInheritance"
                    // type.FirstCLRBaseType = {InheritanceAdapter}
                    // clrInstance 就是 {InheritanceAdapter+Adaptor}
                    clrInstance = ((Enviorment.CrossBindingAdaptor)type.FirstCLRBaseType).CreateCLRInstance(type.AppDomain, this);
                        return new Adaptor(appdomain, instance);//創建一個新的實例
        // m = "HotFix_Project.TestInheritance..ctor()"
        var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
            res = inteptreter.Run((ILMethod)m, instance, p);
                if (method.HasThis)
                    // 入棧 {ILRuntime.Runtime.Intepreter.ILTypeInstance}
                    esp = PushObject(esp, mStack, instance);
                    // 參數方法 入棧
                    esp = PushParameters(method, esp, p);
                    // 執行方法 "HotFix_Project.TestInheritance..ctor()"
                    esp = Execute(method, esp, out unhandledException);
                        // body
                        // Ldarg_0, 0, 0
                        // Call 536870913,0
                        // Nop, 0, 0
                        // Ret, 0, 0
                        OpCode[] body = method.Body;
                            // 初始化 method.Body
                            InitCodeBody();
                                // 局部變量數量
                                localVarCnt = def.Body.Variables.Count;
                                body = new OpCode[def.Body.Instructions.Count];
                                Dictionary<Mono.Cecil.Cil.Instruction, int> addr = new Dictionary<Mono.Cecil.Cil.Instruction, int>();
                                for (int i = 0; i < body.Length; i++)
                                {
                                    var c = def.Body.Instructions[i];
                                    OpCode code = new OpCode();
                                    code.Code = (OpCodeEnum)c.OpCode.Code;
                                    // "[IL_0000: ldarg.0, 0]"
                                    // "[IL_0001: call System.Void TestClassBase::.ctor(), 1]"
                                    // "[IL_0006: nop, 2]"
                                    // "[IL_0007: ret, 3]"
                                    addr[c] = i;
                                    // Ldarg_0, 0, 0
                                    // Call, 0, 0
                                    // Nop, 0, 0
                                    // Ret, 0, 0
                                    body[i] = code;
                                }
                                for (int i = 0; i < body.Length; i++)
                                {
                                    var c = def.Body.Instructions[i];
                                    // 將IL 指令 轉換為 ILRuntime 指令
                                    // body[1] = "IL_0001: call System.Void TestClassBase::.ctor()"
                                    // c.Operand = "System.Void TestClassBase::.ctor()"
                                    InitToken(ref body[i], c.Operand, addr);
                                        case OpCodeEnum.Call:
                                        case OpCodeEnum.Newobj:
                                        case OpCodeEnum.Ldftn:
                                        case OpCodeEnum.Ldvirtftn
                                        case OpCodeEnum.Callvirt:
                                            bool invalidToken;
                                            // token = "System.Void TestClassBase::.ctor()"
                                            // declaringType = "HotFix_Project.TestInheritance"
                                            // this = "HotFix_Project.TestInheritance::.ctor()"
                                            var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
                                                // 目前沒有
                                                if (mapMethod.TryGetValue(hashCode, out method))
                                                // 是 MethodReference
                                                if (token is Mono.Cecil.MethodReference)
                                                    // ".ctor"
                                                    methodname = _ref.Name;
                                                    // typeDef: MethodReference = "TestClassBase"
                                                    var typeDef = _ref.DeclaringType;
                                                    // type = "TestClassBase"
                                                    type = GetType(typeDef, contextType, contextMethod);    
                                                    
                                                    if (isConstructor)
                                                        // type = TestClassBase
                                                        // 獲取 TestClassBase 的構造函數
                                                        method = type.GetConstructor(paramList);
                                                            // 初始化 TestClassBase 的方法
                                                            InitializeMethods();
                                                            
                                                    // TestClassBase 沒有構造函數
                                                    if (method == null)
                                                        // contextType = "HotFix_Project.TestInheritance"
                                                        // contextType.BaseType = {InheritanceAdapter}
                                                        method = contextType.BaseType.GetConstructor(paramList);
                                                            // 初始化 InheritanceAdapter 的方法
                                                            InitializeMethods
                                                                // 獲取 "InheritanceAdapter+Adaptor" 的 構造函數
                                                                foreach (var i in clrType.GetConstructors())
                                                                {
                                                                    // this = "InheritanceAdapter+Adaptor"
                                                                    constructors.Add(new CLRMethod(i, this, appdomain));
                                                                }
                                                        // 536870913 = "InheritanceAdapter+Adaptor".ctor
                                                        mapMethod[method.GetHashCode()] = method;
                                                        
                                            if (m != null)
                                            {
                                                if (invalidToken)
                                                    // m.GetHashCode() = 536870913
                                                    code.TokenInteger = m.GetHashCode();
                                                else
                                                    code.TokenInteger = token.GetHashCode();
                                            }
                                            else
                                            {
                                                //Cannot find method or the method is dummy
                                                MethodReference _ref = (MethodReference)token;
                                                int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
                                                if (_ref.HasThis)
                                                    paramCnt++;
                                                code.TokenLong = paramCnt;
                                            }                                            
                                        
                                    
                                    if (i > 0 && c.OpCode.Code == Mono.Cecil.Cil.Code.Callvirt && def.Body.Instructions[i - 1].OpCode.Code == Mono.Cecil.Cil.Code.Constrained)
                                    {
                                        body[i - 1].TokenLong = body[i].TokenInteger;
                                    }
                                }

                                for (int i = 0; i < def.Body.ExceptionHandlers.Count; i++)
                                {
                                    var eh = def.Body.ExceptionHandlers[i];
                                    if (exceptionHandler == null)
                                        exceptionHandler = new Method.ExceptionHandler[def.Body.ExceptionHandlers.Count];
                                    ExceptionHandler e = new ExceptionHandler();
                                    e.HandlerStart = addr[eh.HandlerStart];
                                    e.HandlerEnd = addr[eh.HandlerEnd] - 1;
                                    e.TryStart = addr[eh.TryStart];
                                    e.TryEnd = addr[eh.TryEnd] - 1;
                                    switch (eh.HandlerType)
                                    {
                                        case Mono.Cecil.Cil.ExceptionHandlerType.Catch:
                                            e.CatchType = appdomain.GetType(eh.CatchType, declaringType, this);
                                            e.HandlerType = ExceptionHandlerType.Catch;
                                            break;
                                        case Mono.Cecil.Cil.ExceptionHandlerType.Finally:
                                            e.HandlerType = ExceptionHandlerType.Finally;
                                            break;
                                        case Mono.Cecil.Cil.ExceptionHandlerType.Fault:
                                            e.HandlerType = ExceptionHandlerType.Fault;
                                            break;
                                        default:
                                            throw new NotImplementedException();
                                    }
                                    exceptionHandler[i] = e;
                                    //Mono.Cecil.Cil.ExceptionHandlerType.
                                }
                                //Release Method body to save memory
                                variables = def.Body.Variables;
                                def.Body = null;
                            }
                            else
                                body = new OpCode[0];                            
                                case OpCodeEnum.Callvirt:
                                    // TokenInteger = 536870913
                                    // 通過 536870913 獲取 方法
                                    // m = "InheritanceAdapter+Adaptor" "Void .ctor()"
                                    IMethod m = domain.GetMethod(ip->TokenInteger);
                                        if (mapMethod.TryGetValue(tokenHash, out res))
                                    // 不是ILMethod
                                    if (m is ILMethod)
                                    // 當然是 CLRMethod
                                    else
                                        CLRMethod cm = (CLRMethod)m;
                                        // 調用 InheritanceAdapter+Adaptor 的構造函數
                                        object result = cm.Invoke(this, esp, mStack);
                                            // 是構造函數
                                            if (isConstructor)
                                                // cDef: ConstructorInfo 不是靜態
                                                if (!cDef.IsStatic)
                                                    // declaringType: CLRType = "InheritanceAdapter+Adaptor"
                                                    // declaringType.TypeForCLR: Type = {InheritanceAdapter+Adaptor}
                                                    object instance = declaringType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((Minus(esp, paramCount + 1)), appdomain, mStack));
                                                        // pt:Type =  {InheritanceAdapter+Adaptor}
                                                        // obj: ILTypeInstance = "HotFix_Project.TestInheritance"
                                                        CheckCLRTypes(this Type pt, object obj)
                                                            //
                                                            else if (obj is ILTypeInstance)
                                                                // 嘗試轉型為 IDelegateAdapter, 轉型失敗
                                                                var adapter = obj as IDelegateAdapter;
                                                                // 是 ILEnumTypeInstance
                                                                if (!(obj is ILEnumTypeInstance))
                                                                    var ins = (ILTypeInstance)obj;
                                                                    // 返回 HotFix_Project.TestInheritance 的 CLRInstance
                                                                    // 也就是InheritanceAdapter+Adaptor
                                                                    return ins.CLRInstance;
                                                                    
                                                if (instance is CrossBindingAdaptorType && paramCount == 0)//It makes no sense to call the Adaptor's default constructor
                                                    return null;
    // ins = {ILRuntime.Runtime.Intepreter.ILTypeInstance}
    // ins.CLRInstance = {InheritanceAdapter+Adaptor}
    // InheritanceAdapter+Adaptor 繼承自 TestClassBase, 所以可以轉型
    return (T)ins.CLRInstance;
    
// obj.GetType() == {InheritanceAdapter+Adaptor}
obj.TestAbstract(123);
    if (!mTestAbstractGot)
    {
        // instance: ILTypeInstance = "HotFix_Project.TestInheritance"
        // instance.Type: ILType = "HotFix_Project.TestInheritance"
        // 獲取 熱更里 HotFix_Project.TestInheritance 的 TestAbstract 方法
        mTestAbstract = instance.Type.GetMethod("TestAbstract", 1);
        mTestAbstractGot = true;
    }
    if (mTestAbstract != null)
    {
        param1[0] = ab;
        // 調用 熱更里 HotFix_Project.TestInheritance.TestAbstract 方法
        appdomain.Invoke(mTestAbstract, instance, param1);//沒有參數建議顯式傳遞null為參數列表,否則會自動new object[0]導致GC Alloc
    }
obj.TestVirtual("Hello");

Debug.Log("現在換個方式創建實例");
obj = appdomain.Invoke("HotFix_Project.TestInheritance", "NewObject", null, null) as TestClassBase;
obj.TestAbstract(456);
obj.TestVirtual("Foobar");        
Inheritance, CrossBindingAdaptor 2.0
熱更項目

amespace HotFix_Project {
    public class HelloWorldWithInheritanceAdapter: MyClassBase {

        public HelloWorldWithInheritanceAdapter() {
            Debug.Log("Inheritance.Constructor");
        }

        public override void TestMethod() {
            Debug.Log("Inheritance.TestMethod");
        }
    }
}


主項目

// 自定義 TypeInstance
public class MyTypeInstance {
    public TypeDefinition def;

    public MyTypeInstance(TypeDefinition def) {
        this.def = def;
    }

    public void Invoke(string methodName) {
        foreach (var item in def.Methods) {

            if (item.Name == "TestMethod") {
                foreach (var i in item.Body.Instructions) {
                    Debug.Log(i);
                }
            }
        }
    }
}

// 適配器 和 熱更項目里的類 要繼承的基類
public class MyClassBase {
    public MyClassBase() {
        Debug.Log("MyClassBase.Constructor");
    }
    
    public virtual void  TestMethod() {
        Debug.Log("BaseMethod");
    }
}

// 適配器
public class MyClassBaseAdapter: MyClassBase {
    public MyTypeInstance instance;

    public MyClassBaseAdapter() {
        Debug.Log("MyClassBaseAdapter.Constructor");
    }

    public override void TestMethod() {
        instance.Invoke("TestMethod");
    }
}


void OnHotFixLoaded()
        // 獲取熱更項目的類型定義
        TypeDefinition type = appdomain.typeDef["HotFix_Project.HelloWorldWithInheritanceAdapter"];

        // 根據 TypeDefinition 實例化 MyTypeInstance
        MyTypeInstance ins = new MyTypeInstance(type);
        
        // 實際 運行的 Adaptor 的 TestMethod 方法
        MyClassBaseAdapter adapter = new MyClassBaseAdapter();
        adapter.instance = ins;

        // 適配器里 運行 MyTypeInstance 即熱更項目里 的 TestMethod 方法
        adapter.TestMethod();
熱更工程繼承主工程, 使用適配器的 流程2.0. 簡化處理, 方便理解

 

 

 

 

熱更工程
using System;
using System.Collections.Generic;

namespace HotFix_Project {
    public class TestCLRRedirection {
        public static void RunTest() {
            UnityEngine.Debug.Log("看看這行的詳細Log信息");
        }
    }
}




沒有重定向 調用 object result = cm.Invoke(this, esp, mStack);    1797

看看這行的詳細Log信息
System.Reflection.MethodBase:Invoke(Object, Object[])
ILRuntime.CLR.Method.CLRMethod:Invoke(ILIntepreter, StackObject*, IList`1, Boolean) (at Assets/ILRuntime/CLR/Method/CLRMethod.cs:316)
ILRuntime.Runtime.Intepreter.ILIntepreter:Execute(ILMethod, StackObject*, Boolean&) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:1797)
ILRuntime.Runtime.Intepreter.ILIntepreter:Run(ILMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:96)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(IMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:1061)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(String, String, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:964)
CLRRedirectionDemo:OnHotFixLoaded() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:85)
<LoadHotFixAssembly>d__4:MoveNext() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:63)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)


Debug.Log("什么時候需要CLR重定向呢,當我們需要挾持原方法實現,添加一些熱更DLL中的特殊處理的時候,就需要CLR重定向了");
Debug.Log("詳細文檔請參見Github主頁的相關文檔");
Debug.Log("CLR重定向對ILRuntime底層實現密切相關,因此要完全理解這個Demo,需要大家先看關於ILRuntime實現原理的Demo");

Debug.Log("下面介紹一個CLR重定向的典型用法,比如我們在DLL里調用Debug.Log,默認情況下是無法顯示DLL內堆棧的,像下面這樣");

Debug.Log("但是經過CLR重定向之后可以做到輸出DLL內堆棧,接下來進行CLR重定向注冊");

var mi = typeof(Debug).GetMethod("Log", new System.Type[] { typeof(object) });
// appdomain.RegisterCLRMethodRedirection(mi, Log_11);
//這個只是為了演示加的,平時不要這么用,直接在InitializeILRuntime方法里面寫CLR重定向注冊就行了
Debug.Log("我們再來調用一次剛剛的方法,注意看下一行日志的變化");
appdomain.Invoke("HotFix_Project.TestCLRRedirection", "RunTest", null, null);
    // Nop, 0, 0
    // Ldstr, 0, -1877045637
    // Call, 1, 0
    // Nop, 0, 0
    // Ret, 0, 0
    res = inteptreter.Run((ILMethod)m, instance, p);
        case OpCodeEnum.Call:
            // cm: CLRMethod = "Void Log(System.Object)"
            // cm.Redirection = null
            var redirect = cm.Redirection;
            object result = cm.Invoke(this, esp, mStack);
                // def: MethodInfo = "Void Log(System.Object)"
                // param = "看看這行的詳細Log信息"
                res = def.Invoke(instance, param);
                

有重定向 調用 esp = redirect(this, esp, mStack, cm, false);     1781

看看這行的詳細Log信息
at HotFix_Project.TestCLRRedirection.RunTest() 

UnityEngine.Debug:Log(Object)
CLRRedirectionDemo:Log_11(ILIntepreter, StackObject*, IList`1, CLRMethod, Boolean) (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:109)
ILRuntime.Runtime.Intepreter.ILIntepreter:Execute(ILMethod, StackObject*, Boolean&) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:1781)
ILRuntime.Runtime.Intepreter.ILIntepreter:Run(ILMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:96)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(IMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:1061)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(String, String, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:964)
CLRRedirectionDemo:OnHotFixLoaded() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:85)
<LoadHotFixAssembly>d__4:MoveNext() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:63)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

Debug.Log("什么時候需要CLR重定向呢,當我們需要挾持原方法實現,添加一些熱更DLL中的特殊處理的時候,就需要CLR重定向了");
Debug.Log("詳細文檔請參見Github主頁的相關文檔");
Debug.Log("CLR重定向對ILRuntime底層實現密切相關,因此要完全理解這個Demo,需要大家先看關於ILRuntime實現原理的Demo");

Debug.Log("下面介紹一個CLR重定向的典型用法,比如我們在DLL里調用Debug.Log,默認情況下是無法顯示DLL內堆棧的,像下面這樣");

Debug.Log("但是經過CLR重定向之后可以做到輸出DLL內堆棧,接下來進行CLR重定向注冊");

var mi = typeof(Debug).GetMethod("Log", new System.Type[] { typeof(object) });
appdomain.RegisterCLRMethodRedirection(mi, Log_11);
    // mi = "Void Log(System.Object)"
    // func: CLRRedirectionDelegate = Log_11: 
    redirectMap[mi] = func;    
//這個只是為了演示加的,平時不要這么用,直接在InitializeILRuntime方法里面寫CLR重定向注冊就行了
Debug.Log("我們再來調用一次剛剛的方法,注意看下一行日志的變化");
appdomain.Invoke("HotFix_Project.TestCLRRedirection", "RunTest", null, null);
    // Nop, 0, 0
    // Ldstr, 0, -1877045637
    // Call, 1, 0
    // Nop, 0, 0
    // Ret, 0, 0
    res = inteptreter.Run((ILMethod)m, instance, p);
        case OpCodeEnum.Call:
            // cm: CLRMethod = "Void Log(System.Object)"
            // cm.Redirection = CLRRedirectionDemo.Log_11
            var redirect = cm.Redirection;
                esp = redirect(this, esp, mStack, cm, false);
                    //ILRuntime的調用約定為被調用者清理堆棧,因此執行這個函數后需要將參數從堆棧清理干凈,並把返回值放在棧頂,具體請看ILRuntime實現原理文檔
                    ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
                    StackObject* ptr_of_this_method;
                    //這個是最后方法返回后esp棧指針的值,應該返回清理完參數並指向返回值,這里是只需要返回清理完參數的值即可
                    // __esp = 0x5d1b201c
                    // __ret = 0x5d1b2010
                    StackObject* __ret = ILIntepreter.Minus(__esp, 1);
                    //取Log方法的參數,如果有兩個參數的話,第一個參數是esp - 2,第二個參數是esp -1, 因為Mono的bug,直接-2值會錯誤,所以要調用ILIntepreter.Minus
                    // ptr_of_this_method = 0x5d1b2010
                    ptr_of_this_method = ILIntepreter.Minus(__esp, 1);

                    //這里是將棧指針上的值轉換成object,如果是基礎類型可直接通過ptr->Value和ptr->ValueLow訪問到值,具體請看ILRuntime實現原理文檔
                    // ptr_of_this_method = 0x5d1b2010
                    // IList = [ ""看看這行的詳細Log信息"" ]
                    object message = typeof(object).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
                        Type.CheckCLRTypes
                            StackObject.ToObject
                                case ObjectTypes.Object:
                                    // esp->Value = 0 表示 從 __mStack 0位置 取得 對象
                                    return mStack[esp->Value];
                    //所有非基礎類型都得調用Free來釋放托管堆棧
                    __intp.Free(ptr_of_this_method);

                    //在真實調用Debug.Log前,我們先獲取DLL內的堆棧
                    var stacktrace = __domain.DebugService.GetStackTrace(__intp);
                        StringBuilder sb = new StringBuilder();
                        ILRuntime.CLR.Method.ILMethod m;
                        // 獲取RuntimeStack 里的 StackFrames
                        // 只有1幀 
                        // Address: IntegerReference = null
                        // BasePointer: StackObject* = 0x5d1b2010 
                        // LocalVarPointer: StackObject* = 0x5d1b2010
                        // ManagedStackBase: int = 0
                        // Method: ILMethod = HotFix_Project.TestCLRRedirection.RunTest()
                        // ValueTypeBasePointer: StackObject* = 0x5d1e2004
                        StackFrame[] frames = intepreper.Stack.Frames.ToArray();
                        Mono.Cecil.Cil.Instruction ins = null;
                        if (frames[0].Address != null)
                        {
                            ins = frames[0].Method.Definition.Body.Instructions[frames[0].Address.Value];
                            sb.AppendLine(ins.ToString());
                        }
                        for (int i = 0; i < frames.Length; i++)
                        {
                            // 獲取 StackFrame
                            var f = frames[i];
                            // 獲取 Method = "HotFix_Project.TestCLRRedirection.RunTest()"
                            m = f.Method;
                            string document = "";
                            if (f.Address != null)
                            {
                                ins = m.Definition.Body.Instructions[f.Address.Value];
                                
                                var seq = FindSequencePoint(ins, m.Definition.DebugInformation.GetSequencePointMapping());
                                if (seq != null)
                                {
                                    document = string.Format("{0}:Line {1}", seq.Document.Url, seq.StartLine);
                                }
                            }
                            // "at HotFix_Project.TestCLRRedirection.RunTest() \r\n"
                            sb.AppendFormat("at {0} {1}\r\n", m, document);
                        }

                        return sb.ToString();                    

                    //我們在輸出信息后面加上DLL堆棧
                    UnityEngine.Debug.Log(message + "\n" + stacktrace);    
CLRRedirection
熱更工程

using System;
using System.Collections.Generic;

namespace HotFix_Project {
    public class TestCLRRedirection {
        public static void RunTest() {
            UnityEngine.Debug.Log("看看這行的詳細Log信息");
        }
    }
}

主工程

// 獲取 Debug.Log 的 MethodBase 
var mi = typeof(Debug).GetMethod("Log", new System.Type[] { typeof(object) });
// 將對 Debug.Log 的調用 重定向到 Log_11中
appdomain.RegisterCLRMethodRedirection(mi, Log_11);
//這個只是為了演示加的,平時不要這么用,直接在InitializeILRuntime方法里面寫CLR重定向注冊就行了
Debug.Log("我們再來調用一次剛剛的方法,注意看下一行日志的變化");
appdomain.Invoke("HotFix_Project.TestCLRRedirection", "RunTest", null, null);


// m = HotFix_Project.TestCLRRedirection
// instance = null
inteptreter.Run((ILMethod)m, instance, p);
    // esp: StackObject* 
    esp = Execute(method, esp, out unhandledException);
        // 如果這個方法的 重定向方法 不為空
        if (method.Redirection != null)
            // 調用這個 重定向方法
            // esp: StackObject* = 0xa68cb04c
            // esp-> ObjectType = Null
            // esp-> Value = 10
            // esp-> ValueLow = 1
            // mStack = [ "看看這行的詳細Log信息" ]
            esp = redirect(this, esp, mStack, cm, false);
            
                //ILRuntime的調用約定為被調用者清理堆棧,因此執行這個函數后需要將參數從堆棧清理干凈,並把返回值放在棧頂,具體請看ILRuntime實現原理文檔
                ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
                
                
                //這個是最后方法返回后esp棧指針的值,應該返回清理完參數並指向返回值,這里是只需要返回清理完參數的值即可
                // __ret: StackObject* = 0xa68cb040
                // __ret-> ObjectType = Object
                // __ret-> Value = 0
                // __ret-> ValueLow = 1374408720
                // __ret 是返回指針, 因為參數不需要了 所以將 棧 下移 1
                StackObject* __ret = ILIntepreter.Minus(__esp, 1);
                
                //取Log方法的參數,如果有兩個參數的話,第一個參數是esp - 2,第二個參數是esp -1, 因為Mono的bug,直接-2值會錯誤,所以要調用ILIntepreter.Minus
                // ptr_of_this_method: StackObject* = 0xa68cb040
                // ptr_of_this_method-> ObjectType = Object
                // ptr_of_this_method-> Value = 0
                // ptr_of_this_method-> ValueLow = 1374408720
                // 參數1  StackObject* 指針
                StackObject* ptr_of_this_method = ILIntepreter.Minus(__esp, 1);

                //這里是將棧指針上的值轉換成object,如果是基礎類型可直接通過ptr->Value和ptr->ValueLow訪問到值,具體請看ILRuntime實現原理文檔
                object message = typeof(object).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
                    // 獲取 0xa68cb040 處的 StackObject
                    StackObject.ToObject
                        switch (esp->ObjectType)
                            case ObjectTypes.Object:
                                // 根據 索引  esp->Value = 0  獲取 托管堆 里的 對象 = "看看這行的詳細Log信息"
                                return mStack[esp->Value];
                    // 將托管堆里的 object 轉型為合適的類型
                    Type.CheckCLRTypes
                
                //所有非基礎類型都得調用Free來釋放托管堆棧
                __intp.Free(ptr_of_this_method);

                //在真實調用Debug.Log前,我們先獲取DLL內的堆棧
                var stacktrace = __domain.DebugService.GetStackTrace(__intp);

                //我們在輸出信息后面加上DLL堆棧
                UnityEngine.Debug.Log(message + "\n" + stacktrace);

                return __ret;                
方法重定向 2.0, 簡化處理, 便於理解
熱更工程

public class InstanceClass {
    public InstanceClass() {
        Vector3 one = Vector3.one;
    }
}


主工程

OnHotFixLoaded()
    // 開啟或關閉 重定向
    // ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);
    var type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
    // 調用 無參構造函數
    object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] {  });
        // esp = 0x77064030
        StackObject* esp = stack.StackBase;

        // 將實例本身壓棧, 棧地址由低到高
        esp = PushObject(esp, mStack, instance);
            esp->ObjectType = ObjectTypes.Object;    
            // Value = 0 
            esp->Value = mStack.Count;
            // mStack[0] = "HotFix_Project.InstanceClass": ILTypeInstance
            mStack.Add(obj);            
            // esp = 0x7706403c
            // 棧向上移動1個 StackObject*,也就是12個字節
            return esp + 1;
            
        // 將"HotFix_Project.InstanceClass..ctor()"入棧
        esp = PushParameters(method, esp, p);
            // 這是個無參構造函數,棧沒有變換 esp = 0x7706403c
            return esp;
            
        // 調用這個方法
        // 原始IL
        // "IL_0000: ldarg.0"
        // "IL_0001: call System.Void System.Object::.ctor()"
        // "IL_0006: nop"
        // "IL_0007: nop"
        // "IL_0008: call UnityEngine.Vector3 UnityEngine.Vector3::get_one()"
        // "IL_000d: stloc.0"
        // "IL_000e: ret"
        // 自定義IL
        // Ldarg_0, 0, 0
        // Call, 0, 1
        // Nop, 0, 0
        // Nop, 0, 0
        // Call, 2, 0
        // Stloc_0, 0, 0
        // Ret, 0, 0
        esp = Execute(method, esp, out unhandledException);
            // v1 = 0x7706403c = 原始 esp + 1
            StackObject* v1 = frame.LocalVarPointer;
            // v2 = 0x77064048 = 原始 esp + 2
            StackObject* v2 = frame.LocalVarPointer + 1;
            
            // esp = 0x77064048     = 原始 esp + 2
            esp = frame.BasePointer;
            
            // arg = 0x7706403c = 原始 esp + 1
            var arg = Minus(frame.LocalVarPointer, method.ParameterCount);
            
            if (method.HasThis)//this parameter is always object reference
                // arg = 0x77064030 = 原始 esp
                arg--;
                paramCnt++;
                
            
        
            // 遍歷局部變量
            for (int i = 0; i < method.LocalVariableCount; i++)
                // 獲取局部變量 v: VariableDefinition
                var v = method.Variables[i];
                // t: CLRType = "UnityEngine.Vector3"
                var t = AppDomain.GetType(v.VariableType, method.DeclearingType, method);
                if (t is not ILType)
                    CLRType cT = (CLRType)t;
                    // loc = 0x7706403c = 原始 esp + 1
                    var loc = Add(v1, i);
                        // new 一個 Vector3
                        obj = ((CLRType)t).CreateDefaultInstance();                    
                        loc->ObjectType = ObjectTypes.Object;    
                        // 將 loc 的值 設為 mStack[1], mStack[1] = Vector3 Activator.CreateInstance(TypeForCLR);
                        loc->Value = locBase + i;
                        mStack[locBase + i] = obj;
            
            case OpCodeEnum.Ldarg_0:
                // esp = 0x77064048 = 原始 esp + 2
                // arg = 0x77064030 = 原始 esp 也就是 實例本身
                // 將 自身 拷貝到 esp + 2
                // mStack[0] = "HotFix_Project.InstanceClass"
                // mStack[1] = "(0.0, 0.0, 0.0)"
                // mStack[2] = "HotFix_Project.InstanceClass"
                CopyToStack(esp, arg, mStack);
                // esp = 0x77064054 = 原始 esp + 3
                esp++
            case OpCodeEnum.Call:
                // 本來是要調用 call System.Void System.Object::.ctor()"
                IMethod m = domain.GetMethod(ip->TokenInteger);        
                // 處理過了,所以沒有
                if (m == null)
                {
                    //Irrelevant method
                    // cnt = 1
                    int cnt = (int)ip->TokenLong;
                    //Balance the stack
                    for (int i = 0; i < cnt; i++)
                    {
                        // 釋放 esp - 1 = 0x77064048 也就是 原始 esp + 2
                        // 移除 mStack[2]
                        Free(esp - 1);
                        // esp =     0x77064048 也就是 原始 esp + 2
                        esp--;
                    }
                }
            case OpCodeEnum.Call:
                // 獲取"UnityEngine.Vector3 get_one()"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                // 如果開啟了重定向############################
                var redirect = cm.Redirection;
                if (redirect != null)
                    // esp = 0x77064048 = 原始 esp + 2
                    // mStack[0] = "HotFix_Project.InstanceClass"
                    // mStack[1] = "(0.0, 0.0, 0.0)"
                    esp = redirect(this, esp, mStack, cm, false);
                    
                    
                    
                // 沒有開啟重定向#########################################
                // esp = 0x77064048 = 原始 esp + 2
                object result = cm.Invoke(this, esp, mStack);
                    // System.Reflection.MethodInfo 調用, GC
                    res = def.Invoke(instance, param);
                        ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
                        // _ret = 0x77064048 = 原始 esp + 2
                        StackObject* __ret = ILIntepreter.Minus(__esp, 0);

                        // result_of_this_method = 自己手寫的 Vector3.one
                        var result_of_this_method = UnityEngine.Vector3.one;

                        if (ILRuntime.Runtime.Generated.CLRBindings.s_UnityEngine_Vector3_Binding_Binder != null) {
                            ILRuntime.Runtime.Generated.CLRBindings.s_UnityEngine_Vector3_Binding_Binder.PushValue(ref result_of_this_method, __intp, __ret, __mStack);
                            return __ret + 1;
                        } else {
                            
                            return ILIntepreter.PushObject(__ret, __mStack, result_of_this_method);
                                esp->ObjectType = ObjectTypes.Object;
                                // esp = 0x77064048 = 原始 esp + 2
                                // esp->Value = 2
                                esp->Value = mStack.Count;
                                // mStack[0] = "HotFix_Project.InstanceClass"
                                // mStack[1] = "(0.0, 0.0, 0.0)"
                                // mStack[2] = "(1.0, 1.0, 1.0)"
                                mStack.Add(obj);                            
                        }                    
                    
                
                esp = PushObject(esp, mStack, result, cm.ReturnType.TypeForCLR == typeof(object));
                    esp->ObjectType = ObjectTypes.Object;
                    // esp = 0x77064048 = 原始 esp + 2
                    // esp->Value = 2
                    esp->Value = mStack.Count;
                    // mStack[0] = "HotFix_Project.InstanceClass"
                    // mStack[1] = "(0.0, 0.0, 0.0)"
                    // mStack[2] = "(1.0, 1.0, 1.0)"
                    mStack.Add(obj);
                    
                    // esp = 0x77064054 = 原始 esp + 3
                    return esp + 1
            case case OpCodeEnum.Stloc_0:
                // esp = 0x77064048 = 原始 esp + 2
                esp--;                
                int idx = locBase;
                // esp = 0x77064048 = 原始 esp + 2
                // v = 0x7706403c = 原始 esp + 1
                // bp = 0x77094024 = 原始 esp - 1
                // idx = 1
                StLocSub(esp, v1, bp, idx, mStack);
                    // 原始指針 esp + 2 賦值 給 原始esp + 1 也就是 Vector3 one = Vector3.one;
                    *v = *esp;    
                    // 指針對應的 mStack 賦值                    
                    mStack[idx] = CheckAndCloneValueType(mStack[v->Value], domain);                    
                    v->Value = idx;
                    
                    // 釋放 esp = 0x77064048 = 原始esp + 2
                    Free(esp);
                    
方法重定向2.1, 簡化處理, 便於理解

 

 

 

 

CLRBinding

未開啟 ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain); 3371ms 浮動

 

開啟 ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);  638ms 浮動

 

主工程 

void Update()
{
    if (ilruntimeReady && !executed && Time.realtimeSinceStartup > 3)
    {
        executed = true;
        //這里為了方便看Profiler,代碼挪到Update中了
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        Debug.LogWarning("運行這個Demo前請先點擊菜單ILRuntime->Generate來生成所需的綁定代碼,並按照提示解除下面相關代碼的注釋");
        Debug.Log("默認情況下,從熱更DLL里調用Unity主工程的方法,是通過反射的方式調用的,這個過程中會產生GC Alloc,並且執行效率會偏低");
        
        Debug.Log("接下來進行CLR綁定注冊,在進行注冊前,需要先在ILRuntimeCodeGenerator的綁定列表里面,添加上CLRBindingTestClass這個測試類型");
        Debug.Log("CLR綁定會生成較多C#代碼,最終會增大包體和Native Code的內存耗用,所以只添加常用類型和頻繁調用的接口即可");
        Debug.Log("接下來需要點擊Unity菜單里面的ILRuntime->Generate CLR Binding Code來生成綁定代碼");
        Debug.Log("ILRuntime->Generate CLR Binding Code by Analysis是ILRT1.2版新加入的功能,可以根據熱更DLL自動生成綁定代碼");
        
        //由於CLR重定向只能重定向一次,並且CLR綁定就是利用的CLR重定向,所以請在初始化最后階段再執行下面的代碼,以保證CLR重定向生效
        //請在生成了綁定代碼后注釋下面這行
        // throw new System.Exception("請在生成了綁定代碼后再運行這個示例");//
        //請在生成了綁定代碼后解除下面這行的注釋
        //請在生成了綁定代碼后解除下面這行的注釋
        //請在生成了綁定代碼后解除下面這行的注釋
        // ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);
        //這個只是為了演示加的,平時不需要這么用,直接在InitializeILRuntime方法里面寫CLR綁定注冊就行了
        
        var type = appdomain.LoadedTypes["HotFix_Project.TestCLRBinding"];
        var m = type.GetMethod("RunTest", 0);
        Debug.Log("現在我們再來試試綁定后的效果");
        sw.Reset();
        sw.Start();
        RunTest2(m);
        Profiler.BeginSample("RunTest2");
        appdomain.Invoke(m, null, null);
            Intepreter.Execute
                // 沒有綁定
                object result = cm.Invoke(this, esp, mStack);    #1797
                // 綁定了
                // redirect: CLRRedirectionDelegate = CLRBindingTestClass_Binding.DoSomeTest_0
                esp = redirect(this, esp, mStack, cm, false);                
                    // 
                    ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
                    StackObject* ptr_of_this_method;
                    // 返回指針
                    StackObject* __ret = ILIntepreter.Minus(__esp, 2);
                    // 參數 b
                    ptr_of_this_method = ILIntepreter.Minus(__esp, 1);
                    System.Single @b = *(float*)&ptr_of_this_method->Value;
                    // 參數 a
                    ptr_of_this_method = ILIntepreter.Minus(__esp, 2);
                    System.Int32 @a = ptr_of_this_method->Value;

                    // 直接調用 主工程里的方法
                    var result_of_this_method = global::CLRBindingTestClass.DoSomeTest(@a, @b);                    

                    // __ret: StackObject*
                    __ret->ObjectType = ObjectTypes.Float;
                    *(float*)&__ret->Value = result_of_this_method;
                    // __ret + 1
                    return __ret + 1;                    
                    
        Profiler.EndSample();
        sw.Stop();
        Debug.LogFormat("剛剛的方法執行了:{0} ms", sw.ElapsedMilliseconds);

        Debug.Log("可以看到運行時間和GC Alloc有大量的差別,RunTest2之所以有20字節的GC Alloc是因為Editor模式ILRuntime會有調試支持,正式發布(關閉Development Build)時這20字節也會隨之消失");
    }
}

void RunTest()
{
    appdomain.Invoke("HotFix_Project.TestCLRBinding", "RunTest", null, null);
}

void RunTest2(IMethod m)
{
    appdomain.Invoke(m, null, null);
}

熱更工程

using System;
using System.Collections.Generic;

namespace HotFix_Project {
    public class TestCLRBinding {
        public static void RunTest() {
            for (int i = 0; i < 100000; i++) {
                CLRBindingTestClass.DoSomeTest(i, i);
            }
        }
    }
}
CLRBinding
測試熱更工程調用主工程的方法

CLR綁定就是利用的CLR重定向


熱更工程

using System;
using System.Collections.Generic;

namespace HotFix_Project {
    public class TestCLRBinding {
        public static void RunTest() {
            // for (int i = 0; i < 1; i++) {
                CLRBindingTestClass.DoSomeTest(1, 2);
            // }
        }
    }
}


主工程

public class CLRBindingTestClass
{
    public static float DoSomeTest(int a, float b)
    {
        return a + b;
    }
}

var type = appdomain.LoadedTypes["HotFix_Project.TestCLRBinding"];
var m = type.GetMethod("RunTest", 0);
appdomain.Invoke(m, null, null);
    inteptreter.Run((ILMethod)m, instance, p);
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldc.i4.1"
        // "IL_0002: ldc.r4 2"
        // "IL_0007: call System.Single CLRBindingTestClass::DoSomeTest(System.Int32,System.Single)"
        // "IL_000c: pop"
        // "IL_000d: ret"
        
        // 自定義IL, 不管有沒有使用重定向
        // Nop, 0, 0
        // Ldc_I4_1, 0, 0
        // Ldc_R4, 1073741824, 0
        // Call, 1, 0
        // Pop, 0, 0
        // Ret, 0, 0
        esp = Execute(method, esp, out unhandledException);
            // 重定向為空
            if (redirect == null)
                object result = cm.Invoke(this, esp, mStack);
                    // 根據熱更工程的元數據調用
                    // def: MethodInfo = "Single DoSomeTest(Int32, Single)"
                    res = def.Invoke(instance, param);
            // 重定向不為空
            else
                // 直接調用 redirect 方法
                esp = redirect(this, esp, mStack, cm, false);
                    // 
                    CLRBindingTestClass_Binding.DoSomeTest_0(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)
                        ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
                        StackObject* ptr_of_this_method;
                        StackObject* __ret = ILIntepreter.Minus(__esp, 2);

                        // 第2個參數
                        ptr_of_this_method = ILIntepreter.Minus(__esp, 1);
                        System.Single @b = *(float*)&ptr_of_this_method->Value;

                        // 第1個參數
                        ptr_of_this_method = ILIntepreter.Minus(__esp, 2);
                        System.Int32 @a = ptr_of_this_method->Value;

                        // 實際調用的是 主工程的方法
                        var result_of_this_method = global::CLRBindingTestClass.DoSomeTest(@a, @b);

                        __ret->ObjectType = ObjectTypes.Float;
                        *(float*)&__ret->Value = result_of_this_method;
                        return __ret + 1;    
CLRBinding 2.0, 便於理解, 簡化處理

 

主工程

using System.Collections.Generic;
using System;
using System.Collections;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.CLR.Method;

public class CoroutineAdapter: CrossBindingAdaptor {

    public override Type BaseCLRType {
        get {
            return null;
        }
    }
    
    public override Type[] BaseCLRTypes {
        get {
            //跨域繼承只能有1個Adapter,因此應該盡量避免一個類同時實現多個外部接口,對於coroutine來說是IEnumerator<object>,IEnumerator和IDisposable,
            //ILRuntime雖然支持,但是一定要小心這種用法,使用不當很容易造成不可預期的問題
            //日常開發如果需要實現多個DLL外部接口,請在Unity這邊先做一個基類實現那些個接口,然后繼承那個基類
            return new Type[] { typeof(IEnumerator<object>), typeof(IEnumerator), typeof(IDisposable) };
        }
    }

    public override Type AdaptorType {
        get {
            return typeof(Adaptor);
        }
    }
    
    public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain,ILTypeInstance instance) {
        return new Adaptor(appdomain, instance);
    }
    
    // Coroutine生成的類實現了IEnumerator<System.Object>, IEnumerator, IDisposable,所以都要實現,這個可以通過reflector之類的IL反編譯軟件得知
    internal class Adaptor: IEnumerator<System.Object>, IEnumerator, IDisposable, CrossBindingAdaptorType {
        ILTypeInstance instance;
        ILRuntime.Runtime.Enviorment.AppDomain appdomain;
        
        public Adaptor() {
        
        }
        
        public Adaptor(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance) {
            this.appdomain = appdomain;
            this.instance = instance;
        }
        
        public ILTypeInstance ILInstance { get { return instance; } }
        
        IMethod mCurrentMethod;
        bool mCurrentMethodGot;
        public object Current {
            get {
                if (!mCurrentMethodGot) {
                    mCurrentMethod = instance.Type.GetMethod("get_Current", 0);
                    if (mCurrentMethod == null) {
                        //這里寫System.Collections.IEnumerator.get_Current而不是直接get_Current是因為coroutine生成的類是顯式實現這個接口的,通過Reflector等反編譯軟件可得知
                        //為了兼容其他只實現了單一Current屬性的,所以上面先直接取了get_Current
                        mCurrentMethod = instance.Type.GetMethod("System.Collections.IEnumerator.get_Current", 0);
                    }
                    mCurrentMethodGot = true;
                }
                
                if (mCurrentMethod != null) {
                    var res = appdomain.Invoke(mCurrentMethod, instance, null);
                    return res;
                } else {
                    return null;
                }
            }
        }
        
        IMethod mDisposeMethod;
        bool mDisposeMethodGot;
        public void Dispose() {
            if (!mDisposeMethodGot) {
                mDisposeMethod = instance.Type.GetMethod("Dispose", 0);
                if (mDisposeMethod == null) {
                    mDisposeMethod = instance.Type.GetMethod("System.IDisposable.Dispose", 0);
                }
                mDisposeMethodGot = true;
            }
            
            if (mDisposeMethod != null) {
                appdomain.Invoke(mDisposeMethod, instance, null);
            }
        }
        
        IMethod mMoveNextMethod;
        bool mMoveNextMethodGot;
        public bool MoveNext() {
            if (!mMoveNextMethodGot) {
                mMoveNextMethod = instance.Type.GetMethod("MoveNext", 0);
                mMoveNextMethodGot = true;
            }
            
            if (mMoveNextMethod != null) {
                return (bool)appdomain.Invoke(mMoveNextMethod, instance, null);
            } else {
                return false;
            }
        }
        
        IMethod mResetMethod;
        bool mResetMethodGot;
        public void Reset() {
            if (!mResetMethodGot) {
                mResetMethod = instance.Type.GetMethod("Reset", 0);
                mResetMethodGot = true;
            }
            
            if (mResetMethod != null) {
                appdomain.Invoke(mResetMethod, instance, null);
            }
        }
        
        public override string ToString() {
            IMethod m = appdomain.ObjectType.GetMethod("ToString", 0);
            m = instance.Type.GetVirtualMethod(m);
            if (m == null || m is ILMethod) {
                return instance.ToString();
            } else {
                return instance.Type.FullName;
            }
        }
    }
}

public class CoroutineDemo: MonoBehaviour {
    ...

    static CoroutineDemo instance;
    public static CoroutineDemo Instance {
        get { return instance; }
    }

    void InitializeILRuntime()
    {
        //這里做一些ILRuntime的注冊
        //使用Couroutine時,C#編譯器會自動生成一個實現了IEnumerator,IEnumerator<object>,IDisposable接口的類,因為這是跨域繼承,所以需要寫CrossBindAdapter(詳細請看04_Inheritance教程),Demo已經直接寫好,直接注冊即可
        appdomain.RegisterCrossBindingAdaptor(new CoroutineAdapter());
        appdomain.DebugService.StartDebugService(56000);
    }
    
    unsafe void OnHotFixLoaded() {
        appdomain.Invoke("HotFix_Project.TestCoroutine", "RunTest", null, null);
    }
    
    public void DoCoroutine(IEnumerator coroutine) {
        StartCoroutine(coroutine);
    }
}


熱更工程

namespace HotFix_Project {
    public class TestCoroutine {
        public static void RunTest() {
            CoroutineDemo.Instance.DoCoroutine(Coroutine());
        }
        
        static System.Collections.IEnumerator Coroutine() {
            Debug.Log("開始協程, t = " + Time.time);
            yield return new WaitForSeconds(3);
            Debug.Log("等待了3秒, t = " + Time.time);
        }
    }
}
Coroutine

sdsdfsfdsdfsdfsdfsdfs

 

熱更項目

namespace HotFix_Project {
    class SomeMonoBehaviour : MonoBehaviour {
        void Awake() {
            Debug.Log("!! SomeMonoBehaviour.Awake");
        }
    }
    
    public class TestMonoBehaviour {
        public static void RunTest(GameObject go) {
            go.AddComponent<SomeMonoBehaviour>();
        }
    }
}


主項目


// 注冊 MonoBehaviour Adapter
appdomain.RegisterCrossBindingAdaptor(new MonoBehaviourAdapter());

// 重定向 MonoBehaviour.AddComponent 方法 到 AddComponent
SetupCLRRedirection()
    var arr = typeof(GameObject).GetMethods();
    foreach (var i in arr)
    {
        if (i.Name == "AddComponent" && i.GetGenericArguments().Length == 1)
        {
            appdomain.RegisterCLRMethodRedirection(i, AddComponent);
        }
    }


appdomain.Invoke("HotFix_Project.TestMonoBehaviour", "RunTest", null, gameObject);


    ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;

    // ptr = 0x4e3a877c
    // ptr->ObjectType = Object
    // ptr->Value = 1, 表示 獲取 托管棧 上的 索引為1 的 元素
    var ptr = __esp - 1;
    //成員方法的第一個參數為this
    GameObject instance = StackObject.ToObject(ptr, __domain, __mStack) as GameObject;
    if (instance == null)
        throw new System.NullReferenceException();
    __intp.Free(ptr);

    // 獲取 這個方法的 泛型參數 HotFix_Project.SomeMonoBehaviour: IType
    var genericArgument = __method.GenericArguments;
    //AddComponent應該有且只有1個泛型參數
    if (genericArgument != null && genericArgument.Length == 1)
    {
        var type = genericArgument[0];
        object res;
        if(type is CLRType)
        {
            //Unity主工程的類不需要任何特殊處理,直接調用Unity接口
            res = instance.AddComponent(type.TypeForCLR);
        }
        else
        {
            // 熱更DLL內的類型比較麻煩。首先我們得自己手動創建實例
            // ILType 當然是 自己 new ILTypeInstance
            var ilInstance = new ILTypeInstance(type as ILType, false);//手動創建實例是因為默認方式會new MonoBehaviour,這在Unity里不允許
            //接下來創建Adapter實例
            // 這里 實際上 添加的是 Adaptor
            var clrInstance = instance.AddComponent<MonoBehaviourAdapter.Adaptor>();
            //unity創建的實例並沒有熱更DLL里面的實例,所以需要手動賦值
            clrInstance.ILInstance = ilInstance;
            clrInstance.AppDomain = __domain;
            //這個實例默認創建的CLRInstance不是通過AddComponent出來的有效實例,所以得手動替換
            ilInstance.CLRInstance = clrInstance;
            
            res = clrInstance.ILInstance;//交給ILRuntime的實例應該為ILInstance

            clrInstance.Awake();//因為Unity調用這個方法時還沒准備好所以這里補調一次
        }

        // 將 res: ILTypeInstance =  "HotFix_Project.SomeMonoBehaviour" 壓入到托管棧,
        return ILIntepreter.PushObject(ptr, __mStack, res);
            // 更新 esP: StacObject* 指針
            esp->ObjectType = ObjectTypes.Object;
            esp->Value = mStack.Count;
            mStack.Add(obj);
            // 非托管棧指針 向上移
            return esp + 1;
            
    return __esp;
}
MonoBehaviour適配 + AddComponent 重定向, 簡化 2.0

 

 

主工程

void OnHotFixLoaded() {
    Debug.Log("C#工程中反射是一個非常經常用到功能,ILRuntime也對反射進行了支持,在熱更DLL中使用反射跟原生C#沒有任何區別,故不做介紹");
    Debug.Log("這個Demo主要是介紹如何在主工程中反射熱更DLL中的類型");
    Debug.Log("假設我們要通過反射創建HotFix_Project.InstanceClass的實例");
    Debug.Log("顯然我們通過Activator或者Type.GetType(\"HotFix_Project.InstanceClass\")是無法取到類型信息的");
    
    Debug.Log("熱更DLL中的類型我們均需要通過AppDomain取得");    
    var it = appdomain.LoadedType["HotFix_Project.InstanceClass"];
    
    Debug.Log("LoadedType返回的是IType類型,但是我們需要獲得對應的System.Type才能繼續使用反射接口");
    var type = it.ReflectionType;
    
    Debug.Log("取得Type之后就可以按照我們熟悉的方式來反射調用了");
    var ctor = type.GetConstructor(new System.Type[0]);
    var obj = ctor.Invoke(null);
    
    Debug.Log("打印一下結果");
    Debug.Log(obj);
    
    Debug.Log("我們試一下用反射給字段賦值");
    var fi = type.GetField("id", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    fi.SetValue(obj, 111111);
    Debug.Log("我們用反射調用屬性檢查剛剛的賦值");
    var pi = type.GetProperty("ID");
    Debug.Log("ID = " + pi.GetValue(obj, null));
}

熱更工程

namespace HotFix_Project
{
    public class InstanceClass
    {
        private int id;

        public InstanceClass()
        {
            UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass()");
            this.id = 0;
        }

        public InstanceClass(int id)
        {
            UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass() id = " + id);
            this.id = id;
        }

        public int ID
        {
            get { return id; }
        }

        // static method
        public static void StaticFunTest()
        {
            UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest()");
        }

        public static void StaticFunTest2(int a)
        {
            UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest2(), a=" + a);
        }

        public static void GenericMethod<T>(T a)
        {
            UnityEngine.Debug.Log("!!! InstanceClass.GenericMethod(), a=" + a);
        }
    }
}
Reflection

 

熱更項目

using UnityEngine;

namespace HotFix_Project {
    public class TestValueType {
        public static void RunTest() {
            Vector3 a = new Vector3(1, 2, 3);
            a += Vector3.one;
        }
    }
}

主項目

// 注冊值類型綁定
appdomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
    if (!valueTypeBinders.ContainsKey(t))
    {
        valueTypeBinders[t] = binder;
        // Vector3Binder 重定向
        binder.RegisterCLRRedirection(this);
            
            BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
            MethodBase method;
            Type[] args;
            // 獲取 Vector3 類型
            Type type = typeof(Vector3);
            // 獲取參數類型
            args = new Type[] { typeof(float), typeof(float), typeof(float) };
            // 獲取 Vector3 的構造函數
            method = type.GetConstructor(flag, null, args, null);
            // 將 new Vector3(3參數)的調用重定向到 NewVector3
            appdomain.RegisterCLRMethodRedirection(method, NewVector3);

            args = new Type[] { typeof(float), typeof(float) };
            method = type.GetConstructor(flag, null, args, null);
            // 將 new Vector3(2參數)的調用重定向到 NewVector3_2
            appdomain.RegisterCLRMethodRedirection(method, NewVector3_2);        
        
            // 后面都是 Vector3 方法的重定向
            ....

        var ct = GetType(t) as CLRType;
        binder.CLRType = ct;
    }

appdomain.Invoke("HotFix_Project.TestValueType", "RunTest", null, null);
    // "System.Void HotFix_Project.TestValueType::RunTest()"調用
    // 原始 IL
    // 
    // "IL_0000: nop"
    // "IL_0001: ldloca.s V_0"
    // "IL_0003: ldc.r4 1"
    // "IL_0008: ldc.r4 2"
    // "IL_000d: ldc.r4 3"
    // "IL_0012: call System.Void UnityEngine.Vector3::.ctor(System.Single,System.Single,System.Single)"
    // "IL_0017: ldloc.0"
    // "IL_0018: call UnityEngine.Vector3 UnityEngine.Vector3::get_one()"
    // "IL_001d: call UnityEngine.Vector3 UnityEngine.Vector3::op_Addition(UnityEngine.Vector3,UnityEngine.Vector3)"
    // "IL_0022: stloc.0"
    // "IL_0023: ret"
    // 
    // 自定義 IL, 不管是否使用 ValueTypeBinder
    // 
    // Nop, 0, 0
    // Ldloca_S, 0, 0
    // Ldc_R4, 1065353216, 0
    // Ldc_R4, 1073741824, 0
    // Ldc_R4, 1077936128, 0
    // Call, 1, 0
    // Ldloc_0, 0, 0
    // Call, 2, 0
    // Call, 3, 0
    // Stloc_0, 0, 0
    // Ret, 0, 0
    // 
    esp = Execute(method, esp, out unhandledException);
        // 局部變量處理
        for (int i = 0; i < method.LocalVariableCount; i++)
            // v: VariableDefinition = V_0
            var v = method.Variables[i];
            // true && false
            if (v.VariableType.IsValueType && !v.VariableType.IsPrimitive)
                // t = "UnityEngine.Vector3"
                var t = AppDomain.GetType(v.VariableType, method.DeclearingType, method);
                    //     
                    appdomain.ValueTypeBinders.TryGetValue(clrType, out valueTypeBinder);
                // 不是 ILType
                if (t is ILType)
                    var loc = Add(v1, i);
                    stack.AllocValueType(loc, t);
                        InitializeValueTypeObject(type, dst);
                    mStack.Add(obj);*/
                else
                    // 轉型為 CLRType
                    CLRType cT = (CLRType)t;
                    // 分配 局部變量指針
                    // loc: StackObject*
                    var loc = Add(v1, i);
                    // 獲取 ValueTypeBinder
                    if (cT.ValueTypeBinder != null)
                        // stack: RuntimeStack
                        stack.AllocValueType(loc, t);
                    else
                        // 創建 Vector(0.0, 0.0, 0.0)
                        obj = ((CLRType)t).CreateDefaultInstance();
                        loc->ObjectType = ObjectTypes.Object;
                        loc->Value = locBase + i;
                        // mStack
                        // [(0.0, 0.0, 0.0)]
                        mStack[locBase + i] = obj;
        // 將位於特定索引處的局部變量的地址加載到計算堆棧上(短格式)
        case OpCodeEnum.Ldloca_S:
            var v = Add(frame.LocalVarPointer, ip->TokenInteger);    
            // StackObjectReference 的值 是 指針
            esp->ObjectType = ObjectTypes.StackObjectReference;    
            *(long*)&esp->Value = (long)v;    
            esp++;
        // 將所提供的 float32 類型的值作為 F (float) 類型推送到計算堆棧上。
        case OpCodeEnum.Ldc_R4:
            *(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
            esp->ObjectType = ObjectTypes.Float;
            esp++;
        // 將所提供的 float32 類型的值作為 F (float) 類型推送到計算堆棧上。
        case OpCodeEnum.Ldc_R4:
            *(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
            esp->ObjectType = ObjectTypes.Float;
            esp++;
        // 將所提供的 float32 類型的值作為 F (float) 類型推送到計算堆棧上。
        case OpCodeEnum.Ldc_R4:
            *(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
            esp->ObjectType = ObjectTypes.Float;
            esp++;
        // 調用 Vector3 構造函數
        case OpCodeEnum.Call:
            // "Void .ctor(Single, Single, Single)"
            IMethod m = domain.GetMethod(ip->TokenInteger);
            // 
            object result = cm.Invoke(this, esp, mStack);
                object instance = declaringType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((Minus(esp, paramCount + 1)), appdomain, mStack));
                // cDef: ConstructorInfo
                cDef.Invoke(instance, param);
        // 將索引 0 處的局部變量加載到計算堆棧上
        case OpCodeEnum.Ldloc_0:
            CopyToStack(esp, v1, mStack);        
            esp++;
        // 調用 "UnityEngine.Vector3 get_one()"
        case OpCodeEnum.Call:
            object result = cm.Invoke(this, esp, mStack);
        // 調用 "UnityEngine.Vector3 op_Addition(UnityEngine.Vector3, UnityEngine.Vector3)"
        case OpCodeEnum.Call: 
            object result = cm.Invoke(this, esp, mStack);
        // 從計算堆棧的頂部彈出當前值並將其存儲到索引 0 處的局部變量列表中。
        case OpCodeEnum.Stloc_0:
            esp--;
            int idx = locBase;
            StLocSub(esp, v1, bp, idx, mStack);
ValueTypeBinder
appdomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
    if (!valueTypeBinders.ContainsKey(t))
    {
        valueTypeBinders[t] = binder;
        binder.RegisterCLRRedirection(this);
            args = new Type[] { };        
            method = type.GetMethod("get_one", flag, null, args, null);        
            appdomain.RegisterCLRMethodRedirection(method, Get_One);
                if (mi == null)
                    return;
                // mi: MethodBase = "UnityEngine.Vector3 get_one()"
                // ValueBinder 也是 使用 CLRMethodRedicrection                
                if (!redirectMap.ContainsKey(mi))
                    redirectMap[mi] = func;


        var ct = GetType(t) as CLRType;
        binder.CLRType = ct;
    }

UnityEngine_Vector3_Binding.Register(app);
    method = type.GetMethod("get_one", flag, null, args, null);
    app.RegisterCLRMethodRedirection(method, get_one_0);                                
        args = new Type[]{};
        method = type.GetMethod("get_one", flag, null, args, null);                                    
        app.RegisterCLRMethodRedirection(method, get_one_0);    
            if (mi == null)        
                return;        
            // mi: MethodBase = "UnityEngine.Vector3 get_one()"
            // 上面已經存過了, 所以不會覆蓋.
            if (!redirectMap.ContainsKey(mi))                                    
                redirectMap[mi] = func;
ValueTypeBinder 也使用 RegisterCLRMethodRedirection
熱更工程


class TestValueType {
    public static void RunTest() {
        Vector3 one = new Vector3(1.0f, 1.0f, 1.0f);
        Debug.Log(one);
    }
}


主工程
    appdomain.Invoke("HotFix_Project.TestValueType", "RunTest", null, null);
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldloca.s V_0"
        // "IL_0003: ldc.r4 1"
        // "IL_0008: ldc.r4 1"
        // "IL_000d: ldc.r4 1"
        // "IL_0012: call System.Void UnityEngine.Vector3::.ctor(System.Single,System.Single,System.Single)"
        // "IL_0017: ldloc.0"
        // "IL_0018: box UnityEngine.Vector3"
        // "IL_001d: call System.Void UnityEngine.Debug::Log(System.Object)"
        // "IL_0022: nop"
        // "IL_0023: ret"
        // 自定義OpCode
        // Nop, 0, 0
        // Ldloca_S, 0, 0
        // Ldc_R4, 1065353216, 0
        // Ldc_R4, 1065353216, 0
        // Ldc_R4, 1065353216, 0
        // Call, 1, 0
        // Ldloc_0, 0, 0
        // Box, 3, 0
        // Call, 2, 0
        // Nop, 0, 0
        // Ret, 0, 0
        // esp = 0xa6479050
        esp = Execute(method, esp, out unhandledException);
            // esp = 0xa647905c, 因為有1個局部變量
            esp = frame.BasePointer;
            // arg = 0xa6479050, 沒有參數
            var arg = Minus(frame.LocalVarPointer, method.ParameterCount);
            // 處理局部變量
            for (int i = 0; i < method.LocalVariableCount; i++)
                // ct: "UnityEngine.Vector3"
                CLRType cT = (CLRType)t;
                // loc = 0xa6479050
                var loc = Add(v1, i);
                // ct 有 ValueTypeBinder
                if (cT.ValueTypeBinder != null)
                    // 分配 Vector3 的 存儲空間
                    // 
                    stack.AllocValueType(loc, t);
                        // 值類型引用
                        loc->ObjectType = ObjectTypes.ValueTypeObjectReference;
                        // dst = 0xa64a9044
                        var dst = valueTypePtr;
                        // loc = 0xa6479050 指向 valueTypePtr 0xa64a9044
                        *(long*)&loc->Value = (long)dst;
                        dst->ObjectType = ObjectTypes.ValueTypeDescriptor;
                        // Vector3 的 HashCode
                        dst->Value = type.GetHashCode();
                        // 字段數量
                        dst->ValueLow = fieldCount;        
                        // valueTypePtr = 0xa64a9014
                        // 留給 Vector3 的3個字段的空間
                        valueTypePtr = ILIntepreter.Minus(valueTypePtr, fieldCount + 1);                        
                        if (valueTypePtr <= StackBase)                        
                            throw new StackOverflowException();                        
                        InitializeValueTypeObject(type, dst);
                            CLRType t = (CLRType)type;
                            // 3個字段
                            var cnt = t.TotalFieldCount;
                            for(int i = 0; i < cnt; i++)
                            {
                                // it: Single
                                var it = t.OrderedFieldTypes[i] as CLRType;
                                // val = 3個字段的 StackObject* 地址
                                // 0xa64a9038
                                // 0xa64a902c
                                // 0xa64a9020
                                StackObject* val = ILIntepreter.Minus(ptr, i + 1);
                                if (it.IsPrimitive)
                                    StackObject.Initialized(val, it);
                                        else if (t == typeof(float))
                                        {                                        
                                            esp->ObjectType = ObjectTypes.Float;                                        
                                            esp->Value = 0;                                        
                                            esp->ValueLow = 0;                                        
                                        }                                
                            }
                // ct 沒有 ValueTypeBinder
                else
                    obj = ((CLRType)t).CreateDefaultInstance();
                        // TypeForCLR = {UnityEngine.Vector3}
                        createDefaultInstanceDelegate = () => Activator.CreateInstance(TypeForCLR);
                    loc->ObjectType = ObjectTypes.Object;
                    loc->Value = locBase + i;
                    // mStack[0] = Vector3(0.0, 0.0, 0.0)
                    mStack[locBase + i] = obj;                

                
            // bp = 0xa64a9014
            var bp = stack.ValueTypeStackPointer;
            // ValueTypeBasePointer = 0xa64a9014
            ValueTypeBasePointer = bp;
            // 將位於特定索引處的局部變量的地址加載到計算堆棧上(短格式)
            case OpCodeEnum.Ldloca_S:
                // v = 0xa6479050
                var v = Add(frame.LocalVarPointer, ip->TokenInteger);
                // esp: StackObject引用
                esp->ObjectType = ObjectTypes.StackObjectReference;    
                // esp = 0xa647905c, esp 指向 v
                *(long*)&esp->Value = (long)v;        
                // esp = 0xa6479068
                esp++;
            case OpCodeEnum.Ldc_R4:
                // esp->Value = 1065353216
                *(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
                esp->ObjectType = ObjectTypes.Float;
                // esp = 0xa6479074
                esp++;
            case OpCodeEnum.Ldc_R4:
                // esp->Value = 1065353216
                *(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
                esp->ObjectType = ObjectTypes.Float;
                // 0xa6479080
                esp++;
            case OpCodeEnum.Ldc_R4:
                // esp->Value = 1065353216
                *(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
                esp->ObjectType = ObjectTypes.Float;
                // 0xa647908c
                esp++;
            case OpCodeEnum.Call:
                // "UnityEngine.Vector3 Void .ctor(Single, Single, Single)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                if (redirect != null)
                    // esp = 0xa647908c = 
                    // mStack[0] = null;
                    esp = redirect(this, esp, mStack, cm, false);
                        StackObject* ret;
                        
                        // ret = 0xa647905c, ret-Value 指向 0xa6479050
                        ret = ILIntepreter.Minus(esp, 4);
                        // instance = 0xa6479050
                        var instance = ILIntepreter.GetObjectAndResolveReference(ret);
                        // dst = 0xa64a9044
                        // dst->Value = 536870920 = Vector3.GetHashCode
                        // dst->ValueLow = 3
                        var dst = *(StackObject**)&instance->Value;
                        // f = 0xa64a9038 = (ValueTypePtr) - 1
                        var f = ILIntepreter.Minus(dst, 1);
                        // v = 0xa6479068 = (0xa6479050 + 1) + 1
                        var v = ILIntepreter.Minus(esp, 3);
                        // 賦值 0xa64a9038
                        *f = *v;

                        // f = 0xa64a902c = (ValueTypePtr) - 2
                        f = ILIntepreter.Minus(dst, 2);
                        // v = 0xa6479074 = (0xa6479050 + 1) + 2
                        v = ILIntepreter.Minus(esp, 2);
                        // 賦值 0xa64a902c
                        *f = *v;

                        // f = 0xa64a9020 = (ValueTypePtr) - 3
                        f = ILIntepreter.Minus(dst, 3);
                        // v = 0xa6479080 = (0xa6479050 + 1) + 3
                        v = ILIntepreter.Minus(esp, 1);
                        // 賦值 0xa64a9020
                        *f = *v;

                        return ret;    
                else 
                    // 
                    object result = cm.Invoke(this, esp, mStack);
                        
            case OpCodeEnum.Ldloc_0:
                // esp = 0xa647905c
                // v1 = 0xa6479050
                // mStack[0] = null
                CopyToStack(esp, v1, mStack);
                    // dst->Value = -1505062844
                    // dst->ObjectType = ValueTypeObjectReference
                    *dst = *src;
                    if (dst->ObjectType >= ObjectTypes.Object)
                    {
                        dst->Value = mStack.Count;
                        var obj = mStack[src->Value];
                        mStack.Add(obj);
                    }
                // esp = 0xa6479068
                esp++
            case OpCodeEnum.Box:
                // objRef = 0xa647905c
                objRef = esp - 1;
                // type = "UnityEngine.Vector3" 獲取要操作的類型
                type = domain.GetType(ip->TokenInteger);
                // 有ValueTypeBinder 的情況下
                if(objRef->ObjectType== ObjectTypes.ValueTypeObjectReference)                
                {
                    // 解析 0xa647905c->Value = 0xa64a9044 = ValueTypePtr
                    dst = ILIntepreter.ResolveReference(objRef);
                    // 獲取到 Vector3: CLRType
                    var vt = domain.GetType(dst->Value);
                    if (vt != type)
                        throw new InvalidCastException();
                    // 調用 Vector3 的 ValueTypeBinder.ToObject
                    object ins = ((CLRType)vt).ValueTypeBinder.ToObject(dst, mStack);
                        // new Vector3()
                        T obj = new T();
                        // 
                        AssignFromStack(ref obj, esp, managedStack);
                            // 獲取 0xa64a9038
                            var v = ILIntepreter.Minus(ptr, 1);
                            // 賦值 給 x
                            ins.x = *(float*)&v->Value;
                            // 獲取 0xa64a902c
                            v = ILIntepreter.Minus(ptr, 2);
                            // 賦值給 y
                            ins.y = *(float*)&v->Value;
                            // 獲取 0xa64a9020
                            v = ILIntepreter.Minus(ptr, 3);
                            // 賦值給z
                            ins.z = *(float*)&v->Value;                        
                            FreeStackValueType(objRef);                    
                            esp = PushObject(objRef, mStack, ins, true);

                        
                        return obj;
                        
                    FreeStackValueType(objRef);
                    esp = PushObject(objRef, mStack, ins, true);
                        // esp = 0xa647905c
                        esp->ObjectType = ObjectTypes.Object;
                        esp->Value = mStack.Count;
                        // mStack[0] = null
                        // mStack[1] = Vector3(1.0, 1.0, 1.0)
                        mStack.Add(obj);
                        // 0xa6479068
                        return esp + 1
                }
            case OpCodeEnum.Call:
                // m = "UnityEngine.Debug Void Log(System.Object)"
                IMethod m = domain.GetMethod(ip->TokenInteger);
                    object result = cm.Invoke(this, esp, mStack);
                        for (int i = paramCount; i >= 1; i--)
                        {
                            // esp = 0xa6479068
                            // p = 0xa647905c
                            var p = Minus(esp, i);
                            var pt = this.param[paramCount - i].ParameterType;
                            // obj = Vector3(1.0, 1.0, 1.0)
                            var obj = pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
                            obj = ILIntepreter.CheckAndCloneValueType(obj, appdomain);
                                // t = UnityEngine.Vector3
                                var t = domain.GetType(type);

                                return ((CLRType)t).PerformMemberwiseClone(obj);
                                    var memberwiseClone = clrType.GetMethod("MemberwiseClone", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
                                    memberwiseCloneDelegate = (ref object t) => memberwiseClone.Invoke(t, null);

                                    return memberwiseCloneDelegate(ref target);
                                
                            param[paramCount - i] = obj;
                        }
                        // param[0] = Vector3(1.0, 1.0, 1.0)
                        res = def.Invoke(instance, param);
                        
                        // esp = 0xa647905c
                        esp = Minus(esp, paramCount);
                        
            // esp = 0xa647905c
            return stack.PopFrame(ref frame, esp);
                // returnVal = 0xa6479050
                StackObject* returnVal = esp - 1;
                // method = "HotFix_Project.TestValueType.RunTest()"
                var method = frame.Method;
                // ret = 0xa6479050
                StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
                // 移除 mStack 里的內容
                ((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
                // 0xa64a9044
                valueTypePtr = frame.ValueTypeBasePointer;
                // ret = 0xa6479050
                return ret;
ValueTypeBinder 再探

 

 

 

 

 

 

熱更工程

using System;
using System.Collections.Generic;

namespace HotFix_Project
{
    public class TestDelegate
    {
        static TestDelegateMethod delegateMethod;

        public static void Initialize()
        {
            delegateMethod = Method;
        }

        public static void RunTest()
        {
            delegateMethod(123);
        }

        public static void Initialize2()
        {
            DelegateDemo.TestMethodDelegate = Method;
        }

        public static void RunTest2()
        {
            DelegateDemo.TestMethodDelegate(123);
        }

        static void Method(int a)
        {
            UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
        }

        static string Function(int a)
        {
            return a.ToString();
        }

        static void Action(string a)
        {
            UnityEngine.Debug.Log("!! TestDelegate.Action, a = " + a);
        }
    }
}



主工程


public delegate void TestDelegateMethod(int a);
public delegate string TestDelegateFunction(int a);


public class DelegateDemo : MonoBehaviour
{
    public static TestDelegateMethod TestMethodDelegate;
    public static TestDelegateFunction TestFunctionDelegate;
    public static System.Action<string> TestActionDelegate;
    

Debug.Log("完全在熱更DLL內部使用的委托,直接可用,不需要做任何處理");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
    // 原始IL
    // "IL_0000: nop"
    // "IL_0001: ldnull"
    // "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
    // "IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
    // "IL_000d: stsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
    // "IL_0012: ret"
    // 自定義 IL
    // Nop, 0, 0
    // Ldnull, 0, 0
    // Ldftn, 1, 0
    // Newobj, 2, 0
    // Stsfld, 0, 17179869184
    // Ret, 0, 0
    esp = Execute(method, esp, out unhandledException);
        // 將指向實現特定方法的本機代碼的非托管指針(native int 類型)推送到計算堆棧上。
        case OpCodeEnum.Ldftn:
            // m = "HotFix_Project.TestDelegate.Method(Int32 a)"
            IMethod m = domain.GetMethod(ip->TokenInteger);        
            esp = PushObject(esp, mStack, m);
        // new 一個 TestDelegateMethod
        case OpCodeEnum.Newobj:
            // m = "Void .ctor(Object, IntPtr)", DeclaringType = "TestDelegateMethod"
            IMethod m = domain.GetMethod(ip->TokenInteger);
            // 如果方法的聲明類型是委托
            if (cm.DeclearingType.IsDelegate)
                objRef = GetObjectAndResolveReference(esp - 1 - 1);
                // mi = "HotFix_Project.TestDelegate.Method(Int32 a)"
                var mi = (IMethod)mStack[(esp - 1)->Value];
                // 如果 mi 是 ILMethod
                if (mi is ILMethod)
                    // 如果 DelegateAdapter 為空
                    if (((ILMethod)mi).DelegateAdapter == null)
                        // 查找然后賦值
                        ((ILMethod)mi).DelegateAdapter = domain.DelegateManager.FindDelegateAdapter(null, (ILMethod)mi);
                            // dummyAdapter
                            res = dummyAdapter.Instantiate(appdomain, instance, method);
                                return new DummyDelegateAdapter(appdomain, instance, method);
                                
                    dele = ((ILMethod)mi).DelegateAdapter;
        // 用來自計算堆棧的值替換靜態字段的值
        case OpCodeEnum.Stsfld:
            // type = "HotFix_Project.TestDelegate"
            type = AppDomain.GetType((int)(ip->TokenLong >> 32));
            t.StaticInstance.AssignFromStack((int)ip->TokenLong, val, AppDomain, mStack);
            

                    
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);
    // 原始IL
    // "IL_0000: nop"
    // "IL_0001: ldsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
    // "IL_0006: ldc.i4.s 123"
    // "IL_0008: callvirt System.Void TestDelegateMethod::Invoke(System.Int32)"
    // "IL_000d: nop"
    // "IL_000e: ret"
    // 自定義IL
    // Nop, 0, 0
    // Ldsfld, 0, 17179869184
    // Ldc_I4_S, 123, 0
    // Callvirt, 3, 0
    // Nop, 0, 0
    // Ret, 0, 0
    esp = Execute(method, esp, out unhandledException);
        case OpCodeEnum.Ldsfld:
            // type = "HotFix_Project.TestDelegate"
            type = AppDomain.GetType((int)(ip->TokenLong >> 32));
        case OpCodeEnum.Ldc_I4_S:
            // esp->Value = 13
            // esp->ValueLow = 108
            esp->Value = ip->TokenInteger;            
            esp->ObjectType = ObjectTypes.Integer;
            esp++;
        case OpCodeEnum.Callvirt:
            // m = "Void Invoke(Int32)", DeclaringType = "TestDelegateMethod"
            IMethod m = domain.GetMethod(ip->TokenInteger);
            
            //
            if (instance is IDelegateAdapter)
            {
                // instance = "HotFix_Project.TestDelegate.Method(Int32 a)"
                esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);
                    var ebp = esp;
                    esp = ILInvokeSub(intp, esp, mStack);
                        // 調用委托指向的函數
                        // method = "HotFix_Project.TestDelegate.Method(Int32 a)"
                        // 原始IL
                        // "IL_0000: nop"
                        // "IL_0001: ldstr \"!! TestDelegate.Method, a = \""
                        // "IL_0006: ldarg.0"
                        // "IL_0007: box System.Int32"
                        // "IL_000c: call System.String System.String::Concat(System.Object,System.Object)"
                        // "IL_0011: call System.Void UnityEngine.Debug::Log(System.Object)"
                        // "IL_0016: nop"
                        // "IL_0017: ret"
                        // 自定義IL
                        // Nop, 0, 0
                        // Ldstr, 0, -1182677902
                        // Ldarg_0, 0, 0
                        // Box, 9, 0
                        // Call, 4, 0
                        // Call, 5, 0
                        // Nop, 0, 0
                        // Ret, 0, 0
                        var ret = intp.Execute(method, esp, out unhandled);
                    
                    return ClearStack(intp, esp, ebp, mStack);
                
                processed = true;
            }
            
            
            
Debug.Log("如果需要跨域調用委托(將熱更DLL里面的委托實例傳到Unity主工程用), 就需要注冊適配器,不然就會像下面這樣");
try {
    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
        // 原始IL
        // "IL_0000: nop"
        // "IL_0001: ldnull"
        // "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
        // "IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
        // "IL_000d: stsfld TestDelegateMethod DelegateDemo::TestMethodDelegate"
        // "IL_0012: ret"
        // 自定義IL
        // Nop, 0, 0
        // Ldnull, 0, 0
        // Ldftn, 1, 0
        // Newobj, 2, 0
        // Stsfld, 0, 2305843113963799552
        // Ret, 0, 0
        esp = Execute(method, esp, out unhandledException);
            case OpCodeEnum.Ldftn:
                // m = "HotFix_Project.TestDelegate.Method(Int32 a)", DeclaringType = "HotFix_Project.TestDelegate"
                IMethod m = domain.GetMethod(ip->TokenInteger);                
                esp = PushObject(esp, mStack, m);
            case OpCodeEnum.Newobj:
                // m = "Void .ctor(Object, IntPtr)", DeclaringType = "TestDelegateMethod"
                IMethod m = domain.GetMethod(ip->TokenInteger);
            case OpCodeEnum.Stsfld:
                // type = "DelegateDemo"
                type = AppDomain.GetType((int)(ip->TokenLong >> 32));
                t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));
                    // pt: Type = {TestDelegateMethod}
                    // obj = "HotFix_Project.TestDelegate.Method(Int32 a)"
                    CheckCLRTypes(this Type pt, object obj)
                        if ((typeFlags & TypeFlags.IsDelegate) != 0)
                            // 不是
                            if (obj is Delegate)
                                return obj;
                            // 不是
                            if (pt == typeof(Delegate))            
                                return ((IDelegateAdapter)obj).Delegate;    
                            // pt: {System.RuntimeType} = {TestDelegateMethod}
                            // obj: {ILRuntime.Runtime.Intepreter.DummyDelegateAdapter} = "HotFix_Project.TestDelegate.Method(Int32 a)"
                            return ((IDelegateAdapter)obj).GetConvertor(pt);        
                            
                                if (converters == null)
                                    converters = new Dictionary<System.Type, Delegate>(new ByReferenceKeyComparer<Type>());
                                Delegate res;
                                if (converters.TryGetValue(type, out res))
                                    return res;
                                else
                                {
                                    // 
                                    res = appdomain.DelegateManager.ConvertToDelegate(type, this);
                                        Func<Delegate, Delegate> func;
                                        // 是 dummyAdapter, 拋出異常
                                        if(adapter is DummyDelegateAdapter)
                                        {
                                            DelegateAdapter.ThrowAdapterNotFound(adapter.Method);
                                            return null;
                                        }
                                        if (clrDelegates.TryGetValue(clrDelegateType, out func))
                                        {
                                            return func(adapter.Delegate);
                                        }
                                        else
                                        {                                    
                                    
                                    converters[type] = res;
                                    return res;
                                }                                
        
} catch (System.Exception ex) {
    Debug.LogError(ex.ToString());
}
//為了演示,清除適配器緩存,實際使用中不要這么做
ClearDelegateCache();
Debug.Log("這是因為iOS的IL2CPP模式下,不能動態生成類型,為了避免出現不可預知的問題,我們沒有通過反射的方式創建委托實例,因此需要手動進行一些注冊");
Debug.Log("首先需要注冊委托適配器,剛剛的報錯的錯誤提示中,有提示需要的注冊代碼");
//下面這些注冊代碼,正式使用的時候,應該寫在InitializeILRuntime中
//TestDelegateMethod, 這個委托類型為有個參數為int的方法,注冊僅需要注冊不同的參數搭配即可
appdomain.DelegateManager.RegisterMethodDelegate<int>();
    var type = typeof(T);
    if (type.IsSubclassOf(typeof(Delegate)))
        // type = {System.Action`1[System.Int32]}
        // action = {System.Func`2[[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
        clrDelegates[type] = action;
        
        
//帶返回值的委托的話需要用RegisterFunctionDelegate,返回類型為最后一個
//appdomain.DelegateManager.RegisterFunctionDelegate<int, string>();
//Action<string> 的參數為一個string
//appdomain.DelegateManager.RegisterMethodDelegate<string>();


Debug.Log("注冊完畢后再次運行會發現這次會報另外的錯誤");
try
{
    appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
        esp = Execute(method, esp, out unhandledException);
            t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));
                return ((IDelegateAdapter)obj).GetConvertor(pt);
                    // type  = {TestDelegateMethod}
                    // this: {ILRuntime.Runtime.Intepreter.MethodDelegateAdapter`1[System.Int32]} = "HotFix_Project.TestDelegate.Method(Int32 a)"
                    res = appdomain.DelegateManager.ConvertToDelegate(type, this);
                    // 找不到 報錯
                    if (clrDelegates.TryGetValue(clrDelegateType, out func))
                
}
catch (System.Exception ex)
{
    Debug.LogError(ex.ToString());
}

Debug.Log("ILRuntime內部是用Action和Func這兩個系統內置的委托類型來創建實例的,所以其他的委托類型都需要寫轉換器");
Debug.Log("將Action或者Func轉換成目標委托類型");

appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) =>
{
    //轉換器的目的是把Action或者Func轉換成正確的類型,這里則是把Action<int>轉換成TestDelegateMethod
    return new TestDelegateMethod((a) =>
    {
        //調用委托實例
        ((System.Action<int>)action)(a);
    });
});
//對於TestDelegateFunction同理,只是是將Func<int, string>轉換成TestDelegateFunction
appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) =>
{
    return new TestDelegateFunction((a) =>
    {
        return ((System.Func<int, string>)action)(a);
    });
});

//下面再舉一個這個Demo中沒有用到,但是UGUI經常遇到的一個委托,例如UnityAction<float>
appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<float>>((action) =>
{
    return new UnityEngine.Events.UnityAction<float>((a) =>
    {
        ((System.Action<float>)action)(a);
    });
});


Debug.Log("現在我們再來運行一次");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest2", null, null);
    // pt = {TestDelegateMethod}
    ((IDelegateAdapter)obj).GetConvertor(pt);
        // this = "HotFix_Project.TestDelegate.Method(Int32 a)"
        res = appdomain.DelegateManager.ConvertToDelegate(type, this);
            ConvertToDelegate
                // func = {System.Func`2[[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
                // func.method = "System.Delegate <OnHotFixLoaded>b__10_0(System.Delegate)"
                // func.Target = {DelegateDemo+<>c}                
                if (clrDelegates.TryGetValue(clrDelegateType, out func))
                    // adapter.Delegate = {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
                    // Delegate.Method = "Void InvokeILMethod(Int32)"
                    // Delegate.Target = "HotFix_Project.TestDelegate.Method(Int32 a)"
                    func(adapter.Delegate);

Debug.Log("運行成功,我們可以看見,用Action或者Func當作委托類型的話,可以避免寫轉換器,所以項目中在不必要的情況下盡量只用Action和Func");
Debug.Log("另外應該盡量減少不必要的跨域委托調用,如果委托只在熱更DLL中用,是不需要進行任何注冊的");
Debug.Log("---------");
Debug.Log("我們再來在Unity主工程中調用一下剛剛的委托試試");
TestMethodDelegate(789);
var str = TestFunctionDelegate(098);
Debug.Log("!! OnHotFixLoaded str = " + str);
TestActionDelegate("Hello From Unity Main Project");
Delegate

 

 

 

 

[MenuItem("ILRuntime/Generate CLR Binding Code by Analysis")]
static void GenerateCLRBindingByAnalysis()
{
    //用新的分析熱更dll調用引用來生成綁定代碼
    
    ILRuntime.Runtime.Enviorment.AppDomain domain = new ILRuntime.Runtime.Enviorment.AppDomain();
    using (System.IO.FileStream fs = new System.IO.FileStream("Assets/StreamingAssets/HotFix_Project.dll", System.IO.FileMode.Open, System.IO.FileAccess.Read))
    {
        // 用AppDomain 加載 hotfix.dll
        domain.LoadAssembly(fs);

        //Crossbind Adapter is needed to generate the correct binding code
        InitILRuntime(domain);
            //這里需要注冊所有熱更DLL中用到的跨域繼承Adapter,否則無法正確抓取引用
            domain.RegisterCrossBindingAdaptor(new MonoBehaviourAdapter());
            domain.RegisterCrossBindingAdaptor(new CoroutineAdapter());
            domain.RegisterCrossBindingAdaptor(new InheritanceAdapter());
            domain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());        
        
        ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(domain, "Assets/ILRuntime/Generated");
            if (domain == null)
                return;
            // outputPath = "Assets/ILRuntime/Generated"
            if (!System.IO.Directory.Exists(outputPath))
                System.IO.Directory.CreateDirectory(outputPath);
            Dictionary<Type, CLRBindingGenerateInfo> infos = new Dictionary<Type, CLRBindingGenerateInfo>(new ByReferenceKeyComparer<Type>());
            // 1.初始化 ILType 的 IMethod, 轉換 ILRuntime.OpCode
            // 2. 將 CLRType的Type 的相關信息添加到 Dictionary<Type, CLRBindingGenerateInfo> infos
            CrawlAppdomain(domain, infos);
                // hotfix.dll 里的類型    e.g. "HotFix_Project.InstanceClass"
                // 系統類型    e.g. System.Int32
                // 適配器 e.g. MonoBehaviourAdapter+Adaptor
                // Unity里的類型    e.g. UnityEngine.Vector3
                var arr = domain.LoadedTypes.Values.ToArray();
                //Prewarm
                foreach (var type in arr)
                {
                    // 適配器不是 ILType e.g. ILRuntime.Runtime.Adaptors.AttributeAdaptor+Adaptor, 不處理
                    // 熱更里的類型是 ILType e.g. "HotFix_Project.InstanceClass"
                    // System.Void 等不是 ILType, 不處理
                    // UnityEngine.Vector3 等不是 ILType, 不處理
                    if (type is CLR.TypeSystem.ILType)
                    {
                        // 如果類型有 泛型參數 則跳過
                        if (type.HasGenericParameter)
                            continue;
                        // 通過調用 ILType.GetMethods 將Mono.Cecil.MethodDefinition 轉換為 IMethod, 並添加到 methods
                        var methods = type.GetMethods().ToList();
                        // 同上 轉換構造函數, 並添加到 methods
                        foreach (var i in ((CLR.TypeSystem.ILType)type).GetConstructors())
                            methods.Add(i);
                        // 同上 轉換靜態構造函數, 並添加到 methods
                        if (((CLR.TypeSystem.ILType)type).GetStaticConstroctor() != null)
                            methods.Add(((CLR.TypeSystem.ILType)type).GetStaticConstroctor());
                        foreach (var j in methods)
                        {
                            CLR.Method.ILMethod method = j as CLR.Method.ILMethod;
                            if (method != null)
                            {
                                if (method.GenericParameterCount > 0 && !method.IsGenericInstance)
                                    continue;
                                // 這里通過調用 method.Body 將 Mono.Cecil.Instruction 轉換為 ILRuntime.OpCode
                                var body = method.Body;
                            }
                        }
                    }
                }
                
                // 重新遍歷, 因為又加入了不少新的類型
                arr = domain.LoadedTypes.Values.ToArray();
                foreach (var type in arr)
                {
                    if (type is CLR.TypeSystem.ILType)
                    {
                        if (type.TypeForCLR.IsByRef || type.HasGenericParameter)
                            continue;
                        // 獲取所有的方法, e.g.
                        // "HotFix_Project.InstanceClass.get_ID()"
                        // "HotFix_Project.InstanceClass.StaticFunTest()"
                        // "HotFix_Project.InstanceClass.StaticFunTest2(Int32 a)"
                        // "HotFix_Project.InstanceClass.GenericMethod(T a)"
                        var methods = type.GetMethods().ToList();
                        // 獲取構造函數, e.g.
                        // "HotFix_Project.InstanceClass..ctor()"
                        // "HotFix_Project.InstanceClass..ctor(Int32 id)"
                        foreach (var i in ((CLR.TypeSystem.ILType)type).GetConstructors())
                            methods.Add(i);
                        // 獲取靜態構造函數
                        if (((CLR.TypeSystem.ILType)type).GetStaticConstroctor() != null)
                            methods.Add(((CLR.TypeSystem.ILType)type).GetStaticConstroctor());
                        // 遍歷這些方法
                        foreach (var j in methods)
                        {
                            // e.g "HotFix_Project.InstanceClass..ctor()"
                            CLR.Method.ILMethod method = j as CLR.Method.ILMethod;
                            if (method != null)
                            {
                                if (method.GenericParameterCount > 0 && !method.IsGenericInstance)
                                    continue;
                                // body: OpCode[]
                                // Ldarg_0, 0, 0
                                // Call, 0, 1
                                // Nop, 0, 0
                                // Nop, 0, 0
                                // Ldstr, 0, -2078173280
                                // Call, 24, 0
                                // Ldarg_0, 0, 0
                                // Ldc_I4_0, 0, 0
                                // Stfld, 0, 335007449088
                                // Ret, 0, 0
                                var body = method.Body;
                                foreach (var ins in body)
                                {
                                    switch (ins.Code)
                                    {
                                        case Intepreter.OpCodes.OpCodeEnum.Newobj:
                                            {
                                                CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod;
                                                // 如果這個方法是 CLRMethod
                                                // e.g. "System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance]"    .ctor
                                                if (m != null)
                                                {
                                                    if (m.DeclearingType.IsDelegate)
                                                        continue;
                                                    Type t = m.DeclearingType.TypeForCLR;
                                                    CLRBindingGenerateInfo info;
                                                    if (!infos.TryGetValue(t, out info))
                                                    {
                                                        info = CreateNewBindingInfo(t);
                                                        // e.g. "[System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                                                        infos[t] = info;
                                                    }
                                                    if (m.IsConstructor)
                                                        info.Constructors.Add(m.ConstructorInfo);
                                                    else
                                                        info.Methods.Add(m.MethodInfo);
                                                }
                                            }
                                            break;
                                        case Intepreter.OpCodes.OpCodeEnum.Ldfld:
                                        case Intepreter.OpCodes.OpCodeEnum.Stfld:
                                        case Intepreter.OpCodes.OpCodeEnum.Ldflda:
                                        case Intepreter.OpCodes.OpCodeEnum.Ldsfld:
                                        case Intepreter.OpCodes.OpCodeEnum.Ldsflda:
                                        case Intepreter.OpCodes.OpCodeEnum.Stsfld:
                                            {
                                                // ins.TokenLong == 335007449088
                                                // ins.TokenLong >> 32 = 335007449088 / (2 ^ 32) = 335007449088 / 4294967296 = 78
                                                
                                                // t = DelegateDemo    是 CLRType
                                                // 
                                                var t = domain.GetType((int)(ins.TokenLong >> 32)) as CLR.TypeSystem.CLRType;
                                                if(t != null)
                                                {
                                                    // fi = "TestDelegateMethod TestMethodDelegate"
                                                    var fi = t.GetField((int)ins.TokenLong);
                                                    if (fi != null && fi.IsPublic)
                                                    {
                                                        CLRBindingGenerateInfo info;
                                                        if (!infos.TryGetValue(t.TypeForCLR, out info))
                                                        {
                                                            info = CreateNewBindingInfo(t.TypeForCLR);
                                                            infos[t.TypeForCLR] = info;
                                                        }
                                                        if(ins.Code == Intepreter.OpCodes.OpCodeEnum.Stfld || ins.Code == Intepreter.OpCodes.OpCodeEnum.Stsfld)
                                                        {
                                                            if (t.IsValueType)
                                                            {
                                                                info.ValueTypeNeeded = true;
                                                                info.DefaultInstanceNeeded = true;
                                                            }
                                                        }
                                                        if (t.TypeForCLR.CheckCanPinn() || !t.IsValueType)
                                                            info.Fields.Add(fi);
                                                    }
                                                }
                                            }
                                            break;
                                        case Intepreter.OpCodes.OpCodeEnum.Ldtoken:
                                            {
                                                if (ins.TokenInteger == 0)
                                                {
                                                    var t = domain.GetType((int)(ins.TokenLong >> 32)) as CLR.TypeSystem.CLRType;
                                                    if (t != null)
                                                    {
                                                        var fi = t.GetField((int)ins.TokenLong);
                                                        if (fi != null)
                                                        {
                                                            CLRBindingGenerateInfo info;
                                                            if (!infos.TryGetValue(t.TypeForCLR, out info))
                                                            {
                                                                info = CreateNewBindingInfo(t.TypeForCLR);
                                                                infos[t.TypeForCLR] = info;
                                                            }
                                                            info.Fields.Add(fi);
                                                        }
                                                    }
                                                }
                                            }
                                            break;
                                        case Intepreter.OpCodes.OpCodeEnum.Newarr:
                                            {
                                                // t = "System.Object", t.ArrayType = "System.Object[]"
                                                var t = domain.GetType(ins.TokenInteger) as CLR.TypeSystem.CLRType;
                                                if(t != null)
                                                {
                                                    CLRBindingGenerateInfo info;
                                                    if (!infos.TryGetValue(t.TypeForCLR, out info))
                                                    {
                                                        info = CreateNewBindingInfo(t.TypeForCLR);
                                                        infos[t.TypeForCLR] = info;
                                                    }
                                                    info.ArrayNeeded = true;
                                                }
                                            }
                                            break;
                                        case Intepreter.OpCodes.OpCodeEnum.Call:
                                        case Intepreter.OpCodes.OpCodeEnum.Callvirt:
                                            {
                                                CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod;
                                                // 如果這個方法是 CLRMethod
                                                // e.g. "System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance]"    "Void Add(ILRuntime.Runtime.Intepreter.ILTypeInstance)"
                                                if (m != null)
                                                {
                                                    //Cannot explicit call base class's constructor directly
                                                    if (m.IsConstructor && m.DeclearingType.CanAssignTo(((CLR.TypeSystem.ILType)type).FirstCLRBaseType))
                                                        continue;
                                                    if (m.IsConstructor)
                                                    {
                                                        if (!m.ConstructorInfo.IsPublic)
                                                            continue;
                                                        Type t = m.DeclearingType.TypeForCLR;
                                                        CLRBindingGenerateInfo info;
                                                        if (!infos.TryGetValue(t, out info))
                                                        {
                                                            info = CreateNewBindingInfo(t);
                                                            infos[t] = info;
                                                        }

                                                        info.Constructors.Add(m.ConstructorInfo);
                                                    }
                                                    else
                                                    {
                                                        if (!m.MethodInfo.IsPublic)
                                                            continue;
                                                        Type t = m.DeclearingType.TypeForCLR;
                                                        CLRBindingGenerateInfo info;
                                                        if (!infos.TryGetValue(t, out info))
                                                        {
                                                            info = CreateNewBindingInfo(t);
                                                            infos[t] = info;
                                                        }
                                                        
                                                        // 添加要生成的方法
                                                        info.Methods.Add(m.MethodInfo);
                                                    }
                                                }
                                            }
                                            break;
                                    }
                                }
                            }
                        }
                    }
                }            
            
            // 刪除舊文件
            string[] oldFiles = System.IO.Directory.GetFiles(outputPath, "*.cs");
            foreach (var i in oldFiles)
            {
                System.IO.File.Delete(i);
            }

            if (valueTypeBinders == null)
                valueTypeBinders = new List<Type>(domain.ValueTypeBinders.Keys);
            
            // 不想包含的 MethodBase
            HashSet<MethodBase> excludeMethods = null;
            // 不想包含的 FieldInfo
            HashSet<FieldInfo> excludeFields = null;
            HashSet<string> files = new HashSet<string>();
            List<string> clsNames = new List<string>();

            // 0, "[System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor()"
                Fields
                Methods
                    "Void Add(ILRuntime.Runtime.Intepreter.ILTypeInstance)"
                    "ILRuntime.Runtime.Intepreter.ILTypeInstance get_Item(Int32)"
            // 1, "[System.Collections.Generic.Dictionary`2[System.String,ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor()"
                Fields
                Methods
                    "Void set_Item(System.String, ILRuntime.Runtime.Intepreter.ILTypeInstance)"
                    "ILRuntime.Runtime.Intepreter.ILTypeInstance get_Item(System.String)"
            // 2, "[System.Collections.Generic.Dictionary`2[System.String,System.Int32], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor()"
                Fields
                Methods
                    "Void set_Item(System.String, Int32)"
                    "Int32 get_Item(System.String)"
            // 3, "[LitJson.JsonMapper, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "System.String ToJson(System.Object)"
                    "ILRuntime.Runtime.Intepreter.ILTypeInstance ToObject[ILTypeInstance](System.String)"
            // 4, "[UnityEngine.Debug, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "Void Log(System.Object)"
                    "Void LogFormat(System.String, System.Object[])"
            // 5, "[System.Diagnostics.Stopwatch, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor()"
                Fields
                Methods
                    "Void Start()"
                    "Void Stop()"
                    "Int64 get_ElapsedMilliseconds()"
            // 6, "[UnityEngine.Vector3, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor(Single, Single, Single)"
                Fields
                Methods
                    "UnityEngine.Vector3 get_one()"
                    "UnityEngine.Vector3 op_Addition(UnityEngine.Vector3, UnityEngine.Vector3)"
                    "UnityEngine.Vector3 op_Subtraction(UnityEngine.Vector3, UnityEngine.Vector3)"
                    "UnityEngine.Vector3 op_Multiply(UnityEngine.Vector3, Single)"
                    "UnityEngine.Vector3 op_Multiply(Single, UnityEngine.Vector3)"
                    "UnityEngine.Vector3 op_Division(UnityEngine.Vector3, Single)"
                    "UnityEngine.Vector3 op_UnaryNegation(UnityEngine.Vector3)"
                    "Boolean op_Equality(UnityEngine.Vector3, UnityEngine.Vector3)"
                    "Boolean op_Inequality(UnityEngine.Vector3, UnityEngine.Vector3)"
                    "Single Dot(UnityEngine.Vector3, UnityEngine.Vector3)"
                    "UnityEngine.Vector3 Cross(UnityEngine.Vector3, UnityEngine.Vector3)"
                    "Single Distance(UnityEngine.Vector3, UnityEngine.Vector3)"
                    "Single get_magnitude()"
                    "UnityEngine.Vector3 get_normalized()"
                    "Single get_sqrMagnitude()"
                    "UnityEngine.Vector3 get_zero()"
                    
            // 7, "[System.String, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "System.String Concat(System.Object, System.Object)"
                    "System.String Concat(System.String, System.String)"
                    
            // 8, "[System.Boolean, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "System.String ToString()"
                    
            // 9, "[System.Object, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
            
            // 10, "[UnityEngine.Quaternion, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor(Single, Single, Single, Single)"
                Fields
                Methods        
                    "UnityEngine.Quaternion get_identity()"
                    "UnityEngine.Quaternion op_Multiply(UnityEngine.Quaternion, UnityEngine.Quaternion)"
                    "UnityEngine.Vector3 op_Multiply(UnityEngine.Quaternion, UnityEngine.Vector3)"
                    "Boolean op_Equality(UnityEngine.Quaternion, UnityEngine.Quaternion)"
                    "Boolean op_Inequality(UnityEngine.Quaternion, UnityEngine.Quaternion)"
                    "Single Dot(UnityEngine.Quaternion, UnityEngine.Quaternion)"
                    "Single Angle(UnityEngine.Quaternion, UnityEngine.Quaternion)"
                    "UnityEngine.Vector3 get_eulerAngles()"
                    "UnityEngine.Quaternion Euler(UnityEngine.Vector3)"
                    "UnityEngine.Quaternion Euler(Single, Single, Single)"
            
            // 11, "[UnityEngine.Vector2, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor(Single, Single)"
                Fields
                Methods
                    "UnityEngine.Vector2 get_one()"
                    "UnityEngine.Vector2 op_Addition(UnityEngine.Vector2, UnityEngine.Vector2)"
                    "UnityEngine.Vector2 op_Subtraction(UnityEngine.Vector2, UnityEngine.Vector2)"
                    "UnityEngine.Vector2 op_Multiply(UnityEngine.Vector2, Single)"
                    "UnityEngine.Vector2 op_Multiply(Single, UnityEngine.Vector2)"
                    "UnityEngine.Vector2 op_Division(UnityEngine.Vector2, Single)"
                    "UnityEngine.Vector2 op_UnaryNegation(UnityEngine.Vector2)"
                    "Boolean op_Equality(UnityEngine.Vector2, UnityEngine.Vector2)"
                    "Boolean op_Inequality(UnityEngine.Vector2, UnityEngine.Vector2)"
                    "UnityEngine.Vector3 op_Implicit(UnityEngine.Vector2)"
                    "UnityEngine.Vector2 op_Implicit(UnityEngine.Vector3)"
                    "Single Dot(UnityEngine.Vector2, UnityEngine.Vector2)"
                    "Single Distance(UnityEngine.Vector2, UnityEngine.Vector2)"
                    "Single get_magnitude()"
                    "UnityEngine.Vector2 get_normalized()"
                    "Single get_sqrMagnitude()"
                    "UnityEngine.Vector2 get_zero()"
            
            
            // 12, "[UnityEngine.Time, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "Single get_time()"
            
            // 13, "[UnityEngine.GameObject, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "Adaptor AddComponent[Adaptor]()"
                    "Adaptor GetComponent[Adaptor]()"
            
            // 14, "[CoroutineDemo, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods        
                    "CoroutineDemo get_Instance()"
                    "Void DoCoroutine(System.Collections.IEnumerator)"
            
            // 15, "[UnityEngine.WaitForSeconds, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor(Single)"
                Fields
                Methods            
            
            // 16, "[System.NotSupportedException, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                    "Void .ctor()"
                Fields
                Methods            
            
            // 17, "[CLRBindingTestClass, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods    
                    "Single DoSomeTest(Int32, Single)"
            
            // 18, "[TestClassBase, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "Void TestVirtual(System.String)"
            
            // 19, "[TestDelegateMethod, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods    
                    "Void Invoke(Int32)"
            
            // 20, "[TestDelegateFunction, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods        
                    "System.String Invoke(Int32)"                
            
            // 21, "[System.Action`1[System.String], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods        
                    "Void Invoke(System.String)"
            
            // 22, "[DelegateDemo, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                    "TestDelegateMethod TestMethodDelegate"
                    "TestDelegateFunction TestFunctionDelegate"
                    "System.Action`1[System.String] TestActionDelegate"
                Methods            
            
            // 23, "[System.Int32, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
                Constructors
                Fields
                Methods
                    "System.String ToString()"
            
            foreach (var info in infos)
            {
                if (!info.Value.NeedGenerate)
                    continue;
                Type i = info.Value.Type;

                //CLR binding for delegate is important for cross domain invocation,so it should be generated
                //if (i.BaseType == typeof(MulticastDelegate))
                //    continue;

                string clsName, realClsName;
                bool isByRef;
                // 如果有 ObsoleteAttribute 就跳過
                if (i.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > 0)
                    continue;
                i.GetClassName(out clsName, out realClsName, out isByRef);
                if (clsNames.Contains(clsName))
                    clsName = clsName + "_t";
                // e.g. "System_Collections_Generic_List_1_ILTypeInstance_Binding"
                clsNames.Add(clsName);
                
                // e.g. "Assets/ILRuntime/Generated/System_Collections_Generic_List_1_ILTypeInstance_Binding"
                string oFileName = outputPath + "/" + clsName;
                int len = Math.Min(oFileName.Length, 100);
                if (len < oFileName.Length)
                    oFileName = oFileName.Substring(0, len) + "_t";
                while (files.Contains(oFileName))
                    oFileName = oFileName + "_t";
                files.Add(oFileName);
                // e.g. "Assets/ILRuntime/Generated/System_Collections_Generic_List_1_ILTypeInstance_Binding.cs"
                oFileName = oFileName + ".cs";
                using (System.IO.StreamWriter sw = new System.IO.StreamWriter(oFileName, false, new UTF8Encoding(false)))
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append(@"using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;

using ILRuntime.CLR.TypeSystem;
using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.Runtime.Stack;
using ILRuntime.Reflection;
using ILRuntime.CLR.Utils;

namespace ILRuntime.Runtime.Generated
{
    unsafe class ");
                    sb.AppendLine(clsName);
                    sb.Append(@"    {
        public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app)
        {
");
                    string flagDef =    "            BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;";
                    string methodDef =  "            MethodBase method;";
                    string methodsDef = "            MethodInfo[] methods = type.GetMethods(flag).Where(t => !t.IsGenericMethod).ToArray();";
                    string fieldDef =   "            FieldInfo field;";
                    string argsDef =    "            Type[] args;";
                    string typeDef = string.Format("            Type type = typeof({0});", realClsName);

                    bool needMethods;
                    MethodInfo[] methods = info.Value.Methods.ToArray();
                    FieldInfo[] fields = info.Value.Fields.ToArray();
                    // 生成 方法注冊字符串 e.g.
                        "            args = new Type[]{typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance)};\r\n            
                                     method = type.GetMethod(\"Add\", flag, null, args, null);\r\n            
                                     app.RegisterCLRMethodRedirection(method, Add_0);\r\n
                                     
                                     args = new Type[]{typeof(System.Int32)};\r\n            
                                     method = type.GetMethod(\"get_Item\", flag, null, args, null);\r\n            
                                     app.RegisterCLRMethodRedirection(method, get_Item_1);\r\n"                    
                    string registerMethodCode = i.GenerateMethodRegisterCode(methods, excludeMethods, out needMethods);
                    // 生成字段注冊字符串
                    string registerFieldCode = fields.Length > 0 ? i.GenerateFieldRegisterCode(fields, excludeFields) : null;
                    // 生成值類型注冊字符串
                    string registerValueTypeCode = info.Value.ValueTypeNeeded ? i.GenerateValueTypeRegisterCode(realClsName) : null;
                    string registerMiscCode = i.GenerateMiscRegisterCode(realClsName, info.Value.DefaultInstanceNeeded, info.Value.ArrayNeeded);
                    string commonCode = i.GenerateCommonCode(realClsName);
                    // 獲取構造函數信息
                    ConstructorInfo[] ctors = info.Value.Constructors.ToArray();
                    // 生成構造函數注冊字符串 e.g.
                        "            args = new Type[]{};\r\n            
                                     method = type.GetConstructor(flag, null, args, null);\r\n            
                                     app.RegisterCLRMethodRedirection(method, Ctor_0);\r\n"
                    string ctorRegisterCode = i.GenerateConstructorRegisterCode(ctors, excludeMethods);
                    // 生成方法體    e.g.
                        "        static StackObject* Add_0(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)\r\n        
                                 {\r\n            
                                    ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;\r\n
                                    StackObject* ptr_of_this_method;\r\n            
                                    StackObject* __ret = ILIntepreter.Minus(__esp, 2);\r\n\r\n            
                                    
                                    ptr_of_this_method = ILIntepreter.Minus(__esp, 1);\r\n            
                                    ILRuntime.Runtime.Intepreter.ILTypeInstance @item = (ILRuntime.Runtime.Intepreter.ILTypeInstance)typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));\r\n
                                    __intp.Free(ptr_of_this_method);\r\n\r\n            
                                    
                                    ptr_of_this_method = ILIntepreter.Minus(__esp, 2);\r\n            
                                    System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance> instance_of_this_method = (System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>)typeof(System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));\r\n
                                    __intp.Free(ptr_of_this_method);\r\n\r\n            
                                    
                                    instance_of_this_method.Add(@item);\r\n\r\n            
                                    return __ret;\r\n        
                                 }\r\n\r\n        
                                 
                                 static StackObject* get_Item_1(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)\r\n        
                                 {\r\n            
                                    ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;\r\n
                                    StackObject* ptr_of_this_method;\r\n
                                    StackObject* __ret = ILIntepreter.Minus(__esp, 2);\r\n\r\n            
                                    ptr_of_this_method = ILIntepreter.Minus(__esp, 1);\r\n            
                                    System.Int32 @index = ptr_of_this_method->Value;\r\n\r\n            
                                    ptr_of_this_method = ILIntepreter.Minus(__esp, 2);\r\n            
                                    System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance> instance_of_this_method = (System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>)typeof(System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));\r\n
                                    __intp.Free(ptr_of_this_method);\r\n\r\n    
                                    
                                    var result_of_this_method = instance_of_this_method[index];\r\n\r\n            
                                    
                                    return ILIntepreter.PushObject(__ret, __mStack, result_of_this_method);\r\n        
                                 }\r\n\r\n"                    
                    string methodWraperCode = i.GenerateMethodWraperCode(methods, realClsName, excludeMethods, valueTypeBinders, domain);
                        // 為每一個方法生成方法體
                        foreach (var i in methods)
                            // 獲取參數數量
                            int paramCnt = param.Length;
                            // 如果不是靜態方法, 參數數量加1 也就是把實例本身也當作參數
                            if (!i.IsStatic)    paramCnt++;
                            sb.AppendLine(string.Format("        static StackObject* {0}_{1}(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)", i.Name, idx));
                            sb.AppendLine("        {");
                            sb.AppendLine("            ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;");
                            if (param.Length != 0 || !i.IsStatic)
                                sb.AppendLine("            StackObject* ptr_of_this_method;");
                            // 返回指針 為當前指針 減去參數數量
                            sb.AppendLine(string.Format("            StackObject* __ret = ILIntepreter.Minus(__esp, {0});", paramCnt));
                            sb.AppendLine();
                            bool hasByRef = param.HasByRefParam();
                            string shouldFreeParam = hasByRef ? "false" : "true";
                            for (int j = param.Length; j > 0; j--)
                                // 設置ptr_of_this_method
                                sb.AppendLine(string.Format("            ptr_of_this_method = ILIntepreter.Minus(__esp, {0});", param.Length - j + 1));
                        
                    // 生成字段方法體
                    string fieldWraperCode = fields.Length > 0 ? i.GenerateFieldWraperCode(fields, realClsName, excludeFields) : null;
                    string cloneWraperCode = null;
                    if (info.Value.ValueTypeNeeded)
                    {
                        //Memberwise clone should copy all fields
                        var fs = i.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
                        cloneWraperCode = i.GenerateCloneWraperCode(fs, realClsName);
                    }

                    bool hasMethodCode = !string.IsNullOrEmpty(registerMethodCode);
                    bool hasFieldCode = !string.IsNullOrEmpty(registerFieldCode);
                    bool hasValueTypeCode = !string.IsNullOrEmpty(registerValueTypeCode);
                    bool hasMiscCode = !string.IsNullOrEmpty(registerMiscCode);
                    bool hasCtorCode = !string.IsNullOrEmpty(ctorRegisterCode);
                    bool hasNormalMethod = methods.Where(x => !x.IsGenericMethod).Count() != 0;

                    if ((hasMethodCode && hasNormalMethod) || hasFieldCode || hasCtorCode)
                        sb.AppendLine(flagDef);
                    if (hasMethodCode || hasCtorCode)
                        sb.AppendLine(methodDef);
                    if (hasFieldCode)
                        sb.AppendLine(fieldDef);
                    if (hasMethodCode || hasFieldCode || hasCtorCode)
                        sb.AppendLine(argsDef);
                    if (hasMethodCode || hasFieldCode || hasValueTypeCode || hasMiscCode || hasCtorCode)
                        sb.AppendLine(typeDef);
                    if (needMethods)
                        sb.AppendLine(methodsDef);

                    sb.AppendLine(registerMethodCode);
                    if (fields.Length > 0)
                        sb.AppendLine(registerFieldCode);
                    if (info.Value.ValueTypeNeeded)
                        sb.AppendLine(registerValueTypeCode);
                    if (!string.IsNullOrEmpty(registerMiscCode))
                        sb.AppendLine(registerMiscCode);
                    sb.AppendLine(ctorRegisterCode);
                    sb.AppendLine("        }");
                    sb.AppendLine();
                    sb.AppendLine(commonCode);
                    sb.AppendLine(methodWraperCode);
                    if (fields.Length > 0)
                        sb.AppendLine(fieldWraperCode);
                    if (info.Value.ValueTypeNeeded)
                        sb.AppendLine(cloneWraperCode);
                    string ctorWraperCode = i.GenerateConstructorWraperCode(ctors, realClsName, excludeMethods, valueTypeBinders);
                    sb.AppendLine(ctorWraperCode);
                    sb.AppendLine("    }");
                    sb.AppendLine("}");

                    sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
                    sw.Flush();
                }
            }

            // 生成 Assets/ILRuntime/Generated/CLRBindings.cs
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/CLRBindings.cs", false, new UTF8Encoding(false)))
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine(@"using System;
using System.Collections.Generic;
using System.Reflection;

namespace ILRuntime.Runtime.Generated
{
    class CLRBindings
    {
        /// <summary>
        /// Initialize the CLR binding, please invoke this AFTER CLR Redirection registration
        /// </summary>
        public static void Initialize(ILRuntime.Runtime.Enviorment.AppDomain app)
        {");
                foreach (var i in clsNames)
                {
                    sb.Append("            ");
                    sb.Append(i);
                    sb.AppendLine(".Register(app);");
                }

                sb.AppendLine(@"        }
    }
}");
                sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
            }

            var delegateClsNames = GenerateDelegateBinding(delegateTypes, outputPath);
            clsNames.AddRange(delegateClsNames);

            GenerateBindingInitializeScript(clsNames, valueTypeBinders, outputPath);        
        
    }
}
ILRuntime/Generate CLR Binding Code by Analysis

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

################################################################################################################################################################### 

 

熱更工程

namespace HotFix_Project {

  public class InstanceClass {

    public InstanceClass() {

    }

  }

}

 

主工程

var type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];

object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] {  });

 

ILIntepreter inteptreter = RequestILIntepreter();
  inteptreter = new ILIntepreter(this);
    stack = new RuntimeStack(this);
      nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);
      pointer = (StackObject*)nativePointer.ToPointer();
      endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
      valueTypePtr = endOfMemory - 1;

// esp = 0x5de00010
// mStack = null;
// instance: ILTypeInstance = "HotFix_Project.InstanceClass"
esp = PushObject(esp, mStack, instance);
  esp->ObjectType = ObjectTypes.Object;
  esp->Value = mStack.Count;
  mStack.Add(obj);

return esp + 1 (0x5de0001c)

// 沒有參數不變
esp = PushParameters(method, esp, p);

// 執行方法
// method = "HotFix_Project.InstanceClass..ctor()"
// esp = 0x5de0001c
// 原始IL
// "IL_0000: ldarg.0"
// "IL_0001: call System.Void System.Object::.ctor()"
// "IL_0006: nop"
// "IL_0007: nop"
// "IL_0008: ret"
// 自定義OpCode
// Ldarg_0, 0, 0
// Call, 1, 0
// Nop, 0, 0
// Nop, 0, 0
// Ret, 0, 0
esp = Execute(method, esp, out unhandledException);
  res = new StackFrame();
  stack.InitializeFrame(method, esp, out frame);
  StackObject* v1 = frame.LocalVarPointer;
  StackObject* v2 = frame.LocalVarPointer + 1;
  StackObject* v3 = frame.LocalVarPointer + 1 + 1;
  StackObject* v4 = Add(frame.LocalVarPointer, 3);
  esp = frame.BasePointer;
  var arg = Minus(frame.LocalVarPointer, method.ParameterCount);

if (method.HasThis) arg--; paramCnt++; 

 

// StackFrame 如 RuntimeStack
stack.PushFrame(ref frame);

// 將索引為 0 的參數加載到計算堆棧上, 將 arg 上的值 拷貝到 esp 上
case OpCodeEnum.Ldarg_0:
  // esp = 0x5de0001c
  // arg = 0x5de00010
  // mStack[0] = "HotFix_Project.InstanceClass"
  CopyToStack(esp, arg, mStack);
  esp++;

 

// 調用由傳遞的方法說明符指示的方法。
case OpCodeEnum.Call:
  IMethod m = domain.GetMethod(ip->TokenInteger);
  if (m == null)
    //Irrelevant method
    int cnt = (int)ip->TokenLong;
    //Balance the stack
    for (int i = 0; i < cnt; i++)
    {
      // esp - 1 = 0x5de0001c
      Free(esp - 1);
      // esp = 0x5de0001c
      esp--;
    }

return stack.PopFrame(ref frame, esp);
  // returnVal = 0x5de00010
  StackObject* returnVal = esp - 1;
  // method = "HotFix_Project.InstanceClass..ctor()"
  var method = frame.Method;
  // ret = 0x5de0001c
  StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
  // ret = 0x5de00010
  if (method.HasThis) ret--;
  // mStack 沒有了
  ((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
  //ret = 0x5de00010
  return ret;

// null
object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - 1), domain, mStack)) : null;
((UncheckedList<object>)mStack).RemoveRange(mStackBase, mStack.Count - mStackBase);

 

無參構造函數最后返回的是 res: ILTypeInstance

public ILTypeInstance Instantiate(bool callDefaultConstructor = true)
{
  var res = new ILTypeInstance(this);
  if (callDefaultConstructor)
  {
    var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
    if (m != null)
    {
      appdomain.Invoke(m, res, null);
    }
  }
  return res;
}

 

################################################################################################################################################################### 

 

 

 

 

 

 

 

 

 

 

 

相關文章

ILRuntime入門筆記

Unity實現c#熱更新方案探究(一)

  程序的熱升級

  unity dll實現熱更新 

Unity實現c#熱更新方案探究(二)

  Mono為何能跨平台?聊聊CIL(MSIL)

  誰偷了我的熱更新?Mono,JIT,iOS 

Unity實現c#熱更新方案探究(三)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM