Implementation & Bootstrap
Implementation & Bootstrap
> xxc's ultimate goal is complete self-hosting, Go-style: compile xxc
> source directly to native machine code, with the entire toolchain —
> lexer, parser, type checker, code generator, assembler, linker — written
> in xxc itself. That goal is achieved. Related pages:
> Language Guide ·
> Quick Start.
Three-backend architecture
| Backend | Command | Role |
|---|---|---|
| Tree-walking interpreter | xxc run | the semantic oracle |
| Flat-stack bytecode VM | xxc vm | the mid-performance tier (~2.8×) |
| Native compiler | xxc build | direct machine code |
All three share one frontend (lexer → parser → typeck), and the
differential gate matrix pins their consistency — every test program
produces byte-identical output on all three pipelines:
| Gate | Covers | Status |
|---|---|---|
| Windows triple | interp = native-PE = VM, ARC gates closed + open | 58/58 × 2 |
| aarch64 native triple | same, on aarch64 hosts | 60/60 × 2 |
| Linux x86-64 | native + VM | 61/61 |
| qemu leg | interp vs x86 ELF under qemu on aarch64 | 59/59 |
| Concurrency gates | w=1 byte parity; w≥2 contracts; line-atomicity multisets | all green |
| Differential fuzz | mix/containers/closures/arc/oop rotation, 3 pipelines | 50 smoke / 250 deep, 0 failures |
| reltest | x86 .bss rip-rel relocation arbiter | CLEAN |
Native compilation: zero external toolchain
xxc build never invokes a C compiler or binutils — xxc carries its own
in-process assembler (assembler.rs) and linkers (pelinker.rs for
Windows PE, elflinker.rs for static Linux ELF). Three targets:
- Windows x86-64: PE with VEH diagnostics and guard pages;
- Linux x86-64: static ELF, pure syscalls, no libc, no PT_INTERP
(Go-style single-file distribution);
- Linux aarch64: AArch64 ELF — generated code lands through the a64
backend (an x86→a64 translator plus a real AArch64 encoder), with LL/SC
atomics honestly encoded at the data register's width.
Cross-compilation: XXC_TARGET=linux from Windows; an aarch64 host builds
native AArch64 by default.
The self-hosted toolchain
selfhost/ is a complete compiler written in xxc:
lexer.xxc → parser.xxc → typeck → gen.xxc → xas.xxc (assembler) → xld (linker)
└──────────── merged into xxcc_full.xxc ────────────┘
- gen1 = the bootstrap compiler built by the Rust seed; gen2 = gen1
compiling xxcc_full.xxc;
- The fixpoint: gen2 re-compiling xxcc_full.xxc produces output
byte-identical to gen1's — verified on every chain refresh by
build_selfhost.sh, under the ARC gate closed and open;
- The Rust seed plays the role of Go's "previous compiler": language
extensions land there first, and the fixpoint proves the self-hosted
compiler stays semantically equivalent on everything else;
- The self-hosted xas/xld outputs are validated byte-exact against the Rust
assembler/pelinker.
Runtime semantics (four derivatives, one semantics)
| Derivative | Purpose |
|---|---|
| rt/runtime.s (canonical) | Windows PE direct translation; carries the line-atomic print family and allocator accounting |
| rt/runtime_new.s | the selfhost-chain variant (no guard imports) |
| linux/runtime_linux.s | generated by mk_runtime.py (never hand-edit) |
| the a64 translation | consumed at aarch64 build time |
Core properties (all gate-verified):
- Deterministic ARC: atomic reference counts (x86
lock/ a64 exclusive
pairs at honest 64-bit width), released at zero; XXC_ARC_FREE=1
exercises the real free path;
- Exact accounting:
alloc_live= currently-owned user bytes (free
strips the 16-byte header, grow accounts the delta), never negative from
churn; XXC_ALLOC_LIMIT (strict base-10) is the runaway guard;
- Line-atomic printing: a statement-level owner-token lock plus a single
flush — concurrent tasks can never tear a line;
- Cross-platform ARC equivalence: Windows PE / x86-linux / a64
event-sequence differential 58/58 three-way MATCH (tools/trace3.py).
Quality discipline
One house rule: build it perfectly, build it correctly — every
discovered problem gets a root fix, never a workaround. Recent cases: the
a64 encoder LL/SC width defect (latent for five sessions; after the root
fix, a full width-law sweep cleared 17 same-class defects across the
encoder), the allocator accounting asymmetries (two "assessed benign" spots
root-fixed), and the canonical-runtime restoration (one canonical source now
carries the line-atomic print for every backend). The full implementation
history lives in the repository's ROADMAP.md.
Environment variables
| Variable | Effect |
|---|---|
| XXC_ALLOC_LIMIT | allocation guard (strict base-10 bytes, default 2GiB; 8e9 parses as 8) |
| XXC_ARC_FREE | 1 = real free path (the gate-open differential's target) |
| XXC_HEAPGUARD | 1 = page-guard allocations (wild-write detection, Windows hardening) |
| XXC_ARC_TRACE | 1 = ARC retain/release trace lines |
| XXC_CONC_WORKERS | concurrency worker count |
| XXC_TARGET | linux = cross-compile a Linux ELF |
| XXC_PRINT_ATOMIC | legacy atomicity-gate selector for the conc ladder |
| XXC_A64_DUMP | 1 = dump the a64 translator's output text |