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

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