Comment fonctionne exactement l'interpréteur Java ou tout interpréteur?


J'ai trouvé le travail d'un interprète, ont googlé autour et ont abouti à une conclusion, je voulais juste qu'il soit corrigé par quelqu'un qui peut me donner une meilleure compréhension du travail de l'interprète.

Donc ce que j'ai compris est:

  1. Un interpréteur est un logiciel qui convertit le code de haut niveau langue au format machine.
  2. en parlant spécifiquement de l'interpréteur java, il obtient du code au format binaire (ce qui est auparavant traduit par le compilateur java du code source au bytecode).
  3. maintenant, la plate-forme pour un interpréteur java est la JVM, dans laquelle elle s'exécute, donc fondamentalement, il va produire du code qui peut être exécuté par JVM.
  4. donc il prend le bytecode produit du code intermédiaire et la machine cible code et le donne à JVM.
  5. JVM exécute à son tour ce code sur la plate-forme du système d'exploitation dans laquelle JVM est mis en œuvre ou en cours d'exécution.

Maintenant, je ne suis toujours pas clair avec le sous-processus qui se produit entre les deux, c'est-à-dire

  1. l'interpréteur produit du code intermédiaire.
  2. le code interprété est alors optimisé.
  3. , puis le code cible est généré
  4. et finalement exécuté.

Quelques questions supplémentaires:

  • l'interpréteur est donc seul responsable de la génération du code cible ? et l'exécution ?
  • et l'exécution signifie-t-elle qu'elle est exécutée dans la JVM ou dans le système d'exploitation sous-jacent ?
Author: Gray, 2017-05-09

4 answers

Un interpréteur est un logiciel qui convertit le code d'un langage de haut niveau au format machine.

Non. C'est un compilateur. Un interpréteur est un programme informatique qui exécute les instructions écrites dans un langage. Voir wikipedia. Ceci est différent d'un compilateur qui convertit un langage de niveau supérieur en un langage inférieur. Le compilateur C passe du C au code assembleur avec l'assembleur (un autre type de compilateur) traduit de l'assembly en le code machine. En Java, le compilateur java vérifie le code et convertit la source en bytecode.

Maintenant, la plate-forme pour un interpréteur java est la JVM, dans laquelle elle s'exécute, donc fondamentalement, elle va produire du code qui peut être exécuté par la JVM.

La JVM fonctionne directement sur le bytecode. L'interpréteur java est intégré si étroitement avec la JVM qu'ils ne devraient pas vraiment être considérés comme des entités distinctes. Ce qui se passe aussi est une tonne de merde d'optimisation où le bytecode est essentiellement optimisé (pensez à cc -O3) et intégré à la volée. Cela rend l'appeler juste un interprète semble inadéquat.

Il prend donc le bytecode produit du code intermédiaire et le code machine cible et le donne à la JVM.

La JVM effectue ces traductions.

JVM exécute à son tour ce code sur la plate-forme du système d'exploitation dans laquelle la JVM est implémentée ou en cours d'exécution.

Je préfère dire que la JVM utilise le bytecode, utilisateur optimisé code, les bibliothèques java qui incluent java et le code natif, en conjonction avec les appels de système d'exploitation pour exécuter des applications java.

Maintenant, je ne suis toujours pas clair avec le sous-processus qui se produit entre les deux, c'est-à-dire 1. l'interpréteur produit du code intermédiaire. 2. le code interprété est ensuite optimisé. 3. ensuite, le code cible est généré 4. et finalement exécuté.

Non. Le compilateur Java génère du bytecode. Lorsque la JVM exécute le code, les étapes 2 à 4 se produisent lors de l'exécution à l'intérieur de la JVM. Il est très différent de C (par exemple) qui a ces étapes distinctes exécutées par différents utilitaires. Ne pensez pas à cela comme des "sous-processus".

L'interpréteur est-il donc seul responsable de la génération du code cible ? et de l'exécution ?

Oui bien qu'à un moment donné le système d'exploitation et le PROCESSEUR entrent en vigueur.

Et l'exécution signifie-t-elle qu'elle est exécutée dans la JVM ou dans le système d'exploitation sous-jacent ?

