Opening up the World of WebAssembly with Guile Hoot

Robin Templeton (they/them) <robin@spritely.institute>

David Thompson (he/him) <dave@spritely.institute>

https://spritely.institute

SeaGL 2023

Introductions

Hi, we're Robin and Dave!

We work for the Spritely Institute.

What is Spritely?

We are building decentralized, secure infrastructure and standards for networked communities!

We are a 501(c)(3) non-profit, research institution

Research means collaboration

Goblins

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

Time-traveling distributed debugger

OCapN: The Object Capability Network

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?

  • W3C open standard
  • Low-level compilation target for the web
  • Available in browsers since 2017

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:

  • 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:

  • 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

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?

  • 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

Decisions, decisions

  • 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

  • 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

"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:

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

Can we run it in a web browser?

Yes!

Welcome to Wireworld!

What the community is building with Hoot

Cybersol by David Wilson (System Crafters, Flux Harmonic)

Status

  • 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.

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

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

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

Example: Testing Scheme compiled to WASM

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 = #<hoot #<procedure>>
scheme@(guile-user)> (hoot-square 4)
$2 = 16

The future of Hoot

  • 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

Hoot 0.2.0 teaser

We are a research institution! Work with us!

Questions?

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