【问题标题】:Decode and dispatch interpretation vs Threaded interpretation解码和调度解释 vs 线程解释
【发布时间】:2014-02-19 17:10:48
【问题描述】:

我试图了解解码和调度解释和线程解释在程序执行过程中的实际区别。

两者的例子真的很有帮助。

我了解 Java 字节码的工作原理以及汇编语言的工作原理。但是 DDI 和 TI 适合什么地方呢?

上下文:Virtual machines: versatile platforms for systems and processes

【问题讨论】:

    标签: compiler-construction operating-system interpretation


    【解决方案1】:

    (注意:我假设“解码和调度”是指基于开关的解释器。)

    基于开关的解释器和线程解释器在运行时的区别基本上在于执行的跳转次数。

    在基于开关的解释器中,指令在某个中心位置进行解码,并根据解码结果跳转到处理解码指令的代码段。一旦那段代码完成了对指令的解释,它就会跳回到集中解码代码,继续执行下一条指令。这意味着(至少)每个解释指令执行两次跳转。以下一段 C 代码说明了这种解释器的外观:

    typedef enum {
      add, /* ... */
    } instruction_t;
    
    void interpret() {
      static instruction_t program[] = { add /* ... */ };
      instruction_t* pc = program;
      int* sp = ...; /* stack pointer */
      for (;;) {
        switch (*pc++) {
          case add:
            sp[1] += sp[0];
            sp++;
            break;
            /* ... other instructions */
        }
      }
    }
    

    在线程解释器中,解码代码不是集中式的,而是在处理指令的每段代码的末尾复制。这意味着,一旦一条指令被解释,解释器不会跳回到某个集中的解码代码,而是解码下一条指令并立即跳转到它。在 ANSI-C 中有效地实现线程代码实际上是不可能的,但是 GCC 的“computed goto”扩展对此非常有效。这是之前解释器的线程版本:

    void interpret() {
      void* program[] = { &&l_add, /* ... */ };
      int* sp = ...;
      void** pc = program;
      goto **pc; /* jump to first instruction */
     l_add:
      sp[1] += sp[0];
      ++sp;
      goto **(++pc); /* jump to next instruction */
      /* ... other instructions */
    }
    

    除了保存跳转之外,这种线程解释器还更高效,因为现代 CPU 可以更好地预测复制的间接跳转(到下一条指令)。 Anton Ertl 在his home page 上有一些有趣的论文,尤其是那篇名为“The Structure and Performance of Efficient Interpreters”的论文,上面的代码片段就是从中改编而来的。

    【讨论】:

      猜你喜欢
      • 2015-03-16
      • 2017-06-04
      • 1970-01-01
      • 2010-09-16
      • 2015-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多