--- title: Intro a WebAssembly (wasm). tags: DAW, wasm --- <div style="width: 30%; margin-left: auto;"> ![](https://hackmd.io/_uploads/HJiR4eGJT.png) </div> <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Llicència de Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a><br />Aquesta obra està subjecta a una llicència de <a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/">Reconeixement-CompartirIgual 4.0 Internacional de Creative Commons</a> # Intro a Web Assembly. ![imagen](https://hackmd.io/_uploads/HkX3zO2nT.png) Segons la pròpia [pàgina oficial](https://webassembly.org), WebAssembly es pot definir com: > WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications. ## Corolaris que s'extreuen directament de la definició: 1. WebAssembly **no** es javascript, és un format binari totalment diferent. 2. WebAssembly corre sobre una màquina virtual basada en pila. 3. WebAssembly està dissenyat per a poderse compilar a partir de diferents llenguatges i facilitar el desplegament a través de la web. ## Principis de disseny de WebAssembly: 1. Efficient i ràpid: L'objectiu de la màquina de pila Wasm, és apropar-se a la velocitat nativa. 2. Segur: L'execució de WebAssembly es produeix dins d'un 'sand box' i en el cas de la web, reforça les polítiques d'origen comú: 'same origin' i polítiques de seguretat del navegador. 3. Oberta i depurable: WebAssembly està dissenyada per a poder representar-se en forma de text agradablement formatat per motius de depuració, proves, optimització, aprenentatge o inclús per a poder escriure programes a ma en format wasm. 4. Part de la plataforma web: Els mòduls de WebAssembly són capaços de fer crides al context de JavaScrip i accedir a la funcionalitat del navegador a través de la mateixa API a la que accedeix JavaScript. ## [Conceptes clau](https://developer.mozilla.org/en-US/docs/WebAssembly/Concepts#webassembly_key_concepts): 1. Module: Represents a WebAssembly binary that has been compiled by the browser into executable machine code. A Module is stateless and thus, like a Blob, can be explicitly shared between windows and workers (via postMessage()). A Module declares imports and exports just like an ES module. 2. Memory: A resizable ArrayBuffer that contains the linear array of bytes read and written by WebAssembly's low-level memory access instructions. 3. Table: A resizable typed array of references (e.g. to functions) that could not otherwise be stored as raw bytes in Memory (for safety and portability reasons). 4. Instance: A Module paired with all the state it uses at runtime including a Memory, Table, and set of imported values. An Instance is like an ES module that has been loaded into a particular global with a particular set of imports. ## Diferents maneres d'utilitzar WebAssembly: 1. Portar una aplicació C/C++ amb Emscripten. 2. Escriure o generar WebAssembly directament a nivel d'ensamblador. 3. Escriure una aplicació en Rust i compilar a WebAssembly. 4. Utilitzar AssemblyScript que s'assembla a TypeScript es compila a un binari de WebAssembly. ## Generant mòduls wasm a partir de codi C/C++. ### Instal·lació d'Emscripten. Les passes necessàries per instal·lar el SDK d'Emscripten les podeu trobar a la [pàgina oficial](https://emscripten.org/docs/getting_started/downloads.html), però us aconsello que comenceu fent ús de la [imatge Docker](https://hub.docker.com/r/emscripten/emsdk#!) preparada a tal efecte. Amb la següent comanda, obtindreu accés a la terminal del contenidor amb la carpeta on heu executat l'ordre montada com a un volum Docker a la ruta '/src' del contenidor. ```bash= docker run -it -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk bash ``` ```bash= xavi@portatil:~/Documentos/wasm$ docker run -it -v $(pwd):/src -u $(id -u):$(id -g) emscripten/emsdk bash groups: cannot find name for group ID 131 emscripten@4fa4fc854c38:/src$ ls favicon.ico hello.html hello.js hello.wasm hello_wasm.html helloworld.cpp helloworld.js helloworld.wasm emscripten@4fa4fc854c38:/src$ ``` ### Generació i compilació del codi C++ d'exemple. Partirem d'un fitxer helloworld.cpp típic: ```cpp= #include <iostream> int main() { std::cout << "Hello World!\n"; return 0; } ``` I el compilarem amb l'eina emcc que tenim preparada al contenidor: ```bash= emscripten@4fa4fc854c38:/src$ emcc helloworld.cpp -o helloworld.js cache:INFO: generating system asset: symbol_lists/27772d71a5153dd93f16df2df7cc5d46369da5ac.json... (this will be cached in "/emsdk/upstream/emscripten/cache/symbol_lists/27772d71a5153dd93f16df2df7cc5d46369da5ac.json" for subsequent builds) cache:INFO: - ok ``` Ara ja tenim el nostre mòdul .wasm i el _codi adhesiu_ ('glue code'): ```bash= emscripten@4fa4fc854c38:/src$ ls -l total 360 -rw-rw-r-- 1 emscripten emscripten 16655 Feb 28 07:16 favicon.ico -rw-rw-r-- 1 emscripten 131 246 Feb 28 08:19 hello_wasm.html -rw-rw-r-- 1 emscripten 131 85 Feb 28 08:15 helloworld.cpp -rw-r--r-- 1 emscripten 131 175276 Feb 28 09:40 helloworld.js -rwxr-xr-x 1 emscripten 131 161689 Feb 28 09:40 helloworld.wasm ``` El fitxer hello_wasm.html ha estat creat a ma. També és possible que el propi compilador emcc ens generi un fitxer html, però no és tant instructiu com aquest codi minimalista escrit a ma: ```htmlembedded= <!DOCTYPE html> <html lang="ca"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Hello wasm!</title> </head> <body> <script src="helloworld.js"></script> </body> ``` El resultat el podem veure a la següent imatge: ![imagen](https://hackmd.io/_uploads/SyhigKnhT.png) ### Integració del codi C al navegador. #### ccall i cwrap Utilitzarem els seguents fitxers: 1. Un programa en c: wrapping.c 2. Un document html: wrapping.html ```clike= // wrapping.c #include <stdio.h> #include "emscripten.h" EMSCRIPTEN_KEEPALIVE int suma(int a, int b) { return a + b; } EMSCRIPTEN_KEEPALIVE int main() { printf("Hello World!, %d\n", suma(4, 6)); return 0; } ``` ```htmlembedded= <!DOCTYPE html> <html lang="ca"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>wrapping.html</title> <script src="wrapping.js"></script> <script> function run_wasm() { var suma = Module.cwrap("suma", "number", ["number","number"]); var result = Module.ccall( "main", "number", null, null ); console.log(result); var a = document.querySelector("#a").value; var b = document.querySelector("#b").value; var result = Module.ccall( "suma", "number", ["number","number"], [a, b] ); console.log(result); console.log(suma(a,b)); } </script> </head> <body> <input type="number" id="a"> <input type="number" id="b"> <button onclick="run_wasm()">Run Wasm</button> </body> </html> ``` I compilarem el codi amb el següent modificador: ```bash= emcc wrapping.c -o wrapping.js -sEXPORTED_RUNTIME_METHODS=ccall,cwrap ``` ![imagen](https://hackmd.io/_uploads/r11yu932T.png)