2011-06-21 57 views
22

我们正在为高级编译语言编写一个字节码,经过一些分析和优化后,很明显,当前最大的性能开销是我们使用的switch语句跳转到字节码的情况。标签地址(MSVC)

我们调查了拔出每个案例标签的地址并将其存储在字节码本身的流中,而不是我们通常打开的指令ID。如果我们这样做了,我们可以跳过跳转表,直接跳到当前正在执行的指令的代码位置。这在GCC中非常有效,但是,MSVC似乎不支持这样的功能。

我们试图使用内联汇编来获取标签的地址(并跳转到它们),并且它可以工作,但是,使用内联汇编会导致MSVC优化器避免整个函数。

有没有办法让优化器仍然运行代码?不幸的是,我们不能将内联程序集提取到另一个函数中,而不是标签所在的函数,因为即使在内联程序集中,也无法为另一个函数引用标签。任何想法或想法?非常感谢您的意见,谢谢!

+3

您是否尝试过函数指针? –

+0

如何在字节码中放置函数地址而不是标签地址?然后,每个指令ID都有一个函数。除非你的获取执行循环在你的大功能标签中。 –

+0

如果我使用每种情况下的函数,并使用函数指针而不是标签地址,它将起作用。但是,我觉得函数调用的开销会非常大,即使函数是微不足道的(无参数,不返回),也会使性能增益无效。我会尝试一下,并感谢张贴。 – Trevor

回答

15

在MSVC这样做的唯一方法是使用内联汇编(这基本上家伙,你针对x64):

int _tmain(int argc, _TCHAR* argv[]) 
{ 
case_1: 
    void* p; 
    __asm{ mov [p],offset case_1 } 
    printf("0x%p\n",p); 
    return 0; 
} 

如果你打算做这样的事情,那么最好的办法是写整个解释器在汇编中,然后通过链接器连接到主要的二进制文件(这是LuaJIT做的,这是虚拟机非常快速的主要原因,当它没有运行JIT'ed代码时)。

LuaJIT is open-source,所以你可能会从中选择一些提示,如果你走的路线。或者,您可能需要查看第四个源代码(其创建者开发的the principle您正在尝试使用),如果有MSVC版本,您可以看到它们是如何实现的,否则您会被GCC卡住(其中并不是这样, t是一件坏事,它适用于所有主要平台)。

3

看来你可以将实际的代码移动到函数而不是案例标签。字节码然后可以简单地转换成直接调用。即字节码1将转换为CALL BC1。由于您正在生成直接调用,因此您没有函数指针的开销。大多数CPU的管道可以遵循这种无条件的直接分支。因此,每个字节代码的实际实现都经过优化,从字节代码到machince代码的转换是一个微不足道的1:1转换。由于每个CALL都是5个字节(假设为x86-32),所以您得到了一些代码扩展,但这不太可能是一个主要问题。