Tail-Call Interpreters in Rust - Jimmy Ostler
Tail-Call Interpreters in Rust
01 Aug 2026 Jimmy Ostler Word Count: 1636 Reading Time: 9 Min
Recently, I came across this post about different styles of VM dispatch as I was searching for ways to improve my ternary project. I had heard of tail-call interpretation, though my original source of inspiration took some time for me to re-find. This post, however, gave an excellent breakdown about several different styles of VM dispatch in Scala. I decided to implement these in Rust (including several variations more relevant to my project) as a fun experiment, and benchmark them to measure how they differ. I'll go over 2 versions - one, meant to emulate Noel's Scala, the other, meant to utilize Rust's strengths with a more complicated and traditional register machine.
Tail-Calls
Tail-call interpretation refers to the technique where some recursion can be turned into a jump during compilation, removing the need to allocate a new stack frame. It's extremely useful for functional languages to keep stack sizes down, such as Scala, but most compilers tend to use it. If you want to learn more, I highly recommend checking out Noel's excellent article above. When compiling with high optimization, Rust also performs this, and the unstable feature explicit_tail_calls lets us directly tell the compiler to perform the optimization or error.
Stack Machine (Noel's Machine)
The simplest machine we can easily work with here is a stack machine with 5 instructions, represented in Rust as so:
enum ByteCode { Lit ( f64 ), Add , Sub , Mul , Div }
Essentially identical to Noel's Scala. Since this is a stack machine, the Lit (literal) instruction pushes a value on the stack; arithmetic instructions pop their operands, and push the resulting value back onto the stack.
... continue reading