Pregunta

Estoy tratando de entender la diferencia práctica durante la ejecución de un programa en Decodificación y despacho interpretación e interpretación roscado .

Ejemplo de ambos realmente ayudará.

Me entender cómo Java bytecode obras y cómo funciona un lenguaje ensamblador. Pero ¿de dónde viene DDI y TI en todo esto?

Contexto: máquinas virtuales: versátil plataformas de sistemas y procesos

¿Fue útil?

Solución

(Nota:. Vamos a suponer que por "decodificar y despacho" quiere decir un intérprete basada en conmutadores)

La diferencia entre una basada en conmutadores y un intérprete de roscado en tiempo de ejecución es, básicamente, el número de saltos que se realizan.

En un intérprete basada en conmutadores, las instrucciones se descodifican en algún lugar central, y en base al resultado de la decodificación, un salto se lleva a cabo a la pieza de código que se encarga de la instrucción decodificada. Una vez que la pieza de código ha terminado la interpretación de la instrucción, se salta de nuevo a la decodificación del código centralizado, que procede con la siguiente instrucción. Esto significa que (al menos) dos saltos se realizan por instrucción interpretado. El siguiente fragmento de código C ilustra lo que un intérprete por ejemplo podría ser:

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 */
    }
  }
}

En un intérprete de roscado, el código de decodificación es no centralizada, sino más bien duplica en el extremo de cada pieza de código que controla una instrucción. Esto significa que una vez que una instrucción ha sido interpretada, en vez de saltar de nuevo a la decodificación de un código centralizado, el intérprete decodifica la siguiente instrucción y de inmediato salta a ella. La implementación de código roscado de manera eficiente en ANSI-C no es realmente posible, pero la extensión "goto calculado" de GCC funciona muy bien para eso. He aquí una versión roscada del intérprete anterior:

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 */
}

Además de ahorrar un salto, tales intérpretes roscados también son más eficientes porque el salto indirecto replicado (a la siguiente instrucción) puede predecirse mejor por las CPU modernas. Antón Ertl tiene algunos interesantes documentos sobre la su página de inicio , especialmente el llamado "La estructura y el funcionamiento de Intérpretes eficiente", de la que se adaptan las piezas anteriores de código.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top