Il existe de plus en plus d’ap­pli­ca­tions qui s'exé­cu­tent depuis un na­vi­ga­teur plutôt que de devoir être ins­tal­lées sur un disque dur. Outre les logiciels bu­reau­tiques clas­siques tels qu'Mi­cro­soft 365 ou Google Docs, dotés de nouvelles fonctions de plus en plus nom­breuses, les jeux sur na­vi­ga­teur gagnent aujourd’hui en com­plexité et né­ces­si­tent des res­sources toujours plus im­por­tantes. Ces ap­pli­ca­tions Web étaient jusqu’ici créées en Ja­vaS­cript. Aujourd’hui, les dé­ve­lop­peurs se tournent mas­si­ve­ment vers We­bAs­sem­bly, une nouvelle approche aux résultats étonnants.

We­bAs­sem­bly, qu’est-ce que c’est ?

We­bAs­sem­bly est un nouveau type de code exé­cu­table depuis un na­vi­ga­teur. Jusqu'à présent, seul Ja­vaS­cript per­met­tait de créer des ap­pli­ca­tions de ce genre. Son fonc­tion­ne­ment re­la­ti­ve­ment lent at­teig­nait ses limites dans certaines si­tua­tions. C'est ce qui a poussé le World Wide Web Con­sor­tium (W3C) à pro­mou­voir un nouveau type de code appelé We­bAs­sem­bly (Wasm en abrégé). Cependant, pour pouvoir fonc­tion­ner cor­rec­te­ment, Wasm doit être exécuté sur un na­vi­ga­teur capable de gérer ce langage. C'est pourquoi Mozilla (Firefox), Microsoft (Edge), Apple (Safari) et Google (Chrome) ont été sol­li­ci­tés pour par­ti­ci­per à son dé­ve­lop­pe­ment. Dans toutes les versions actuelles des na­vi­ga­teurs les plus courants, les ap­pli­ca­tions peuvent être exécutées en We­bAs­sem­bly.

Conseil

Pour découvrir par vous-même la puissance de We­bAs­sem­bly, nous vous con­seil­lons de jouer à Funky Karts. Ce jeu, qui est au départ une ap­pli­ca­tion mobile, a été converti en We­bAs­sem­bly pour pouvoir être exécuté dans un na­vi­ga­teur. Dans le cadre de ce projet, le dé­ve­lop­peur du jeu a tenu un blog in­té­res­sant sur lequel il a décrit les dif­fé­rentes étapes de la con­ver­sion.

Dans le principe, We­bAs­sem­bly est une forme de bytecode pour na­vi­ga­teur. Le bytecode peut être considéré comme une étape in­ter­mé­diaire entre le code machine, qui n’est com­pré­hen­sible que par l'or­di­na­teur, et un langage de pro­gram­ma­tion typique, lisible pour l'homme mais qui nécessite d’être compilé au préalable. C’est de là que We­bAs­sem­bly tire sa relative rapidité : le travail de con­ver­sion du code par l'or­di­na­teur est fortement minimisé. Mais il est gé­né­ra­le­ment assez malaisé d’écrire en bytecode. L'avan­tage de Wasm, c’est qu’il évite de devoir tra­vail­ler soi-même dans ce langage de pro­gram­ma­tion. Dans la pratique, on peut écrire une ap­pli­ca­tion Web en C ou C++, par exemple.

Le code source est ensuite converti grâce à l'ap­pli­ca­tion Em­scrip­ten. Cet outil existait avant l'arrivée de We­bAs­sem­bly : sa raison d’être était de convertir le C/C++ en Ja­vaS­cript (ou ams.js). Mais le code peut également être réécrit en Wasm. Il est pré­com­pilé, ce qui évite d'avoir à le compiler ou l’in­ter­pré­ter au moment de l'exé­cu­tion de l'ap­pli­ca­tion. Lorsque celle-ci est ouverte dans le na­vi­ga­teur, une petite machine virtuelle est au­to­ma­ti­que­ment lancée. Tech­ni­que­ment, c’est dans cette machine virtuelle que l'ap­pli­ca­tion fonc­tionne.

Les avantages de We­bAs­sem­bly

À l'heure actuelle, We­bAs­sem­bly ne connaît qu’un seul véritable frein : sa diffusion reste re­la­ti­ve­ment lente. Les dé­ve­lop­peurs Web sont habitués à tra­vail­ler sur Ja­vaS­cript, un langage dont la dis­pa­ri­tion n’est cer­tai­ne­ment pas pro­gram­mée à l’heure actuelle. La direction du projet attache par con­sé­quent une grande im­por­tance à la nécessité de pro­mou­voir Wasm comme une option com­plé­men­taire au Ja­vaS­cript. Toutefois, grâce au soutien apporté par les prin­ci­paux fa­bri­cants de na­vi­ga­teurs et par le W3C, l’uti­li­sa­tion de Wasm se répand de plus en plus vite. Le fait que les visiteurs du site Internet porteur de l'ap­pli­ca­tion ne doivent prendre aucune mesure eux-mêmes n’y est sans doute pas étranger : les ap­pli­ca­tions Web dé­ve­lop­pées en We­bAs­sem­bly se chargent aussi fa­ci­le­ment que le code en Ja­vaS­cript, et plus ra­pi­de­ment.

