热可重载结构:内存映射

2020-05-02 18:01:13

Mun V0.2版本即将发布,所以我们想借此机会更深入地研究一下这个版本的新特性:热可重载结构(Hotable Reloadable Structs)。能够毫不费力地热加载数据是我们在设计Mun时最初要做的事情,所以我们很兴奋地分享我们是如何实现这一壮举的。

在其核心部分,Mun利用了由Mun编译器生成的函数和类型信息(称为符号)。当源文件的更改导致重新编译时,运行库会检测到这一点,并尝试热重新加载;将旧函数和类型与新的对等函数和类型互换,而不会停止宿主应用程序。虽然在大多数语言中都可以很容易地完成函数的热重装(例如,通过用固定的API交换共享库),但是热重装数据要复杂得多,因为它需要……。

给定结构的新旧布局,我们可以将字段值从旧结构实例内存映射到新实例的内存位置。多亏了蒙的符号,我们现在可以推断出这种映射--尽管不是微不足道的。本博客的其余部分将解释我们开发的算法,以创建从旧类型列表到新列表的“正确”内存映射。

考虑这一问题的另一种方法是:给定起始状态S和目标状态G,我们可以构造一个序列[c1,c2,..。在理想的世界里,我们应该知道所有的变化,Ci;相反,我们只知道S和G。因此,我们需要自己推导出“正确的”变化集合。

注意:通过IDE集成来获得所有更改ci是可能的,该集成将所有按键笔划转换为更改集,但由于我们不能假设每个人都会使用我们的集成-也不能假设它是完美的-我们需要一个用于最简单用例的好算法。

与我们的问题类似的是git diff,它确定两个列表文件之间的更改集。默认情况下,git使用Myers diff算法来计算从开始状态S到目标状态G的插入和删除集。要全面解释Myers diff算法,我推荐这个博客。

Myers diff算法是确定不同之处的一个很好的起点,但是我们需要改进它的结果,以找出两个结构可能的不同之处。

在这一点上,最好问问我们自己,两个结构列表之间可能会有什么不同。给定旧的结构类型列表,

struct LayoutA{a:f32,b:i16,c:u8,d:bool,}struct LayoutB{e:u128,f:i64,}struct LayoutC{g:bool,}。

struct LayoutBB{//重命名struct+Move struct e:u128,f:i64,}struct LayoutA{//移动struct c:u8,//移动字段a:f64,//转换字段类型+移动字段bb:i16,//重命名字段+移动字段//d:bool,//删除字段e:i16,//插入字段}//struct LayoutC{//删除结构//g:bool,/。

您将注意到两种类型的带注释的差异:与结构或结构字段相关的更改。细心的读者可能已经认识到,在某些情况下,存在多个可能的注释。例如,对LayoutA::bb的更改也可以分类为新插入的字段,从而导致旧的LayoutA::bfield被删除。这两个结论都是正确的,但在设计我们的算法时,我们决定选择任何可以保留数据的选择。我们宁愿有一个用户……。

那么,我们如何得出“正确”的映射呢?通过添加一些假设和限制,我们能够避免大多数(如果不是全部)模棱两可的情况。我们所做的假设是:

如果旧结构类型和新结构类型具有相同的名称,则它们必须是相同的类型。在本例中,我们接受对结构及其字段的任何和所有更改。LayoutA就是一个这样的例子;结构名称保持不变,但是它被下移了一个位置,并且它的所有字段都被编辑了。

如果旧结构类型和新结构类型具有不同的名称,但它们的字段都相同,则该结构必须已重命名,并且可以选择移动。LayoutB就是一个例子;该结构被重命名为LayoutBB,并且向上移动了一个位置,但是它的所有字段都保持不变。

如果旧字段和新字段具有相同的名称和类型,则它们必须保持不变。在这种情况下,该字段可以移动。LayoutA::C就是一个这样的例子;字段名称和类型保持不变,但它移动了两个位置。

如果旧字段和新字段具有相同的名称,则它们必须是相同的字段。在这种情况下,我们接受类型转换,字段可能会被移动。LayoutA::A就是这样的一个例子;字段名称保持不变,但是它被下移了一个位置并进行了类型转换。

如果旧字段和新字段名称不同但类型相同,则该字段可能已被重命名。由于可以有多个相同类型的候选项,因此我们接受重命名