Runtime model

mu programs compile to bytecode and run on a small, stack-based VM. The VM is the reference implementation for language semantics.

The execution pipeline

  1. Lexing and parsing produce an AST.
  2. The compiler lowers the AST into bytecode (via a small IR).
  3. The VM executes the bytecode on a stack machine.

Bytecode VM

Native backend

The native backend lowers the same IR into machine code without invoking external assemblers or linkers. Non-FFI programs stay self-contained; programs that call C libraries intentionally carry the dynamic-loader metadata they need. It keeps semantics aligned with the VM so programs behave the same in either mode.

Build with -B, and cross-compile with -p os/arch:

$ mu -B -o hello hello.mu
$ mu -B -p linux/riscv64 -o hello hello.mu

There are two native backends, and their target lists differ slightly:

Target Go backend (mu -B) Self-hosted backend
darwin/arm64 yes yes
linux/amd64 yes yes
linux/riscv64 yes yes
linux/arm64 yes not yet
darwin/amd64 not yet not yet

Self-hosting

selfhost/ holds a lexer, parser, compiler, VM and native backend written in mu. It is not the default build, but it is not a plan either: compiling it with itself reaches a byte-identical fixpoint — the compiler reproduces itself exactly, gcc-style, with no Go in the path — on darwin/arm64 and linux/amd64. scripts/bootstrap.sh checks that on every change.

That gives four ways to run a mu program, and they are held to the same tests: the Go host’s VM, the Go native backend, the self-hosted VM, and the self-hosted native backend. Where they still differ is recorded below and on the FFI and concurrency pages rather than left to be discovered.

Deterministic concurrency

Tasks and channels use cooperative scheduling with FIFO queues. Blocking operations (send/recv/wait/sleep and I/O) yield so the scheduler can resume other work deterministically.

Concurrency is implemented across the four execution paths: Go VM, Go native, self-hosted VM, and self-hosted native. The target matrix still matters: the self-hosted native backend currently covers darwin/arm64, linux/amd64, and linux/riscv64, while the Go native backend also covers linux/arm64.

Learn more

Next steps