vendredi, juin 11, 2010

La machine virtuelle virtuelle




La semaine passée, en sortant de la conférence de Douglas Hofstadter sur la centralité de l'analogie dans les sciences cognitives (cours de Serge Haroche) et, dans le cas d'espèce, sur son importance indubitable dans la traduction poétique à partir de l'exemple d'Eugène Onéguine d'Alexandre Pouchkine, je tombai à l'improviste sur mon amie Claude Computing, que je n'avais pas vue depuis quelque temps, et qui, à mon grand étonnement, sortait aussi de cette même conférence du Collège de France.



Je l'entraînai donc rapidement vers une terrasse ensoleillée pour lui demander autour d'un café quel rapport pouvait bien exister entre la structure particulière de la strophe onéguinienne (14 vers, aBaBccDDeFeFGG) et ses propres travaux avancés de psychopathologie virtualisante des hyperviseurs qui justifiât de sa présence ce jour là au cours (polyglotte) d'Hofstadter ? Si l'on peut dire de Claude qu'elle a parfois la tête dans les nuages, ses sources d'information et ses travaux techniques sont, en revanche, d'une rare exactitude. « Vois-tu, » me dit-elle, « la qualité de la traduction poétique, vient de nous démontrer Hofstadter, repose sur l'habileté du traducteur à respecter non seulement l'analogie de fond mais également l'analogie de forme dans le passage d'une langue à l'autre. C'est précisément la même chose dans la virtualisation ! »



Devant mes yeux agrandis de surprise, elle me décrivit rapidement la situation d'un de ses patients, OSGi (désigné par ses initiales pour préserver son identité), souffrant de troubles de la personnalité multiple. Dans le cas d'OSGi, ces personnalités ou bundles, dans le jargon des thérapeutes, regroupent un ensemble de composants Java chargés par un class loader spécifique. Mais chez ce patient, un bundle n'est pas protégé contre les exactions éventuelles d'un autre bundle, malicieux ou simplement bogué. Pour y remédier, Claude s'intéressait aux travaux communs du LIP6, de l'INSA et du Forschungszentrum Informatik de Karlsruhe, autour d'une machine virtuelle Java, JVM-I, qui embarque un mécanisme d'isolement entre bundles. La communication reste permise entre bundles par un contrôle maîtrisé de la migration des threads d'une cellule d'isolement - un isolat - à une autre. JVM-I isole la mémoire (en rendant privés à l'isolat les variables statiques, chaînes et autres objets associés à java.lang.class, autrement partagés entre tous les bundles) ; entretient une comptabilité des ressources mémoire et CPU (en gardant trace de l'isolat dans lesquels s'exécute une thread) ; et gère le cycle de vie des isolats (en assurant qu'une fois terminé, une invocation de ses classes provoque une exception).



« Mais le plus intéressant, » continua-t-elle, « c'est l'architecture de cette machine virtuelle Java : c'est une machine virtuelle virtuelle ! ».



Deuxième effet spéculaire qui accrut ma perplexité !



Au fait, les exemples de machines virtuelles pour les langages de programmation sont bien connus : machine virtuelle Java JVM, à l'origine pour le langage Java mais également maintenant utile pour Jython, JRuby, Groovy, Scala et quelques autres ; la Common Language Infrastructure (CLI) proposée par Microsoft devenu standards ECMA qui sous-tend une variété de langages de programmation, de C# à F#, d'IronPython à IronRuby, de Boo à Cobra et bien d'autres encore, sans oublier Mono, une implémentation Open Source. Ces machines virtuelles ont demandé des années d'effort pour la conception de leur architecture et leur développement. Bâtir une nouvelle machine virtuelle apparaît donc à l'observateur averti comme bien plus difficile que de porter ou d'inventer un langage de programmation pour ces machines virtuelles déjà bien établies.



Et cependant, l'idée fascinante de l'équipe du LIP6/INRIA/Regal est de virtualiser les machines virtuelles. VMKit, le premier produit de cette réflexion méta-programmatique (qui nous ramène inévitablement à l'oeuvre d'Hofstadter qui lui valut un Pulitzer), est donc un Managed Runtime Environment (MRE) générique : une plate-forme permettant à moindre coût de développer une machine virtuelle spécifique. Un outillage complet pour des Domain-Specific Virtual Machines. Pour réussir ce tour de force, insista Claude, les recommandations d'Hofstadter ont été suivies à la lettre : abstraire la traduction tant du fond que de la forme d'une machine virtuelle à une autre. Dans le cas d'espèce, la JVM et CLI ont été entièrement et facilement ré-implémentées, sous les noms respectifs de J3 et N3, sur le même substrat VMKit.



