Racketeering Gophers

rocketeering gopher

Close enough.

I've been working on a Wasm implementation in Racket for the past couple of weeks and have recently reached a neat milestone.

I can take this Go program,

package main

import (

func main() {
        log.Println("GETing https://defn.io...")
        resp, err := http.Get("https://defn.io")
        if err != nil {
        defer resp.Body.Close()

compile it to Wasm

$ env GOARCH=wasm GOOS=js go build -o http.wasm http.go

and end up with a 7MiB Wasm file

-rwxr-xr-x  1 bogdan  staff   7.1M Nov 17 12:43 http.wasm*

that this Racket program can run:

#lang racket/base

(require wasm/private/binary

;; Read the module.
(define m (call-with-input-file "http.wasm" read-wasm))

;; Typecheck.
(define-values (valid? error-message)
  (mod-valid? m))
(unless valid? (error error-message))

;; Create an interpreter.
(define v (make-vm m (hash "go" *go*)))

;; Grab the entrypoint and run it.
;; run(argc, argv)
(define run (vm-ref v "run" #f))
(parameterize ([current-vm v])
  (run 0 0))
$ racket run.rkt
2020/11/17 12:48:19 GETing https://defn.io...
2020/11/17 12:48:19 200 OK

Tada! The compiled Go code requires some runtime support that's specific to it, which is where the go-runtime.rkt module above comes in. I've only implemented the parts of the Go runtime support that I needed to get the above program to work and that code is pretty bad, but it gets the job done as a test for the Wasm implementation.

There's still a lot to do until this is ready to be used by others (note the lack of any sort of public API or documentation so far), but I thought this was a cool little result worth sharing.

Credit: Rocketeering Gopher by Egon Elbre on GitHub.