Euh, il est exécuté par / dans la JVM qui est en cours d'exécution en tant que processus à l'intérieur d'un système d'exploitation avec le CPU et le reste de l'architecture matérielle responsable de l'exécution du code machine.

 4
Author: Gray, 2017-05-09 13:40:20

1) Un interpréteur est un logiciel qui convertit le code d'un langage de haut niveau au format machine.

Incorrect. Un interpréteur est un programme qui exécute un programme exprimé dans un langage qui n'est PAS le code machine natif de l'ordinateur.

Il peut y avoir une étape de ce processus dans laquelle la langue source est analysée et traduite dans une langue intermédiaire, mais ce n'est pas une exigence fondamentale pour un interprète. Dans le Java cas, le langage bytecode a été conçu de sorte que ni l'analyse syntaxique ni un langage intermédiaire distinct ne sont nécessaires.

2) parlant spécifiquement de l'interpréteur java, il obtient du code au format binaire (qui est précédemment traduit par le compilateur java du code source au bytecode).

Correcte. Le "format binaire" est des bytecodes Java.

3) maintenant, la plate-forme pour un interpréteur java est la JVM, dans laquelle elle s'exécute, donc fondamentalement, elle va produire code qui peut être exécuté par JVM.

Incorrect. L'interpréteur de bytecode est une partie de la JVM. L'interpréteur ne s'exécute pas sur la JVM. Et l'interpréteur de bytecode ne produit rien. Il suffit que exécute les bytecodes.

4) il prend donc le bytecode produit du code intermédiaire et le code machine cible et le donne à la JVM.

Incorrect.

5) JVM exécute à son tour ce code sur la plate-forme OS dans laquelle JVM est mis en œuvre ou en cours d'exécution.

Incorrect.

La vraie histoire est la suivante:

  • La JVM a un certain nombre de composants.
  • Un composant est l'interpréteur de bytecode. Il exécute les bytecodes à peu près directement1. Vous pouvez considérer l'interpréteur comme un émulateur pour un ordinateur abstrait dont le jeu d'instructions est constitué de bytecodes.
  • Un deuxième composant est le compilateur JIT. Cela traduit les bytecodes en code machine natif de la machine cible afin qu'il puisse être exécuté par le matériel cible.

1 - Un interpréteur de bytecode typique effectue un travail pour mapper des cadres de pile abstraits et des dispositions d'objets à des cadres concrets impliquant des tailles et des décalages spécifiques à la cible. Mais appeler cela un "code intermédiaire" est un étirement. L'interpréteur est vraiment juste améliorant les bytecodes.

 4
Author: Stephen C, 2017-05-09 13:55:04

Donnant une vue de 1000 pieds qui, espérons-le, éclaircira les choses:

Il y a 2 étapes principales d'une application java: compilation, et runtime. Chaque processus a des fonctions et des objectifs très différents. Les principaux processus pour les deux sont décrits ci-dessous:

Compilation

  • Ceci est (normalement) exécuté par [com.sun.tools.javac][1] habituellement trouvé dans les outils.fichier jar, traditionnellement dans votre JAV JAVA_HOME - au même endroit que java.jar, etc.
  • Le but ici est de traduire .fichiers source java dans .fichiers de classe qui contiennent la "recette" pour l'environnement d'exécution java.

