std in Nikaia, a Real Mapping, and a Parallel DriverStatus: Accepted
Closes: fs::map reading rather than mapping, and a parallel section running
its pieces in sequence
Superseded in part by: ADR-002 D4 (when D1’s lowering runs),
ADR-015 D3 (D3’s measurement)
Related: ADR-001 D4 (Stage 0 is a transpiler — which is what
makes D1 possible at all), ADR-296 D11 and D15
Two things the flagship needed — a real mapping and a parallel driver — are dependency decisions rather than compiler ones.
A third question: can more of Nikaia be written in Nikaia? The answer is yes, in a bounded way, and the way matters more than the amount.
nikaia-std are .nika files, compiled by Stage 0.Changed by ADR-002 D4: std’s Nikaia half is lowered at release time by the nikaia binary and the .rs is committed beside the .nika; there is no build script and no build-dependency on the compiler.
The first such file is one function:
pub fn digit_value(c: char) -> i32 {
return c as i32 - 48
}
The point is not its size. It is code the project itself runs on that the
Nikaia compiler produced, and it establishes the mechanism by which the share
grows: what a .nika file in std may contain is exactly what Stage 0 can
lower, and each construct the compiler learns is a function that can move.
list.rs (a trait with a generic method) moves when traits and generics are
lowered; cli.rs when std::env is reachable. fs.rs does not move: it is
unsafe around a memory mapping, and that is the layer a self-hosted language
still writes in the host.
fs::map is a memory mapping.Read-only, validated as UTF-8 once when the map is made; after that a view of
the text is a view of the pages, and the unsafe that says so is a comment
pointing at the validation. A zero-length file cannot be mapped and is an empty
input rather than an error.
ADR-296 D15’s allowance — leave a large read-only mapping to the OS at process exit — is not taken; the mapping is released on drop.
Changed by ADR-015 D3: the absolute figures are re-measured there; the ratio below is unchanged.
The backend’s rayon feature is enabled on the workspace dependency rather
than on nikaia-std alone, for a build reason rather than a semantic one: cargo
would otherwise hold two differently-featured copies of the crate, and the tests
that compile emitted programs against the deps directory would have to know
which one the runtime meant.
Measured on 8 million lines, 4 cores: wall time divides by the cores while user time is unchanged, which is what a frame plus a monoid buys and what nothing in the program says how to do.
Output is identical byte for byte at either setting — ADR-296 D10’s whole claim.
A deps directory can hold two rlibs of one crate that do not link together, and then “the newest file” is a coin toss.
An rlib’s dependencies can be read out as name-hash, the hash being the one in
the file name. The tests anchor on nikaia_std, read the parser backend from it
and winnow from that, and hand rustc one consistent set. This is why
nikaia-std declares the parser backend as a dependency: the runtime and the
parser it runs on are one dependency, and the chain needs somewhere to start.
The flagship does everything its comments claim. A test checks it on the real file; the timing is not a test, because a test that asserts a speed-up fails on a loaded CI runner. The identical output at either setting is asserted; the speed-up is measured.