WebAssembly / Wasm pour plus de puissance sur le web ?

Présen­té en 2015 par Bren­dan Eich, le créa­teur de JavaScript et en par­tie d’Asm.js, WebAssem­bly ou wasm pour les intimes, est un nou­veau lan­gage de représen­ta­tion inter­mé­di­aire (IRL) com­pat­i­ble avec tous les nav­i­ga­teurs.

WebAssem­bly est au web ce que l’assembleur est à votre ordi­na­teur.  Les plus anciens d’entre-nous con­nais­sent bien l’assembleur car à l’époque, c’était la seule façon d’étendre les capac­ités de nos librairies stan­dards de pro­gram­ma­tion. Et puis, c’était aus­si la garantie (à con­di­tion de ne pas coder avec les pieds) d’avoir des fonc­tions ultra-rapi­des et dont nous avons la par­faite maitrise ! Wasm, c’est exacte­ment ça !

Dans cet arti­cle, je vous pro­pose de repar­ler un peu d’assembleur. Puis je vous présen­terai Wasm, son fonc­tion­nement, son inté­gra­tion à Emscripten. Et enfin, nous finirons par des petits tests à la “hel­lo world”, mais en WASM et en WAST.

Qu’est-ce que l’assembleur ?

Pour résumer, on prend un script com­posé d’un ensem­ble d’instructions rel­a­tive­ment lim­ité et adap­té à un type par­ti­c­uli­er de processeur, et on l’assemble pour for­mer un code binaire que le processeur com­prend directe­ment. Selon les besoins, on le “link­era” avec divers librairies, écrites ou non en assem­bleur.

Exé­cuter un code binaire con­siste à “branch­er” directe­ment le processeur dans une zone mémoire grâce à son poin­teur d’instructions. Cette zone con­tient notre binaire chargé par le sys­tème d’exploitation. Ain­si, le processeur va inter­préter une série de “A0 0F 23 5E…” comme autant d’instructions qu’il recon­nait (com­mençant par un opcode). Il n’y a rien de plus proche de la machine que ce lan­gage dit “binaire” car il s’agit ni plus ni moins qu’une suc­ces­sion de 0 et de 1 à son niveau.

Un pro­gramme écrit dans un lan­gage dit “de haut niveau” (car plus éloigné de la machine) néces­site d’être inter­prété ou com­pilé. La com­pi­la­tion con­siste à le trans­former dans un lan­gage inter­mé­di­aire, voir en assem­bleur lorsqu’on cible un processeur par­ti­c­uli­er. De par sa nature “haut niveau”, il est aus­si beau­coup plus portable.

Per­son­ne (à ma con­nais­sance) ne sait coder directe­ment en binaire, ou alors pour de tout petits pro­grammes, pour déboguer un dri­ver, etc. Mais cette forme de pro­gram­ma­tion n’est absol­u­ment pas adap­té à l’être humain.Il faudrait mémoris­er tous les opcodes, penser les vari­ables en terme de zone mémoire, etc. C’est qua­si­ment impos­si­ble pour un être nor­male­ment con­sti­tué.

Par con­tre, l’assembleur est vrai­ment très sim­ple d’accès. Pour moi, il est bien plus facile d’apprendre à pro­gram­mer en assem­bleur qu’en tout autre lan­gage (Bon, plus facile sur un RISC qui a un nom­bre d’instructions lim­ité que sur un CISC comme la majorité de nos PC et pour lesquels le jeu d’instruction est de plus en plus impor­tant).

La dif­fi­culté quand on est proche de la machine, c’est qu’il est aus­si plus long, plus dif­fi­cile de créer des pro­grammes impor­tants. Et ces derniers sont bien plus dif­fi­cile à main­tenir dans le temps. D’où l’intérêt de mix­er des lan­gages de haut niveau comme le C++ avec des librairies écrites en assem­bleur pour les par­ties les plus sen­si­bles, celles qui deman­dent le plus d’optimisations.

Main­tenant, si vous n’êtes pas un “codeur assem­bleur”, je ne vais pas vous con­seiller ce ter­rain. Il faut savoir que les com­pi­la­teurs mod­ernes sont telle­ment opti­misés qu’il est très sou­vent dif­fi­cile de faire mieux. J’avais créé une librairie il y a quelques années en assem­bleur pour exploiter les instruc­tions SIMD des processeurs AMD64 (SSE), et assez rapi­de­ment l’option est apparue sous GCC (Com­pi­la­teur Gnu C). Au final, le com­pi­la­teur savait exploiter de lui-même ces nou­velles instruc­tions et mes rou­tines assem­bleur n’apportaient qua­si­ment plus rien.  Sauf qu’un pro­gramme con­tenant une par­tie de son code en assem­bleur perd beau­coup en porta­bil­ité. Si vous écrivez un pro­gramme en C en util­isant la librairie stan­dard, vous pour­rez le com­pil­er pour votre PC (x64), votre Rasp­ber­ry, votre mobile android (ARM), votre Atari (m68000), votre CPC (z80)… Mais s’il est en assem­bleur, il vous fau­dra réécrire le code pour chaque processeur car les instruc­tions ne sont pas les mêmes.

