huatuo官方技术教程:huatuo之AOT泛型限制及原理介绍
中AOT泛型的底层机制及解决方法。知乎的文档格式化有问题,更舒服的版本请看 AOT泛型原理介绍 。
CLR 泛型
CLR中有两类泛型特性:泛型类型和泛型函数。泛型是c#中使用极其广泛的特性。即使一个没有明显包含泛型的用法,可能隐含了泛型相关的定义或者操作。
例如
int[]隐含就实现 IEnemrable之类的接口。
为async生成状态机代码时,也会隐含生成一些对 System.Runtime.CompilerServices.AsyncTaskMethodBuilder::AwaitUnsafeOnCompleted 之类的泛型代码的调用。
AOT泛型的问题
泛型类型本身只是元数据,内存可以动态创造出任意泛型类型的实例化,无论是AOT泛型还是解释器泛型。但泛型函数(包括泛型类的普通成员函数)则情况有点不同。
解释器泛型函数没有任何限制,但AOT泛型函数则遇到一个严重的问题:由于泛型函数的原始函数体元数据在il2cpp翻译后已经丢失,理论不可能根据已有的c++泛型函数指针为一个新的泛型类型产生对应泛型实例化函数。
对于一些特殊的AOT泛型,huatuo作了特殊处理,没有限制:
泛型数组,包括多维数组
泛型delegate
泛型Nullable类型
但显然不可能对每个AOT泛型类特殊处理。因此,如果你在热更新脚本里定义了个值类型:





class引用类型
reduce type为 object
泛型类型
GenericType<T1,T2,...> 如果是class类型则reduce type为object,否则reduce type为 GenericType<ReduceType<T1>, ReduceType<T2>, ...>。
例如
Dictionary<int, string>的reduce type为object。
YourValueType<int, string>的reduce type为YourValueType<int,object>



基于补充元数据的泛型函数实例化技术(huatuo的专利技术)
既然AOT泛型函数无法实例化的问题本质上是il2cpp翻译造成的元数据缺失的问题,那解决思路也很简单,补充上原始元数据那就能正常实例化了。使用 HuatuoApi.LoadMetadataForAOTAssembly 函数为AOT的assembly补充对应的元数据。
注意,当前要求补充的dll与打包时裁剪后的dll精确一致,因此必须使用build过程中生成的裁剪后的dll,则不能直接复制原始dll,这个限制将来可能会去掉。这些dll可以在目录 {project}/Temp/StagingArea/Il2Cpp/Managed 下找到。另外,对于一些平台如Win Standalone的包,在 {build}/{project}/Managed 目录下也能找到。
你只要在使用AOT泛型前调用即可(只需要调用一次)。如果未注册相应的泛型元数据,则退回到il2cpp的泛型共享机制。
基于补充元数据的泛型函数实例化技术虽然相当完美,但毕竟实例化的函数以解释方式执行,如果能提前在AOT中泛型实例化,可以大幅提升性能。 所以推荐对于常用尤其是性能敏感的泛型类和函数,提前在AOT中实例化。后续我们也会提供工具帮助自动扫描收集相应的泛型实例。
以下代码来自 huatuo_trial 。
