Mojo Crafting Interpreters
Bytecode VM with mark-and-sweep GC in Mojo using compile-time parametric structs
Overview
A bytecode virtual machine interpreter for the Lox programming language implemented entirely in Mojo -- Modular's systems programming language combining Python's ergonomics with C-level performance. The implementation follows the clox path: single-pass Pratt-parser compiler emitting bytecode for a stack-based VM with mark-and-sweep garbage collection, string interning, function calls via call frames, and native function FFI. Demonstrates how Mojo's ownership model, compile-time parametric types, InlineArray stack allocation, and UnsafePointer primitives replace C's raw pointer arithmetic while preserving performance.
Architecture
The VM is parameterized at compile time with a Config value struct containing stack size, frames max, and debug flags -- monomorphized so debug code is dead-code-eliminated in production builds. Both the value stack and call frames use InlineArray (stack-allocated, no heap indirection). Object hierarchy uses pointer casting with a common Obj header (type tag, GC next pointer, marked flag), mirroring C's struct-prefix inheritance with Mojo's typed bitcast.
Code Highlights
struct VM[config: Config]:
var frames: InlineArray[CallFrame, config.framesMax]
var framesCount: Int
var stack: InlineArray[Value, config.stackMax]
var stackTop: UnsafePointer[Value]
var globals: Hashmap[StrObjHashmapKey, Value]
var strings: InternedStringsMap
# GC
var bytesAllocated: UInt
var nextGC: UInt
var objects: UnsafePointer[Obj]
var grayStack: DynamicArray[UnsafePointer[Obj]]Highlights
- Complete bytecode VM with mark-and-sweep GC in Mojo -- one of very few public garbage-collected language runtimes in Modular's systems language
- Compile-time parametric VM architecture: InlineArray stack allocation, monomorphized dispatch loops, zero-cost debug instrumentation via Config struct
- Tri-color mark-and-sweep GC with weak-reference awareness for interned strings and GC-safe allocation sequences
- Custom data structures from scratch: generic DynamicArray with move semantics, open-addressing Hashmap with tombstone deletion, RLE line info
Related Projects
Blang (Bitis)
Lazy functional language with compile-time ownership and borrowing instead of garbage collection
Novel PL contribution: first lazy functional language using ownership/borrowing instead of GC, introducing self-borrows for cyclic data structures (graphs, infinite streams)
Atheris
Complete compiler for a Swift-like OOP language with vtables and polymorphic dispatch
Designed and implemented a complete compiler from scratch for a Swift-like OOP language (~120 Java source files, ~8,000+ lines)
SML-to-Racket
Source-to-source compiler with lambda calculus IR and Church-encoded algebraic datatypes
Dual-target compiler with direct Racket emission and a lambda calculus IR featuring Church-encoded booleans, tuples, and algebraic datatypes