Document MIN_PAYLOAD_SIZE and mark-compact GC mark bits
authorÖmer Sinan Ağacan <omeragacan@gmail.com>
Thu, 19 Sep 2019 07:16:09 +0000 (10:16 +0300)
committerMarge Bot <ben+marge-bot@smart-cactus.org>
Sat, 21 Sep 2019 13:53:29 +0000 (09:53 -0400)
This updates the documentation of the MIN_PAYLOAD_SIZE constant and adds
a new Note [Mark bits in mark-compact collector] explaning why the
mark-compact collector uses two bits per objet and why we need
MIN_PAYLOAD_SIZE.

includes/rts/Constants.h
rts/sm/Compact.c
rts/sm/Compact.h

index 15ff2a4..c2cad8f 100644 (file)
 /* -----------------------------------------------------------------------------
    Minimum closure sizes
 
-   This is the minimum number of words in the payload of a
-   heap-allocated closure, so that the closure has enough room to be
-   overwritten with a forwarding pointer during garbage collection.
+   This is the minimum number of words in the payload of a heap-allocated
+   closure, so that the closure has two bits in the bitmap for mark-compact
+   collection.
+
+   See Note [Mark bits in mark-compact collector] in rts/sm/Compact.h
    -------------------------------------------------------------------------- */
 
 #define MIN_PAYLOAD_SIZE 1
index 3bfefa7..927a505 100644 (file)
@@ -830,10 +830,11 @@ update_fwd_compact( bdescr *blocks )
 
             size = p - q;
             if (free + size > free_bd->start + BLOCK_SIZE_W) {
-                // set the next bit in the bitmap to indicate that
-                // this object needs to be pushed into the next
-                // block.  This saves us having to run down the
-                // threaded info pointer list twice during the next pass.
+                // set the next bit in the bitmap to indicate that this object
+                // needs to be pushed into the next block.  This saves us having
+                // to run down the threaded info pointer list twice during the
+                // next pass. See Note [Mark bits in mark-compact collector] in
+                // Compact.h.
                 mark(q+1,bd);
                 free_bd = free_bd->link;
                 free = free_bd->start;
index b052112..be9a09d 100644 (file)
 
 #include "BeginPrivate.h"
 
+/* -----------------------------------------------------------------------------
+   Note [Mark bits in mark-compact collector]
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   In mark-compact collector each closure has two mark bits:
+
+   - Liveness bit: not marked == unreachable (dead)
+
+   - "Too large" bit: when this is set it means that the closure won't fit in
+     the current heap block and we need to move it to the next block in the
+     heap.
+
+   Why do we need the second bit? We only know a closure's size *before*
+   threading it, because after threading the info table pointer will be end of
+   the chain. So by the time we do the second pass to move the closures and
+   unthread chains we'd have to do two passes, one for to get the info table
+   pointer at the end of the chain to compute the closure size and update the
+   free pointer if it's too large to fit in the current block, and then another
+   pass to actually unthread.
+
+   To avoid this we update the second bit when we first visit an object (in the
+   "forward" pass) and realize that it won't fit in the current block, and check
+   that bit in the second pass (where we actually move the object and update all
+   references). If the bit is set we move the object to the free location in the
+   next block in heap chain, otherwise we use the free pointer in the current
+   block.
+
+   Instead of allocating two bits per object, we use the fact that most heap
+   closures will be at least two words (as one-word closures will mostly be
+   static objects), and allocate one bit per word in the heap. In the rare cases
+   where we allocate single-word heap objects (e.g. a non-top-level FUN with
+   empty payload) we add one non-pointer field to the payload so that the object
+   will have two words. The minimum amount of words in the payload is defined in
+   includes/rts/Constants.h as MIN_PAYLOAD_SIZE.
+
+   (See also !1701 where we discussed lifting this restriction and allocating
+   two bits per object)
+   -------------------------------------------------------------------------- */
+
 INLINE_HEADER void
 mark(StgPtr p, bdescr *bd)
 {