De plus, Wasm permet désormais aux nombreux dé­ve­lop­peurs qui écrivent en C, C++ exemple Rust de pro­gram­mer di­rec­te­ment pour Internet. Ces langages de pro­gram­ma­tion ont l’avantage d’apporter parfois d'autres options de con­cep­tion d’une ap­pli­ca­tion : quand on ne parvient pas à trouver les bi­blio­thèques ou les fra­me­works né­ces­saires à la création d’un programme en Ja­vaS­cript, cela permet de bé­né­fi­cier d’un arsenal bien plus vaste pour atteindre son objectif. Tout dé­ve­lop­peur peut donc y trouver des raisons de s’in­té­res­ser de plus près à We­bAs­sem­bly :

  • Un standard Web ouvert du W3C
  • Hautes per­for­mances pour une petite taille de fichier
  • Par con­sé­quent, il convient aussi par­fai­te­ment pour la na­vi­ga­tion mobile
  • La réalité virtuelle devient aussi théo­ri­que­ment ac­ces­sible depuis un na­vi­ga­teur
  • Il n’est pas né­ces­saire d'ap­prendre un nouveau langage de pro­gram­ma­tion
  • Au contraire, les langages C, C++ ou Rust peuvent désormais être utilisés pour la pro­gram­ma­tion d'ap­pli­ca­tions Web
  • Le projet est soutenu par tous les prin­ci­paux fa­bri­cants de na­vi­ga­teurs
  • Aucune res­tric­tion n’est imposée à l'uti­li­sa­teur

We­bAs­sem­bly en pratique

We­bAs­semby n’est pas conçu pour faire réel­le­ment de la pro­gram­ma­tion. L’avantage principal de cette technique repose sur le fait qu’elle fait appel à un langage de pro­gram­ma­tion à la fois de haut niveau et très répandu, comme C, et que ce code est ensuite transféré sur le puissant format Wasm. Il peut toutefois être très utile d’examiner le code déjà compilé et de creuser la fonction We­bAs­sem­bly.

Le code source est dis­po­nible en deux versions : We­bAs­sem­bly Text Format (WAT) et We­bAs­sem­bly Binary Format (Wasm). Ce dernier format cor­res­pond au code réel exécuté par l’or­di­na­teur. Mais dans la mesure où il est ex­clu­si­ve­ment constitué de code binaire, il est quasiment impropre à l’analyse humaine. C’est la raison pour laquelle il existe le format in­ter­mé­diaire WAT, qui utilise des ex­pres­sions lisibles et peut ainsi être déchiffré par les pro­gram­meurs. En revanche, il n’offre pas le confort de travail habituel des langages de pro­gram­ma­tions bien établis.

À titre d’exemple, nous utilisons un code source très simple en C :

#define WASM_EXPORT __attribute__((visibility("default")))
WASM_EXPORT
int main() {
    return 1;
}

Le même code en format WAT est sig­ni­fi­ca­ti­ve­ment plus long :

(module
    (type $t0 (func))
    (type $t1 (func (result i32)))
    (func $__wasm_call_ctors (type $t0))
    (func $main (export "main") (type $t1) (result i32)
        i32.const 1)
    (table $T0 1 1 anyfunc)
    (memory $memory (export "memory") 2)
    (global $g0 (mut i32) (i32.const 66560))
    (global $__heap_base (export "__heap_base") i32 (i32.const 66560))
    (global $__data_end (export "__data_end") i32 (i32.const 1024)))

La li­si­bi­lité est très limitée, mais l’on distingue tout de même les éléments suivants : dans We­bAs­sem­bly, tout le contenu est divisé en modules, eux-mêmes divisés en fonctions, spé­ci­fiées par des pa­ra­mètres. Au total on peut iden­ti­fier 5 éléments distincts :

  • Module : unité su­pé­rieure dans We­bAs­sem­bly
  • Function : re­grou­pe­ment au sein d’un module
  • Memory : tableau avec des octets
  • Global : valeur pouvant être utilisée dans plusieurs modules
  • Table : mémoire des ré­fé­rences

Cependant, lorsque le code est traduit sous forme binaire, on ne peut rien dis­tin­guer de tout ceci :

