Compact GC root ranges
Issue #706 continues the debug path optimization. Consecutive instruction boundaries with identical root references in the same function/block now share an encoded range. Admission reconstructs every original boundary and reference list before the existing verifier and execution image use them. Small sections retain legacy encoding when ranges would increase aligned physical size.
Baseline parent: 3cf190d4; VM: 190479a. Updated VM: 9968700. Measurements use the same local compiler inputs and workstation as
the earlier reports. All six builtin generator determinism checks and the larger mapNotNull/mutableList inputs
were rerun. KiB = 1024 bytes. No external compression or interpreter speed improvement is claimed.
| Artifact | After paths, KiB | After ranges, KiB | This step | Combined reduction from original |
|---|---|---|---|---|
boot |
37.54 | 35.19 | 6.26% | 11.93% |
edit |
177.53 | 151.14 | 14.86% | 29.69% |
kotlinc |
35.40 | 33.45 | 5.52% | 15.93% |
shell |
124.15 | 115.07 | 7.32% | 20.74% |
vmbench-agent |
36.62 | 31.80 | 13.16% | 24.27% |
vmbench |
42.57 | 37.75 | 11.32% | 20.58% |
kotlin-map-not-null |
388.43 | 363.28 | 6.47% | 33.71% |
kotlin-mutable-list |
284.10 | 264.84 | 6.78% | 35.34% |
The editor is now 154772 bytes, down from 181788 after path pooling and 220116 originally. Shell is 117828 bytes. The mapNotNull example that reproduced the half-megabyte artifact is now 372000 bytes (363.28 KiB), from 561176. Runtime image maps still have one entry per original boundary; this is an artifact storage optimization.
Identity, admission and compatibility
The read-only equivalence check expands root ranges and rebuilds the container. All eight expanded files match exactly the previous #704 SHA-256. Expanding their debug paths then reproduces the original pre-optimization SHA-256 as well. This preserves every GC map, semantic payload, module hash, import reference and debug entry. The updated native public verifier independently accepts all eight compact files and validates module hashes.
SAFEPOINT_ROOT_RANGES (0x0112, critical/nonsemantic, flags 1) selects the compact representation in SAFEPOINT_ROOTS.
The marker declares version 1, expanded row count and canonical legacy payload length. Module hashing streams
the canonical expanded root encoding; other semantic sections keep their existing raw hashing. Runtime ABI 1.15,
container format 3.0 and native C ABI 20 remain unchanged. Old readers reject the new critical marker, and updated
readers retain legacy support. A negative check strips nonsemantic debug sections from compact boot to isolate
the root marker: the updated public reader accepts it; the frozen baseline native reader rejects it before execution.
Expanded counts, reference order, function/block ownership, block endpoints, range overlap, overflow, per-function
safepoint limits and canonical byte lengths are validated before constructing maps. Cumulative expanded root
payloads across modules count against the artifact-byte policy. Kotlin defaults to a 16 MiB expansion budget and
retains read(bytes); the added read(bytes, maximumExpandedRootBytes) overload permits custom host policy.
Rust uses fallible allocations and streams hashing without allocating another expanded byte buffer.
Published Runtime 0.20.0 bundles predate both compact capabilities. Use updated source-built natives; an immutable native release and parent pin update are still required before packaging with published bundles. No full-checkout or release readiness is claimed. The ABI reference owns the byte-level contract.
Verification
- 165 compiler-artifact JVM tests passed, including range round trips, every restored boundary, semantic identity, deterministic output, legacy fallback, malformed marker/owner/bounds and configurable expansion-byte limits.
- Rust workspace tests: 548 passed, 10 ignored. New public admission checks preserve legacy module hashes; parser tests preserve live references and reject malformed runs, overlaps, unmerged neighbors, widths and expansion limits. Existing golden artifacts and native GC/runtime tests continue to pass.
- Rust formatting and Clippy with all targets and warnings denied passed.
- Six builtin generators and mapNotNull/mutableList generators passed; Kotlin-to-VM mapNotNull, mutableList, exceptions and list-any-quota scenarios passed. The quota scenario executes boxed covariant list reads in a 64 KiB heap across exhausted slices; the restored maps retain the prior GC checkpoint coverage.
- Updated public native verification accepts all eight measured artifacts. Exact legacy equivalence and analyzer accounting pass; logical empty-root, root-set and repeated-map counts remain equal to the earlier inventory.
Exact sizes and hashes, section inventory, verification commands.
Reproduce the exact byte comparison from this source revision after regenerating the inputs:
python3 docs/benchmarks/root-ranges-706-2026-10-07/verify_legacy_equivalence.py
The script reads current artifacts and the earlier recorded hashes, expands in memory, and prints JSON only after both legacy equivalence checks succeed. It is not a substitute for native verification.