← Back to CV

Compilers & Language Engineering

Mojo Crafting Interpreters

Bytecode VM with mark-and-sweep GC in Mojo using compile-time parametric structs

2024 Mojo
Mojo Crafting Interpreters screenshot

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

Mojo Crafting Interpreters 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.

Key concepts

Compile-Time Parametric VM

VM[config] generates specialized code for each configuration. Stack sizes flow into InlineArray size parameters at compile time, debug tracing branches are eliminated by the compiler in release builds, and the entire execution hot path operates on stack-allocated data with zero heap indirection.

Code highlights

Compile-Time Parametric VM Instantiation
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