#+TITLE: Opening up the World of WebAssembly with Guile Hoot #+AUTHOR: Robin Templeton & David Thompson #+DATE: 2023-11-03 Fri #+REVEAL_INIT_OPTIONS: width:1200, height:800, controlsLayout: 'edges' # #+OPTIONS: reveal_center:t reveal_progress:t reveal_history:nil reveal_control:t # #+OPTIONS: reveal_mathjax:t reveal_rolling_links:t reveal_keyboard:t reveal_overview:t num:nil # #+OPTIONS: reveal_width:1200 reveal_height:800 #+OPTIONS: toc:nil num:nil reveal_title_slide:nil #+REVEAL_MAX_SCALE: 2 #+REVEAL_MARGIN: 0.075 #+REVEAL_MIN_SCALE: 0.5 #+REVEAL_TRANS: cube #+REVEAL_THEME: night #+REVEAL_HLEVEL: 2 #+REVEAL_ROOT: ../static/reveal.js * Opening up the World of WebAssembly with Guile Hoot Robin Templeton (they/them) David Thompson (he/him) https://spritely.institute SeaGL 2023 *** Introductions Hi, we're Robin and Dave! We work for the Spritely Institute. *** What is Spritely? #+REVEAL_HTML: We are building decentralized, secure infrastructure and standards for networked communities! We are a 501(c)(3) non-profit, research institution *** Research means collaboration #+REVEAL_HTML: *** Goblins #+REVEAL_HTML: Distributed, transactional programming with a security model you can understand. /"If you don't have it, you can't use it!"/ *** Time-traveling distributed debugger #+REVEAL_HTML: *** Time-traveling distributed debugger #+REVEAL_HTML: *** OCapN: The Object Capability Network #+REVEAL_HTML: An open standard for the next generation of networked communities. Pre-standardization effort happening now! https://ocapn.org/ *** Getting Goblins into the hands of users - Everyone has a browser, so Goblins /should/ run in the browser - ...but Goblins is written in *Guile Scheme*, not JavaScript - We need *WebAssembly* - And so does everyone else! ** What is WebAssembly? #+REVEAL_HTML:
#+REVEAL_HTML: - W3C *open standard* - *Low-level compilation target* for the web - Available in browsers since *2017* #+REVEAL_HTML:
*** Why should I give a hoot? - JavaScript is no longer the *only* game in town - *Fewer compromises* than compiling to JavaScript - *Capability* security model - Production runtimes are *fast* - Growing number of *non-browser runtimes* *** History time: JavaScript's origin story It is 1995: #+ATTR_REVEAL: :frag (fade-in fade-in fade-in fade-in fade-in fade-in) - Netscape wants to add a scripting language to Navigator - Netscape hires Brendan Eich with the promise of "Scheme in the browser" - Netscape contracts with Sun to add Java to Navigator - Netscape debates: "Why two languages?" - Management says Eich's scripting language must look like Java - The world receives JavaScript *** Before WASM: asm.js It is 2013: #+ATTR_REVEAL: :frag (fade-in fade-in fade-in fade-in fade-in fade-in) - JavaScript well-established as /the/ language of the web - Languages that compile to JS rise in popularity - Mozilla releases asm.js, a strict JS subset for compilers, for Firefox - Performance pressure forces other browsers to implement - A clever hack, but something better was needed - WebAssembly developed to supersede asm.js *** WASM 1.0 - *Linear memory* oriented - Good target for C/Rust/etc. - Bad target for languages that *need GC* - Implementing GC in WASM feasible but impractical # Frequently generated via LLVM, most high-level languages compile their # interpreter or VM # Superset of asm.js functionality; simple bytecode, loading and # validation, "streamable" and fast as the network for typical clients, # extensible via w3c standardization process # "High-level" assembly: modules, functions, explicit typing, block # structure instead of GOTOs, now GC and higher-level types. Capability # security: no ambient authority to access resources beyond what's # explicitly provided to the module *** WASM 2.0 - WASM for *the rest of us*! - Heap allocated reference types - Structs, arrays, immediates (=i31=) - Leverages the *host GC* *** Let's go! Let's take a closer look at how Spritely is using WASM to bring Guile to the web. ** What is Guile? #+REVEAL_HTML:
#+REVEAL_HTML: - Flexible Scheme implementation - Supports several Scheme standards, libraries, and extensions - Good bytecode compiler and JIT compiler - Also a platform for hosting non-Scheme languages - Used in Unix-like environments mostly... until now #+REVEAL_HTML:
# - Scheme implementation with extensible *compiler tower* # - *Dynamic language* that uses garbage collection # - *Minimalistic* but with a respectable standard library # - Bytecode VM and *JIT compiler* # - Supports several Scheme standards and *many extensions* # - Usable for *scripts*, *extensions* to C/Rust/etc. programs, or *the # entire program*! *** Decisions, decisions #+ATTR_REVEAL: :frag (fade-in fade-in fade-in) - Option 1: Compile Guile VM via emscripten - Ship faster - Run slower (no JIT for Guile bytecode) - Poor integration with JS - Option 2: Compile directly to WASM GC - Ship slower - Run faster (no Guile bytecode) - Good integration with JS - We chose option 2 ** Introducing: Guile Hoot #+REVEAL_HTML:
#+REVEAL_HTML: - Scheme to WASM compiler - Built for WASM GC - /Not/ a C runtime compiled via emscripten - Includes a full WASM toolchain - v0.1.0 released in October #+REVEAL_HTML:
/"Bring your whole self."/ — Andy Wingo *** Goals 1. Run *Goblins applications* in the browser 2. Advocate for *all dynamic languages* in the WASM ecosystem 3. Provide an *alternative* to the mainstream WASM toolchain *** Example This is the update loop for a particular cellular automaton: #+BEGIN_SRC scheme (define (update from to) (do ((y 0 (+ y 1))) ((= y grid-size)) (do ((x 0 (+ x 1))) ((= x grid-size)) (let* ((t (grid-ref from x y)) (t* (cond ((= t empty) empty) ((= t cu) (if (<= 1 (neighbors from x y) 2) ehead cu)) ((= t ehead) etail) ((= t etail) cu)))) (grid-set! to x y t*))))) #+END_SRC Can we run it in a web browser? *** Yes! Welcome to Wireworld! #+REVEAL_HTML: *** What the community is building with Hoot #+REVEAL_HTML: Cybersol by David Wilson (System Crafters, Flux Harmonic) *** Status #+REVEAL_HTML: - Most of R7RS-small Scheme - Some Guile-specific features - JS interoperability library ** Hoot is a compiler Hoot provides a *new compiler backend* for Guile Scheme → +Guile Bytecode+ *WASM* *** What Hoot needs from WASM - GC - Tail calls - +stringref+ Upcoming Firefox 121 and Chrome 119 have it all! Should be in stable releases of all major browsers by early 2024. #+REVEAL_HTML: (except stringref... more on that later.) *** The good - WAT is nice, especially the folded form - We have /tail calls!/ - Reference type system is pretty darn good *** Example: Inline WASM - WebAssembly Text format uses s-expressions... - ...so why not embed WASM directly into Scheme? - Composes well with the Scheme code around it #+BEGIN_SRC scheme (define (port? x) (%inline-wasm '(func (param $obj (ref eq)) (result (ref eq)) (if (ref eq) (ref.test $port (local.get $obj)) (then (ref.i31 (i32.const 17))) (else (ref.i31 (i32.const 1))))) x)) #+END_SRC *** The bad - No stringref in production WASM hosts - No stack switching - Limited constant expressions *** Example: Strings - We like *stringref*, but it hasn't been adopted - Passing strings WASM⇆JS means *copying* at the boundary - JS String Builtins proposal will help, but doesn't resolve all issues - Will DOM API calls from WASM ever be as fast as JS? ** Hoot is a library of WASM tools - Hoot provides its own *self-contained* WASM toolchain - Write, compile, and *execute* WASM in one place - Alternative to emscripten, binaryen, wabt, etc. *** The toolchain - Available as a set of Scheme modules for *easy programmatic access* - Extensions to Guile's =guild= tool for hooking into build systems - Contains: - WAT parser - Assembler - Disassembler - Linker - Dumper - Interpreter *** The development environment - Built-in WASM interpreter - Validate and execute code without leaving Guile - Debug tools to inspect stack, function locals, etc. - Scheme-in-Scheme reflection library *** Example: Testing a simple WASM module #+BEGIN_SRC scheme scheme@(guile-user)> ,use (wasm wat) (wasm resolve) (wasm vm) scheme@(guile-user)> (define wasm (resolve-wasm (wat->wasm '(module (func (export "fmod") (param $x f64) (param $y f64) (result f64) (f64.sub (local.get $x) (f64.mul (f64.trunc (f64.div (local.get $x) (local.get $y))) (local.get $y)))))))) scheme@(guile-user)> (define instance (instantiate-wasm (validate-wasm wasm))) scheme@(guile-user)> ((wasm-instance-export-ref instance "fmod") 4.3 2.0) $1 = 0.2999999999999998 #+END_SRC *** Example: Testing Scheme compiled to WASM #+BEGIN_SRC scheme scheme@(guile-user)> ,use (hoot reflect) (wasm parse) scheme@(guile-user)> (define reflector (call-with-input-file "js-runtime/reflect.wasm" parse-wasm)) scheme@(guile-user)> (define hoot-square (compile-value reflector '(lambda (x) (* x x)))) scheme@(guile-user)> hoot-square $1 = #> scheme@(guile-user)> (hoot-square 4) $2 = 16 #+END_SRC ** The future of Hoot # - Debugging! - More *R7RS-small* features - More *Guile* features - Foreign function interface - Modules! - *Fibers!* - /Goblins!/ *** The future of WASM - Hoot has had an outsized impact on the WASM GC proposal - Come all ye dynamic language implementers! - Get involved with the WASM CG - We changed things and you can, too! *** Conclusion - *Scheme is now an alternative* to JavaScript - WASM should have space for *all languages* - Hoot is for Scheme but *not only Scheme* - Hoot provides an *alternative WASM toolchain* *** Hoot 0.2.0 teaser #+REVEAL_HTML: *** Hoot 0.2.0 teaser #+REVEAL_HTML: *** We are a research institution! Work with us! #+REVEAL_HTML: *** Questions? #+REVEAL_HTML: Learn more about Hoot: https://spritely.institute/hoot Join our community forum! (use code OCAPN2023) https://community.spritely.institute Chat with us! =#spritely= on irc.libera.chat