optimization - 字节码如何用于优化动态语言的执行时间?

标签 optimization bytecode vm-implementation

我对一些优化方法或通用字节码设计感兴趣,与 AST 的解释相比,它们可能有助于加快使用 VM 的执行速度。

最佳答案

AST 解释与字节码的主要胜利是操作调度成本,对于高度优化的解释器,这开始成为一个真正的问题。 "dispatch"是用于描述开始执行操作(例如算术、属性访问等)所需的开销的术语。

一个相当普通的基于 AST 的解释器看起来像这样:

class ASTNode {
    virtual double execute() = 0;
}

class NumberNode {
    virtual double execute() { return m_value; }
    double m_value;
}

class AddNode {
    virtual double execute() { return left->execute() + right->execute(); }
}

因此,执行像 1+1 这样简单的代码需要 3 个虚拟调用。由于进行调用的多个间接调用,以及首先进行调用的一般成本,虚拟调用非常昂贵(从总体上看)。

在字节码解释器中,你有一个不同的调度模型——而不是虚拟调用,你有一个执行循环,类似于:
while (1) {
    switch (op.type) {
        case op_add:
            // Efficient interpreters use "registers" rather than
            // a stack these days, but the example code would be more
            // complicated
            push(pop() + pop());
            continue;
        case op_end:
            return pop();
    }
}

与 native 代码相比,这仍然具有相当昂贵的调度成本,但比虚拟调度快得多。您可以使用名为“computed goto”的 gcc 扩展进一步提高性能,它允许您删除开关调度,将总调度成本降低到基本上单个间接分支。

除了提高调度成本之外,基于字节码的解释器与 AST 解释器相比还有许多额外的优势,主要是由于字节码能够像真机一样“直接”跳转到其他位置,例如想象这样的代码片段:
while (1) {
    ...statements...
    if (a)
        break;
    else
        continue;
}

为了在每次执行语句时正确实现这一点,您需要指出执行是停留在循环中还是停止,因此执行循环变为:
while (condition->execute() == true) {
    for (i = 0; i < statements->length(); i++) {
        result = statements[i]->execute();
        if (result.type == BREAK)
            break;
        if (result.type == CONTINUE)
            i = 0;
    }
}

随着您添加更多形式的流量控制,这种信令变得越来越昂贵。一旦您添加了异常(例如,可能在任何地方发生的流控制),您就开始需要在基本算术的中间检查这些东西,从而导致开销不断增加。如果您想在现实世界中看到这一点,我鼓励您查看 ECMAScript 规范,它们根据 AST 解释器描述了执行模型。

在字节码解释器中,这些问题基本上消失了,因为字节码能够直接表达控制流,而不是通过信令间接表达,例如。 continue简单地转换为跳转指令,并且只有在实际命中时才会获得该成本。

最后,AST 解释器根据定义是递归的,因此必须防止溢出系统堆栈,这对您可以在代码中递归的程度施加了非常严格的限制,例如:
1+(1+(1+(1+(1+(1+(1+(1+1)))))))

在解释器中有 8 级递归(至少)——这可能是一个非常大的成本;旧版本的 Safari(SquirrelFish 之前)使用 AST 解释器,因此 JS 只允许几百级递归,而现代浏览器允许 1000 级。

关于optimization - 字节码如何用于优化动态语言的执行时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3588693/

相关文章:

java - C++/ java : Efficiently find a set in the collection containing given value

c - 在医学图像重建实现中改善局部性并减少缓存污染

compiler-construction - 将 LLVM/CLANG 用于自定义字节码 VM 的程序的大小是多少?

使用 += 运算符的 Java 最佳实践

java - Hibernate 5 字节码增强关联管理仅朝一个方向工作

compiler-construction - 使用哈希表在类中存储方法有什么优点?

performance - 有哪些不同的技术可以使超形态调用站点更加高效

javascript - 优化 Jquery 代码 - 单击时添加和删除类

python - 优化大量数据的搜索和插入操作

java - 如何修复反编译 .class 为 .java 错误