JavaScript est-il interprété par la conception?

73

Je suis prudent de poser cette question parce qu'elle pourrait paraître trop fastidieuse. Je viens d'ouvrir JavaScript: The Definitive Guide, et il est indiqué à la première page du chapitre 1

"JavaScript est un langage de programmation interprété de haut niveau, dynamique et non typé"

Je suppose donc que la partie interprétée est une exigence de la spécification du langage ou est-il trompeur de dire que le langage est un langage de programmation interprété dans le respect de la différence entre un langage et ses nombreuses implémentations?

Apparemment, il n'y a pas de compilateurs statiques pour JavaScript - https://stackoverflow.com/questions/1118138/is-there-a-native-machine-code-compiler-for-javascript donc c'est peut-être juste un reflet de cela.

Matt Esch
la source
Pendant un certain temps, jscript.net était similaire à AS3 / "perdu" ES4. Il a été compilé en bytecode dans CIL.
13
V8 prétend explicitement ne pas être un interprète mais un compilateur.
pimvdb
@GGG JScript.Net est toujours en vie et ... maladif. Mais toujours en vie. msdn.microsoft.com/fr-fr/bibliotheque/72\15a.aspx
Jetti
1
FWIW, le bit "non typé" n'est pas tout à fait vrai non plus
Rob Agar
Firefox venait de publier le premier compilateur JIT basé sur un navigateur l'année où cette question recevait une réponse dans FF 3.5; elle n'était donc probablement pas très connue à l'époque. Je crois que les JIT modernes font beaucoup de compilation (ou au moins de préparation pour la compilation) lors du premier passage d'un document JS pour faire des choses comme identifier et mettre en cache des méthodes qui sont isolées à une portée donnée.
Erik Reppen

Réponses:

50

Je suppose donc que la partie interprétée est une exigence de la spécification du langage ou est-il trompeur de dire que le langage est un langage de programmation interprété dans le respect de la différence entre un langage et ses nombreuses implémentations?

Langage EcmaScript Les geeks utilisent souvent le terme "interprète ES" pour faire référence à une implémentation d'EcmaScript, mais la spécification n'utilise pas ce terme. L’ aperçu de la langue en particulier décrit la langue en termes interprète-agnostique:

ECMAScript est basé sur les objets: le langage de base et les fonctions d’hôte sont fournies par des objets, et un programme ECMAScript est un cluster d’objets communicants.

EcmaScript suppose donc un "environnement hôte" défini en tant que fournisseur de définitions d'objet, y compris toutes celles qui autorisent les E / S ou tout autre lien avec le monde extérieur, mais ne nécessite pas d'interprète.

La sémantique des instructions et des expressions dans le langage est définie en termes de spécification de complétude qui est implémentée de manière triviale dans un interpréteur, mais la spécification ne l'exige pas.

8.9 Le type de spécification d'achèvement

Le type d'achèvement est utilisé pour expliquer le comportement des déclarations ( break, continue, returnet throw) qui effectuent des transferts non locaux de contrôle. Les valeurs du type Completion sont des triples de la forme ( type , valeur , cible ), où type est l'une des valeurs suivantes : normal , pause , continuer , retour ou projection , valeur est n'importe quelle valeur de langage ECMAScript ou vide , et cible est tout identificateur ECMAScript ou vide .

Le terme «achèvement brutal» désigne tout achèvement avec un type autre que normal .

Les transferts de contrôle non locaux peuvent être convertis en tableaux d'instructions avec des sauts permettant une compilation en code natif ou par octet.

"Moteur EcmaScript" pourrait être un meilleur moyen d’exprimer la même idée.


Il n'y a apparemment aucun compilateur statique pour JavaScript

Ce n'est pas vrai. L '"interpréteur" V8 compile en interne en code natif, Rhino en option compile en interne en octetcode Java et divers interprètes de Mozilla ({Trace, Spider, Jager} Monkey) utilisent un compilateur JIT.

