WebAssembly-to-C compiler
  • C 54.7%
  • Scheme 41.7%
  • M4 1.4%
  • Makefile 0.9%
  • WebAssembly 0.6%
  • Other 0.6%
Find a file
2026-04-03 21:22:50 +02:00
bin Restrict set of available GCs 2026-02-05 16:06:27 +01:00
build-aux Move things around a bit 2026-02-06 15:11:19 +01:00
examples Move things around a bit 2026-02-06 15:11:19 +01:00
js-runtime Move things around a bit 2026-02-06 15:11:19 +01:00
module Fix return_call_indirect validation 2026-04-03 21:22:50 +02:00
resource Implement weak maps, weak refs 2026-04-02 16:18:06 +02:00
test Fix tests, wheee 2026-01-29 16:44:27 +01:00
whippet Implement weak maps, weak refs 2026-04-02 16:18:06 +02:00
.gitignore Move things around a bit 2026-02-06 15:11:19 +01:00
acinclude.m4 Initial commit 2025-10-10 16:54:45 +02:00
bootstrap.sh Initial commit 2025-10-10 16:54:45 +02:00
build.mk Prepare for partitioning 2026-03-18 16:23:55 +01:00
configure.ac Move things around a bit 2026-02-06 15:11:19 +01:00
guix.scm Remove lttng-tools from guix.scm 2026-01-15 10:43:57 +01:00
LICENSE.txt Add README.md and LICENSE.txt 2025-10-10 21:48:48 +02:00
Makefile.am Implement weak maps, weak refs 2026-04-02 16:18:06 +02:00
pre-inst-env.in Actually manages to link against whippet, whee 2026-01-25 16:27:46 +01:00
README.md Update README 2026-03-31 14:40:29 +02:00
test.c Initial compiler 2025-10-10 16:54:48 +02:00
test.wasm Initial compiler 2025-10-10 16:54:48 +02:00

Wastrel, a research WebAssembly-to-C compiler

Wastrel is an implementation of WebAssembly. It compiles Wasm modules to C, and thence to native code.

Wastrel is a whole-program ahead-of-time compiler, designed to compile one Wasm module into one executable.

Virtues

  • Wastrel is easy to use: it's like Wasmtime's command-line interface, except that it takes longer in the compile phase.

  • The resulting code is quite fast! Wastrel's output binaries have best-in-class performance.

  • Security is OK? The wastrel compiler itself is written in a memory-safe language, the output code uses C's type system as well as we can to avoid signedness, type confusion, and pointer construction bugs, and the output uses Linux's memory protection and filesystem namespace isolation facilities to prevent bugs by construction.

Scope

  • Wastrel supports pretty much all of Wasm 3.0: garbage collection (GC), multi-memory, exception handling, tail calls, and so on. SIMD is the main missing piece.

  • Wastrel aims to support experimental extensions: stack switching and all that hot mess.

  • Wastrel serves as a test bed for Whippet, a garbage collection library.

  • Wastrel supports well-known sets of imports, currently WASI 0.1 as well as the imports used by the Hoot Wasm-to-Scheme compiler. We'd be happy to add standard-library support for other GC-using language toolchains, for example Scala, OCaml, or Kotlin, and we are also interested in adding support for Wasm components via a lower-to-vanilla-Wasm pre-pass.

Comparison

There are other great Wasm-to-C compilers!

  • w2c2 is the best of them. Wastrel will be interesting if you want an easy CLI that also handles compilation to binaries. Also, Wastrel does a more modern Wasm; w2c2 doesn't do GC, exception handling, tail calls, or the like. On the other hand, Wastrel isn't a streaming compiler: it parses the whole Wasm binary into memory, and is a bit slower to emit C than w2c2.

  • wasm2c is the original. It doesn't do GC either, though it does do exception handling. Also, its focus is for embedding Wasm into an existing C project, instead of producing standalone executables.

In the space of ahead-of-time Wasm compilers, there is also Wizard and WAMR; give them a try and let us know how they compare for your use case!

Finally, the gold standard is Wasmtime. Wasmtime is great, probably you should be using it too! In my tests, Wastrel has tended to produce significantly faster binaries. I suspect this is due to three factors: (1) more interprocedural optimizations (Wasmtime does none), (2) superlinear intraprocedural optimizations, and (3) a more mature instruction selector and register allocator. You will likely prefer Wasmtime if you are on the leading edge of the component-model ecosystem, if you need low-latency compilation, or if the use of a general-purpose C compiler doesn't fit with your security model. However, even if you need Wasmtime in production, Wastrel is valuable as a performance oracle, setting a standard against which Wasmtime can be compared.

WASI

Wastrel implements WASI 0.1. If a module imports interfaces from the wasi_snapshot_preview1 module, Wastrel will provide implementations. Additionally, if the module exports a nullary procedure named _start, or otherwise exports any nullary procedure, that procedure will be called as part of the compiled main function.

