欢迎光临散文网 会员登陆 & 注册

关于huatuo可行性的思维实验

2022-12-22 18:53 作者:unity小能手  | 我要投稿

在确定目标,动手实现huatuo前,有一个必须考虑的问题——我们如何确定huatuo的可行性?

il2cpp虽然不是一个极其完整的运行时,但代码仍高达12w行,复杂度相当高,想要短期内深入了解它的实现是非常困难的。而且除了官方几个介绍il2cpp的博客外,几乎找不到其他文档。 Hybrid mode execution 的实现复杂度也很高,如果不能确信能够在il2cpp上实现这套机制,贸然投入开发,万一几个月后发现此路不通,或者说开发完成后,突然发现有一个严重并且无解的系统性的缺陷导致这个方案完全不可用于商业项目,这会带来巨大的资源浪费,以及对开发者产生巨大的信心挫伤。 磨刀不误砍柴工,在动手前从理论上确信这套方案有极高可行性,是完全必要的。

 

以我们对CLR运行时的认识,要实现 hybrid mode execution 机制,至少要解决以下几个问题:

  • 能够动态注册元数据,这些动态注册的元数据必须在运行时中跟AOT元数据完全等价。

  • 所有调用动态加载的assembly中函数的路径,都能定向到正确的解释器实现。包括虚函数override、delegate回调、反射调用等等

  • 解释器中的gc,必须能够与AOT部分的gc统一处理

  • 多线程相关能正常工作。包括且不限于创建Thread、async、volatile、ThreadStatic等等

我们下面一一分析解决这些问题

动态注册元数据

我们大略地分析了il2cpp元数据初始化相关代码,得出以下结论。

首先,动态修改globalmetadata.dat这个方式不可行。因为globalmetadata.dat保存了持久化的元数据,元数据之间关系大量使用id来相互引用,添加新的数据很容易引入错误,变成极难检测的bug。另外,globalmetadata里有不少数据项由于没有文档,无法分析实际用途,也不得而知如何设置正确的值。另外,运行时会动态加载新的dll,重新计算globalmetadata.dat是成本高昂的事情。而且il2cpp中元数据管理并不支持二次加载,重复加载globalmetadata.dat会产生相当大的代码改动。

一个较可行办法,修改所有元数据访问的底层函数,检查被访问的元数据的类型,如果是AOT元数据,则保持之前的调用,如果来自动态加载,则跳转到huatuo的元数据管理模块,返回一个恰当的值。但这儿又遇到一个问题,其次globalmetadata为了优化性能,所有dll中的元数据在统一的id命名空间下。很多元数据查询操作仅仅使用一个id参数,如何根据id区别出到底是AOT还是interpreter的元数据?

我们发现实际项目生成的globalmetadata.dat中这些元数据id的值都较小,最大也不过几十万级别。思考后用一个技巧:我们将id分成两部分: 高位为image id,低位为实际上的id,将image id=0保留给AOT元数据使用。我们为每个动态加载的dll分配一个image id,这个image中解析出的所有元数据id的高位为相应的image id。

我们通过这个技巧,hook了所有底层访问元数据的方法。大约修改了几十处,基本都是如下这样的代码,尽量不修改原始逻辑,很容易保证正确性。

总结

我们通过少量的对实际il2cpp代码的观察,以及对CLR运行时原理的了解,再配合思维实验,可以99.9%以上确定,既然il2cpp生成的代码都能在运行时正确运行,那huatuo解释模式下执行的代码,也能正确运行。

我们在完成思维实验的那一刻,难掩内心激动的心情。作为一名物理专业的IT人,脑海里第一时间浮现出爱因斯坦在思考广义相对论时的,使用电梯思维实验得出引力使时空弯曲这一惊人结论。我们不敢比肩这种伟大的科学家,但我们确实在使用类似的思维技巧。可以说,huatuo不是简单的经验总结,是深刻洞察力与分析能力孕育的结果。


关于huatuo可行性的思维实验的评论 (共 条)

分享到微博请遵守国家法律