Question

J'essaie de comprendre la différence pratique lors de l'exécution d'un programme Décodage et interprétation expédition et interprétation hiérarchique .

Exemple de deux va vraiment aider.

Je comprends comment bytecode Java fonctionne et comment fonctionne en langage assembleur. Mais où est la place DDI et TI dans?

Contexte: Les machines virtuelles: polyvalent plates-formes pour les systèmes et les processus

Était-ce utile?

La solution

(Note:. Je suppose que par « decode et l'expédition » vous voulez dire un interprète à base de commutation)

La différence entre une base de commutateur et un interpréteur fileté au moment de l'exécution est, en gros, le nombre de sauts qui sont effectuées.

Dans un interprète basé commutation, les instructions sont décodées à un emplacement central, et en fonction du résultat du décodage, un saut est effectué vers le morceau de code qui gère l'instruction décodée. Une fois que ce morceau de code a fini d'interpréter l'instruction, il revient au code de décodage centralisé, qui procède à l'instruction suivante. Cela signifie que (au moins) deux sauts sont effectués par l'instruction interprétée. La pièce de code suivant C illustre ce qu'un tel interprète pourrait ressembler à:

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

Dans un interprète fileté, le code de décodage est pas centralisée, mais plutôt en double à la fin de chaque morceau de code qui gère une instruction. Cela signifie qu'une fois qu'une instruction a été interprétée, au lieu de sauter en arrière à un code de décodage centralisé, l'interprète décode l'instruction suivante et passe immédiatement à elle. La mise en œuvre du code fileté de manière efficace dans la norme ANSI-C est pas vraiment possible, mais l'extension « goto calculée » de GCC fonctionne très bien pour cela. Voici une version filetée de l'interpréteur précédent:

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

En dehors de l'enregistrement d'un saut, les interprètes filetés sont également plus efficaces parce que le saut indirect répliqué (à l'instruction suivante) peut être prédit mieux par les processeurs modernes. Anton Ertl a quelques articles intéressants sur sa page d'accueil , en particulier celui appelé « La structure et la performance des interprètes efficace », à partir de laquelle les pièces ci-dessus ont été adaptées de code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top