## WebAssembly ### Motivation - Web applications become more complex - e.g., audio, video, 3D objects, games - Problem with JavaScript: - Slow execution time compared to native code - But: No real alternative exists - Performance improved by Just-In-Time compiling (only works sometimes) - Alternative languages failed (e.g., ActiveX, Flash, Java) - Current trend: - Transform other languages to JS - Use languages with better concepts - e.g., TypeScript having type safety - Use languages with better performance - e.g., C++ code is transpiled to `asm.js` - `asm.js` a faster subset of JS (foundation for WebAssembly) - References: [WASM concepts](https://developer.mozilla.org/en-US/docs/WebAssembly/Concepts) --- ### Basics - WebAssembly (WASM) is a byte-code format - Secure - Rapidly executable (performance) - Portable - Security: - In other languages security is achieved by the interpreter/runtime environment - Low-level code can not be secured that easy - Performance - WASM is *ahead-of-time* compiled - Performance of *ahead-of-time* compiled code is better than interpreted code - Format must be compact for fast loading - Portable - Important property for web technology - Requires that the format is hardware- and platform-independent - Summary - Supported by many browsers - No multithreading --- ### Technical Realization - Technical: - WASM realizes a virtual Instruction Set Architecture (ISA) - ISA can be target of different programming languages - e.g., compile C++/Rust to WASM - Requires languages with static memory management - WASM vs. JavaScript: - WASM is loaded faster - WASM is executed faster - Code format: - Low-level byte-code format - Has a binary and textual representation (equal) - Supporting 32-bit/64-bit integers (i32, i64) - Supporting floating point numbers (f32, f64) ![](images/08-highlevel.png) ![](images/08-js-vs-wasm.png) #### Concepts - *Module*: - Compiled binary program - Stateless - Can be shared with Web Workers - A Program is called *module* - Memory: - Provides an ArrayBuffer (variable length) - Represents the memory section of the program - Table: - Array with variable size for references - These could not otherwise be stored in the memory segment (portability or security reasons) - Instance: - Instance of a module paired with a memory and a table - Stateful and resolved imports - Comparable to ES2015 module ![](images/08-module.png) #### Module Sections (Anatomy) 1. Type - *Function signature declaration* - Contains all functions declarations of the module - Example: - `(i32 i32 -> i32) // func_type #0` - `(i64 -> i64) // func_type #1` 2. Import - *Import declarations* - Lists external dependencies (module name, field name and type) - Browser resolves the dependencies - Enable dynamic linking - Enable the embedding of other modules and the use of extern functions - Example: - `("dumb-math", "quadruple", (func_type 1)) // func #0` 3. Function - *Function declarations* - Define an *index* of functions implemented by the code segment - Call functions by their index (`func #N`) - Example: - `(func_type 1) // func #1` 4. Table - *Indirect function table* - Contains one or more tables - Tables contain elements which are not directly accessible by WASM (e.g., JS objects, file descriptors) - Connect the low-level un-trustable linear memory and the higher-level language functions and references 5. Memory - *Memory attributes* - Allocate additional/optional memory for the module - Requires initial and maximal size 6. Global - *Global declarations* - Declare all global variables (cf., `static` from C++) 7. Export - *Exports* - Define all extern accessible elements - e.g., `("half" (func 1))` - "half" can be combined to `function half(arg0:int64):int64` using the *function* and the *type* section - This can be functions, tables, memory segments and global variables 8. Start - *Start function declaration* - Define a *main()*-function - Function is called if the module is loaded 9. Element - *Elements section* - Initialize the previously imported or previously defined tables 10. Code - *Function bodies* - Contains code of all functions - Functions are provided by the order in the index (function section) - WASM represents an abstract stack-machine - Additional operations: `div`, `add`, `eqz` (check if zero) 11. Data - *Data segments* - Set imported and locally defined memory regions - e.g., reserve 4 bytes for an i32 value --- ### Operations #### Translation and Execution - Translation (`emscripten`): 1. Clang/LLVM compiler takes C++ files 2. Clang/LLVM generates a intermediate representation 3. Emscripten converts intermediate representation to a `.wasm` file (module) - Execution: - Problem: WASM can **not** access the DOM - Only call JS functions exchanging integers and floats - *Glue code*: Emscripten provides helper functions (enable connection between WASM and browser API) - Emscripten helper functions: - Provides popular C++ libraries - e.g., SDL, OpenGL, OpenAL, POSIX - Must be connected to Web API of the browser - Must be provides on loading the module - e.g., redirect stdout to a textarea - Using JS it is possible to generate WASM modules (using the plain text format) - Example: `emcc hello.c -s WASM=1 -o hello.html` - `-s WASM=1`: Create WASM code - `-o hello.html`: Create template with helper functions - Result: `hello.{wasm,js,html}` ![](images/08-emscripten.png) #### Calling Functions - To use a WASM function in JavaScript, mark the function using `EMSCRIPTEN_KEEPALIVE` - To keep the module running after calling the main() function, compile with `NO_EXIT_RUNTIME=1` - Calling function from JavaScript: - `Module.ccall('myFunc', null, null, null);` - 1st argument: Name of function - 2nd argument: Return type - 3rd argument: Argument types - 4th argument: arguments ![](images/08-function-call.png) #### Importing Functions - Situation: WASM code imports a function I - Script must function I to JS function #### Loading Modules - Two types: - Classic loading and translation - Streaming API ![](images/08-loading.png) #### Using Memory - Each module has its own memory region (address starts at 0) - Goal: Isolation between instances - JavaScript perspective: - WASM module memory is ArrayBuffer with variable length - Memory can also be creating using JS - `var m = new WebAssembly.Memory({initial: 10, maximum: 100})` - Allocate multiple of 64 KB - Access: - Getter/setter - `new Uint32Array(memory.buffer)[0] = 42` - Increase memory: - `memory.grow(bytes)` - Until the maximum size (then, `WebAssembly.RangeError`) - Memory can be accessed from both sides: - Advantages: - Initialize memory while module is loaded (save time) - Use memory in multiple instances (realize dynamic linking) #### Using Tables - Tables are the only way to call functions - Tables can be accessed/edited/resized by JS - Functionality is required for dynamic linking #### Caching - Problem: - Complex applications have a lot code which must be compiled - Idea: Store the compiled modules in an IndexedDB - Use versioning to get correct version