Asm.js, la compatibilité universelle des applications
Ce sous-ensemble de JavaScript défini par Mozilla donne aux applications et jeux presque la vitesse du code natif.
On pensait depuis longtemps à l'intérêt d'une machine virtuelle dans le navigateur permettant de compiler des langages différents et de les faire fonctionner sur tous les systèmes d'exploitation. Cette idée à pris forme grâce aux développeurs de Mozilla, et Asm.js est implémenté dans SpiderMonkey en 2013.
Il ne s'agit pas d'un bytecode réel mais d'un sous-ensemble de JavaScript qui est compilé et optimisé pour la vitesse. Le code Asm.js est compilé AOT (une fois pour toutes - jusqu'à ce qu'on change le source), alors que le code JavaScript est JIT, compilé à la volée.
On peut compiler différents langages statiquement typés en bitcode LLVM, puis utiliser Emscriptem pour le convertir en Asm.js. Le code originel étant déjà optimisé, cela produit du JavaScript plus rapide et Asm.js lui apporte en outre la vitesse qui deux fois plus lente que le binaire mais dix fois plus rapide que JavaScript.
Une application entière peut être convertie en Asm.js ou seulement une bibliothèque venant d'un autre langage pour être utilisée par un programme JavaScript.
Avec le réalisateur de jeu Epic, Mozilla a implémenté le moteur 3D Unreal Engine 3 sous Asm.js (vidéo). Cela à incité les développeurs de V8 à optimiser le compilateur JavaScript de Chrome et Node.js pour Asm.js. Opera également à une optimisation pour le code Asm.js.
Microsoft de son coté a annoncé l'implémentation d'Asm.js dans Windows 10 et pour ce faire, travaille en collaboration avec Mozilla.
Le code Asm.js depuis les dernières optimisations en décembre 2013 met 1.5 fois le temps du code natif pour exécuter le même programme.
Asm.js est implémenté dans le nouveau navigateur Edge de Microsoft, avec l'aide de Mozilla. Cela a été commenté dans plusieurs billet de la firme, dont l'un titré: Bringing Asm.js to Chackra in Microsoft Edge.
Caractéristiques
De C au bitcode LLVM à Asm.js
Asm.js est compatible avec JavaScript, et n'apporte aucune fonction supplémentaire mais pour être validé et compilé, ne doit contenir que le sous-ensemble défini par la spécification.
- Le code Asm.js est compilé en code natif lors de chaque exécution mais le code compilé demeure en place et est réutilisé si le source n'est pas modifié.
- Il fonctionne sur tout navigateur mais plus vite quand Asm.js est implémenté.
- C'est un langage typé sans déclaration. Toutes la variables ont un type qui est attribué lors de la compilation mais non expressément indiqué par le programmeur.
- Les annotations sont des déclarations qui donnent un type et une valeur par défaut aux variables, notamment quand elles sont les arguments d'une fonction ou les valeurs de retour.. Cela a la forme x = x | 0; La valeur par défaut est 0 et le type est entier.
- Les chaînes de caractères sont traitées comme des zones de mémoire.
- Les seules librairies standards valides sont Math et stdlib.
- La spécification ne fait pas mention d'objets.
- Un type de tableau générique ArrayBufferView, dont dérivent plusieurs types numériques.
- L'accès au DOM n'est pas effectué en Asm.js, mais en JavaScript. Il n'est pas accéléré.
- Il n'a pas de garbage-collector. Le générateur de code gére l'allocation mémoire. Il est prévu d'en inclure un plus tard.
- Un module est défini sous la même forme qu'une fonction dont la première ligne du corps est "use asm"; Il contient d'autres fonctions. Il peut être utilisé par le JavaScript standard.
- La compilation dynamique telle que le fait eval est possible. Le code peut donc se développer dynamiquement.
- Il est prévu de permettre le stockage du code généré pour une compilation unique lors de la première exécution.
On ne peut tirer avantage d'Asm.js que si le langage compilé à des types statiques car c'est sur ce point qu'Asm.js trouve sa vitesse. Un langage dynamique devrait plutôt être compilé en JavaScript ordinaire pour fonctionner dans le navigateur.
Asm.js vs. Native Client vs. WebAssembly
Quelle solution doit-on préférer, Asm.js, ou NaCl, autrement dit des programmes compilés en bitcode pour LLVM, fonctionnant eux-aussi dans le navigateur?
Un programme sous NaCl même s'il fonctionne dans le navigateur doit être compilé pour chaque système d'exploitation. Donc le créateur doit fournir de multiples versions ce qui n'est pas le cas pour Asm.js qui fonctionne à l'identique sous tout système.
Sachant que Mozilla ne veut pas implémenter NaCl, cela l'exclut de Firefox, et apparemment d'Internet Explorer aussi.
Asm.js fonctionne d'office puisqu'un compilateur JS existe déjà dans chaque navigateur. On sait l'optimiser et il ne faut que quelques modification mineures pour qu'il fonctionne sur V8 ou autre JIT (Just-In-Time) ou AOT (Ahead-Of-Time).
L'annonce de WebAssembly en juin 2015, rend NaCl obsolète, d'autant qu'il sera supporté par tous les navigateurs alors que NaCl ne l'est que par Chrome. Mais ce n'est pas le cas d'Asm.js avec lequel il va coexister. En fait le code WebAssembly sera similaire au code Asm.js au départ, avant de diverger. Wasm pourra être converti en Asm.js pour fonctionner sur les anciens navigateurs. Il il pourra aussi être utilisé dans des modules JavaScript ou Asm.js.
Exemple de code
On définit la fonction strlen et on affiche les lettres d'une chaîne.
JavaScript:
function strlen(ptr)
{
var curr = ptr;
while(MEM8[curr] != 0)
curr++;
return (curr - ptr);
}
var ptr = "demo";
var len = strlen(ptr);
for(var i = 0; i < len; i++)
{
document.write(ptr[i]);
}
Asm.js:
function strlen(ptr)
{
ptr = ptr | 0;
var curr = 0;
curr = ptr;
while (MEM8[curr]|0 != 0)
{
curr = (curr + 1) | 0;
}
return (curr - ptr) | 0;
}
var ptr = "demo";
var len = strlen(ptr) | 0;
for(var i = 0; i < len; i++)
{
document.write(ptr[i]);
}
Je ne garantis pas que document.write soit validé, il est là pour la démonstration.
Emscriptem avec l'option ASM_JS=1 produit du code Asm.js au lieu de JavaScript.
Documentation
- Specification.
- Bananabench. Démo de 3D dans le navigateur.
- Monster Madness (vidéo). Un jeu 3D commercial porté en Asm.js (en une semaine) avec Emscriptem parce qu'il a été écrit en C++, totalement fonctionnel, fonctionnant dans le navigateur!
- Un jeu fait en asm.js. Vidéo. Le jeu est réalisé avec Unity ou en C et converti pour fonctionner dans le navigateur et donc sous tout OS!