Architecture¶
The user-facing architecture documentation lives under
docs/architecture/ (pipeline, Vm, performance, stdlib, concurrency,
memory model, diagnostics). This file is the plan-side summary of the
shape of the system and the load-bearing design decisions.
Pipeline¶
source text
│
▼ span (SourceMap, FileId, Span)
▼ lexer (token stream, trivia preserved)
▼ parser (AST + diagnostics)
▼ ir (AST → register IR lowering; applicability = the
│ shared overload-resolution engine; jit_loop = the
│ native compiler over the IR)
▼ interp_ir (the Vm: executes IR; JIT tiers compile hot code)
▼ cli (binary: run / test / check / lex / parse / dump-ir /
bake / repl / pack)
resolver and typeck (backed by types and cfa) serve the
klio check diagnostics path, and under KLIO_EAGER=1 they run
ahead of lowering on the run path so lowering consumes type-derived
resolution answers. runtime owns the Value model, the ObjRef
cell protocol, the tracing GC, and the perf profiles; stdlib owns
the native intrinsics and symbol index; pack / stdlib_pack own
the .klio-pack format and the embedded stdlib.
The module graph is data-driven in build.zig (mod_list): one Zig
module per subsystem under src/, each src/<name>/<name>.zig the
root file re-exporting the public API.
Design choices¶
- One module per subsystem. Explicit dependency edges in
build.zig;scripts/zigcheck.py <module>verifies any module in isolation against that graph. Spanover raw offsets. Encodes file identity so diagnostics never confuse two files.- Diagnostics-first. Every pass threads a
DiagnosticSink; diagnostics are data, not Zig errors. - IR-only execution. There is no AST evaluator on the run path; every construct lowers to structured register IR.
- Native code is additive. The JIT (x86-64 + AArch64 emitters behind one comptime-selected API) compiles hot loops and functions; any unsupported shape falls back to the interpreter with identical semantics.
- Memory by reachability. The tracing mark-sweep GC
(
src/runtime/gc.zig, design inGC.md) frees by reachability; profiles (--opt) can drop to a never-free arena.
Reference checkouts¶
kotlin-language-spec/— spec PDFs by section (gitignored).kotlin/— JetBrains/kotlin submodule at tag v2.4.20, populated sparsely (libraries/stdlib+libraries/kotlin.test) byscripts/init-kotlin-submodule.sh.
Everything targets Kotlin 2.4.20. When the spec PDFs and the
kotlin/ source disagree, the source wins, because that is what real
Kotlin code is compiled against today.
kotlin/compiler/(when present in a full checkout) is a cross-reference for tokenization, parsing, and resolution behavior.kotlin/libraries/stdlib/is the source of truth for the standard library klio ships: thecommon/subtree is interpreted directly as the stdlib pack's Kotlin source, with klio-authored actuals underkotlin-klio/and native Zig intrinsics shadowing individual functions at dispatch.
Stdlib strategy¶
See STDLIB.md for the full strategy. Headlines: the upstream
stdlib source is the implementation (interpreted, not re-written);
stdlib_gen mines the upstream tree into the symbol index; native
intrinsics exist where host access or performance demands them; the
whole thing ships as stdlib.klio-pack embedded in the binary and is
verified by running upstream's own commonTest suite under the
interpreter.
Scope: packs, not JVM interop¶
Third-party libraries reach klio as .klio-packs built from Kotlin
source (docs/packs/), with optional native bindings registered by
host modules. JVM interop — Maven resolution, .jar / .klib
consumption, a classpath — remains out of scope. Anything a program
references that no loaded pack or the stdlib provides fails to
resolve with a clear diagnostic.