我的项目有一个VM,它执行从特定于域的语言编译的字节码。我正在寻找可以改善字节码执行时间的方法。作为第一步,我想看看在进入机器代码编译之前是否有办法简单地改进字节码解释器。
解释器的主循环如下所示:
while(true)
{
uint8_t cmd = *code++;
switch( cmd )
{
case op_1: ...; break;
...
}
}
问题:有没有更快的方法来实现这个循环而不需要使用汇编程序?
我看到的一个选项是GCC,专门用于使用标签地址的动态转到。我可以直接跳到下一条指令而不是每个案例末尾的break
。我曾希望优化器会为我做这个,但是看看反汇编它显然不会:大多数op_codes结束时会有一个重复的持续跳转。
如果相关,VM是一个简单的基于寄存器的机器,具有浮点和整数寄存器(每个寄存器8个)。没有堆栈,只有一个全局堆(该语言并不复杂)。
答案 0 :(得分:3)
一个非常简单的优化是代替 开关/外壳/外壳/外壳/外壳/外壳,
只需定义一个带有函数指针的数组(其中每个函数都会处理一个指定的命令,或者几个命令,在这种情况下你可以将数组中的几个条目设置为同一个函数,函数本身可以检查确切的代码),而不是
switch(cmd)
只做一个
array[cmd]()
这是因为你没有太多的命令。另外,做一些检查是否你不会定义所有可能的命令(也许你只有300个命令,但你必须使用2个字节来表示它们,所以不要用65536个项目来定义一个数组,只需检查命令是否少于超过301,如果不是,不要查找)
如果你不这样做,至少要对switch语句开头最常用的命令进行排序。
否则就是要查看哈希表,但我假设你没有那么多命令,在这种情况下,做哈希函数的开销可能会花费你更多而不是不必进行切换。 (或者有一个非常简单的哈希函数)
答案 1 :(得分:1)
架构是什么?你可以通过字对齐的操作码加速,但它会破坏你的代码大小,这意味着你必须平衡它与高速缓存未命中的成本。
答案 2 :(得分:-1)
我看到的很少有明显的优化,
cmd
之外的地方使用switch()
,请直接使用指针间接switch( *code++ )
。对于较长的while(true)
循环,这可能没什么用处。switch()
中,您可以使用continue
代替break
。因为在continue
或if/else
中使用switch
时,编译器知道执行必须跳转到外部循环;同样不适用于break
(相对于switch
)。
希望这会有所帮助。