There are newer versions of WASI, notably version 1.0 that is coming out sometime early in 2026. Newer versions of WASI specify mechanisms to compose components into a whole, which involves some amount of run-time linking support. Wastrel should be able to be a part of that world somehow, but hopefully in the same way it implements WASI 0.1: by requiring that some other tool link components together and lower from component-model types to a conventional ABI, and Wastrel just provides the WASI standard library.

That said, one goal of Wastrel is to experiment with garbage collection as a compositional paradigm. Culturally speaking, WASI's thesis is that shared-nothing architectures allow one to robustly build larger systems from smaller pieces. This is at the same time obviously true but also limiting: for the size of system that can stay within an address space, we can avoid copies if we can pass immutable data by reference. This might not simply be more efficient, as it may result in systems with a completely different flavor, relative to the shared-nothing discipline. We should find out!

Limitations

Wastrel is not currently intended to allow Wasm modules to be instantiated multiple times in a process, or to be included as a library in a larger program. Would you like this? We should talk!

Tail calls (return_call, return_call_ref, and return_call_indirect) only work on GCC currently, because Clang requires not only that a tail callee match the return type of the caller, but also that it have the same parameter types. It seems that Clang will relax this restriction at some point, but it's a current limitation.

Building

The only dependencies of Wastrel are Guile 3.0.x for the Wasm-to-C translation, a Linux system on which to run, and a C compiler. Wastrel is mainly tested on GCC.

Checking out the git repo

git clone https://codeberg.org/andywingo/wastrel
cd wastrel

Building on Guix

On Guix:

guix shell
./bootstrap.sh && ./configure && make -j

Building on Debian/Ubuntu

Something like this should work to install dependencies:

sudo apt install guile-3.0 guile-3.0-dev pkg-config gcc automake autoconf make

Building on some other Linux distro

You need Guile! And a C compiler of course. And pkg-config and automake and autoconf and make so that the build works. Godspeed!

Building on MacOS or Windows

Firstly, what are you doing with your life? I cannot imagine developing software on a platform controlled by one company. What a drag. You do you, though!

But here's the thing. Compiling plain Wasm files to C should work fine on these targets, but a plain Wasm file can't do much. Mostly you will be compiling Wasm binaries that use WASI interfaces because that's what gives you, like, the ability to print to the console and access files. But you don't want to let the binaries access any file, and indeed WASI provides for some sandboxing. But despite the capabilities-oriented security veneer, in practice many WASI implementations effectively implement the sandbox via a permissions layer: for example the WASI implementation has capabilities to access the parents of preopened directories via .., but has to actively prevent this capability from leaking to the compiled module via run-time checks.

Wastrel takes a different approach, which is to use Linux's filesystem namespaces to build a tree in which only the exposed files are accessible. No run-time checks are necessary; the system is secure by construction. I do not want to implement file sandboxing any other way.

So is there a nice way to do this on MacOS? Well let's talk, surely it isn't too much code. But if not, we're back to my first point: what are you doing with your life?

Usage

$ ./pre-inst-env bin/wastrel test.wasm
Hello, world from ./test.wasm.YkJpch!

Neat, right? Just running wastrel my-wasm-file.wasm is short for running wastrel run my-wasm-file.wasm. You can instead stop with creating a binary with wastrel compile:

$ ./pre-inst-env bin/wastrel compile -o test test.wasm
$ ./test
Hello, world from ./test!

Or at creating a C file:

$ ./pre-inst-env bin/wastrel compile -S -o test-out.c test.wasm
$ gcc -O2 -o test -lm -Wall -Wno-unused-label -Wno-unused-variable test-out.c
$ ./test
Hello, world from ./test!

However, letting Wastrel compile the C itself is better, because Wastrel will generate multiple C files, compile them in parallel, and make the executable with link-time optimization (LTO). Also, letting Wastrel compile is currently the only way to get support for GC; we could improve this a bit in future, but it's not a high priority.

Performance

Well, comparisons are fraught. I have looked at the Coremark benchmark and Wastrel's speed is the same as native (slightly faster actually?), a tiny bit faster than w2c2, and some 40% faster than Wasmtime. A proper evaluation will take more time.

Other Wasm implementations have virtues that Wastrel will probably never have. Like, use something else if you need to run on Windows, right? Our goal is to be a test bed for experimentation. Having state of the art performance is necessary; portability to HaikuOS is not.

Acknowledgements

Wastrel uses the WebAssembly support libraries from Spritely's Hoot Scheme-to-WebAssembly compiler. Thanks especially to David Thompson for his work on these libraries.

License

Wastrel is Free Software, and can be run, distributed, and modified in accordance with the Apache License, version 2.0. See LICENSE.txt, for full details.

Compiling WebAssembly modules that use garbage collection will result in a binary that links to the embedded Whippet garbage collection library, which has a permissive MIT license. See the Whippet README for full details.

Similarly, WebAssembly modules that use bignums use mini-gmp, from the GMP project. This code is available under either or both of the GNU LGPLv3+ and the GPLv2+. In practice, we understand the LGPLv3+ to mean that if you distribute a bignum-using executable built using Wastrel, you need to also distribute the "source" wasm file and a reference to the revision of Wastrel that you used to compile it.