# tail calls

Published articles for tail calls.

This is one page of public article previews, not the complete archive. Follow Next page to continue. Summaries are not the original full articles.

## WebAssembly interpreter performance depends on the runtime, not just the code pattern

DevFeed: [WebAssembly interpreter performance depends on the runtime, not just the code pattern](<https://devfeed.tech/articles/the-value-of-a-performance-oracle-35035.md>)

Original publisher: [Read original article](<https://wingolog.org/archives/2026/04/07/the-value-of-a-performance-oracle>)

Author: Andy Wingo

Published: 2026-04-07T12:49:39Z

Content type: article

Language: en

Sources: [wingolog](<https://devfeed.tech/sources/wingolog.md>)

Topics: [Rust](<https://devfeed.tech/topics/rust.md>), [WebAssembly](<https://devfeed.tech/topics/web-assembly.md>), [Assembly](<https://devfeed.tech/topics/assembly.md>), [toolchain](<https://devfeed.tech/topics/toolchain.md>), [V8](<https://devfeed.tech/topics/v8.md>), [Chrome](<https://devfeed.tech/topics/chrome.md>), [Firefox](<https://devfeed.tech/topics/firefox.md>)

Tags: [assembler](<https://devfeed.tech/tags/assembler.md>), [assembly](<https://devfeed.tech/tags/assembly.md>), [chrome](<https://devfeed.tech/tags/chrome.md>), [firefox](<https://devfeed.tech/tags/firefox.md>), [oracles](<https://devfeed.tech/tags/oracles.md>), [performance](<https://devfeed.tech/tags/performance.md>), [performance-oracles](<https://devfeed.tech/tags/performance-oracles.md>), [raven](<https://devfeed.tech/tags/raven.md>), [rust](<https://devfeed.tech/tags/rust.md>), [tail-calls](<https://devfeed.tech/tags/tail-calls.md>), [toolchain](<https://devfeed.tech/tags/toolchain.md>), [wasm](<https://devfeed.tech/tags/wasm.md>), [wasmtime](<https://devfeed.tech/tags/wasmtime.md>), [wastrel](<https://devfeed.tech/tags/wastrel.md>), [webassembly](<https://devfeed.tech/tags/webassembly.md>)

### AI overview

The article revisits a comparison of switch-based and tail-calling bytecode interpreters. Its measurements confirm earlier native and Wasmtime results but report that Wastrel substantially reduces the apparent WebAssembly penalty, suggesting that the poor performance is runtime-specific rather than inherent to WebAssembly.

### Source excerpt

Over on his excellent blog, Matt Keeter posts some results from having ported a bytecode virtual machine to tail-calling style. He finds that his tail-calling interpreter written in Rust beats his switch-based interpreter, and even beats hand-coded assembly on some platforms. He also compares tail-calling versus switch-based interpreters on WebAssembly, and concludes that performance of tail-calling interpreters in Wasm is terrible: 1.2x slower on Firefox, 3.7x slower on Chrome, and 4.6x slower in wasmtime. I guess patterns which generate good assembly don't map well to the WASM stack machine, and the JITs aren't smart enough to lower it to optimal machine code. In this article, I would like to argue the opposite: patterns that generate good assembly map just fine to the Wasm stack machine, and the underperformance of V8, SpiderMonkey, and Wasmtime is an accident. some numbers I re-ran Matt's experiment locally on my x86-64 machine (AMD Ryzen Threadripper PRO 5955WX). I tested three toolchains: Compiled natively via cargo / rustc Compiled to WebAssembly, then run with Wasmtime Compiled to WebAssembly, then run with Wastrel For each of these toolchains, I tested Raven as implemented in Rust in both "switch-based" and "tail-calling" modes. Additionally, Matt has a Raven implementation written directly in assembly; I test this as well, for the native toolchain. All results use nightly/git toolchains from 7 April 2026. My results confirm Matt's for the native and wasmtime toolchains, but wastrel puts them in context: We can read this chart from left to right: a switch-based interpreter written in Rust is 1.5x slower than a tail-calling interpreter, and the tail-calling interpreter just about reaches the speed of hand-written assembler. (Testing on AArch64, Matt even sees the tail-calling interpreter beating his hand-written assembler.) Then moving to WebAssembly run using Wasmtime, we see that Wasmtime takes 4.3x as much time to run the switch-based interpreter, compare

## Wastrel Compiles Hoot Scheme-to-WebAssembly Output

DevFeed: [Wastrel Compiles Hoot Scheme-to-WebAssembly Output](<https://devfeed.tech/articles/wastrelly-wabbits-35034.md>)

Original publisher: [Read original article](<https://wingolog.org/archives/2026/03/31/wastrelly-wabbits>)

Author: Andy Wingo

Published: 2026-03-31T20:34:23Z

Content type: article

Language: en

Sources: [wingolog](<https://devfeed.tech/sources/wingolog.md>)

Topics: [WebAssembly](<https://devfeed.tech/topics/web-assembly.md>), [Compiler](<https://devfeed.tech/topics/compiler.md>), [scheme](<https://devfeed.tech/topics/scheme.md>)

Tags: [accidentally-quadratic](<https://devfeed.tech/tags/accidentally-quadratic.md>), [aot](<https://devfeed.tech/tags/aot.md>), [bigint](<https://devfeed.tech/tags/bigint.md>), [bignums](<https://devfeed.tech/tags/bignums.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [compilers](<https://devfeed.tech/tags/compilers.md>), [exception-handling](<https://devfeed.tech/tags/exception-handling.md>), [exceptions](<https://devfeed.tech/tags/exceptions.md>), [gc](<https://devfeed.tech/tags/gc.md>), [gcc](<https://devfeed.tech/tags/gcc.md>), [gmp](<https://devfeed.tech/tags/gmp.md>), [hoot](<https://devfeed.tech/tags/hoot.md>), [igalia](<https://devfeed.tech/tags/igalia.md>), [library](<https://devfeed.tech/tags/library.md>), [maps](<https://devfeed.tech/tags/maps.md>), [precision](<https://devfeed.tech/tags/precision.md>), [scheme](<https://devfeed.tech/tags/scheme.md>), [standard](<https://devfeed.tech/tags/standard.md>), [tail-calls](<https://devfeed.tech/tags/tail-calls.md>), [wasm](<https://devfeed.tech/tags/wasm.md>), [wastrel](<https://devfeed.tech/tags/wastrel.md>), [webassembly](<https://devfeed.tech/tags/webassembly.md>), [whippet](<https://devfeed.tech/tags/whippet.md>)

### AI overview

The article describes recent work on Wastrel, an ahead-of-time WebAssembly compiler, including compiling output from the Hoot Scheme-to-Wasm compiler. It covers implementing bignum operations with mini-gmp and updating Hoot to use standardized WebAssembly exception handling.

### Source excerpt

Good day! Today (tonight), some notes on the last couple months of Wastrel, my ahead-of-time WebAssembly compiler. Back in the beginning of February, I showed Wastrel running programs that use garbage collection, using an embedded copy of the Whippet collector, specialized to the types present in the Wasm program. But, the two synthetic GC-using programs I tested on were just ported microbenchmarks, and didn't reflect the output of any real toolchain. In this cycle I worked on compiling the output from the Hoot Scheme-to-Wasm compiler. There were some interesting challenges! bignums When I originally wrote the Hoot compiler, it targetted the browser, which already has a bignum implementation in the form of BigInt, which I worked on back in the day. Hoot-generated Wasm files use host bigints via externref (though wrapped in structs to allow for hashing and identity). In Wastrel, then, I implemented the imports that implement bignum operations: addition, multiplication, and so on. I did so using mini-gmp, a stripped-down implementation of the workhorse GNU multi-precision library. At some point if bignums become important, this gives me the option to link to the full GMP instead. Bignums were the first managed data type in Wastrel that wasn't defined as part of the Wasm module itself, instead hiding behind externref, so I had to add a facility to allocate type codes to these "host" data types. More types will come in time: weak maps, ephemerons, and so on. I think bignums would be a great proposal for the Wasm standard, similar to stringref ideally (sniff!), possibly in an attenuated form. exception handling Hoot used to emit a pre-standardization form of exception handling, and hadn't gotten around to updating to the newer version that was standardized last July. I updated Hoot to emit the newer kind of exceptions, as it was easier to implement them in Wastrel that way. Some of the problems Chris Fallin contended with in Wasmtime don't apply in the Wastrel case: sinc