Il numero di ap­pli­ca­zio­ni che girano su browser e che, quindi, non sono in­stal­la­te su disco rigido, è in costante crescita. Oltre ai classici software da ufficio come Microsoft 365 e Google Docs, che pre­sen­ta­no sempre nuove funzioni, anche i giochi basati su browser si fanno sempre più complessi e ri­chie­do­no quindi maggiori risorse. Anche se, spesso, tali ap­pli­ca­zio­ni web sono di­spo­ni­bi­li in Ja­va­Script, un numero sempre crescente di svi­lup­pa­to­ri sta invece puntando a We­bAs­sem­bly, un nuovo tipo di approccio dai risultati davvero sor­pren­den­ti.

Cos’è We­bAs­sem­bly?

We­bAs­sem­bly (Wasm) è una nuova soluzione a di­spo­si­zio­ne degli svi­lup­pa­to­ri web al fine di creare delle ap­pli­ca­zio­ni di­spo­ni­bi­li online. Finora l’unica risorsa di­spo­ni­bi­le in tal senso era Ja­va­Script, un lin­guag­gio che, tuttavia, risulta piuttosto lento e, in alcuni casi, anche limitato. Il World Wide Web Con­sor­tium (W3C) ha quindi deciso di avviare lo sviluppo di un nuovo metodo, appunto, il We­bAs­sem­bly. Per per­met­te­re a Wasm di fun­zio­na­re, anche il relativo browser deve tuttavia essere in grado di gestire il lin­guag­gio in questione ed è per questo che Mozilla (Firefox), Microsoft (Edge), Apple (Safari) e Google (Chrome) hanno par­te­ci­pa­to allo sviluppo di Wasm. Su tutte le attuali versioni dei browser dei vari pro­dut­to­ri è quindi possibile eseguire le ap­pli­ca­zio­ni in We­bAs­sem­bly.

Consiglio

Al fine di testare per­so­nal­men­te l’ef­fi­cien­za di We­bAs­sem­bly vale si­cu­ra­men­te la pena provare Funky Karts. Il gioco, che è a tutti gli effetti un’app mobile, è stato con­ver­ti­to in We­bAs­sem­bly in modo da poter essere eseguito anche su browser. Nel corso del progetto lo svi­lup­pa­to­re ha anche rea­liz­za­to un in­te­res­san­te blog, all’interno del quale ha il­lu­stra­to i singoli passaggi relativi alla con­ver­sio­ne.

In linea di principio We­bAs­sem­bly consiste in bytecode, che possono essere con­si­de­ra­ti un passaggio in­ter­me­dio tra un codice macchina, com­pren­si­bi­le soltanto per i computer, e un tipico lin­guag­gio di pro­gram­ma­zio­ne che risulta sì com­pren­si­bi­le agli umani, ma che deve essere tuttavia prima compilato. Infatti, se comparato ad altri linguaggi, We­bAs­sem­bly sembra estre­ma­men­te veloce, dal momento che il computer impiega po­chis­si­me risorse per tra­sfor­ma­re il codice di scrittura. Tuttavia, quella di scrivere in bytecode è un’ope­ra­zio­ne alquanto inusuale: il vantaggio legato a Wasm consiste proprio nel fatto di non dover lavorare con questo lin­guag­gio di pro­gram­ma­zio­ne.

In pratica, l’ap­pli­ca­zio­ne può essere scritta in C o C++ e il codice sorgente viene poi tra­sfor­ma­to tramite l’ap­pli­ca­zio­ne Em­scrip­ten. Questo strumento era già uti­liz­za­to prima dello sviluppo di We­bAs­sem­bly al fine di tra­sfor­ma­re il codice C/C++ in Ja­va­Script (e asm.js). In tal modo, il codice può comunque essere riscritto anche in Wasm, essendo quindi compilato a priori e senza la necessità di essere compilato o in­ter­pre­ta­to in fase di ese­cu­zio­ne. Infine, nel momento in cui l’utente apre l’ap­pli­ca­zio­ne all’interno del browser, si avvia una piccola macchina virtuale all’interno della quale gira l’ap­pli­ca­zio­ne.

I vantaggi offerti da We­bAs­sem­bly