Si vous n’êtes pas famil­iarisé avec l’assembleur, je vous pro­pose de par­courir rapi­de­ment cet arti­cle sur l’assembleur x64 et de con­sul­ter cette page.

Qu’est-que que Wasm ?

C’est un code binaire  qui est chargé directe­ment par le nav­i­ga­teur. Bien enten­du, il ne sera pas lu directe­ment par le processeur de votre ordi­na­teur, mais par une machine virtuelle (comme le byte­code et Java). Et grâce à cette machine virtuelle inter­mé­di­aire, vous n’avez plus de soucis de porta­bil­ité. Un seul code, une MV / processeur.

A quoi cela sert-il ? On avait déjà la com­pi­la­tion Just-In-time per­me­t­tant de traduire des scripts à la volée pour qu’ils soient exé­cutés rapi­de­ment par votre ordi­na­teur. L’intérêt est ici qu’il n’y a pas de temps de com­pi­la­tion inter­mé­di­aire (bon, y-a une machine virtuelle quand même), que le code binaire est beau­coup plus petit et qu’il charge donc plus rapi­de­ment, et qu’on peut ain­si pro­téger son code !

Vous avez déjà util­isé un moteur 3D pour le web codé en Javascript ? Sou­vent, la seule pro­tec­tion con­siste à ren­dre illis­i­ble le code en sup­p­ri­mant les blancs inutiles à la com­pi­la­tion et les com­men­taires… mais le code reste lis­i­ble — c’est du javascript. Là, allez lire du WASM. Ca reste pos­si­ble… tout comme on peut décom­pil­er un pro­gramme binaire… mais c’est vrai­ment pas ragoutant.

WASM est Open Source, sous licence Apache. Vous pou­vez aller jeter un oeil à son dépôt Github.

Wasm est conçu sous stan­dard ouvert W3C (com­prend des représen­tants de tous les prin­ci­paux nav­i­ga­teurs). Tout a été pen­sé pour qu’il soit plus rapi­de à analyser et à exé­cuter que javascript. Ain­si, il est pos­si­ble de charg­er des mod­ules WebAssem­bly dans une appli­ca­tion javascript et de partager les fonc­tion­nal­ités per­me­t­tant de prof­iter de la per­for­mance de WebAssem­bly et de la puis­sance et la flex­i­bil­ité de JavaScript dans les mêmes appli­ca­tions, même si vous ne savez pas com­ment écrire du code WebAssem­bly.

WebAssem­bly per­met aux appli­ca­tions com­plex­es de fonc­tion­ner de façon opti­male sur tous les nav­i­ga­teurs le sup­por­t­ant :

  • jeux vidéo 3D
  • appli­ca­tions peer to peer (jeux, édi­tion col­lab­o­ra­tive, cen­tral­isée et décen­tral­isée)
  • réal­ité virtuelle et réal­ité aug­men­tée ( besoin d’une latence très faible)
  • appli­ca­tions de musique (stream­ing, mise en cache)
  • mon­tage d’images et vidéos
  • recon­nais­sance d’images, IA
  • visu­al­i­sa­tion et sim­u­la­tion sci­en­tifique
  • inter­prètes de langues et machines virtuelles
  • bureau à dis­tance
  • cryptage

Les développeurs peu­vent utilis­er WebAssem­bly pour accélér­er les appli­ca­tions web.

Wasm et Emscripten

Vous n’écrivez bien sûr pas en code binaire, tout comme pour l’assembleur. C’est un out­il qui com­pile en binaire… C’est un peu l’idée sous-jacente à LLVM/Emscripten. Rap­pelez-vous, on en a sou­vent par­lé. Avec Clang, LLVM per­met, par exem­ple, à un moteur comme Unre­al Engine qui est écrit en C++ d’exporter des jeux et des appli­ca­tions en HTML5/WebGL. Avec WASM, c’est la même démarche: vous pro­gram­mez en lan­gage C, C++, Rust, …  et votre code, au lieu d’être com­pilé en Assem­bleur, le sera en “Web Assem­bleur”.

Le tableau ci-dessous représente 3 vues dif­férentes d’un même code:

Le for­mat binaire n’est pas conçu pour être util­isé par les humains. C’est par exem­ple emscripten qui va traduire le C++ en for­mat wasm directe­ment.

Ain­si, le for­mat texte (WAST) est lis­i­ble par l’homme (la spé­ci­fi­ca­tion est tou­jours en cours de final­i­sa­tion) et per­met d’écrire ou de mod­i­fi­er le code pour déboguer. Vous trou­verez la doc­u­men­ta­tion com­plète sur emscripten.

Pourquoi un nou­veau lan­gage inter­mé­di­aire? Pourquoi ne pas utilis­er sim­ple­ment LLVM, le byte­code Java, ou .NET?  Le bit­code LLVM n’a pas été retenu parce qu’il n’est pas portable. Il con­tient des méta-don­nées et est conçu pour pro­duire des binaires exé­cuta­bles, non pour fonc­tion­ner directe­ment sur tous les sys­tèmes. Cepen­dant on utilise Emscriptem pour com­pil­er le lan­gage inter­mé­di­aire de LLVM en wasm, donc on garde le béné­fice de ses out­ils.

