Plus tard, en 2008, a été lancé ce qui a été désigné comme étant la guerre des performances ; les navigateurs ont commencé à ajouter la compilation à la volée (JIT, une technique visant à améliorer la performance de systèmes bytecode compilés par la traduction de bytecode en code machine natif au moment de l'exécution). Tandis que le JavaScript s’exécutait, le JIT pouvait voir des modèles et faire en sorte que le code s’exécute plus rapidement en fonction de ces modèles. C’est ce qui a contribué à l’amélioration des performances de JavaScript qui a alors commencé à être utilisé pour plus de choses qu’il n’était censé gérer au départ, comme la programmation côté serveur avec Node.js.
Pourtant, malgré ces améliorations, il arrive que les performances soient imprévisibles. Aussi, pour accélérer les choses, le JIT a ajouté quelques éléments à l'exécution, parmi lesquels :
- l’optimisation et la désoptimisation ;
- de la mémoire utilisée pour les informations de compatibilité et de récupération du moniteur pour les cas où des récupérations se produisent ;
- de la mémoire utilisée pour stocker les versions de base et optimisées d'une fonction.
Autant d’éléments qui font qu’il arrive que le navigateur ne peut pas exécuter une application aussi rapidement qu’en natif. C’est alors qu’intervient WebAssembly dont l’un des objectifs est de permettre aux applications complexes de fonctionner de façon optimale sur navigateur – telles que les jeux vidéo immersifs en 3D, le design informatisé, l’édition d’image et de vidéo et la visualisation scientifique.
WASI, l'interface système WebAssembly
Mozilla a annoncé le début d'un nouvel effort de normalisation avec WASI, l'interface système de WebAssembly.
Pourquoi ? La fondation explique que les développeurs commencent à pousser WebAssembly au-delà du navigateur, car il fournit un moyen rapide, évolutif et sécurisé d’exécuter le même code sur toutes les machines.
Mais nous n’avons pas encore de base solide sur laquelle évoluer. Le code en dehors d'un navigateur nécessite un moyen de communiquer avec le système: une interface système. Et la plateforme WebAssembly ne l’a pas encore.
WebAssembly est un langage d'assemblage pour une machine conceptuelle et non physique. C'est pourquoi il peut être utilisé dans différentes architectures de machines.
Tout comme WebAssembly est un langage d'assemblage pour une machine conceptuelle, WebAssembly a besoin d'une interface système pour un système d'exploitation conceptuel, et non d'un système d'exploitation unique. De cette façon, il peut être exécuté sur tous les systèmes d'exploitation.
C’est ce que WASI est : une interface système pour la plateforme WebAssembly.
Mozilla assure que son objectif est de créer une interface système qui sera un véritable compagnon de WebAssembly et qui résistera à l'épreuve du temps. Cela signifie respecter les principes clés de WebAssembly - la portabilité et la sécurité.
Vous pouvez voir WASI en action dans cette vidéo :
Comment WebAssembly s'exécute-t-il en dehors du navigateur aujourd'hui ?
Emscripten était le premier outil de production de WebAssembly. Il émule une interface système d’exploitation particulière, POSIX, sur le Web. Cela signifie que le développeur peut utiliser des fonctions de la bibliothèque standard C (libc).
Pour ce faire, Emscripten a créé sa propre implémentation de libc. Cette implémentation a été scindée en deux parties: elle a été compilée dans le module WebAssembly et l'autre partie a été implémentée dans le code de laison JS. Celui-ci appelle ensuite le navigateur, qui parle ensuite au système d'exploitation.
La plupart des premiers codes de WebAssembly ont été compilés avec Emscripten. Aussi, lorsque les utilisateurs ont commencé à vouloir exécuter WebAssembly sans navigateur, ils ont commencé par faire exécuter le code compilé par Emscripten.
Ainsi, ces environnements d'exécution ont dû créer leurs propres implémentations pour toutes ces fonctions qui se trouvaient dans le code de liaison JS.
Il y a un problème ici, cependant. L’interface fournie par ce code de liaison JS n’a pas été conçue pour être une interface standard, ni même publique. Ce n’était pas le problème qu’elle résolvait.
Par exemple, pour une fonction qui va appeler quelque chose comme read dans une API conçue pour être une interface publique, le code de liaison JS utilise à la place _system3(which, varargs).
Le premier paramètre, which, est un entier qui est toujours le même que le nombre dans le nom (donc 3 dans ce cas).
Le deuxième paramètre, varargs, sont les arguments à utiliser. Il s’appelle varargs parce que vous pouvez en avoir un nombre variable. WebAssembly ne permet toutefois pas de transmettre un nombre variable d’arguments à une fonction. Au lieu de cela, les arguments sont transmis via la mémoire linéaire. Ce type n’est pas sûr, et il est également plus lent que si les arguments pouvaient être passés dans des registres.
Cela convenait lorsqu’Emscripten était exécuté dans le navigateur. Cependant, les environnements d’exécution traitent cela comme un standard de facto et implémentent leurs propres versions du code de liaison JS. Ils émulent un détail interne d'une couche d'émulation de POSIX.
Cela signifie qu'ils ré-implémentent des choix (tels que transmettre des arguments en tant que valeurs de tas) qui ont du sens en fonction des contraintes d’Emscripten, même si ces contraintes ne s’appliquent pas dans leurs environnements.
Envoyé par Mozilla
Deux principes importants sont intégrés à WebAssembly:
- portabilité
- Sécurité
Mozilla estime qu’il est donc important de maintenir ces principes clés à mesure que nous passons à des cas d'utilisation en dehors du navigateur.
Dans l’état actuel des choses, l’approche de sécurité de POSIX et d’Unix en matière de contrôle d’accès ne nous y conduit pas vraiment.
Portabilité
POSIX fournit la portabilité du code source. Vous pouvez compiler le même code source avec différentes versions de libc pour cibler différentes machines.
WebAssembly doit toutefois aller au-delà de cela. Mozilla estime que nous devons être capables de compiler une fois et de faire tourner un tas de machines différentes. Nous avons besoin de fichiers binaires portables.
Ce type de portabilité facilite beaucoup la distribution de code aux utilisateurs.
Par exemple, si les modules natifs de Node étaient écrits dans WebAssembly, les utilisateurs n’auraient pas besoin de lancer node-gyp lorsqu’ils installeraient des applications avec des modules natifs, et les développeurs n’auraient pas besoin de configurer et de distribuer des dizaines de fichiers binaires.
Sécurité
Lorsqu'une ligne de code demande au système d'exploitation d'effectuer une entrée ou une sortie, le système d'exploitation doit déterminer s'il est prudent de faire ce que le code demande.
Les systèmes d'exploitation gèrent généralement cela avec un contrôle d'accès basé sur la propriété et les groupes.
Par exemple, le programme peut demander au système d'exploitation d'ouvrir un fichier. Un utilisateur a un certain ensemble de fichiers auquel il a accès.
Lorsque l'utilisateur démarre le programme, le programme s'exécute au nom de cet utilisateur. Si l'utilisateur a accès au fichier - soit parce qu'il en est le propriétaire, soit parce qu'il fait partie d'un groupe disposant d'un accès -, le programme dispose également du même accès.
Cela protège les utilisateurs les uns des autres. Cela avait beaucoup de sens lorsque les premiers systèmes d'exploitation ont été développés. Les systèmes étaient souvent multi-utilisateurs et les administrateurs contrôlaient le logiciel installé. La menace la plus importante était donc que d'autres utilisateurs jettent un coup d'œil à vos fichiers.
Cependant cette configuration a changé. Les systèmes sont maintenant généralement à un seul utilisateur, toutefois, ils utilisent un code qui intègre beaucoup d'autres codes tiers de confiance inconnue. Désormais, la plus grande menace est que le code que vous exécutez vous-même se retourne contre vous.
Par exemple, supposons que la bibliothèque que vous utilisez dans une application ait un nouveau responsable (comme cela se produit souvent dans l’open source). Ce mainteneur peut avoir votre intérêt à cœur ou non. Et s'il a le droit de faire quoi que ce soit sur votre système - par exemple, ouvrir n'importe lequel de vos fichiers et l’envoyer sur le réseau - son code peut alors faire beaucoup de dégâts.
C'est pourquoi l'utilisation de bibliothèques tierces pouvant communiquer directement avec le système peut être dangereuse.
La méthode de WebAssembly en matière de sécurité est différente. WebAssembly est un bac à sable.
Cela signifie que le code ne peut pas communiquer directement avec le système d'exploitation. Mais alors, comment fait-il quelque chose avec les ressources système? L'hôte (qui peut être un navigateur ou un environnement d'exécution wasm) place les fonctions dans le bac à sable que le code peut utiliser.
Cela signifie que l'hôte peut limiter ce qu'un programme peut faire. Il ne laisse donc pas que le programme agisse au nom de l’utilisateur, faisant un appel système avec toutes les autorisations de l’utilisateur.
Avoir un mécanisme de sandboxing ne rend pas un système sécurisé en soi - l'hôte peut toujours mettre toutes les fonctionnalités dans le bac à sable, auquel cas nous ne sommes pas mieux lotis - mais il donne au moins aux hôtes la possibilité de créer un système plus sécurisé.
C’est pourquoi Mozilla pense que
Envoyé par Mozilla
Et vous ?
Que pensez-vous de WebAssembly ? L'avez-vous déjà utilisé ?
L'avez-vous déjà utilisé en dehors du Web ?
Que pensez-vous de cet effort de standardisation ?