NishiLang vs the field
Measured rankings against C, Rust, Go, JavaScript and Python · the architectural choices that produce each number · where we are state of the art, where we are not, and the plan to get there. Every number below was produced by running code on this machine on 2026-07-28, against the compiler that actually ships (nx_cc sha256 d25c7a3a…, 542,168 bytes, self-hosted). Every performance arm must print the identical checksum 31447040000 or its row is invalid — the work, not the timer, is what gets compared.
Ranking 1 — what happens on an out-of-bounds write
One program per language: write through a runtime index six slots into a four-slot array, then read it back. This is CWE-787, the most consequential software weakness class in the world. What each language does is its real safety ranking:
| language | behaviour on a[6] of [4]i64 | verdict |
|---|---|---|
NishiLang (checked [N]T/[]T) | refuses, names the rule, suggests the remedy, exits 71 | REFUSED, with a diagnostic |
Rust 1.96 -O | panics, exits 101 | REFUSED |
| Go 1.22 | panics: index out of range, exits 2 | REFUSED |
| Python 3.12 | IndexError | REFUSED (interpreted) |
| JavaScript (node 22, V8) | write “succeeds” — the array silently grows to length 7 | ABSORBED — memory-safe but the bug is masked, not caught |
C, gcc 13.3 -O2 | write and read both “succeed”, value 4242 | ALLOWED — silent memory corruption |
C, clang 18 -O2 | write and read both “succeed”, value 4242 | ALLOWED — silent memory corruption |
NishiLang sits in the refusing class with Rust and Go — and is the only compiled entry whose refusal message tells the operator what rule fired and what to do about it. This guarantee reaches stack arrays ([N]T), module statics, and heap memory through the slice type []T, a pointer that carries its length. Raw *T indexing remains available and unchecked by explicit choice — that cell is a deliberate, tested gate cell, not an oversight.
Ranking 2 — what the guarantee costs
The identical hot loop in every language: sum a 1,024-element i64 array 20,000 times (20.48M accesses), best of 3:
| arm | time | vs C | what the number contains |
|---|---|---|---|
C, gcc -O2 (unchecked) | 2,065 µs | 1.00× | the no-guarantee baseline: 40 years of optimizer |
| Go 1.22 (checked, elided) | 4,146 µs | 2.01× | bounds checks exist but its compiler proves them away in this loop |
NishiLang (unchecked *T) | 4,271 µs | 2.07× | our pure codegen gap — no checks in play |
Rust 1.96 -O (checked []) | 4,346 µs | 2.10× | LLVM + checks it could not fully elide here |
NishiLang (checked [N]T) | 8,484 µs | 4.11× | our codegen gap × our unelided checks — both named below |
| JavaScript (node 22, V8 JIT) | 12,487 µs | 6.05× | dynamic array, JIT-compiled |
| Python 3.12 | 785,415 µs | 380× | the interpreter class, honestly measured |
The architectures, and why each produces its numbers
C — trust the programmer, optimize the contract
gcc and clang assume the program never breaks the rules; undefined behaviour is the license for four decades of optimization (SSA form, register allocation, vectorization). That is why C wins the cost table and loses the safety table by the same design decision. The 4242 in the safety row is the world's CVE backlog in one integer.
Rust — move the checking to compile time, buy the backend
Ownership and borrows are proven at compile time; what cannot be proven (like our runtime index) stays a runtime check inside an LLVM-optimized loop. The architecture is powerful and heavy: the toolchain is tens of millions of lines you did not write, compile times are long, and the ecosystem model (crates) makes the supply chain part of your trusted computing base.
Go — keep the checks, teach the compiler to delete them
Go ships a garbage-collected runtime and mandatory bounds checks — then its compiler's bounds-check elimination proves, per loop, when the index cannot escape the array and removes the check entirely. Its 2.01× here is the existence proof for our elision rung: same guarantee as our 4.11× row, half the price, via a compiler theorem rather than a faster branch.
JavaScript and Python — the VM classes
V8 JIT-compiles hot dynamic code to within ~6× of C, and its arrays absorb out-of-range writes instead of refusing them — memory-safe, but the defect travels onward as data. CPython interprets: perfectly serviceable glue at 380×, never a codec. These architectures trade peak performance and strictness for dynamism.
NishiLang — sovereign from byte 0, safety as a runtime theorem, gates as the discipline
The entire pipeline is ours and self-hosted: a 15,413-line core (parser 5,451 · IR 1,581 · optimizer 3,846 · register allocator 1,110 · x86-64 backend 3,425) compiles NishiLang to its own assembly, assembled by our own assembler into ELF binaries that speak raw syscalls — no libc, no LLVM, no external linker, nothing downloaded. The same front end emits a WebAssembly lane. Safety is spatial-first: types that know their length ([N]T, []T) make every check derivable with zero annotations and zero false positives by construction. Correctness discipline is the gauntlet: 30 mutation-proven witness cells that must stay green through a two-generation self-host fixpoint before any compiler blesses — an instrument that has twice refused its own author's changes, which is the strongest evidence it works.
Where we are state of the art
| axis | claim | evidence |
|---|---|---|
| Toolchain sovereignty | 1000‰ — no mainstream language matches it | Self-hosted fixpoint (generation 2 = generation 3, byte-identical); zero external compiler, assembler, linker, runtime, or package registry anywhere in the chain. The public edge daemon serving this page rebuilds from source byte-identical to the live binary (md5-verified this week). |
| Supply-chain surface | effectively zero third-party code | No crates, no npm, no pip, no vendored C. The TLS 1.3 stack, HTTP server, video codec, and this site's tooling are all NishiLang from byte 0. The trusted computing base is the 542KB compiler you can read. |
| Spatial safety with usable diagnostics | refusing class, parity with Rust/Go, ahead of C — measured today | Safety table above; exit-71 refusal names the rule and the remedy. Guarantee reaches stack, static, and heap ([]T) memory; witnessed by mutation-proven gate cells, not by policy. |
| WebAssembly from our own compiler | a production codec in the field, no LLVM/Emscripten anywhere | The family video codec — SIMD wasm emitted by this toolchain — runs live calls at 60fps-class rates and holds 2.70× of x264's bitrate at equal PSNR, from 6.7× three days ago. |
| Whole-stack velocity in one language | compiler, daemons, codecs, formats, sites — one substrate | The measured week: a codec closed 6.7×→2.70× vs x264 while the same language's edge daemon, health evaluator, and 3D format shipped. Monocultures compound. |
Where we are not — each gap with its root cause, not a shrug
| gap | measured | root cause (diagnosed, not guessed) |
|---|---|---|
| Scalar codegen vs C | 2.07× | OP_PHI does not exist in the IR (grep count 0), so mem2reg only promotes single-store variables — every loop-carried variable lives in memory. Read straight from the emitted assembly, which is dominated by stack traffic, not by our checks. |
| Bounds-check cost | ~2× on a read-only loop | No elision pass. Go's 2.01× row proves the same guarantee can cost ~0 here when a compiler proves indexes in-range. An unsound elision is worse than none, so this waits for the blessed dominance oracle. |
Slice ([]T) access | 3.73× vs Rust &[T] (07-25) | The loop-invariant {data,len} header reloads every iteration; the hoist blocks on the same missing-phi ceiling (G9). Corpus migration deliberately waits — migrating first would ship a tree-wide regression. |
| Null-safety, data-race safety | unmeasured | No probes exist yet, so the axes score zero by exclusion. Expect the headline grade to fall when they land; that is the ruler working. |
| Compiler robustness | open defect class | An undefined identifier can still compile silently in some shapes (sev-9, open); string literals cap near 4.5KB; compiler stderr does not yet surface through the build API. Each has a filed debt row. |
| Ecosystem breadth | structural | No package registry by design — sovereignty is the point. The cost is real: every capability is built, not imported. The measured mitigation is the velocity row above. |
The plan — ordered by measured deficit, every rung gated
- Phi nodes + real mem2reg (the 2.07× rung). Add
OP_PHI, place phis at merge points (over-approximate, then let copy-propagation and DCE clean up — dominance frontiers not required), rename via the existing dominator tree, then eliminate phis into predecessor copies so the register allocator and both backends need zero changes. Sized at 300–400 lines in the safety-critical file; runs as a dedicated session because two smaller optimizer attempts at session-tail both ended in gate-refused reverts. Gates: gauntlet 30/30, self-host fixpoint, head-to-head rerun. - Sound bounds-check elision (the second 2×). Use the already-blessed exact dominance oracle to delete checks only where the index is provably in range — the Go result is the target picture. Soundness is the constraint: a wrong elision is a silent memory-safety hole, so every elided site gets a witness cell.
- Hoist the slice header, then migrate the corpus to
[]T— in that order. Adoption of the safe type is the point of having it; doing it before the 3.73× falls would push the regression tree-wide. - Probes for null-safety and data-races, so the two excluded axes become measured ones. The grade will drop before it rises; published anyway.
- Robustness debts: hard-error on undefined identifiers everywhere, lift the literal ceiling, surface compiler diagnostics through the build API (the multiplier that makes novel-organ authoring debuggable at scale).
- The disabled load-forwarding pass stays disabled until it gets a dedicated session: its wrong-value bug is fixed (escape-predicate alias rule), a distinct compiler crash remains, and the gauntlet has correctly refused it twice. A gate that keeps saying no is information, not an obstacle.