Wasm veut être aux appli­ca­tions dans le nav­i­ga­teur ce que Vulkan est à OpenGL et Direc­tX: un code inter­mé­di­aire uni­versel et portable avec une vitesse d’exécution proche du natif.

Où trouver ce Wasm ?

Le plus drôle, c’est que le nav­i­ga­teur que vous utilisez pour lire ce blog a prob­a­ble­ment déjà la capac­ité de lire le Wasm.

Il est main­tenant activé sur les nav­i­ga­teurs Fire­fox 52, Mozil­la, Chrome 57, Edge, Opera et Webkit.

Voici un exem­ple de démo util­isant Wasm:

Ahah, vous l’avez recon­nu… ben oui, c’est de l’Unreal Engine exporté en HTML5/WebGL. Oui, ça repose sur Wasm!

Bon, une vidéo c’est bien, mais une véri­ta­ble démo c’est mieux non ? On va être fair­play, celle-ci a été dévelop­pée sous Uni­ty. Essayez-là, c’est vous le petit tank rouge, pour tir­er c’est la touche “entrée”.

Bon, c’est bien tout ça, mais si tu es développeur, tu as peut-être envie de tester toi même du code Wasm, sans pass­er par une solu­tion inter­mé­di­aire. Pour cela, il te faut déjà aller sur GitHub pour récupér­er les out­ils:

  • Wabt — The Web Assem­bly Bina­ry Toolk­it: con­tient les out­ils prin­ci­paux.
  • Water­fall: Du python et du Wasm pour faire des bots? ça vous rap­pelle pas mon précé­dent arti­cle ? 😉
  • wasm-jit-pro­to­type: pour pou­voir utilis­er wasm en dehors du nav­i­ga­teur. Il s’agit d’une ver­sion “stand­alone” de la machine virtuelle util­isée par LLVM JIT.
  • Bina­ryen : Script pour exé­cuter le code wasm en ligne de com­mande.
  • Was­mint: librairie pour inter­préter et déboguer du code WASM dans une appli C++.

On fait un test ?

Tout d’abord, on va tester WASM via Emscripten. Pour la suite, je vais con­sid­ér­er que vous êtes sous Lin­ux. Si ce n’est pas le cas et que vous êtes sous Win­dows 10, ce n’est pas grave, il suf­fit que le BASH soit activé activé.

Si vous n’êtes pas un afi­ciona­do de Lin­ux, sachez que quand je vous dis que vous avez besoin de xxx instal­lé, il suf­fit que vous lan­ciez sudo apt-get install xxx pour que xxx soit instal­lé automa­tique­ment. Sous Bash/Win10, ça fonc­tionne stricte­ment de la même façon.

Pour la suite il faut installer les out­ils suiv­ants: make, gcc, clang, bison, cmake, g++.

Pour Emscripten:

Cela va pren­dre un cer­tain temps. Puis, lancez:

$ source ./emsdk_env.sh

Une fois instal­lé, créez ce petit pro­gramme “hello.c” en C:

Lancez la com­pi­la­tion par ”

$ emcc hello.c -s WASM=1 -o hello.html

Testez ensuite en laçant hello.html dans votre nav­i­ga­teur web:

Nous venons donc de trans­former du C en quelque-chose de lis­i­ble en HTML. Bon, rien de tran­scen­dant, et pour­tant. En temps nor­mal, si on n’utilise pas “WASM=1”, emscripten ne créé que 2 fichiers: hello.html et hello.js.

Mais avec cette option, le code de hel­lo est bien dans un WASM, les autres fichiers n’étant présents que pour per­me­t­tre de lancer ce fichi­er binaire.

Main­tenant, si vous souhaitez installer les out­ils spé­ci­fiques du sdk de WASM:

Sans installer, vous pou­vez déjà voir plusieurs exem­ples à cette page. Si on prend l’exemple du fac­to­riel, voici le fichi­er WAST à gauche et une par­tie du WASM à droite (cliquez dessus pour agrandir):

Le fichi­er .WAST, c’est le script à l’origine du binaire. C’est l’équivalent du fichi­er .ASM avant d’être assem­blé en binaire. Et à droite, il s’agit du WASM, mais sous forme textuel et com­men­té pour mieux com­pren­dre.  Sinon, c’est bien un fichi­er binaire con­tenant la séquence “0061736d0d0000001000160017e017e…”.

Bon, il s’agit juste d’une petite intro à WASM. Je suis loin d’être entré dans le détail, mais nous aurons l’occasion d’y revenir un peu plus tard pour détailler un peu les out­ils et le fonc­tion­nement de ce dernier.L’important, c’est que vous ayez une notion de ce qu’est le lan­gage, de sa forme WAST, WASM, de la façon dont il est “com­pilé” via une sorte de machine virtuelle lancée en Javascript dans le nav­i­ga­teur (ou sans d’ailleurs).

En atten­dant, je vous invite à con­sul­ter la FAQ et les spé­ci­fi­ca­tions du lan­gage.

 

 

 

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.