At­tual­men­te We­bAs­sem­bly presenta un unico svan­tag­gio concreto, ovvero la lentezza legata alla sua dif­fu­sio­ne. Infatti, gli svi­lup­pa­to­ri web sono abituati a lavorare con Ja­va­Script di cui, in generale, non è prevista la so­sti­tu­zio­ne. La direzione del progetto We­bAs­sem­bly dà quindi grande im­por­tan­za alla co­mu­ni­ca­zio­ne fi­na­liz­za­ta a pre­sen­ta­re i vantaggi di Wasm come soluzione ag­giun­ti­va a Ja­va­Script. Tuttavia, grazie al supporto offerto dai maggiori svi­lup­pa­to­ri di browser e dal W3C, la dif­fu­sio­ne di Wasm sta pro­gres­si­va­men­te au­men­tan­do. Questo è legato anche al fatto che gli utenti, in fase di accesso a un sito, non debbano eseguire au­to­no­ma­men­te alcuna ope­ra­zio­ne: caricare le ap­pli­ca­zio­ni web in We­bAs­sem­bly risulta infatti semplice quanto in Ja­va­Script, con il vantaggio di essere più veloce.

Dunque, molti svi­lup­pa­to­ri che uti­liz­za­no già i linguaggi C, C++ o, ad esempio, Rust hanno ora la pos­si­bi­li­tà di creare di­ret­ta­men­te programmi anche per il web. Talvolta i linguaggi di pro­gram­ma­zio­ne prevedono anche ulteriori modalità per strut­tu­ra­re l’ap­pli­ca­zio­ne. Chi su Ja­va­Script non dovesse trovare le librerie o i framework necessari al proprio programma, avrà ora a di­spo­si­zio­ne una scelta più ampia per rag­giun­ge­re il proprio scopo. Gli svi­lup­pa­to­ri hanno quindi diversi motivi per con­si­de­ra­re più da vicino We­bAs­sem­bly:

  • È uno standard web aperto del W3C
  • Offre grandi per­for­man­ce e file poco pesanti
  • Risulta per­fet­ta­men­te adat­ta­bi­le anche alla na­vi­ga­zio­ne mobile
  • Offre la pos­si­bi­li­tà teorica di svi­lup­pa­re anche programmi di realtà virtuale su browser
  • Non necessita di un nuovo lin­guag­gio di pro­gram­ma­zio­ne
  • Consente di uti­liz­za­re anche C, C++ o Rust per la pro­gram­ma­zio­ne di ap­pli­ca­zio­ni web
  • È sup­por­ta­to da tutti i maggiori svi­lup­pa­to­ri di browser
  • Non presenta alcuna li­mi­ta­zio­ne per gli utenti

We­bAs­sem­bly nella pratica

Non è prevista la pro­gram­ma­zio­ne tramite We­bAs­sem­bly. Il vantaggio più grande della tec­no­lo­gia è proprio il poter uti­liz­za­re un lin­guag­gio a pia­ci­men­to come C per poi con­ver­tir­lo nel potente formato Wasm. Tuttavia può anche risultare sensato lavorare sul codice già compilato e ana­liz­za­re il fun­zio­na­men­to di We­bAs­sem­bly.

Il codice sorgente è di­spo­ni­bi­le in due diverse varianti: We­bAs­sem­bly Text Format (WAT) e We­bAs­sem­bly Binary Format (Wasm). L’ultimo è il codice effettivo azionato dalla macchina. Siccome però è co­sti­tui­to esclu­si­va­men­te da codice binario, è più o meno inu­ti­liz­za­bi­le per un’analisi umana. Per questo motivo esiste la forma in­ter­me­dia WAT. Un simile codice impiega espres­sio­ni leggibili e può quindi essere studiato dagli stessi pro­gram­ma­to­ri, tuttavia non offre il comfort di lavoro offerto invece da altri linguaggi di pro­gram­ma­zio­ne affermati.

Come esempio ci serviamo di un codice sorgente molto semplice in lin­guag­gio C:

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

Il medesimo codice in formato WAT è vi­si­bil­men­te più lungo:

(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)))

A questo punto la leg­gi­bi­li­tà è già for­te­men­te limitata, ma qualche elemento è in­di­vi­dua­bi­le: in­nan­zi­tut­to con We­bAs­sem­bly è tutto suddiviso in moduli. Questi moduli sono a loro volta suddivisi in funzioni spe­ci­fi­ca­te da parametri. Nel complesso si possono ri­co­no­sce­re 5 diversi elementi:

  • module: unità più elevata di We­bAs­sem­bly
  • function: rag­grup­pa­men­to all’interno di un modulo
  • memory: array con bytes
  • global: valore uti­liz­za­bi­le per più moduli
  • table: memoria per ri­fe­ri­men­ti

Se però il codice viene tradotto in forma binaria niente di tutto ciò è più ri­co­no­sci­bi­le:

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
Consiglio

Chi desidera provare a muovere i primi passi in We­bAs­sem­bly può uti­liz­za­re We­bAs­sem­bly Studio, all’interno del quale troverà un ambiente di sviluppo online per Wasm.

Vai al menu prin­ci­pa­le