V8 :

V8 augmente les performances en compilant JavaScript en code machine natif avant de l'exécuter, par opposition à l'exécution de bytecode ou à son interprétation.

Rhinocéros :

public final void setOptimizationLevel(int optimizationLevel)

Définissez le niveau d'optimisation actuel. Le niveau d'optimisation devrait être un entier compris entre -1 et 9. Toute valeur négative sera interprétée en tant que -1 et toute valeur supérieure à 9 sera interprétée en 9. Un niveau d'optimisation de -1 indique que le mode d'interprétation sera toujours utilisé. Les niveaux 0 à 9 indiquent que des fichiers de classe peuvent être générés. Des niveaux d’optimisation plus élevés compromettent les performances de temps de compilation et d’exécution. Le niveau d'optimisation ne peut pas être supérieur à -1 si le package d'optimiseur n'existe pas au moment de l'exécution.

TraceMonkey :

TraceMonkey ajoute la compilation de code natif au moteur JavaScript® de Mozilla (connu sous le nom de «SpiderMonkey»). Il est basé sur une technique mise au point par l’UC Irvine, appelée «arbre à traces», et repose sur le code et les idées partagés avec le projet Tamarin Tracing. Le résultat net est une augmentation massive de la vitesse du contenu du navigateur et du contenu des pages Web.

Mike Samuel
la source
1
Merci pour cette réponse, cela répond effectivement à la question. Je suppose que le dernier commentaire sur l'absence de compilation statique est ce qui a provoqué le buzz sur les implémentations qui compilent réellement le code et celles qui ne le font pas. Tout ce qui m'intéressait était la validité de la déclaration "JavaScript est un langage interprété" qui, étant donné les citations d'implémentation et l'absence de définition par la spécification, semble être fausse. Ce n'est pas encourageant pour le deuxième paragraphe d'un "Guide définitif", mais je suppose que je vais m'en tenir à cela.
Matt Esch
@ me232, la déclaration était en grande partie vraie avant 2008. Rhino est un ancien interprète, mais très peu auraient reproché au "Guide définitif" de l'ignorer. Je n'ai pas lu le livre, je ne peux donc pas dire à quel point cette phrase est représentative de sa qualité générale.
Mike Samuel
Quelle est la définition de "compilateur statique". Je pensais que cette définition signifiait que la compilation ne se produisait qu’une seule fois et que vous obteniez un seau de bits statique (c’est-à-dire invariable) que vous exécutiez ensuite. Autant que je sache, ce n'est pas ainsi que fonctionne un moteur JavaScript. C'est pourquoi ils ont des de-optimizationmarches. En d'autres termes, JavaScript est compilé par ces moteurs, mais il n'est pas compilé de manière statique.
Gman
@gman, le générateur de bytecode de Rhino fonctionne de cette manière.
Mike Samuel
Autant que je sache, ce n'est pas le cas. Rhino peut inclure d'autres fichiers JavaScript qui doivent être compilés au moment de l'exécution. Ce n'est pas une complication statique .
Gman
20

La machine virtuelle JavaScript V8 utilisée dans Chrome n'inclut pas d'interprète. Au lieu de cela, il se compose de deux compilateurs et compile le code à la volée. L'un des compilateurs s'exécute rapidement mais génère un code inefficace, l'autre est un compilateur d'optimisation.

Je peux comprendre pourquoi certaines personnes considéreraient cela comme une "triche", puisque la V8 prend le code source en entrée à chaque exécution du code et que l'utilisateur doit installer la V8. Mais considérons un compilateur qui émet un fichier exécutable comprenant un interpréteur complet et un code octet. Ensuite, vous auriez un programme autonome. Ce ne serait tout simplement pas très efficace.

Jørgen Fogh
la source
19

