ILRuntime 学习
ILRuntime: https://github.com/Ourpalm/ILRuntime
Demo: https://github.com/Ourpalm/ILRuntimeU3D
中文在线文档: https://ourpalm.github.io/ILRuntime/public/v1/guide/index.html
Mono: https://www.mono-project.com/
Mono.Cecil https://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cecil/
XCode请使用Relase编译, 使用Debug编译会出现函数调用层数超过一定数量iOS手机闪退
ESP: 栈指针寄存器(extended stack pointer), 指向栈顶的指针
EBP: 基址指针寄存器(extended base pointer), 指向栈底的指针
var module = ModuleDefinition.ReadModule(stream); //从MONO中加载模块 foreach(TypeDefinition type in module.Types) {
UnityEngine.Debug.Log(type.FullName);
}
从Mono中加载模块
public RuntimeStack(ILIntepreter intepreter)
{
this.intepreter = intepreter; // 通过使用指定的字节数,从进程的非托管内存中分配内存
// sizeof(StackObject) == 12 字节
// 分配 12 * 1024 * 16 字节
nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS); // 将 IntPtr 转换为 StackObject* 指针
// pointer 地址为 0x5737F010
pointer = (StackObject*)nativePointer.ToPointer();
// endOfMemory 地址为 0x573AF010
endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
// valueTypePtr 地址为 0x573AF004
valueTypePtr = endOfMemory - ;
}
RuntimeStack 构造
struct StackObject
{
public ObjectTypes ObjectType;
public int Value; //高32位
public int ValueLow; //低32位
}
enum ObjectTypes
{
Null,//null
Integer,
Long,
Float,
Double,
StackObjectReference,//引用指针,Value = 指针地址,
StaticFieldReference,//静态变量引用,Value = 类型Hash, ValueLow= Field的Index
Object,//托管对象,Value = 对象Index
FieldReference,//类成员变量引用,Value = 对象Index, ValueLow = Field的Index
ArrayReference,//数组引用,Value = 对象Index, ValueLow = 元素的Index
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ILRuntime.Runtime.Intepreter.OpCodes
{
enum OpCodeEnum
{
/// <summary>
/// 如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作。
/// </summary>
Nop,
/// <summary>
/// 向公共语言结构 (CLI) 发出信号以通知调试器已撞上了一个断点。
/// </summary>
Break,
/// <summary>
/// 将索引为 0 的参数加载到计算堆栈上。
/// </summary>
Ldarg_0,
/// <summary>
/// 将索引为 1 的参数加载到计算堆栈上。
/// </summary>
Ldarg_1,
/// <summary>
/// 将索引为 2 的参数加载到计算堆栈上。
/// </summary>
Ldarg_2,
/// <summary>
/// 将索引为 3 的参数加载到计算堆栈上。
/// </summary>
Ldarg_3,
/// <summary>
/// 将索引 0 处的局部变量加载到计算堆栈上。
/// </summary>
Ldloc_0,
/// <summary>
/// 将索引 1 处的局部变量加载到计算堆栈上。
/// </summary>
Ldloc_1,
/// <summary>
/// 将索引 2 处的局部变量加载到计算堆栈上。
/// </summary>
Ldloc_2,
/// <summary>
/// 将索引 3 处的局部变量加载到计算堆栈上。
/// </summary>
Ldloc_3,
/// <summary>
/// 从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中。
/// </summary>
Stloc_0,
/// <summary>
/// 从计算堆栈的顶部弹出当前值并将其存储到索引 1 处的局部变量列表中。
/// </summary>
Stloc_1,
/// <summary>
/// 从计算堆栈的顶部弹出当前值并将其存储到索引 2 处的局部变量列表中。
/// </summary>
Stloc_2,
/// <summary>
/// 从计算堆栈的顶部弹出当前值并将其存储到索引 3 处的局部变量列表中。
/// </summary>
Stloc_3,
/// <summary>
/// 将参数(由指定的短格式索引引用)加载到计算堆栈上。
/// </summary>
Ldarg_S,
/// <summary>
/// 以短格式将参数地址加载到计算堆栈上。
/// </summary>
Ldarga_S,
/// <summary>
/// 将位于计算堆栈顶部的值存储在参数槽中的指定索引处(短格式)。
/// </summary>
Starg_S,
/// <summary>
/// 将特定索引处的局部变量加载到计算堆栈上(短格式)。
/// </summary>
Ldloc_S,
/// <summary>
/// 将位于特定索引处的局部变量的地址加载到计算堆栈上(短格式)。
/// </summary>
Ldloca_S,
/// <summary>
/// 从计算堆栈的顶部弹出当前值并将其存储在局部变量列表中的 index 处(短格式)。
/// </summary>
Stloc_S,
/// <summary>
/// 将空引用(O 类型)推送到计算堆栈上。
/// </summary>
Ldnull,
/// <summary>
/// 将整数值 -1 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_M1,
/// <summary>
/// 将整数值 0 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_0,
/// <summary>
/// 将整数值 1 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_1,
/// <summary>
/// 将整数值 2 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_2,
/// <summary>
/// 将整数值 3 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_3,
/// <summary>
/// 将整数值 4 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_4,
/// <summary>
/// 将整数值 5 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_5,
/// <summary>
/// 将整数值 6 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_6,
/// <summary>
/// 将整数值 7 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_7,
/// <summary>
/// 将整数值 8 作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4_8,
/// <summary>
/// 将提供的 int8 值作为 int32 推送到计算堆栈上(短格式)。
/// </summary>
Ldc_I4_S,
/// <summary>
/// 将所提供的 int32 类型的值作为 int32 推送到计算堆栈上。
/// </summary>
Ldc_I4,
/// <summary>
/// 将所提供的 int64 类型的值作为 int64 推送到计算堆栈上。
/// </summary>
Ldc_I8,
/// <summary>
/// 将所提供的 float32 类型的值作为 F (float) 类型推送到计算堆栈上。
/// </summary>
Ldc_R4,
/// <summary>
/// 将所提供的 float64 类型的值作为 F (float) 类型推送到计算堆栈上。
/// </summary>
Ldc_R8,
/// <summary>
/// 复制计算堆栈上当前最顶端的值,然后将副本推送到计算堆栈上。
/// </summary>
Dup,
/// <summary>
/// 移除当前位于计算堆栈顶部的值。
/// </summary>
Pop,
/// <summary>
/// 退出当前方法并跳至指定方法。
/// </summary>
Jmp,
/// <summary>
/// 调用由传递的方法说明符指示的方法。
/// </summary>
Call,
/// <summary>
/// 通过调用约定描述的参数调用在计算堆栈上指示的方法(作为指向入口点的指针)。
/// </summary>
Calli,
/// <summary>
/// 从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
/// </summary>
Ret,
/// <summary>
/// 无条件地将控制转移到目标指令(短格式)。
/// </summary>
Br_S,
/// <summary>
/// 如果 value 为 false、空引用或零,则将控制转移到目标指令。
/// </summary>
Brfalse_S,
/// <summary>
/// 如果 value 为 true、非空或非零,则将控制转移到目标指令(短格式)。
/// </summary>
Brtrue_S,
/// <summary>
/// 如果两个值相等,则将控制转移到目标指令(短格式)。
/// </summary>
Beq_S,
/// <summary>
/// 如果第一个值大于或等于第二个值,则将控制转移到目标指令(短格式)。
/// </summary>
Bge_S,
/// <summary>
/// 如果第一个值大于第二个值,则将控制转移到目标指令(短格式)。
/// </summary>
Bgt_S,
/// <summary>
/// 如果第一个值小于或等于第二个值,则将控制转移到目标指令(短格式)。
/// </summary>
Ble_S,
/// <summary>
/// 如果第一个值小于第二个值,则将控制转移到目标指令(短格式)。
/// </summary>
Blt_S,
/// <summary>
/// 当两个无符号整数值或不可排序的浮点型值不相等时,将控制转移到目标指令(短格式)。
/// </summary>
Bne_Un_S,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令(短格式)。
/// </summary>
Bge_Un_S,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令(短格式)。
/// </summary>
Bgt_Un_S,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点值时,如果第一个值小于或等于第二个值,则将控制权转移到目标指令(短格式)。
/// </summary>
Ble_Un_S,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点型值时,如果第一个值小于第二个值,则将控制转移到目标指令(短格式)。
/// </summary>
Blt_Un_S,
/// <summary>
/// 无条件地将控制转移到目标指令。
/// </summary>
Br,
/// <summary>
/// 如果 value 为 false、空引用(Visual Basic 中的 Nothing)或零,则将控制转移到目标指令。
/// </summary>
Brfalse,
/// <summary>
/// 如果 value 为 true、非空或非零,则将控制转移到目标指令。
/// </summary>
Brtrue,
/// <summary>
/// 如果两个值相等,则将控制转移到目标指令。
/// </summary>
Beq,
/// <summary>
/// 如果第一个值大于或等于第二个值,则将控制转移到目标指令。
/// </summary>
Bge,
/// <summary>
/// 如果第一个值大于第二个值,则将控制转移到目标指令。
/// </summary>
Bgt,
/// <summary>
/// 如果第一个值小于或等于第二个值,则将控制转移到目标指令。
/// </summary>
Ble,
/// <summary>
/// 如果第一个值小于第二个值,则将控制转移到目标指令。
/// </summary>
Blt,
/// <summary>
/// 当两个无符号整数值或不可排序的浮点型值不相等时,将控制转移到目标指令。
/// </summary>
Bne_Un,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令。
/// </summary>
Bge_Un,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点型值时,如果第一个值大于第二个值,则将控制转移到目标指令。
/// </summary>
Bgt_Un,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点型值时,如果第一个值小于或等于第二个值,则将控制转移到目标指令。
/// </summary>
Ble_Un,
/// <summary>
/// 当比较无符号整数值或不可排序的浮点型值时,如果第一个值小于第二个值,则将控制转移到目标指令。
/// </summary>
Blt_Un,
/// <summary>
/// 实现跳转表。
/// </summary>
Switch,
/// <summary>
/// 将 int8 类型的值作为 int32 间接加载到计算堆栈上。
/// </summary>
Ldind_I1,
/// <summary>
/// 将 unsigned int8 类型的值作为 int32 间接加载到计算堆栈上。
/// </summary>
Ldind_U1,
/// <summary>
/// 将 int16 类型的值作为 int32 间接加载到计算堆栈上。
/// </summary>
Ldind_I2,
/// <summary>
/// 将 unsigned int16 类型的值作为 int32 间接加载到计算堆栈上。
/// </summary>
Ldind_U2,
/// <summary>
/// 将 int32 类型的值作为 int32 间接加载到计算堆栈上。
/// </summary>
Ldind_I4,
/// <summary>
/// 将 unsigned int32 类型的值作为 int32 间接加载到计算堆栈上。
/// </summary>
Ldind_U4,
/// <summary>
/// 将 int64 类型的值作为 int64 间接加载到计算堆栈上。
/// </summary>
Ldind_I8,
/// <summary>
/// 将 native int 类型的值作为 native int 间接加载到计算堆栈上。
/// </summary>
Ldind_I,
/// <summary>
/// 将 float32 类型的值作为 F (float) 类型间接加载到计算堆栈上。
/// </summary>
Ldind_R4,
/// <summary>
/// 将 float64 类型的值作为 F (float) 类型间接加载到计算堆栈上。
/// </summary>
Ldind_R8,
/// <summary>
/// 将对象引用作为 O(对象引用)类型间接加载到计算堆栈上。
/// </summary>
Ldind_Ref,
/// <summary>
/// 存储所提供地址处的对象引用值。
/// </summary>
Stind_Ref,
/// <summary>
/// 在所提供的地址存储 int8 类型的值。
/// </summary>
Stind_I1,
/// <summary>
/// 在所提供的地址存储 int16 类型的值。
/// </summary>
Stind_I2,
/// <summary>
/// 在所提供的地址存储 int32 类型的值。
/// </summary>
Stind_I4,
/// <summary>
/// 在所提供的地址存储 int64 类型的值。
/// </summary>
Stind_I8,
/// <summary>
/// 在所提供的地址存储 float32 类型的值。
/// </summary>
Stind_R4,
/// <summary>
/// 在所提供的地址存储 float64 类型的值。
/// </summary>
Stind_R8,
/// <summary>
/// 将两个值相加并将结果推送到计算堆栈上。
/// </summary>
Add,
/// <summary>
/// 从其他值中减去一个值并将结果推送到计算堆栈上。
/// </summary>
Sub,
/// <summary>
/// 将两个值相乘并将结果推送到计算堆栈上。
/// </summary>
Mul,
/// <summary>
/// 将两个值相除并将结果作为浮点(F 类型)或商(int32 类型)推送到计算堆栈上。
/// </summary>
Div,
/// <summary>
/// 两个无符号整数值相除并将结果 ( int32 ) 推送到计算堆栈上。
/// </summary>
Div_Un,
/// <summary>
/// 将两个值相除并将余数推送到计算堆栈上。
/// </summary>
Rem,
/// <summary>
/// 将两个无符号值相除并将余数推送到计算堆栈上。
/// </summary>
Rem_Un,
/// <summary>
/// 计算两个值的按位“与”并将结果推送到计算堆栈上。
/// </summary>
And,
/// <summary>
/// 计算位于堆栈顶部的两个整数值的按位求补并将结果推送到计算堆栈上。
/// </summary>
Or,
/// <summary>
/// 计算位于计算堆栈顶部的两个值的按位异或,并且将结果推送到计算堆栈上。
/// </summary>
Xor,
/// <summary>
/// 将整数值左移(用零填充)指定的位数,并将结果推送到计算堆栈上。
/// </summary>
Shl,
/// <summary>
/// 将整数值右移(保留符号)指定的位数,并将结果推送到计算堆栈上。
/// </summary>
Shr,
/// <summary>
/// 将无符号整数值右移(用零填充)指定的位数,并将结果推送到计算堆栈上。
/// </summary>
Shr_Un,
/// <summary>
/// 对一个值执行求反并将结果推送到计算堆栈上。
/// </summary>
Neg,
/// <summary>
/// 计算堆栈顶部整数值的按位求补并将结果作为相同的类型推送到计算堆栈上。
/// </summary>
Not,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 int8,然后将其扩展(填充)为 int32。
/// </summary>
Conv_I1,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 int16,然后将其扩展(填充)为 int32。
/// </summary>
Conv_I2,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 int32。
/// </summary>
Conv_I4,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 int64。
/// </summary>
Conv_I8,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 float32。
/// </summary>
Conv_R4,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 float64。
/// </summary>
Conv_R8,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 unsigned int32,然后将其扩展为 int32。
/// </summary>
Conv_U4,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 unsigned int64,然后将其扩展为 int64。
/// </summary>
Conv_U8,
/// <summary>
/// 对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。
/// </summary>
Callvirt,
/// <summary>
/// 将位于对象(&、* 或 native int 类型)地址的值类型复制到目标对象(&、* 或 native int 类型)的地址。
/// </summary>
Cpobj,
/// <summary>
/// 将地址指向的值类型对象复制到计算堆栈的顶部。
/// </summary>
Ldobj,
/// <summary>
/// 推送对元数据中存储的字符串的新对象引用。
/// </summary>
Ldstr,
/// <summary>
/// 创建一个值类型的新对象或新实例,并将对象引用(O 类型)推送到计算堆栈上。
/// </summary>
Newobj,
/// <summary>
/// 尝试将引用传递的对象转换为指定的类。
/// </summary>
Castclass,
/// <summary>
/// 测试对象引用(O 类型)是否为特定类的实例。
/// </summary>
Isinst,
/// <summary>
/// 将位于计算堆栈顶部的无符号整数值转换为 float32。
/// </summary>
Conv_R_Un,
/// <summary>
/// 将值类型的已装箱的表示形式转换为其未装箱的形式。
/// </summary>
Unbox,
/// <summary>
/// 引发当前位于计算堆栈上的异常对象。
/// </summary>
Throw,
/// <summary>
/// 查找对象中其引用当前位于计算堆栈的字段的值。
/// </summary>
Ldfld,
/// <summary>
/// 查找对象中其引用当前位于计算堆栈的字段的地址。
/// </summary>
Ldflda,
/// <summary>
/// 用新值替换在对象引用或指针的字段中存储的值。
/// </summary>
Stfld,
/// <summary>
/// 将静态字段的值推送到计算堆栈上。
/// </summary>
Ldsfld,
/// <summary>
/// 将静态字段的地址推送到计算堆栈上。
/// </summary>
Ldsflda,
/// <summary>
/// 用来自计算堆栈的值替换静态字段的值。
/// </summary>
Stsfld,
/// <summary>
/// 将指定类型的值从计算堆栈复制到所提供的内存地址中。
/// </summary>
Stobj,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为有符号 int8 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I1_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为有符号 int16 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I2_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为有符号 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I4_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为有符号 int64,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I8_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为 unsigned int8 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U1_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为 unsigned int16 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U2_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为 unsigned int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U4_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为 unsigned int64,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U8_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为有符号 native int,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I_Un,
/// <summary>
/// 将位于计算堆栈顶部的无符号值转换为 unsigned native int,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U_Un,
/// <summary>
/// 将值类转换为对象引用(O 类型)。
/// </summary>
Box,
/// <summary>
/// 将对新的从零开始的一维数组(其元素属于特定类型)的对象引用推送到计算堆栈上。
/// </summary>
Newarr,
/// <summary>
/// 将从零开始的、一维数组的元素的数目推送到计算堆栈上。
/// </summary>
Ldlen,
/// <summary>
/// 将位于指定数组索引的数组元素的地址作为 & 类型(托管指针)加载到计算堆栈的顶部。
/// </summary>
Ldelema,
/// <summary>
/// 将位于指定数组索引处的 int8 类型的元素作为 int32 加载到计算堆栈的顶部。
/// </summary>
Ldelem_I1,
/// <summary>
/// 将位于指定数组索引处的 unsigned int8 类型的元素作为 int32 加载到计算堆栈的顶部。
/// </summary>
Ldelem_U1,
/// <summary>
/// 将位于指定数组索引处的 int16 类型的元素作为 int32 加载到计算堆栈的顶部。
/// </summary>
Ldelem_I2,
/// <summary>
/// 将位于指定数组索引处的 unsigned int16 类型的元素作为 int32 加载到计算堆栈的顶部。
/// </summary>
Ldelem_U2,
/// <summary>
/// 将位于指定数组索引处的 int32 类型的元素作为 int32 加载到计算堆栈的顶部。
/// </summary>
Ldelem_I4,
/// <summary>
/// 将位于指定数组索引处的 unsigned int32 类型的元素作为 int32 加载到计算堆栈的顶部。
/// </summary>
Ldelem_U4,
/// <summary>
/// 将位于指定数组索引处的 int64 类型的元素作为 int64 加载到计算堆栈的顶部。
/// </summary>
Ldelem_I8,
/// <summary>
/// 将位于指定数组索引处的 native int 类型的元素作为 native int 加载到计算堆栈的顶部。
/// </summary>
Ldelem_I,
/// <summary>
/// 将位于指定数组索引处的 float32 类型的元素作为 F 类型(浮点型)加载到计算堆栈的顶部。
/// </summary>
Ldelem_R4,
/// <summary>
/// 将位于指定数组索引处的 float64 类型的元素作为 F 类型(浮点型)加载到计算堆栈的顶部。
/// </summary>
Ldelem_R8,
/// <summary>
/// 将位于指定数组索引处的包含对象引用的元素作为 O 类型(对象引用)加载到计算堆栈的顶部。
/// </summary>
Ldelem_Ref,
/// <summary>
/// 用计算堆栈上的 native int 值替换给定索引处的数组元素。
/// </summary>
Stelem_I,
/// <summary>
/// 用计算堆栈上的 int8 值替换给定索引处的数组元素。
/// </summary>
Stelem_I1,
/// <summary>
/// 用计算堆栈上的 int16 值替换给定索引处的数组元素。
/// </summary>
Stelem_I2,
/// <summary>
/// 用计算堆栈上的 int32 值替换给定索引处的数组元素。
/// </summary>
Stelem_I4,
/// <summary>
/// 用计算堆栈上的 int64 值替换给定索引处的数组元素。
/// </summary>
Stelem_I8,
/// <summary>
/// 用计算堆栈上的 float32 值替换给定索引处的数组元素。
/// </summary>
Stelem_R4,
/// <summary>
/// 用计算堆栈上的 float64 值替换给定索引处的数组元素。
/// </summary>
Stelem_R8,
/// <summary>
/// 用计算堆栈上的对象 ref 值(O 类型)替换给定索引处的数组元素。
/// </summary>
Stelem_Ref,
/// <summary>
/// 按照指令中指定的类型,将指定数组索引中的元素加载到计算堆栈的顶部。
/// </summary>
Ldelem_Any,
/// <summary>
/// 用计算堆栈中的值替换给定索引处的数组元素,其类型在指令中指定。
/// </summary>
Stelem_Any,
/// <summary>
/// 将指令中指定类型的已装箱的表示形式转换成未装箱形式。
/// </summary>
Unbox_Any,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为有符号 int8 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I1,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为 unsigned int8 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U1,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为有符号 int16 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I2,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为 unsigned int16 并将其扩展为 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U2,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为有符号 int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I4,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为 unsigned int32,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U4,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为有符号 int64,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I8,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为 unsigned int64,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U8,
/// <summary>
/// 检索嵌入在类型化引用内的地址(& 类型)。
/// </summary>
Refanyval,
/// <summary>
/// 如果值不是有限数,则引发 ArithmeticException。
/// </summary>
Ckfinite,
/// <summary>
/// 将对特定类型实例的类型化引用推送到计算堆栈上。
/// </summary>
Mkrefany,
/// <summary>
/// 将元数据标记转换为其运行时表示形式,并将其推送到计算堆栈上。
/// </summary>
Ldtoken,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 unsigned int16,然后将其扩展为 int32。
/// </summary>
Conv_U2,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 unsigned int8,然后将其扩展为 int32。
/// </summary>
Conv_U1,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 native int。
/// </summary>
Conv_I,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为有符号 native int,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_I,
/// <summary>
/// 将位于计算堆栈顶部的有符号值转换为 unsigned native int,并在溢出时引发 OverflowException。
/// </summary>
Conv_Ovf_U,
/// <summary>
/// 将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上。
/// </summary>
Add_Ovf,
/// <summary>
/// 将两个无符号整数值相加,执行溢出检查,并且将结果推送到计算堆栈上。
/// </summary>
Add_Ovf_Un,
/// <summary>
/// 将两个整数值相乘,执行溢出检查,并将结果推送到计算堆栈上。
/// </summary>
Mul_Ovf,
/// <summary>
/// 将两个无符号整数值相乘,执行溢出检查,并将结果推送到计算堆栈上。
/// </summary>
Mul_Ovf_Un,
/// <summary>
/// 从另一值中减去一个整数值,执行溢出检查,并且将结果推送到计算堆栈上。
/// </summary>
Sub_Ovf,
/// <summary>
/// 从另一值中减去一个无符号整数值,执行溢出检查,并且将结果推送到计算堆栈上。
/// </summary>
Sub_Ovf_Un,
/// <summary>
/// 将控制从异常块的 fault 或 finally 子句转移回公共语言结构 (CLI) 异常处理程序。
/// </summary>
Endfinally,
/// <summary>
/// 退出受保护的代码区域,无条件将控制转移到特定目标指令。
/// </summary>
Leave,
/// <summary>
/// 退出受保护的代码区域,无条件将控制转移到目标指令(缩写形式)。
/// </summary>
Leave_S,
/// <summary>
/// 在所提供的地址存储 native int 类型的值。
/// </summary>
Stind_I,
/// <summary>
/// 将位于计算堆栈顶部的值转换为 unsigned native int,然后将其扩展为 native int。
/// </summary>
Conv_U,
/// <summary>
/// 返回指向当前方法的参数列表的非托管指针。
/// </summary>
Arglist,
/// <summary>
/// 比较两个值。如果这两个值相等,则将整数值 1 (int32) 推送到计算堆栈上;否则,将 0 (int32) 推送到计算堆栈上。
/// </summary>
Ceq,
/// <summary>
/// 比较两个值。如果第一个值大于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
/// </summary>
Cgt,
/// <summary>
/// 比较两个无符号的或不可排序的值。如果第一个值大于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
/// </summary>
Cgt_Un,
/// <summary>
/// 比较两个值。如果第一个值小于第二个值,则将整数值 1 (int32) 推送到计算堆栈上;反之,将 0 (int32) 推送到计算堆栈上。
/// </summary>
Clt,
/// <summary>
/// 比较无符号的或不可排序的值 value1 和 value2。如果 value1 小于 value2,则将整数值 1 (int32 ) 推送到计算堆栈上;反之,将 0 ( int32 ) 推送到计算堆栈上。
/// </summary>
Clt_Un,
/// <summary>
/// 将指向实现特定方法的本机代码的非托管指针(native int 类型)推送到计算堆栈上。
/// </summary>
Ldftn,
/// <summary>
/// 将指向实现与指定对象关联的特定虚方法的本机代码的非托管指针(native int 类型)推送到计算堆栈上。
/// </summary>
Ldvirtftn,
/// <summary>
/// 将参数(由指定索引值引用)加载到堆栈上。
/// </summary>
Ldarg,
/// <summary>
/// 将参数地址加载到计算堆栈上。
/// </summary>
Ldarga,
/// <summary>
/// 将位于计算堆栈顶部的值存储到位于指定索引的参数槽中。
/// </summary>
Starg,
/// <summary>
/// 将指定索引处的局部变量加载到计算堆栈上。
/// </summary>
Ldloc,
/// <summary>
/// 将位于特定索引处的局部变量的地址加载到计算堆栈上。
/// </summary>
Ldloca,
/// <summary>
/// 从计算堆栈的顶部弹出当前值并将其存储到指定索引处的局部变量列表中。
/// </summary>
Stloc,
/// <summary>
/// 从本地动态内存池分配特定数目的字节并将第一个分配的字节的地址(瞬态指针,* 类型)推送到计算堆栈上。
/// </summary>
Localloc,
/// <summary>
/// 将控制从异常的 filter 子句转移回公共语言结构 (CLI) 异常处理程序。
/// </summary>
Endfilter,
/// <summary>
/// 指示当前位于计算堆栈上的地址可能没有与紧接的 ldind、stind、ldfld、stfld、ldobj、stobj、initblk 或 cpblk 指令的自然大小对齐。
/// </summary>
Unaligned,
/// <summary>
/// 指定当前位于计算堆栈顶部的地址可以是易失的,并且读取该位置的结果不能被缓存,或者对该地址的多个存储区不能被取消。
/// </summary>
Volatile,
/// <summary>
/// 执行后缀的方法调用指令,以便在执行实际调用指令前移除当前方法的堆栈帧。
/// </summary>
Tail,
/// <summary>
/// 将位于指定地址的值类型的每个字段初始化为空引用或适当的基元类型的 0。
/// </summary>
Initobj,
/// <summary>
/// 约束要对其进行虚方法调用的类型。
/// </summary>
Constrained,
/// <summary>
/// 将指定数目的字节从源地址复制到目标地址。
/// </summary>
Cpblk,
/// <summary>
/// 将位于特定地址的内存的指定块初始化为给定大小和初始值。
/// </summary>
Initblk,
No,
/// <summary>
/// 再次引发当前异常。
/// </summary>
Rethrow,
/// <summary>
/// 将提供的值类型的大小(以字节为单位)推送到计算堆栈上。
/// </summary>
Sizeof,
/// <summary>
/// 检索嵌入在类型化引用内的类型标记。
/// </summary>
Refanytype,
/// <summary>
/// 指定后面的数组地址操作在运行时不执行类型检查,并且返回可变性受限的托管指针。
/// </summary>
Readonly,
}
}
OpCodeEnum
using System;
using System.Collections.Generic; namespace HotFix_Project
{
public class InstanceClass
{
private int id; public InstanceClass()
{
UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass()");
this.id = ;
} public InstanceClass(int id)
{
UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass() id = " + id);
this.id = id;
} public int ID
{
get { return id; }
} // static method
public static void StaticFunTest()
{
UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest()");
} public static void StaticFunTest2(int a)
{
UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest2(), a=" + a);
} public static void GenericMethod<T>(T a)
{
UnityEngine.Debug.Log("!!! InstanceClass.GenericMethod(), a=" + a);
}
} }
HotFix_Project.InstanceClass
System.Void HotFix_Project.InstanceClass::.ctor()
System.Void HotFix_Project.InstanceClass::.ctor(System.Int32)
System.Int32 HotFix_Project.InstanceClass::get_ID()
System.Void HotFix_Project.InstanceClass::StaticFunTest()
System.Void HotFix_Project.InstanceClass::StaticFunTest2(System.Int32)
System.Void HotFix_Project.InstanceClass::GenericMethod(T)
Mono.Cecil.Methods: MethodDifinition(HotFix_Project.InstanceClass)
IType.ArrayRank :
IType.ArrayType :
IType.BaseType :
IType.ByRefType :
IType.ElementType :
IType.FullName : HotFix_Project.InstanceClass
IType.GenericArguments :
IType.GetActualType() : ILRuntime.CLR.TypeSystem.ILType
IType.HasGenericParameter : False
IType.Implements :
IType.IsArray : False
IType.IsByRef : False
IType.IsDelegate : False
IType.IsEnum : False
IType.IsGenericInstance : False
IType.IsGenericParameter : False
IType.IsInterface : False
IType.IsPrimitive : False
IType.IsValueType : False
IType.Name : InstanceClass
IType.ReflectionType : Type: InstanceClass
IType.TypeForCLR : ILRuntime.Runtime.Intepreter.ILTypeInstance
HotFix_Project.InstanceClass IType 部分属性
public unsafe AppDomain() { } appdomain.LoadAssembly(fs); appdomain.mapType.Count =
[<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.\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.\Editor\UnityEditor.Advertisements.dll
Unity.Analytics.Tracker, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.analytics@3.2.\Unity.Analytics.Tracker.dll
Unity.Analytics.StandardEvents, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.analytics@3.2.\Unity.Analytics.StandardEvents.dll
Unity.Analytics.Editor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.analytics@3.2.\Unity.Analytics.Editor.dll
UnityEditor.Purchasing, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Library\PackageCache\com.unity.purchasing@2.0.\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 : ); // 转型为 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();
// System.Reflection.MethodInfo.Invoke
// Module: UnityEngine.CoreModule.dll
// Assembly: UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// Module.FullyQualifiedName "D:\\Program Files\\Unity\\2018.4.6f1\\Editor\\Data\\Managed\\UnityEngine\\UnityEngine.CoreModule.dll
cm.def.Invoke(null, new[] { "Hello World" });
}
真正的Hello World
热更项目 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace HotFix_Project {
public class HelloWorld {
public int id = ; public HelloWorld() {
id = ;
}
}
} 主项目 AppDomain.LoadAssembly
foreach (var t in module.GetTypes()) //获取所有此模块定义的类型
{
ILType type = new ILType(t, this); mapType[t.FullName] = type;
types.Add(type); // 这里
// e.g. <"HotFix_Project.HelloWorld": string, HotFix_Project.HelloWorld: TypeDefintion>
typeDef[t.FullName] = t;
} HelloWorldDemo.OnHotFixLoaded
TypeDefinition type = appdomain.typeDef["HotFix_Project.HelloWorld"];
MyInstance ins = new MyInstance(type);
Assert(ins.id == ) // 根据 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[];
method = def.Methods[]; // IL 指令
Collection<Instruction> instructions = this.def.Methods[].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 = ;
break;
// 用新值替换在对象引用或指针的字段中存储的值
case Code.Stfld:
// stfld: System.Int32 HotFix_Project.HelloWorld::id = 0
id = dummyStack;
break;
// 将整数值 0 作为 int32 推送到计算堆栈上
case Code.Ldc_I4_2:
dummyStack = ;
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 : ;
// 通过方法名字符串 获取 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 - ;
// 返回解释器
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 = ; 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 = ; 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 = ;
while (isCollision)
{
cnt++;
hashCode = cnt << | oriHash;
isCollision = CheckStringCollision(hashCode, str);
}
mapString[hashCode] = (string)token;
}
return hashCode;
// 将 TokenLong 设置为 字符串的 hash
code.TokenLong = hashCode; }
case OpCodeEnum.Call:
{
bool invalidToken;
// token = System.Void UnityEngine.Debug::Log(System.Object)
// declaringType = HotFix_Project.InstanceClass
var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
string methodname = null;
string typename = null;
List<IType> paramList = null;
// hashCoede = 1
int hashCode = token.GetHashCode();
IMethod method;
IType[] genericArguments = null;
IType returnType;
invalidToken = false;
bool isConstructor = false;
// 通过 hashCode = 1 找到了 UnityEngine.Debug.Log 方法
if (mapMethod.TryGetValue(hashCode, out method))
return method; if (m != null)
{
if (invalidToken)
code.TokenInteger = m.GetHashCode();
else
// TokenInteger = 1
code.TokenInteger = token.GetHashCode();
}
else
{
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : ;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
}
} if (i > && c.OpCode.Code == Mono.Cecil.Cil.Code.Callvirt && def.Body.Instructions[i - ].OpCode.Code == Mono.Cecil.Cil.Code.Constrained)
{
body[i - ].TokenLong = body[i].TokenInteger;
}
} // def.Body.ExceptionHandlers.Count = 0
for (int i = ; 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] - ;
e.TryStart = addr[eh.TryStart];
e.TryEnd = addr[eh.TryEnd] - ;
switch (eh.HandlerType)
{
case Mono.Cecil.Cil.ExceptionHandlerType.Catch:
e.CatchType = appdomain.GetType(eh.CatchType, declaringType, this);
e.HandlerType = ExceptionHandlerType.Catch;
break;
case Mono.Cecil.Cil.ExceptionHandlerType.Finally:
e.HandlerType = ExceptionHandlerType.Finally;
break;
case Mono.Cecil.Cil.ExceptionHandlerType.Fault:
e.HandlerType = ExceptionHandlerType.Fault;
break;
default:
throw new NotImplementedException();
}
exceptionHandler[i] = e;
//Mono.Cecil.Cil.ExceptionHandlerType.
}
//Release Method body to save memory
// 变量为 0
variables = def.Body.Variables;
def.Body = null;
}
else
body = new OpCode[];
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 > ? Add(esp, method.LocalVariableCount) : esp;
// 设置 ValueTypeBasePointer 0x4dbc6004
res.ValueTypeBasePointer = valueTypePtr;
// v1 = 0x4db96010
StackObject* v1 = frame.LocalVarPointer;
// v2 = 0x4db9601C
StackObject* v2 = frame.LocalVarPointer + ;
// v3 = 0x4db96028
StackObject* v3 = frame.LocalVarPointer + + ;
// v4 = 0x4db96034
StackObject* v4 = Add(frame.LocalVarPointer, );
int finallyEndAddress = ;
// 设置 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 = ; 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) != )
{
UnboxObject(esp, obj, mStack);
}
else if ((typeFlags & CLR.Utils.Extensions.TypeFlags.IsEnum) != )
{
esp->ObjectType = ObjectTypes.Integer;
esp->Value = Convert.ToInt32(obj);
}
else
{
// 是Object类型
esp->ObjectType = ObjectTypes.Object; esp->Value = mStack.Count;
// 添加到 List<object> || UncheckedList<object>
mStack.Add(obj);
}
}
else
{
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
mStack.Add(obj);
}
}
else
{
return PushNull(esp);
}
// 指针+ 1, e.g. 0x4db96010 + 12 = 0x4db9601C
return esp + ;
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 >= ; i--)
{
var p = Minus(esp, i);
var pt = this.param[paramCount - i].ParameterType;
var obj = pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
case ObjectType.Object:
// 通过 StackObject 指针的 value 获得 mStack 里的参数值
// mStack[0] = !!! InstanceClass.StaticFunTest()
return mStack[esp->Value]; var typeFlags = GetTypeFlags(pt);
return obj; obj = ILIntepreter.CheckAndCloneValueType(obj, appdomain);
if (obj is ILTypeInstance)
{
ILTypeInstance ins = obj as ILTypeInstance;
if (ins.IsValueType)
{
return ins.Clone();
}
}
else
{
// System.String
var type = obj.GetType();
// Default
var typeFlags = type.GetTypeFlags();
// false
var isPrimitive = (typeFlags & CLR.Utils.Extensions.TypeFlags.IsPrimitive) != ;
// false
var isValueType = (typeFlags & CLR.Utils.Extensions.TypeFlags.IsValueType) != ; 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 = ; i <= paramCount; i++)
{
// 释放
Free(Minus(esp, i));
if (esp->ObjectType >= ObjectTypes.Object)
{
var mStack = stack.ManagedStack;
if (esp->Value == mStack.Count - )
mStack.RemoveAt(esp->Value);
}
}
// 移动栈顶指针
esp = Minus(esp, paramCount);
if (cm.HasThis)
{
Free(esp - );
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 > && frames.Peek().BasePointer == frame.BasePointer)
frames.Pop();
// null
object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - ), 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:
ILRuntime.Runtime.Intepreter.ILIntepreter, type: ILRuntime.Runtime.Intepreter.ILIntepreter mapType: ThreadSafeDictionary<string, IType> Count:
[<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:
[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:
[, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Int64], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Boolean], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Single], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Double], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Void], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Int32], type: ILRuntime.CLR.TypeSystem.CLRType
[, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[, UnityEngine.Debug], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Object], type: ILRuntime.CLR.TypeSystem.CLRType
[, UnityEngine.ILogger], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.Type], type: ILRuntime.CLR.TypeSystem.CLRType
[, System.String], type: ILRuntime.CLR.TypeSystem.CLRType mapMethod: ThreadSafeDictionary<int, IMethod> Count :
[, Void Log(System.Object)], type: ILRuntime.CLR.Method.CLRMethod mapString: ThreadSafeDictionary<long, string> Count :
[-, !!! InstanceClass.StaticFunTest()], type: System.String
各种字典
Debug.Log 流程
[System.Void HotFix_Project.InstanceClass::StaticFunTest(): ILMethod].InitCodeBody
// ILRuntime.Mono.Cecil.Cil.Instruction.OpCode.Code == Call
// ILRuntime.Mono.Cecil.Cil.Instruction.Operand == System.Void UnityEngine.Debug::Log(System.Object)
[ILMethod].InitToken()
bool invalidToken;
// token: ILRuntime.Mono.Cecil.Body.Instruction.Operand = System.Void UnityEngine.Debug::Log(System.Object)
// declaringType: HotFix_Project.InstanceClass
// this: System.Void HotFix_Project.InstanceClass::StaticFunTest(): ILMethod
var m = [appdomain].GetMethod(token, declaringType, this, out invalidToken);
// 获取 Operand 的 hashCode == 1
int hashCode = token.GetHashCode();
// mapMethod字典目前没有这个方法
if (mapMethod.TryGetValue(hashCode, out method))
return method;
// object 是 Mono.Cecil.MethodReference
if (token is Mono.Cecil.MethodReference)
// token 也就是 UnityEngine.Debug.Log 转型为 Mono.Cecil.MethodReference
Mono.Cecil.MethodReference _ref = (token as Mono.Cecil.MethodReference);
// Log
methodname = _ref.Name;
var typeDef = _ref.DeclaringType;
// 获取Log 方法所属类型
// typeDef: TypeReference = UnityEngine.Debug
// contextType: ILType = HotFix_Project.InstanceClass
// contextMethod: ILMethod = HotFix_Project.InstanceClass.StaticFunTest()
type = [appdomain].GetType(typeDef, contextType, contextMethod);
// 获取 UnityEngine.Debug hashcode = 4
int hash = token.GetHashCode();
// mapTypeToken 字典目前没有这个类型
if (mapTypeToken.TryGetValue(hash, out res))
return res;
// UnityEngine.Debug 是 TypeReference
if (token is Mono.Cecil.TypeReference)
// token 也就是 UnityEngine.Debug.Log 转型为 TypeReference
Mono.Cecil.TypeReference _ref = (token as Mono.Cecil.TypeReference);
// 获取 module = HotFix_Project.dll
module = _ref.Module;
// 获取 类型全名 UnityEngine.Debug
typename = _ref.FullName;
// _ref.Scope = UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// scope = UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
scope = GetAssemblyName(_ref.Scope);
// 获取 UnityEngine.Debug 的 IType
res = GetType(typename);
// mapType 字典 目前没有 这个类型
if (mapType.TryGetValue(fullname, out res))
return res;
// 通过 UnityEngine.Debug 获取 Type
Type t = Type.GetType(fullname);
// 没有找到 UnityEngine.Debug
if (res == null)
{
// 将 / 替换成 +
typename = typename.Replace("/", "+");
res = GetType(typename);
}
// res == null scope == UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
if (res == null && scope != null)
res = GetType(typename + ", " + scope);
// 获取 UnityEngine.Debug, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
Type t = Type.GetType(fullname);
// clrTypeMapping 字典里没有这个类型
if (!clrTypeMapping.TryGetValue(t, out res))
{
// 通过 Type new 一个 CLRType
res = new CLRType(t, this);
clrTypeMapping[t] = res;
}
// 获取参数
paramList = _ref.GetParamList(this, contextType, contextMethod, genericArguments);
// 有参数
if (def.HasParameters)
List<IType> param = new List<IType>();
// UnityEngine.Debug
var dt = appdomain.GetType(def.DeclaringType, contextType, contextMethod);
// 遍历参数
foreach (var i in def.Parameters)
// System.Object
t = appdomain.GetType(i.ParameterType, dt, null);
// 获取返回类型
// System.Void
returnType = GetType(_ref.ReturnType, type, null);
// 获取方法 // 获取方法
// methodname = Log
method = [UnityEngine.Debug type: CLRType].GetMethod(methodname, paramList, genericArguments, returnType, true);
// 目前 UnityEngine.Debug 里没有 方法
if (methods == null)
[CLRType].InitializeMethods();
if (i.IsPrivate)
continue;
List<CLRMethod> lst;
if (!methods.TryGetValue(i.Name, out lst))
{
lst = new List<CLRMethod>();
methods[i.Name] = lst;
"[get_unityLogger, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[DrawLine, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[DrawRay, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Break, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[DebugBreak, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Log, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogError, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogErrorFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[ClearDeveloperConsole, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[get_developerConsoleVisible, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[set_developerConsoleVisible, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogException, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogPlayerBuildError, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogWarning, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogWarningFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Assert, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[AssertFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogAssertion, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[LogAssertionFormat, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[get_isDebugBuild, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[OpenConsoleFile, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetDiagnosticSwitches, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetDiagnosticSwitch, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[SetDiagnosticSwitch, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[get_logger, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Equals, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[Finalize, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetHashCode, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[GetType, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[MemberwiseClone, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
"[ToString, System.Collections.Generic.List`1[ILRuntime.CLR.Method.CLRMethod]]"
}
lst.Add(new CLRMethod(i, this, appdomain)); // UnityEngine.Debug.Log 方法 添加到 全局 mapMethod 字典里
if (!invalidToken)
mapMethod[hashCode] = method;
else
mapMethod[method.GetHashCode()] = method; // 将 hashcode 复制给 OpCode.TokenInteger, 主要是用于查找方法
if (m != null)
{
if (invalidToken)
code.TokenInteger = m.GetHashCode();
else
code.TokenInteger = token.GetHashCode();
}
else
{
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : ;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
}
Debug 调用流程
热更项目 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine; namespace HotFix_Project {
public class HelloWorldWithDebug { public HelloWorldWithDebug() {
Debug.Log("HelloWorldWithDebug");
}
}
} 主项目
OnHotFixLoaded()
// 主项目通过 MethodInfo 调用 UnityEngine.Debug.Log, 和热更项目没关系
System.Type debugType = typeof(Debug);
System.Reflection.MethodInfo log = null; foreach (var item in debugType.GetMethods()) {
if (item.Name == "Log" && item.GetParameters().Length == ) {
log = item;
}
} log.Invoke(null, new[] { "Hello" }); // 热更项目 里 调用 UnityEngine.Debug.Log
var obj = appdomain.Instantiate("HotFix_Project.HelloWorldWithDebug");
// 根据 IL 指令 初始化方法
// ILMethod = "HotFix_Project.HelloWorldWithDebug..ctor()" OpCode[] body = method.Body;
[ILMethod].InitCodeBody
// body[5] = Call, 0, 0
// c.Operand: MethodReference = "System.Void UnityEngine.Debug::Log(System.Object)"
// addr =
// "IL_0000: ldarg.0"
// "IL_0001: call System.Void System.Object::.ctor()"
// "IL_0006: nop"
// "IL_0007: nop"
// "IL_0008: ldstr \"HelloWorldWithDebug\""
// "IL_000d: call System.Void UnityEngine.Debug::Log(System.Object)"
// "IL_0012: nop"
// "IL_0013: ret"
InitToken(ref body[i], c.Operand, addr);
case OpCodeEnum.Call:
bool invalidToken;
// token: MethodReference = System.Void UnityEngine.Debug::Log(System.Object)
// declaringType: ILType = "HotFix_Project.HelloWorldWithDebug"
var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
// _ref = token
// DeclaringType = "UnityEngine.Debug"
var typeDef = _ref.DeclaringType;
// 获取 UnityEngine.Debug 的类型
type = GetType(typeDef, contextType, contextMethod);
// 是
if (token is Mono.Cecil.TypeReference)
// typename = "UnityEngine.Debug"
typename = _ref.FullName;
// "UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
scope = GetAssemblyName(_ref.Scope);
// 获取 UnityEngine.Debug 的类型
res = GetType(typename);
// 通过 System.Type.GetType 获取 UnityEngine.Debug 的类型
// t = null 没找到
Type t = Type.GetType(fullname);
// res = null
// scope = "UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
if (res == null && scope != null)
// 通过 "UnityEngine.Debug, UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" 查找类型
res = GetType(typename + ", " + scope);
// 找到了
Type t = Type.GetType(fullname);
res = new CLRType(t, this);
// [UnityEngine.Debug: Type, UnityEngine.Debug: CLRType]
clrTypeMapping[t] = res;
// 通过 type = UnityEngine.Debug, methodname = Log, 查找方法
method = type.GetMethod(methodname, paramList, genericArguments, returnType, true);
// 初始化 UnityEngine.Debug 的方法
InitializeMethods();
// 获取 UnityEngine.Debug 的方法, 存入 UnityEngine.Debug: CLRType 里
foreach (var i in clrType: Type.GetMethods)
// e.g. Log
new CLRMethod(i, this, appdomain));
this.def: MethodInfo = "Void Log(System.Object)"
// 通过 methods 获取 UnityEngine.Debug.Log
if (methods.TryGetValue(name, out lst)) if (m != null)
{
if (invalidToken)
code.TokenInteger = m.GetHashCode();
else
// TokenInteger = 2
// token: MethodReference = "System.Void UnityEngine.Debug::Log(System.Object)"
code.TokenInteger = token.GetHashCode();
}
else
{
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : ;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
} // 执行
case OpCodeEnum.Call:
// m: CLRMethod = "Void Log(System.Object)"
IMethod m = domain.GetMethod(ip->TokenInteger);
CLRMethod cm = (CLRMethod)m;
// 执行CLRMethod.Invoke
object result = cm.Invoke(this, esp, mStack);
// 从 非托管栈上 获取 参数
// obj = "HelloWorldWithDebug"
var obj = pt.CheckCLRTypes(StackObject.ToObject(p, appdomain, mStack));
// def: MethodInfo = "Void Log(System.Object)"
// param = HelloWorldWithDebug
res = def.Invoke(instance, param);
热更项目 里 调用 UnityEngine.Debug.Log 2.0
热更项目 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.SceneManagement; namespace HotFix_Project {
public class HelloWorldWithScene { public HelloWorldWithScene() {
// 热更项目获取 主项目当前场景
Scene scene = SceneManager.GetActiveScene();
// 热更项目获取 当前场景里的第一个 GameObject
GameObject go = scene.GetRootGameObjects()[];
// 热更项目获取 主项目里 挂在 GameObject 身上的 HelloWorld 脚本
HelloWorld hw = go.GetComponent<HelloWorld>();
// 热更项目调用 主项目脚本里的方法 Test1
hw.Test1();
}
}
} 主项目 public void Test1() {
var pos = transform.position;
pos.x += ;
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", ); 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, );
指定参数类型来获得IMethod
Debug.Log("实例化热更里的类");
object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { });
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 != ;
// 初始化 "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 = ; i < fields.Length; i++)
{
managedObjs.Add(null);
}
// 初始化 HotFix_Project.InstanceClass 的字段
[ILTypeInstance].InitializeFields(type);
for (int i = ; 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 = ;
esp.ValueLow = ;
} }
if (type.BaseType != null && type.BaseType is ILType)
InitializeFields((ILType)type.BaseType);
return res; // 如果有构造函数
if (hasConstructor)
{
// 通过参数数量 获取 构造函数
var ilm = ilType.GetConstructor(args.Length);
if (constructors == null)
InitializeMethods();
foreach (var i in constructors)
{
if (i.ParameterCount == paramCnt)
{
return i;
}
}
return null;
// 根据 ILMethod ILTypeInstance , args 调用方法
[AppDomain].Invoke(ilm, res, args);
// 请求解释器
ILIntepreter inteptreter = RequestILIntepreter();
// 解释器 运行 方法
res = inteptreter.Run((ILMethod)m, instance, p);
// 有 this
if (method.HasThis)
{
if (instance is CrossBindingAdaptorType)
instance = ((CrossBindingAdaptorType)instance).ILInstance;
if (instance == null)
throw new NullReferenceException("instance should not be null!");
// 将实例 压栈
esp = PushObject(esp, mStack, instance);
}
// 将参数入栈
esp = PushParameters(method, esp, p);
bool unhandledException;
// 执行方法
esp = Execute(method, esp, out unhandledException);
}
return res;
}
} return null; //预先获得IMethod,可以减低每次调用查找方法耗用的时间
IType type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
//第二种方式
object obj2 = ((ILType)type).Instantiate();
实例化热更里的类
热更项目 using System;
using System.Collections.Generic; namespace HotFix_Project
{
private int id; public class InstanceClass
{
public InstanceClass() { }
}
} 主项目 AppDomain.LoadAssembly
// t: TypeDefinition
foreach (var t in module.GetTypes())
// 通过 TypeDefinition 构造 ILType
ILType type = new ILType(t, this);
// this.typeRef: TypeReference = t: TypeDefinition
this.typeRef = def;
[ILType].RetriveDefinitino(def);
// def 不是泛型参数
if (!def.IsGenericParameter)
if (def is TypeSpecification)
definition = def as TypeDefinition; ILTypeInstance obj = appdomain.Instantiate("HotFix_Project.InstanceClass");
// mapType 通过字符串 获取 ILType e.g. HotFix_Project.InstanceClass: ILType
if (mapType.TryGetValue(type, out t))
// 没有参数
bool hasConstructor = args != null && args.Length != ;
// 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 = ; 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 = ; i < fields.Length; i++)
// 托管对象 默认为空
managedObjs.Add(null);
// 初始化字段
InitializeFields(type);
for (int i = ; 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 = ; // 值的高32位
esp.ValueLow = ; // 值的低32位
}
// 没有 BaseType
if (type.BaseType != null && type.BaseType is ILType)
InitializeFields((ILType)type.BaseType);
if (initializeCLRInstance)
// FirstCLRBaseType 不是 CrossBindingAdaptor
if (!type.FirstCLRBaseType is Enviorment.CrossBindingAdaptor)
// HotFix_Project.InstanceClass: ILTypeInstance.clrInstance = 自己
clrInstance = this;
// 调用默认构造函数
if (callDefaultConstructor)
IMethod m = [ILType].GetConstructor(CLR.Utils.Extensions.EmptyParamList);
// constructors 默认为空
if (constructors == null)
// 第一次调用, 初始化方法
InitializeMethods();
// 普通方法 字典
methods = new Dictionary<string, List<ILMethod>>();
// 构造函数字典
constructors = new List<ILMethod>();
// TypeDefinition 不为空
if (definition == null)
return;
// 只有一个 "System.Void HotFix_Project.InstanceClass::.ctor()"
foreach (var i in definition.Methods)
{
// 是构造函数
if (i.IsConstructor)
{
if (i.IsStatic)
staticConstructor = new ILMethod(i, this, appdomain);
else
// 不是 静态构造函数 new 一个ILMethod 添加到 constructors
constructors.Add(new ILMethod(i, this, appdomain));
// this.def: MethodDefinition
this.def = def;
// declaringType: ILType HotFix_Project.InstanceClass
declaringType = type;
// 返回类型不是 泛型
if (def.ReturnType.IsGenericParameter)
{
ReturnType = FindGenericArgument(def.ReturnType.Name);
}
else
// 获取 返回类型 System.Void Type hashCode = 3
ReturnType = domain.GetType(def.ReturnType, type, this);
// declaringType 不是委托, MethodDifinition.Name 也不是 Invoke
if (type.IsDelegate && def.Name == "Invoke")
isDelegateInvoke = true;
this.appdomain = domain;
// 参数数量为0
paramCnt = def.HasParameters ? def.Parameters.Count : ;
}
else
{
List<ILMethod> lst;
if (!methods.TryGetValue(i.Name, out lst))
{
lst = new List<ILMethod>();
methods[i.Name] = lst;
}
var m = new ILMethod(i, this, appdomain);
lst.Add(m);
}
}
// 遍历构造函数
foreach (var i in constructors)
// 参数数量适配
if (i.ParameterCount == param.Count)
// 返回这个方法
return i;
// m: ILMethod = "HotFix_Project.InstanceClass..ctor()"
// res: ILTypeInstance = HotFix_Project.InstanceClass
appdomain.Invoke(m, res, null);
// 函数调用结果
object res = null;
if (m is ILMethod)
{
// 请求解释器
ILIntepreter inteptreter = RequestILIntepreter();
// new 一个解释器
inteptreter = new ILIntepreter(this);
// new 一个 运行时堆栈
stack = new RuntimeStack(this);
// 没开调试, 是 UncheckedList<object>
IList<object> managedStack = new UncheckedList<object>()
// 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 - ;
try
{
// 解释器 执行这个方法
res = inteptreter.Run((ILMethod)m, instance, p);
// 获取 托管对象
IList<object> mStack = stack.ManagedStack;
// 获取托管对象数量
int mStackBase = mStack.Count;
// 获取 栈对象指针 0x5b4bf030 分配的非托管堆的 起始指针
StackObject* esp = stack.StackBase;
// 重设 值类型指针
stack.ResetValueTypePointer();
// 有 this
if (method.HasThis)
// 实例不是 CrossBindingAdaptorType
if (instance is CrossBindingAdaptorType)
instance = ((CrossBindingAdaptorType)instance).ILInstance;
// 实例不为空
if (instance == null)
throw new NullReferenceException("instance should not be null!");
// 将 ILTypeInstance 压入托管栈, 同时设置 esp 指向的 StackObject的值, 最后 esp += 1
esp = PushObject(esp, mStack, instance);
// {ILRuntime.Runtime.Intepreter.ILTypeInstance} 不为空
if (obj != null)
{
// 默认 isBox = false
if (!isBox)
{
// typeFalgs = Default
var typeFlags = obj.GetType().GetTypeFlags(); // 不是 基本类型
if ((typeFlags & CLR.Utils.Extensions.TypeFlags.IsPrimitive) != )
{
UnboxObject(esp, obj, mStack);
}
// 不是 枚举
else if ((typeFlags & CLR.Utils.Extensions.TypeFlags.IsEnum) != )
{
esp->ObjectType = ObjectTypes.Integer;
esp->Value = Convert.ToInt32(obj);
}
else
{
// 栈对象里的对象的类型 是 Object
esp->ObjectType = ObjectTypes.Object;
// 栈对象里的的值是 托管对象数组的索引
esp->Value = mStack.Count;
// 将 HotFix_Project.InstanceClass: {ILRuntime.Runtime.Intepreter.ILTypeInstance} 压入托管列表
mStack.Add(obj);
}
}
else
{
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
mStack.Add(obj);
}
}
else
{
return PushNull(esp);
}
// 栈指针 + 1, esp = 起始指针 0x5b4bf030 + 12个字节 = 0x5b4bf03c
return esp + ;
//
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 : ;
// 参数数量2 = 0
int pCnt2 = p != null ? p.Length : ;
// 不匹配 抛出异常
if (pCnt != pCnt2)
throw new ArgumentOutOfRangeException("Parameter mismatch");
if (pCnt2 > )
{
for (int i = ; 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 > && 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 > ? 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 + ;
// v3 = 0x5b4bf054
StackObject* v3 = frame.LocalVarPointer + + ;
// v4 = 0x5b4bf060
StackObject* v4 = Add(frame.LocalVarPointer, );
int finallyEndAddress = ;
// 栈指针指向 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 = ; 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 = ; i < method.LocalVariableCount; i++)
{
mStack.Add(null);
}
// LocalVariableCount=0, 没有局部变量,没进
for (int i = ; i < method.LocalVariableCount; i++)
// 值类型指针 0x5b4ef024
var bp = stack.ValueTypeStackPointer;
ValueTypeBasePointer = bp; // body: OpCode[]
// Ldarg_0, 0, 0
// Call, 0, 1
// Nop, 0, 0
// Nop, 0, 0
// Ret, 0, 0
fixed (OpCode* ptr = body)
{
OpCode* ip = ptr;
OpCodeEnum code = ip->Code;
bool returned = false;
// 读取所有的 OpCode ,直到返回
while (!returned)
{
try
{
code = ip->Code;
switch (code)
{
// 将索引为 0 的参数加载到计算堆栈上。
case OpCodeEnum.Ldarg_0:
// 将托管堆里的 HotFix_Project.InstanceClass 拷贝到 栈帧
CopyToStack(esp, arg, mStack);
// 将 0x5b4bf030 的 StackObject 的值,拷贝到 当前栈帧 指向的 StackObject* 0x5b4bf03c
// StackObject.ObjectType = ObjectType.Object 对象
// StackObject.Value = 0 对应的托管堆里的 索引
*dst = *src;
// >= 没错
if (dst->ObjectType >= ObjectTypes.Object)
{
// 栈帧指向的 非托管栈 的 值为 1
dst->Value = mStack.Count;
// 获取 被拷贝的 StackObject* 指向的 托管堆的 HotFix_Project.InstanceClass
var obj = mStack[src->Value];
// 复制这个 obj 到 托管堆
// [1] = HotFix_Project.InstanceClass
// [0] = HotFix_Project.InstanceClass
mStack.Add(obj);
}
// 栈指针++ = 0x5b4bf048
esp++;
break;
// 调用由传递的方法说明符指示的方法。
case OpCodeEnum.Call:
// 对对象调用后期绑定方法,并且将返回值推送到计算堆栈上。
case OpCodeEnum.Callvirt:
// ip->TokenInteger = 0
// 没找到ILMethod
IMethod m = domain.GetMethod(ip->TokenInteger);
if (m == null)
//Irrelevant method
// ip->TokenLong = 1
int cnt = (int)ip->TokenLong;
//Balance the stack
for (int i = ; i < cnt; i++)
{
// esp = 0x5b4bf048
// esp - 1 = 0x5b4bf03c
// 释放 esp - 1 也就是 0x5b4bf03c StackObject* 指向的 托管对象
Free(esp - );
if (esp->ObjectType >= ObjectTypes.Object)
{
// [0] = HotFix_Project.InstanceClass
// [1] = HotFix_Project.InstanceClass
var mStack = stack.ManagedStack;
// 非托管指针 指向 托管对象索引0
if (esp->Value == mStack.Count - )
// 现在
// [0] = HotFix_Project.InstanceClass
mStack.RemoveAt(esp->Value);
}
// 非托管栈 下移
// 非托管栈指针指向 0x5b4bf03c
esp--;
}
break;
// 从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
case OpCodeEnum.Ret:
returned = true;
break;
}
// IL指令索引+1
ip++
}
// esp = 0x5b4bf03c
return stack.PopFrame(ref frame, esp);
// 栈帧出栈
if (frames.Count > && frames.Peek().BasePointer == frame.BasePointer)
frames.Pop();
else
throw new NotSupportedException();
// 返回的 StackObject* 临时变量 returnVal = 0x5b4bf030 起始指针
StackObject* returnVal = esp - ;
// 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 - ), domain, mStack)) : null;
// esp = 0x5b4bf03c
// esp - 1= 0x5b4bf030
StackObject.ToObject((esp - ), 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[] { }); 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 = ; 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, );
获取泛型方法的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();
} 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 - )->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 >> ));
if type is ILType
ILType t = type as ILType;
val = esp - ;
t.StaticInstance.AssignFromStack((int)ip->TokenLong, val, AppDomain, mStack);
// fieldIndx = 0, fields.Length = 1
if (fieldIdx < fields.Length && fieldIdx >= )
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 >> ));
// 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 + )), 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 > ; 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 - );//Return value for multicast delegate doesn't make sense, only return the last one's value
}
DelegateAdapter n = (DelegateAdapter)next;
ret = n.ILInvokeSub(intp, ebp, mStack); }
return ret;
return ClearStack(intp, esp, ebp, mStack);
processed = true;
完全在热更DLL内部使用的委托
热更工程 using System;
using System.Collections.Generic; namespace HotFix_Project
{
public delegate void MyDelegate(int a); public class TestDelegate
{
static MyDelegate myDelegate; public static void Initialize()
{
myDelegate = Method;
} public static void RunTest()
{
myDelegate();
} static void Method(int a)
{
UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
} 主工程 OnHotFixLoaded()
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
// method = "HotFix_Project.TestDelegate.Initialize()"
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldnull"
// "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
// "IL_0008: newobj System.Void HotFix_Project.MyDelegate::.ctor(System.Object,System.IntPtr)"
// "IL_000d: stsfld HotFix_Project.MyDelegate HotFix_Project.TestDelegate::myDelegate"
// "IL_0012: ret"
esp = Execute(method, esp, out unhandledException);
case OpCodeEnum.Newobj:
// 获取 "HotFix_Project.MyDelegate..ctor(Object object, IntPtr method)"
IMethod m = domain.GetMethod(ip->TokenInteger);
// 热更里的委托是ILMethod
if (m is ILMethod)
// 获取委托指向的方法 "HotFix_Project.TestDelegate.Method(Int32 a)"
var mi = (IMethod)mStack[(esp - )->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 >> ));
// 是 ILType
if (type is ILType)
ILType t = type as ILType;
val = esp - ;
// 将 "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 >> ));
// 将 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 + )), domain, mStack);
if (instance is IDelegateAdapter)
esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);
var ebp = esp;
esp = [DummyDelegateAdapter].ILInvokeSub(intp, esp, mStack);
// 调用委托适配器指向的 方法
// method = "HotFix_Project.TestDelegate.Method(Int32 a)"
var ret = intp.Execute(method, esp, out unhandled);
return ClearStack(intp, esp, ebp, mStack);
热更里的工程调用热更里的委托实例(该委托类型在热更项目里声明, 该委托实例指向热更里的函数, 不需要注册适配器)2.0
using System;
using System.Collections.Generic; namespace HotFix_Project
{ public class TestDelegate
{
static TestDelegateMethod delegateMethod; public static void Initialize()
{
delegateMethod = Method;
} public static void RunTest()
{
delegateMethod();
} static void Method(int a)
{
UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
} 主工程 public static TestDelegateMethod TestMethodDelegate; OnHotFixLoaded()
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
// method = "HotFix_Project.TestDelegate.Initialize()"
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldnull"
// "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
// "IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
// "IL_000d: stsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
// "IL_0012: ret"
esp = Execute(method, esp, out unhandledException);
case OpCodeEnum.Newobj:
// 获取 TestDelegateMethod."Void .ctor(Object, IntPtr)"
IMethod m = domain.GetMethod(ip->TokenInteger);
// 主工程里的 委托构造函数 不是ILMethod, 而是 CLRMethod
if (m is not ILMethod)
// 转型为 CLRMethod
CLRMethod cm = (CLRMethod)m;
if (cm.DeclearingType.IsDelegate)
// 从栈上获取 mi = "HotFix_Project.TestDelegate.Method(Int32 a)"
var mi = (IMethod)mStack[(esp - )->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 >> ));
// 是 ILType
if (type is ILType)
ILType t = type as ILType;
val = esp - ;
// 将 "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 >> ));
// 将 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 + )), domain, mStack);
if (instance is IDelegateAdapter)
esp = ((IDelegateAdapter)instance).ILInvoke(this, esp, mStack);
var ebp = esp;
esp = [DummyDelegateAdapter].ILInvokeSub(intp, esp, mStack);
// 调用委托适配器指向的 方法
// method = "HotFix_Project.TestDelegate.Method(Int32 a)"
var ret = intp.Execute(method, esp, out unhandled);
return ClearStack(intp, esp, ebp, mStack);
热更里的工程调用热更里的委托实例(该委托类型在主工程项目里声明, 该委托实例指向热更里的函数, 不需要注册适配器)2.0
using System;
using System.Collections.Generic; namespace HotFix_Project
{ public class TestDelegate
{ public static void Initialize2()
{
DelegateDemo.TestMethodDelegate = Method;
} static void Method(int a)
{
UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
} 主工程 public static TestDelegateMethod TestMethodDelegate; OnHotFixLoaded()
// 委托适配器注册, 不注册就会提示没有找到委托适配器 Cannot find Delegate Adapter for:HotFix_Project.TestDelegate.Method(Int32 a)
appdomain.DelegateManager.RegisterMethodDelegate<int>();
DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
node.Adapter = new MethodDelegateAdapter<T1>();
node.ParameterTypes = new Type[] { typeof(T1) };
methods.Add(node);
RegisterDelegateConvertor<Action<T1>>(defaultConverter);
// type = System.Action`1[System.Int32]
var type = typeof(T);
if (type.IsSubclassOf(typeof(Delegate)))
// action = null
clrDelegates[type] = action; // 委托转换器注册, 不注册就会提示没有找到委托转换器 Cannot find convertor for global::TestDelegateMethod
appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) => {
// type = {TestDelegateMethod}
var type = typeof(T);
if (type.IsSubclassOf(typeof(Delegate)))
// action = {System.Func`2[[System.Delegate],[System.Delegate]]}
clrDelegates[type] = action; //转换器的目的是把Action或者Func转换成正确的类型,这里则是把Action<int>转换成TestDelegateMethod
return new TestDelegateMethod((a) => {
//调用委托实例
((System.Action<int>)action)(a);
});
}); appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
// method = "HotFix_Project.TestDelegate.Initialize2()"
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldnull"
// "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
// "IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
// "IL_000d: stsfld TestDelegateMethod DelegateDemo::TestMethodDelegate"
// "IL_0012: ret"
esp = Execute(method, esp, out unhandledException);
case OpCodeEnum.Newobj:
// 获取 TestDelegateMethod."Void .ctor(Object, IntPtr)"
IMethod m = domain.GetMethod(ip->TokenInteger);
// 主工程里的 委托构造函数 不是ILMethod, 而是 CLRMethod
if (m is not ILMethod)
// 转型为 CLRMethod
CLRMethod cm = (CLRMethod)m;
if (cm.DeclearingType.IsDelegate)
// 从栈上获取 mi = "HotFix_Project.TestDelegate.Method(Int32 a)"
var mi = (IMethod)mStack[(esp - )->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 >> ));
// 主工程里的类型是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 - ;
// 重新设置 TestMethodDelegate 指向 主工程的 委托适配器 而不是 热更工程里的函数
t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));
CheckCLRTypes(obj)
// typeFlags = IsDelegate
else if ((typeFlags & TypeFlags.IsDelegate) != )
// 不是 Delegate
if (obj is Delegate)
return obj;
// 另一种类型运算, 也不是
if (pt == typeof(Delegate))
return ((IDelegateAdapter)obj).Delegate;
// 获取 HotFix_Project.TestDelegate.Method(Int32 a) 的 真正的委托
return ((IDelegateAdapter)obj).GetConvertor(pt);
if (converters == null)
converters = new Dictionary<System.Type, Delegate>(new ByReferenceKeyComparer<Type>());
Delegate res;
// 没有注册,所以没有
if (converters.TryGetValue(type, out res))
return res;
else
// 将 HotFix_Project.TestDelegate.Method(Int32 a): MethodDelegateAdapter`1[System.Int32] 的 {TestDelegateMethod} 委托转换为可识别的委托
res = appdomain.DelegateManager.ConvertToDelegate(type, this);
// 如果是 DummyAdapter 直接报错, 不是
if(adapter is DummyDelegateAdapter)
DelegateAdapter.ThrowAdapterNotFound(adapter.Method);
// 注册了 直接返回那个委托
if (clrDelegates.TryGetValue(clrDelegateType, out func))
// 没有注册 {TestDelegateMethod} 对应的 Func<Delegate, Delegate> 报错
else
converters[type] = res;
return res; appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest2", null, null);
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldsfld TestDelegateMethod DelegateDemo::TestMethodDelegate"
// "IL_0006: ldc.i4.s 123"
// "IL_0008: callvirt System.Void TestDelegateMethod::Invoke(System.Int32)"
// "IL_000d: nop"
// "IL_000e: ret"
esp = Execute(method, esp, out unhandledException);
case OpCodeEnum.Ldsfld:
// 获取"DelegateDemo"
type = AppDomain.GetType((int)(ip->TokenLong >> ));
// 主工程的 是 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 + )), 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;
//
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 - ; case OpCodeEnum.Newobj:
// 注册过委托
if (match)
{
// method: "HotFix_Project.TestDelegate.Method(Int32 a)"
// Adapter: MethodDelegateAdapter<T1>
res = i.Adapter.Instantiate(appdomain, instance, method);
MethodDelegateAdapter<T1>.Instantiate
return new MethodDelegateAdapter<T1>(appdomain, instance, method);
// action: {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
action = InvokeILMethod;
using (var c = appdomain.BeginInvoke(method))
if (m is ILMethod)
{
ILIntepreter inteptreter = RequestILIntepreter();
return new InvocationContext(inteptreter, (ILMethod)m);
}
else
throw new NotSupportedException("Cannot invoke CLRMethod");
{
var ctx = c;
if (method.HasThis)
ctx.PushObject(instance);
PushParameter(ref ctx, pType, p1);
ctx.Invoke();
} if (instance != null)
instance.SetDelegateAdapter(method, res);
return res;
} // 没有注册过委托
if (((ILMethod)mi).DelegateAdapter == null)
{
((ILMethod)mi).DelegateAdapter = domain.DelegateManager.FindDelegateAdapter(null, (ILMethod)mi);
// 生成一个 dummyAdapter
res = dummyAdapter.Instantiate(appdomain, instance, method);
}
dele = ((ILMethod)mi).DelegateAdapter; t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));
CheckCLRTypes
CheckAndCloneValueType
StackObject.ToObject
case ObjectTypes.Object:
// HotFix_Project.TestDelegate.Method(Int32 a)
return mStack[esp->Value];
// HotFix_Project.TestDelegate.Method(Int32 a)
return obj;
Type.GetTypeFlags
// Default
var result = TypeFlags.Default;
// typeFlags: Dictionary<Type, TypeFlags>
// "[ILRuntime.CLR.Method.ILMethod, Default]"
// "[ILRuntime.Runtime.Intepreter.DummyDelegateAdapter, Default]"
if (!typeFlags.TryGetValue(pt, out result))
if (pt == typeof(Delegate) || pt.IsSubclassOf(typeof(Delegate)))
{ result |= TypeFlags.IsDelegate;
}
// typeFlags: Dictionary<Type, TypeFlags>
// "[ILRuntime.CLR.Method.ILMethod, Default]"
// "[ILRuntime.Runtime.Intepreter.DummyDelegateAdapter, Default]"
// "[TestDelegateMethod, IsDelegate]"
typeFlags[pt] = result;
// pt = {TestDelegateMethod}
var typeFlags = GetTypeFlags(pt);
else if ((typeFlags & TypeFlags.IsDelegate) != )
if (obj is Delegate)
return obj;
if (pt == typeof(Delegate))
return ((IDelegateAdapter)obj).Delegate;
return ((IDelegateAdapter)obj).GetConvertor(pt); if (converters == null)
converters = new Dictionary<System.Type, Delegate>(new ByReferenceKeyComparer<Type>());
Delegate res;
if (converters.TryGetValue(type, out res))
return res;
else
{ res = appdomain.DelegateManager.ConvertToDelegate(type, this);
[DelegateManager].ConvertToDelegate
// 是 DummyDelegateAdapter 抛出异常
if(adapter is DummyDelegateAdapter)
{
DelegateAdapter.ThrowAdapterNotFound(adapter.Method);
return null;
}
// 如果事先注册过了
// clrDelegates
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[TestDelegateMethod, System.Func`2[System.Delegate,System.Delegate]]"
if (clrDelegates.TryGetValue(clrDelegateType, out func))
{
return func(adapter.Delegate);
}
converters[type] = res;
return res;
}
} catch (System.Exception ex) {
Debug.LogError(ex.ToString());
}
//为了演示,清除适配器缓存,实际使用中不要这么做
ClearDelegateCache();
Debug.Log("这是因为iOS的IL2CPP模式下,不能动态生成类型,为了避免出现不可预知的问题,我们没有通过反射的方式创建委托实例,因此需要手动进行一些注册");
Debug.Log("首先需要注册委托适配器,刚刚的报错的错误提示中,有提示需要的注册代码");
//下面这些注册代码,正式使用的时候,应该写在InitializeILRuntime中
//TestDelegateMethod, 这个委托类型为有个参数为int的方法,注册仅需要注册不同的参数搭配即可
appdomain.DelegateManager.RegisterMethodDelegate<int>();
DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
node.Adapter = new MethodDelegateAdapter<T1>();
pType: static InvocationTypes = GetInvocationType<T1>();
node.ParameterTypes = new Type[] { typeof(T1) };
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
methods.Add(node);
RegisterDelegateConvertor<Action<T1>>(defaultConverter);
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
//带返回值的委托的话需要用RegisterFunctionDelegate,返回类型为最后一个
appdomain.DelegateManager.RegisterFunctionDelegate<int, string>();
DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
node.Adapter = new FunctionDelegateAdapter<T1, TResult>();
node.ParameterTypes = new Type[] { typeof(T1), typeof(TResult) };
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
functions.Add(node);
RegisterDelegateConvertor<Func<T1, TResult>>(defaultConverter);
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
//Action<string> 的参数为一个string
appdomain.DelegateManager.RegisterMethodDelegate<string>();
DelegateMapNode node = new Enviorment.DelegateManager.DelegateMapNode();
node.Adapter = new MethodDelegateAdapter<T1>();
node.ParameterTypes = new Type[] { typeof(T1) };
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
// {ILRuntime.Runtime.Enviorment.DelegateManager+DelegateMapNode}
methods.Add(node);
RegisterDelegateConvertor<Action<T1>>(defaultConverter);
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action; Debug.Log("注册完毕后再次运行会发现这次会报另外的错误");
try {
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
} catch (System.Exception ex) {
Debug.LogError(ex.ToString());
} Debug.Log("ILRuntime内部是用Action和Func这两个系统内置的委托类型来创建实例的,所以其他的委托类型都需要写转换器");
Debug.Log("将Action或者Func转换成目标委托类型"); appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) => {
// "[System.Action, System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.Int32], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Func`2[System.Int32,System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[System.Action`1[System.String], System.Func`2[System.Delegate,System.Delegate]]"
// "[TestDelegateMethod, System.Func`2[System.Delegate,System.Delegate]]"
clrDelegates[type] = action;
//转换器的目的是把Action或者Func转换成正确的类型,这里则是把Action<int>转换成TestDelegateMethod
return new TestDelegateMethod((a) => {
//调用委托实例
// {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
// Method: Void InvokeILMethod(Int32)
// Target: "HotFix_Project.TestDelegate.Method(Int32 a)"
((System.Action<int>)action)(a);
});
});
////对于TestDelegateFunction同理,只是是将Func<int, string>转换成TestDelegateFunction
//appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) => {
// return new TestDelegateFunction((a) => {
// return ((System.Func<int, string>)action)(a);
// });
//}); ////下面再举一个这个Demo中没有用到,但是UGUI经常遇到的一个委托,例如UnityAction<float>
//appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<float>>((action) => {
// return new UnityEngine.Events.UnityAction<float>((a) => {
// ((System.Action<float>)action)(a);
// });
//}); Debug.Log("现在我们再来运行一次");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest2", null, null);
//debug.log("运行成功,我们可以看见,用action或者func当作委托类型的话,可以避免写转换器,所以项目中在不必要的情况下尽量只用action和func");
//debug.log("另外应该尽量减少不必要的跨域委托调用,如果委托只在热更dll中用,是不需要进行任何注册的");
//debug.log("---------");
//debug.log("我们再来在unity主工程中调用一下刚刚的委托试试");
//testmethoddelegate(789);
//var str = testfunctiondelegate(098);
//debug.log("!! onhotfixloaded str = " + str);
//testactiondelegate("hello from unity main project");
委托流程
热更项目 namespace HotFix_Project {
public class TestDelegate {
static Action<string> delegateAction; public static void Initialize() {
delegateAction = Action;
} public static void RunTest() {
delegateAction("rrr");
}
}
} 主项目 appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldnull"
// "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Action(System.String)"
// "IL_0008: newobj System.Void System.Action`1<System.String>::.ctor(System.Object,System.IntPtr)"
// "IL_000d: stsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction"
// "IL_0012: ret"
// 自定义OpCode
// Nop, 0, 0
// Ldnull, 0, 0
// Ldftn, 1, 0
// Newobj, 2, 0
// Stsfld, 0, 12884901888
// Ret, 0, 0
esp = Execute(method, esp, out unhandledException);
case OpCodeEnum.Ldftn:
// m = "HotFix_Project.TestDelegate.Action(String a)"
IMethod m = domain.GetMethod(ip->TokenInteger);
esp = PushObject(esp, mStack, m);
case OpCodeEnum.Newobj:
// "System.Action`1[System.String] Void .ctor(Object, IntPtr)"
IMethod m = domain.GetMethod(ip->TokenInteger);
if (m is CLRMethod)
// Action<string> 当然是Delegate
if (cm.DeclearingType.IsDelegate)
// 获取托管堆上方法
// "HotFix_Project.TestDelegate.Action(String a)"
var mi = (IMethod)mStack[(esp - )->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 >> ));
if (type is ILType)
ILType t = type as ILType;
val = esp - ;
// 将 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 >> ));
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 + )), 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 > ; i--)
intp.CopyToStack(esp, Minus(ebp, i), mStack);
*dst = *src;
if (dst->ObjectType >= ObjectTypes.Object)
dst->Value = mStack.Count;
var obj = mStack[src->Value];
mStack.Add(obj);
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldstr \"!! TestDelegate.Action, a = \""
// "IL_0006: ldarg.0"
// "IL_0007: call System.String System.String::Concat(System.String,System.String)"
// "IL_000c: call System.Void UnityEngine.Debug::Log(System.Object)"
// "IL_0011: nop"
// "IL_0012: ret"
// Nop, 0, 0
// Ldstr, 0, 1342813397
// Ldarg_0, 0, 0
// Call, 4, 0
// Call, 5, 0
// Nop, 0, 0
// Ret, 0, 0
var ret = intp.Execute(method, esp, out unhandled);
case OpCodeEnum.Ldstr:
// 将 "!! TestDelegate.Action, a = " 入栈
esp = PushObject(esp, mStack, AppDomain.GetString(ip->TokenLong));
// 将"rrr" 入栈
case OpCodeEnum.Ldarg_0:
CopyToStack(esp, arg, mStack);
case OpCodeEnum.Call:
// m = "System.String Concat(System.String, System.String)"
IMethod m = domain.GetMethod(ip->TokenInteger);
if (m is CLRMethod)
// result = "!! TestDelegate.Action, a = rrr"
object result = cm.Invoke(this, esp, mStack);
case OpCodeEnum.Call:
// m = "UnityEngine.Debug Void Log(System.Object)"
IMethod m = domain.GetMethod(ip->TokenInteger);
if (m is CLRMethod)
// result = "!! TestDelegate.Action, a = rrr"
object result = cm.Invoke(this, esp, mStack);
if (m is CLRMethod)
// 调用 UnityEngine.Debug.Log("!! TestDelegate.Action, a = rrr");
object result = cm.Invoke(this, esp, mStack);
return ClearStack(intp, esp, ebp, mStack);
processed = true;
热更项目调用Action 委托
热更工程 namespace HotFix_Project { public delegate void MyTestDelegate(string a); public class TestDelegate {
static Action<string> delegateAction; public static void Initialize() {
delegateAction = Action;
delegateAction("hahaah");
} static void Action(string a) {
UnityEngine.Debug.Log(a);
}
}
} 主工程
OnHotFixLoaded() { TypeDefinition td = appdomain.typeDef["HotFix_Project.TestDelegate"]; MyType mt = new MyType(td); List<object> managedStack = new List<object>(); for (int i = ; i < ; i++) {
managedStack.Add(null);
} System.Delegate dele = null;
System.Type type = null;
MyDelegateAdapter da = null; foreach (var item in td.Methods[].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[] = 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[] as MethodDefinition);
break;
// stsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction
case Code.Stsfld:
// 将 DelegateAdapter 设置给这个字段
mt.staticField = da;
managedStack.Remove();
break;
// ldsfld System.Action`1<System.String> HotFix_Project.TestDelegate::delegateAction
case Code.Ldsfld:
MyDelegateAdapter da1 = (mt.staticField as MyDelegateAdapter);
managedStack[] = da1;
break;
// ldstr "hahaah"
case Code.Ldstr:
managedStack[] = "hahaah";
break;
// callvirt System.Void System.Action`1<System.String>::Invoke(!0)
case Code.Callvirt:
MyDelegateAdapter da2 = managedStack[] as MyDelegateAdapter;
da2.Invoke();
break;
default:
break;
}
} } public class MyType {
public TypeDefinition td; public object staticField; public MyType(TypeDefinition td) {
this.td = td;
}
} public class MyDelegateAdapter {
public MethodDefinition md; public MyDelegateAdapter(MethodDefinition md) {
this.md = md;
} public void Invoke() {
foreach (var item in md.Body.Instructions) {
Debug.Log(item);
switch (item.OpCode.Code) {
// ldarg.0
case Code.Ldarg_0:
// managedStack[2] = "hahaah"
break;
// call System.Void UnityEngine.Debug::Log(System.Object)
case Code.Call:
// UnityEngine.Debug.Log(managedStack[2])
UnityEngine.Debug.Log("hahaah");
break;
}
}
}
}
委托调用流程自定义
System.Func<System.Delegate, System.Delegate> func = new System.Func<System.Delegate, System.Delegate>((dele) => {
Debug.Log(dele.GetType()); return dele;
}); System.Action ac = () => {
Debug.Log("Action");
}; ((System.Action)func(ac))();
System.Func<System.Delegate, System.Delegate>
主工程 // 主工程要被继承的类
public abstract class TestClassBase
{
public virtual int Value
{
get
{
return ;
}
} public virtual void TestVirtual(string str)
{
Debug.Log("!! TestClassBase.TestVirtual, str = " + str);
} public abstract void TestAbstract(int gg);
} //
public class InheritanceAdapter : CrossBindingAdaptor
{
public override Type BaseCLRType
{
get
{
// 获取 TestClassBase的 type
return typeof(TestClassBase);//这是你想继承的那个类
}
} public override Type AdaptorType
{
get
{
// 获取 InheritanceAdapter.Adaptor 嵌套类 的 type
return typeof(Adaptor);//这是实际的适配器类
}
} // new 一个 InheritanceAdapter.Adaptor
public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
{
return new Adaptor(appdomain, instance);//创建一个新的实例
} //实际的适配器类需要继承你想继承的那个类,并且实现CrossBindingAdaptorType接口
class Adaptor : TestClassBase, CrossBindingAdaptorType
{
ILTypeInstance instance;
ILRuntime.Runtime.Enviorment.AppDomain appdomain; // 对应 TestClassBase.TestAbstract
IMethod mTestAbstract;
bool mTestAbstractGot; // 对应 TestClassBase.TestVirtual
IMethod mTestVirtual;
bool mTestVirtualGot;
bool isTestVirtualInvoking = false; // 对应 TestClassBase.Value
IMethod mGetValue;
bool mGetValueGot;
bool isGetValueInvoking = false; //缓存这个数组来避免调用时的GC Alloc
object[] param1 = new object[]; 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", );
mTestAbstractGot = true;
}
if (mTestAbstract != null)
{
param1[] = 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", );
mTestVirtualGot = true;
}
//对于虚函数而言,必须设定一个标识位来确定是否当前已经在调用中,否则如果脚本类中调用base.TestVirtual()就会造成无限循环,最终导致爆栈
if (mTestVirtual != null && !isTestVirtualInvoking)
{
isTestVirtualInvoking = true;
param1[] = str;
appdomain.Invoke(mTestVirtual, instance, param1);
isTestVirtualInvoking = false;
}
else
base.TestVirtual(str);
} public override int Value
{
get
{
if (!mGetValueGot)
{
//属性的Getter编译后会以get_XXX存在,如果不确定的话可以打开Reflector等反编译软件看一下函数名称
mGetValue = instance.Type.GetMethod("get_Value", );
mGetValueGot = true;
}
//对于虚函数而言,必须设定一个标识位来确定是否当前已经在调用中,否则如果脚本类中调用base.Value就会造成无限循环,最终导致爆栈
if (mGetValue != null && !isGetValueInvoking)
{
isGetValueInvoking = true;
var res = (int)appdomain.Invoke(mGetValue, instance, null);
isGetValueInvoking = false;
return res;
}
else
return base.Value;
}
} public override string ToString()
{
IMethod m = appdomain.ObjectType.GetMethod("ToString", );
m = instance.Type.GetVirtualMethod(m);
if (m == null || m is ILMethod)
{
return instance.ToString();
}
else
return instance.Type.FullName;
}
}
} Debug.Log("首先我们来创建热更里的类实例");
TestClassBase obj;
try
{
obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
// type: "HotFix_Project.TestInheritance"
ILTypeInstance ins = Instantiate(type, args);
//
var res = ilType.Instantiate(!hasConstructor);
var res = new ILTypeInstance(this);
fields = new StackObject[type.TotalFieldCount];
ILType.InitializeBaseType
// definition.BaseType = "TestClassBase"
baseType = appdomain.GetType(definition.BaseType, this, null);
// 不是
if (baseType.TypeForCLR == typeof(Enum) || baseType.TypeForCLR == typeof(object) || baseType.TypeForCLR == typeof(ValueType) || baseType.TypeForCLR == typeof(System.Enum))
// 不是
else if (baseType.TypeForCLR == typeof(MulticastDelegate))
// 找 CrossBindingAdaptor
CrossBindingAdaptor adaptor;
if (appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR, out adaptor))
{
baseType = adaptor;
}
// 没注册就找不到
else
throw new TypeLoadException("Cannot find Adaptor for:" + baseType.TypeForCLR.ToString());
return (T)ins.CLRInstance;
}
catch(System.Exception ex)
{
Debug.LogError(ex.ToString());
}
Debug.Log("Oops, 报错了,因为跨域继承必须要注册适配器。 如果是热更DLL里面继承热更里面的类型,不需要任何注册。"); Debug.Log("所以现在我们来注册适配器");
appdomain.RegisterCrossBindingAdaptor(new InheritanceAdapter());
var bType = adaptor.BaseCLRType;
// 自己写的
return typeof(TestClassBase)
var t = adaptor.AdaptorType;
// 自己写的 {InheritanceAdapter+Adaptor}
return typeof(Adaptor)
var res = GetType(t);
IType res;
// 没有 {InheritanceAdapter+Adaptor} 这个类型
if (clrTypeMapping.TryGetValue(t, out res))
return res;
else
// "InheritanceAdapter+Adaptor, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
return GetType(t.AssemblyQualifiedName);
// 没有这个类型
if (!clrTypeMapping.TryGetValue(t, out res))
// new 一个 CLRType
res = new CLRType(t, this);
clrTypeMapping[t] = res;
// {InheritanceAdapter}.RuntimeType = "InheritanceAdapter+Adaptor" 嵌套类
adaptor.RuntimeType = res;
// "[TestClassBase, InheritanceAdapter]"
crossAdaptors[bType] = adaptor;
Debug.Log("现在再来尝试创建一个实例");
obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
// type: "HotFix_Project.TestInheritance"
ILTypeInstance ins = Instantiate(type, args);
// 根据 "HotFix_Project.TestInheritance" 查找 HotFix_Project.TestInheritance: IType
if (mapType.TryGetValue(type, out t))
// HotFix_Project.TestInheritance: ILType
var res = ilType.Instantiate(!hasConstructor);
var res = new ILTypeInstance(this);
fields = new StackObject[type.TotalFieldCount];
InitializeBaseType
// definition.BaseType = HotFix_Project.TestInheritance."TestClassBase" Module null
baseType = appdomain.GetType(definition.BaseType, this, null);
// hash = 1, 没找到
if (mapTypeToken.TryGetValue(hash, out res))
// token = TestClassBase, 不是 TypeDefinition
if (token is Mono.Cecil.TypeDefinition)
// token 是 TypeReference
// Module "HotFix_Project.dll"
// Scope "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
else if (token is Mono.Cecil.TypeReference)
// 获取 scope
scope = GetAssemblyName(_ref.Scope);
// 获取引用程序集
return scope is AssemblyNameReference ? ((AssemblyNameReference)scope).FullName : null;
// 通过 Type.GetType 获取 类型
Type t = Type.GetType(fullname);
// clrTypeMapping 没有找到 TestClassBase
if (!clrTypeMapping.TryGetValue(t, out res))
// new 一个 CLRType
res = new CLRType(t, this);
// 是 CLRType
if (baseType is CLRType)
// 不是
if (baseType.TypeForCLR == typeof(Enum) || baseType.TypeForCLR == typeof(object) || baseType.TypeForCLR == typeof(ValueType) || baseType.TypeForCLR == typeof(System.Enum))
// 不是
else if (baseType.TypeForCLR == typeof(MulticastDelegate))
else
// 以上都不是,根据 TestClassBase: Type 查找 adapter
if (appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR, out adaptor))
// 现在 baseType 是 {InheritanceAdapter}
baseType = adaptor;
var curBase = baseType; var curBase = baseType;
// 不是 ILType
while (curBase is ILType)
{
curBase = curBase.BaseType;
}
// type.FirstCLRBaseType = HotFix_Project.TestInheritance.InheritanceAdapter 是 CrossBindingAdaptor
if (type.FirstCLRBaseType is Enviorment.CrossBindingAdaptor)
// {InheritanceAdapter}.CreateCLRInstance
clrInstance = ((Enviorment.CrossBindingAdaptor)type.FirstCLRBaseType).CreateCLRInstance(type.AppDomain, this);
// new InheritanceAdapter+Adaptor
return new Adaptor(appdomain, instance);//创建一个新的实例
// 获取 HotFix_Project.TestInheritance 的构造函数
var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
// m: HotFix_Project.TestInheritance..ctor()
appdomain.Invoke(m, res, null);
res = inteptreter.Run((ILMethod)m, instance, p);
// Ldarg_0, 0, 0
// Call, 536870913, 0
// Nop, 0, 0
// Ret, 0, 0
esp = Execute(method, esp, out unhandledException);
case OpCodeEnum.Ldarg_0:
// 将 HotFix_Project.TestInheritance 压栈
CopyToStack(esp, arg, mStack);
case OpCodeEnum.Call:
// 通过 StackObject.TokenInteger 获取 HotFix_Project.TestInheritance.ctor()
IMethod m = domain.GetMethod(ip->TokenInteger);
// 转换成 CLRMethod
CLRMethod cm = (CLRMethod)m;
cm.Invoke
return (T)ins.CLRInstance;
Debug.Log("现在来调用成员方法");
obj.TestAbstract();
if (!mTestAbstractGot)
{
// instance: "HotFix_Project.TestInheritance"
// 获取实际执行的热更里面的代码
mTestAbstract = instance.Type.GetMethod("TestAbstract", );
// 获取到了 这个方法
mTestAbstractGot = true;
}
if (mTestAbstract != null)
{
param1[] = 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();
obj.TestVirtual("Foobar"); 热更工程 namespace HotFix_Project {
//一定要特别注意,:后面只允许有1个Unity主工程的类或者接口,但是可以有随便多少个热更DLL中的接口
public class TestInheritance : TestClassBase {
public override void TestAbstract(int gg) {
UnityEngine.Debug.Log("!! TestInheritance.TestAbstract gg =" + gg);
} public override void TestVirtual(string str) {
base.TestVirtual(str);
UnityEngine.Debug.Log("!! TestInheritance.TestVirtual str =" + str);
} public static TestInheritance NewObject() {
return new HotFix_Project.TestInheritance();
}
}
}
Inheritance
热更项目 using System;
using System.Collections.Generic; namespace HotFix_Project {
//一定要特别注意,:后面只允许有1个Unity主工程的类或者接口,但是可以有随便多少个热更DLL中的接口
public class TestInheritance : TestClassBase {
public override void TestAbstract(int gg) {
UnityEngine.Debug.Log("!! TestInheritance.TestAbstract gg =" + gg);
} public override void TestVirtual(string str) {
base.TestVirtual(str);
UnityEngine.Debug.Log("!! TestInheritance.TestVirtual str =" + str);
} public static TestInheritance NewObject() {
return new HotFix_Project.TestInheritance();
}
}
} 主项目 热更项目里的 TestInheritance 构造函数 IL 指令
System.Void HotFix_Project.TestInheritance::.ctor()
IL_0000: ldarg.
// 这里并不能调用到
IL_0001: call System.Void TestClassBase::.ctor()
IL_0006: nop
IL_0007: ret Debug.Log("首先我们来创建热更里的类实例");
TestClassBase obj;
try
{
obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
// type = "HotFix_Project.TestInheritance"
ILTypeInstance ins = Instantiate(type, args);
// 有找到
if (mapType.TryGetValue(type, out t))
var res = ilType.Instantiate(!hasConstructor);
// new 一个ILTypeInstance
var res = new ILTypeInstance(this);
this.type = type;
fields = new StackObject[type.TotalFieldCount];
get
if (totalFieldCnt < )
if (fieldMapping == null)
// 初始化字段
InitializeFields();
int idx = FieldStartIndex;
get
if (fieldStartIdx < )
// 获取 HotFix_Project.TestInheritance的BaseType
if (BaseType != null)
// baseType 没有初始化
if (!baseTypeInitialized)
// 初始化 BaseType
InitializeBaseType();
// 不为空
if (definition != null && definition.BaseType != null)
// 获取 baseType
baseType = appdomain.GetType(definition.BaseType, this, null);
// TestClassBase 是 TypeReference
// Module = "HotFix_Project.dll"
// Scope = "Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
else if (token is Mono.Cecil.TypeReference)
// typename = "TestClassBase"
res = GetType(typename);
// TestClassBase 是主工程的类型,所以可以使用 System.Type.GetType
Type t = Type.GetType(fullname);
// 查找 CLRTypeMapping
if (!clrTypeMapping.TryGetValue(t, out res))
// 根据 System.Type 构造一个 CLRType
res = new CLRType(t, this);
clrTypeMapping[t] = res; // TestClassBase 是 CLRType
if (baseType is CLRType) {
// 不是基本类型, 也不是 委托, 查找 适配器
// 没有注册适配器, 报错
CrossBindingAdaptor adaptor;
if (appdomain.CrossBindingAdaptors.TryGetValue(baseType.TypeForCLR, out adaptor))
{
baseType = adaptor;
}
else
throw new TypeLoadException("Cannot find Adaptor for:" + baseType.TypeForCLR.ToString());
}
return (T)ins.CLRInstance;
}
catch(System.Exception ex)
{
Debug.LogError(ex.ToString());
}
Debug.Log("Oops, 报错了,因为跨域继承必须要注册适配器。 如果是热更DLL里面继承热更里面的类型,不需要任何注册。"); Debug.Log("所以现在我们来注册适配器");
appdomain.RegisterCrossBindingAdaptor(new InheritanceAdapter());
new InheritanceAdapter()
public class InheritanceAdapter : CrossBindingAdaptor
{
public override Type BaseCLRType
{
get
{
// 手动设置 HotFix_Project.TestInheritance 基类类型为 TestClassBase
return typeof(TestClassBase);//这是你想继承的那个类
}
} public override Type AdaptorType
{
get
{
// 手动设置 HotFix_Project.TestInheritance 相关的 适配器类型为 InheritanceAdapter.Adaptor
return typeof(Adaptor);//这是实际的适配器类
}
} public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance)
{
// 类型为 InheritanceAdapter.Adaptor
return new Adaptor(appdomain, instance);//创建一个新的实例
} //实际的适配器类需要继承你想继承的那个类,并且实现CrossBindingAdaptorType接口
class Adaptor : TestClassBase, CrossBindingAdaptorType
{
// 根据 HotFix_Project.TestInheritance 生成的 ILTypeInstance
ILTypeInstance instance;
ILRuntime.Runtime.Enviorment.AppDomain appdomain; // 对应 TestClassBase.TestAbstract
IMethod mTestAbstract;
bool mTestAbstractGot; // 对应 TestClassBase.TestVirtual
IMethod mTestVirtual;
bool mTestVirtualGot;
bool isTestVirtualInvoking = false; // 对应 TestClassBase.Value
IMethod mGetValue;
bool mGetValueGot;
bool isGetValueInvoking = false; //缓存这个数组来避免调用时的GC Alloc
object[] param1 = new object[]; 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", );
mTestAbstractGot = true;
}
if (mTestAbstract != null)
{
param1[] = 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", );
mTestVirtualGot = true;
}
//对于虚函数而言,必须设定一个标识位来确定是否当前已经在调用中,否则如果脚本类中调用base.TestVirtual()就会造成无限循环,最终导致爆栈
if (mTestVirtual != null && !isTestVirtualInvoking)
{
isTestVirtualInvoking = true;
param1[] = str;
appdomain.Invoke(mTestVirtual, instance, param1);
isTestVirtualInvoking = false;
}
else
base.TestVirtual(str);
} public override int Value
{
get
{
if (!mGetValueGot)
{
//属性的Getter编译后会以get_XXX存在,如果不确定的话可以打开Reflector等反编译软件看一下函数名称
mGetValue = instance.Type.GetMethod("get_Value", );
mGetValueGot = true;
}
//对于虚函数而言,必须设定一个标识位来确定是否当前已经在调用中,否则如果脚本类中调用base.Value就会造成无限循环,最终导致爆栈
if (mGetValue != null && !isGetValueInvoking)
{
isGetValueInvoking = true;
var res = (int)appdomain.Invoke(mGetValue, instance, null);
isGetValueInvoking = false;
return res;
}
else
return base.Value;
}
} public override string ToString()
{
IMethod m = appdomain.ObjectType.GetMethod("ToString", );
m = instance.Type.GetVirtualMethod(m);
if (m == null || m is ILMethod)
{
return instance.ToString();
}
else
return instance.Type.FullName;
}
}
} RegisterCrossBindingAdaptor()
// 自己写的 typeof(TestClassBase)
var bType = adaptor.BaseCLRType;
if (bType != null)
{
// 目前没有
if (!crossAdaptors.ContainsKey(bType))
{
// 自己写的 typeof(Adaptor) = InheritanceAdapter+Adaptor
var t = adaptor.AdaptorType;
var res = GetType(t);
IType res;
// 目前没有
if (clrTypeMapping.TryGetValue(t, out res))
return res;
else
// "InheritanceAdapter+Adaptor, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
return GetType(t.AssemblyQualifiedName);
// 目前没有
if (mapType.TryGetValue(fullname, out res))
return res;
// 通过 System.Type.GetType 获取类型
Type t = Type.GetType(fullname);
// 目前没有
if (!clrTypeMapping.TryGetValue(t, out res))
{
// 通过 InheritanceAdapter+Adaptor 实例化 CLRType
res = new CLRType(t, this);
clrTypeMapping[t] = res;
}
// 各种存
mapType[fullname] = res;
mapType[res.FullName] = res;
mapType[t.AssemblyQualifiedName] = res;
mapTypeToken[res.GetHashCode()] = res; if (res == null)
{
res = new CLRType(t, this);
mapType[res.FullName] = res;
mapType[t.AssemblyQualifiedName] = res;
clrTypeMapping[t] = res;
}
// InheritanceAdapter 的 运行时 类型 为 InheritanceAdapter+Adaptor: CLRType
adaptor.RuntimeType = res;
// TestClassBase 的 适配器类型为 InheritanceAdapter
crossAdaptors[bType] = adaptor;
}
else
throw new Exception("Crossbinding Adapter for " + bType.FullName + " is already added.");
}
else
{
var bTypes = adaptor.BaseCLRTypes;
var t = adaptor.AdaptorType;
var res = GetType(t);
if (res == null)
{
res = new CLRType(t, this);
mapType[res.FullName] = res;
mapType[t.AssemblyQualifiedName] = res;
clrTypeMapping[t] = res;
}
adaptor.RuntimeType = res; foreach (var i in bTypes)
{
if (!crossAdaptors.ContainsKey(i))
{
crossAdaptors[i] = adaptor;
}
else
throw new Exception("Crossbinding Adapter for " + i.FullName + " is already added.");
}
} Debug.Log("现在再来尝试创建一个实例");
obj = appdomain.Instantiate<TestClassBase>("HotFix_Project.TestInheritance");
// 通过 "HotFix_Project.TestInheritance" 实例化一个 ILTypeInstance
ILTypeInstance ins = Instantiate(type, args);
var res = ilType.Instantiate(!hasConstructor);
var res = new ILTypeInstance(this);
[ILType].TotalFieldCount
[ILType].InitializeFields
[ILType].FieldStartIndex
[ILType].BaseType
[ILType].InitializeBaseType
// definition: MethodDefinition = "HotFix_Project.TestInheritance"
// definition.BaseType = "TestClassBase"
// 通过 TestClassBase: TypeReference 的hashcode 在 mapTypeToken 里 查找到 InheritanceAdapter
baseType = appdomain.GetType(definition.BaseType, this, null);
// InheritanceAdapter 是 CLRType
if (baseType is CLRType)
// baseType.TypeForCLR = {InheritanceAdapter+Adaptor}
// 不是下列类型
if (baseType.TypeForCLR == typeof(Enum) || baseType.TypeForCLR == typeof(object) || baseType.TypeForCLR == typeof(ValueType) || baseType.TypeForCLR == typeof(System.Enum))
// 不是 MulticastDelegate
else if (baseType.TypeForCLR == typeof(MulticastDelegate))
// 查找 CrossBindingAdaptor
else
// adaptor = {InheritanceAdapter}
baseType = adaptor
// type.FirstCLRBaseType = {InheritanceAdapter}
if (type.FirstCLRBaseType is Enviorment.CrossBindingAdaptor)
// type = "HotFix_Project.TestInheritance"
// type.FirstCLRBaseType = {InheritanceAdapter}
// clrInstance 就是 {InheritanceAdapter+Adaptor}
clrInstance = ((Enviorment.CrossBindingAdaptor)type.FirstCLRBaseType).CreateCLRInstance(type.AppDomain, this);
return new Adaptor(appdomain, instance);//创建一个新的实例
// m = "HotFix_Project.TestInheritance..ctor()"
var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
res = inteptreter.Run((ILMethod)m, instance, p);
if (method.HasThis)
// 入栈 {ILRuntime.Runtime.Intepreter.ILTypeInstance}
esp = PushObject(esp, mStack, instance);
// 参数方法 入栈
esp = PushParameters(method, esp, p);
// 执行方法 "HotFix_Project.TestInheritance..ctor()"
esp = Execute(method, esp, out unhandledException);
// body
// Ldarg_0, 0, 0
// Call 536870913,0
// Nop, 0, 0
// Ret, 0, 0
OpCode[] body = method.Body;
// 初始化 method.Body
InitCodeBody();
// 局部变量数量
localVarCnt = def.Body.Variables.Count;
body = new OpCode[def.Body.Instructions.Count];
Dictionary<Mono.Cecil.Cil.Instruction, int> addr = new Dictionary<Mono.Cecil.Cil.Instruction, int>();
for (int i = ; 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 = ; i < body.Length; i++)
{
var c = def.Body.Instructions[i];
// 将IL 指令 转换为 ILRuntime 指令
// body[1] = "IL_0001: call System.Void TestClassBase::.ctor()"
// c.Operand = "System.Void TestClassBase::.ctor()"
InitToken(ref body[i], c.Operand, addr);
case OpCodeEnum.Call:
case OpCodeEnum.Newobj:
case OpCodeEnum.Ldftn:
case OpCodeEnum.Ldvirtftn
case OpCodeEnum.Callvirt:
bool invalidToken;
// token = "System.Void TestClassBase::.ctor()"
// declaringType = "HotFix_Project.TestInheritance"
// this = "HotFix_Project.TestInheritance::.ctor()"
var m = appdomain.GetMethod(token, declaringType, this, out invalidToken);
// 目前没有
if (mapMethod.TryGetValue(hashCode, out method))
// 是 MethodReference
if (token is Mono.Cecil.MethodReference)
// ".ctor"
methodname = _ref.Name;
// typeDef: MethodReference = "TestClassBase"
var typeDef = _ref.DeclaringType;
// type = "TestClassBase"
type = GetType(typeDef, contextType, contextMethod); if (isConstructor)
// type = TestClassBase
// 获取 TestClassBase 的构造函数
method = type.GetConstructor(paramList);
// 初始化 TestClassBase 的方法
InitializeMethods(); // TestClassBase 没有构造函数
if (method == null)
// contextType = "HotFix_Project.TestInheritance"
// contextType.BaseType = {InheritanceAdapter}
method = contextType.BaseType.GetConstructor(paramList);
// 初始化 InheritanceAdapter 的方法
InitializeMethods
// 获取 "InheritanceAdapter+Adaptor" 的 构造函数
foreach (var i in clrType.GetConstructors())
{
// this = "InheritanceAdapter+Adaptor"
constructors.Add(new CLRMethod(i, this, appdomain));
}
// 536870913 = "InheritanceAdapter+Adaptor".ctor
mapMethod[method.GetHashCode()] = method; if (m != null)
{
if (invalidToken)
// m.GetHashCode() = 536870913
code.TokenInteger = m.GetHashCode();
else
code.TokenInteger = token.GetHashCode();
}
else
{
//Cannot find method or the method is dummy
MethodReference _ref = (MethodReference)token;
int paramCnt = _ref.HasParameters ? _ref.Parameters.Count : ;
if (_ref.HasThis)
paramCnt++;
code.TokenLong = paramCnt;
} if (i > && c.OpCode.Code == Mono.Cecil.Cil.Code.Callvirt && def.Body.Instructions[i - ].OpCode.Code == Mono.Cecil.Cil.Code.Constrained)
{
body[i - ].TokenLong = body[i].TokenInteger;
}
} for (int i = ; 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] - ;
e.TryStart = addr[eh.TryStart];
e.TryEnd = addr[eh.TryEnd] - ;
switch (eh.HandlerType)
{
case Mono.Cecil.Cil.ExceptionHandlerType.Catch:
e.CatchType = appdomain.GetType(eh.CatchType, declaringType, this);
e.HandlerType = ExceptionHandlerType.Catch;
break;
case Mono.Cecil.Cil.ExceptionHandlerType.Finally:
e.HandlerType = ExceptionHandlerType.Finally;
break;
case Mono.Cecil.Cil.ExceptionHandlerType.Fault:
e.HandlerType = ExceptionHandlerType.Fault;
break;
default:
throw new NotImplementedException();
}
exceptionHandler[i] = e;
//Mono.Cecil.Cil.ExceptionHandlerType.
}
//Release Method body to save memory
variables = def.Body.Variables;
def.Body = null;
}
else
body = new OpCode[];
case OpCodeEnum.Callvirt:
// TokenInteger = 536870913
// 通过 536870913 获取 方法
// m = "InheritanceAdapter+Adaptor" "Void .ctor()"
IMethod m = domain.GetMethod(ip->TokenInteger);
if (mapMethod.TryGetValue(tokenHash, out res))
// 不是ILMethod
if (m is ILMethod)
// 当然是 CLRMethod
else
CLRMethod cm = (CLRMethod)m;
// 调用 InheritanceAdapter+Adaptor 的构造函数
object result = cm.Invoke(this, esp, mStack);
// 是构造函数
if (isConstructor)
// cDef: ConstructorInfo 不是静态
if (!cDef.IsStatic)
// declaringType: CLRType = "InheritanceAdapter+Adaptor"
// declaringType.TypeForCLR: Type = {InheritanceAdapter+Adaptor}
object instance = declaringType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((Minus(esp, paramCount + )), 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 == )//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();
if (!mTestAbstractGot)
{
// instance: ILTypeInstance = "HotFix_Project.TestInheritance"
// instance.Type: ILType = "HotFix_Project.TestInheritance"
// 获取 热更里 HotFix_Project.TestInheritance 的 TestAbstract 方法
mTestAbstract = instance.Type.GetMethod("TestAbstract", );
mTestAbstractGot = true;
}
if (mTestAbstract != null)
{
param1[] = 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();
obj.TestVirtual("Foobar");
Inheritance, CrossBindingAdaptor 2.0
热更项目 amespace HotFix_Project {
public class HelloWorldWithInheritanceAdapter: MyClassBase { public HelloWorldWithInheritanceAdapter() {
Debug.Log("Inheritance.Constructor");
} public override void TestMethod() {
Debug.Log("Inheritance.TestMethod");
}
}
} 主项目 // 自定义 TypeInstance
public class MyTypeInstance {
public TypeDefinition def; public MyTypeInstance(TypeDefinition def) {
this.def = def;
} public void Invoke(string methodName) {
foreach (var item in def.Methods) { if (item.Name == "TestMethod") {
foreach (var i in item.Body.Instructions) {
Debug.Log(i);
}
}
}
}
} // 适配器 和 热更项目里的类 要继承的基类
public class MyClassBase {
public MyClassBase() {
Debug.Log("MyClassBase.Constructor");
} public virtual void TestMethod() {
Debug.Log("BaseMethod");
}
} // 适配器
public class MyClassBaseAdapter: MyClassBase {
public MyTypeInstance instance; public MyClassBaseAdapter() {
Debug.Log("MyClassBaseAdapter.Constructor");
} public override void TestMethod() {
instance.Invoke("TestMethod");
}
} void OnHotFixLoaded()
// 获取热更项目的类型定义
TypeDefinition type = appdomain.typeDef["HotFix_Project.HelloWorldWithInheritanceAdapter"]; // 根据 TypeDefinition 实例化 MyTypeInstance
MyTypeInstance ins = new MyTypeInstance(type); // 实际 运行的 Adaptor 的 TestMethod 方法
MyClassBaseAdapter adapter = new MyClassBaseAdapter();
adapter.instance = ins; // 适配器里 运行 MyTypeInstance 即热更项目里 的 TestMethod 方法
adapter.TestMethod();
热更工程继承主工程, 使用适配器的 流程2.0. 简化处理, 方便理解
热更工程
using System;
using System.Collections.Generic; namespace HotFix_Project {
public class TestCLRRedirection {
public static void RunTest() {
UnityEngine.Debug.Log("看看这行的详细Log信息");
}
}
} 没有重定向 调用 object result = cm.Invoke(this, esp, mStack); 看看这行的详细Log信息
System.Reflection.MethodBase:Invoke(Object, Object[])
ILRuntime.CLR.Method.CLRMethod:Invoke(ILIntepreter, StackObject*, IList`, Boolean) (at Assets/ILRuntime/CLR/Method/CLRMethod.cs:)
ILRuntime.Runtime.Intepreter.ILIntepreter:Execute(ILMethod, StackObject*, Boolean&) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:)
ILRuntime.Runtime.Intepreter.ILIntepreter:Run(ILMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(IMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(String, String, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:)
CLRRedirectionDemo:OnHotFixLoaded() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:)
<LoadHotFixAssembly>d__4:MoveNext() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:)
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); 看看这行的详细Log信息
at HotFix_Project.TestCLRRedirection.RunTest() UnityEngine.Debug:Log(Object)
CLRRedirectionDemo:Log_11(ILIntepreter, StackObject*, IList`, CLRMethod, Boolean) (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:)
ILRuntime.Runtime.Intepreter.ILIntepreter:Execute(ILMethod, StackObject*, Boolean&) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:)
ILRuntime.Runtime.Intepreter.ILIntepreter:Run(ILMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Intepreter/ILIntepreter.cs:)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(IMethod, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:)
ILRuntime.Runtime.Enviorment.AppDomain:Invoke(String, String, Object, Object[]) (at Assets/ILRuntime/Runtime/Enviorment/AppDomain.cs:)
CLRRedirectionDemo:OnHotFixLoaded() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:)
<LoadHotFixAssembly>d__4:MoveNext() (at Assets/Scripts/Examples/05_CLRRedirection/CLRRedirectionDemo.cs:)
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, );
//取Log方法的参数,如果有两个参数的话,第一个参数是esp - 2,第二个参数是esp -1, 因为Mono的bug,直接-2值会错误,所以要调用ILIntepreter.Minus
// ptr_of_this_method = 0x5d1b2010
ptr_of_this_method = ILIntepreter.Minus(__esp, ); //这里是将栈指针上的值转换成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[].Address != null)
{
ins = frames[].Method.Definition.Body.Instructions[frames[].Address.Value];
sb.AppendLine(ins.ToString());
}
for (int i = ; i < frames.Length; i++)
{
// 获取 StackFrame
var f = frames[i];
// 获取 Method = "HotFix_Project.TestCLRRedirection.RunTest()"
m = f.Method;
string document = "";
if (f.Address != null)
{
ins = m.Definition.Body.Instructions[f.Address.Value]; var seq = FindSequencePoint(ins, m.Definition.DebugInformation.GetSequencePointMapping());
if (seq != null)
{
document = string.Format("{0}:Line {1}", seq.Document.Url, seq.StartLine);
}
}
// "at HotFix_Project.TestCLRRedirection.RunTest() \r\n"
sb.AppendFormat("at {0} {1}\r\n", m, document);
} return sb.ToString(); //我们在输出信息后面加上DLL堆栈
UnityEngine.Debug.Log(message + "\n" + stacktrace);
CLRRedirection
热更工程 using System;
using System.Collections.Generic; namespace HotFix_Project {
public class TestCLRRedirection {
public static void RunTest() {
UnityEngine.Debug.Log("看看这行的详细Log信息");
}
}
} 主工程 // 获取 Debug.Log 的 MethodBase
var mi = typeof(Debug).GetMethod("Log", new System.Type[] { typeof(object) });
// 将对 Debug.Log 的调用 重定向到 Log_11中
appdomain.RegisterCLRMethodRedirection(mi, Log_11);
//这个只是为了演示加的,平时不要这么用,直接在InitializeILRuntime方法里面写CLR重定向注册就行了
Debug.Log("我们再来调用一次刚刚的方法,注意看下一行日志的变化");
appdomain.Invoke("HotFix_Project.TestCLRRedirection", "RunTest", null, null); // m = HotFix_Project.TestCLRRedirection
// instance = null
inteptreter.Run((ILMethod)m, instance, p);
// esp: StackObject*
esp = Execute(method, esp, out unhandledException);
// 如果这个方法的 重定向方法 不为空
if (method.Redirection != null)
// 调用这个 重定向方法
// esp: StackObject* = 0xa68cb04c
// esp-> ObjectType = Null
// esp-> Value = 10
// esp-> ValueLow = 1
// mStack = [ "看看这行的详细Log信息" ]
esp = redirect(this, esp, mStack, cm, false); //ILRuntime的调用约定为被调用者清理堆栈,因此执行这个函数后需要将参数从堆栈清理干净,并把返回值放在栈顶,具体请看ILRuntime实现原理文档
ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain; //这个是最后方法返回后esp栈指针的值,应该返回清理完参数并指向返回值,这里是只需要返回清理完参数的值即可
// __ret: StackObject* = 0xa68cb040
// __ret-> ObjectType = Object
// __ret-> Value = 0
// __ret-> ValueLow = 1374408720
// __ret 是返回指针, 因为参数不需要了 所以将 栈 下移 1
StackObject* __ret = ILIntepreter.Minus(__esp, ); //取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, ); //这里是将栈指针上的值转换成object,如果是基础类型可直接通过ptr->Value和ptr->ValueLow访问到值,具体请看ILRuntime实现原理文档
object message = typeof(object).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
// 获取 0xa68cb040 处的 StackObject
StackObject.ToObject
switch (esp->ObjectType)
case ObjectTypes.Object:
// 根据 索引 esp->Value = 0 获取 托管堆 里的 对象 = "看看这行的详细Log信息"
return mStack[esp->Value];
// 将托管堆里的 object 转型为合适的类型
Type.CheckCLRTypes //所有非基础类型都得调用Free来释放托管堆栈
__intp.Free(ptr_of_this_method); //在真实调用Debug.Log前,我们先获取DLL内的堆栈
var stacktrace = __domain.DebugService.GetStackTrace(__intp); //我们在输出信息后面加上DLL堆栈
UnityEngine.Debug.Log(message + "\n" + stacktrace); return __ret;
方法重定向 2.0, 简化处理, 便于理解
热更工程 public class InstanceClass {
public InstanceClass() {
Vector3 one = Vector3.one;
}
} 主工程 OnHotFixLoaded()
// 开启或关闭 重定向
// ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain);
var type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
// 调用 无参构造函数
object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { });
// esp = 0x77064030
StackObject* esp = stack.StackBase; // 将实例本身压栈, 栈地址由低到高
esp = PushObject(esp, mStack, instance);
esp->ObjectType = ObjectTypes.Object;
// Value = 0
esp->Value = mStack.Count;
// mStack[0] = "HotFix_Project.InstanceClass": ILTypeInstance
mStack.Add(obj);
// esp = 0x7706403c
// 栈向上移动1个 StackObject*,也就是12个字节
return esp + ; // 将"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 + ; // 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 = ; 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 = ; i < cnt; i++)
{
// 释放 esp - 1 = 0x77064048 也就是 原始 esp + 2
// 移除 mStack[2]
Free(esp - );
// 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, ); // 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 + ;
} 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 +
case case OpCodeEnum.Stloc_0:
// esp = 0x77064048 = 原始 esp + 2
esp--;
int idx = locBase;
// esp = 0x77064048 = 原始 esp + 2
// v = 0x7706403c = 原始 esp + 1
// bp = 0x77094024 = 原始 esp - 1
// idx = 1
StLocSub(esp, v1, bp, idx, mStack);
// 原始指针 esp + 2 赋值 给 原始esp + 1 也就是 Vector3 one = Vector3.one;
*v = *esp;
// 指针对应的 mStack 赋值
mStack[idx] = CheckAndCloneValueType(mStack[v->Value], domain);
v->Value = idx; // 释放 esp = 0x77064048 = 原始esp + 2
Free(esp);
方法重定向2.1, 简化处理, 便于理解
CLRBinding
未开启 ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain); 3371ms 浮动
开启 ILRuntime.Runtime.Generated.CLRBindings.Initialize(appdomain); 638ms 浮动
主工程 void Update()
{
if (ilruntimeReady && !executed && Time.realtimeSinceStartup > )
{
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", );
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); #
// 绑定了
// 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, );
// 参数 b
ptr_of_this_method = ILIntepreter.Minus(__esp, );
System.Single @b = *(float*)&ptr_of_this_method->Value;
// 参数 a
ptr_of_this_method = ILIntepreter.Minus(__esp, );
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 + ; 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 = ; i < ; i++) {
CLRBindingTestClass.DoSomeTest(i, i);
}
}
}
}
CLRBinding
测试热更工程调用主工程的方法 CLR绑定就是利用的CLR重定向 热更工程 using System;
using System.Collections.Generic; namespace HotFix_Project {
public class TestCLRBinding {
public static void RunTest() {
// for (int i = 0; i < 1; i++) {
CLRBindingTestClass.DoSomeTest(, );
// }
}
}
} 主工程 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", );
appdomain.Invoke(m, null, null);
inteptreter.Run((ILMethod)m, instance, p);
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldc.i4.1"
// "IL_0002: ldc.r4 2"
// "IL_0007: call System.Single CLRBindingTestClass::DoSomeTest(System.Int32,System.Single)"
// "IL_000c: pop"
// "IL_000d: ret" // 自定义IL, 不管有没有使用重定向
// Nop, 0, 0
// Ldc_I4_1, 0, 0
// Ldc_R4, 1073741824, 0
// Call, 1, 0
// Pop, 0, 0
// Ret, 0, 0
esp = Execute(method, esp, out unhandledException);
// 重定向为空
if (redirect == null)
object result = cm.Invoke(this, esp, mStack);
// 根据热更工程的元数据调用
// def: MethodInfo = "Single DoSomeTest(Int32, Single)"
res = def.Invoke(instance, param);
// 重定向不为空
else
// 直接调用 redirect 方法
esp = redirect(this, esp, mStack, cm, false);
//
CLRBindingTestClass_Binding.DoSomeTest_0(ILIntepreter __intp, StackObject* __esp, IList<object> __mStack, CLRMethod __method, bool isNewObj)
ILRuntime.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
StackObject* ptr_of_this_method;
StackObject* __ret = ILIntepreter.Minus(__esp, ); // 第2个参数
ptr_of_this_method = ILIntepreter.Minus(__esp, );
System.Single @b = *(float*)&ptr_of_this_method->Value; // 第1个参数
ptr_of_this_method = ILIntepreter.Minus(__esp, );
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 + ;
CLRBinding 2.0, 便于理解, 简化处理
主工程 using System.Collections.Generic;
using System;
using System.Collections;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.CLR.Method; public class CoroutineAdapter: CrossBindingAdaptor { public override Type BaseCLRType {
get {
return null;
}
} public override Type[] BaseCLRTypes {
get {
//跨域继承只能有1个Adapter,因此应该尽量避免一个类同时实现多个外部接口,对于coroutine来说是IEnumerator<object>,IEnumerator和IDisposable,
//ILRuntime虽然支持,但是一定要小心这种用法,使用不当很容易造成不可预期的问题
//日常开发如果需要实现多个DLL外部接口,请在Unity这边先做一个基类实现那些个接口,然后继承那个基类
return new Type[] { typeof(IEnumerator<object>), typeof(IEnumerator), typeof(IDisposable) };
}
} public override Type AdaptorType {
get {
return typeof(Adaptor);
}
} public override object CreateCLRInstance(ILRuntime.Runtime.Enviorment.AppDomain appdomain,ILTypeInstance instance) {
return new Adaptor(appdomain, instance);
} // Coroutine生成的类实现了IEnumerator<System.Object>, IEnumerator, IDisposable,所以都要实现,这个可以通过reflector之类的IL反编译软件得知
internal class Adaptor: IEnumerator<System.Object>, IEnumerator, IDisposable, CrossBindingAdaptorType {
ILTypeInstance instance;
ILRuntime.Runtime.Enviorment.AppDomain appdomain; public Adaptor() { } public Adaptor(ILRuntime.Runtime.Enviorment.AppDomain appdomain, ILTypeInstance instance) {
this.appdomain = appdomain;
this.instance = instance;
} public ILTypeInstance ILInstance { get { return instance; } } IMethod mCurrentMethod;
bool mCurrentMethodGot;
public object Current {
get {
if (!mCurrentMethodGot) {
mCurrentMethod = instance.Type.GetMethod("get_Current", );
if (mCurrentMethod == null) {
//这里写System.Collections.IEnumerator.get_Current而不是直接get_Current是因为coroutine生成的类是显式实现这个接口的,通过Reflector等反编译软件可得知
//为了兼容其他只实现了单一Current属性的,所以上面先直接取了get_Current
mCurrentMethod = instance.Type.GetMethod("System.Collections.IEnumerator.get_Current", );
}
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", );
if (mDisposeMethod == null) {
mDisposeMethod = instance.Type.GetMethod("System.IDisposable.Dispose", );
}
mDisposeMethodGot = true;
} if (mDisposeMethod != null) {
appdomain.Invoke(mDisposeMethod, instance, null);
}
} IMethod mMoveNextMethod;
bool mMoveNextMethodGot;
public bool MoveNext() {
if (!mMoveNextMethodGot) {
mMoveNextMethod = instance.Type.GetMethod("MoveNext", );
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", );
mResetMethodGot = true;
} if (mResetMethod != null) {
appdomain.Invoke(mResetMethod, instance, null);
}
} public override string ToString() {
IMethod m = appdomain.ObjectType.GetMethod("ToString", );
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();
} 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();
Debug.Log("等待了3秒, t = " + Time.time);
}
}
}
Coroutine
sdsdfsfdsdfsdfsdfsdfs
热更项目 namespace HotFix_Project {
class SomeMonoBehaviour : MonoBehaviour {
void Awake() {
Debug.Log("!! SomeMonoBehaviour.Awake");
}
} public class TestMonoBehaviour {
public static void RunTest(GameObject go) {
go.AddComponent<SomeMonoBehaviour>();
}
}
} 主项目 // 注册 MonoBehaviour Adapter
appdomain.RegisterCrossBindingAdaptor(new MonoBehaviourAdapter()); // 重定向 MonoBehaviour.AddComponent 方法 到 AddComponent
SetupCLRRedirection()
var arr = typeof(GameObject).GetMethods();
foreach (var i in arr)
{
if (i.Name == "AddComponent" && i.GetGenericArguments().Length == )
{
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 - ;
//成员方法的第一个参数为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 == )
{
var type = genericArgument[];
object res;
if(type is CLRType)
{
//Unity主工程的类不需要任何特殊处理,直接调用Unity接口
res = instance.AddComponent(type.TypeForCLR);
}
else
{
// 热更DLL内的类型比较麻烦。首先我们得自己手动创建实例
// ILType 当然是 自己 new ILTypeInstance
var ilInstance = new ILTypeInstance(type as ILType, false);//手动创建实例是因为默认方式会new MonoBehaviour,这在Unity里不允许
//接下来创建Adapter实例
// 这里 实际上 添加的是 Adaptor
var clrInstance = instance.AddComponent<MonoBehaviourAdapter.Adaptor>();
//unity创建的实例并没有热更DLL里面的实例,所以需要手动赋值
clrInstance.ILInstance = ilInstance;
clrInstance.AppDomain = __domain;
//这个实例默认创建的CLRInstance不是通过AddComponent出来的有效实例,所以得手动替换
ilInstance.CLRInstance = clrInstance; res = clrInstance.ILInstance;//交给ILRuntime的实例应该为ILInstance clrInstance.Awake();//因为Unity调用这个方法时还没准备好所以这里补调一次
} // 将 res: ILTypeInstance = "HotFix_Project.SomeMonoBehaviour" 压入到托管栈,
return ILIntepreter.PushObject(ptr, __mStack, res);
// 更新 esP: StacObject* 指针
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
mStack.Add(obj);
// 非托管栈指针 向上移
return esp + ; 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[]);
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, );
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 = ;
} public InstanceClass(int id)
{
UnityEngine.Debug.Log("!!! InstanceClass::InstanceClass() id = " + id);
this.id = id;
} public int ID
{
get { return id; }
} // static method
public static void StaticFunTest()
{
UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest()");
} public static void StaticFunTest2(int a)
{
UnityEngine.Debug.Log("!!! InstanceClass.StaticFunTest2(), a=" + a);
} public static void GenericMethod<T>(T a)
{
UnityEngine.Debug.Log("!!! InstanceClass.GenericMethod(), a=" + a);
}
}
}
Reflection
热更项目 using UnityEngine; namespace HotFix_Project {
public class TestValueType {
public static void RunTest() {
Vector3 a = new Vector3(, , );
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 = ; i < method.LocalVariableCount; i++)
// v: VariableDefinition = V_0
var v = method.Variables[i];
// true && false
if (v.VariableType.IsValueType && !v.VariableType.IsPrimitive)
// t = "UnityEngine.Vector3"
var t = AppDomain.GetType(v.VariableType, method.DeclearingType, method);
//
appdomain.ValueTypeBinders.TryGetValue(clrType, out valueTypeBinder);
// 不是 ILType
if (t is ILType)
var loc = Add(v1, i);
stack.AllocValueType(loc, t);
InitializeValueTypeObject(type, dst);
mStack.Add(obj);*/
else
// 转型为 CLRType
CLRType cT = (CLRType)t;
// 分配 局部变量指针
// loc: StackObject*
var loc = Add(v1, i);
// 获取 ValueTypeBinder
if (cT.ValueTypeBinder != null)
// stack: RuntimeStack
stack.AllocValueType(loc, t);
else
// 创建 Vector(0.0, 0.0, 0.0)
obj = ((CLRType)t).CreateDefaultInstance();
loc->ObjectType = ObjectTypes.Object;
loc->Value = locBase + i;
// mStack
// [(0.0, 0.0, 0.0)]
mStack[locBase + i] = obj;
// 将位于特定索引处的局部变量的地址加载到计算堆栈上(短格式)
case OpCodeEnum.Ldloca_S:
var v = Add(frame.LocalVarPointer, ip->TokenInteger);
// StackObjectReference 的值 是 指针
esp->ObjectType = ObjectTypes.StackObjectReference;
*(long*)&esp->Value = (long)v;
esp++;
// 将所提供的 float32 类型的值作为 F (float) 类型推送到计算堆栈上。
case OpCodeEnum.Ldc_R4:
*(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
esp->ObjectType = ObjectTypes.Float;
esp++;
// 将所提供的 float32 类型的值作为 F (float) 类型推送到计算堆栈上。
case OpCodeEnum.Ldc_R4:
*(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
esp->ObjectType = ObjectTypes.Float;
esp++;
// 将所提供的 float32 类型的值作为 F (float) 类型推送到计算堆栈上。
case OpCodeEnum.Ldc_R4:
*(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
esp->ObjectType = ObjectTypes.Float;
esp++;
// 调用 Vector3 构造函数
case OpCodeEnum.Call:
// "Void .ctor(Single, Single, Single)"
IMethod m = domain.GetMethod(ip->TokenInteger);
//
object result = cm.Invoke(this, esp, mStack);
object instance = declaringType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((Minus(esp, paramCount + )), appdomain, mStack));
// cDef: ConstructorInfo
cDef.Invoke(instance, param);
// 将索引 0 处的局部变量加载到计算堆栈上
case OpCodeEnum.Ldloc_0:
CopyToStack(esp, v1, mStack);
esp++;
// 调用 "UnityEngine.Vector3 get_one()"
case OpCodeEnum.Call:
object result = cm.Invoke(this, esp, mStack);
// 调用 "UnityEngine.Vector3 op_Addition(UnityEngine.Vector3, UnityEngine.Vector3)"
case OpCodeEnum.Call:
object result = cm.Invoke(this, esp, mStack);
// 从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中。
case OpCodeEnum.Stloc_0:
esp--;
int idx = locBase;
StLocSub(esp, v1, bp, idx, mStack);
ValueTypeBinder
appdomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
if (!valueTypeBinders.ContainsKey(t))
{
valueTypeBinders[t] = binder;
binder.RegisterCLRRedirection(this);
args = new Type[] { };
method = type.GetMethod("get_one", flag, null, args, null);
appdomain.RegisterCLRMethodRedirection(method, Get_One);
if (mi == null)
return;
// mi: MethodBase = "UnityEngine.Vector3 get_one()"
// ValueBinder 也是 使用 CLRMethodRedicrection
if (!redirectMap.ContainsKey(mi))
redirectMap[mi] = func; var ct = GetType(t) as CLRType;
binder.CLRType = ct;
} UnityEngine_Vector3_Binding.Register(app);
method = type.GetMethod("get_one", flag, null, args, null);
app.RegisterCLRMethodRedirection(method, get_one_0);
args = new Type[]{};
method = type.GetMethod("get_one", flag, null, args, null);
app.RegisterCLRMethodRedirection(method, get_one_0);
if (mi == null)
return;
// mi: MethodBase = "UnityEngine.Vector3 get_one()"
// 上面已经存过了, 所以不会覆盖.
if (!redirectMap.ContainsKey(mi))
redirectMap[mi] = func;
ValueTypeBinder 也使用 RegisterCLRMethodRedirection
热更工程 class TestValueType {
public static void RunTest() {
Vector3 one = new Vector3(1.0f, 1.0f, 1.0f);
Debug.Log(one);
}
} 主工程
appdomain.Invoke("HotFix_Project.TestValueType", "RunTest", null, null);
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldloca.s V_0"
// "IL_0003: ldc.r4 1"
// "IL_0008: ldc.r4 1"
// "IL_000d: ldc.r4 1"
// "IL_0012: call System.Void UnityEngine.Vector3::.ctor(System.Single,System.Single,System.Single)"
// "IL_0017: ldloc.0"
// "IL_0018: box UnityEngine.Vector3"
// "IL_001d: call System.Void UnityEngine.Debug::Log(System.Object)"
// "IL_0022: nop"
// "IL_0023: ret"
// 自定义OpCode
// Nop, 0, 0
// Ldloca_S, 0, 0
// Ldc_R4, 1065353216, 0
// Ldc_R4, 1065353216, 0
// Ldc_R4, 1065353216, 0
// Call, 1, 0
// Ldloc_0, 0, 0
// Box, 3, 0
// Call, 2, 0
// Nop, 0, 0
// Ret, 0, 0
// esp = 0xa6479050
esp = Execute(method, esp, out unhandledException);
// esp = 0xa647905c, 因为有1个局部变量
esp = frame.BasePointer;
// arg = 0xa6479050, 没有参数
var arg = Minus(frame.LocalVarPointer, method.ParameterCount);
// 处理局部变量
for (int i = ; 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 + );
if (valueTypePtr <= StackBase)
throw new StackOverflowException();
InitializeValueTypeObject(type, dst);
CLRType t = (CLRType)type;
// 3个字段
var cnt = t.TotalFieldCount;
for(int i = ; i < cnt; i++)
{
// it: Single
var it = t.OrderedFieldTypes[i] as CLRType;
// val = 3个字段的 StackObject* 地址
// 0xa64a9038
// 0xa64a902c
// 0xa64a9020
StackObject* val = ILIntepreter.Minus(ptr, i + );
if (it.IsPrimitive)
StackObject.Initialized(val, it);
else if (t == typeof(float))
{
esp->ObjectType = ObjectTypes.Float;
esp->Value = ;
esp->ValueLow = ;
}
}
// ct 没有 ValueTypeBinder
else
obj = ((CLRType)t).CreateDefaultInstance();
// TypeForCLR = {UnityEngine.Vector3}
createDefaultInstanceDelegate = () => Activator.CreateInstance(TypeForCLR);
loc->ObjectType = ObjectTypes.Object;
loc->Value = locBase + i;
// mStack[0] = Vector3(0.0, 0.0, 0.0)
mStack[locBase + i] = obj; // bp = 0xa64a9014
var bp = stack.ValueTypeStackPointer;
// ValueTypeBasePointer = 0xa64a9014
ValueTypeBasePointer = bp;
// 将位于特定索引处的局部变量的地址加载到计算堆栈上(短格式)
case OpCodeEnum.Ldloca_S:
// v = 0xa6479050
var v = Add(frame.LocalVarPointer, ip->TokenInteger);
// esp: StackObject引用
esp->ObjectType = ObjectTypes.StackObjectReference;
// esp = 0xa647905c, esp 指向 v
*(long*)&esp->Value = (long)v;
// esp = 0xa6479068
esp++;
case OpCodeEnum.Ldc_R4:
// esp->Value = 1065353216
*(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
esp->ObjectType = ObjectTypes.Float;
// esp = 0xa6479074
esp++;
case OpCodeEnum.Ldc_R4:
// esp->Value = 1065353216
*(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
esp->ObjectType = ObjectTypes.Float;
// 0xa6479080
esp++;
case OpCodeEnum.Ldc_R4:
// esp->Value = 1065353216
*(float*)(&esp->Value) = *(float*)&ip->TokenInteger;
esp->ObjectType = ObjectTypes.Float;
// 0xa647908c
esp++;
case OpCodeEnum.Call:
// "UnityEngine.Vector3 Void .ctor(Single, Single, Single)"
IMethod m = domain.GetMethod(ip->TokenInteger);
if (redirect != null)
// esp = 0xa647908c =
// mStack[0] = null;
esp = redirect(this, esp, mStack, cm, false);
StackObject* ret; // ret = 0xa647905c, ret-Value 指向 0xa6479050
ret = ILIntepreter.Minus(esp, );
// 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, );
// v = 0xa6479068 = (0xa6479050 + 1) + 1
var v = ILIntepreter.Minus(esp, );
// 赋值 0xa64a9038
*f = *v; // f = 0xa64a902c = (ValueTypePtr) - 2
f = ILIntepreter.Minus(dst, );
// v = 0xa6479074 = (0xa6479050 + 1) + 2
v = ILIntepreter.Minus(esp, );
// 赋值 0xa64a902c
*f = *v; // f = 0xa64a9020 = (ValueTypePtr) - 3
f = ILIntepreter.Minus(dst, );
// v = 0xa6479080 = (0xa6479050 + 1) + 3
v = ILIntepreter.Minus(esp, );
// 赋值 0xa64a9020
*f = *v; return ret;
else
//
object result = cm.Invoke(this, esp, mStack); case OpCodeEnum.Ldloc_0:
// esp = 0xa647905c
// v1 = 0xa6479050
// mStack[0] = null
CopyToStack(esp, v1, mStack);
// dst->Value = -1505062844
// dst->ObjectType = ValueTypeObjectReference
*dst = *src;
if (dst->ObjectType >= ObjectTypes.Object)
{
dst->Value = mStack.Count;
var obj = mStack[src->Value];
mStack.Add(obj);
}
// esp = 0xa6479068
esp++
case OpCodeEnum.Box:
// objRef = 0xa647905c
objRef = esp - ;
// 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, );
// 赋值 给 x
ins.x = *(float*)&v->Value;
// 获取 0xa64a902c
v = ILIntepreter.Minus(ptr, );
// 赋值给 y
ins.y = *(float*)&v->Value;
// 获取 0xa64a9020
v = ILIntepreter.Minus(ptr, );
// 赋值给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 +
}
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 >= ; 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 - ;
// method = "HotFix_Project.TestValueType.RunTest()"
var method = frame.Method;
// ret = 0xa6479050
StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
// 移除 mStack 里的内容
((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
// 0xa64a9044
valueTypePtr = frame.ValueTypeBasePointer;
// ret = 0xa6479050
return ret;
ValueTypeBinder 再探
热更工程 using System;
using System.Collections.Generic; namespace HotFix_Project
{
public class TestDelegate
{
static TestDelegateMethod delegateMethod; public static void Initialize()
{
delegateMethod = Method;
} public static void RunTest()
{
delegateMethod();
} public static void Initialize2()
{
DelegateDemo.TestMethodDelegate = Method;
} public static void RunTest2()
{
DelegateDemo.TestMethodDelegate();
} static void Method(int a)
{
UnityEngine.Debug.Log("!! TestDelegate.Method, a = " + a);
} static string Function(int a)
{
return a.ToString();
} static void Action(string a)
{
UnityEngine.Debug.Log("!! TestDelegate.Action, a = " + a);
}
}
} 主工程 public delegate void TestDelegateMethod(int a);
public delegate string TestDelegateFunction(int a); public class DelegateDemo : MonoBehaviour
{
public static TestDelegateMethod TestMethodDelegate;
public static TestDelegateFunction TestFunctionDelegate;
public static System.Action<string> TestActionDelegate; Debug.Log("完全在热更DLL内部使用的委托,直接可用,不需要做任何处理");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize", null, null);
// 原始IL
// "IL_0000: nop"
// "IL_0001: ldnull"
// "IL_0002: ldftn System.Void HotFix_Project.TestDelegate::Method(System.Int32)"
// "IL_0008: newobj System.Void TestDelegateMethod::.ctor(System.Object,System.IntPtr)"
// "IL_000d: stsfld TestDelegateMethod HotFix_Project.TestDelegate::delegateMethod"
// "IL_0012: ret"
// 自定义 IL
// Nop, 0, 0
// Ldnull, 0, 0
// Ldftn, 1, 0
// Newobj, 2, 0
// Stsfld, 0, 17179869184
// Ret, 0, 0
esp = Execute(method, esp, out unhandledException);
// 将指向实现特定方法的本机代码的非托管指针(native int 类型)推送到计算堆栈上。
case OpCodeEnum.Ldftn:
// m = "HotFix_Project.TestDelegate.Method(Int32 a)"
IMethod m = domain.GetMethod(ip->TokenInteger);
esp = PushObject(esp, mStack, m);
// new 一个 TestDelegateMethod
case OpCodeEnum.Newobj:
// m = "Void .ctor(Object, IntPtr)", DeclaringType = "TestDelegateMethod"
IMethod m = domain.GetMethod(ip->TokenInteger);
// 如果方法的声明类型是委托
if (cm.DeclearingType.IsDelegate)
objRef = GetObjectAndResolveReference(esp - - );
// mi = "HotFix_Project.TestDelegate.Method(Int32 a)"
var mi = (IMethod)mStack[(esp - )->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 >> ));
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 >> ));
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 >> ));
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) != )
// 不是
if (obj is Delegate)
return obj;
// 不是
if (pt == typeof(Delegate))
return ((IDelegateAdapter)obj).Delegate;
// pt: {System.RuntimeType} = {TestDelegateMethod}
// obj: {ILRuntime.Runtime.Intepreter.DummyDelegateAdapter} = "HotFix_Project.TestDelegate.Method(Int32 a)"
return ((IDelegateAdapter)obj).GetConvertor(pt); if (converters == null)
converters = new Dictionary<System.Type, Delegate>(new ByReferenceKeyComparer<Type>());
Delegate res;
if (converters.TryGetValue(type, out res))
return res;
else
{
//
res = appdomain.DelegateManager.ConvertToDelegate(type, this);
Func<Delegate, Delegate> func;
// 是 dummyAdapter, 抛出异常
if(adapter is DummyDelegateAdapter)
{
DelegateAdapter.ThrowAdapterNotFound(adapter.Method);
return null;
}
if (clrDelegates.TryGetValue(clrDelegateType, out func))
{
return func(adapter.Delegate);
}
else
{ converters[type] = res;
return res;
} } catch (System.Exception ex) {
Debug.LogError(ex.ToString());
}
//为了演示,清除适配器缓存,实际使用中不要这么做
ClearDelegateCache();
Debug.Log("这是因为iOS的IL2CPP模式下,不能动态生成类型,为了避免出现不可预知的问题,我们没有通过反射的方式创建委托实例,因此需要手动进行一些注册");
Debug.Log("首先需要注册委托适配器,刚刚的报错的错误提示中,有提示需要的注册代码");
//下面这些注册代码,正式使用的时候,应该写在InitializeILRuntime中
//TestDelegateMethod, 这个委托类型为有个参数为int的方法,注册仅需要注册不同的参数搭配即可
appdomain.DelegateManager.RegisterMethodDelegate<int>();
var type = typeof(T);
if (type.IsSubclassOf(typeof(Delegate)))
// type = {System.Action`1[System.Int32]}
// action = {System.Func`2[[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
clrDelegates[type] = action; //带返回值的委托的话需要用RegisterFunctionDelegate,返回类型为最后一个
//appdomain.DelegateManager.RegisterFunctionDelegate<int, string>();
//Action<string> 的参数为一个string
//appdomain.DelegateManager.RegisterMethodDelegate<string>(); Debug.Log("注册完毕后再次运行会发现这次会报另外的错误");
try
{
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
esp = Execute(method, esp, out unhandledException);
t.SetStaticFieldValue(idx, f.FieldType.CheckCLRTypes(CheckAndCloneValueType(StackObject.ToObject(val, domain, mStack), domain)));
return ((IDelegateAdapter)obj).GetConvertor(pt);
// type = {TestDelegateMethod}
// this: {ILRuntime.Runtime.Intepreter.MethodDelegateAdapter`1[System.Int32]} = "HotFix_Project.TestDelegate.Method(Int32 a)"
res = appdomain.DelegateManager.ConvertToDelegate(type, this);
// 找不到 报错
if (clrDelegates.TryGetValue(clrDelegateType, out func)) }
catch (System.Exception ex)
{
Debug.LogError(ex.ToString());
} Debug.Log("ILRuntime内部是用Action和Func这两个系统内置的委托类型来创建实例的,所以其他的委托类型都需要写转换器");
Debug.Log("将Action或者Func转换成目标委托类型"); appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateMethod>((action) =>
{
//转换器的目的是把Action或者Func转换成正确的类型,这里则是把Action<int>转换成TestDelegateMethod
return new TestDelegateMethod((a) =>
{
//调用委托实例
((System.Action<int>)action)(a);
});
});
//对于TestDelegateFunction同理,只是是将Func<int, string>转换成TestDelegateFunction
appdomain.DelegateManager.RegisterDelegateConvertor<TestDelegateFunction>((action) =>
{
return new TestDelegateFunction((a) =>
{
return ((System.Func<int, string>)action)(a);
});
}); //下面再举一个这个Demo中没有用到,但是UGUI经常遇到的一个委托,例如UnityAction<float>
appdomain.DelegateManager.RegisterDelegateConvertor<UnityEngine.Events.UnityAction<float>>((action) =>
{
return new UnityEngine.Events.UnityAction<float>((a) =>
{
((System.Action<float>)action)(a);
});
}); Debug.Log("现在我们再来运行一次");
appdomain.Invoke("HotFix_Project.TestDelegate", "Initialize2", null, null);
appdomain.Invoke("HotFix_Project.TestDelegate", "RunTest2", null, null);
// pt = {TestDelegateMethod}
((IDelegateAdapter)obj).GetConvertor(pt);
// this = "HotFix_Project.TestDelegate.Method(Int32 a)"
res = appdomain.DelegateManager.ConvertToDelegate(type, this);
ConvertToDelegate
// func = {System.Func`2[[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Delegate, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
// func.method = "System.Delegate <OnHotFixLoaded>b__10_0(System.Delegate)"
// func.Target = {DelegateDemo+<>c}
if (clrDelegates.TryGetValue(clrDelegateType, out func))
// adapter.Delegate = {System.Action`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]}
// Delegate.Method = "Void InvokeILMethod(Int32)"
// Delegate.Target = "HotFix_Project.TestDelegate.Method(Int32 a)"
func(adapter.Delegate); Debug.Log("运行成功,我们可以看见,用Action或者Func当作委托类型的话,可以避免写转换器,所以项目中在不必要的情况下尽量只用Action和Func");
Debug.Log("另外应该尽量减少不必要的跨域委托调用,如果委托只在热更DLL中用,是不需要进行任何注册的");
Debug.Log("---------");
Debug.Log("我们再来在Unity主工程中调用一下刚刚的委托试试");
TestMethodDelegate();
var str = TestFunctionDelegate();
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 > && !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 > && !method.IsGenericInstance)
continue;
// body: OpCode[]
// Ldarg_0, 0, 0
// Call, 0, 1
// Nop, 0, 0
// Nop, 0, 0
// Ldstr, 0, -2078173280
// Call, 24, 0
// Ldarg_0, 0, 0
// Ldc_I4_0, 0, 0
// Stfld, 0, 335007449088
// Ret, 0, 0
var body = method.Body;
foreach (var ins in body)
{
switch (ins.Code)
{
case Intepreter.OpCodes.OpCodeEnum.Newobj:
{
CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod;
// 如果这个方法是 CLRMethod
// e.g. "System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance]" .ctor
if (m != null)
{
if (m.DeclearingType.IsDelegate)
continue;
Type t = m.DeclearingType.TypeForCLR;
CLRBindingGenerateInfo info;
if (!infos.TryGetValue(t, out info))
{
info = CreateNewBindingInfo(t);
// e.g. "[System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
infos[t] = info;
}
if (m.IsConstructor)
info.Constructors.Add(m.ConstructorInfo);
else
info.Methods.Add(m.MethodInfo);
}
}
break;
case Intepreter.OpCodes.OpCodeEnum.Ldfld:
case Intepreter.OpCodes.OpCodeEnum.Stfld:
case Intepreter.OpCodes.OpCodeEnum.Ldflda:
case Intepreter.OpCodes.OpCodeEnum.Ldsfld:
case Intepreter.OpCodes.OpCodeEnum.Ldsflda:
case Intepreter.OpCodes.OpCodeEnum.Stsfld:
{
// ins.TokenLong == 335007449088
// ins.TokenLong >> 32 = 335007449088 / (2 ^ 32) = 335007449088 / 4294967296 = 78 // t = DelegateDemo 是 CLRType
//
var t = domain.GetType((int)(ins.TokenLong >> )) 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 == )
{
var t = domain.GetType((int)(ins.TokenLong >> )) as CLR.TypeSystem.CLRType;
if (t != null)
{
var fi = t.GetField((int)ins.TokenLong);
if (fi != null)
{
CLRBindingGenerateInfo info;
if (!infos.TryGetValue(t.TypeForCLR, out info))
{
info = CreateNewBindingInfo(t.TypeForCLR);
infos[t.TypeForCLR] = info;
}
info.Fields.Add(fi);
}
}
}
}
break;
case Intepreter.OpCodes.OpCodeEnum.Newarr:
{
// t = "System.Object", t.ArrayType = "System.Object[]"
var t = domain.GetType(ins.TokenInteger) as CLR.TypeSystem.CLRType;
if(t != null)
{
CLRBindingGenerateInfo info;
if (!infos.TryGetValue(t.TypeForCLR, out info))
{
info = CreateNewBindingInfo(t.TypeForCLR);
infos[t.TypeForCLR] = info;
}
info.ArrayNeeded = true;
}
}
break;
case Intepreter.OpCodes.OpCodeEnum.Call:
case Intepreter.OpCodes.OpCodeEnum.Callvirt:
{
CLR.Method.CLRMethod m = domain.GetMethod(ins.TokenInteger) as CLR.Method.CLRMethod;
// 如果这个方法是 CLRMethod
// e.g. "System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance]" "Void Add(ILRuntime.Runtime.Intepreter.ILTypeInstance)"
if (m != null)
{
//Cannot explicit call base class's constructor directly
if (m.IsConstructor && m.DeclearingType.CanAssignTo(((CLR.TypeSystem.ILType)type).FirstCLRBaseType))
continue;
if (m.IsConstructor)
{
if (!m.ConstructorInfo.IsPublic)
continue;
Type t = m.DeclearingType.TypeForCLR;
CLRBindingGenerateInfo info;
if (!infos.TryGetValue(t, out info))
{
info = CreateNewBindingInfo(t);
infos[t] = info;
} info.Constructors.Add(m.ConstructorInfo);
}
else
{
if (!m.MethodInfo.IsPublic)
continue;
Type t = m.DeclearingType.TypeForCLR;
CLRBindingGenerateInfo info;
if (!infos.TryGetValue(t, out info))
{
info = CreateNewBindingInfo(t);
infos[t] = info;
} // 添加要生成的方法
info.Methods.Add(m.MethodInfo);
}
}
}
break;
}
}
}
}
}
} // 删除旧文件
string[] oldFiles = System.IO.Directory.GetFiles(outputPath, "*.cs");
foreach (var i in oldFiles)
{
System.IO.File.Delete(i);
} if (valueTypeBinders == null)
valueTypeBinders = new List<Type>(domain.ValueTypeBinders.Keys); // 不想包含的 MethodBase
HashSet<MethodBase> excludeMethods = null;
// 不想包含的 FieldInfo
HashSet<FieldInfo> excludeFields = null;
HashSet<string> files = new HashSet<string>();
List<string> clsNames = new List<string>(); // 0, "[System.Collections.Generic.List`1[ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void Add(ILRuntime.Runtime.Intepreter.ILTypeInstance)"
"ILRuntime.Runtime.Intepreter.ILTypeInstance get_Item(Int32)"
// 1, "[System.Collections.Generic.Dictionary`2[System.String,ILRuntime.Runtime.Intepreter.ILTypeInstance], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void set_Item(System.String, ILRuntime.Runtime.Intepreter.ILTypeInstance)"
"ILRuntime.Runtime.Intepreter.ILTypeInstance get_Item(System.String)"
// 2, "[System.Collections.Generic.Dictionary`2[System.String,System.Int32], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void set_Item(System.String, Int32)"
"Int32 get_Item(System.String)"
// 3, "[LitJson.JsonMapper, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String ToJson(System.Object)"
"ILRuntime.Runtime.Intepreter.ILTypeInstance ToObject[ILTypeInstance](System.String)"
// 4, "[UnityEngine.Debug, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void Log(System.Object)"
"Void LogFormat(System.String, System.Object[])"
// 5, "[System.Diagnostics.Stopwatch, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods
"Void Start()"
"Void Stop()"
"Int64 get_ElapsedMilliseconds()"
// 6, "[UnityEngine.Vector3, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single, Single, Single)"
Fields
Methods
"UnityEngine.Vector3 get_one()"
"UnityEngine.Vector3 op_Addition(UnityEngine.Vector3, UnityEngine.Vector3)"
"UnityEngine.Vector3 op_Subtraction(UnityEngine.Vector3, UnityEngine.Vector3)"
"UnityEngine.Vector3 op_Multiply(UnityEngine.Vector3, Single)"
"UnityEngine.Vector3 op_Multiply(Single, UnityEngine.Vector3)"
"UnityEngine.Vector3 op_Division(UnityEngine.Vector3, Single)"
"UnityEngine.Vector3 op_UnaryNegation(UnityEngine.Vector3)"
"Boolean op_Equality(UnityEngine.Vector3, UnityEngine.Vector3)"
"Boolean op_Inequality(UnityEngine.Vector3, UnityEngine.Vector3)"
"Single Dot(UnityEngine.Vector3, UnityEngine.Vector3)"
"UnityEngine.Vector3 Cross(UnityEngine.Vector3, UnityEngine.Vector3)"
"Single Distance(UnityEngine.Vector3, UnityEngine.Vector3)"
"Single get_magnitude()"
"UnityEngine.Vector3 get_normalized()"
"Single get_sqrMagnitude()"
"UnityEngine.Vector3 get_zero()" // 7, "[System.String, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String Concat(System.Object, System.Object)"
"System.String Concat(System.String, System.String)" // 8, "[System.Boolean, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String ToString()" // 9, "[System.Object, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods // 10, "[UnityEngine.Quaternion, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single, Single, Single, Single)"
Fields
Methods
"UnityEngine.Quaternion get_identity()"
"UnityEngine.Quaternion op_Multiply(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"UnityEngine.Vector3 op_Multiply(UnityEngine.Quaternion, UnityEngine.Vector3)"
"Boolean op_Equality(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"Boolean op_Inequality(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"Single Dot(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"Single Angle(UnityEngine.Quaternion, UnityEngine.Quaternion)"
"UnityEngine.Vector3 get_eulerAngles()"
"UnityEngine.Quaternion Euler(UnityEngine.Vector3)"
"UnityEngine.Quaternion Euler(Single, Single, Single)" // 11, "[UnityEngine.Vector2, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single, Single)"
Fields
Methods
"UnityEngine.Vector2 get_one()"
"UnityEngine.Vector2 op_Addition(UnityEngine.Vector2, UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Subtraction(UnityEngine.Vector2, UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Multiply(UnityEngine.Vector2, Single)"
"UnityEngine.Vector2 op_Multiply(Single, UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Division(UnityEngine.Vector2, Single)"
"UnityEngine.Vector2 op_UnaryNegation(UnityEngine.Vector2)"
"Boolean op_Equality(UnityEngine.Vector2, UnityEngine.Vector2)"
"Boolean op_Inequality(UnityEngine.Vector2, UnityEngine.Vector2)"
"UnityEngine.Vector3 op_Implicit(UnityEngine.Vector2)"
"UnityEngine.Vector2 op_Implicit(UnityEngine.Vector3)"
"Single Dot(UnityEngine.Vector2, UnityEngine.Vector2)"
"Single Distance(UnityEngine.Vector2, UnityEngine.Vector2)"
"Single get_magnitude()"
"UnityEngine.Vector2 get_normalized()"
"Single get_sqrMagnitude()"
"UnityEngine.Vector2 get_zero()" // 12, "[UnityEngine.Time, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Single get_time()" // 13, "[UnityEngine.GameObject, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Adaptor AddComponent[Adaptor]()"
"Adaptor GetComponent[Adaptor]()" // 14, "[CoroutineDemo, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"CoroutineDemo get_Instance()"
"Void DoCoroutine(System.Collections.IEnumerator)" // 15, "[UnityEngine.WaitForSeconds, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor(Single)"
Fields
Methods // 16, "[System.NotSupportedException, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
"Void .ctor()"
Fields
Methods // 17, "[CLRBindingTestClass, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Single DoSomeTest(Int32, Single)" // 18, "[TestClassBase, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void TestVirtual(System.String)" // 19, "[TestDelegateMethod, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void Invoke(Int32)" // 20, "[TestDelegateFunction, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String Invoke(Int32)" // 21, "[System.Action`1[System.String], ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"Void Invoke(System.String)" // 22, "[DelegateDemo, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
"TestDelegateMethod TestMethodDelegate"
"TestDelegateFunction TestFunctionDelegate"
"System.Action`1[System.String] TestActionDelegate"
Methods // 23, "[System.Int32, ILRuntime.Runtime.CLRBinding.BindingCodeGenerator+CLRBindingGenerateInfo]"
Constructors
Fields
Methods
"System.String ToString()" foreach (var info in infos)
{
if (!info.Value.NeedGenerate)
continue;
Type i = info.Value.Type; //CLR binding for delegate is important for cross domain invocation,so it should be generated
//if (i.BaseType == typeof(MulticastDelegate))
// continue; string clsName, realClsName;
bool isByRef;
// 如果有 ObsoleteAttribute 就跳过
if (i.GetCustomAttributes(typeof(ObsoleteAttribute), true).Length > )
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, );
if (len < oFileName.Length)
oFileName = oFileName.Substring(, 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 > ? 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, );\r\n\r\n ptr_of_this_method = ILIntepreter.Minus(__esp, );\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, );\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, );\r\n\r\n
ptr_of_this_method = ILIntepreter.Minus(__esp, );\r\n
System.Int32 @index = ptr_of_this_method->Value;\r\n\r\n
ptr_of_this_method = ILIntepreter.Minus(__esp, );\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 != || !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 > ; j--)
// 设置ptr_of_this_method
sb.AppendLine(string.Format(" ptr_of_this_method = ILIntepreter.Minus(__esp, {0});", param.Length - j + )); // 生成字段方法体
string fieldWraperCode = fields.Length > ? 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() != ; 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 > )
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 > )
sb.AppendLine(fieldWraperCode);
if (info.Value.ValueTypeNeeded)
sb.AppendLine(cloneWraperCode);
string ctorWraperCode = i.GenerateConstructorWraperCode(ctors, realClsName, excludeMethods, valueTypeBinders);
sb.AppendLine(ctorWraperCode);
sb.AppendLine(" }");
sb.AppendLine("}"); sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
sw.Flush();
}
} // 生成 Assets/ILRuntime/Generated/CLRBindings.cs
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputPath + "/CLRBindings.cs", false, new UTF8Encoding(false)))
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(@"using System;
using System.Collections.Generic;
using System.Reflection; namespace ILRuntime.Runtime.Generated
{
class CLRBindings
{
/// <summary>
/// Initialize the CLR binding, please invoke this AFTER CLR Redirection registration
/// </summary>
public static void Initialize(ILRuntime.Runtime.Enviorment.AppDomain app)
{");
foreach (var i in clsNames)
{
sb.Append(" ");
sb.Append(i);
sb.AppendLine(".Register(app);");
} sb.AppendLine(@" }
}
}");
sw.Write(Regex.Replace(sb.ToString(), "(?<!\r)\n", "\r\n"));
} var delegateClsNames = GenerateDelegateBinding(delegateTypes, outputPath);
clsNames.AddRange(delegateClsNames); GenerateBindingInitializeScript(clsNames, valueTypeBinders, outputPath); }
}
ILRuntime/Generate CLR Binding Code by Analysis
###################################################################################################################################################################
热更工程
namespace HotFix_Project {
public class InstanceClass {
public InstanceClass() {
}
}
}
主工程
var type = appdomain.LoadedTypes["HotFix_Project.InstanceClass"];
object obj = appdomain.Instantiate("HotFix_Project.InstanceClass", new object[] { });
ILIntepreter inteptreter = RequestILIntepreter();
inteptreter = new ILIntepreter(this);
stack = new RuntimeStack(this);
nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(StackObject) * MAXIMAL_STACK_OBJECTS);
pointer = (StackObject*)nativePointer.ToPointer();
endOfMemory = Add(pointer, MAXIMAL_STACK_OBJECTS);
valueTypePtr = endOfMemory - 1;
// esp = 0x5de00010
// mStack = null;
// instance: ILTypeInstance = "HotFix_Project.InstanceClass"
esp = PushObject(esp, mStack, instance);
esp->ObjectType = ObjectTypes.Object;
esp->Value = mStack.Count;
mStack.Add(obj);
return esp + 1 (0x5de0001c)
// 没有参数不变
esp = PushParameters(method, esp, p);
// 执行方法
// method = "HotFix_Project.InstanceClass..ctor()"
// esp = 0x5de0001c
// 原始IL
// "IL_0000: ldarg.0"
// "IL_0001: call System.Void System.Object::.ctor()"
// "IL_0006: nop"
// "IL_0007: nop"
// "IL_0008: ret"
// 自定义OpCode
// Ldarg_0, 0, 0
// Call, 1, 0
// Nop, 0, 0
// Nop, 0, 0
// Ret, 0, 0
esp = Execute(method, esp, out unhandledException);
res = new StackFrame();
stack.InitializeFrame(method, esp, out frame);
StackObject* v1 = frame.LocalVarPointer;
StackObject* v2 = frame.LocalVarPointer + 1;
StackObject* v3 = frame.LocalVarPointer + 1 + 1;
StackObject* v4 = Add(frame.LocalVarPointer, 3);
esp = frame.BasePointer;
var arg = Minus(frame.LocalVarPointer, method.ParameterCount);
if (method.HasThis) arg--; paramCnt++;
// StackFrame 如 RuntimeStack
stack.PushFrame(ref frame);
// 将索引为 0 的参数加载到计算堆栈上, 将 arg 上的值 拷贝到 esp 上
case OpCodeEnum.Ldarg_0:
// esp = 0x5de0001c
// arg = 0x5de00010
// mStack[0] = "HotFix_Project.InstanceClass"
CopyToStack(esp, arg, mStack);
esp++;
// 调用由传递的方法说明符指示的方法。
case OpCodeEnum.Call:
IMethod m = domain.GetMethod(ip->TokenInteger);
if (m == null)
//Irrelevant method
int cnt = (int)ip->TokenLong;
//Balance the stack
for (int i = 0; i < cnt; i++)
{
// esp - 1 = 0x5de0001c
Free(esp - 1);
// esp = 0x5de0001c
esp--;
}
return stack.PopFrame(ref frame, esp);
// returnVal = 0x5de00010
StackObject* returnVal = esp - 1;
// method = "HotFix_Project.InstanceClass..ctor()"
var method = frame.Method;
// ret = 0x5de0001c
StackObject* ret = ILIntepreter.Minus(frame.LocalVarPointer, method.ParameterCount);
// ret = 0x5de00010
if (method.HasThis) ret--;
// mStack 没有了
((UncheckedList<object>)managedStack).RemoveRange(mStackBase, managedStack.Count - mStackBase);
//ret = 0x5de00010
return ret;
// null
object result = method.ReturnType != domain.VoidType ? method.ReturnType.TypeForCLR.CheckCLRTypes(StackObject.ToObject((esp - 1), domain, mStack)) : null;
((UncheckedList<object>)mStack).RemoveRange(mStackBase, mStack.Count - mStackBase);
无参构造函数最后返回的是 res: ILTypeInstance
public ILTypeInstance Instantiate(bool callDefaultConstructor = true)
{
var res = new ILTypeInstance(this);
if (callDefaultConstructor)
{
var m = GetConstructor(CLR.Utils.Extensions.EmptyParamList);
if (m != null)
{
appdomain.Invoke(m, res, null);
}
}
return res;
}
###################################################################################################################################################################
相关文章
ILRuntime 学习的更多相关文章
- 2019年Unity学习资源指南[精心整理]
前言 进入一个领域,最直接有效的方法就是,寻找相关综述性文章,首先你需要对你入门的领域有个概括性的了解,这些包括: 1.主流的学习社区与网站. 2.该领域的知名大牛与热心分享的从业者. 3.如何有效的 ...
- Unity S老师系列课程学习
AssetBundle(创建打包)入门学习(基于Unity2017) (已看) 分组策略 逻辑实体分组 按照类型分组 按照使用分组 分组策略----总结 把经常更新的资源放在一个单独的包里面,跟不经常 ...
- 从直播编程到直播教育:LiveEdu.tv开启多元化的在线学习直播时代
2015年9月,一个叫Livecoding.tv的网站在互联网上引起了编程界的注意.缘于Pingwest品玩的一位编辑在上网时无意中发现了这个网站,并写了一篇文章<一个比直播睡觉更奇怪的网站:直 ...
- Angular2学习笔记(1)
Angular2学习笔记(1) 1. 写在前面 之前基于Electron写过一个Markdown编辑器.就其功能而言,主要功能已经实现,一些小的不影响使用的功能由于时间关系还没有完成:但就代码而言,之 ...
- ABP入门系列(1)——学习Abp框架之实操演练
作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...
- 消息队列——RabbitMQ学习笔记
消息队列--RabbitMQ学习笔记 1. 写在前面 昨天简单学习了一个消息队列项目--RabbitMQ,今天趁热打铁,将学到的东西记录下来. 学习的资料主要是官网给出的6个基本的消息发送/接收模型, ...
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- Unity3d学习 制作地形
这周学习了如何在unity中制作地形,就是在一个Terrain的对象上盖几座小山,在山底种几棵树,那就讲一下如何完成上述内容. 1.在新键得项目的游戏的Hierarchy目录中新键一个Terrain对 ...
- 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...
随机推荐
- 【洛谷5072】[Ynoi2015] 盼君勿忘(莫队)
点此看题面 大致题意: 一个序列,每次询问一个区间\([l,r]\)并给出一个模数\(p\),求模\(p\)意义下区间\([l,r]\)内所有子序列去重后值的和. 题意转化 原来的题意看起来似乎很棘手 ...
- keras RAdam优化器使用教程, keras加载模型包含自定义优化器报错 如何解决?
本文首发于个人博客https://kezunlin.me/post/c691f02b/,欢迎阅读最新内容! python keras RAdam tutorial and load custom op ...
- Java泛型类型擦除与运行时类型获取
Java的泛型大家都知道是类型擦除的方式实现的,“编译器会进行泛型擦除”是一个常识了(实际擦除的是参数和自变量的类型).“类型擦除” 并非像许多开发者认为的那样,在 <..> 符号内的东西 ...
- C++ 类的static静态成员
静态static 静态成员的提出是为了解决数据共享的问题.实现共享有许多方法,如:设置全局性的变量或对象是一种方法.但是,全局变量或对象是有局限性的. 在全局变量前,加上关键字static该变量就被定 ...
- IT从业者不可不知的三条定律
信息技术行业,也就是我们所说的IT行业,有着传统行业所未有的发展速度和模式,当然也有着它独特的发展定律.如果你是从事相关行业,下面讲到的三条定律,不可不知. 摩尔定律 比尔·盖茨曾跟通用公司老板说:如 ...
- python登陆代码简单逻辑
孩子:妈妈,我想要一个登陆的接口 妈妈:写,现在写,写1个够吗? 孩子:够了,妈妈真好,谢谢妈妈. 需求写一个简单的登陆逻辑: 1.定义一个账号和密码 2.输入账号和密码,密码要求密文 3.输入正确提 ...
- boolean matches(String regex)正则表达式判断当前字符串是否满足格式要求
package seday02;/*** boolean matches(String regex) * 使用给定正则表达式判断当前字符串是否满足格式要求,满足 则返回true. * 注意:此方法是做 ...
- PHP面试题2019年搜狐面试题及答案解析
一.单选题(共27题,每题5分) 1.阅读下面PHP代码,并选择输出结果( ) A.0 B.1 C.2 D.3 参考答案:D 答案解析:static属性常驻内存 2.PHP单例模式操作描述错误的是? ...
- iOS多线程比较
.iOS的三种多线程技术 .NSThread 每个NSThread对象对应一个线程,量级较轻(真正的多线程) .以下两点是苹果专门开发的“并发”技术,使得程序员可以不再去关心线程的具体使用问题 ØNS ...
- 禁止ViewPager滑动
实现如下: public class NoScrollViewPager extends ViewPager { public NoScrollViewPager (Context context) ...