Parallel GC mutators need write barriers, stack-map coverage, and scheduler coordination. Shipping partial parallel GC risks data races on the Abfall heap.
Contracts and edge cases
Platform spec article
Contracts and edge cases
Spec standingStandard
-
v0.2 targets single mutator; Phase B requires spec and barrier completion first.
Context
Decision
Phase Mutators Ship order A (v0.2) One Beskid mutator; many cooperative fibers Default ship B (v0.3, opt-in) Parallel mutators + real gc_write_barrieron pointer-payload channels + syscall-pool guardWired behind BESKID_RUNTIME_PHASE_B/set_runtime_phase(RuntimePhase::PhaseB); stays opt-in until preemption emission and concurrent-mark stress landB (later) Phase B becomes the default Requires AOT/JIT to insert runtime_preempt_checkprologues and full concurrent-mark stress coveragePhase B must not become the default without updating this feature hub and fiber scheduler contracts.
Consequences
Phase A barriers stay correct because Phase B reuses the same Dijkstra insertion barrier; the difference is that Phase B exercises it on multi-mutator workloads and on pointer-payload channel ops. Fiber/feature docs cross-link Phase tables.
Verification anchors
GC integration tests under
crates/beskid_runtime/tests/:tests/concurrency.rs— channel/scheduler coretests/gc.rs,tests/gc_concurrency.rs— Phase A heap and root handlestests/phase_b_concurrency.rs— Phase B multi-mutator stress, pointer-payload channels with write barriers, syscall-pool guard, optional preemption hook
Platform-spec Phase diagrams in hub and design model.
-
Reference runtime uses vendored Abfall mark/sweep with barriered stores.
Context
The prior arena model needed a collector that supports concurrent marking and precise scanning with compiler-emitted descriptors.
Decision
Component Role Abfall Tri-color mark/sweep heap integrated in beskid_runtime::gcBarriers gc_write_barrieron pointer stores during markingSTW Limited stop-the-world for root scan and phase transitions Snapshots GcSnapshot/enter_runtime_scopefor host toolingGit anchor:
6ecd493(vendored Abfall + Beskid heap integration).Consequences
Lowering must emit barriers where Phase requires them. Hosts attach runtime scope before JIT/AOT execution.
Verification anchors
compiler/crates/beskid_runtime/src/gc/; JIT runtime tests. -
alloc attaches descriptors; roots include stacks, globals, and handles.
Context
Conservative stack scanning alone is insufficient for precise Beskid object graphs across fibers and codegen optimizations.
Decision
Rule Detail Header Heap objects begin with a type descriptor pointer for precise scan Allocation alloc(size, type_desc)usesabfall::Heap::allocate_beskidStrings / arrays BeskidStr,BeskidArrayheaders per builtins layoutRoots Stacks (stack maps), globals (registered roots), gc_root_handleexternalsCompiler Lowers descriptors and stack maps; does not embed collector policy Consequences
Descriptor schema changes are ABI-visible per D-EXEC-ABI-0002.
Verification anchors
beskid_codegenstack maps;beskid_runtimealloc/GC tests.
- Contracts and edge cases MUST rules for allocation, barriers, roots, and Phase A mutator exclusivity.
- Design model Heap ownership, tri-color GC, Phase A mutator rules, and compiler/runtime split.
- Examples Allocation failures, GC pacing triggers, and external root pinning scenarios.
- FAQ and troubleshooting GC pauses, mutator violations, barrier omissions, and heap growth debugging.
- Flow and algorithm Allocation, barrier insertion, collection pacing, and safepoint algorithms.
- Verification and traceability Runtime GC tests, Abfall integration, and compiler stack-map obligations.
0 revisions (git unavailable at build; counts may be empty)
No commits recorded for this path.
| Section id | Required | Found |
|---|---|---|
what-this-feature-specifies | yes | yes |
implementation-anchors | yes | yes |
Full tree: run pnpm verify:platform-spec-layout (writes src/generated/platform-spec-layout-report.json).
Normative requirements
Section titled “Normative requirements”| ID | Requirement |
|---|---|
| GC-001 | All heap objects must carry type descriptors reachable from the object header for precise scanning. |
| GC-002 | Pointer stores in generated code must lower to gc_write_barrier when concurrent marking is enabled. |
| GC-003 | Phase A must execute at most one Beskid mutator performing allocations at a time. |
| GC-004 | gc_collect / gc_collect_if_needed must be safe to call from host tooling when runtime scope is entered. |
| GC-005 | External roots must pair gc_register_root with gc_unregister_root (or handle APIs) to avoid leaks. |
| GC-006 | Stack maps must be emitted for functions that hold GC pointers across safepoints. |
| GC-007 | Phase B mutators must attach to a shared heap through attach_phase_b_mutator (or an equivalent runtime scope) before allocating or reading GC-managed pointers. |
| GC-008 | Syscall-pool worker threads must not allocate on the Beskid heap; the runtime must trap the violation when assertions are enabled. |
| GC-009 | Pointer-payload channel transfers must apply the insertion write barrier on both send and receive paths, and must keep the in-flight pointer reachable via an external GC handle while it sits in the queue. |
| GC-010 | Optional preemption (runtime_preempt_check) must be a no-op when preemption is disabled and must never block a syscall-pool worker thread. |
GC export contracts
Section titled “GC export contracts”| Symbol | Returns | Semantics |
|---|---|---|
gc_bytes_allocated | i64 | Total allocated bytes (diagnostic) |
gc_object_count | i64 | Live object estimate |
gc_phase | i64 | Phase enum 0/1/2 |
gc_write_barrier | void | Barrier hook |
gc_root_handle | i64 | Temporary external pin |
channel_send_ptr / channel_receive_ptr | i64 status | Pointer-payload channel ops with barrier and external-handle handoff |
runtime_preempt_check | void | Optional safe-point hook; yields when preemption is enabled |
Edge cases
Section titled “Edge cases”| Case | Behavior |
|---|---|
| Null pointer store | Lowering should avoid barrier; runtime barrier on null should no-op |
| Fiber migration mid-mark | Scheduler holds mutator lock; no second mutator attaches (Phase A only) |
| Multiple Phase B mutators on one heap | Each thread holds a MutatorAttachGuard; shared heap + per-thread GC context |
Full heap during str_concat | Panic/trap — matches allocation failure policy |
| Conservative fallback | Forbidden — Beskid uses precise descriptors only |
| Syscall-pool worker accidentally allocates | assert_mutator_allowed panics; the worker is not a mutator |
| Pointer-payload channel sender from a non-fiber OS thread | Backpressure resolved by try_send + thread::yield_now, never park_current |
Rejected alternatives (decision record)
Section titled “Rejected alternatives (decision record)”Reference counting, conservative GC, and region-only allocation are rejected for v0.2; see legacy Concurrent GC decision summary.