xxc

可编译可解释的系统级语言 - 确定性 ARC 无 GC / 全自举工具链 / 三后端逐字节一致

📂 开发工具#编程语言#编译器#自举#跨平台#无GC#并发#开发工具📅 2026-10-9

Implementation & Bootstrap

📅 2026-10-9

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 |