ILRuntime 学习
ILRuntime: https://github.com/Ourpalm/ILRuntime
Demo: https://github.com/Ourpalm/ILRuntimeU3D
中文在线文档: https://ourpalm.github.io/ILRuntime/public/v1/guide/index.html
Mono: https://www.mono-project.com/
Mono.Cecil https://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/
XCode请使用Relase编译, 使用Debug编译会出现函数调用层数超过一定数量iOS手机闪退
ESP: 栈指针寄存器(extended stack pointer), 指向栈顶的指针
EBP: 基址指针寄存器(extended base pointer), 指向栈底的指针
var module = ModuleDefinition.ReadModule(stream); //从MONO中加载模块 foreach(TypeDefinition type in module.Types) { UnityEngine.Debug.Log(type.FullName); }
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); } } }
热更项目 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;
}
###################################################################################################################################################################
相关文章