gencgc: Defer moving pinned pages to newspace as late as possible.
authorAlastair Bridgewater <alastair.bridgewater@gmail.com>
Sun, 12 May 2013 14:49:55 +0000 (10:49 -0400)
committerAlastair Bridgewater <nyef@kana.lisphacker.com>
Mon, 20 May 2013 19:51:20 +0000 (15:51 -0400)
  * Rather than moving pinned pages to newspace immediately, defer
moving them until just before we start to scavenge (evacuate) all
of the oldpsace pages.

  * This, in theory, makes it easier to move pages to newspace if
they are mostly-live, rather than having to allocate new pages for
the data (increasing peak address-space use during GC), assuming
that we know that some page meets such criteria.

  * While we're here, commentary updates also replace an "XX I'd
rather not do this but the GC logic can't cope with not doing it"
with an actual explanation of WHY it needs to be done.  In fact,
commentary updates explain it twice, in two different locations.

src/runtime/gencgc.c

index f755b80..c902d29 100644 (file)
@@ -2312,14 +2312,6 @@ preserve_pointer(void *addr)
         /* Mark the page static. */
         page_table[i].dont_move = 1;
 
-        /* Move the page to the new_space. XX I'd rather not do this
-         * but the GC logic is not quite able to copy with the static
-         * pages remaining in the from space. This also requires the
-         * generation bytes_allocated counters be updated. */
-        page_table[i].gen = new_space;
-        generations[new_space].bytes_allocated += page_table[i].bytes_used;
-        generations[from_space].bytes_allocated -= page_table[i].bytes_used;
-
         /* It is essential that the pages are not write protected as
          * they may have pointers into the old-space which need
          * scavenging. They shouldn't be write protected at this
@@ -3362,6 +3354,28 @@ preserve_context_registers (os_context_t *c)
 }
 #endif
 
+static void
+move_pinned_pages_to_newspace()
+{
+    page_index_t i;
+
+    /* scavenge() will evacuate all oldspace pages, but no newspace
+     * pages.  Pinned pages are precisely those pages which must not
+     * be evacuated, so move them to newspace directly. */
+
+    for (i = 0; i < last_free_page; i++) {
+        if (page_table[i].dont_move &&
+            /* dont_move is cleared lazily, so validate the space as well. */
+            page_table[i].gen == from_space) {
+            page_table[i].gen = new_space;
+            /* And since we're moving the pages wholesale, also adjust
+             * the generation allocation counters. */
+            generations[new_space].bytes_allocated += page_table[i].bytes_used;
+            generations[from_space].bytes_allocated -= page_table[i].bytes_used;
+        }
+    }
+}
+
 /* Garbage collect a generation. If raise is 0 then the remains of the
  * generation are not raised to the next generation. */
 static void
@@ -3529,6 +3543,12 @@ garbage_collect_generation(generation_index_t generation, int raise)
     }
 #endif
 
+    /* Now that all of the pinned (dont_move) pages are known, and
+     * before we start to scavenge (and thus relocate) objects,
+     * relocate the pinned pages to newspace, so that the scavenger
+     * will not attempt to relocate their contents. */
+    move_pinned_pages_to_newspace();
+
     /* Scavenge all the rest of the roots. */
 
 #if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)