|
|
求醉的冲锋衣 · 算力基建升级驱动光模块需求高涨 ...· 7 月前 · |
|
|
胡子拉碴的凉面 · GitHub - ...· 8 月前 · |
|
|
爱旅游的手套 · 惊!蜘蛛侠居然也朝三暮四?论蜘蛛侠到底有多少 ...· 1 年前 · |
|
|
知识渊博的帽子 · 《暗黑破坏神4》有拍卖行吗_暗黑破坏神4手游 ...· 1 年前 · |
|
|
深情的炒粉 · shell-2.变量,单引号和双引号_she ...· 1 年前 · |
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手机闪退
var module = ModuleDefinition.ReadModule(stream); //从MONO中加载模块
foreach(TypeDefinition type in module.Types) {
UnityEngine.Debug.Log(type.FullName);
从Mono中加载模块
// sizeof(StackObject) == 12 字节
// 分配 12 * 1024 * 16 字节
nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);
// 将 IntPtr 转换为 StackObject* 指针
// pointer 地址为 0x5737F010
pointer = (StackObject*)nativePointer.ToPointer();
// endOfMemory 地址为 0x573AF010
endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
// valueTypePtr 地址为 0x573AF004
valueTypePtr = endOfMemory - 1;
RuntimeStack 构造
struct StackObject
public ObjectTypes ObjectType;
public int Value; //高32位
public int ValueLow; //低32位
enum ObjectTypes
Null,//null
Integer,
Long,
Float,
Double,
StackObjectReference,//引用指针,Value = 指针地址,
StaticFieldReference,//静态变量引用,Value = 类型Hash, ValueLow= Field的Index
Object,//托管对象,Value = 对象Index
FieldReference,//类成员变量引用,Value = 对象Index, ValueLow = Field的Index
ArrayReference,//数组引用,Value = 对象Index, ValueLow = 元素的Index
/// <summary>
/// 如果 value 为 false、空引用(Visual Basic 中的 Nothing)或零,则将控制转移到目标指令。
/// </summary>
Brfalse,
/// <summary>
/// 如果 value 为 true、非空或非零,则将控制转移到目标指令。
/// </summary>
Brtrue,
/// <summary>
/// 如果两个值相等,则将控制转移到目标指令。
/// </summary>
/// <summary>
/// 如果第一个值大于或等于第二个值,则将控制转移到目标指令。
/// </summary>
/// <summary>
/// 如果第一个值大于第二个值,则将控制转移到目标指令。
/// </summary>
/// <summary>
/// 如果第一个值小于或等于第二个值,则将控制转移到目标指令。
/// </summary>
/// <summary>
/// 如果第一个值小于第二个值,则将控制转移到目标指令。
/// </summary>
/// <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>
/// <summary>
/// 从其他值中减去一个值并将结果推送到计算堆栈上。
/// </summary>
/// <summary>
/// 将两个值相乘并将结果推送到计算堆栈上。
/// </summary>
/// <summary>
/// 将两个值相除并将结果作为浮点(F 类型)或商(int32 类型)推送到计算堆栈上。
/// </summary>
/// <summary>
/// 两个无符号整数值相除并将结果 ( int32 ) 推送到计算堆栈上。
/// </summary>
Div_Un,
/// <summary>
/// 将两个值相除并将余数推送到计算堆栈上。
/// </summary>
/// <summary>
/// 将两个无符号值相除并将余数推送到计算堆栈上。
/// </summary>
Rem_Un,
/// <summary>
/// 计算两个值的按位“与”并将结果推送到计算堆栈上。
/// </summary>
/// <summary>
/// 计算位于堆栈顶部的两个整数值的按位求补并将结果推送到计算堆栈上。
/// </summary>
///
<summary>
/// 计算位于计算堆栈顶部的两个值的按位异或,并且将结果推送到计算堆栈上。
/// </summary>
/// <summary>
/// 将整数值左移(用零填充)指定的位数,并将结果推送到计算堆栈上。
/// </summary>
/// <summary>
/// 将整数值右移(保留符号)指定的位数,并将结果推送到计算堆栈上。
/// </summary>
/// <summary>
/// 将无符号整数值右移(用零填充)指定的位数,并将结果推送到计算堆栈上。
/// </summary>
Shr_Un,
/// <summary>
/// 对一个值执行求反并将结果推送到计算堆栈上。
/// </summary>
/// <summary>
/// 计算堆栈顶部整数值的按位求补并将结果作为相同的类型推送到计算堆栈上。
/// </summary>
/// <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>
/// <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>
/// <summary>
/// 比较两个值。如果第一个值大于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
/// </summary>
/// <summary>
/// 比较两个无符号的或不可排序的值。如果第一个值大于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
/// </summary>
Cgt_Un,
/// <summary>
/// 比较两个值。如果第一个值小于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
/// </summary>
/// <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,
/// <summary>
/// 再次引发当前异常。
/// </summary>
Rethrow,
/// <summary>
/// 将提供的值类型的大小(以字节为单位)推送到计算堆栈上。
/// </summary>
Sizeof,
/// <summary>
/// 检索嵌入在类型化引用内的类型标记。
/// </summary>
Refanytype,
/// <summary>
/// 指定后面的数组地址操作在运行时不执行类型检查,并且返回可变性受限的托管指针。
/// </summary>
Readonly,
OpCodeEnum
public InstanceClass(int id)
UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass() id = " + id);
this.id = id;
public int ID
get { return id; }
// static method
public static void StaticFunTest()
UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest()");
public static void StaticFunTest2(int a)
UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest2(), a=" + a);
public static void GenericMethod<T>(T a)
UnityEngine.Debug.Log("!!! InstanceClass.GenericMethod(), a=" + a);
HotFix_Project.InstanceClass
System.Void HotFix_Project.InstanceClass::.ctor()
System.Void HotFix_Project.InstanceClass::.ctor(System.Int32)
System.Int32 HotFix_Project.InstanceClass::get_ID()
System.Void HotFix_Project.InstanceClass::StaticFunTest()
System.Void HotFix_Project.InstanceClass::StaticFunTest2(System.Int32)
System.Void HotFix_Project.InstanceClass::GenericMethod(T)
Mono.Cecil.Methods: MethodDifinition(HotFix_Project.InstanceClass)
IType.FullName : HotFix_Project.InstanceClass
IType.GenericArguments :
IType.GetActualType() : ILRuntime.CLR.TypeSystem.ILType
IType.HasGenericParameter : False
IType.Implements :
IType.IsArray : False
IType.IsByRef : False
IType.IsDelegate : False
IType.IsEnum : False
IType.IsGenericInstance : False
IType.IsGenericParameter : False
IType.IsInterface : False
IType.IsPrimitive : False
IType.IsValueType : False
IType.Name : InstanceClass
IType.ReflectionType : Type: InstanceClass
IType.TypeForCLR : ILRuntime.Runtime.Intepreter.ILTypeInstance
HotFix_Project.InstanceClass IType 部分属性
appdomain.mapType.Count = 0
[<Module>, <Module>]
[HotFix_Project.InstanceClass, HotFix_Project.InstanceClass]
只加载程序集的 AppDomain 初始状态
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\mscorlib.dll
UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.dll
UnityEngine.AIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AIModule.dll
UnityEngine.ARModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ARModule.dll
UnityEngine.AccessibilityModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AccessibilityModule.dll
UnityEngine.AnimationModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AnimationModule.dll
UnityEngine.AssetBundleModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AssetBundleModule.dll
UnityEngine.AudioModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.AudioModule.dll
UnityEngine.BaselibModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.BaselibModule.dll
UnityEngine.ClothModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ClothModule.dll
UnityEngine.ClusterInputModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterInputModule.dll
UnityEngine.ClusterRendererModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ClusterRendererModule.dll
UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CoreModule.dll
UnityEngine.CrashReportingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.CrashReportingModule.dll
UnityEngine.DirectorModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.DirectorModule.dll
UnityEngine.FileSystemHttpModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.FileSystemHttpModule.dll
UnityEngine.GameCenterModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.GameCenterModule.dll
UnityEngine.GridModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.GridModule.dll
UnityEngine.HotReloadModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.HotReloadModule.dll
UnityEngine.IMGUIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll
UnityEngine.ImageConversionModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ImageConversionModule.dll
UnityEngine.InputModule, Version=0.0.0.0
, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.InputModule.dll
UnityEngine.JSONSerializeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.JSONSerializeModule.dll
UnityEngine.LocalizationModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.LocalizationModule.dll
UnityEngine.ParticleSystemModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ParticleSystemModule.dll
UnityEngine.PerformanceReportingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.PerformanceReportingModule.dll
UnityEngine.PhysicsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.PhysicsModule.dll
UnityEngine.Physics2DModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.Physics2DModule.dll
UnityEngine.ProfilerModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ProfilerModule.dll
UnityEngine.ScreenCaptureModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.ScreenCaptureModule.dll
UnityEngine.SharedInternalsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SharedInternalsModule.dll
UnityEngine.SpatialTrackingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SpatialTrackingModule.dll
UnityEngine.SpriteMaskModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteMaskModule.dll
UnityEngine.SpriteShapeModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SpriteShapeModule.dll
UnityEngine.StreamingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.StreamingModule.dll
UnityEngine.StyleSheetsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.StyleSheetsModule.dll
UnityEngine.SubstanceModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.SubstanceModule.dll
UnityEngine.TLSModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TLSModule.dll
UnityEngine.TerrainModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainModule.dll
UnityEngine.TerrainPhysicsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TerrainPhysicsModule.dll
UnityEngine.TextCoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TextCoreModule.dll
UnityEngine.TextRenderingModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TextRenderingModule.dll
UnityEngine.TilemapModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TilemapModule.dll
UnityEngine.TimelineModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.TimelineModule.dll
UnityEngine.UIModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UIModule.dll
UnityEngine.UIElementsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UIElementsModule.dll
UnityEngine.UNETModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UNETModule.dll
UnityEngine.UmbraModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UmbraModule.dll
UnityEngine.UnityAnalyticsModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityAnalyticsModule.dll
UnityEngine.UnityConnectModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityConnectModule.dll
UnityEngine.UnityTestProtocolModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityTestProtocolModule.dll
UnityEngine.UnityWebRequestModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestModule.dll
UnityEngine.UnityWebRequestAssetBundleModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAssetBundleModule.dll
UnityEngine.UnityWebRequestAudioModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestAudioModule.dll
UnityEngine.UnityWebRequestTextureModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestTextureModule.dll
UnityEngine.UnityWebRequestWWWModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.UnityWebRequestWWWModule.dll
UnityEngine.VFXModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VFXModule.dll
UnityEngine.VRModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VRModule.dll
UnityEngine.VehiclesModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VehiclesModule.dll
UnityEngine.VideoModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.VideoModule.dll
UnityEngine.WindModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.WindModule.dll
UnityEngine.XRModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEngine\UnityEngine.XRModule.dll
UnityEditor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEditor.dll
Unity.Locator, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\Unity.Locator.dll
System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Core.dll
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.dll
Mono.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756
Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\Mono.Security.dll
System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Configuration.dll
System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Xml.dll
Unity.DataContract, Version=1.0.2.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\Unity.DataContract.dll
Unity.PackageManager, Version=4.5.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\PackageManager\Unity\PackageManager\2018.4.6\Unity.PackageManager.dll
UnityEngine.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\GUISystem\UnityEngine.UI.dll
UnityEditor.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\GUISystem\Editor\UnityEditor.UI.dll
UnityEditor.TestRunner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\TestRunner\Editor\UnityEditor.TestRunner.dll
UnityEngine.TestRunner, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\TestRunner\UnityEngine.TestRunner.dll
nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb
Unity\Editor\Data\UnityExtensions\Unity\TestRunner\net35\unity-custom\nunit.framework.dll
UnityEngine.Timeline, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\Timeline\RuntimeEditor\UnityEngine.Timeline.dll
UnityEditor.Timeline, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\Timeline\Editor\UnityEditor.Timeline.dll
UnityEngine.Networking, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\Networking\UnityEngine.Networking.dll
UnityEditor.Networking, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\Networking\Editor\UnityEditor.Networking.dll
UnityEditor.GoogleAudioSpatializer, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\UnityGoogleAudioSpatializer\Editor\UnityEditor.GoogleAudioSpatializer.dll
UnityEngine.GoogleAudioSpatializer, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\UnityGoogleAudioSpatializer\RuntimeEditor\UnityEngine.GoogleAudioSpatializer.dll
UnityEditor.SpatialTracking, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\UnitySpatialTracking\Editor\UnityEditor.SpatialTracking.dll
UnityEngine.SpatialTracking, Version
=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\UnitySpatialTracking\RuntimeEditor\UnityEngine.SpatialTracking.dll
UnityEditor.VR, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\UnityVR\Editor\UnityEditor.VR.dll
UnityEditor.Graphs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\UnityEditor.Graphs.dll
UnityEditor.WindowsStandalone.Extensions, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\PlaybackEngines\windowsstandalonesupport\UnityEditor.WindowsStandalone.Extensions.dll
SyntaxTree.VisualStudio.Unity.Bridge, Version=3.9.0.3, Culture=neutral, PublicKeyToken=null
C:\Program Files (x86)\Microsoft Visual Studio Tools for Unity\15.0\Editor\SyntaxTree.VisualStudio.Unity.Bridge.dll
Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\ScriptAssemblies\Assembly-CSharp.dll
Assembly-CSharp-Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\ScriptAssemblies\Assembly-CSharp-Editor.dll
Unity.TextMeshPro.Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\ScriptAssemblies\Unity.TextMeshPro.Editor.dll
Unity.PackageManagerUI.Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\ScriptAssemblies\Unity.PackageManagerUI.Editor.dll
Unity.CollabProxy.Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\ScriptAssemblies\Unity.CollabProxy.Editor.dll
Unity.TextMeshPro, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\ScriptAssemblies\Unity.TextMeshPro.dll
Unity.Analytics.DataPrivacy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\ScriptAssemblies\Unity.Analytics.DataPrivacy.dll
ILRuntim.Mono.Cecil, Version=0.10.1.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e
Assets\Plugins\ILRuntim.Mono.Cecil.dll
ILRuntime.Mono.Cecil.Mdb, Version=0.10.1.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e
Assets\Plugins\ILRuntime.Mono.Cecil.Mdb.dll
ILRuntime.Mono.Cecil.Pdb, Version=0.10.1.0, Culture=neutral, PublicKeyToken=50cebf1cceb9d05e
Assets\Plugins\ILRuntime.Mono.Cecil.Pdb.dll
UnityEditor.Advertisements, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.ads@2.0.8\Editor\UnityEditor.Advertisements.dll
Unity.Analytics.Tracker, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.analytics@3.2.2\Unity.Analytics.Tracker.dll
Unity.Analytics.StandardEvents, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.analytics@3.2.2\Unity.Analytics.StandardEvents.dll
Unity.Analytics.Editor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.analytics@3.2.2\Unity.Analytics.Editor.dll
UnityEditor.Purchasing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.purchasing@2.0.3\Editor\UnityEditor.Purchasing.dll
Unity.Cecil, Version=0.10.0.0, Culture=neutral, PublicKeyToken=fc15b93552389f74
Unity\Editor\Data\Managed\Unity.Cecil.dll
System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Unity\Editor\Data\MonoBleedingEdge\lib\mono\unityjit\System.Xml.Linq.dll
Unity.SerializationLogic, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\Unity.SerializationLogic.dll
Unity.Legacy.NRefactory, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\Unity.Legacy.NRefactory.dll
ExCSS.Unity, Version=2.0.6.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\ExCSS.Unity.dll
Unity.IvyParser, Version=1.0.3.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\Managed\Unity.IvyParser.dll
UnityEditor.iOS.Extensions.Xcode, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Unity\Editor\Data\UnityExtensions\Unity\UnityVR\Editor\UnityEditor.iOS.Extensions.Xcode.dll
SyntaxTree.VisualStudio.Unity.Messaging, Version=3.9.0.3, Culture=neutral, PublicKeyToken=31bf3856ad364e35
C:\Program Files (x86)\Microsoft Visual Studio Tools for Unity\15.0\Editor\SyntaxTree.VisualStudio.Unity.Messaging.dll
主工程加载的程序集
public object Invoke(string type, string method, object instance, params object[] p) {
// 通过 HotFix_Project.InstanceClass:string 获取 HotFix_Project.InstanceClass: ILType
IType t = GetType(type);
if (t == null)
return null;
// 通过 StaticFunTest:string 获取 StaticFunTest:ILMethod
var m = t.GetMethod(method, p != null ? p.Length : 0);
// 转型为 ILMethod
ILMethod ilm = (ILMethod)m;
ilm.Prewarm();
// 通过 def.Body.Instructions 转型为 ILRuntime.Runtime.Intepreter.OpCodes.OpCode
InitCodeBody()
InitToken()
// 缓存参数 字符串
Ldstr: long hashCode = appdomain.CacheString(token);
// 缓存 UnityEngine.Debug.Log 方法
Call: var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
// 获取 UnityEngine.Debug.Log 方法
CLRMethod cm = (CLRMethod)GetMethod(1);
// System.Reflection.MethodInfo.Invoke
// Module: UnityEngine.CoreModule.dll
// Assembly: UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Module.FullyQualifiedName "D:\\Program Files\\Unity\\2018.4.6f1\\Editor\\Data\\Managed\\UnityEngine\\UnityEngine.CoreModule.dll
cm.def.Invoke(null, new[] { "Hello World" });
真正的Hello World
foreach (var t in module.GetTypes()) //获取所有此模块定义的类型
ILType type = new ILType(t, this);
mapType[t.FullName] = type;
types.Add(type);
// 这里
// e.g. <"HotFix_Project.HelloWorld": string, HotFix_Project.HelloWorld: TypeDefintion>
typeDef[t.FullName] = t;
HelloWorldDemo.OnHotFixLoaded
TypeDefinition type = appdomain.typeDef["HotFix_Project.HelloWorld"];
MyInstance ins = new MyInstance(type);
Assert(ins.id == 2)
// 根据 TypeDefinition 自定义的 实例
// 热更的项目 System.Type.GetType("HotFix_Project.HelloWorld") 并获取不到
// 虽然整个类型没法获取到, 但是 类型里的 字段,方法,嵌套类 等等 几乎都能获取到
// 因此可以通过 类型的 零件 自己组合一个 类型
// 所以 可以把 new MyInstance() 理解为 new object()
public class MyInstance {
// Mono类型定义
public TypeDefinition def;
// Mono字段定义
public FieldDefinition fieldDef;
// Mono方法定义
public MethodDefinition method;
public int id;
private int dummyStack;
public MyInstance(TypeDefinition def) {
this.def = def;
fieldDef = def.Fields[0];
method = def.Methods[0];
// IL 指令
Collection<Instruction> instructions = this.def.Methods[0].Body.Instructions;
// HotFix_Project.HelloWorld 构造函数的 IL指令
// ldarg.0 :
// ldc.i4.0 :
// stfld : System.Int32 HotFix_Project.HelloWorld::id
// ldarg.0 :
// call : System.Void System.Object::.ctor()
// nop :
// nop :
// ldarg.0 :
// ldc.i4.2 :
// stfld : System.Int32 HotFix_Project.HelloWorld::id
// ret :
foreach (var item in instructions) {
switch (item.OpCode.Code) {
// 将整数值 0 作为 int32 推送到计算堆栈上
case Code.Ldc_I4_0:
dummyStack = 0;
break;
// 用新值替换在对象引用或指针的字段中存储的值
case Code.Stfld:
// stfld: System.Int32 HotFix_Project.HelloWorld::id = 0
id = dummyStack;
break;
// 将整数值 0 作为 int32 推送到计算堆栈上
case Code.Ldc_I4_2:
dummyStack
= 2;
break;
// case Code.Stfld:
// // stfld : System.Int32 HotFix_Project.HelloWorld::id = 2
// id = dummyStack;
// break;
// 退出
case Code.Ret:
break;
default:
break;
真正的HelloWorld 2.0, 便于理解,简化处理
void OnHotFixLoaded() {
appdomain.Invoke("HotFix_Project.InstanceClass", "StaticFunText", null, null);
热更工程:
namespace HotFix_Project {
public class InstanceClass {
public InstanceClass() {
UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass()");
HotFix_Project.InstanceClass.StaticFunTest 调用无参数静态方法
// 调用HotFix_Project.InstanceClass.StaticFunTest
[AppDomain].Invoke
// 获取HotFix_Project.InstanceClass: ILType
[AppDomain].GetType
// 获取StaticFunTest:ILMethod
[HotFix_Project.InstanceClass: ILType].GetMethod
// 如果 InstanceClass的methods: Dictionary<string, List<ILMethod>> 为空(默认为空,调用之后会缓存)
[HotFix_Project.InstanceClass: ILType].InitializeMethods
// 将静态构造函数添加到 staticConstructor: ILMethod
// 将构造函数添加到 constructors: List<ILMethod>
// 将函数添加到 methods: Dictionary<string, List<ILMethod>>
new ILMethod
// 设置 this.def: MethodDefinition
this.def = def;
// 设置声明类型 declaringType: ILType
declaringType = type;
// 设置 返回类型
ReturnType = domain.GetType(System.Void, HotFix_Project.InstanceClass, this);
// 设置参数数量
paramCnt = def.HasParameters ? def.Parameters.Count : 0;
// 通过方法名字符串 获取 List<ILMethod>
if (methods.TryGetValue(name, out lst))
// 遍历ILMethod 列表
foreach (var i in lst)
// 参数数量相等
if (i.ParameterCount == paramCount)
// 返回找到的ILMethod
return i;
[AppDomain].Invoke(HotFix_Project.InstanceClass.StaticFunTest(), null, null)
// 请求解释器 Interpreter
[ILIntepreter] inteptreter = [AppDomain].RequestILIntepreter();
// 锁定 freeIntepreters: Queue<ILIntepreter>
lock (freeIntepreters)
// new 一个 解释器
inteptreter = new ILIntepreter(this);
// new 一个 运行时 堆栈
stack = new RuntimeStack();
// frames: Stack<StackFrame>
Stack<StackFrame> frames = new Stack<StackFrame>();
// 通过使用指定的字节数,从进程的非托管内存中分配内存
// sizeof(StackObject) == 12 字节
// 分配 12 * 1024 * 16 字节
nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);
// 将 IntPtr 转换为 StackObject* 指针
// e.g. pointer 地址为 0x5737F010
pointer = (StackObject*)nativePointer.ToPointer();
// e.g. endOfMemory 地址为 0x573AF010
endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
// e.g. valueTypePtr 地址为 0x573AF004
valueTypePtr = endOfMemory - 1;
// 返回解释器
return interpreter
try {
// 解释器运行
res = [inteptreter].Run((ILMethod)m, instance, p);
// 栈顶指针 e.g. 0x4db96010
StackObject* esp = stack.StackBase;
// 重置 valueTypePtr
stack.ResetValueTypePointer();
// 没有参数 esp 没有改变 还是 0x4db96010
esp = PushParameters(method, esp, p);
// 执行方法
esp = Execute(method, esp, out unhandledException);
// [Nop: 如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作]
// 0 Code = Nop, TokenInteger = 0, TokenLong = 0
// [Ldstr: 推送对元数据中存储的字符串的新对象引用]
// 1 Code = Ldstr, TokenInteger = 0, TokenLong = -1451757320
// [Call: 调用由传递的方法说明符指示的方法]
// 2 Code = Call, TokenInteger = 1, TokenLong = 0
// [Nop: 如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作]
// 3 Code = Nop, TokenInteger = 1, TokenLong = 0
// [Ret: 从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上? 反了吧?]
// 4 Code = Ret, TokenInteger = 0, TokenLong = 0
OpCode[] body = method.Body;
// MethodDefinition.HasBody
if (def.HasBody)
localVarCnt = def.Body.Variables.Count;
body = new OpCode[def.Body.Instructions.Count];
Dictionary<Mono.Cecil.Cil.Instruction, int> addr = new Dictionary<Mono.Cecil.Cil.Instruction, int>();
// 根据Mono.Cecil.Cil.Instruction 初始化 ILRuntime.Runtime.Intepreter.OpCodes.OpCode
for (int i = 0; i < body.Length; i++)
// 0 IL_000: nop Next: IL_0001: ldstr \"!!! InstanceClass.StaticFunTest()\"
// 1 IL_0001: ldstr \"!!! InstanceClass.StaticFunTest()\" Next: IL_0006: call System.Void UnityEngine.Debug::Log(System.Object)
// 2 IL_0006: call System.Void UnityEngine.Debug::Log(System.Object) Next: IL_000b: nop
// 3 IL_000b: nop Next: IL_000c: ret
// 4 IL_000c: ret Next: null
var c = def.Body.Instructions[i];
OpCode code = new OpCode();
// 0 Nop
// 1 Ldstr
// 2 Call
// 3 Nop
// 4 Ret
code.Code = (OpCodeEnum)c.OpCode.Code;
// [IL_0000: nop, 0]
// [IL_0001: ldstr \"!!! InstanceClass.StaticFunTest()\", 1]
// [IL_0006: call System.Void UnityEngine.Debug::Log(System.Object), 2]
// [IL_000b: nop, 3]
// [IL_000c: ret, 4]
addr[c] = i;
// 0, Nop,0,0
// 1, Ldstr,0,0
// 2, Call,0,0
// 3, Nop,0,0
// 4, Ret,0,0
body[i] = code;
for (int i = 0; i < body.Length; i++)
var c = def.Body.Instructions[i];
// 根据Mono.Cecil.Cil.Instruction 初始化 ILRuntime.Runtime.Intepreter.OpCodes.OpCode.TokenLong
// Operand: object 操作对象
InitToken(ref body[i], c.Operand, addr);
case OpCodeEnum.Ldstr:
// token e.g. "!!! InstanceClass.StaticFunTest()"
// 缓存 string
long hashCode = [appdomain].CacheString(token);
// 获取原始 hashCode, -1451757320
long oriHash = token.GetHashCode();
long hashCode = oriHash;
string str = (string)token;
lock (mapString)
// 检测碰撞
bool isCollision = CheckStringCollision(hashCode, str);
long cnt = 0;
while (isCollision)
cnt++;
hashCode = cnt << 32 | oriHash;
isCollision = CheckStringCollision(hashCode, str);
mapString[hashCode] = (string)token;
return hashCode;
// 将 TokenLong 设置为 字符串的 hash
code.TokenLong = hashCode;
case OpCodeEnum.Call:
bool invalidToken;
// token = System.Void UnityEngine.Debug::Log(System.Object)
// declaringType = HotFix_Project.InstanceClass
var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
string methodname = null;
string typename = null;
List<IType> paramList = null;
// hashCoede = 1
int hashCode = token.GetHashCode();
IMethod method;
IType[] genericArguments = null;
IType returnType;
invalidToken = false;
bool isConstructor = false;
// 通过 hashCode = 1 找到了 UnityEngine.Debug.Log 方法
if (mapMethod.TryGetValue(hashCode, out method))
return method;
if (m != null)
if (invalidToken)
code.TokenInteger = m.GetHashCode();
// TokenInteger = 1
code.TokenInteger = token.GetHashCode();
//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;
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);
// 是Object类型
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
// 添加到 List<object> || UncheckedList<object>
mStack.Add(obj);
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
mStack.Add(obj);
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();
// 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;
int paramCount = cm.ParameterCount;
for (int i = 1; i <= paramCount; i++)
// 释放
Free(Minus(esp, i));
if (esp->ObjectType >= ObjectTypes.Object)
var mStack = stack.ManagedStack;
if (esp->Value == mStack.Count - 1)
mStack.RemoveAt(esp->Value);
// 移动栈顶指针
esp = Minus(esp, paramCount);
if (cm.HasThis)
Free(esp - 1);
esp--;
if (cm.ReturnType != AppDomain.VoidType && !cm.IsConstructor)
esp = PushObject(esp, mStack, result, cm.ReturnType.TypeForCLR == typeof(object));
break;
case OpCodeEnum.Ret:
returned = true;
break;
ip++; // 指针++
// 清空 RuntimeStack
return stack.PopFrame(ref frame, esp);
if (frames.Count > 0 && frames.Peek().BasePointer == frame.BasePointer)
frames.Pop();
// null
object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - 1), domain, mStack)) : null;
} finally {
[AppDomain].FreeILIntepreter(inteptreter);
lock (freeIntepreters)
// 托管栈 清空
inteptreter.Stack.ManagedStack.Clear();
// Stack<StackFrame> 清空
inteptreter.Stack.Frames.Clear();
// 将清空的解释入队
freeIntepreters.Enqueue(inteptreter);
HotFix_Project.InstanceClass.StaticFunTest 调用无参数静态方法 流程
freeIntepreters: Queue<ILIntepreter> Count: 1
ILRuntime.Runtime.Intepreter.ILIntepreter, type: ILRuntime.Runtime.Intepreter.ILIntepreter
mapType: ThreadSafeDictionary<string, IType> Count: 25
[<Module>, <Module>], type: ILRuntime.CLR.TypeSystem.ILType
[HotFix_Project.InstanceClass, HotFix_Project.InstanceClass], type: ILRuntime.CLR.TypeSystem.ILType
[System.Void, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Void, mscorlib, Version
=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int32, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int64, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Boolean, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Single, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Double, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Object, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.ILogger, UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.ILogger, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Type, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Type, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[System.String, System.String], type: ILRuntime.CLR.TypeSystem.CLRType
[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, System.String], type: ILRuntime.CLR.TypeSystem.CLRType
clrTypeMapping: Dictionary<Type, IType> Count: 11
[System.Void, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int32, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Int64, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Boolean, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Single, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Double, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Object, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.Debug, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[UnityEngine.ILogger, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[System.Type, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[System.String, System.String], type: ILRuntime.CLR.TypeSystem.CLRType
mapTypeToken: ThreadSafeDictionary<int, IType> Count: 16
[536870913, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[536870914, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[536870915, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[536870916, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[536870917, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[536870918, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[536870919, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[1, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[2, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[3, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[536870920, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[4, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[5, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[536870921, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[536870922, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[536870923, System.String], type: ILRuntime.CLR.TypeSystem.CLRType
mapMethod: ThreadSafeDictionary<int, IMethod> Count :1
[1, Void Log(System.Object)], type: ILRuntime.CLR.Method.CLRMethod
mapString: ThreadSafeDictionary<long, string> Count : 1
[-1451757320, !!! InstanceClass.StaticFunTest()], type: System.String
Debug.Log 流程
[System.Void HotFix_Project.InstanceClass::StaticFunTest(): ILMethod].InitCodeBody
// ILRuntime.Mono.Cecil.Cil.Instruction.OpCode.Code == Call
// ILRuntime.Mono.Cecil.Cil.Instruction.Operand == System.Void UnityEngine.Debug::Log(System.Object)
[ILMethod].InitToken()
bool invalidToken;
// token: ILRuntime.Mono.Cecil.Body.Instruction.Operand = System.Void UnityEngine.Debug::Log(System.Object)
// declaringType: HotFix_Project.InstanceClass
// this: System.Void HotFix_Project.InstanceClass::StaticFunTest(): ILMethod
var m = [appdomain].GetMethod(token, declaringType, this, out invalidToken);
// 获取 Operand 的 hashCode == 1
int hashCode = token.GetHashCode();
// mapMethod字典目前没有这个方法
if (mapMethod.TryGetValue(hashCode, out method))
return method;
// object 是 Mono.Cecil.MethodReference
if (token is Mono.Cecil.MethodReference)
// token 也就是 UnityEngine.Debug.Log 转型为 Mono.Cecil.MethodReference
Mono.Cecil.MethodReference _ref = (token as Mono.Cecil.MethodReference);
// Log
methodname = _ref.Name;
var typeDef = _ref.DeclaringType;
// 获取Log 方法所属类型
// typeDef: TypeReference = UnityEngine.Debug
// contextType: ILType = HotFix_Project.InstanceClass
// contextMethod: ILMethod = HotFix_Project.InstanceClass.StaticFunTest()
type = [appdomain].GetType(typeDef, contextType, contextMethod);
// 获取 UnityEngine.Debug hashcode = 4
int hash = token.GetHashCode();
// mapTypeToken 字典目前没有这个类型
if (mapTypeToken.TryGetValue(hash, out res))
return res;
// UnityEngine.Debug 是 TypeReference
if (token is Mono.Cecil.TypeReference)
// token 也就是 UnityEngine.Debug.Log 转型为 TypeReference
Mono.Cecil.TypeReference _ref = (token as Mono.Cecil.TypeReference);
// 获取 module = HotFix_Project.dll
module = _ref.Module;
// 获取 类型全名 UnityEngine.Debug
typename = _ref.FullName;
// _ref.Scope = UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// scope = UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
scope = GetAssemblyName(_ref.Scope);
// 获取 UnityEngine.Debug 的 IType
res = GetType(typename);
// mapType 字典 目前没有 这个类型
if (mapType.TryGetValue(fullname, out res))
return res;
// 通过 UnityEngine.Debug 获取 Type
Type t = Type.GetType(fullname);
// 没有找到 UnityEngine.Debug
if (res == null)
// 将 / 替换成 +
typename = typename.Replace("/", "+");
res = GetType(typename);
// res == null scope == UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
if (res == null && scope != null)
res = GetType(typename + ", " + scope);
// 获取 UnityEngine.Debug, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Type t = Type.GetType(fullname);
// clrTypeMapping 字典里没有这个类型
if (!clrTypeMapping.TryGetValue(t, out res))
// 通过 Type new 一个 CLRType
res = new CLRType(t, this);
clrTypeMapping[t] = res;
// 获取参数
paramList = _ref.GetParamList(this, contextType, contextMethod, genericArguments);
// 有参数
if (def.HasParameters)
List<IType> param = new List<IType>();
// UnityEngine.Debug
var dt = appdomain.GetType(def.DeclaringType, contextType, contextMethod);
// 遍历参数
foreach (var i in def.Parameters)
// System.Object
t = appdomain.GetType(i.ParameterType, dt, null);
// 获取返回类型
// System.Void
returnType = GetType(_ref.ReturnType, type, null
);
// 获取方法
// 获取方法
// methodname = Log
method = [UnityEngine.Debug type: CLRType].GetMethod(methodname, paramList, genericArguments, returnType, true);
// 目前 UnityEngine.Debug 里没有 方法
if (methods == null)
[CLRType].InitializeMethods();
if (i.IsPrivate)
continue;
List<CLRMethod> lst;
if (!methods.TryGetValue(i.Name, out lst))
lst = new List<CLRMethod>();
methods[i.Name] = lst;
"[get_unityLogger, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[DrawLine, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[DrawRay, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Break, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[DebugBreak, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Log, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogError, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogErrorFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[ClearDeveloperConsole, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[get_developerConsoleVisible, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[set_developerConsoleVisible, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogException, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogPlayerBuildError, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogWarning, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogWarningFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Assert, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[AssertFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogAssertion, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogAssertionFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[get_isDebugBuild, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[OpenConsoleFile, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetDiagnosticSwitches, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetDiagnosticSwitch, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[SetDiagnosticSwitch, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[get_logger, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Equals, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Finalize, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetHashCode, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetType, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[MemberwiseClone, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[ToString, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
lst.Add(new CLRMethod(i, this, appdomain));
// UnityEngine.Debug.Log 方法 添加到 全局 mapMethod 字典里
if (!invalidToken)
mapMethod[hashCode] = method;
mapMethod[method.GetHashCode()] = method;
// 将 hashcode 复制给 OpCode.TokenInteger, 主要是用于查找方法
if (m != null)
if (invalidToken)
code.TokenInteger = m.GetHashCode();
code.TokenInteger = token.GetHashCode();
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
Debug 调用流程
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();
// TokenInteger = 2
// token: MethodReference = "System.Void UnityEngine.Debug::Log(System.Object)"
code.TokenInteger = token.GetHashCode();
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : 0;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
// 执行
case OpCodeEnum.Call:
// m: CLRMethod = "Void Log(System.Object)"
IMethod m = domain.GetMethod(ip->TokenInteger);
CLRMethod cm = (CLRMethod)m;
// 执行CLRMethod.Invoke
object result = cm.Invoke(this, esp, mStack);
// 从 非托管栈上 获取 参数
// obj = "HelloWorldWithDebug"
var obj = pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
// def: MethodInfo = "Void Log(System.Object)"
// param = HelloWorldWithDebug
res = def.Invoke(instance, param);
热更项目 里 调用 UnityEngine.Debug.Log 2.0
public HelloWorldWithScene() {
// 热更项目获取 主项目当前场景
Scene scene = SceneManager.GetActiveScene();
// 热更项目获取 当前场景里的第一个 GameObject
GameObject go = scene.GetRootGameObjects()[0];
// 热更项目获取 主项目里 挂在 GameObject 身上的 HelloWorld 脚本
HelloWorld hw = go.GetComponent<HelloWorld>();
// 热更项目调用 主项目脚本里的方法 Test1
hw.Test1();
public void Test1() {
var pos = transform.position;
pos.x += 10;
transform.position = pos;
void OnHotFixLoaded()
// 主项目调用热更项目的 构造函数
ILTypeInstance obj = appdomain.Instantiate("HotFix_Project.HelloWorldWithScene");
// 获取构造函数
var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
// 初始化 方法
// 只有一个方法 "System.Void HotFix_Project.HelloWorldWithScene::.ctor()"
InitializeMethods();
// m: ILMethod = "HotFix_Project.HelloWorldWithScene..ctor()"
// res: ILTypeInstacen = "HotFix_Project.HelloWorldWithScene"
appdomain.Invoke(m, res, null);
// 在解释器里 运行
res = inteptreter.Run((ILMethod)m, instance, p);
// 执行
esp = Execute(method, esp, out unhandledException);
// 原始IL
// "IL_0000: ldarg.0"
// "IL_0001: call System.Void System.Object::.ctor()"
// "IL_0006: nop"
// "IL_0007: nop"
// "IL_0008: call UnityEngine.SceneManagement.Scene UnityEngine.SceneManagement.SceneManager::GetActiveScene()"
// "IL_000d: stloc.0"
// "IL_000e: ldloca.s V_0"
// "IL_0010: call UnityEngine.GameObject[] UnityEngine.SceneManagement.Scene::GetRootGameObjects()"
// "IL_0015: ldc.i4.0"
// "IL_0016: ldelem.ref"
// "IL_0017: stloc.1"
// "IL_0018: ldloc.1"
// "IL_0019: callvirt !!0 UnityEngine.GameObject::GetComponent<HelloWorld>()"
// "IL_001e: stloc.2"
// "IL_001f: ldloc.2"
// "IL_0020: callvirt System.Void HelloWorld::Test1()"
// "IL_0025: nop"
// "IL_0026: ret"
// 自定义IL
// Ldarg_0, 0, 0
// 获取
OpCode[] body = method.Body;
InitCodeBody();
// 将 原始 IL 转换为 自定义的 IL
InitToken(ref body[i], c.Operand, addr);
// Ldarg_0, 0, 0 无特殊转换
// Call, 0, 1 TokenLong = 1 参数数量 也就是实例自己
// Nop, 0, 0 无特殊转换
// Nop, 0, 0 无特殊转换
// Call, 2, 0 TokenInteger = 2 对应的是 "UnityEngine.SceneManagement.Scene UnityEngine.SceneManagement.SceneManager::GetActiveScene()"
// Stloc_0, 0, 0 无特殊转换
// Ldloca_S, 0, 0 TokenInteger = 0 局部变量索引
// Call, 3, 0 TokenInteger = 3 对应的是 UnityEngine.GameObject[] UnityEngine.SceneManagement.Scene::GetRootGameObjects()
// Ldc_I4_0, 0, 0 无特殊转换
// Ldelem_Ref, 0, 0 无特转换
// Stloc_1, 0, 0 无特殊转换
// Ldloc_1, 0, 0 无特殊转换
// Callvirt, 4, 0 TokenInteger = 4 对应的是 "!!0 UnityEngine.GameObject::GetComponent<HelloWorld>()"
// Stloc_2, 0, 0 无特殊转换
// Ldloc_2, 0, 0 无特殊转换
// Callvirt, 5, 0 TokenInteger = 5 对应的是 System.Void HelloWorld::Test1()
// Nop, 0, 0 无特殊转换
// Ret, 0, 0 无特殊转换
code = ip->Code;
switch(code)
case Ldarg_0: // 将"HotFix_Project.HelloWorldWithScene" 复制到 非托管栈
case Call: // 平衡栈
case Nop: // 无操作
case Nop: // 无操作
case Call: // 根据 TokenInteger = 2 调用 "UnityEngine.SceneManagement.Scene GetActiveScene()"
// instance = null
// param = null
// def: MethodInfo = "UnityEngine.SceneManagement.Scene GetActiveScene()"
// 返回 res: UnityEngine.SceneManagement.Scene
res = def.Invoke(instance, param);
case Stloc_0: // 从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中. 操作 局部变量 scene
case Ldloca_S: // 将位于特定索引处的局部变量的地址加载到计算堆栈上(短格式)。操作 局部变量 scene
case Call: // 根据 TokenInteger = 3 调用 UnityEngine.GameObject[] UnityEngine.SceneManagement.Scene::GetRootGameObjects()
// 返回 res: UnityEngine.GameObject[1]
res = def.Invoke(instance, param);
case Ldc_I4_0: // 将整数值 0 作为 int32 推送到计算堆栈上
case Ldelem_Ref: // 将位于指定数组索引处的包含对象引用的元素作为 O 类型(对象引用)加载到计算堆栈的顶部。 也就是操作 gameobject
case Stloc_1: // 从计算堆栈的顶部弹出当前值并将其存储到索引 1 处的局部变量列表中。 也就是操作 gameObject
case Ldloc_1: // 将索引 1 处的局部变量加载到计算堆栈上。 也就是操作 gameobject
case Callvirt: // 对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。
// 通过 TokenInteger = 4 调用 "HelloWorld GetComponent[HelloWorld]()"
// instance = 主工程 场景里的 GameObject
// def: MethodInfo = "HelloWorld GetComponent[HelloWorld]()"
// res: HelloWorld 场景里 GameObject 上的 HelloWorld 脚本
res = def.Invoke(instance, param);
case Stloc_2: // 从计算堆栈的顶部弹出当前值并将其存储到索引 2 处的局部变量列表中。 也就是操作 HelloWorld
case Ldloc_2: // 将索引 2 处的局部变量加载到计算堆栈上 也就是操作 HelloWorld
case Callvirt: // 根据 TokenInteger = 2 调用 System.Void HelloWorld::Test1()"
// instance = 主工程 HelloWorld 脚本实例
// def: MethodInfo = "Void Test1()"
// res = null
res = def.Invoke(instance, param);
case Nop: // 无操作
case Ret: // 返回
热更项目里调用主工程的方法 2.0 简化处理,便于理解
Debug.Log("通过IMethod调用方法");
//预先获得IMethod,可以减低每次调用查找方法耗用的时间
IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
//根据方法名称和参数个数获取方法
IMethod method = type.GetMethod("StaticFunTest", 0);
appdomain.Invoke(method, null, null);
通过IMethod调用方法
//预先获得IMethod,可以减低每次调用查找方法耗用的时间
IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
Debug.Log("指定参数类型来获得IMethod");
IType intType = appdomain.GetType(typeof(int));
//参数类型列表
List<IType> paramList = new List<ILRuntime.CLR.TypeSystem.IType>();
paramList.Add(intType);
//根据方法名称和参数类型列表获取方法
IMethod method = type.GetMethod("StaticFunTest2", paramList, null);
appdomain.Invoke(method, null, 456);
指定参数类型来获得IMethod
Debug.Log("实例化热更里的类");
object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { 233 });
IType t;
// 根据 "HotFix_Project.InstanceClass" HotFix_Project.InstanceClass
if (mapType.TryGetValue(type, out t))
ILType ilType = t as ILType;
if (ilType != null)
// 有构造函数
bool hasConstructor = args != null && args.Length != 0;
// 初始化 "HotFix_Project.InstanceClass"
var res = ilType.Instantiate(!hasConstructor);
// 生成 ILTypeInstance
var res = new [ILTypeInstance](this);
this.type = type;
// 根据实例字段数量 初始化 StackObject[1]
fields = new StackObject[type.TotalFieldCount];
// 根据实例字段数量 初始化 List<object>[1]
managedObjs = new List<object>(fields.Length);
// managedObjs 里的元素 默认为null
for (int i = 0; i < fields.Length; i++)
managedObjs.Add(null);
// 初始化 HotFix_Project.InstanceClass 的字段
[ILTypeInstance].InitializeFields(type);
for (int i = 0; i < type.FieldTypes.Length; i++)
// ILRuntime.CLR.TypeSystem.IType
var ft = type.FieldTypes[i];
StackObject.Initialized(ref fields[type.FieldStartIndex + i], type.FieldStartIndex + i, ft.TypeForCLR, ft, managedObjs);
// 是基本类型
if (t.IsPrimitive)
if (t == typeof(int) || t == typeof(uint) || t == typeof(short) || t == typeof(ushort) || t == typeof(byte) || t == typeof(sbyte) || t == typeof(char) || t == typeof(bool))
StackObject 的 ObjectType 为 int32
esp.ObjectType = ObjectTypes.Integer;
esp.Value = 0;
esp.ValueLow = 0;
if (type.BaseType != null && type.BaseType is ILType)
InitializeFields((ILType)type.BaseType);
return res;
// 如果有构造函数
if (hasConstructor)
// 通过参数数量 获取 构造函数
var ilm = ilType.GetConstructor(args.Length);
if (constructors == null)
InitializeMethods();
foreach (var i in constructors)
if (i.ParameterCount == paramCnt)
return i;
return null;
// 根据 ILMethod ILTypeInstance , args 调用方法
[AppDomain].Invoke(ilm, res, args);
// 请求解释器
ILIntepreter inteptreter = RequestILIntepreter();
// 解释器 运行 方法
res = inteptreter.Run((ILMethod)m, instance, p);
// 有 this
if (method.HasThis)
if (instance is CrossBindingAdaptorType)
instance = ((CrossBindingAdaptorType)instance).ILInstance;
if (instance == null)
throw new NullReferenceException("instance should not be null!");
// 将实例 压栈
esp = PushObject(esp, mStack, instance);
// 将参数入栈
esp = PushParameters(method, esp, p);
bool unhandledException;
// 执行方法
esp = Execute(method, esp, out unhandledException);
return res;
return null;
//预先获得IMethod,可以减低每次调用查找方法耗用的时间
IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
//第二种方式
object obj2 = ((ILType)type).Instantiate();
实例化热更里的类
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);
// 不是 静态构造函数 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);
// 获取 返回类型 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;
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;
// 解释器 执行这个方法
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);
// 栈对象里的对象的类型 是 Object
esp->ObjectType = ObjectTypes.Object;
// 栈对象里的的值是 托管对象数组的索引
esp->Value = mStack.Count;
// 将 HotFix_Project.InstanceClass: {ILRuntime.Runtime.Intepreter.ILTypeInstance} 压入托管列表
mStack.Add(obj);
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
mStack.Add(obj);
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)
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
// esp = 0x5b4bf03c
return stack.PopFrame(ref frame, esp);
// 栈帧出栈
if (frames.Count > 0 && frames.Peek().BasePointer == frame.BasePointer)
frames.Pop();
throw new NotSupportedException();
// 返回的 StackObject* 临时变量 returnVal = 0x5b4bf030 起始指针
StackObject* returnVal = esp - 1;
// method = "HotFix_Project.InstanceClass..ctor()"
var method = frame.Method;
// frame.LocalVarPointer = 0x5b4bf03c
// 真正要返回的 StackObject*
StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
// 栈帧存储的 托管对象索引 = 0
int mStackBase = frame.ManagedStackBase;
// 实例方法 有 this
if (method.HasThis)
// ret = 0x5b4bf03c
ret--;
// 不等于
if(method.ReturnType != intepreter.AppDomain.VoidType)
*ret = *returnVal;
if(ret->ObjectType == ObjectTypes.Object)
// 返回的 StackObject* 的value 指向的托管堆 索引
ret->Value = mStackBase;
// 将 返回的 StackObject* 指向的 托管堆的对象 复制到 托管堆 mStackBase位置
managedStack[mStackBase] = managedStack[returnVal->Value];
mStackBase++;
else if(ret->ObjectType == ObjectTypes.ValueTypeObjectReference)
StackObject* oriAddr = frame.ValueTypeBasePointer;
RelocateValueType(ret, ref frame.ValueTypeBasePointer, ref mStackBase);
*(long*)&ret->Value = (long)oriAddr;
// 0x5b4bf03c, 非托管栈指针上移
ret++;
#if DEBUG && !DISABLE_ILRUNTIME_DEBUG
((List<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
#else
// 托管堆 清理
// [0] {ILRuntime.Runtime.Intepreter.ILTypeInstance}
((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
#endif
// 设置 值类型指针
valueTypePtr = frame.ValueTypeBasePointer;
// ret = 0x5b4bf03c
return ret;
// result = HotFix_Project.InstanceClass
object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - 1), domain, mStack)) : null;
// esp = 0x5b4bf03c
// esp - 1= 0x5b4bf030
StackObject.ToObject((esp - 1), domain, mStack)
switch (esp->ObjectType)
case ObjectTypes.Object:
// esp->Value = 0
// 返回托管堆的对象 HotFix_Project.InstanceClass
return mStack[esp->Value];
// 移除托管堆对象
// 现在托管堆空了
((UncheckedList<object>)mStack).RemoveRange(mStackBase, mStack.Count - mStackBase);
// retuurn HotFix_Project.InstanceClass
return result;
finally
// 清空解释器
FreeILIntepreter(inteptreter);
lock (freeIntepreters)
// 清空托管堆
inteptreter.Stack.ManagedStack.Clear();
// 清空 Stack<StackFrame>
inteptreter.Stack.Frames.Clear();
// 将这个解释器 放入到 空闲解释器 队列
freeIntepreters.Enqueue(inteptreter);
// res = HotFix_Project.InstanceClass
return res;
实例化热更里的类2.0 简化处理,便于理解
Debug.Log("实例化热更里的类");
object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { 233 });
Debug.Log("调用成员方法");
int id = (int)appdomain.Invoke("HotFix_Project.InstanceClass", "get_ID", obj, null);
Debug.Log("!! HotFix_Project.InstanceClass.ID = " + id);
id = (int)appdomain.Invoke("HotFix_Project.InstanceClass", "get_ID", obj2, null);
Debug.Log("!! HotFix_Project.InstanceClass.ID = " + id);
调用成员方法
Debug.Log("调用泛型方法");
IType stringType = appdomain.GetType(typeof(string));
IType[] genericArguments = new IType[] { stringType };
appdomain.InvokeGenericMethod("HotFix_Project.InstanceClass", "GenericMethod", genericArguments, null, "TestString");
IType t = GetType(type);
if (t == null)
return null;
// Name: GenericMethod
// CallingConvention: Generic
// FullName: System.Void HotFix_Project.InstanceClass::GenericMethod(T)
// ILRuntime.Mono.Cecil.GenericParameterCollection ["T"]
var m = t.GetMethod(method, p.Length);
if (m != null)
// 生成泛型方法
m = m.MakeGenericMethod(genericArguments);
KeyValuePair<string, IType>[] genericParameters = new KeyValuePair<string, IType>[genericArguments.Length];
for (int i = 0; i < genericArguments.Length; i++)
string name = def.GenericParameters[i].Name;
IType val = genericArguments[i];
genericParameters[i] = new KeyValuePair<string, IType>(name, val);
ILMethod m = new ILMethod(def, declaringType, appdomain);
m.genericParameters = genericParameters;
m.genericArguments = genericArguments;
if (m.def.ReturnType.IsGenericParameter)
m.ReturnType = m.FindGenericArgument(m.def.ReturnType.Name);
return m;
return Invoke(m, instance, p);
return null;
调用泛型方法
IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
IType intType = appdomain.GetType(typeof(int));
//参数类型列表
List<IType> paramList = new List<ILRuntime.CLR.TypeSystem.IType>();
IType stringType = appdomain.GetType(typeof(string));
IType[] genericArguments = new IType[] { stringType };
Debug.Log("获取泛型方法的IMethod
");
paramList.Clear();
paramList.Add(intType);
genericArguments = new IType[] { intType };
IMethod method = type.GetMethod("GenericMethod", paramList, genericArguments);
appdomain.Invoke(method, null, 33333);
获取泛型方法的IMethod
Debug.Log("完全在热更DLL内部使用的委托,直接可用,不需要做任何处理");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);
using System;
using System.Collections.Generic;
namespace HotFix_Project
public class TestDelegate
static TestDelegateMethod delegateMethod;
public static void Initialize()
delegateMethod = Method;
public static void RunTest()
delegateMethod(123);
static void Method(int a)
UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
new AppDomain()
dMgr = new DelegateManager(this);
defaultConverter: Func<Delegate, Delegate> = DefaultConverterStub;
// 注册委托转换器
dMgr.RegisterDelegateConvertor<Action>((dele) => { return dele; });
// System.Action
var type = typeof(T);
// System.Action 是 Delegate
if (type.IsSubclassOf(typeof(Delegate)))
// action
// System.Func`2
// [System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],
// [System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
// Nop, 0, 0
// Ldnull, 0, 0
// Ldfftn, 1, 0
// Newobj, 2, 0
// Stsfld, 0, 17179869184
// Ret, 0, 0
[ILIntepreter].Execute
// 将指向实现特定方法的本机代码的非托管指针(native int 类型)推送到计算堆栈上
OpCodeEnum.Ldftn:
// HotFix_Project.TestDelegate.Method(Int32 a)
IMethod m = domain.GetMethod(ip->TokenInteger);
// 将这个方法入栈
esp = PushObject(esp, mStack, m);
// 创建一个值类型的新对象或新实例,并将对象引用(O 类型)推送到计算堆栈上。
case OpCodeEnum.Newobj:
// TestDelegateMethod.Void .ctor(Object, IntPtr)
IMethod m = domain.GetMethod(ip->TokenInteger);
if (!m is ILMethod)
CLRMethod cm = (CLRMethod)m;
// TestDelegateMethod 是委托
if (cm.DeclearingType.IsDelegate)
// "HotFix_Project.TestDelegate.Method(Int32 a)"
var mi = (IMethod)mStack[(esp - 1)->Value];
if (((ILMethod)mi).DelegateAdapter == null)
// 设置 DelegateAdapter
((ILMethod)mi).DelegateAdapter = domain.DelegateManager.FindDelegateAdapter(null, (ILMethod)mi);
// new 一个 dummyAdapter
res = dummyAdapter.Instantiate(appdomain, instance, method);
return new DummyDelegateAdapter(appdomain, instance, method);
DelegateAdapter()
this.appdomain = appdomain;
this.instance: ILTypeInstance = instance;
this.method: ILMethod = method;
CLRInstance: object = this;
// "HotFix_Project.TestDelegate.Method(Int32 a)"
dele: object = ((ILMethod)mi).DelegateAdapter;
// 入栈
esp = PushObject(esp, mStack, dele);
// 用来自计算堆栈的值替换静态字段的值
case OpCodeEnum.Stsfld:
// "HotFix_Project.TestDelegate"
type = AppDomain.GetType((int)(ip->TokenLong >> 32));
if type is ILType
ILType t = type as ILType;
val = esp - 1;
t.StaticInstance.AssignFromStack((int)ip->TokenLong, val, AppDomain, mStack);
// fieldIndx = 0, fields.Length = 1
if (fieldIdx < fields.Length && fieldIdx >= 0)
AssignFromStackSub(ref fields[fieldIdx], fieldIdx, esp, managedStack);
case ObjectTypes.FieldReference:
field.Value = fieldIdx;
managedObjs[fieldIdx] = ILIntepreter.CheckAndCloneValueType(managedStack[esp->Value], Type.AppDomain);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest", null, null);
// "HotFix_Project.TestDelegate.RunTest()"
return Invoke(m, instance, p);
// Nop, 0, 0
// Ldsfld, 0, 12884901888
// Ldc_I4_S, 0, 123
// Callvirt, 3, 0
// Nop, 0, 0
// Ret, 0, 0
res = inteptreter.Run((ILMethod)m, instance, p);
esp = Execute(method, esp, out unhandledException);
case OpCodeEnum.Ldsfld:
// "HotFix_Project.TestDelegate"
type = AppDomain.GetType((int)(ip->TokenLong >> 32));
// t.StaticInstance: ILTypeStaticInstance
t.StaticInstance.PushToStack((int)ip->TokenLong, esp, AppDomain, mStack);
// 将提供的 int8 值作为 int32 推送到计算堆栈上(短格式)
case OpCodeEnum.Ldc_I4_S:
esp->Value = ip->TokenInteger;
esp->ObjectType = ObjectTypes.Integer;
case OpCodeEnum.Callvirt:
// TestDelegateMethod.Invoke
IMethod m = domain.GetMethod(ip->TokenInteger);
LRMethod cm = (CLRMethod)m;
if (cm.IsDelegateInvoke)
// instance = "HotFix_Project.TestDelegate.Method(Int32 a)"
var instance = StackObject.ToObject((Minus(esp, cm.ParameterCount + 1)), domain, mStack);
if (instance is IDelegateAdapter)
esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);
var ebp = esp;
esp = ILInvokeSub(intp, esp, mStack);
var ebp = esp;
bool unhandled;
if (method.HasThis)
esp = ILIntepreter.PushObject(esp, mStack, instance);
int paramCnt = method.ParameterCount;
for(int i = paramCnt; i > 0; i--)
intp.CopyToStack(esp, Minus(ebp, i), mStack);
esp++;
// 调用实际方法
// Nop, 0, 0
// Ldstr, 0, -1182677902
// Ldarg_0, 0, 0
// Box, 4, 0
// Call, 5, 0
// Nop, 0, 0
// Ret, 0, 0
var ret = intp.Execute(method, esp, out
unhandled);
case Ldarg_0:
// 将 参数 123 拷贝到 栈上
CopyToStack(esp, arg, mStack);
// 装箱
case OpCodeEnum.Box:
if (type.TypeForCLR.IsPrimitive)
case ObjectTypes.Integer:
esp = PushObject(objRef, mStack, objRef->Value, true);
// 0 "HotFix_Project.TestDelegate.Method(Int32 a)"
// 1 "!! TestDelegate.Method, a = "
// 2 123
mStack
case OpCodeEnum.Call:
// "System.String Concat(System.Object, System.Object)"
IMethod m = domain.GetMethod(ip->TokenInteger);
object result = cm.Invoke(this, esp, mStack);
// param
// 0 "!! TestDelegate.Method, a = "
// 1 123
res = def.Invoke(instance, param);
case OpCodeEnum.Call:
// "UnityEngine.Debug.Log"
object result = cm.Invoke(this, esp, mStack);
if (next != null)
if (method.ReturnType != appdomain.VoidType)
intp.Free(ret - 1);//Return value for multicast delegate doesn't make sense, only return the last one's value
DelegateAdapter n = (DelegateAdapter)next;
ret = n.ILInvokeSub(intp, ebp, mStack);
return ret;
return ClearStack(intp, esp, ebp, mStack);
processed = true;
完全在热更DLL内部使用的委托
OnHotFixLoaded()
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
Initialize
"
,
null
,
null
);
//
method = "HotFix_Project.TestDelegate.Initialize()"
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldnull"
//
"IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
//
"IL_0008: newobj System.Void HotFix_Project.MyDelegate::.ctor(System.Object,System.IntPtr)"
//
"IL_000d: stsfld HotFix_Project.MyDelegate HotFix_Project.TestDelegate::myDelegate"
//
"IL_0012: ret"
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Newobj:
//
获取 "HotFix_Project.MyDelegate..ctor(Object object, IntPtr method)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
//
热更里的委托是ILMethod
if
(m
is
ILMethod)
//
获取委托指向的方法 "HotFix_Project.TestDelegate.Method(Int32 a)"
var
mi = (IMethod)mStack[(esp -
1
)->
Value];
//
是ILMethod
if
(mi
is
ILMethod)
if
(((ILMethod)mi).DelegateAdapter ==
null
)
//
去 委托管理器 里查找 委托适配器
((ILMethod)mi).DelegateAdapter = domain.[DelegateManager].FindDelegateAdapter(
null
, (ILMethod)mi);
//
返回类型是 void
if
(method.ReturnType ==
appdomain.VoidType)
//
初始化一个 dummyAdapter
res =
dummyAdapter.Instantiate(appdomain, instance, method);
return
new
DummyDelegateAdapter(appdomain, instance, method);
//
将 DummyDelegateAdapter 入栈, 这个 委托适配里 包含了 对应的方法
esp =
PushObject(esp, mStack, dele);
case
OpCodeEnum.Stsfld:
//
type = "HotFix_Project.TestDelegate"
type = AppDomain.GetType((
int
)(ip->TokenLong >>
32
));
//
是 ILType
if
(type
is
ILType)
ILType t
= type
as
ILType;
val
= esp -
1
;
//
将 "HotFix_Project.TestDelegate.Method(Int32 a)" 复制给 静态字段 HotFix_Project.TestDelegate::delegateMethod
t.StaticInstance.AssignFromStack((
int
)ip->
TokenLong, val, AppDomain, mStack);
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
RunTest
"
,
null
,
null
);
//
method = "HotFix_Project.TestDelegate.RunTest()"
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldsfld HotFix_Project.MyDelegate HotFix_Project.TestDelegate::myDelegate"
//
"IL_0006: ldc.i4 456"
//
"IL_000b: callvirt System.Void HotFix_Project.MyDelegate::Invoke(System.Int32)"
//
"IL_0010: nop"
//
"IL_0011: ret"
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Ldsfld:
//
获取"HotFix_Project.TestDelegate"
type = AppDomain.GetType((
int
)(ip->TokenLong >>
32
));
//
将 HotFix_Project.TestDelegate 的指向 IDelegateAdapter 的静态成员 入栈
t.StaticInstance.PushToStack((
int
)ip->
TokenLong, esp, AppDomain, mStack);
case
OpCodeEnum.Callvirt:
//
m = "HotFix_Project.MyDelegate.Invoke(Int32 a)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
if
(m
is
ILMethod)
if
(m.IsDelegateInvoke)
//
从栈上获取 HotFix_Project.TestDelegate.Method(Int32 a):IDelegateAdapter 委托适配器
var
instance = StackObject.ToObject((Minus(esp, m.ParameterCount +
1
)), domain, mStack);
if
(instance
is
IDelegateAdapter)
esp
= ((IDelegateAdapter)instance).ILInvoke(
this
, esp, mStack);
var
ebp =
esp;
esp
=
[DummyDelegateAdapter].ILInvokeSub(intp, esp, mStack);
//
调用委托适配器指向的 方法
//
method = "HotFix_Project.TestDelegate.Method(Int32 a)"
var
ret = intp.Execute(method, esp,
out
unhandled);
return
ClearStack(intp, esp, ebp, mStack);
热更里的工程调用热更里的委托实例(该委托类型在热更项目里声明, 该委托实例指向热更里的函数, 不需要注册适配器)2.0
OnHotFixLoaded()
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
Initialize
"
,
null
,
null
);
//
method = "HotFix_Project.TestDelegate.Initialize()"
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldnull"
//
"IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
//
"IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
//
"IL_000d: stsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
//
"IL_0012: ret"
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Newobj:
//
获取 TestDelegateMethod."Void .ctor(Object, IntPtr)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
//
主工程里的 委托构造函数 不是ILMethod, 而是 CLRMethod
if
(m
is
not ILMethod)
//
转型为 CLRMethod
CLRMethod cm =
(CLRMethod)m;
if
(cm.DeclearingType.IsDelegate)
//
从栈上获取 mi = "HotFix_Project.TestDelegate.Method(Int32 a)"
var
mi = (IMethod)mStack[(esp -
1
)->
Value];
//
热更工程里的 方法是 ILMethod
if
(mi
is
ILMethod)
if
(ins ==
null
)
//
委托实际调用的方法 默认是没有 DelegateAdapter的
if
(((ILMethod)mi).DelegateAdapter ==
null
)
//
去 委托管理器 里查找 委托适配器
((ILMethod)mi).DelegateAdapter = domain.[DelegateManager].FindDelegateAdapter(
null
, (ILMethod)mi);
//
返回类型是 void
if
(method.ReturnType ==
appdomain.VoidType)
//
初始化一个 dummyAdapter
res =
dummyAdapter.Instantiate(appdomain, instance, method);
return
new
DummyDelegateAdapter(appdomain, instance, method);
//
将 DummyDelegateAdapter 入栈, 这个 委托适配里 包含了 对应的方法
esp =
PushObject(esp, mStack, dele);
case
OpCodeEnum.Stsfld:
//
type = "HotFix_Project.TestDelegate"
type = AppDomain.GetType((
int
)(ip->TokenLong >>
32
));
//
是 ILType
if
(type
is
ILType)
ILType t
= type
as
ILType;
val
= esp -
1
;
//
将 "HotFix_Project.TestDelegate.Method(Int32 a)" 复制给 静态字段 HotFix_Project.TestDelegate::delegateMethod
t.StaticInstance.AssignFromStack((
int
)ip->
TokenLong, val, AppDomain, mStack);
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
RunTest
"
,
null
,
null
);
//
method = "HotFix_Project.TestDelegate.RunTest()"
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
//
"IL_0006: ldc.i4.s 123"
//
"IL_0008: callvirt System.Void TestDelegateMethod::Invoke(System.Int32)"
//
"IL_0010: nop"
//
"IL_0011: ret"
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Ldsfld:
//
获取"HotFix_Project.TestDelegate"
type = AppDomain.GetType((
int
)(ip->TokenLong >>
32
));
//
将 HotFix_Project.TestDelegate 的指向 IDelegateAdapter 的静态成员 入栈
t.StaticInstance.PushToStack((
int
)ip->
TokenLong, esp, AppDomain, mStack);
case
OpCodeEnum.Callvirt:
//
m = "TestDelegateMethod Void Invoke(Int32)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
//
主工程的委托Invoke 不是 ILMethod 而是 CLRMethod
if
(m
is
not ILMethod)
//
转型为 CLRMethod
CLRMethod cm =
(CLRMethod)m;
if
(m.IsDelegateInvoke)
//
从栈上获取 HotFix_Project.TestDelegate.Method(Int32 a):IDelegateAdapter
var
instance = StackObject.ToObject((Minus(esp, m.ParameterCount +
1
)), domain, mStack);
if
(instance
is
IDelegateAdapter)
esp
= ((IDelegateAdapter)instance).ILInvoke(
this
, esp, mStack);
var
ebp =
esp;
esp
=
[DummyDelegateAdapter].ILInvokeSub(intp, esp, mStack);
//
调用委托适配器指向的 方法
//
method = "HotFix_Project.TestDelegate.Method(Int32 a)"
var
ret = intp.Execute(method, esp,
out
unhandled);
return
ClearStack(intp, esp, ebp, mStack);
热更里的工程调用热更里的委托实例(该委托类型在主工程项目里声明, 该委托实例指向热更里的函数, 不需要注册适配器)2.0
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;
//
将 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> 报错
converters[type]
=
res;
return
res;
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
RunTest2
"
,
null
,
null
);
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldsfld TestDelegateMethod DelegateDemo::TestMethodDelegate"
//
"IL_0006: ldc.i4.s 123"
//
"IL_0008: callvirt System.Void TestDelegateMethod::Invoke(System.Int32)"
//
"IL_000d: nop"
//
"IL_000e: ret"
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Ldsfld:
//
获取"DelegateDemo"
type = AppDomain.GetType((
int
)(ip->TokenLong >>
32
));
//
主工程的 是 CLRType
if
(type
is
not ILType)
CLRType t
= type
as
CLRType;
int
idx = (
int
)ip->
TokenLong;
var
f =
t.GetField(idx);
obj
= t.GetFieldValue(idx,
null
);
if
(obj
is
CrossBindingAdaptorType)
obj
=
((CrossBindingAdaptorType)obj).ILInstance;
//
将委托压栈
PushObject(esp, mStack, obj, f.FieldType ==
typeof
(
object
));
case
OpCodeEnum.Callvirt:
//
m = "TestDelegateMethod Void Invoke(Int32)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
//
主工程的委托Invoke 不是 ILMethod 而是 CLRMethod
if
(m
is
not ILMethod)
//
转型为 CLRMethod
CLRMethod cm =
(CLRMethod)m;
if
(cm.IsDelegateInvoke)
//
从栈上获取 instance: TestDelegateMethod
var
instance = StackObject.ToObject((Minus(esp, m.ParameterCount +
1
)), domain, mStack);
//
不是
if
(instance
is
IDelegateAdapter)
//
cm: CLRMethod = "TestDelegateMethod Void Invoke(Int32)"
object
result = cm.Invoke(
this
, esp, mStack);
//
def: MethodInfo = "Void Invoke(Int32)"
res =
def.Invoke(instance, param);
return
new
TestDelegateMethod((a) =>
{
//
调用委托实例
((System.Action<
int
>
)action)(a);
//
{ILRuntime.Runtime.Intepreter.MethodDelegateAdapter`1[System.Int32]}
InvokeILMethod(T1 p1)
热更里的工程将热更里的函数赋值给主工程里的委托实例(该委托类型在主工程项目里声明,该委托实例指向热更里的函数)2.0
Debug.Log("如果需要跨域调用委托(将热更DLL里面的委托实例传到Unity主工程用), 就需要注册适配器,不然就会像下面这样");
try {
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
[ILIntepreter].Run
// "DelegateDemo"
CLRType t = type as CLRType;
// 1233051648
int idx = (int)ip->TokenLong;
// t.Fields
// "[1233051648, TestDelegateMethod TestMethodDelegate]"
// "[-628392448, TestDelegateFunction TestFunctionDelegate]"
// "[1805130752, System.Action`1[System.String] TestActionDelegate]"
var f = t.GetField(idx);
val = esp - 1;
case OpCodeEnum.Newobj:
// 注册过委托
if (match)
// method: "HotFix_Project.TestDelegate.Method(Int32 a)"
// Adapter: MethodDelegateAdapter<T1>
res = i.Adapter.Instantiate(appdomain, instance, method);
MethodDelegateAdapter<T1>.Instantiate
return new MethodDelegateAdapter<T1>(appdomain, instance, method);
// action: {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
action = InvokeILMethod;
using (var c = appdomain.BeginInvoke(method))
if (m is ILMethod)
ILIntepreter inteptreter = RequestILIntepreter();
return new InvocationContext(inteptreter, (ILMethod)m);
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;
res = appdomain.DelegateManager.ConvertToDelegate(type, this);
[DelegateManager].ConvertToDelegate
// 是 DummyDelegateAdapter 抛出异常
if(adapter is DummyDelegateAdapter)
DelegateAdapter.ThrowAdapterNotFound(adapter.Method);
return null;
// 如果事先注册过了
// clrDelegates
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[TestDelegateMethod, System.Func`2[System.Delegate,System.Delegate]]"
if (clrDelegates.TryGetValue(clrDelegateType, out func))
return func(adapter.Delegate);
converters[type] = res;
return res;
} catch (System.Exception ex) {
Debug.LogError(ex.ToString());
//为了演示,清除适配器缓存,实际使用中不要这么做
ClearDelegateCache();
Debug.Log("这是因为iOS的IL2CPP模式下,不能动态生成类型,为了避免出现不可预知的问题,我们没有通过反射的方式创建委托实例,因此需要手动进行一些注册");
Debug.Log("首先需要注册委托适配器,刚刚的报错的错误提示中,有提示需要的注册代码");
//下面这些注册代码,正式使用的时候,应该写在InitializeILRuntime中
//TestDelegateMethod, 这个委托类型为有个参数为int的方法,注册仅需要注册不同的参数搭配即可
appdomain.DelegateManager.RegisterMethodDelegate<int>();
DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
node.Adapter = new MethodDelegateAdapter<T1>();
pType: static InvocationTypes = GetInvocationType<T1>();
node.ParameterTypes = new Type[] { typeof(T1) };
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
methods.Add(node);
RegisterDelegateConvertor<Action<T1>>(defaultConverter);
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
//带返回值的委托的话需要用RegisterFunctionDelegate,返回类型为最后一个
appdomain.DelegateManager.RegisterFunctionDelegate<int, string>();
DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
node.Adapter = new FunctionDelegateAdapter<T1, TResult>();
node.ParameterTypes = new Type[] { typeof(T1), typeof(TResult) };
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
functions.Add(node);
RegisterDelegateConvertor<Func<T1, TResult>>(defaultConverter);
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
//Action<string> 的参数为一个string
appdomain.DelegateManager.RegisterMethodDelegate<string>();
DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
node.Adapter = new MethodDelegateAdapter<T1>();
node.ParameterTypes = new Type[] { typeof(T1) };
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
methods.Add(node);
RegisterDelegateConvertor<Action<T1>>(defaultConverter);
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
Debug.Log("注册完毕后再次运行会发现这次会报另外的错误");
try {
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
} catch (System.Exception ex) {
Debug.LogError(ex.ToString());
Debug.Log("ILRuntime内部是用Action和Func这两个系统内置的委托类型来创建实例的,所以其他的委托类型都需要写转换器");
Debug.Log("将Action或者Func转换成目标委托类型");
appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) => {
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[TestDelegateMethod, System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
//转换器的目的是把Action或者Func转换成正确的类型,这里则是把Action<int>转换成TestDelegateMethod
return new TestDelegateMethod((a) => {
//调用委托实例
// {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
// Method: Void InvokeILMethod(Int32)
// Target: "HotFix_Project.TestDelegate.Method(Int32 a)"
((System.Action<int>)action)(a);
////对于TestDelegateFunction同理,只是是将Func<int, string>转换成TestDelegateFunction
//appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) => {
// return new TestDelegateFunction((a) => {
// return ((System.Func<int, string>)action)(a);
// });
//});
////下面再举一个这个Demo中没有用到,但是UGUI经常遇到的一个委托,例如UnityAction<float>
//appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<float>>((action) => {
// return new UnityEngine.Events.UnityAction<float>((a) => {
// ((System.Action<float>)action)(a);
// });
//});
Debug.Log("现在我们再来运行一次");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest2", null, null);
//debug.log("运行成功,我们可以看见,用action或者func当作委托类型的话,可以避免写转换器,所以项目中在不必要的情况下尽量只用action和func");
//debug.log("另外应该尽量减少不必要的跨域委托调用,如果委托只在热更dll中用,是不需要进行任何注册的");
//debug.log("---------");
//debug.log("我们再来在unity主工程中调用一下刚刚的委托试试");
//testmethoddelegate(789);
//var str = testfunctiondelegate(098);
//debug.log("!! onhotfixloaded str = " + str);
//testactiondelegate("hello from unity main project");
namespace
HotFix_Project {
public
class
TestDelegate {
static
Action<
string
>
delegateAction;
public
static
void
Initialize() {
delegateAction
=
Action;
public
static
void
RunTest() {
delegateAction(
"
rrr
"
);
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
Initialize
"
,
null
,
null
);
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldnull"
//
"IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Action(System.String)"
//
"IL_0008: newobj System.Void System.Action`1<System.String>::.ctor(System.Object,System.IntPtr)"
//
"IL_000d: stsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction"
//
"IL_0012: ret"
//
自定义OpCode
//
Nop, 0, 0
//
Ldnull, 0, 0
//
Ldftn, 1, 0
//
Newobj, 2, 0
//
Stsfld, 0, 12884901888
//
Ret, 0, 0
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Ldftn:
//
m = "HotFix_Project.TestDelegate.Action(String a)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
esp
=
PushObject(esp, mStack, m);
case
OpCodeEnum.Newobj:
//
"System.Action`1[System.String] Void .ctor(Object, IntPtr)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
if
(m
is
CLRMethod)
//
Action<string> 当然是Delegate
if
(cm.DeclearingType.IsDelegate)
//
获取托管堆上方法
//
"HotFix_Project.TestDelegate.Action(String a)"
var
mi = (IMethod)mStack[(esp -
1
)->
Value];
//
热更里的类型的方法
if
(mi
is
ILMethod)
//
调用 Action<string> 没有注册DelegateAdapter,所以为null
if
(((ILMethod)mi).DelegateAdapter ==
null
)
//
去委托管理器里面赵 委托适配器
((ILMethod)mi).DelegateAdapter = domain.DelegateManager.FindDelegateAdapter(
null
, (ILMethod)mi);
//
没有注册所以直接实例化一个 DummyAdapter
res =
dummyAdapter.Instantiate(appdomain, instance, method);
return
new
DummyDelegateAdapter(appdomain, instance, method);
this
.appdomain =
appdomain;
this
.instance =
instance;
//
DummyAdapter.method = "HotFix_Project.TestDelegate.Action(String a)"
this
.method =
method;
//
CLRInstance 就是 这个 DummyAdapter
CLRInstance =
this
;
dele
=
((ILMethod)mi).DelegateAdapter;
case
OpCodeEnum.Stsfld:
//
type = "HotFix_Project.TestDelegate"
type = AppDomain.GetType((
int
)(ip->TokenLong >>
32
));
if
(type
is
ILType)
ILType t
= type
as
ILType;
val
= esp -
1
;
//
将 HotFix_Project.TestDelegate.Action(String a): DummyDelegateAdapter 赋值给 静态字段 delegateAction
t.StaticInstance.AssignFromStack((
int
)ip->
TokenLong, val, AppDomain, mStack);
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
RunTest
"
,
null
,
null
);
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction"
//
"IL_0006: ldstr \"rrr\""
//
"IL_000b: callvirt System.Void System.Action`1<System.String>::Invoke(!0)"
//
"IL_0010: nop"
//
"IL_0011: ret"
//
自定义OpCode
//
Nop, 0, 0
//
Ldsfld, 0, 12884901888
//
Ldstr, 0, 386853784
//
Callvirt, 5, 0
//
Nop, 0, 0
//
Ret, 0, 0
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Ldsfld:
//
type = "HotFix_Project.TestDelegate"
type = AppDomain.GetType((
int
)(ip->TokenLong >>
32
));
if
(type
is
ILType)
ILType t
= type
as
ILType;
//
将 TestDelegate.delegateAction 对应的值 也就是 "HotFix_Project.TestDelegate.Action(String a)":DummyAdapter 入栈
t.StaticInstance.PushToStack((
int
)ip->
TokenLong, esp, AppDomain, mStack);
case
OpCodeEnum.Ldstr:
//
将字符串 "rrr" 入栈
esp = PushObject(esp, mStack, AppDomain.GetString(ip->
TokenLong));
case
OpCodeEnum.Callvirt:
//
m = "System.Action`1[System.String] Void Invoke(System.String)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
if
(m
is
CLRMethod)
if
(cm.IsDelegateInvoke)
//
"HotFix_Project.TestDelegate.Action(String a)": DummyAdapter
var
instance = StackObject.ToObject((Minus(esp, cm.ParameterCount +
1
)), domain, mStack);
if
(instance
is
IDelegateAdapter)
//
DummyAdapter.ILInvoke
esp = ((IDelegateAdapter)instance).ILInvoke(
this
, esp, mStack);
var
ebp =
esp;
esp
=
ILInvokeSub(intp, esp, mStack);
//
将参数入栈
for
(
int
i = paramCnt; i >
0
; i--
)
intp.CopyToStack(esp, Minus(ebp, i), mStack);
*dst = *
src;
if
(dst->ObjectType >=
ObjectTypes.Object)
dst
->Value =
mStack.Count;
var
obj = mStack[src->
Value];
mStack.Add(obj);
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldstr \"!! TestDelegate.Action, a = \""
//
"IL_0006: ldarg.0"
//
"IL_0007: call System.String System.String::Concat(System.String,System.String)"
//
"IL_000c: call System.Void UnityEngine.Debug::Log(System.Object)"
//
"IL_0011: nop"
//
"IL_0012: ret"
//
Nop, 0, 0
//
Ldstr, 0, 1342813397
//
Ldarg_0, 0, 0
//
Call, 4, 0
//
Call, 5, 0
//
Nop, 0, 0
//
Ret, 0, 0
var
ret = intp.Execute(method, esp,
out
unhandled);
case
OpCodeEnum.Ldstr:
//
将 "!! TestDelegate.Action, a = " 入栈
esp = PushObject(esp, mStack, AppDomain.GetString(ip->
TokenLong));
//
将"rrr" 入栈
case
OpCodeEnum.Ldarg_0:
CopyToStack(esp, arg, mStack);
case
OpCodeEnum.Call:
//
m = "System.String Concat(System.String, System.String)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
if
(m
is
CLRMethod)
//
result = "!! TestDelegate.Action, a = rrr"
object
result = cm.Invoke(
this
, esp, mStack);
case
OpCodeEnum.Call:
//
m = "UnityEngine.Debug Void Log(System.Object)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
if
(m
is
CLRMethod)
//
result = "!! TestDelegate.Action, a = rrr"
object
result = cm.Invoke(
this
, esp, mStack);
if
(m
is
CLRMethod)
//
调用 UnityEngine.Debug.Log("!! TestDelegate.Action, a = rrr");
object
result = cm.Invoke(
this
, esp, mStack);
return
ClearStack(intp, esp, ebp, mStack);
processed
=
true
;
热更项目调用Action 委托
OnHotFixLoaded() {
TypeDefinition td = appdomain.typeDef[
"
HotFix_Project.TestDelegate
"
];
MyType mt
=
new
MyType(td);
List
<
object
> managedStack =
new
List<
object
>(
5
);
for
(
int
i =
0
; i <
5
; i++
) {
managedStack.Add(
null
);
System.Delegate dele
=
null
;
System.Type type
=
null
;
MyDelegateAdapter da
=
null
;
foreach
(
var
item
in
td.Methods[
0
].Body.Instructions) {
UnityEngine.Debug.Log(item);
switch
(item.OpCode.Code) {
//
ldftn System.Void HotFix_Project.TestDelegate::Action(System.String)
case
Code.Ldftn:
MethodDefinition md
= item.Operand
as
MethodDefinition;
managedStack[
0
] =
md;
break
;
//
newobj System.Void System.Action`1<System.String>::.ctor(System.Object,System.IntPtr
case
Code.Newobj:
MethodReference mr
= item.Operand
as
MethodReference;
//
System.Action`1<System.String> 替换成 System.Action`1[System.String]
type = System.Type.GetType(mr.DeclaringType.FullName.Replace(
'
<
'
,
'
[
'
).Replace(
'
>
'
,
da
=
new
MyDelegateAdapter(managedStack[
0
]
as
MethodDefinition);
break
;
//
stsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction
case
Code.Stsfld:
//
将 DelegateAdapter 设置给这个字段
mt.staticField =
da;
managedStack.Remove(
0
);
break
;
//
ldsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction
case
Code.Ldsfld:
MyDelegateAdapter da1
= (mt.staticField
as
MyDelegateAdapter);
managedStack[
0
] =
da1;
break
;
//
ldstr "hahaah"
case
Code.Ldstr:
managedStack[
1
] =
"
hahaah
"
;
break
;
//
callvirt System.Void System.Action`1<System.String>::Invoke(!0)
case
Code.Callvirt:
MyDelegateAdapter da2
= managedStack[
0
]
as
MyDelegateAdapter;
da2.Invoke();
break
;
default
:
break
;
public
class
MyType {
public
TypeDefinition td;
public
object
staticField;
public
MyType(TypeDefinition td) {
this
.td =
td;
public
class
MyDelegateAdapter {
public
MethodDefinition md;
public
MyDelegateAdapter(MethodDefinition md) {
this
.md =
md;
public
void
Invoke() {
foreach
(
var
item
in
md.Body.Instructions) {
Debug.Log(item);
switch
(item.OpCode.Code) {
//
ldarg.0
case
Code.Ldarg_0:
//
managedStack[2] = "hahaah"
break
;
//
call System.Void UnityEngine.Debug::Log(System.Object)
case
Code.Call:
//
UnityEngine.Debug.Log(managedStack[2])
UnityEngine.Debug.Log(
"
hahaah
"
);
break
;
委托调用流程自定义
System.Func<System.Delegate, System.Delegate> func = new System.Func<System.Delegate, System.Delegate>((dele) => {
Debug.Log(dele.GetType());
return dele;
System.Action ac = () => {
Debug.Log("Action");
((System.Action)func(ac))();
System.Func<System.Delegate, System.Delegate>
public
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
//
获取 TestClassBase的 type
return
typeof
(TestClassBase);
//
这是你想继承的那个类
public
override
Type AdaptorType
//
获取 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
;
base
.TestVirtual(str);
public
override
int
Value
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;
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();
return
instance.Type.FullName;
Debug.Log(
"
首先我们来创建热更里的类实例
"
);
TestClassBase obj;
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;
//
没注册就找不到
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;
//
"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))
//
以上都不是,根据 TestClassBase: Type 查找 adapter
if
(appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR,
out
adaptor))
//
现在 baseType 是 {InheritanceAdapter}
baseType =
adaptor;
var
curBase =
baseType;
var
curBase =
baseType;
//
不是 ILType
while
(curBase
is
ILType)
curBase
=
curBase.BaseType;
//
type.FirstCLRBaseType = HotFix_Project.TestInheritance.InheritanceAdapter 是 CrossBindingAdaptor
if
(type.FirstCLRBaseType
is
Enviorment.CrossBindingAdaptor)
//
{InheritanceAdapter}.CreateCLRInstance
clrInstance = ((Enviorment.CrossBindingAdaptor)type.FirstCLRBaseType).CreateCLRInstance(type.AppDomain,
this
);
//
new InheritanceAdapter+Adaptor
return
new
Adaptor(appdomain, instance);
//
创建一个新的实例
//
获取 HotFix_Project.TestInheritance 的构造函数
var
m =
GetConstructor(CLR.Utils.Extensions.EmptyParamList);
//
m: HotFix_Project.TestInheritance..ctor()
appdomain.Invoke(m, res,
null
);
res
=
inteptreter.Run((ILMethod)m, instance, p);
//
Ldarg_0, 0, 0
//
Call, 536870913, 0
//
Nop, 0, 0
//
Ret, 0, 0
esp = Execute(method, esp,
out
unhandledException);
case
OpCodeEnum.Ldarg_0:
//
将 HotFix_Project.TestInheritance 压栈
CopyToStack(esp, arg, mStack);
case
OpCodeEnum.Call:
//
通过 StackObject.TokenInteger 获取 HotFix_Project.TestInheritance.ctor()
IMethod m = domain.GetMethod(ip->
TokenInteger);
//
转换成 CLRMethod
CLRMethod cm =
(CLRMethod)m;
cm.Invoke
return
(T)ins.CLRInstance;
Debug.Log(
"
现在来调用成员方法
"
);
obj.TestAbstract(
123
);
if
(!
mTestAbstractGot)
//
instance: "HotFix_Project.TestInheritance"
//
获取实际执行的热更里面的代码
mTestAbstract = instance.Type.GetMethod(
"
TestAbstract
"
,
1
);
//
获取到了 这个方法
mTestAbstractGot =
true
;
if
(mTestAbstract !=
null
)
param1[
0
] =
ab;
//
调用热更里的方法
//
mTestAbstract: HotFix_Project.TestInheritance.TestAbstract(Int32 gg)
//
instance: "HotFix_Project.TestInheritance"
//
param1: ab = 123
appdomain.Invoke(mTestAbstract, instance, param1);
//
没有参数建议显式传递null为参数列表,否则会自动new object[0]导致GC Alloc
obj.TestVirtual(
"
Hello
"
);
Debug.Log(
"
现在换个方式创建实例
"
);
obj
= appdomain.Invoke(
"
HotFix_Project.TestInheritance
"
,
"
NewObject
"
,
null
,
null
)
as
TestClassBase;
obj.TestAbstract(
456
);
obj.TestVirtual(
"
Foobar
"
);
namespace
HotFix_Project {
//
一定要特别注意,:后面只允许有1个Unity主工程的类或者接口,但是可以有随便多少个热更DLL中的接口
public
class
TestInheritance : TestClassBase {
public
override
void
TestAbstract(
int
gg) {
UnityEngine.Debug.Log(
"
!! TestInheritance.TestAbstract gg =
"
+
gg);
public
override
void
TestVirtual(
string
str) {
base
.TestVirtual(str);
UnityEngine.Debug.Log(
"
!! TestInheritance.TestVirtual str =
"
+
str);
public
static
TestInheritance NewObject() {
return
new
HotFix_Project.TestInheritance();
Inheritance
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;
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];
if
(totalFieldCnt <
0
)
if
(fieldMapping ==
null
)
//
初始化字段
InitializeFields();
int
idx =
FieldStartIndex;
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;
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
//
手动设置 HotFix_Project.TestInheritance 基类类型为 TestClassBase
return
typeof
(TestClassBase);
//
这是你想继承的那个类
public
override
Type AdaptorType
//
手动设置 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
;
base
.TestVirtual(str);
public
override
int
Value
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;
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();
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;
//
"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;
throw
new
Exception(
"
Crossbinding Adapter for
"
+ bType.FullName +
"
is already added.
"
);
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;
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
//
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();
code.TokenInteger
=
token.GetHashCode();
//
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
;
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
CLRMethod cm
=
(CLRMethod)m;
//
调用 InheritanceAdapter+Adaptor 的构造函数
object
result = cm.Invoke(
this
, esp, mStack);
//
是构造函数
if
(isConstructor)
//
cDef: ConstructorInfo 不是静态
if
(!
cDef.IsStatic)
//
declaringType: CLRType = "InheritanceAdapter+Adaptor"
//
declaringType.TypeForCLR: Type = {InheritanceAdapter+Adaptor}
object
instance = declaringType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((Minus(esp, paramCount +
1
)), appdomain, mStack));
//
pt:Type = {InheritanceAdapter+Adaptor}
//
obj: ILTypeInstance = "HotFix_Project.TestInheritance"
CheckCLRTypes(
this
Type pt,
object
obj)
else
if
(obj
is
ILTypeInstance)
//
尝试转型为 IDelegateAdapter, 转型失败
var
adapter = obj
as
IDelegateAdapter;
//
是 ILEnumTypeInstance
if
(!(obj
is
ILEnumTypeInstance))
var
ins =
(ILTypeInstance)obj;
//
返回 HotFix_Project.TestInheritance 的 CLRInstance
//
也就是InheritanceAdapter+Adaptor
return
ins.CLRInstance;
if
(instance
is
CrossBindingAdaptorType && paramCount ==
0
)
//
It makes no sense to call the Adaptor's default constructor
return
null
;
//
ins = {ILRuntime.Runtime.Intepreter.ILTypeInstance}
//
ins.CLRInstance = {InheritanceAdapter+Adaptor}
//
InheritanceAdapter+Adaptor 继承自 TestClassBase, 所以可以转型
return
(T)ins.CLRInstance;
//
obj.GetType() == {InheritanceAdapter+Adaptor}
obj.TestAbstract(
123
);
if
(!
mTestAbstractGot)
//
instance: ILTypeInstance = "HotFix_Project.TestInheritance"
//
instance.Type: ILType = "HotFix_Project.TestInheritance"
//
获取 热更里 HotFix_Project.TestInheritance 的 TestAbstract 方法
mTestAbstract = instance.Type.GetMethod(
"
TestAbstract
"
,
1
);
mTestAbstractGot
=
true
;
if
(mTestAbstract !=
null
)
param1[
0
] =
ab;
//
调用 热更里 HotFix_Project.TestInheritance.TestAbstract 方法
appdomain.Invoke(mTestAbstract, instance, param1);
//
没有参数建议显式传递null为参数列表,否则会自动new object[0]导致GC Alloc
obj.TestVirtual(
"
Hello
"
);
Debug.Log(
"
现在换个方式创建实例
"
);
obj
= appdomain.Invoke(
"
HotFix_Project.TestInheritance
"
,
"
NewObject
"
,
null
,
null
)
as
TestClassBase;
obj.TestAbstract(
456
);
obj.TestVirtual(
"
Foobar
"
);
Inheritance, CrossBindingAdaptor 2.0
public
class
HelloWorldWithInheritanceAdapter: MyClassBase {
public
HelloWorldWithInheritanceAdapter() {
Debug.Log(
"
Inheritance.Constructor
"
);
public
override
void
TestMethod() {
Debug.Log(
"
Inheritance.TestMethod
"
);
//
自定义 TypeInstance
public
class
MyTypeInstance {
public
TypeDefinition def;
public
MyTypeInstance(TypeDefinition def) {
this
.def =
def;
public
void
Invoke(
string
methodName) {
foreach
(
var
item
in
def.Methods) {
if
(item.Name ==
"
TestMethod
"
) {
foreach
(
var
i
in
item.Body.Instructions) {
Debug.Log(i);
//
适配器 和 热更项目里的类 要继承的基类
public
class
MyClassBase {
public
MyClassBase() {
Debug.Log(
"
MyClassBase.Constructor
"
);
public
virtual
void
TestMethod() {
Debug.Log(
"
BaseMethod
"
);
//
适配器
public
class
MyClassBaseAdapter: MyClassBase {
public
MyTypeInstance instance;
public
MyClassBaseAdapter() {
Debug.Log(
"
MyClassBaseAdapter.Constructor
"
);
public
override
void
TestMethod() {
instance.Invoke(
"
TestMethod
"
);
void
OnHotFixLoaded()
//
获取热更项目的类型定义
TypeDefinition type = appdomain.typeDef[
"
HotFix_Project.HelloWorldWithInheritanceAdapter
"
];
//
根据 TypeDefinition 实例化 MyTypeInstance
MyTypeInstance ins =
new
MyTypeInstance(type);
//
实际 运行的 Adaptor 的 TestMethod 方法
MyClassBaseAdapter adapter =
new
MyClassBaseAdapter();
adapter.instance
=
ins;
//
适配器里 运行 MyTypeInstance 即热更项目里 的 TestMethod 方法
adapter.TestMethod();
热更工程继承主工程, 使用适配器的 流程2.0. 简化处理, 方便理解
namespace
HotFix_Project {
public
class
TestCLRRedirection {
public
static
void
RunTest() {
UnityEngine.Debug.Log(
"
看看这行的详细Log信息
"
);
看看这行的详细Log信息
System.Reflection.MethodBase:Invoke(Object, Object[])
ILRuntime.CLR.Method.CLRMethod:Invoke(ILIntepreter, StackObject
*, IList`
1
, Boolean) (at Assets/ILRuntime/CLR/Method/CLRMethod.cs:
316
)
ILRuntime.Runtime.Intepreter.ILIntepreter:Execute(ILMethod, StackObject
*, Boolean&) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:
1797
)
ILRuntime.Runtime.Intepreter.ILIntepreter:Run(ILMethod, Object, Object[]) (at Assets
/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:
96
)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(IMethod, Object, Object[]) (at Assets
/ILRuntime/Runtime/Enviorment/AppDomain.cs:
1061
)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(String, String, Object, Object[]) (at Assets
/ILRuntime/Runtime/Enviorment/AppDomain.cs:
964
)
CLRRedirectionDemo:OnHotFixLoaded() (at Assets
/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:
85
)
<LoadHotFixAssembly>d__4:MoveNext() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:
63
)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
Debug.Log(
"
什么时候需要CLR重定向呢,当我们需要挟持原方法实现,添加一些热更DLL中的特殊处理的时候,就需要CLR重定向了
"
);
Debug.Log(
"
详细文档请参见Github主页的相关文档
"
);
Debug.Log(
"
CLR重定向对ILRuntime底层实现密切相关,因此要完全理解这个Demo,需要大家先看关于ILRuntime实现原理的Demo
"
);
Debug.Log(
"
下面介绍一个CLR重定向的典型用法,比如我们在DLL里调用Debug.Log,默认情况下是无法显示DLL内堆栈的,像下面这样
"
);
Debug.Log(
"
但是经过CLR重定向之后可以做到输出DLL内堆栈,接下来进行CLR重定向注册
"
);
var
mi =
typeof
(Debug).GetMethod(
"
Log
"
,
new
System.Type[] {
typeof
(
object
) });
//
appdomain.RegisterCLRMethodRedirection(mi, Log_11);
//
这个只是为了演示加的,平时不要这么用,直接在InitializeILRuntime方法里面写CLR重定向注册就行了
Debug.Log(
"
我们再来调用一次刚刚的方法,注意看下一行日志的变化
"
);
appdomain.Invoke(
"
HotFix_Project.TestCLRRedirection
"
,
"
RunTest
"
,
null
,
null
);
//
Nop, 0, 0
//
Ldstr, 0, -1877045637
//
Call, 1, 0
//
Nop, 0, 0
//
Ret, 0, 0
res =
inteptreter.Run((ILMethod)m, instance, p);
case
OpCodeEnum.Call:
//
cm: CLRMethod = "Void Log(System.Object)"
//
cm.Redirection = null
var
redirect =
cm.Redirection;
object
result = cm.Invoke(
this
, esp, mStack);
//
def: MethodInfo = "Void Log(System.Object)"
//
param = "看看这行的详细Log信息"
res =
def.Invoke(instance, param);
有重定向 调用 esp
= redirect(
this
, esp, mStack, cm,
false
);
1781
看看这行的详细Log信息
at HotFix_Project.TestCLRRedirection.RunTest()
UnityEngine.Debug:Log(Object)
CLRRedirectionDemo:Log_11(ILIntepreter, StackObject
*, IList`
1
, CLRMethod, Boolean) (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:
109
)
ILRuntime.Runtime.Intepreter.ILIntepreter:Execute(ILMethod, StackObject
*, Boolean&) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:
1781
)
ILRuntime.Runtime.Intepreter.ILIntepreter:Run(ILMethod, Object, Object[]) (at Assets
/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:
96
)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(IMethod, Object, Object[]) (at Assets
/ILRuntime/Runtime/Enviorment/AppDomain.cs:
1061
)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(String, String, Object, Object[]) (at Assets
/ILRuntime/Runtime/Enviorment/AppDomain.cs:
964
)
CLRRedirectionDemo:OnHotFixLoaded() (at Assets
/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:
85
)
<LoadHotFixAssembly>d__4:MoveNext() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:
63
)
UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)
Debug.Log(
"
什么时候需要CLR重定向呢,当我们需要挟持原方法实现,添加一些热更DLL中的特殊处理的时候,就需要CLR重定向了
"
);
Debug.Log(
"
详细文档请参见Github主页的相关文档
"
);
Debug.Log(
"
CLR重定向对ILRuntime底层实现密切相关,因此要完全理解这个Demo,需要大家先看关于ILRuntime实现原理的Demo
"
);
Debug.Log(
"
下面介绍一个CLR重定向的典型用法,比如我们在DLL里调用Debug.Log,默认情况下是无法显示DLL内堆栈的,像下面这样
"
);
Debug.Log(
"
但是经过CLR重定向之后可以做到输出DLL内堆栈,接下来进行CLR重定向注册
"
);
var
mi =
typeof
(Debug).GetMethod(
"
Log
"
,
new
System.Type[] {
typeof
(
object
) });
appdomain.RegisterCLRMethodRedirection(mi, Log_11);
//
mi = "Void Log(System.Object)"
//
func: CLRRedirectionDelegate = Log_11:
redirectMap[mi] =
func;
//
这个只是为了演示加的,平时不要这么用,直接在InitializeILRuntime方法里面写CLR重定向注册就行了
Debug.Log(
"
我们再来调用一次刚刚的方法,注意看下一行日志的变化
"
);
appdomain.Invoke(
"
HotFix_Project.TestCLRRedirection
"
,
"
RunTest
"
,
null
,
null
);
//
Nop, 0, 0
//
Ldstr, 0, -1877045637
//
Call, 1, 0
//
Nop, 0, 0
//
Ret, 0, 0
res =
inteptreter.Run((ILMethod)m, instance, p);
case
OpCodeEnum.Call:
//
cm: CLRMethod = "Void Log(System.Object)"
//
cm.Redirection = CLRRedirectionDemo.Log_11
var
redirect =
cm.Redirection;
esp
= redirect(
this
, esp, mStack, cm,
false
);
//
ILRuntime的调用约定为被调用者清理堆栈,因此执行这个函数后需要将参数从堆栈清理干净,并把返回值放在栈顶,具体请看ILRuntime实现原理文档
ILRuntime.Runtime.Enviorment.AppDomain __domain =
__intp.AppDomain;
StackObject
*
ptr_of_this_method;
//
这个是最后方法返回后esp栈指针的值,应该返回清理完参数并指向返回值,这里是只需要返回清理完参数的值即可
//
__esp = 0x5d1b201c
//
__ret = 0x5d1b2010
StackObject* __ret = ILIntepreter.Minus(__esp,
1
);
//
取Log方法的参数,如果有两个参数的话,第一个参数是esp - 2,第二个参数是esp -1, 因为Mono的bug,直接-2值会错误,所以要调用ILIntepreter.Minus
//
ptr_of_this_method = 0x5d1b2010
ptr_of_this_method = ILIntepreter.Minus(__esp,
1
);
//
这里是将栈指针上的值转换成object,如果是基础类型可直接通过ptr->Value和ptr->ValueLow访问到值,具体请看ILRuntime实现原理文档
//
ptr_of_this_method = 0x5d1b2010
//
IList = [ ""看看这行的详细Log信息"" ]
object
message =
typeof
(
object
).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
Type.CheckCLRTypes
StackObject.ToObject
case
ObjectTypes.Object:
//
esp->Value = 0 表示 从 __mStack 0位置 取得 对象
return
mStack[esp->
Value];
//
所有非基础类型都得调用Free来释放托管堆栈
__intp.Free(ptr_of_this_method);
//
在真实调用Debug.Log前,我们先获取DLL内的堆栈
var
stacktrace =
__domain.DebugService.GetStackTrace(__intp);
StringBuilder sb
=
new
StringBuilder();
ILRuntime.CLR.Method.ILMethod m;
//
获取RuntimeStack 里的 StackFrames
//
只有1帧
//
Address: IntegerReference = null
//
BasePointer: StackObject* = 0x5d1b2010
//
LocalVarPointer: StackObject* = 0x5d1b2010
//
ManagedStackBase: int = 0
//
Method: ILMethod = HotFix_Project.TestCLRRedirection.RunTest()
//
ValueTypeBasePointer: StackObject* = 0x5d1e2004
StackFrame[] frames =
intepreper.Stack.Frames.ToArray();
Mono.Cecil.Cil.Instruction ins
=
null
;
if
(frames[
0
].Address !=
null
)
ins
= frames[
0
].Method.Definition.Body.Instructions[frames[
0
].Address.Value];
sb.AppendLine(ins.ToString());
for
(
int
i =
0
; i < frames.Length; i++
)
//
获取 StackFrame
var
f =
frames[i];
//
获取 Method = "HotFix_Project.TestCLRRedirection.RunTest()"
m =
f.Method;
string
document =
""
;
if
(f.Address !=
null
)
ins
=
m.Definition.Body.Instructions[f.Address.Value];
var
seq =
FindSequencePoint(ins, m.Definition.DebugInformation.GetSequencePointMapping());
if
(seq !=
null
)
document
=
string
.Format(
"
{0}:Line {1}
"
, seq.Document.Url, seq.StartLine);
//
"at HotFix_Project.TestCLRRedirection.RunTest() \r\n"
sb.AppendFormat(
"
at {0} {1}\r\n
"
, m, document);
return
sb.ToString();
//
我们在输出信息后面加上DLL堆栈
UnityEngine.Debug.Log(message +
"
\n
"
+ stacktrace);
CLRRedirection
namespace
HotFix_Project {
public
class
TestCLRRedirection {
public
static
void
RunTest() {
UnityEngine.Debug.Log(
"
看看这行的详细Log信息
"
);
//
获取 Debug.Log 的 MethodBase
var
mi =
typeof
(Debug).GetMethod(
"
Log
"
,
new
System.Type[] {
typeof
(
object
) });
//
将对 Debug.Log 的调用 重定向到 Log_11中
appdomain.RegisterCLRMethodRedirection(mi, Log_11);
//
这个只是为了演示加的,平时不要这么用,直接在InitializeILRuntime方法里面写CLR重定向注册就行了
Debug.Log(
"
我们再来调用一次刚刚的方法,注意看下一行日志的变化
"
);
appdomain.Invoke(
"
HotFix_Project.TestCLRRedirection
"
,
"
RunTest
"
,
null
,
null
);
//
m = HotFix_Project.TestCLRRedirection
//
instance = null
inteptreter.Run((ILMethod)m, instance, p);
//
esp: StackObject*
esp = Execute(method, esp,
out
unhandledException);
//
如果这个方法的 重定向方法 不为空
if
(method.Redirection !=
null
)
//
调用这个 重定向方法
//
esp: StackObject* = 0xa68cb04c
//
esp-> ObjectType = Null
//
esp-> Value = 10
//
esp-> ValueLow = 1
//
mStack = [ "看看这行的详细Log信息" ]
esp = redirect(
this
, esp, mStack, cm,
false
);
//
ILRuntime的调用约定为被调用者清理堆栈,因此执行这个函数后需要将参数从堆栈清理干净,并把返回值放在栈顶,具体请看ILRuntime实现原理文档
ILRuntime.Runtime.Enviorment.AppDomain __domain =
__intp.AppDomain;
//
这个是最后方法返回后esp栈指针的值,应该返回清理完参数并指向返回值,这里是只需要返回清理完参数的值即可
//
__ret: StackObject* = 0xa68cb040
//
__ret-> ObjectType = Object
//
__ret-> Value = 0
//
__ret-> ValueLow = 1374408720
//
__ret 是返回指针, 因为参数不需要了 所以将 栈 下移 1
StackObject* __ret = ILIntepreter.Minus(__esp,
1
);
//
取Log方法的参数,如果有两个参数的话,第一个参数是esp - 2,第二个参数是esp -1, 因为Mono的bug,直接-2值会错误,所以要调用ILIntepreter.Minus
//
ptr_of_this_method: StackObject* = 0xa68cb040
//
ptr_of_this_method-> ObjectType = Object
//
ptr_of_this_method-> Value = 0
//
ptr_of_this_method-> ValueLow = 1374408720
//
参数1 StackObject* 指针
StackObject* ptr_of_this_method = ILIntepreter.Minus(__esp,
1
);
//
这里是将栈指针上的值转换成object,如果是基础类型可直接通过ptr->Value和ptr->ValueLow访问到值,具体请看ILRuntime实现原理文档
object
message =
typeof
(
object
).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
//
获取 0xa68cb040 处的 StackObject
StackObject.ToObject
switch
(esp->
ObjectType)
case
ObjectTypes.Object:
//
根据 索引 esp->Value = 0 获取 托管堆 里的 对象 = "看看这行的详细Log信息"
return
mStack[esp->
Value];
//
将托管堆里的 object 转型为合适的类型
Type.CheckCLRTypes
//
所有非基础类型都得调用Free来释放托管堆栈
__intp.Free(ptr_of_this_method);
//
在真实调用Debug.Log前,我们先获取DLL内的堆栈
var
stacktrace =
__domain.DebugService.GetStackTrace(__intp);
//
我们在输出信息后面加上DLL堆栈
UnityEngine.Debug.Log(message +
"
\n
"
+
stacktrace);
return
__ret;
方法重定向 2.0, 简化处理, 便于理解
OnHotFixLoaded()
//
开启或关闭 重定向
//
ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);
var
type = appdomain.LoadedTypes[
"
HotFix_Project.InstanceClass
"
];
//
调用 无参构造函数
object
obj = appdomain.Instantiate(
"
HotFix_Project.InstanceClass
"
,
new
object
[] { });
//
esp = 0x77064030
StackObject* esp =
stack.StackBase;
//
将实例本身压栈, 栈地址由低到高
esp =
PushObject(esp, mStack, instance);
esp
->ObjectType =
ObjectTypes.Object;
//
Value = 0
esp->Value =
mStack.Count;
//
mStack[0] = "HotFix_Project.InstanceClass": ILTypeInstance
mStack.Add(obj);
//
esp = 0x7706403c
//
栈向上移动1个 StackObject*,也就是12个字节
return
esp +
1
;
//
将"HotFix_Project.InstanceClass..ctor()"入栈
esp =
PushParameters(method, esp, p);
//
这是个无参构造函数,栈没有变换 esp = 0x7706403c
return
esp;
//
调用这个方法
//
原始IL
//
"IL_0000: ldarg.0"
//
"IL_0001: call System.Void System.Object::.ctor()"
//
"IL_0006: nop"
//
"IL_0007: nop"
//
"IL_0008: call UnityEngine.Vector3 UnityEngine.Vector3::get_one()"
//
"IL_000d: stloc.0"
//
"IL_000e: ret"
//
自定义IL
//
Ldarg_0, 0, 0
//
Call, 0, 1
//
Nop, 0, 0
//
Nop, 0, 0
//
Call, 2, 0
//
Stloc_0, 0, 0
//
Ret, 0, 0
esp = Execute(method, esp,
out
unhandledException);
//
v1 = 0x7706403c = 原始 esp + 1
StackObject* v1 =
frame.LocalVarPointer;
//
v2 = 0x77064048 = 原始 esp + 2
StackObject* v2 = frame.LocalVarPointer +
1
;
//
esp = 0x77064048 = 原始 esp + 2
esp =
frame.BasePointer;
//
arg = 0x7706403c = 原始 esp + 1
var
arg =
Minus(frame.LocalVarPointer, method.ParameterCount);
if
(method.HasThis)
//
this parameter is always object reference
//
arg = 0x77064030 = 原始 esp
arg--
;
paramCnt
++
;
//
遍历局部变量
for
(
int
i =
0
; i < method.LocalVariableCount; i++
)
//
获取局部变量 v: VariableDefinition
var
v =
method.Variables[i];
//
t: CLRType = "UnityEngine.Vector3"
var
t =
AppDomain.GetType(v.VariableType, method.DeclearingType, method);
if
(t
is
not ILType)
CLRType cT
=
(CLRType)t;
//
loc = 0x7706403c = 原始 esp + 1
var
loc =
Add(v1, i);
//
new 一个 Vector3
obj =
((CLRType)t).CreateDefaultInstance();
loc
->ObjectType =
ObjectTypes.Object;
//
将 loc 的值 设为 mStack[1], mStack[1] = Vector3 Activator.CreateInstance(TypeForCLR);
loc->Value = locBase +
i;
mStack[locBase
+ i] =
obj;
case
OpCodeEnum.Ldarg_0:
//
esp = 0x77064048 = 原始 esp + 2
//
arg = 0x77064030 = 原始 esp 也就是 实例本身
//
将 自身 拷贝到 esp + 2
//
mStack[0] = "HotFix_Project.InstanceClass"
//
mStack[1] = "(0.0, 0.0, 0.0)"
//
mStack[2] = "HotFix_Project.InstanceClass"
CopyToStack(esp, arg, mStack);
//
esp = 0x77064054 = 原始 esp + 3
esp++
case
OpCodeEnum.Call:
//
本来是要调用 call System.Void System.Object::.ctor()"
IMethod m = domain.GetMethod(ip->
TokenInteger);
//
处理过了,所以没有
if
(m ==
null
)
//
Irrelevant method
//
cnt = 1
int
cnt = (
int
)ip->
TokenLong;
//
Balance the stack
for
(
int
i =
0
; i < cnt; i++
)
//
释放 esp - 1 = 0x77064048 也就是 原始 esp + 2
//
移除 mStack[2]
Free(esp -
1
);
//
esp = 0x77064048 也就是 原始 esp + 2
esp--
;
case
OpCodeEnum.Call:
//
获取"UnityEngine.Vector3 get_one()"
IMethod m = domain.GetMethod(ip->
TokenInteger);
//
如果开启了重定向############################
var
redirect =
cm.Redirection;
if
(redirect !=
null
)
//
esp = 0x77064048 = 原始 esp + 2
//
mStack[0] = "HotFix_Project.InstanceClass"
//
mStack[1] = "(0.0, 0.0, 0.0)"
esp = redirect(
this
, esp, mStack, cm,
false
);
//
没有开启重定向#########################################
//
esp = 0x77064048 = 原始 esp + 2
object
result = cm.Invoke(
this
, esp, mStack);
//
System.Reflection.MethodInfo 调用, GC
res =
def.Invoke(instance, param);
ILRuntime.Runtime.Enviorment.AppDomain __domain
=
__intp.AppDomain;
//
_ret = 0x77064048 = 原始 esp + 2
StackObject* __ret = ILIntepreter.Minus(__esp,
0
);
//
result_of_this_method = 自己手写的 Vector3.one
var
result_of_this_method =
UnityEngine.Vector3.one;
if
(ILRuntime.Runtime.Generated.CLRBindings.s_UnityEngine_Vector3_Binding_Binder !=
null
) {
ILRuntime.Runtime.Generated.CLRBindings.s_UnityEngine_Vector3_Binding_Binder.PushValue(
ref
result_of_this_method, __intp, __ret, __mStack);
return
__ret +
1
;
}
else
{
return
ILIntepreter.PushObject(__ret, __mStack, result_of_this_method);
esp
->ObjectType =
ObjectTypes.Object;
//
esp = 0x77064048 = 原始 esp + 2
//
esp->Value = 2
esp->Value =
mStack.Count;
//
mStack[0] = "HotFix_Project.InstanceClass"
//
mStack[1] = "(0.0, 0.0, 0.0)"
//
mStack[2] = "(1.0, 1.0, 1.0)"
mStack.Add(obj);
esp
= PushObject(esp, mStack, result, cm.ReturnType.TypeForCLR ==
typeof
(
object
));
esp
->ObjectType =
ObjectTypes.Object;
//
esp = 0x77064048 = 原始 esp + 2
//
esp->Value = 2
esp->Value =
mStack.Count;
//
mStack[0] = "HotFix_Project.InstanceClass"
//
mStack[1] = "(0.0, 0.0, 0.0)"
//
mStack[2] = "(1.0, 1.0, 1.0)"
mStack.Add(obj);
//
esp = 0x77064054 = 原始 esp + 3
return
esp +
1
case
case
OpCodeEnum.Stloc_0:
//
esp = 0x77064048 = 原始 esp + 2
esp--
;
int
idx =
locBase;
//
esp = 0x77064048 = 原始 esp + 2
//
v = 0x7706403c = 原始 esp + 1
//
bp = 0x77094024 = 原始 esp - 1
//
idx = 1
StLocSub(esp, v1, bp, idx, mStack);
//
原始指针 esp + 2 赋值 给 原始esp + 1 也就是 Vector3 one = Vector3.one;
*v = *
esp;
//
指针对应的 mStack 赋值
mStack[idx] = CheckAndCloneValueType(mStack[v->
Value], domain);
v
->Value =
idx;
//
释放 esp = 0x77064048 = 原始esp + 2
Free(esp);
方法重定向2.1, 简化处理, 便于理解
executed
=
true
;
//
这里为了方便看Profiler,代码挪到Update中了
System.Diagnostics.Stopwatch sw =
new
System.Diagnostics.Stopwatch();
Debug.LogWarning(
"
运行这个Demo前请先点击菜单ILRuntime->Generate来生成所需的绑定代码,并按照提示解除下面相关代码的注释
"
);
Debug.Log(
"
默认情况下,从热更DLL里调用Unity主工程的方法,是通过反射的方式调用的,这个过程中会产生GC Alloc,并且执行效率会偏低
"
);
Debug.Log(
"
接下来进行CLR绑定注册,在进行注册前,需要先在ILRuntimeCodeGenerator的绑定列表里面,添加上CLRBindingTestClass这个测试类型
"
);
Debug.Log(
"
CLR绑定会生成较多C#代码,最终会增大包体和Native Code的内存耗用,所以只添加常用类型和频繁调用的接口即可
"
);
Debug.Log(
"
接下来需要点击Unity菜单里面的ILRuntime->Generate CLR Binding Code来生成绑定代码
"
);
Debug.Log(
"
ILRuntime->Generate CLR Binding Code by Analysis是ILRT1.2版新加入的功能,可以根据热更DLL自动生成绑定代码
"
);
//
由于CLR重定向只能重定向一次,并且CLR绑定就是利用的CLR重定向,所以请在初始化最后阶段再执行下面的代码,以保证CLR重定向生效
//
请在生成了绑定代码后注释下面这行
//
throw new System.Exception("请在生成了绑定代码后再运行这个示例");
//
//
请在生成了绑定代码后解除下面这行的注释
//
请在生成了绑定代码后解除下面这行的注释
//
请在生成了绑定代码后解除下面这行的注释
//
ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);
//
这个只是为了演示加的,平时不需要这么用,直接在InitializeILRuntime方法里面写CLR绑定注册就行了
var
type = appdomain.LoadedTypes[
"
HotFix_Project.TestCLRBinding
"
];
var
m = type.GetMethod(
"
RunTest
"
,
0
);
Debug.Log(
"
现在我们再来试试绑定后的效果
"
);
sw.Reset();
sw.Start();
RunTest2(m);
Profiler.BeginSample(
"
RunTest2
"
);
appdomain.Invoke(m,
null
,
null
);
Intepreter.Execute
//
没有绑定
object
result = cm.Invoke(
this
, esp, mStack); #
1797
//
绑定了
//
redirect: CLRRedirectionDelegate = CLRBindingTestClass_Binding.DoSomeTest_0
esp = redirect(
this
, esp, mStack, cm,
false
);
ILRuntime.Runtime.Enviorment.AppDomain __domain =
__intp.AppDomain;
StackObject
*
ptr_of_this_method;
//
返回指针
StackObject* __ret = ILIntepreter.Minus(__esp,
2
);
//
参数 b
ptr_of_this_method = ILIntepreter.Minus(__esp,
1
);
System.Single @b
= *(
float
*)&ptr_of_this_method->
Value;
//
参数 a
ptr_of_this_method = ILIntepreter.Minus(__esp,
2
);
System.Int32 @a
= ptr_of_this_method->
Value;
//
直接调用 主工程里的方法
var
result_of_this_method =
global
::CLRBindingTestClass.DoSomeTest(@a, @b);
//
__ret: StackObject*
__ret->ObjectType =
ObjectTypes.Float;
*(
float
*)&__ret->Value =
result_of_this_method;
//
__ret + 1
return
__ret +
1
;
Profiler.EndSample();
sw.Stop();
Debug.LogFormat(
"
刚刚的方法执行了:{0} ms
"
, sw.ElapsedMilliseconds);
Debug.Log(
"
可以看到运行时间和GC Alloc有大量的差别,RunTest2之所以有20字节的GC Alloc是因为Editor模式ILRuntime会有调试支持,正式发布(关闭Development Build)时这20字节也会随之消失
"
);
void
RunTest()
appdomain.Invoke(
"
HotFix_Project.TestCLRBinding
"
,
"
RunTest
"
,
null
,
null
);
void
RunTest2(IMethod m)
appdomain.Invoke(m,
null
,
null
);
using
System;
using
System.Collections.Generic;
namespace
HotFix_Project {
public
class
TestCLRBinding {
public
static
void
RunTest() {
for
(
int
i =
0
; i <
100000
; i++
) {
CLRBindingTestClass.DoSomeTest(i, i);
CLRBinding
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);
//
重定向不为空
//
直接调用 redirect 方法
esp = redirect(
this
, esp, mStack, cm,
false
);
CLRBindingTestClass_Binding.DoSomeTest_0(ILIntepreter __intp, StackObject* __esp, IList<
object
> __mStack, CLRMethod __method,
bool
isNewObj)
ILRuntime.Runtime.Enviorment.AppDomain __domain
=
__intp.AppDomain;
StackObject
*
ptr_of_this_method;
StackObject
* __ret = ILIntepreter.Minus(__esp,
2
);
//
第2个参数
ptr_of_this_method = ILIntepreter.Minus(__esp,
1
);
System.Single @b
= *(
float
*)&ptr_of_this_method->
Value;
//
第1个参数
ptr_of_this_method = ILIntepreter.Minus(__esp,
2
);
System.Int32 @a
= ptr_of_this_method->
Value;
//
实际调用的是 主工程的方法
var
result_of_this_method =
global
::CLRBindingTestClass.DoSomeTest(@a, @b);
__ret
->ObjectType =
ObjectTypes.Float;
*(
float
*)&__ret->Value =
result_of_this_method;
return
__ret +
1
;
CLRBinding 2.0, 便于理解, 简化处理
using
System.Collections;
using
ILRuntime.Runtime.Enviorment;
using
ILRuntime.Runtime.Intepreter;
using
ILRuntime.CLR.Method;
public
class
CoroutineAdapter: CrossBindingAdaptor {
public
override
Type BaseCLRType {
get
{
return
null
;
public
override
Type[] BaseCLRTypes {
get
{
//
跨域继承只能有1个Adapter,因此应该尽量避免一个类同时实现多个外部接口,对于coroutine来说是IEnumerator<object>,IEnumerator和IDisposable,
//
ILRuntime虽然支持,但是一定要小心这种用法,使用不当很容易造成不可预期的问题
//
日常开发如果需要实现多个DLL外部接口,请在Unity这边先做一个基类实现那些个接口,然后继承那个基类
return
new
Type[] {
typeof
(IEnumerator<
object
>),
typeof
(IEnumerator),
typeof
(IDisposable) };
public
override
Type AdaptorType {
get
{
return
typeof
(Adaptor);
public
override
object
CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain,ILTypeInstance instance) {
return
new
Adaptor(appdomain, instance);
//
Coroutine生成的类实现了IEnumerator<System.Object>, IEnumerator, IDisposable,所以都要实现,这个可以通过reflector之类的IL反编译软件得知
internal
class
Adaptor: IEnumerator<System.Object>
, IEnumerator, IDisposable, CrossBindingAdaptorType {
ILTypeInstance instance;
ILRuntime.Runtime.Enviorment.AppDomain appdomain;
public
Adaptor() {
public
Adaptor(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance) {
this
.appdomain =
appdomain;
this
.instance =
instance;
public
ILTypeInstance ILInstance {
get
{
return
instance; } }
IMethod mCurrentMethod;
bool
mCurrentMethodGot;
public
object
Current {
get
{
if
(!
mCurrentMethodGot) {
mCurrentMethod
= instance.Type.GetMethod(
"
get_Current
"
,
0
);
if
(mCurrentMethod ==
null
) {
//
这里写System.Collections.IEnumerator.get_Current而不是直接get_Current是因为coroutine生成的类是显式实现这个接口的,通过Reflector等反编译软件可得知
//
为了兼容其他只实现了单一Current属性的,所以上面先直接取了get_Current
mCurrentMethod = instance.Type.GetMethod(
"
System.Collections.IEnumerator.get_Current
"
,
0
);
mCurrentMethodGot
=
true
;
if
(mCurrentMethod !=
null
) {
var
res = appdomain.Invoke(mCurrentMethod, instance,
null
);
return
res;
}
else
{
return
null
;
IMethod mDisposeMethod;
bool
mDisposeMethodGot;
public
void
Dispose() {
if
(!
mDisposeMethodGot) {
mDisposeMethod
= instance.Type.GetMethod(
"
Dispose
"
,
0
);
if
(mDisposeMethod ==
null
) {
mDisposeMethod
= instance.Type.GetMethod(
"
System.IDisposable.Dispose
"
,
0
);
mDisposeMethodGot
=
true
;
if
(mDisposeMethod !=
null
) {
appdomain.Invoke(mDisposeMethod, instance,
null
);
IMethod mMoveNextMethod;
bool
mMoveNextMethodGot;
public
bool
MoveNext() {
if
(!
mMoveNextMethodGot) {
mMoveNextMethod
= instance.Type.GetMethod(
"
MoveNext
"
,
0
);
mMoveNextMethodGot
=
true
;
if
(mMoveNextMethod !=
null
) {
return
(
bool
)appdomain.Invoke(mMoveNextMethod, instance,
null
);
}
else
{
return
false
;
IMethod mResetMethod;
bool
mResetMethodGot;
public
void
Reset() {
if
(!
mResetMethodGot) {
mResetMethod
= instance.Type.GetMethod(
"
Reset
"
,
0
);
mResetMethodGot
=
true
;
if
(mResetMethod !=
null
) {
appdomain.Invoke(mResetMethod, instance,
null
);
public
override
string
ToString() {
IMethod m
= appdomain.ObjectType.GetMethod(
"
ToString
"
,
0
);
m
=
instance.Type.GetVirtualMethod(m);
if
(m ==
null
|| m
is
ILMethod) {
return
instance.ToString();
}
else
{
return
instance.Type.FullName;
public
class
CoroutineDemo: MonoBehaviour {
static
CoroutineDemo instance;
public
static
CoroutineDemo Instance {
get
{
return
instance; }
void
InitializeILRuntime()
//
这里做一些ILRuntime的注册
//
使用Couroutine时,C#编译器会自动生成一个实现了IEnumerator,IEnumerator<object>,IDisposable接口的类,因为这是跨域继承,所以需要写CrossBindAdapter(详细请看04_Inheritance教程),Demo已经直接写好,直接注册即可
appdomain.RegisterCrossBindingAdaptor(
new
CoroutineAdapter());
appdomain.DebugService.StartDebugService(
56000
);
unsafe
void
OnHotFixLoaded() {
appdomain.Invoke(
"
HotFix_Project.TestCoroutine
"
,
"
RunTest
"
,
null
,
null
);
public
void
DoCoroutine(IEnumerator coroutine) {
StartCoroutine(coroutine);
namespace
HotFix_Project {
public
class
TestCoroutine {
public
static
void
RunTest() {
CoroutineDemo.Instance.DoCoroutine(Coroutine());
static
System.Collections.IEnumerator Coroutine() {
Debug.Log(
"
开始协程, t =
"
+
Time.time);
yield
return
new
WaitForSeconds(
3
);
Debug.Log(
"
等待了3秒, t =
"
+
Time.time);
Coroutine
sdsdfsfdsdfsdfsdfsdfs
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); // 热更DLL内的类型比较麻烦。首先我们得自己手动创建实例 // ILType 当然是 自己 new ILTypeInstance var ilInstance = new ILTypeInstance(type as ILType, false ); // 手动创建实例是因为默认方式会new MonoBehaviour,这在Unity里不允许 // 接下来创建Adapter实例 // 这里 实际上 添加的是 Adaptor var clrInstance = instance.AddComponent<MonoBehaviourAdapter.Adaptor> (); // unity创建的实例并没有热更DLL里面的实例,所以需要手动赋值 clrInstance.ILInstance = ilInstance; clrInstance.AppDomain = __domain; // 这个实例默认创建的CLRInstance不是通过AddComponent出来的有效实例,所以得手动替换 ilInstance.CLRInstance = clrInstance; res = clrInstance.ILInstance; // 交给ILRuntime的实例应该为ILInstance clrInstance.Awake(); // 因为Unity调用这个方法时还没准备好所以这里补调一次 // 将 res: ILTypeInstance = "HotFix_Project.SomeMonoBehaviour" 压入到托管栈, return ILIntepreter.PushObject(ptr, __mStack, res); // 更新 esP: StacObject* 指针 esp->ObjectType = ObjectTypes.Object; esp ->Value = mStack.Count; mStack.Add(obj); // 非托管栈指针 向上移 return esp + 1 ; return __esp; MonoBehaviour适配 + AddComponent 重定向, 简化 2.0 void OnHotFixLoaded() { Debug.Log( " C#工程中反射是一个非常经常用到功能,ILRuntime也对反射进行了支持,在热更DLL中使用反射跟原生C#没有任何区别,故不做介绍 " ); Debug.Log( " 这个Demo主要是介绍如何在主工程中反射热更DLL中的类型 " ); Debug.Log( " 假设我们要通过反射创建HotFix_Project.InstanceClass的实例 " ); Debug.Log( " 显然我们通过Activator或者Type.GetType(\"HotFix_Project.InstanceClass\")是无法取到类型信息的 " ); Debug.Log( " 热更DLL中的类型我们均需要通过AppDomain取得 " ); var it = appdomain.LoadedType[ " HotFix_Project.InstanceClass " ]; Debug.Log( " LoadedType返回的是IType类型,但是我们需要获得对应的System.Type才能继续使用反射接口 " ); var type = it.ReflectionType; Debug.Log( " 取得Type之后就可以按照我们熟悉的方式来反射调用了 " ); var ctor = type.GetConstructor( new System.Type[ 0 ]); var obj = ctor.Invoke( null ); Debug.Log( " 打印一下结果 " ); Debug.Log(obj); Debug.Log( " 我们试一下用反射给字段赋值 " ); var fi = type.GetField( " id " , System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); fi.SetValue(obj, 111111 ); Debug.Log( " 我们用反射调用属性检查刚刚的赋值 " ); var pi = type.GetProperty( " ID " ); Debug.Log( " ID = " + pi.GetValue(obj, null )); namespace HotFix_Project public class InstanceClass private int id; public InstanceClass() UnityEngine.Debug.Log( " !!! InstanceClass::InstanceClass() " ); this .id = 0 ; public InstanceClass( int id) UnityEngine.Debug.Log( " !!! InstanceClass::InstanceClass() id = " + id); this .id = id; public int ID get { return id; } // static method public static void StaticFunTest() UnityEngine.Debug.Log( " !!! InstanceClass.StaticFunTest() " ); public static void StaticFunTest2( int a) UnityEngine.Debug.Log( " !!! InstanceClass.StaticFunTest2(), a= " + a); public static void GenericMethod<T> (T a) UnityEngine.Debug.Log( " !!! InstanceClass.GenericMethod(), a= " + a); Reflection 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); */ // 转型为 CLRType CLRType cT = (CLRType)t; // 分配 局部变量指针 // loc: StackObject* var loc = Add(v1, i); // 获取 ValueTypeBinder if (cT.ValueTypeBinder != null ) // stack: RuntimeStack stack.AllocValueType(loc, t); // 创建 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); ValueTypeBinderappdomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
if (!valueTypeBinders.ContainsKey(t))
valueTypeBinders[t] = binder;
binder.RegisterCLRRedirection(this);
args = new Type[] { };
method = type.GetMethod("get_one", flag, null, args, null);
appdomain.RegisterCLRMethodRedirection(method, Get_One);
if (mi == null)
return;
// mi: MethodBase = "UnityEngine.Vector3 get_one()"
// ValueBinder 也是 使用 CLRMethodRedicrection
if (!redirectMap.ContainsKey(mi))
redirectMap[mi] = func;
var ct = GetType(t) as CLRType;
binder.CLRType = ct;
UnityEngine_Vector3_Binding.Register(app);
method = type.GetMethod("get_one", flag, null, args, null);
app.RegisterCLRMethodRedirection(method, get_one_0);
args = new Type[]{};
method = type.GetMethod("get_one", flag, null, args, null);
app.RegisterCLRMethodRedirection(method, get_one_0);
if (mi == null)
return;
// mi: MethodBase = "UnityEngine.Vector3 get_one()"
// 上面已经存过了, 所以不会覆盖.
if (!redirectMap.ContainsKey(mi))
redirectMap[mi] = func;
ValueTypeBinder 也使用 RegisterCLRMethodRedirection
class
TestValueType {
public
static
void
RunTest() {
Vector3 one
=
new
Vector3(
1.0f
,
1.0f
,
1.0f
);
Debug.Log(one);
appdomain.Invoke(
"
HotFix_Project.TestValueType
"
,
"
RunTest
"
,
null
,
null
);
//
原始IL
//
"IL_0000: nop"
//
"IL_0001: ldloca.s V_0"
//
"IL_0003: ldc.r4 1"
//
"IL_0008: ldc.r4 1"
//
"IL_000d: ldc.r4 1"
//
"IL_0012: call System.Void UnityEngine.Vector3::.ctor(System.Single,System.Single,System.Single)"
//
"IL_0017: ldloc.0"
//
"IL_0018: box UnityEngine.Vector3"
//
"IL_001d: call System.Void UnityEngine.Debug::Log(System.Object)"
//
"IL_0022: nop"
//
"IL_0023: ret"
//
自定义OpCode
//
Nop, 0, 0
//
Ldloca_S, 0, 0
//
Ldc_R4, 1065353216, 0
//
Ldc_R4, 1065353216, 0
//
Ldc_R4, 1065353216, 0
//
Call, 1, 0
//
Ldloc_0, 0, 0
//
Box, 3, 0
//
Call, 2, 0
//
Nop, 0, 0
//
Ret, 0, 0
//
esp = 0xa6479050
esp = Execute(method, esp,
out
unhandledException);
//
esp = 0xa647905c, 因为有1个局部变量
esp =
frame.BasePointer;
//
arg = 0xa6479050, 没有参数
var
arg =
Minus(frame.LocalVarPointer, method.ParameterCount);
//
处理局部变量
for
(
int
i =
0
; i < method.LocalVariableCount; i++
)
//
ct: "UnityEngine.Vector3"
CLRType cT =
(CLRType)t;
//
loc = 0xa6479050
var
loc =
Add(v1, i);
//
ct 有 ValueTypeBinder
if
(cT.ValueTypeBinder !=
null
)
//
分配 Vector3 的 存储空间
stack.AllocValueType(loc, t);
//
值类型引用
loc->ObjectType =
ObjectTypes.ValueTypeObjectReference;
//
dst = 0xa64a9044
var
dst =
valueTypePtr;
//
loc = 0xa6479050 指向 valueTypePtr 0xa64a9044
*(
long
*)&loc->Value = (
long
)dst;
dst
->ObjectType =
ObjectTypes.ValueTypeDescriptor;
//
Vector3 的 HashCode
dst->Value =
type.GetHashCode();
//
字段数量
dst->ValueLow =
fieldCount;
//
valueTypePtr = 0xa64a9014
//
留给 Vector3 的3个字段的空间
valueTypePtr = ILIntepreter.Minus(valueTypePtr, fieldCount +
1
);
if
(valueTypePtr <=
StackBase)
throw
new
StackOverflowException();
InitializeValueTypeObject(type, dst);
CLRType t
=
(CLRType)type;
//
3个字段
var
cnt =
t.TotalFieldCount;
for
(
int
i =
0
; i < cnt; i++
)
//
it: Single
var
it = t.OrderedFieldTypes[i]
as
CLRType;
//
val = 3个字段的 StackObject* 地址
//
0xa64a9038
//
0xa64a902c
//
0xa64a9020
StackObject* val = ILIntepreter.Minus(ptr, i +
1
);
if
(it.IsPrimitive)
StackObject.Initialized(val, it);
else
if
(t ==
typeof
(
float
))
esp
->ObjectType =
ObjectTypes.Float;
esp
->Value =
0
;
esp
->ValueLow =
0
;
//
ct 没有 ValueTypeBinder
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;
object
result = cm.Invoke(
this
, esp, mStack);
case
OpCodeEnum.Ldloc_0:
//
esp = 0xa647905c
//
v1 = 0xa6479050
//
mStack[0] = null
CopyToStack(esp, v1, mStack);
//
dst->Value = -1505062844
//
dst->ObjectType = ValueTypeObjectReference
*dst = *
src;
if
(dst->ObjectType >=
ObjectTypes.Object)
dst
->Value =
mStack.Count;
var
obj = mStack[src->
Value];
mStack.Add(obj);
//
esp = 0xa6479068
esp++
case
OpCodeEnum.Box:
//
objRef = 0xa647905c
objRef = esp -
1
;
//
type = "UnityEngine.Vector3" 获取要操作的类型
type = domain.GetType(ip->
TokenInteger);
//
有ValueTypeBinder 的情况下
if
(objRef->ObjectType==
ObjectTypes.ValueTypeObjectReference)
//
解析 0xa647905c->Value = 0xa64a9044 = ValueTypePtr
dst =
ILIntepreter.ResolveReference(objRef);
//
获取到 Vector3: CLRType
var
vt = domain.GetType(dst->
Value);
if
(vt !=
type)
throw
new
InvalidCastException();
//
调用 Vector3 的 ValueTypeBinder.ToObject
object
ins =
((CLRType)vt).ValueTypeBinder.ToObject(dst, mStack);
//
new Vector3()
T obj =
new
T();
AssignFromStack(
ref
obj, esp, managedStack);
//
获取 0xa64a9038
var
v = ILIntepreter.Minus(ptr,
1
);
//
赋值 给 x
ins.x = *(
float
*)&v->
Value;
//
获取 0xa64a902c
v = ILIntepreter.Minus(ptr,
2
);
//
赋值给 y
ins.y = *(
float
*)&v->
Value;
//
获取 0xa64a9020
v = ILIntepreter.Minus(ptr,
3
);
//
赋值给z
ins.z = *(
float
*)&v->
Value;
FreeStackValueType(objRef);
esp
= PushObject(objRef, mStack, ins,
true
);
return
obj;
FreeStackValueType(objRef);
esp
= PushObject(objRef, mStack, ins,
true
);
//
esp = 0xa647905c
esp->ObjectType =
ObjectTypes.Object;
esp
->Value =
mStack.Count;
//
mStack[0] = null
//
mStack[1] = Vector3(1.0, 1.0, 1.0)
mStack.Add(obj);
//
0xa6479068
return
esp +
1
case
OpCodeEnum.Call:
//
m = "UnityEngine.Debug Void Log(System.Object)"
IMethod m = domain.GetMethod(ip->
TokenInteger);
object
result = cm.Invoke(
this
, esp, mStack);
for
(
int
i = paramCount; i >=
1
; i--
)
//
esp = 0xa6479068
//
p = 0xa647905c
var
p =
Minus(esp, i);
var
pt =
this
.param[paramCount -
i].ParameterType;
//
obj = Vector3(1.0, 1.0, 1.0)
var
obj =
pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
obj
=
ILIntepreter.CheckAndCloneValueType(obj, appdomain);
//
t = UnityEngine.Vector3
var
t =
domain.GetType(type);
return
((CLRType)t).PerformMemberwiseClone(obj);
var
memberwiseClone = clrType.GetMethod(
"
MemberwiseClone
"
, System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic);
memberwiseCloneDelegate
= (
ref
object
t) => memberwiseClone.Invoke(t,
null
);
return
memberwiseCloneDelegate(
ref
target);
param[paramCount
- i] =
obj;
//
param[0] = Vector3(1.0, 1.0, 1.0)
res =
def.Invoke(instance, param);
//
esp = 0xa647905c
esp =
Minus(esp, paramCount);
//
esp = 0xa647905c
return
stack.PopFrame(
ref
frame, esp);
//
returnVal = 0xa6479050
StackObject* returnVal = esp -
1
;
//
method = "HotFix_Project.TestValueType.RunTest()"
var
method =
frame.Method;
//
ret = 0xa6479050
StackObject* ret =
ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
//
移除 mStack 里的内容
((UncheckedList<
object
>)managedStack).RemoveRange(mStackBase, managedStack.Count -
mStackBase);
//
0xa64a9044
valueTypePtr =
frame.ValueTypeBasePointer;
//
ret = 0xa6479050
return
ret;
ValueTypeBinder 再探
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;
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);
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(
"
注册完毕后再次运行会发现这次会报另外的错误
"
);
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
Initialize2
"
,
null
,
null
);
esp
= Execute(method, esp,
out
unhandledException);
t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));
return
((IDelegateAdapter)obj).GetConvertor(pt);
//
type = {TestDelegateMethod}
//
this: {ILRuntime.Runtime.Intepreter.MethodDelegateAdapter`1[System.Int32]} = "HotFix_Project.TestDelegate.Method(Int32 a)"
res = appdomain.DelegateManager.ConvertToDelegate(type,
this
);
//
找不到 报错
if
(clrDelegates.TryGetValue(clrDelegateType,
out
func))
catch
(System.Exception ex)
Debug.LogError(ex.ToString());
Debug.Log(
"
ILRuntime内部是用Action和Func这两个系统内置的委托类型来创建实例的,所以其他的委托类型都需要写转换器
"
);
Debug.Log(
"
将Action或者Func转换成目标委托类型
"
);
appdomain.DelegateManager.RegisterDelegateConvertor
<TestDelegateMethod>((action) =>
//
转换器的目的是把Action或者Func转换成正确的类型,这里则是把Action<int>转换成TestDelegateMethod
return
new
TestDelegateMethod((a) =>
//
调用委托实例
((System.Action<
int
>
)action)(a);
//
对于TestDelegateFunction同理,只是是将Func<int, string>转换成TestDelegateFunction
appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) =>
return
new
TestDelegateFunction((a) =>
return
((System.Func<
int
,
string
>
)action)(a);
//
下面再举一个这个Demo中没有用到,但是UGUI经常遇到的一个委托,例如UnityAction<float>
appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<
float
>>((action) =>
return
new
UnityEngine.Events.UnityAction<
float
>((a) =>
((System.Action
<
float
>
)action)(a);
Debug.Log(
"
现在我们再来运行一次
"
);
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
Initialize2
"
,
null
,
null
);
appdomain.Invoke(
"
HotFix_Project.TestDelegate
"
,
"
RunTest2
"
,
null
,
null
);
//
pt = {TestDelegateMethod}
((IDelegateAdapter)obj).GetConvertor(pt);
//
this = "HotFix_Project.TestDelegate.Method(Int32 a)"
res = appdomain.DelegateManager.ConvertToDelegate(type,
this
);
ConvertToDelegate
//
func = {System.Func`2[[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
//
func.method = "System.Delegate <OnHotFixLoaded>b__10_0(System.Delegate)"
//
func.Target = {DelegateDemo+<>c}
if
(clrDelegates.TryGetValue(clrDelegateType,
out
func))
//
adapter.Delegate = {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
//
Delegate.Method = "Void InvokeILMethod(Int32)"
//
Delegate.Target = "HotFix_Project.TestDelegate.Method(Int32 a)"
func(adapter.Delegate);
Debug.Log(
"
运行成功,我们可以看见,用Action或者Func当作委托类型的话,可以避免写转换器,所以项目中在不必要的情况下尽量只用Action和Func
"
);
Debug.Log(
"
另外应该尽量减少不必要的跨域委托调用,如果委托只在热更DLL中用,是不需要进行任何注册的
"
);
Debug.Log(
"
---------
"
);
Debug.Log(
"
我们再来在Unity主工程中调用一下刚刚的委托试试
"
);
TestMethodDelegate(
789
);
var
str = TestFunctionDelegate(
098
);
Debug.Log(
"
!! OnHotFixLoaded str =
"
+
str);
TestActionDelegate(
"
Hello From Unity Main Project
"
);
Delegate
[MenuItem("ILRuntime/Generate CLR Binding Code by Analysis")]
static void GenerateCLRBindingByAnalysis()
//用新的分析热更dll调用引用来生成绑定代码
ILRuntime.Runtime.Enviorment.AppDomain domain = new ILRuntime.Runtime.Enviorment.AppDomain();
using (System.IO.FileStream fs = new System.IO.FileStream("Assets/StreamingAssets/HotFix_Project.dll", System.IO.FileMode.Open, System.IO.FileAccess.Read))
// 用AppDomain 加载 hotfix.dll
domain.LoadAssembly(fs);
//Crossbind Adapter is needed to generate the correct binding code
InitILRuntime(domain);
//这里需要注册所有热更DLL中用到的跨域继承Adapter,否则无法正确抓取引用
domain.RegisterCrossBindingAdaptor(new MonoBehaviourAdapter());
domain.RegisterCrossBindingAdaptor(new CoroutineAdapter());
domain.RegisterCrossBindingAdaptor(new InheritanceAdapter());
domain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
ILRuntime.Runtime.CLRBinding.BindingCodeGenerator.GenerateBindingCode(domain, "Assets/ILRuntime/Generated");
if (domain == null)
return;
// outputPath = "Assets/ILRuntime/Generated"
if (!System.IO.Directory.Exists(outputPath))
System.IO.Directory.CreateDirectory(outputPath);
Dictionary<Type, CLRBindingGenerateInfo> infos = new Dictionary<Type, CLRBindingGenerateInfo>(new ByReferenceKeyComparer<Type>());
// 1.初始化 ILType 的 IMethod, 转换 ILRuntime.OpCode
// 2. 将 CLRType的Type 的相关信息添加到 Dictionary<Type, CLRBindingGenerateInfo> infos
CrawlAppdomain(domain, infos);
// hotfix.dll 里的类型 e.g. "HotFix_Project.InstanceClass"
// 系统类型 e.g. System.Int32
// 适配器 e.g. MonoBehaviourAdapter+Adaptor
// Unity里的类型 e.g. UnityEngine.Vector3
var arr = domain.LoadedTypes.Values.ToArray();
//Prewarm
foreach (var type in arr)
// 适配器不是 ILType e.g. ILRuntime.Runtime.Adaptors.AttributeAdaptor+Adaptor, 不处理
// 热更里的类型是 ILType e.g. "HotFix_Project.InstanceClass"
// System.Void 等不是 ILType, 不处理
// UnityEngine.Vector3 等不是 ILType, 不处理
if (type is CLR.TypeSystem.ILType)
// 如果类型有 泛型参数 则跳过
if (type.HasGenericParameter)
continue;
// 通过调用 ILType.GetMethods 将Mono.Cecil.MethodDefinition 转换为 IMethod, 并添加到 methods
var methods = type.GetMethods().ToList();
// 同上 转换构造函数, 并添加到 methods
foreach (var i in ((CLR.TypeSystem.ILType)type).GetConstructors())
methods.Add(i);
// 同上 转换静态构造函数, 并添加到 methods
if (((CLR.TypeSystem.ILType)type).GetStaticConstroctor() != null)
methods.Add(((CLR.TypeSystem.ILType)type).GetStaticConstroctor());
foreach (var j in methods)
CLR.Method.ILMethod method = j as CLR.Method.ILMethod;
if (method != null)
if (method.GenericParameterCount > 0 && !method.IsGenericInstance)
continue;
// 这里通过调用 method.Body 将 Mono.Cecil.Instruction 转换为 ILRuntime.OpCode
var body = method.Body;
// 重新遍历, 因为又加入了不少新的类型
arr = domain.LoadedTypes.Values.ToArray();
foreach (var type in arr)
if (type is CLR.TypeSystem.ILType)
if (type.TypeForCLR.IsByRef || type.HasGenericParameter)
continue;
// 获取所有的方法, e.g.
// "HotFix_Project.InstanceClass.get_ID()"
// "HotFix_Project.InstanceClass.StaticFunTest()"
// "HotFix_Project.InstanceClass.StaticFunTest2(Int32 a)"
// "HotFix_Project.InstanceClass.GenericMethod(T a)"
var methods = type.GetMethods().ToList();
// 获取构造函数, e.g.
// "HotFix_Project.InstanceClass..ctor()"
// "HotFix_Project.InstanceClass..ctor(Int32 id)"
foreach (var i in ((CLR.TypeSystem.ILType)type).GetConstructors())
methods.Add(i);
// 获取静态构造函数
if (((CLR.TypeSystem.ILType)type).GetStaticConstroctor() != null)
methods.Add(((CLR.TypeSystem.ILType)type).GetStaticConstroctor());
// 遍历这些方法
foreach (var j in methods)
// e.g "HotFix_Project.InstanceClass..ctor()"
CLR.Method.ILMethod method = j as CLR.Method.ILMethod;
if (method != null)
if (method.GenericParameterCount > 0 && !method.IsGenericInstance)
continue;
// body: OpCode[]
// Ldarg_0, 0, 0
// Call, 0, 1
// Nop, 0, 0
// Nop, 0, 0
// Ldstr, 0, -2078173280
// Call, 24, 0
// Ldarg_0, 0, 0
// Ldc_I4_0, 0, 0
// Stfld, 0, 335007449088
// Ret, 0, 0
var body = method.Body;
foreach (var ins in body)
switch (ins.Code)
case Intepreter.OpCodes.OpCodeEnum.Newobj:
CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod;
// 如果这个方法是 CLRMethod
// e.g. "System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance]" .ctor
if (m != null)
if (m.DeclearingType.IsDelegate)
continue;
Type t = m.DeclearingType.TypeForCLR;
CLRBindingGenerateInfo info;
if (!infos.TryGetValue(t, out info))
info = CreateNewBindingInfo(t);
// e.g. "[System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
infos[t] = info;
if (m.IsConstructor)
info.Constructors.Add(m.ConstructorInfo);
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);
if (!m.MethodInfo.IsPublic)
continue;
Type t = m.DeclearingType.TypeForCLR;
CLRBindingGenerateInfo info;
if (!infos.TryGetValue(t, out info))
info = CreateNewBindingInfo(t);
infos[t] = info;
// 添加要生成的方法
info.Methods.Add(m.MethodInfo);
break;
// 删除旧文件
string[] oldFiles = System.IO.Directory.GetFiles(outputPath, "*.cs");
foreach (var i in oldFiles)
System.IO.File.Delete(i);
if (valueTypeBinders == null)
valueTypeBinders = new List<Type>(domain.ValueTypeBinders.Keys);
// 不想包含的 MethodBase
HashSet<MethodBase> excludeMethods = null;
// 不想包含的 FieldInfo
HashSet<FieldInfo> excludeFields = null;
HashSet<string> files = new HashSet<string>();
List<string> clsNames = new List<string>();
// 0, "[System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void Add(ILRuntime.Runtime.Intepreter.ILTypeInstance)"
"ILRuntime.Runtime.Intepreter.ILTypeInstance get_Item(Int32)"
// 1, "[System.Collections.Generic.Dictionary`2[System.String,ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void set_Item(System.String, ILRuntime.Runtime.Intepreter.ILTypeInstance)"
"ILRuntime.Runtime.Intepreter.ILTypeInstance get_Item(System.String)"
// 2, "[System.Collections.Generic.Dictionary`2[System.String,System.Int32], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void set_Item(System.String, Int32)"
"Int32 get_Item(System.String)"
// 3, "[LitJson.JsonMapper, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String ToJson(System.Object)"
"ILRuntime.Runtime.Intepreter.ILTypeInstance ToObject[ILTypeInstance](System.String)"
// 4, "[UnityEngine.Debug, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void Log(System.Object)"
"Void LogFormat(System.String, System.Object[])"
// 5, "[System.Diagnostics.Stopwatch, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void Start()"
"Void Stop()"
"Int64 get_ElapsedMilliseconds()"
// 6, "[UnityEngine.Vector3, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single, Single, Single)"
Fields
Methods
"UnityEngine.Vector3 get_one()"
"UnityEngine.Vector3 op_Addition(UnityEngine.Vector3, UnityEngine.Vector3)"
"UnityEngine.Vector3 op_Subtraction(UnityEngine.Vector3, UnityEngine.Vector3)"
"UnityEngine.Vector3 op_Multiply(UnityEngine.Vector3, Single)"
"UnityEngine.Vector3 op_Multiply(Single, UnityEngine.Vector3)"
"UnityEngine.Vector3 op_Division(UnityEngine.Vector3, Single)"
"UnityEngine.Vector3 op_UnaryNegation(UnityEngine.Vector3)"
"Boolean op_Equality(UnityEngine.Vector3, UnityEngine.Vector3)"
"Boolean op_Inequality(UnityEngine.Vector3, UnityEngine.Vector3)"
"Single Dot(UnityEngine.Vector3, UnityEngine.Vector3)"
"UnityEngine.Vector3 Cross(UnityEngine.Vector3, UnityEngine.Vector3)"
"Single Distance(UnityEngine.Vector3, UnityEngine.Vector3)"
"Single get_magnitude()"
"UnityEngine.Vector3 get_normalized()"
"Single get_sqrMagnitude()"
"UnityEngine.Vector3 get_zero()"
// 7, "[System.String, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String Concat(System.Object, System.Object)"
"System.String Concat(System.String, System.String)"
// 8, "[System.Boolean, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String ToString()"
// 9, "[System.Object, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
// 10, "[UnityEngine.Quaternion, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single, Single, Single, Single)"
Fields
Methods
"UnityEngine.Quaternion get_identity()"
"UnityEngine.Quaternion op_Multiply(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"UnityEngine.Vector3 op_Multiply(UnityEngine.Quaternion, UnityEngine.Vector3)"
"Boolean op_Equality(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"Boolean op_Inequality(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"Single Dot(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"Single Angle(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"UnityEngine.Vector3 get_eulerAngles()"
"UnityEngine.Quaternion Euler(UnityEngine.Vector3)"
"UnityEngine.Quaternion Euler(Single, Single, Single)"
// 11, "[UnityEngine.Vector2, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single, Single)"
Fields
Methods
"UnityEngine.Vector2 get_one()"
"UnityEngine.Vector2 op_Addition(UnityEngine.Vector2, UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Subtraction(UnityEngine.Vector2, UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Multiply(UnityEngine.Vector2, Single)"
"UnityEngine.Vector2 op_Multiply(Single, UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Division(UnityEngine.Vector2, Single)"
"UnityEngine.Vector2 op_UnaryNegation(UnityEngine.Vector2)"
"Boolean op_Equality(UnityEngine.Vector2, UnityEngine.Vector2)"
"Boolean op_Inequality(UnityEngine.Vector2, UnityEngine.Vector2)"
"UnityEngine.Vector3 op_Implicit(UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Implicit(UnityEngine.Vector3)"
"Single Dot(UnityEngine.Vector2, UnityEngine.Vector2)"
"Single Distance(UnityEngine.Vector2, UnityEngine.Vector2)"
"Single get_magnitude()"
"UnityEngine.Vector2 get_normalized()"
"Single get_sqrMagnitude()"
"UnityEngine.Vector2 get_zero()"
// 12, "[UnityEngine.Time, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Single get_time()"
// 13, "[UnityEngine.GameObject, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Adaptor AddComponent[Adaptor]()"
"Adaptor GetComponent[Adaptor]()"
// 14, "[CoroutineDemo, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"CoroutineDemo get_Instance()"
"Void DoCoroutine(System.Collections.IEnumerator)"
// 15, "[UnityEngine.WaitForSeconds, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single)"
Fields
Methods
// 16, "[System.NotSupportedException, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
// 17, "[CLRBindingTestClass, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Single DoSomeTest(Int32, Single)"
// 18, "[TestClassBase, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void TestVirtual(System.String)"
// 19, "[TestDelegateMethod, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void Invoke(Int32)"
// 20, "[TestDelegateFunction, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String Invoke(Int32)"
// 21, "[System.Action`1[System.String], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void Invoke(System.String)"
// 22, "[DelegateDemo, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
"TestDelegateMethod TestMethodDelegate"
"TestDelegateFunction TestFunctionDelegate"
"System.Action`1[System.String] TestActionDelegate"
Methods
// 23, "[System.Int32, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String ToString()"
foreach (var info in infos)
if (!info.Value.NeedGenerate)
continue;
Type i = info.Value.Type;
//CLR binding for delegate is important for cross domain invocation,so it should be generated
//if (i.BaseType == typeof(MulticastDelegate))
// continue;
string clsName, realClsName;
bool isByRef;
// 如果有 ObsoleteAttribute 就跳过
if (i.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > 0)
continue;
i.GetClassName(out clsName, out realClsName, out isByRef);
if (clsNames.Contains(clsName))
clsName = clsName + "_t";
// e.g. "System_Collections_Generic_List_1_ILTypeInstance_Binding"
clsNames.Add(clsName);
// e.g. "Assets/ILRuntime/Generated/System_Collections_Generic_List_1_ILTypeInstance_Binding"
string oFileName = outputPath + "/" + clsName;
int len = Math.Min(oFileName.Length, 100);
if (len < oFileName.Length)
oFileName = oFileName.Substring(0, len) + "_t";
while (files.Contains(oFileName))
oFileName = oFileName + "_t";
files.Add(oFileName);
// e.g. "Assets/ILRuntime/Generated/System_Collections_Generic_List_1_ILTypeInstance_Binding.cs"
oFileName = oFileName + ".cs";
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(oFileName, false, new UTF8Encoding(false)))
StringBuilder sb = new StringBuilder();
sb.Append(@"using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using ILRuntime.CLR.TypeSystem;
using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.Runtime.Stack;
using ILRuntime.Reflection;
using ILRuntime.CLR.Utils;
namespace ILRuntime.Runtime.Generated
unsafe class ");
sb.AppendLine(clsName);
sb.Append(@" {
public static void Register(ILRuntime.Runtime.Enviorment.AppDomain app)
string flagDef = " BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;";
string methodDef = " MethodBase method;";
string methodsDef = " MethodInfo[] methods = type.GetMethods(flag).Where(t => !t.IsGenericMethod).ToArray();";
string fieldDef = "
FieldInfo field;";
string argsDef = " Type[] args;";
string typeDef = string.Format(" Type type = typeof({0});", realClsName);
bool needMethods;
MethodInfo[] methods = info.Value.Methods.ToArray();
FieldInfo[] fields = info.Value.Fields.ToArray();
// 生成 方法注册字符串 e.g.
" args = new Type[]{typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance)};\r\n
method = type.GetMethod(\"Add\", flag, null, args, null);\r\n
app.RegisterCLRMethodRedirection(method, Add_0);\r\n
args = new Type[]{typeof(System.Int32)};\r\n
method = type.GetMethod(\"get_Item\", flag, null, args, null);\r\n
app.RegisterCLRMethodRedirection(method, get_Item_1);\r\n"
string registerMethodCode = i.GenerateMethodRegisterCode(methods, excludeMethods, out needMethods);
// 生成字段注册字符串
string registerFieldCode = fields.Length > 0 ? i.GenerateFieldRegisterCode(fields, excludeFields) : null;
// 生成值类型注册字符串
string registerValueTypeCode = info.Value.ValueTypeNeeded ? i.GenerateValueTypeRegisterCode(realClsName) : null;
string registerMiscCode = i.GenerateMiscRegisterCode(realClsName, info.Value.DefaultInstanceNeeded, info.Value.ArrayNeeded);
string commonCode = i.GenerateCommonCode(realClsName);
// 获取构造函数信息
ConstructorInfo[] ctors = info.Value.Constructors.ToArray();
// 生成构造函数注册字符串 e.g.
" args = new Type[]{};\r\n
method = type.GetConstructor(flag, null, args, null);\r\n
app.RegisterCLRMethodRedirection(method, Ctor_0);\r\n"
string ctorRegisterCode = i.GenerateConstructorRegisterCode(ctors, excludeMethods);
// 生成方法体 e.g.
" static StackObject* Add_0(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)\r\n
{\r\n
ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;\r\n
StackObject* ptr_of_this_method;\r\n
StackObject* __ret = ILIntepreter.Minus(__esp, 2);\r\n\r\n
ptr_of_this_method = ILIntepreter.Minus(__esp, 1);\r\n
ILRuntime.Runtime.Intepreter.ILTypeInstance @item = (ILRuntime.Runtime.Intepreter.ILTypeInstance)typeof(ILRuntime.Runtime.Intepreter.ILTypeInstance).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));\r\n
__intp.Free(ptr_of_this_method);\r\n\r\n
ptr_of_this_method = ILIntepreter.Minus(__esp, 2);\r\n
System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance> instance_of_this_method = (System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>)typeof(System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));\r\n
__intp.Free(ptr_of_this_method);\r\n\r\n
instance_of_this_method.Add(@item);\r\n\r\n
return __ret;\r\n
}\r\n\r\n
static StackObject* get_Item_1(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)\r\n
{\r\n
ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;\r\n
StackObject* ptr_of_this_method;\r\n
StackObject* __ret = ILIntepreter.Minus(__esp, 2);\r\n\r\n
ptr_of_this_method = ILIntepreter.Minus(__esp, 1);\r\n
System.Int32 @index = ptr_of_this_method->Value;\r\n\r\n
ptr_of_this_method = ILIntepreter.Minus(__esp, 2);\r\n
System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance> instance_of_this_method = (System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>)typeof(System.Collections.Generic.List<ILRuntime.Runtime.Intepreter.ILTypeInstance>).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));\r\n
__intp.Free(ptr_of_this_method);\r\n\r\n
var result_of_this_method = instance_of_this_method[index];\r\n\r\n
return ILIntepreter.PushObject(__ret, __mStack, result_of_this_method);\r\n
}\r\n\r\n"
string methodWraperCode = i.GenerateMethodWraperCode(methods, realClsName, excludeMethods, valueTypeBinders, domain);
// 为每一个方法生成方法体
foreach (var i in methods)
// 获取参数数量
int paramCnt = param.Length;
// 如果不是静态方法, 参数数量加1 也就是把实例本身也当作参数
if (!i.IsStatic) paramCnt++;
sb.AppendLine(string.Format(" static StackObject* {0}_{1}(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)", i.Name, idx));
sb.AppendLine(" {");
sb.AppendLine(" ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;");
if (param.Length != 0 || !i.IsStatic)
sb.AppendLine(" StackObject* ptr_of_this_method;");
// 返回指针 为当前指针 减去参数数量
sb.AppendLine(string.Format(" StackObject* __ret = ILIntepreter.Minus(__esp, {0});", paramCnt));
sb.AppendLine();
bool hasByRef = param.HasByRefParam();
string shouldFreeParam = hasByRef ? "false" : "true";
for (int j = param.Length; j > 0; j--)
// 设置ptr_of_this_method
sb.AppendLine(string.Format(" ptr_of_this_method = ILIntepreter.Minus(__esp, {0});", param.Length - j + 1));
// 生成字段方法体
string fieldWraperCode = fields.Length > 0 ? i.GenerateFieldWraperCode(fields, realClsName, excludeFields) : null;
string cloneWraperCode = null;
if (info.Value.ValueTypeNeeded)
//Memberwise clone should copy all fields
var fs = i.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly);
cloneWraperCode = i.GenerateCloneWraperCode(fs, realClsName);
bool hasMethodCode = !string.IsNullOrEmpty(registerMethodCode);
bool hasFieldCode = !string.IsNullOrEmpty(registerFieldCode);
bool hasValueTypeCode = !string.IsNullOrEmpty(registerValueTypeCode);
bool hasMiscCode = !string.IsNullOrEmpty(registerMiscCode);
bool hasCtorCode = !string.IsNullOrEmpty(ctorRegisterCode);
bool hasNormalMethod = methods.Where(x => !x.IsGenericMethod).Count() != 0;
if ((hasMethodCode && hasNormalMethod) || hasFieldCode || hasCtorCode)
sb.AppendLine(flagDef);
if (hasMethodCode || hasCtorCode)
sb.AppendLine(methodDef);
if (hasFieldCode)
sb.AppendLine(fieldDef);
if (hasMethodCode || hasFieldCode || hasCtorCode)
sb.AppendLine(argsDef);
if (hasMethodCode || hasFieldCode || hasValueTypeCode || hasMiscCode || hasCtorCode)
sb.AppendLine(typeDef);
if (needMethods)
sb.AppendLine(methodsDef);
sb.AppendLine(registerMethodCode);
if (fields.Length > 0)
sb.AppendLine(registerFieldCode);
if (info.Value.ValueTypeNeeded)
sb.AppendLine(registerValueTypeCode);
if (!string.IsNullOrEmpty(registerMiscCode))
sb.AppendLine(registerMiscCode);
sb.AppendLine(ctorRegisterCode);
sb.AppendLine(" }");
sb.AppendLine();
sb.AppendLine(commonCode);
sb.AppendLine(methodWraperCode);
if (fields.Length > 0)
sb.AppendLine(fieldWraperCode);
if (info.Value.ValueTypeNeeded)
sb.AppendLine(cloneWraperCode);
string ctorWraperCode = i.GenerateConstructorWraperCode(ctors, realClsName, excludeMethods, valueTypeBinders);
sb.AppendLine(ctorWraperCode);
sb.AppendLine(" }");
sb.AppendLine("}");
sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
sw.Flush();
// 生成 Assets/ILRuntime/Generated/CLRBindings.cs
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/CLRBindings.cs", false, new UTF8Encoding(false)))
StringBuilder sb = new StringBuilder();
sb.AppendLine(@"using System;
using System.Collections.Generic;
using System.Reflection;
namespace ILRuntime.Runtime.Generated
class CLRBindings
/// <summary>
/// Initialize the CLR binding, please invoke this AFTER CLR Redirection registration
/// </summary>
public static void Initialize(ILRuntime.Runtime.Enviorment.AppDomain app)
{");
foreach (var i in clsNames)
sb.Append(" ");
sb.Append(i);
sb.AppendLine(".Register(app);");
sb.AppendLine(@" }
}");
sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
var delegateClsNames = GenerateDelegateBinding(delegateTypes, outputPath);
clsNames.AddRange(delegateClsNames);
GenerateBindingInitializeScript(clsNames, valueTypeBinders, outputPath);
ILRuntime/Generate CLR Binding Code by Analysis
###################################################################################################################################################################
namespace HotFix_Project {
public class InstanceClass {
public InstanceClass() {
var type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { });
ILIntepreter inteptreter = RequestILIntepreter();
inteptreter = new ILIntepreter(this);
stack = new RuntimeStack(this);
nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);
pointer = (StackObject*)nativePointer.ToPointer();
endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
valueTypePtr = endOfMemory - 1;
// esp = 0x5de00010
// mStack = null;
// instance: ILTypeInstance = "HotFix_Project.InstanceClass"
esp = PushObject(esp, mStack, instance);
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
mStack.Add(obj);
return esp + 1 (0x5de0001c)
// 没有参数不变
esp = PushParameters(method, esp, p);
// 执行方法
// method = "HotFix_Project.InstanceClass..ctor()"
// esp = 0x5de0001c
// 原始IL
// "IL_0000: ldarg.0"
// "IL_0001: call System.Void System.Object::.ctor()"
// "IL_0006: nop"
// "IL_0007: nop"
// "IL_0008: ret"
// 自定义OpCode
// Ldarg_0, 0, 0
// Call, 1, 0
// Nop, 0, 0
// Nop, 0, 0
// Ret, 0, 0
esp = Execute(method, esp, out unhandledException);
res = new StackFrame();
stack.InitializeFrame(method, esp, out frame);
StackObject* v1 = frame.LocalVarPointer;
StackObject* v2 = frame.LocalVarPointer + 1;
StackObject* v3 = frame.LocalVarPointer + 1 + 1;
StackObject* v4 = Add(frame.LocalVarPointer, 3);
esp = frame.BasePointer;
var arg = Minus(frame.LocalVarPointer, method.ParameterCount);
if (method.HasThis) arg--; paramCnt++;
// StackFrame 如 RuntimeStack
stack.PushFrame(ref frame);
// 将索引为 0 的参数加载到计算堆栈上, 将 arg 上的值 拷贝到 esp 上
case OpCodeEnum.Ldarg_0:
// esp = 0x5de0001c
// arg = 0x5de00010
// mStack[0] = "HotFix_Project.InstanceClass"
CopyToStack(esp, arg, mStack);
esp++;
// 调用由传递的方法说明符指示的方法。
case OpCodeEnum.Call:
IMethod m = domain.GetMethod(ip->TokenInteger);
if (m == null)
//Irrelevant method
int cnt = (int)ip->TokenLong;
//Balance the stack
for (int i = 0; i < cnt; i++)
{
// esp - 1 = 0x5de0001c
Free(esp - 1);
// esp = 0x5de0001c
esp--;
}
return stack.PopFrame(ref frame, esp);
// returnVal = 0x5de00010
StackObject* returnVal = esp - 1;
// method = "HotFix_Project.InstanceClass..ctor()"
var method = frame.Method;
// ret = 0x5de0001c
StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
// ret = 0x5de00010
if (method.HasThis) ret--;
// mStack 没有了
((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
//ret = 0x5de00010
return ret;
// null
object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - 1), domain, mStack)) : null;
((UncheckedList<object>)mStack).RemoveRange(mStackBase, mStack.Count - mStackBase);
无参构造函数最后返回的是 res: ILTypeInstance
public ILTypeInstance Instantiate(bool callDefaultConstructor = true)
{
var res = new ILTypeInstance(this);
if (callDefaultConstructor)
{
var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
if (m != null)
{
appdomain.Invoke(m, res, null);
}
}
return res;
}
###################################################################################################################################################################
|
|
爱旅游的手套 · 惊!蜘蛛侠居然也朝三暮四?论蜘蛛侠到底有多少个女朋友 1 年前 |