在Stack Overflow上向所有编译器设计者致意。
我目前正在开发一个项目,该项目专注于开发用于高性能计算的新脚本语言。首先将源代码编译成字节代码表示。然后运行时加载字节代码,它对它执行积极的(并且可能是耗时的)优化(这远远超过甚至大多数“提前”编译器所做的事情,毕竟这是在整个过程中的全部内容。项目)。请记住,此过程的结果仍然是字节代码。
然后在虚拟机上运行字节代码。目前,该虚拟机使用直接跳转表和消息泵来实现。虚拟机使用指针在字节代码上运行,在指针下加载指令,在跳转表中查找指令处理程序并跳转到它。指令处理程序执行适当的操作,最后将控制权返回给消息循环。虚拟机的指令指针递增,整个过程重新开始。我用这种方法实现的性能实际上非常惊人。当然,实际指令处理程序的代码再次手动微调。
现在,大多数“专业”运行时环境(如Java,.NET等)使用即时编译在执行前将字节代码转换为本机代码。使用JIT的VM通常比字节码解释器具有更好的性能。现在的问题是,因为所有解释器基本上都是加载一条指令并在跳转表中查找跳转目标(记住指令处理程序本身是静态编译到解释器中,所以它已经是本机代码),将使用即时编译会导致性能提升或实际上降低性能?我无法想象解释器的跳转表会降低 的性能,以弥补使用JITer编译该代码所花费的时间。我知道JITer可以对代码执行额外的优化,但在我的情况下,在执行之前已经在字节代码级别上执行了非常积极的优化。你认为我可以通过JIT编译器替换解释器来获得更快的速度吗?如果是这样,为什么?
我知道实施这两种方法和基准测试将为这个问题提供最准确的答案,但如果有明确的答案,可能不值得花时间。
感谢。
答案 0 :(得分:3)
答案在于单字节代码指令复杂性与跳转表开销的比率。如果您正在对大型矩阵乘法等高级操作进行建模,那么一点点开销将是微不足道的。如果你正在递增一个整数,那么当然这会受到跳转表的显着影响。总的来说,平衡将取决于语言使用的时间关键任务的性质。如果它是一种通用语言,那么因为你不知道在紧密循环中会使用什么,所以对于一切都有最小的开销更有用。要快速量化潜在的改进,只需对一些嵌套循环进行基准测试,然后执行一些简单的操作(但是那些无法优化的操作)与等效的C或C ++程序。
答案 1 :(得分:2)
使用解释器时,处理器中的代码缓存会缓存解释器代码;不是字节代码(可以缓存在数据缓存中)。由于代码缓存比数据缓存快2至3倍,因此IIRC;如果JIT编译,你可能会看到性能提升。此外,您正在执行的本机实际代码可能是PIC; JITted代码可以避免的事情。
其他一切都取决于字节码的优化程度,恕我直言。
答案 2 :(得分:1)
JIT理论上可以更好地优化,因为它具有在编译时不可用的信息(特别是关于典型的运行时行为)。因此,它可以做更好的分支预测,根据需要推出循环,等等。
我确信你的可跳转方法没问题,但我认为与直接C代码相比它会表现得相当差,你不觉得吗?