L'émergence des compilateurs JIT pour les langages de script a brouillé la frontière entre compilation et interprétation à un point tel que la question ne veut plus dire grand chose. Est-ce seulement une interprétation lorsque le moteur lit une ligne de code et l'exécute immédiatement? (Les scripts shell sont toujours généralement implémentés de cette manière.) Est-ce une interprétation lorsque le moteur prend tout le fichier, le compile immédiatement en un code octet, puis interprète le code octet? (Le moteur Mozilla de première étape fonctionne ainsi, à l'instar de CPython.) S'agit-il d'une interprétation lorsque le moteur analyse une fonction à la fois et que JIT le compile en code natif? Qu'en est-il des moteurs qui compilent l'intégralité du fichier en code octet, puis exécutent une fonction à la fois selon les besoins? (La plupart des moteurs de script fonctionnent de cette façon,

Il y a beaucoup de nuances entre la compilation et l'interprétation.

Je pense que la définition la plus utile pour l'interprétation est "est alimenté le code source du programme au moment de l'exécution, sans étape d'avance séparée". Par cette définition, tous les moteurs JavaScript sont des interprètes. Mais ce n’est certainement pas la seule définition possible de l’interprétation.

Mais JavaScript est-il conçu pour l'interprétation? En un sens, oui: il possède une evalfonction ainsi que le Functionconstructeur que vous pouvez donner au code du programme sous forme de chaîne à exécuter. La possibilité de construire dynamiquement du code de programme au moment de l'exécution nécessite que le moteur soit capable d'interpréter le code source. Mais cela ne signifie pas que vous ne pouvez pas faire tout le reste en avance. Même dans un langage compilé comme C ++ et C #, vous pouvez utiliser le code source, le compiler en mémoire dans un nouveau code machine, puis l'exécuter. Il existe même des bibliothèques pour cela: LLVM + Clang en C ++ et le projet Roslyn en C #.

En outre, le mécanisme de livraison de JavaScript est le code source. il n'y a pas de code d'octet reconnu sous sa forme. C # et Java ont leur code d'octet officiel, et tout le monde s'attend à ce que C ++ soit livré sous forme de code machine. Mais ce n’est toujours pas un aspect inhérent à la langue, c’est un scénario d’utilisation dominante. En fait, le code ActionScript relatif proche de JavaScript dans Flash est en fait fourni sous forme de code octet (le compilateur Flash précompile tous les scripts).

Sebastian Redl
la source
4

Il n'y a pas de définition totalement acceptée de «interprété» par opposition à «compilé». Dans la distinction classique, les langages compilés produisent un exécutable binaire autonome, tandis que les langages interprétés nécessitent un runtime déployé pour exécuter le code. Les machines virtuelles, le bytecode, etc., estompent la distinction.

Mais voici une définition éventuellement utile: Un langage interprété est un langage dans lequel le langage standard peut exécuter le texte du code source en entrée et l’exécuter. Selon cette définition, les scripts Perl, Python, Ruby, JavaScript et shell, etc., sont interprétés (même s’ils utilisent des étapes intermédiaires telles que le bytecode ou même le code natif). Java, C #, C etc. ne le sont pas. Et JavaScript est par définition interprété, même si la spécification n'utilise pas le mot exact.

JacquesB
la source
Hmm, je n'aime pas mettre Java et C dans la même catégorie. Peut-être une meilleure distinction concerne-t-elle les langues les plus communément distribuées sous forme de code source (A), de code intermédiaire (B) ou de code machine (C). Par exemple, A = javascript, B = Java, C = C.
John Henckel
Appeler un langage interprété ou compilé n’est pas correct. Par exemple, sous cette règle, vous conviendrez que C ++ est un langage compilé, n'est-ce pas? Alors que dire de Cling, cela exécute le code c ++ sans le compiler. "et similaires sont interprétés (même s’ils utilisent des étapes intermédiaires telles que le bytecode ou même le code natif)" Pour cela, java est également interprété, interprété par sa machine virtuelle.
Abhinav Gauniyal