1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00

Update manual

This commit is contained in:
Andy Wingo 2024-09-16 14:33:30 +02:00
parent b7306950bc
commit 506b4187fc
3 changed files with 71 additions and 10 deletions

View file

@ -26,6 +26,8 @@ See the [documentation](./doc/README.md).
- Inline allocation / write barrier fast paths (supporting JIT)
- One unified API with no-overhead abstraction: switch collectors when
you like
- Three policies for sizing heaps: fixed, proportional to live size, and
[MemBalancer](http://marisa.moe/balancer.html)
## Source repository structure
@ -42,9 +44,9 @@ See the [documentation](./doc/README.md).
## Status and roadmap
As of September 2024, Whippet is almost feature-complete. The main
missing feature is dynamic heap growth and shrinkage
(https://github.com/wingo/whippet/issues/5), which should land soon.
As of September 2024, Whippet is almost feature-complete. We need to
land a per-object pinning API, and an API for cooperative safepoints for
use by threads that are looping without allocating.
After that, the next phase on the roadmap is support for tracing, and
some performance noodling.

View file

@ -15,6 +15,12 @@ finalizers), and both ephemerons and finalizers only approximate the
Whippet behavior, because they are implemented in terms of what BDW-GC
provides.
`bdw` supports the `fixed` and `growable` heap-sizing policies, but not
`adaptive`, as BDW-GC can't reliably return memory to the OS. Also,
[`growable` has an effective limit of a 3x heap
multiplier](https://github.com/wingo/whippet/blob/main/src/bdw.c#L478).
Oh well!
It's a bit of an oddball from a Whippet perspective, but useful as a
migration path if you have an embedder that is already using BDW-GC.
And, it is a useful performance comparison.

View file

@ -77,13 +77,15 @@ visitor function on all outgoing edges in an object. It also includes a
of an object. `trace_edge` and `size` may be `NULL`, in which case no
tracing or size computation should be performed.
### Tracing ephemerons
### Tracing ephemerons and finalizers
Most kinds of GC-managed object are defined by the program, but the GC
itself has support for a specific object kind: ephemerons. If the
program allocates ephemerons, it should trace them in the
`gc_trace_object` function by calling `gc_trace_ephemeron` from
[`gc-ephemerons.h`](../api/gc-ephemerons.h).
itself has support for two specific object kind: ephemerons and
finalizers. If the program allocates ephemerons, it should trace them
in the `gc_trace_object` function by calling `gc_trace_ephemeron` from
[`gc-ephemerons.h`](../api/gc-ephemerons.h). Likewise if the program
allocates finalizers, it should trace them by calling
`gc_trace_finalizer` from [`gc-finalizer.h`](../api/gc-finalizer.h).
### Remembered-set bits
@ -299,6 +301,12 @@ We do this by including the `gc-embedder-api.h` implementation, via
$(COMPILE) -include foo-embedder.h -o gc-ephemeron.o -c gc-ephemeron.c
```
As for ephemerons, finalizers also have their own compilation unit.
```
$(COMPILE) -include foo-embedder.h -o gc-finalizer.o -c gc-finalizer.c
```
#### Compile-time options
There are a number of pre-processor definitions that can parameterize
@ -469,7 +477,7 @@ defined for all collectors:
You can set these options via `gc_option_set_int` and so on; see
[`gc-options.h`](../api/gc-options.h). Or, you can parse options from
trings: `heap-size-policy`, `heap-size`, `maximum-heap-size`, and so
strings: `heap-size-policy`, `heap-size`, `maximum-heap-size`, and so
on. Use `gc_option_from_string` to determine if a string is really an
option. Use `gc_option_parse_and_set` to parse a value for an option.
Use `gc_options_parse_and_set_many` to parse a number of comma-delimited
@ -669,4 +677,49 @@ An ephemeron association can be removed via `gc_ephemeron_mark_dead`.
### Finalizers
Not yet implemented!
A finalizer allows the embedder to be notified when an object becomes
unreachable.
A finalizer has a priority. When the heap is created, the embedder
should declare how many priorities there are. Lower-numbered priorities
take precedence; if an object has a priority-0 finalizer outstanding,
that will prevent any finalizer at level 1 (or 2, ...) from firing
until no priority-0 finalizer remains.
Call `gc_attach_finalizer`, from `gc-finalizer.h`, to attach a finalizer
to an object.
A finalizer also references an associated GC-managed closure object.
A finalizer's reference to the closure object is strong: if a
finalizer's closure closure references its finalizable object,
directly or indirectly, the finalizer will never fire.
When an object with a finalizer becomes unreachable, it is added to a
queue. The embedder can call `gc_pop_finalizable` to get the next
finalizable object and its associated closure. At that point the
embedder can do anything with the object, including keeping it alive.
Ephemeron associations will still be present while the finalizable
object is live. Note however that any objects referenced by the
finalizable object may themselves be already finalized; finalizers are
enqueued for objects when they become unreachable, which can concern
whole subgraphs of objects at once.
The usual way for an embedder to know when the queue of finalizable
object is non-empty is to call `gc_set_finalizer_callback` to
provide a function that will be invoked when there are pending
finalizers.
Arranging to call `gc_pop_finalizable` and doing something with the
finalizable object and closure is the responsibility of the embedder.
The embedder's finalization action can end up invoking arbitrary code,
so unless the embedder imposes some kind of restriction on what
finalizers can do, generally speaking finalizers should be run in a
dedicated thread instead of recursively from within whatever mutator
thread caused GC. Setting up such a thread is the responsibility of the
mutator. `gc_pop_finalizable` is thread-safe, allowing multiple
finalization threads if that is appropriate.
`gc_allocate_finalizer` returns a finalizer, which is a fresh GC-managed
heap object. The mutator should then directly attach it to an object
using `gc_finalizer_attach`. When the finalizer is fired, it becomes
available to the mutator via `gc_pop_finalizable`.