0000000: 0061 736d                                 ; WASM_BINARY_MAGIC
0000004: 0100 0000                                 ; WASM_BINARY_VERSION
; section "Type" (1)
0000008: 01                                        ; section code
0000009: 00                                        ; section size (guess)
000000a: 02                                        ; num types
; type 0
000000b: 60                                        ; func
000000c: 00                                        ; num params
000000d: 00                                        ; num results
; type 1
000000e: 60                                        ; func
000000f: 00                                        ; num params
0000010: 01                                        ; num results
0000011: 7f                                        ; i32
0000009: 08                                        ; FIXUP section size
; section "Function" (3)
0000012: 03                                        ; section code
0000013: 00                                        ; section size (guess)
0000014: 02                                        ; num functions
0000015: 00                                        ; function 0 signature index
0000016: 01                                        ; function 1 signature index
0000013: 03                                        ; FIXUP section size
; section "Table" (4)
0000017: 04                                        ; section code
0000018: 00                                        ; section size (guess)
0000019: 01                                        ; num tables
; table 0
000001a: 70                                        ; funcref
000001b: 01                                        ; limits: flags
000001c: 01                                        ; limits: initial
000001d: 01                                        ; limits: max
0000018: 05                                        ; FIXUP section size
; section "Memory" (5)
000001e: 05                                        ; section code
000001f: 00                                        ; section size (guess)
0000020: 01                                        ; num memories
; memory 0
0000021: 00                                        ; limits: flags
0000022: 02                                        ; limits: initial
000001f: 03                                        ; FIXUP section size
; section "Global" (6)
0000023: 06                                        ; section code
0000024: 00                                        ; section size (guess)
0000025: 03                                        ; num globals
0000026: 7f                                        ; i32
0000027: 01                                        ; global mutability
0000028: 41                                        ; i32.const
0000029: 8088 04                                   ; i32 literal
000002c: 0b                                        ; end
000002d: 7f                                        ; i32
000002e: 00                                        ; global mutability
000002f: 41                                        ; i32.const
0000030: 8088 04                                   ; i32 literal
0000033: 0b                                        ; end
0000034: 7f                                        ; i32
0000035: 00                                        ; global mutability
0000036: 41                                        ; i32.const
0000037: 8008                                      ; i32 literal
0000039: 0b                                        ; end
0000024: 15                                        ; FIXUP section size
; section "Export" (7)
000003a: 07                                        ; section code
000003b: 00                                        ; section size (guess)
000003c: 04                                        ; num exports
000003d: 04                                        ; string length
000003e: 6d61 696e                                main  ; export name
0000042: 00                                        ; export kind
0000043: 01                                        ; export func index
0000044: 06                                        ; string length
0000045: 6d65 6d6f 7279                           memory  ; export name
000004b: 02                                        ; export kind
000004c: 00                                        ; export memory index
000004d: 0b                                        ; string length
000004e: 5f5f 6865 6170 5f62 6173 65              __heap_base  ; export name
0000059: 03                                        ; export kind
000005a: 01                                        ; export global index
000005b: 0a                                        ; string length
000005c: 5f5f 6461 7461 5f65 6e64                 __data_end  ; export name
0000066: 03                                        ; export kind
0000067: 02                                        ; export global index
000003b: 2c                                        ; FIXUP section size
; section "Code" (10)
0000068: 0a                                        ; section code
0000069: 00                                        ; section size (guess)
000006a: 02                                        ; num functions
; function body 0
000006b: 00                                        ; func body size (guess)
000006c: 00                                        ; local decl count
000006d: 0b                                        ; end
000006b: 02                                        ; FIXUP func body size
; function body 1
000006e: 00                                        ; func body size (guess)
000006f: 00                                        ; local decl count
0000070: 41                                        ; i32.const
0000071: 01                                        ; i32 literal
0000072: 0b                                        ; end
000006e: 04                                        ; FIXUP func body size
0000069: 09                                        ; FIXUP section size
; section "name"
0000073: 00                                        ; section code
0000074: 00                                        ; section size (guess)
0000075: 04                                        ; string length
0000076: 6e61 6d65                                name  ; custom section name
000007a: 01                                        ; function name type
000007b: 00                                        ; subsection size (guess)
000007c: 02                                        ; num functions
000007d: 00                                        ; function index
000007e: 11                                        ; string length
000007f: 5f5f 7761 736d 5f63 616c 6c5f 6374 6f72  __wasm_call_ctor
000008f: 73                                       s  ; func name 0
0000090: 01                                        ; function index
0000091: 04                                        ; string length
0000092: 6d61 696e                                main  ; func name 1
000007b: 1a                                        ; FIXUP subsection size
0000096: 02                                        ; local name type
0000097: 00                                        ; subsection size (guess)
0000098: 02                                        ; num functions
0000099: 00                                        ; function index
000009a: 00                                        ; num locals
000009b: 01                                        ; function index
000009c: 00                                        ; num locals
0000097: 05                                        ; FIXUP subsection size
0000074: 28                                        ; FIXUP section size
Conseil

Si vous souhaitez faire vos premiers pas en We­bAs­sem­bly, vous pouvez vous tourner vers le Studio We­bAs­sem­bly. Vous y trouverez un en­vi­ron­ne­ment de dé­ve­lop­pe­ment en ligne pour Wasm.

Aller au menu principal