wingo pushed a commit to branch wip-whippet
in repository guile.

commit 3a86fedcded198a65d5c32cc519fe4bca77b9de1
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Fri Mar 7 21:15:47 2025 +0100

    Update nofl metadata byte comment
---
 src/nofl-space.h | 44 ++++++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 20 deletions(-)

diff --git a/src/nofl-space.h b/src/nofl-space.h
index 9a7f29304..2668232c6 100644
--- a/src/nofl-space.h
+++ b/src/nofl-space.h
@@ -197,32 +197,42 @@ struct nofl_allocator {
 // Because we want to allow for conservative roots, we need to know
 // whether an address indicates an object or not.  That means that when
 // an object is allocated, it has to set a bit, somewhere.  We use the
-// metadata byte for this purpose, setting the "young" bit.
+// metadata byte for this purpose, setting the "young" mark.
 //
-// The "young" bit's name might make you think about generational
+// The "young" mark's name might make you think about generational
 // collection, and indeed all objects collected in a minor collection
 // will have this bit set.  However, the nofl space never needs to check
-// for the young bit; if it weren't for the need to identify
-// conservative roots, we wouldn't need a young bit at all.  Perhaps in
+// for the young mark; if it weren't for the need to identify
+// conservative roots, we wouldn't need a young mark at all.  Perhaps in
 // an all-precise system, we would be able to avoid the overhead of
 // initializing mark byte upon each fresh allocation.
 //
-// When an object becomes dead after a GC, it will still have a bit set
-// -- maybe the young bit, or maybe a survivor bit.  The sweeper has to
-// clear these bits before the next collection.  But if we add
+// When an object becomes dead after a GC, it will still have a mark set
+// -- maybe the young mark, or maybe a survivor mark.  The sweeper has
+// to clear these marks before the next collection.  If we add
 // concurrent marking, we will also be marking "live" objects, updating
-// their mark bits.  So there are four object states concurrently
-// observable:  young, dead, survivor, and marked.  (We don't currently
-// have concurrent marking, though.)  Even though these states are
-// mutually exclusive, we use separate bits for them because we have the
-// space.  After each collection, the dead, survivor, and marked states
-// rotate by one bit.
+// their mark bits.  So there are three and possibly four object states
+// concurrently observable:  young, dead, survivor, and marked.  (We
+// don't currently have concurrent marking, though.)  We store this
+// state in the low 3 bits of the byte.  After each major collection,
+// the dead, survivor, and marked states rotate.
+//
+// It can be useful to support "raw" allocations, most often
+// pointerless, but for compatibility with BDW-GC, sometimes
+// conservatively-traced tagless data.  We reserve one or two bits for
+// the "kind" of the allocation: either a normal object traceable via
+// `gc_trace_object`, a pointerless untagged allocation that doesn't
+// need tracing, an allocation that should be traced conservatively, or
+// an ephemeron.  The latter two states are only used when conservative
+// tracing is enabled.
 //
 // An object can be pinned, preventing it from being evacuated during
 // collection.  Pinning does not keep the object alive; if it is
 // otherwise unreachable, it will be collected.  To pin an object, a
 // running mutator can set the pinned bit, using atomic
-// compare-and-swap.
+// compare-and-swap.  This bit overlaps the "trace conservatively" and
+// "ephemeron" trace kinds, but that's OK because we don't use the
+// pinned bit in those cases, as all objects are implicitly pinned.
 //
 // For generational collectors, the nofl space supports a field-logging
 // write barrier.  The two logging bits correspond to the two words in a
@@ -230,12 +240,6 @@ struct nofl_allocator {
 // the logged bit; if it is unset, it should try to atomically set the
 // bit, and if that works, then we record the field location as a
 // generational root, adding it to a sequential-store buffer.
-//
-// Finally, for heap-conservative collectors, nofl generally traces all
-// objects in the same way, treating them as an array of conservative
-// edges.  But we need to know when we have an ephemeron.  In that case,
-// we re-use the pinned bit, because it's of no use to us anyway in that
-// configuration, as all objects are pinned.
 enum nofl_metadata_byte {
   NOFL_METADATA_BYTE_NONE = 0,
   NOFL_METADATA_BYTE_YOUNG = 1,

Reply via email to