什么操作码调度策略用于高效的解释器?

时间:2009-02-04 14:24:46

标签: optimization interpreter

哪些技术可以促进高效的操作码调度以快速翻译?是否有一些技术仅适用于现代硬件,而其他技术因硬件的进步而无法正常工作?在易于实施,速度和可移植性之间必须做出哪些权衡?

我很高兴Python的C实现最终超越了一个简单的switch (opcode) {...}实现操作码调度到间接线程作为编译时选项,但我不太高兴他们用了20年才到达那里。也许如果我们在stackoverflow上记录这些策略,下一种语言的速度会更快。

8 个答案:

答案 0 :(得分:13)

关于不同类型的派遣,有很多论文:

微米。 Anton Ertl和David Gregg,Optimizing Indirect Branch Prediction Accuracy in Virtual Machine Interpreters,参见ACM SIGPLAN 2003会议编程语言设计与实现会议(PLDI 03),第278-288页,加利福尼亚州圣地亚哥,2003年6月。

微米。 Anton Ertl和David Gregg, The behaviour of efficient virtual machine interpreters on modern architectures,参见第7届欧洲并行计算会议论文集(Europar 2001),第403-412页,LNCS 2150,曼彻斯特,2001年8月。

Yunhe Shi in his PhD thesis提供了一个很好的摘要。

此外,几年前someone discovered a new technique是有效的ANSI C。

答案 1 :(得分:6)

当你开始任何事情时,请检查Lua

它很小(150Kb),纯ANSI C,适用于任何具有C编译器的东西。非常快。

最重要的是 - 源代码清晰易读。值得一试。

答案 2 :(得分:4)

间接线程是一种策略,其中每个操作码实现都有自己的JMP到下一个操作码。 Python解释器的补丁看起来像这样:

add:
    result = a + b;
    goto *opcode_targets[*next_instruction++];

opcode_targets将语言字节码中的指令映射到操作码实现的内存中。这更快,因为处理器的分支预测器可以对每个字节码进行不同的预测,而只有一个分支指令的switch语句。

编译器必须支持计算goto才能工作,这主要是指gcc。

直接线程类似,但在直接线程中,操作码数组被替换为指向操作码实现的指针,如下所示:

goto *next_opcode_target++;

这些技术仅有用,因为现代处理器是流水线的,必须在错误预测的分支上清除它们的管道(缓慢)。处理器设计人员进行分支预测以避免必须经常清除管道,但分支预测仅适用于更有可能采用特定路径的分支。

答案 3 :(得分:3)

Just-in-time compilation就是一个。

答案 4 :(得分:1)

一个重要的胜利是以中间形式存储源代码,而不是在执行期间重做词法分析和解析。

这可以从存储令牌,通过Forth样式的线程代码到JIT编译一直到。

答案 5 :(得分:0)

基准测试是在给定平台上快速制作任何东西的好方法。测试,完善,再次测试,改进。

我认为你不能得到任何更好的答案。制作口译员有很多技巧。但是我给你一个提示,不做权衡,只选择你真正需要的东西并追求这些目标。

答案 6 :(得分:0)

我发现了一篇关于线程解释器实现的博客文章很有用。

作者描述了基于GCC标签的线程以及如何使用内联汇编程序在Visual Studio中执行此操作。

http://abepralle.wordpress.com/2009/01/25/how-not-to-make-a-virtual-machine-label-based-threading/

结果很有趣。他报告使用GCC时性能提高了33%,但令人惊讶的是Visual Studio内联汇编实现速度慢了3倍!

答案 7 :(得分:-1)

问题有点模糊。但是,似乎你在考虑写一个翻译。

解释器通常使用传统的解析组件:词法分析器,解析器和抽象语法树(AST)。这允许设计者读取和解释有效语法,并使用相关的运算符,参数等构建命令的树结构。

一旦进入AST格式,整个输入就会被标记化,解释器可以通过遍历树开始执行。

有很多选项,但我最近使用ANTLR作为解析器生成器,可以使用各种目标语言构建解析器,包括C / C ++和C#。