Célébrons 10 ans de V8
Ce mois-ci marque le 10e anniversaire de la sortie non seulement de Google Chrome, mais aussi du projet V8. Ce post offre un aperçu des grandes étapes du projet V8 au cours des 10 dernières années ainsi que les années précédentes, lorsque le projet était encore secret.
gource
.Avant la sortie de V8 : les premières années
Google a recruté Lars Bak à l'automne 2006 pour développer un nouveau moteur JavaScript pour le navigateur web Chrome, qui était alors un projet interne secret de Google. Lars venait de retourner à Aarhus, au Danemark, après avoir séjourné dans la Silicon Valley. Comme il n'y avait pas de bureau Google là-bas et que Lars souhaitait rester au Danemark, Lars et plusieurs des ingénieurs originaux du projet ont commencé à travailler sur le projet dans une dépendance de sa ferme. Le nouveau runtime JavaScript fut baptisé « V8 », une référence ludique au moteur puissant que l'on trouve dans une voiture de sport classique. Plus tard, quand l'équipe V8 s'est agrandie, les développeurs ont déménagé de leurs locaux modestes vers un bâtiment de bureau moderne à Aarhus, tout en gardant leur ambition unique de créer le runtime JavaScript le plus rapide du monde.
Lancement et évolution de V8
V8 est devenu open-source le même jour où Chrome a été lancé : le 2 septembre 2008. Le premier commit date du 30 juin 2008. Avant cette date, le développement de V8 se faisait dans un dépôt CVS privé. Initialement, V8 supportait uniquement les jeux d'instructions ia32 et ARM et utilisait SCons comme système de construction.
2009 a vu l'introduction d'un tout nouveau moteur d'expressions régulières nommé Irregexp, entraînant des améliorations de performance pour les expressions régulières réelles. Avec l'introduction d'un port x64, le nombre de jeux d'instructions pris en charge est passé de deux à trois. 2009 a également marqué la première version du projet Node.js, qui intègre V8. La possibilité pour les projets hors navigateur d'intégrer V8 est explicitement mentionnée dans la bande dessinée originale de Chrome. Avec Node.js, cela est devenu réalité ! Node.js est devenu l'un des écosystèmes JavaScript les plus populaires.
2010 a vu une grande amélioration de la performance du runtime alors que V8 a introduit un tout nouveau compilateur JIT optimisant. Crankshaft générait du code machine deux fois plus rapide et 30 % plus petit que le précédent compilateur (sans nom) de V8. La même année, V8 a ajouté son quatrième jeu d'instructions : MIPS 32 bits.
En 2011, la gestion des collectes de déchets a été considérablement améliorée. Un nouveau collecteur de déchets incrémental a considérablement réduit les temps de pause tout en maintenant des performances maximales exceptionnelles et une faible utilisation de mémoire. V8 a introduit le concept d'Isolates, qui permet aux intégrateurs de démarrer plusieurs instances du runtime V8 dans un processus, ouvrant la voie à des Web Workers plus légers dans Chrome. La première des deux migrations de système de construction de V8 a eu lieu alors que nous sommes passés de SCons à GYP. Nous avons implémenté la compatibilité avec le mode strict ES5. Pendant ce temps, le développement a été transféré d'Aarhus à Munich (Allemagne) sous une nouvelle direction avec beaucoup de collaboration des membres originaux de l'équipe d'Aarhus.
2012 a été une année de référence pour le projet V8. L'équipe a effectué des sprints de vitesse pour optimiser les performances de V8 mesurées à travers les suites de benchmarks SunSpider et Kraken. Plus tard, nous avons développé une nouvelle suite de benchmarks nommée Octane (avec V8 Bench au cœur) qui a mis en avant la compétition de performance maximale et encouragé des améliorations considérables de la technologie d'exécution et de compilation à la volée dans tous les principaux moteurs JS. Un des résultats de ces efforts a été le passage d’un système d'échantillonnage aléatoire à une technique déterministe basée sur un comptage pour détecter les fonctions “intensives” dans le profiliseur de runtime de V8. Cela a rendu beaucoup moins probable que certains chargements de pages (ou exécutions de benchmarks) soient aléatoirement beaucoup plus lents que d'autres.
2013 a vu l'apparition d'un sous-ensemble de bas niveau de JavaScript nommé asm.js. Étant donné qu'asm.js se limite à l'arithmétique typée statiquement, aux appels de fonctions et aux accès au tas avec uniquement des types primitifs, le code asm.js validé pouvait être exécuté avec des performances prévisibles. Nous avons publié une nouvelle version d'Octane, Octane 2.0, avec des mises à jour des benchmarks existants ainsi que de nouveaux benchmarks ciblant des cas d'usage comme asm.js. Octane a encouragé le développement de nouvelles optimisations de compilateur comme allocation folding et les optimisations basées sur les sites d'allocation pour la transition de types et le pré-entretien qui ont considérablement amélioré les performances maximales. Dans le cadre d'un effort que nous avons surnommé en interne “Handlepocalypse”, l'API Handle de V8 a été complètement réécrite pour en faciliter l'utilisation correcte et sécurisée. Aussi en 2013, l'implémentation dans Chrome des TypedArray
en JavaScript a été déplacée de Blink vers V8.
En 2014, V8 a déporté une partie du travail de compilation à la volée hors du thread principal grâce à la compilation concurrente, réduisant les saccades et améliorant considérablement les performances. Plus tard cette année-là, nous avons implémenté la version initiale d'un nouveau compilateur optimisant nommé TurboFan. Parallèlement, nos partenaires ont aidé à porter V8 sur trois nouvelles architectures d'instruction : PPC, MIPS64 et ARM64. Suite à Chromium, V8 est passé à encore un autre système de build, GN. L'infrastructure de test de V8 a connu des améliorations significatives, avec un Tryserver désormais disponible pour tester chaque patch sur différents bots de build avant sa mise en production. Concernant le contrôle de version, V8 a migré de SVN vers Git.
2015 a été une année chargée pour V8 sur plusieurs fronts. Nous avons mis en œuvre le cache de code et le streaming de scripts, accélérant considérablement les temps de chargement des pages web. Les recherches sur l'utilisation des mémos d'allocation dans notre système d'exécution ont été publiées dans ISMM 2015. Plus tard cette année-là, nous avons lancé le travail sur un nouvel interpréteur nommé Ignition. Nous avons expérimenté avec l'idée de sous-ensemble de JavaScript nommé strong mode pour obtenir des garanties plus fortes et des performances plus prévisibles. Nous avons mis en œuvre le strong mode derrière un drapeau, mais nous avons ensuite constaté que ses avantages ne justifiaient pas ses coûts. L'ajout d'une file de commit a considérablement amélioré la productivité et la stabilité. Le collecteur de déchets de V8 a également commencé à coopérer avec des intégrateurs comme Blink pour planifier le travail de collecte des déchets pendant les périodes d'inactivité. La collecte de déchets en temps d’inactivité a réduit de manière significative les saccades perceptibles dues à la collecte des déchets et la consommation de mémoire. En décembre, le premier prototype de WebAssembly a été intégré à V8.
En 2016, nous avons livré les dernières pièces de l'ensemble de fonctionnalités ES2015 (précédemment connu sous le nom de « ES6 »), comprenant les promesses, la syntaxe des classes, la portée lexicale, le destructuring, et plus encore, ainsi que certaines fonctionnalités ES2016. Nous avons également commencé à déployer le nouveau pipeline Ignition et TurboFan, l'utilisant pour compiler et optimiser les fonctionnalités ES2015 et ES2016, et en activant Ignition par défaut pour les appareils Android bas de gamme. Notre travail réussi sur la collecte des déchets en temps de repos a été présenté à PLDI 2016. Nous avons lancé le projet Orinoco, un nouveau collecteur de déchets principalement parallèle et concurrent pour V8 afin de réduire le temps de collecte des déchets sur le thread principal. Dans une réorientation majeure, nous avons détourné nos efforts de performance des micro-benchmarks synthétiques pour commencer à sérieusement mesurer et optimiser les performances en conditions réelles. Pour le débogage, l'inspecteur V8 a été migré de Chromium à V8, permettant à tout utilisateur de V8 (et pas seulement Chromium) d'utiliser les Chrome DevTools pour déboguer le JavaScript s'exécutant dans V8. Le prototype WebAssembly est passé du stade de prototype à un support expérimental, en coordination avec d'autres fournisseurs de navigateurs support expérimental pour WebAssembly. V8 a reçu le prix ACM SIGPLAN Programming Languages Software Award. Et un autre port a été ajouté : S390.
En 2017, nous avons finalement complété notre refonte pluriannuelle du moteur, permettant la nouvelle pipeline Ignition et TurboFan par défaut. Cela a permis de supprimer Crankshaft (130 380 lignes de code supprimées) et Full-codegen de la base de code. Nous avons lancé Orinoco v1.0, incluant le marquage concurrent, le balayage concurrent, le scavenging parallèle, et la compaction parallèle. Nous avons officiellement reconnu Node.js comme un utilisateur de V8 de premier ordre aux côtés de Chromium. Depuis, il est impossible qu'un patch V8 soit accepté s'il casse les tests de la suite Node.js. Nos infrastructures ont gagné le support au fuzzing de correction, garantissant que toute portion de code produit des résultats cohérents quelle que soit la configuration dans laquelle elle s'exécute.
Dans un lancement coordonné à l'échelle de l'industrie, V8 a lancé WebAssembly activé par défaut. Nous avons implémenté le support des modules JavaScript ainsi que des ensembles de fonctionnalités ES2017 et ES2018 complets (incluant les fonctions async, la mémoire partagée, l'itération asynchrone, les propriétés rest/spread, et les fonctionnalités RegExp). Nous avons livré le support natif de la couverture de code JavaScript et lancé Web Tooling Benchmark pour nous aider à mesurer comment les optimisations de V8 impactent les performances des outils de développement réels et du code JavaScript qu'ils génèrent. Le traçage wrapper des objets JavaScript aux objets DOM en C++ et vice versa nous a permis de résoudre des fuites de mémoire persistantes dans Chrome et de gérer efficacement la fermeture transitive des objets sur les tas JavaScript et Blink. Nous avons ensuite utilisé cette infrastructure pour augmenter les capacités de l'outil de développement de capture instantanée de heap.
En 2018, un événement de sécurité à l'échelle de l'industrie a bouleversé ce que nous pensions savoir sur la sécurité des informations CPU avec la divulgation publique des vulnérabilités Spectre/Meltdown. Les ingénieurs V8 ont mené de vastes recherches offensives pour aider à comprendre les menaces pour les langages gérés et développer des mesures d'atténuation. V8 a livré des atténuations contre Spectre et d'autres attaques par canal auxiliaire similaires pour les intégrateurs exécutant du code non fiable.
Récemment, nous avons livré un compilateur de base pour WebAssembly nommé Liftoff qui réduit considérablement le temps de démarrage des applications WebAssembly tout en maintenant des performances prévisibles. Nous avons livré BigInt
, un nouveau primitif JavaScript permettant des entiers de précision arbitraire. Nous avons implémenté des bibliothèques intégrées embarquées, et rendu possible leur désérialisation paresseuse, réduisant considérablement l'empreinte de V8 pour plusieurs Isolates. Nous avons rendu possible la compilation de bytecode de script sur un thread en arrière-plan. Nous avons démarré le projet Unified V8-Blink Heap pour exécuter une collecte de déchets V8 et Blink inter-composant de manière synchronisée. Et l'année n'est pas encore terminée...
Les hauts et les bas des performances
Le score de V8 Bench de Chrome au fil des années montre l'impact sur les performances des modifications de V8. (Nous utilisons V8 Bench car c'est l'un des rares benchmarks qui peut encore s'exécuter dans la version bêta initiale de Chrome.)
Notre score sur ce benchmark a augmenté de 4× au cours des dix dernières années !
Cependant, vous pourriez remarquer deux baisses de performance au fil des années. Les deux sont intéressantes car elles correspondent à des événements significatifs dans l'histoire de V8. La baisse de performance en 2015 s'est produite lorsque V8 a livré des versions de base des fonctionnalités ES2015. Ces fonctionnalités touchaient de nombreux aspects de la base de code de V8, et nous nous sommes donc concentrés sur la rigueur plutôt que sur les performances pour leur sortie initiale. Nous avons accepté ces légères régressions de vitesse pour fournir rapidement ces fonctionnalités aux développeurs. Début 2018, la vulnérabilité Spectre a été révélée, et V8 a livré des atténuations pour protéger les utilisateurs contre d'éventuelles exploitations, entraînant une autre régression des performances. Heureusement, maintenant que Chrome propose l'isolation des sites, nous pouvons désactiver les atténuations, ramenant ainsi les performances à leur niveau d'origine.
Un autre point à retenir de ce graphique est qu'il commence à se stabiliser autour de 2013. Cela signifie-t-il que V8 a renoncé et a cessé d'investir dans les performances ? Bien au contraire ! L'aplatissement des graphes représente le pivot de l'équipe V8, passant des micro-benchmarks synthétiques (tels que V8 Bench et Octane) à l'optimisation pour les performances réelles. V8 Bench est un ancien benchmark qui n'utilise aucune des fonctionnalités modernes de JavaScript, ni n'approximait le code de production réel. Comparez cela avec la suite de benchmarks plus récente Speedometer :
Bien que V8 Bench montre des améliorations minimales entre 2013 et 2018, notre score de Speedometer 1 a quadruplé (4×) au cours de cette même période. (Nous avons utilisé Speedometer 1 car Speedometer 2 utilise des fonctionnalités modernes de JavaScript qui n'étaient pas encore prises en charge en 2013.)
De nos jours, nous disposons de benchmarks encore meilleurs et plus représentatifs des applications JavaScript modernes, et en plus de cela, nous mesurons activement et optimisons les applications web existantes.
Résumé
Bien que V8 ait été initialement conçu pour Google Chrome, il a toujours été un projet autonome avec une base de code distincte et une API d'intégration permettant à tout programme d'utiliser ses services d'exécution JavaScript. Au cours des 10 dernières années, la nature ouverte du projet l'a aidé à devenir une technologie clé non seulement pour la Plateforme Web, mais aussi dans d'autres contextes comme Node.js. En chemin, le projet a évolué et est resté pertinent malgré de nombreux changements et une croissance spectaculaire.
Au départ, V8 ne prenait en charge que deux jeux d'instructions. Au cours des 10 dernières années, la liste des plateformes prises en charge a atteint huit : ia32, x64, ARM, ARM64, MIPS 32 et 64 bits, PPC 64 bits et S390. Le système de build de V8 a migré de SCons à GYP puis à GN. Le projet a déménagé du Danemark vers l'Allemagne, et compte maintenant des ingénieurs partout dans le monde, notamment à Londres, Mountain View et San Francisco, avec des contributeurs extérieurs à Google venant de nombreux autres endroits. Nous avons transformé tout notre pipeline de compilation JavaScript depuis des composants sans nom à Full-codegen (un compilateur de base) et Crankshaft (un compilateur optimisant basé sur des retours) vers Ignition (un interpréteur) et TurboFan (un meilleur compilateur optimisant basé sur des retours). V8 est passé d'un simple moteur JavaScript à un moteur prenant également en charge WebAssembly. Le langage JavaScript lui-même a évolué d'ECMAScript 3 à ES2018 ; la version la plus récente de V8 implémente même des fonctionnalités post-ES2018.
L'arc narratif du Web est long et durable. Fêter le 10e anniversaire de Chrome et V8 est une bonne occasion de réfléchir au fait que, même si cela représente une étape importante, la narration de la Plateforme Web perdure depuis plus de 25 ans. Nous n'avons aucun doute que l'histoire du Web continuera au moins aussi longtemps dans le futur. Nous nous engageons à veiller à ce que V8, JavaScript et WebAssembly continuent à jouer un rôle passionnant dans ce récit. Nous sommes impatients de voir ce que la prochaine décennie nous réserve. Restez à l'écoute !