Il faut une sacrée dose de vulgarisation pour arriver à faire comprendre le sens de cet article technique à des non initiés. Mais je me lance en espérant que tout le monde, techniciens comme érudit, sera en mesure de saisir les enjeux autour de LLVM qui dépassent le simple cadre du projet OpenSource.
Depuis quelques années, toutes les technologies qui ont émergées n'ont cessé d'abonder dans le sens d'un navigateur universel ou en tout cas d'une machine virtuelle universelle. Pendant longtemps, les VM Java ou .NET ont laissé entrevoir un espoir très vite balayé par le fait que l'intégration de code natif (écrit en C/C++ ou Assembleur) était un obstacle insurmontable.
On le sait aujourd'hui, proposer un programme portable est clairement un voeu pieu. Même si les architectures matérielles restent globalement stables et se concentrent sur les habituels x86, ARM, PowerPC, etc. la dimension 32 bits ou 64 bits vient s'ajouter à l'ensemble. Et ne parlons pas des périphériques qui implémentent des sous-ensembles de spécifications matérielles (tablettes, téléphones mobiles, etc .). Bref, le rêve ultime serait d'avoir en quelque sorte une machine magique capable de lire du code source et de le traduire dans du code machine spécifique au périphérique sur lequel on s'exécute. A part quelques ajustements d'ordre graphique (la taille d'un téléphone mobile n'étant pas celle d'une tablette ou d'un écran de PC), le développeur n'aurait pas à réécrire son programme pour iPhone, Android, Tablette et navigateurs Web.
Pendant longtemps, Google a entretenu ce doux rêve avec NaCl pour Native Client. Une technologie censée exécuter du byte-code universel à partir d'un plugin qui ressemble pour schématiser vulgairement (que les initiés me pardonnent) à une sorte de VMWare embarqué dans le navigateur. Or aujourd'hui, NaCl ne perce pas car le marché ne jure que par HTML 5 et JavaScript. Un langage dont NaCl fait totalement l'impasse. Il en fait même un contre-exemple car on fait du NaCl pour palier aux performances de JavaScript avant tout. Et c'est le noeud du problème car lorsque JavaScript entre en confrontation avec NaCl, il gagne souvent par la simplicité de son environnement d'exécution (un simple navigateur suffit) là où NaCl requiert l'installation d'une couche logicielle spécifique.
Aujourd'hui, tout cela est en train de bouger avec les récents travaux de recherche autour du projet LLVM. LLVM signifie (Low Level Virtual Machine). Pour bien comprendre LLVM, il faut un minimum de pré-requis en théorie de compilation. Lorsqu'on compile un programme source en exécutable machine, il est d'abord traduit dans une structure intermédiaire (appelé encore IR pour Intermediate Representation ou BitCode pour LLVM). Cette structure va ensuite servir à créer un CFG (Control Flow Graph) qui est une sorte de graphe permettant de mettre le générateur de code machine dans les meilleurs prédispositions pour qu'il puisse optimiser le code initial (spécialiser par rapport à l'architecture matérielle, enlever le code mort, inférer les types, inliner, etc .. ). On parle souvent de front-end pour la partie du compilateur qui génère l'IR et de back-end pour la partie qui génère le code machine.
Quel lien entre tout cela et LLVM ? LLVM est issu des travaux de recherche de Chris Lattner, à l'époque assistant chercheur à l'université de l'Illinois et accessoirement génie de l'informatique. LLVM a ensuite été industrialisé à plus large échelle lorsque Chris a intégré Apple. LLVM est devenu au fil des mois une infrastructure complètement innovante proposant un IR très complet et intégrant dans sa structure un CFG basé sur le puissant algorithme SSA pour Static Single Assignment (créé par IBM dans les années 80 !). Sans aller dans les détails techniques, il faut simplement savoir que LLVM adresse non seulement les langages à typage statique mais aussi ceux à typage dynamique (C, Java, Php, Python/Ruby,Fortran .). L'IR de LLVM est en quelque sorte le parfait modèle intermédiaire pour représenter un programme qui va ensuite générer du code machine natif optimisé via le jeu du générateur de code (Just In Time si cela est fait à la volée lors de l'exécution).
Depuis l'année dernière, Google a compris la puissance de l'IR dans LLVM et l'a intégré à NaCl au travers de pinnacle (Portable NaCl). Cela signifie donc qu'un programme NaCl qui utilisera un compilateur LLVM pourra générer n'importe quel type de code machine. Une aubaine pour LLVM et l'ouverture d'un énorme marché pour Google.
Mais quel lien avec JavaScript et le Web de demain ? Souvenez-vous, JavaScript aujourd'hui est l'infrastructure d'exécution plébiscitée pour les années à venir. Si JavaScript a quelques défauts (pas de multi-threading, représentation 64 bits non supporté pour les nombres), il ne se démarque pas plus que cela des autres langages. De là à faire le lien entre LLVM et JavaScript, il n'y a qu'un pas que le génial Alon Zakai a franchi. En créant emscripten, ce développeur Mozilla a prouvé qu'il était possible de coder une application en C++ réalisant des tâches graphiques puis de générer son code machine en JavaScript via LLVM, démo à l'appui. Ammo.js n'est rien de moins que le portage de la bibliothèque « Bullet Physics Engine » originalement écrite en C++.
Evidemment, il y a encore de nombreuses zones d'ombres, notamment sur les performances de JavaScript. Sur son blog, Chad Austin fait un mini benchmark des performances de C/C++ comparés à leur équivalent JavaScript. Si le facteur laisse pantois (multiplié par 140), concrètement, la faisabilité technique a été démontrée. Imaginez un instant la valeur de cette architecture pour les développeurs de jeux vidéo qui s'arrachent aujourd'hui les cheveux avec la portabilité. Nous aurions un seul code source (et peu importe s'il est en C, C++, C#, Java ou Fortran) capable de s'exécuter via un compilateur compatible LLVM. Puis un déploiement complètement lié à l'environnement d'exécution cible. Ce serait NaCl sur les navigateurs avec plugin et JavaScript pour ceux sans plugin.
Il reste encore deux problèmes majeurs à cette infrastructure multi-plateformes. Créer des environnements de développement adaptés (faire en sorte de générer directement de l'IR LLVM et non un pseudo bytecode propriétaire) et démocratiser NaCl sur le marché. Malgré son statut Open Source (http://code.google.com/p/nativeclient/), NaCl est encore vu comme un projet propriétaire créé par Google. Et c'est bien dommage.
Sami Jaber
ps : L'idée de cet article m'est venu en lisant ce billet de Joel s'arrachant les cheveux avec emscripten pour valider les performances des différents scénarios
Décidément, le match "client web/client natif", et l'évolution des compilateurs, remettent au gout du jour le principe de cross-compilation ; idem GWT.