Étapes de compilation:

  1. Analyse: les fichiers sont lus et dépouillés de leurs caractères de syntaxe "limites", tels que les accolades, les points-virgules et les parenthèses. Ceux-ci existent pour dire à l'analyseur dans quel objet java traduire chaque composant source (plus à ce sujet dans le point suivant).
  2. AST creation : L'arbre de syntaxe abstraite est la façon dont un fichier source est représenté. Il s'agit d'une structure de données "arborescente" littérale, et la classe racine pour cela est [com.sun.tools.JCTree][3]. L'idée générale est qu'il existe un objet java pour chaque Expression et chaque Instruction. À ce stade, on sait relativement peu de choses sur les "types" réels que chacun représente. La seule chose qui est vérifiée lors de la création de l'AST est la syntaxe littérale
  3. Desugar : C'est là pour les boucles et autres syntaxiques le sucre est traduit sous une forme plus simple. Le langage est toujours sous forme d'arbre et non de bytecode, ce qui peut facilement se produire
  4. Vérification de type / Inférence: Où le compilateur devient complexe. Java est un langage statique, donc le compilateur doit passer en revue l'AST en utilisant le modèle de visiteur et déterminer les types de tout avant tim et s'assurer qu'à l'exécution tout (enfin, presque) sera légal en ce qui concerne les types, les signatures de méthode, etc. aller. Si quelque chose est trop vague ou invalide, la compilation échoue.
  5. Bytecode : Le flux de contrôle est vérifié pour s'assurer que la logique d'exécution du programme est valide (pas d'instructions inaccessibles, etc.) Si tout passe les contrôles sans erreurs, alors l'AST est traduit en bytecodes que le programme représente.
  6. .écriture de fichier de classe: à ce stade, les fichiers de classe sont écrits. Essentiellement, le bytecode est une petite couche d'abstraction au-dessus de specialized le code machine. Cela permet de porter sur d'autres machines/structures CPU/plates-formes sans avoir à se soucier des différences relativement faibles entre elles.

Runtime

Aussi...

    L'API du compilateur Java a été normalisée sous JSR 199. Bien que ne relevant pas exactement de la même chose (impossible de trouver le JLS exact), de nombreux autres langages et outils exploitent le processus/API de compilation standardisé afin d'utiliser la technologie avancée JVM (runtime) fournie par Oracle, tout en permettant une syntaxe différente.
    • Voir Scala, Groovy, Kotlin, Jython, JRuby, etc. Tous ces éléments tirent parti de l'environnement d'exécution Java car ils traduisent leur syntaxe différente pour être compatibles avec l'API du compilateur Java! C'est assez soigné - n'importe qui peut écrire un langage haute performance avec la syntaxe qu'il veut en raison du découplage des deux. Il y a des adaptations pour presque toutes les langues pour le JVM
 3
Author: Preston Garno, 2017-05-23 11:54:54

Je vais répondre en fonction de mon expérience sur la création d'un DSL.

C est compilé parce que vous exécutez passer le code source au gcc et exécute le programme stocké dans le code machine.

Python est interprété parce que vous exécutez des programmes en passant la source du programme à l'interpréteur. L'interpréteur lit le fichier source et l'exécute.

Java est un mélange des deux car vous "compilez" le fichier Java en bytecode, puis invoque la JVM pour l'exécuter. Le bytecode n'est pas du code machine, il doit être interprété par la machine virtuelle java. Java est à un niveau entre C et Python car vous ne pouvez pas faire des choses fantaisistes comme une "eval" (évaluation de morceaux de code ou d'expressions à l'exécution comme en Python). Cependant, Java a des capacités de réflexion qui sont impossibles à un programme C. En bref, la conception de Java runtime étant dans un niveau intermédiaire entre un langage compilé pur et un langage interprété donne le meilleur (et le pire) des deux mots en termes de performance et de flexibilité.

Cependant, Python a également une machine virtuelle et son propre format de bytecode. Il en va de même pour Perl, Lua, etc. Ces interprètes convertissent d'abord un fichier source en bytecode, puis interprètent le bytecode.

Je me suis toujours demandé pourquoi cela était nécessaire, jusqu'à ce que je fasse mon propre interprète pour une simulation DSL. Mon interprète fait une analyse lexicale (casser une source en jetons), la convertit en un arbre de syntaxe abstraite, puis il évalue l'arbre en le parcourant. Pour le génie logiciel je suis l'utilisation de certains modèles de conception et mon code utilise fortement le polymorphisme. C'est très lent par rapport au traitement d'un format de bytecode efficace qui imite une architecture informatique réelle. Mes simulations seraient beaucoup plus rapides si je créais ma propre machine virtuelle ou en utilisais une existante. Pour évaluer une expression numérique longue, par exemple, il sera plus rapide de la traduire en quelque chose de similaire au code assembleur que de traiter une branche d'un arbre abstrait, car cela nécessite d'appeler beaucoup de polymorphes méthode.

 1
Author: Danilo M. Oliveira, 2017-05-10 08:13:25