Allow having separate GC heaps and implement coordinated marking between
them; this is useful for keeping wasm and js GC heaps separated with a
clear boundary.
Mirrors `WeakHashSet` for map shapes. Cell-typed key and/or value
slots are stored as `Weak<T>` so entries vanish when their referent
is collected; non-cell slots are stored directly.
Similar to GC::Root<T>, make GC::RootVector<T> constructible without
explicitly passing a Heap.
This is implemented by having RootVectorBase use GC::Heap::the() for
heap-free construction.
The LibGC container and visitor tests share one heap per test binary.
A function-local static heap runs its destructor during C++ static
teardown. That makes sanitizer-only results depend on process shutdown
ordering.
Use NeverDestroyed for these process-lifetime test heaps. This matches
the intended lifetime and avoids destructor-time GC work during final
LSan checking.
Collection was purely allocation-driven: a GC only ran once
allocation since the last collection passed a threshold of 7/4 of
the live set (floored at 8 MiB). A page that allocated garbage but
never reached that threshold held onto it indefinitely once it went
idle, so we never handed memory back to the system promptly.
Run a 4-second repeating timer while the mutator is allocating; on
each tick IdleCollectionPolicy picks one of three actions:
- Park the timer when nothing has been allocated since the last
collection. The next allocation re-arms it, so a fully idle heap
costs nothing.
- Collect when this tick's allocation rate fell below 1/4 of the
peak rate seen this episode (the mutator left an active phase),
provided at least threshold/16 of garbage has piled up, so we
don't mark the whole live heap to reclaim a trivial amount.
- Otherwise let a watchdog collect after 15 ticks (60 seconds), so
garbage cannot sit indefinitely on a heap that allocates too
steadily to show a rate drop, or too slowly to clear the gate.
The GC heap is never completely silent in practice, since event-loop
housekeeping keeps queuing small objects like HTML tasks; that is
why the trigger watches for a relative rate drop rather than for
zero allocation.
The per-tick decision lives in IdleCollectionPolicy, separate from
the timer plumbing, with a unit test covering the rate-drop trigger,
the minimum-garbage gate, the watchdog, and parking when idle.
This requires the Variant to contain at least one visitable type.
For example, requiring them all to be visitable wouldn't allow types
such as `Variant<Empty, GC::Ref<Document>>`.
Add the proper annotations for the Cell and Cell::Visitor classes to be
visible in Swift. This lets us remove some OpaquePointer shinangians in
the Swift bindings.
This includes a protocol for creating LibGC Heap allocated Swift
objects. Pay no attention to the Unmanaged shenanigans, they are
all behind the curtain.