Les perspectives me donnaient soudain le tournis.



J'avais à peu près réalisé que créer des langages de programmation spécifiques à un besoin ou un domaine d'application particulier était devenu pratiquement chose courante (les Domain-Specific Languages) grâce à leur compilation vers un bytecode directement exécutable par les machines virtuelles Java ou CLI. J'avais même compris que l'instrumentation moderne permettait de compiler son propre compilateur spécifique. Mais ici, Claude allait encore un cran plus loin, puisque c'est la machine virtuelle elle-même, chargée d'exécuter le bytecode, que l'on peut maintenant spécifier, une machine donc deux fois virtuelle se chargeant de son exécution... Superbe mise en abyme, théâtre dans le théâtre, méta-récit des threads et de la mémoire !



À l'examen, la diégétique de VMKit s'articule autour d'un compilateur à la volée (JIT) - le fameux traducteur dynamique dont il est question chez Hofstadter pour la strophe onéguinienne -, un gestionnaire de mémoire avec ramasse-miettes et un gestionnaire de threads. Ces trois fonctions sont les hypostases indispensables à la plupart des MRE (Cacao, Harmony, Mono ou JikesRVM), même si elles ne sont pas forcément toutes utilisées dans une implémentation d'un MRE particulier.



Ainsi, grâce à VMKit et pour la beauté du geste, ses concepteurs ont pu développer : (i) une machine virtuelle Java complète, J3, dont 96% du code provient de la plate-forme VMKit et seulement 4% lui donne la personnalité JVM ; puis (ii) en moins d'un mois, à la lueur de l'expérience acquise avec J3, une seconde machine virtuelle, baptisée N3, implémentant la CLI pour un ratio de code spécifique à générique similaire !



Je commandai précipitamment une infusion de ballote fétide et d'escholtzia pour tenter d'apaiser le bouillonnement de mes pensées. Claude était passée au brou d'ashwagandha à ma très vive inquiétude.



Pour construire le compilateur à la volée de VMKit, le choix s'est porté naturellement sur LLVM, qui au-delà d'un jeu d'instructions complet et d'un modèle de machine à une infinité de registres, peut être facilement étendu de nouvelles fonctions système internes (intrinsics) et effectuer une compilation à la demande (lazy compilation).



Pour le choix du gestionnaire de mémoire, MMTk a été retenu. Les ramasse-miettes de MMTk sont employés dans Jikes/RVM, une machine virtuelle de « recherche » et d'expérimentation implémentée en Java, d'ailleurs exécuté par elle-même - aïe, aïe, perspective de migraine méta-diégétique ! MMTk permet de définir l'architecture de sa mémoire virtuelle, ses mécanismes d'allocation de la mémoire et de ramasse-miettes, et calcule les statistiques d'utilisation. MMTk, qui est implémenté en Java, offre donc un toolkit complet pour écrire son propre gestionnaire mémoire que l'on peut ainsi adapter à des modèles objet ou des hiérarchies de types spécifiques. (Comme MMTk est en Java on a évidemment un problème de poule et d'oeuf puisqu'il faut une machine virtuelle Java pour exécuter le gestionnaire de mémoire du MRE. Qu'à cela ne tienne ! On recompile MMTk avec LLVM pour obtenir un bitcode LLVM neutre qui est compilé au vol et chargé à l'initialisation de VMKit.)



Enfin le thread manager est simplement le standard POSIX Threads (PThreads). Dans l'environnement multi-thread du MRE, l'interaction entre threads et mémoire pour le ramasse-miettes est implémentée en associant à chaque thread une mémoire locale contenant les informations nécessaires au ramasse-miettes (les barrières).



La machine virtuelle Java, J3, développée avec VMKit et les classes Java de GNU Classpath - même si ce MRE virtuel est toujours en cours de développement, research in progress - est déjà capable de faire tourner des programmes qui sont loin d'être triviaux comme Tomcat ou Eclipse. N3, qui utilise VMKit et les librairies DotGNU Portable .NET ou Mono, affiche déjà des performances comparables à celles de Mono.



Claude Computing, appelée à d'autres obligations, me laissa donc abîmé dans mes réflexions et la réalisation soudaine que si le choix d'un langage de programmation est pour beaucoup souvent guidé par les préférences personnelles des développeurs et pour le reste par des différences objectives, les progrès actuels de LLVM et de VMKit laissaient peut-être présager de la disparition pure et simple de ces différences objectives. Babel reconstruit ?






ShareThis