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); }

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; }
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, } }

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); } } }

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)

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

public unsafe AppDomain() { } appdomain.LoadAssembly(fs); appdomain.mapType.Count = 0 [<Module>, <Module>] [HotFix_Project.InstanceClass, HotFix_Project.InstanceClass]

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" }); }

熱更項目 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; } } } }

主工程: 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 [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); }

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; }

熱更項目 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);

熱更項目 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: // 返回 }

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

//預先獲得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);

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;

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);

主工程 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;

熱更工程 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);

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);

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) });

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;

熱更工程 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))();

主工程 // 主工程要被繼承的類 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(); } } }

熱更項目 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");

熱更項目 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();

熱更工程 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);

熱更工程 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;

熱更工程 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);
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); } } } }

測試熱更工程調用主工程的方法 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;

主工程 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); } } }
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; }

主工程 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); } } }

熱更項目 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);

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;

熱更工程 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;

熱更工程 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");

[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); } }
###################################################################################################################################################################
熱更工程
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;
}
###################################################################################################################################################################
相關文章