Complete native stable generational GC and retained-heap fast paths - #24
Merged
Conversation
Admit object, array, table, and pin placement against committed pages before mutating the nursery. Keep emergency and evacuation reserves inside the hard limit and include typed non-heap usage in admission. Drive adaptive collection targets, bounded mature-cycle assists, empty page return, deterministic out-of-memory failures, and saturating pressure, debt, domain, and reserve telemetry. Keep the runtime labeled as conformance-only until concurrent workers and relocating backends land.
Track typed mutator execution states and require exact once-only state\npublication before a collector phase can advance. Keep heap-sized work out\nof the coordinator and expose deterministic transition telemetry.\n\nDocument the standalone coordinator separately from the remaining scheduler\nintegration and background worker work.
Run exact object-map scans on persistent host worker threads and return\nresults in deterministic sequence order before collector-owned mutation. Use\nbounded per-worker queues, dispatch sweep work, expose telemetry, and join all\nthreads during shutdown.\n\nKeep the runtime profile at relocation conformance until epochs, workers, and\nnative scheduler transitions are integrated for true mutator concurrency.
Scan immutable mature-card snapshots on the bounded worker pool before a\nminor evacuation. Install the exact young-reference result as collecting\nsafe-point roots so relocation preserves mature-to-young reachability without\nrescanning those cards on the collector owner.\n\nKeep concurrent mutator refinement open; this slice is parallel only inside\nthe already collecting safe point.
Replace the heap-sized unreachable-object inventory at the mark/sweep\ntransition with an ordered cursor that examines at most the configured work\nbudget per slice. Treat mature allocations during sweeping as live for the\nactive cycle and retain deterministic worker dispatch.\n\nThis removes full-heap transition work without claiming concurrent page\nreclamation.
Track scheduler-local, isolated, and shared ownership independently from\ngeneration, placement, allocation class, and pin state. Publish complete local\ngraphs transactionally into shared ownership and reject shared-to-local edges\nbefore any barrier or heap mutation.\n\nPreserve pinned and large-object placement as distinct memory-domain facts and\nleave isolated transfer and scheduler-indexed heaps for their own contracts.
Construct isolated regions only after proving one external owner and\nrejecting other handles, pins, stack roots, and incoming object edges. Keep\nisolated placement and accounting distinct, protect the owner capability, and\ntransfer scheduler ownership without copying object identity or graph edges.\n\nProvide explicit dissolution back to scheduler-local mature ownership so region\nlifetimes and owner handles do not become permanent leaks.
Give each scheduler independent TLAB cursors, page ownership metadata, minor\nrequests, and nursery evacuation scope. Preserve other schedulers' young\nobjects and tokens during a local collection and reject direct local edges\nacross scheduler ownership domains.\n\nKeep parallel scheduler execution and parallel evacuation as separate remaining\nproduction work.
Allocate scheduler-owned arena objects through typed bump storage with\ndisjoint scalar, same-arena, and managed-reference slots. Keep managed targets\nas precise relocating roots, reject cross-arena and cross-scheduler edges, and\nbulk-release all objects and roots on close.\n\nAccount arena bytes against the global hard limit before mutation and expose\nlifecycle, allocation, peak-byte, and bulk-reclamation telemetry.
ADR 0057 accepts Actor as a standard/platform root and Cluster as an optional official Package, but the canonical public inventory and catalog still omitted both names. This left the completed standard-foundation roadmap inconsistent with its architecture conformance snapshot. Record both roots in the owning catalog and implementation phase while keeping them planned and outside the frozen prelude and API baseline.
Scanning a large pointer array as one mark work item could monopolize a safe point or collector worker. Worker marking also cloned each complete allocation even when only a bounded part of its layout was needed. Split pointer-dense layouts into precise slot-range continuations. Schedule only one continuation at a time, interleave it with ordinary mark work, and send workers only the selected slot values. Preserve SATB and post-scan barriers across chunk boundaries and skip field tracing for pointer-free large objects. Expose cumulative chunk telemetry and keep the implementation roadmaps in sync with the verified collector behavior.
Selective evacuation needs exact pin metadata, but the generational runtime only retained opaque pin roots. It could not distinguish multiple handles for one object or report how long a pin constrained relocation. Track scoped handles and unique pinned objects separately. Measure active and completed lifetimes in deterministic safe-point units and report each long-lived handle once through runtime-private telemetry. Preflight the pin token and placement without work proportional to heap size, and keep failed pin or unpin operations telemetry-atomic. Update the collector and implementation roadmaps with the verified pinning boundary.
Reject noncanonical compatibility identities, namespace roots, prelude tier mismatches, and documentation path traversal before the frozen Standard baseline reaches name resolution. Bound total input, entry count, and individual rows so malformed metadata cannot consume unbounded work. Record the completed ADR 0058 consistency gate in the release roadmap and bootstrap documentation.
Track physical regions independently from page numbering so allocation domains and scheduler-local owners cannot mix. Report exact live, committed, fragmented, pinned, and reference-slot facts while shared regions follow the mature mark and sweep lifecycle. Choose only positive-benefit shared candidates within a fixed region bound and the protected evacuation reserve. Keep selected regions out of allocation pools and exclude pinned and large-object spaces before later forwarding and relocation work.
Copy every object in a selected shared region into compact monomorphic destination pages and rewrite precise fields, stack roots, strong handles, and card metadata before invalidating stale tokens.\n\nStage placement and heap updates together so malformed roots or reserve exhaustion cannot expose a partial relocation. Retire source regions through quarantine and record peak committed memory for the evacuation slice.
Avoid constructing root publications at native safe points when no collection is pending while still validating every published handle. Materialize bulk-initialized arrays in one allocation pass instead of zeroing and filling the same storage separately.\n\nRecord the checksum-equivalent churn and retained-object host baselines in the roadmap. The measurements identify repeated native ABI locking and handle access as the next optimization target.
Attach the persistent bounded worker pool after runtime configuration and use it to rewrite internal references in collector-staged evacuation copies. Preserve deterministic result ordering and keep the final external-edge, root, handle, card, and placement update failure-atomic on the collector.\n\nRecord worker evacuation telemetry and reject duplicate worker-pool attachment so custom runtimes can enable the same bounded path safely.
Capture the host-only Pop and Go checkpoint immediately after the evacuation worker slice. Record the rejected bootstrap access experiment as well so later optimization work targets the native ABI and storage boundary instead of repeating a measured regression.
Replace isolated worker channels with bounded owner-FIFO queues that let idle collectors steal from a peer's opposite end. Keep queue locks independent so marking, card refinement, sweeping, and evacuation do not serialize on one scheduling mutex.\n\nContinue to sort completed jobs by submission sequence before collector-owned mutation, report completed steals, and join every worker during shutdown.
Integrate the typed epoch coordinator with the generational runtime so a requested major cycle cannot trace or dispatch worker jobs before every registered managed mutator publishes a validated precise-root snapshot. Defer nursery relocation while the handshake retains physical tokens and record the completed boundary in the implementation roadmaps.
Replace the native bootstrap composition with the ABI 1 stable-token generational collector authorized by ADR 0059. Keep nursery movement and evacuation gated on writable roots in ABI 2. Batch mature-page reclamation, index active allocation pages, and bulk initialize scalar arrays. Scalar-replace safe read-only loop-local arrays so allocation-churn programs do not pay for unobservable heap objects.
Publish class and record payloads atomically through native ABI 1.11. This removes initializer barrier calls while preserving precise maps and failure-atomic publication.\n\nAdopt span-local cursors, cached memory accounting, inline small payloads, and deterministic arena-indexed token metadata. These changes remove ordered-map scans and per-object payload allocations from the retained-object fast path without scalar-replacing the managed graph.\n\nThe checksum-validated objectArray median falls from about 408 ms to 38 ms on the development host. Direct page-backed access and inline barriers remain production performance work.
Store each logical payload slot as one untagged machine word and let the exact object map define its interpretation. This preserves precise tracing while halving retained slot storage. Derive managed tokens from segmented directory coordinates instead of storing them beside every entry. Classify homogeneous array stores from their allocation descriptor so managed arrays keep constant-time checked access. This reduces the checksum-validated retained-object median from about 38.0 ms to 34.223 ms on the development host, while leaving direct page-backed access and common-path mutex removal as the next optimization boundary.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace the native bootstrap collector with Pop Lang’s stable-token generational
collector and make real native executables exercise mature allocation, SATB
marking, bounded sweeping, memory pacing, page management, and precise object
storage.
This PR delivers the complete ABI 1 stable-generational conformance slice:
BootstrapRuntimefrom native program execution;NativeStableGenerationalConformance;non-moving mature, large, or pinned domains;
relocation;
of allocation followed by repeated field calls;
safe points;
metadata;
duplicate token beside every entry;
a valid managed token;
objectArrayworkload and checksum validation;ROADMAP.md.The implementation does not scalar-replace or fuse the retained managed graph.
objectArraystill creates 200,000 distinct managed objects, retains themthrough a managed-reference array, reads every array element and object field,
and validates the
20000100000checksum.The branch also adds
LIST.md, a documentation-only inventory of proposedfirst-party Pop Lang batteries. It does not change GC or language semantics.
Performance
The original native retained-object path measured approximately 408 ms on the
development host.
Successive changes in this PR reduced the checksum-validated
objectArrayworkload to:
barrier specialization, and segmented metadata;
and token-derived directory entries;
The checked-in broad benchmark snapshot reports:
allocationChurn: approximately 0.770 ms;objectArray: approximately 32.145 ms.That snapshot contains one sample per runtime and is published as dashboard
data, not used as the primary regression claim. Performance numbers are
machine-local evidence rather than portable language guarantees.
Architecture traceability
architecture/15-garbage-collector-architecture.mdAllocateObjectInitializedPLRI operation;pop_rt_allocate_initialized_object;NativeStableGenerationalConformance;than the bootstrap collector;
ROADMAP.md, including concrete remaining heap problems.Verification
cargo fmt --all -- --checkcargo check --workspace --all-targetscargo test --workspace --all-targetscargo clippy --workspace --all-targets -- -D warningsAdditional completed verification:
pop-runtime-collectortest suite;tables, lists, ranges, and iteration tests;
-D warnings;objectArrayPop Lang/Go comparison.If a check was not run, explain why:
The final workspace-wide test and workspace-wide clippy commands were started
but interrupted before completion. Focused collector, native ABI, LLVM,
architecture, benchmark, formatting, workspace checking, and collector clippy
verification passed. CI should run the two unchecked workspace-wide commands.
Review notes
The tracked benchmark JSON and HTML reports are intentionally refreshed
benchmark artifacts. No build output, dependency cache, credentials, or editor
state is included. The untracked
popbook/directory is not part of this PR.Compatibility
Newly generated ABI 1.11 programs require a runtime archive that exports
pop_rt_allocate_initialized_object.Already-generated ABI 1.10 programs remain compatible with their corresponding
ABI 1.10 runtime. This PR does not silently select moving native allocation for
ABI 1 code.
Known limitations
This PR completes the stable native generational/conformance stage. It does not
claim that
ProductionConcurrentGenerationalis complete.Remaining problems are recorded in
ROADMAP.md:performance gate;
compiler-emitted descriptors;
incomplete;
Moving nursery allocation and selective evacuation remain disabled for native
ABI 1. They may be enabled only after ABI 2 writable-root reloads, forced native
relocation, stale-token rejection, stack/register/coroutine/unwind/FFI coverage,
and cross-backend tests pass.
The current worker path performs bounded parallel collector work but joins each
slice before returning to the mutator. It is not yet fully mutator-concurrent
collection.
The experimental C backend remains outside the production GC parity target.