在C虚拟机中实现寄存器

jak*_*gut 6 memory performance assembly vm-implementation

我在C中编写了一个虚拟机作为业余爱好项目.此虚拟机执行的代码与Intel语法x86程序集非常相似.问题是这个虚拟机使用的寄存器只是名称中的寄存器.在我的VM代码中,寄存器与x86寄存器一样使用,但机器将它们存储在系统内存中.在VM代码中使用寄存器而非系统内存没有性能改进.(我认为只有地方才能提高性能,但在实践中,没有任何改变.)

在解释程序时,此虚拟机将指令的参数存储为指针.这允许虚拟指令获取内存地址,常量值,虚拟寄存器或几乎任何参数.

由于硬件寄存器没有地址,我想不出将VM寄存器实际存储在硬件寄存器中的方法.在我的虚拟寄存器类型上使用register关键字不起作用,因为我必须得到一个指向虚拟寄存器的指针才能将其用作参数.有没有办法让这些虚拟寄存器更像他们的原生对应物?

如果有必要的话,我很乐意钻研装配.我知道JIT编译这个VM代码可以让我使用硬件寄存器,但我希望能够将它们与我的解释代码一起使用.

zeu*_*xcg 8

  1. 机器寄存器没有索引支持:无论代码生成如何,您都无法使用运行时指定的"索引"访问该寄存器.由于您可能会从指令中解码寄存器索引,因此唯一的方法是进行大量切换(即switch (opcode) { case ADD_R0_R1: r[0] += r[1]; break; ... }).这可能是个坏主意,因为它会过多地增加解释器循环的大小,因此会引入指令缓存抖动.

  2. 如果我们谈论的是x86,那么额外的问题是通用寄存器的数量非常少; 其中一些将用于簿记(存储PC,存储您的VM堆栈状态,解码指令等) - 您不可能为VM提供多个免费注册.

  3. 即使注册索引支持可用,它也不太可能给你很多性能.通常在解释器中,最大的瓶颈是指令解码; x86支持基于寄存器值(即mov eax, dword ptr [ebx * 4 + ecx])的快速和紧凑的内存寻址,因此您不会赢得太多.虽然检查生成的程序集是值得的 - 即确保'寄存器池'地址存储在寄存器中.

  4. 加速口译员的最佳方法是JITting; 即使是简单的JIT(即没有智能寄存器分配 - 基本上只是发出与指令循环和switch语句一起执行的相同代码,除了指令解码)可以将性能提高3倍或更多(这些是来自简单JITter的实际结果)在类似Lua的基于寄存器的VM上.最好将解释器保留为参考代码(或者对于冷代码来降低JIT内存成本 - 对于简单的JIT,JIT生成成本不是问题).