[MLton-commit] r4122

Matthew Fluet MLton@mlton.org
Sat, 29 Oct 2005 12:00:22 -0700


Mark-compact GC
----------------------------------------------------------------------

U   mlton/branches/on-20050822-x86_64-branch/runtime/gc/mark-compact.c

----------------------------------------------------------------------

Modified: mlton/branches/on-20050822-x86_64-branch/runtime/gc/mark-compact.c
===================================================================
--- mlton/branches/on-20050822-x86_64-branch/runtime/gc/mark-compact.c	2005-10-26 01:25:07 UTC (rev 4121)
+++ mlton/branches/on-20050822-x86_64-branch/runtime/gc/mark-compact.c	2005-10-29 19:00:21 UTC (rev 4122)
@@ -31,242 +31,261 @@
   dfsMark (s, p, UNMARK_MODE, FALSE);
 }
 
-static inline void threadInternal (GC_state s, objptr *opp) {
+/* An object pointer might be larger than a header.
+ */ 
+static inline void threadInternalCopy (pointer dst, pointer src) {
+  size_t count = (OBJPTR_SIZE - GC_HEADER_SIZE) / GC_HEADER_SIZE;
+  src = src + GC_HEADER_SIZE * count;
+
+  for (size_t i = 0; i <= count; i++) {
+    *((GC_header*)dst) = *((GC_header*)src);
+    dst += GC_HEADER_SIZE;
+    src -= GC_HEADER_SIZE;
+  }
+}
+
+static inline void threadInternalObjptr (GC_state s, objptr *opp) {
+  objptr opop;
   pointer p;
   GC_header *headerp;
 
+  opop = pointerToObjptr ((pointer)opp, s->heap.start);
   p = objptrToPointer (*opp, s->heap.start);
   if (FALSE)
     fprintf (stderr, 
              "threadInternal opp = "FMTPTR"  p = "FMTPTR"  header = "FMTHDR"\n",
              (uintptr_t)opp, (uintptr_t)p, getHeader (p));
   headerp = getHeaderp (p);
+  threadInternalCopy ((pointer)(opp), (pointer)(headerp));
+  threadInternalCopy ((pointer)(headerp), (pointer)(&opop));
 }
 
-/* static inline void threadInternal (GC_state s, pointer *pp) { */
-/*         Header *headerp; */
+/* If p is weak, the object pointer was valid, and points to an unmarked object,
+ * then clear the object pointer.
+ */
+static inline void maybeClearWeak (GC_state s, pointer p) {
+  GC_header header;
+  GC_header *headerp;
+  uint16_t numNonObjptrs, numObjptrs;
+  GC_objectTypeTag tag;
 
-/*         if (FALSE) */
-/*                 fprintf (stderr, "threadInternal pp = 0x%08x  *pp = 0x%08x  header = 0x%08x\n", */
-/*                                 (uint)pp, *(uint*)pp, (uint)GC_getHeader (*pp)); */
-/*         headerp = GC_getHeaderp (*pp); */
-/*         *(Header*)pp = *headerp; */
-/*         *headerp = (Header)pp; */
-/* } */
+  headerp = getHeaderp (p);
+  header = *headerp;
+  splitHeader(s, *headerp, &tag, NULL, &numNonObjptrs, &numObjptrs);
+  if (WEAK_TAG == tag and 1 == numObjptrs) {
+    GC_header h2;
+    
+    if (DEBUG_WEAK)
+      fprintf (stderr, "maybeClearWeak ("FMTPTR")  header = "FMTHDR"\n",
+               (uintptr_t)p, header);
+    h2 = getHeader (objptrToPointer(((GC_weak)p)->objptr, s->heap.start));
+    /* If it's unmarked not threaded, clear the weak pointer. */
+    if (1 == ((MARK_MASK | 1) & h2)) {
+      ((GC_weak)p)->objptr = BOGUS_OBJPTR;
+      header = GC_WEAK_GONE_HEADER | MARK_MASK;
+      if (DEBUG_WEAK)
+        fprintf (stderr, "cleared.  new header = "FMTHDR"\n",
+                 header);
+      *headerp = header;
+    }
+  }
+}
 
-/* /\* If p is weak, the object pointer was valid, and points to an unmarked object, */
-/*  * then clear the object pointer. */
-/*  *\/ */
-/* static inline void maybeClearWeak (GC_state s, pointer p) { */
-/*         Bool hasIdentity; */
-/*         Header header; */
-/*         Header *headerp; */
-/*         uint numPointers; */
-/*         uint numNonPointers; */
-/*         uint tag; */
+static void updateForwardPointers (GC_state s) {
+  pointer back;
+  pointer endOfLastMarked;
+  pointer front;
+  size_t gap;
+  GC_header header;
+  GC_header *headerp;
+  pointer p;
+  size_t size;
 
-/*         headerp = GC_getHeaderp (p); */
-/*         header = *headerp; */
-/*         SPLIT_HEADER(); */
-/*         if (WEAK_TAG == tag and 1 == numPointers) {  */
-/*                 Header h2; */
+  if (DEBUG_MARK_COMPACT)
+    fprintf (stderr, "Update forward pointers.\n");
+  front = alignFrontier (s, s->heap.start);
+  back = s->heap.start + s->heap.oldGenSize;
+  endOfLastMarked = front;
+  gap = 0;
+updateObject:
+  if (DEBUG_MARK_COMPACT)
+    fprintf (stderr, "updateObject  front = "FMTPTR"  back = "FMTPTR"\n",
+             (uintptr_t)front, (uintptr_t)back);
+  if (front == back)
+    goto done;
+  headerp = (GC_header*)front;
+  header = *headerp;
+  if (0 == header) {
+    /* We're looking at an array.  Move to the header. */
+    p = front + GC_ARRAY_HEADER_SIZE;
+    headerp = (GC_header*)(p - GC_HEADER_SIZE);
+    header = *headerp;
+  } else
+    p = front + GC_HEADER_SIZE;
+  if (1 == (1 & header)) {
+    /* It's a header */
+    if (MARK_MASK & header) {
+      /* It is marked, but has no forward pointers.
+       * Thread internal pointers.
+       */
+thread:
+      maybeClearWeak (s, p);
+      size = objectSize (s, p);
+      if (DEBUG_MARK_COMPACT)
+        fprintf (stderr, "threading "FMTPTR" of size %zu\n",
+                 (uintptr_t)p, size);
+      if ((size_t)(front - endOfLastMarked) >= GC_ARRAY_HEADER_SIZE + OBJPTR_SIZE) {
+        /* Compress all of the unmarked into one string.  We require
+         * (GC_ARRAY_HEADER_SIZE + OBJPTR_SIZE) space to be available
+         * because that is the smallest possible array.  You cannot
+         * use GC_ARRAY_HEADER_SIZE because even zero-length arrays
+         * require an extra word for the forwarding pointer.  If you
+         * did use GC_ARRAY_HEADER_SIZE,
+         * updateBackwardPointersAndSlide would skip the extra word
+         * and be completely busted.
+         */
+        if (DEBUG_MARK_COMPACT)
+          fprintf (stderr, "compressing from "FMTPTR" to "FMTPTR" (length = %zu)\n",
+                   (uintptr_t)endOfLastMarked, (uintptr_t)front,
+                   (size_t)(front - endOfLastMarked));
+        *((GC_arrayCounter*)(endOfLastMarked)) = 0;
+        endOfLastMarked = endOfLastMarked + GC_ARRAY_COUNTER_SIZE;
+        *((GC_arrayLength*)(endOfLastMarked)) = ((size_t)(front - endOfLastMarked)) - GC_ARRAY_HEADER_SIZE;
+        endOfLastMarked = endOfLastMarked + GC_ARRAY_LENGTH_SIZE;
+        *((GC_header*)(endOfLastMarked)) = GC_STRING_HEADER;
+      }
+      front += size;
+      endOfLastMarked = front;
+      foreachObjptrInObject (s, p, FALSE, threadInternalObjptr);
+      goto updateObject;
+    } else {
+      /* It's not marked. */
+      size = objectSize (s, p);
+      gap += size;
+      front += size;
+      goto updateObject;
+    }
+  } else {
+    pointer new;
+    objptr newObjptr;
 
-/*                 if (DEBUG_WEAK) */
-/*                         fprintf (stderr, "maybeClearWeak (0x%08x)  header = 0x%08x\n", */
-/*                                         (uint)p, (uint)header); */
-/*                 h2 = GC_getHeader (((GC_weak)p)->object); */
-/*                 /\* If it's unmarked not threaded, clear the weak pointer. *\/ */
-/*                 if (1 == ((MARK_MASK | 1) & h2)) { */
-/*                         ((GC_weak)p)->object = (pointer)BOGUS_POINTER; */
-/*                         header = WEAK_GONE_HEADER | MARK_MASK; */
-/*                         if (DEBUG_WEAK) */
-/*                                 fprintf (stderr, "cleared.  new header = 0x%08x\n", */
-/*                                                 (uint)header); */
-/*                         *headerp = header; */
-/*                 } */
-/*         } */
-/* } */
+    assert (0 == (1 & header));
+    /* It's a pointer.  This object must be live.  Fix all the forward
+     * pointers to it, store its header, then thread its internal
+     * pointers.
+     */
+    new = p - gap;
+    newObjptr = pointerToObjptr (new, s->heap.start);
+    do {
+      pointer cur;
+      objptr curObjptr;
 
-/* static void updateForwardPointers (GC_state s) { */
-/*         pointer back; */
-/*         pointer front; */
-/*         uint gap; */
-/*         pointer endOfLastMarked; */
-/*         Header header; */
-/*         Header *headerp; */
-/*         pointer p; */
-/*         uint size; */
+      threadInternalCopy ((pointer)(&curObjptr), (pointer)headerp);
+      cur = objptrToPointer (curObjptr, s->heap.start);
 
-/*         if (DEBUG_MARK_COMPACT) */
-/*                 fprintf (stderr, "Update forward pointers.\n"); */
-/*         front = alignFrontier (s, s->heap.start); */
-/*         back = s->heap.start + s->oldGenSize; */
-/*         endOfLastMarked = front; */
-/*         gap = 0; */
-/* updateObject: */
-/*         if (DEBUG_MARK_COMPACT) */
-/*                 fprintf (stderr, "updateObject  front = 0x%08x  back = 0x%08x\n", */
-/*                                 (uint)front, (uint)back); */
-/*         if (front == back) */
-/*                 goto done; */
-/*         headerp = (Header*)front; */
-/*         header = *headerp; */
-/*         if (0 == header) { */
-/*                 /\* We're looking at an array.  Move to the header. *\/ */
-/*                 p = front + 3 * WORD_SIZE; */
-/*                 headerp = (Header*)(p - WORD_SIZE); */
-/*                 header = *headerp; */
-/*         } else  */
-/*                 p = front + WORD_SIZE; */
-/*         if (1 == (1 & header)) { */
-/*                 /\* It's a header *\/ */
-/*                 if (MARK_MASK & header) { */
-/*                         /\* It is marked, but has no forward pointers.  */
-/*                          * Thread internal pointers. */
-/*                          *\/ */
-/* thread: */
-/*                         maybeClearWeak (s, p); */
-/*                         size = objectSize (s, p); */
-/*                         if (DEBUG_MARK_COMPACT) */
-/*                                 fprintf (stderr, "threading 0x%08x of size %u\n",  */
-/*                                                 (uint)p, size); */
-/*                         if (front - endOfLastMarked >= 4 * WORD_SIZE) { */
-/*                                 /\* Compress all of the unmarked into one string. */
-/*                                  * We require 4 * WORD_SIZE space to be available */
-/*                                  * because that is the smallest possible array. */
-/*                                  * You cannot use 3 * WORD_SIZE because even */
-/*                                  * zero-length arrays require an extra word for */
-/*                                  * the forwarding pointer.  If you did use */
-/*                                  * 3 * WORD_SIZE, updateBackwardPointersAndSlide */
-/*                                  * would skip the extra word and be completely */
-/*                                  * busted. */
-/*                                  *\/ */
-/*                                 if (DEBUG_MARK_COMPACT) */
-/*                                         fprintf (stderr, "compressing from 0x%08x to 0x%08x (length = %u)\n", */
-/*                                                         (uint)endOfLastMarked, */
-/*                                                         (uint)front, */
-/*                                                         front - endOfLastMarked); */
-/*                                 *(uint*)endOfLastMarked = 0; */
-/*                                 *(uint*)(endOfLastMarked + WORD_SIZE) =  */
-/*                                         front - endOfLastMarked - 3 * WORD_SIZE; */
-/*                                 *(uint*)(endOfLastMarked + 2 * WORD_SIZE) = */
-/*                                         GC_objectHeader (STRING_TYPE_INDEX); */
-/*                         } */
-/*                         front += size; */
-/*                         endOfLastMarked = front; */
-/*                         foreachPointerInObject (s, p, FALSE, threadInternal); */
-/*                         goto updateObject; */
-/*                 } else { */
-/*                         /\* It's not marked. *\/ */
-/*                         size = objectSize (s, p); */
-/*                         gap += size; */
-/*                         front += size; */
-/*                         goto updateObject; */
-/*                 } */
-/*         } else { */
-/*                 pointer new; */
+      threadInternalCopy ((pointer)headerp, cur);
+      *((objptr*)cur) = newObjptr;
 
-/*                 assert (0 == (3 & header)); */
-/*                 /\* It's a pointer.  This object must be live.  Fix all the */
-/*                  * forward pointers to it, store its header, then thread */
-/*                  * its internal pointers. */
-/*                  *\/ */
-/*                 new = p - gap; */
-/*                 do { */
-/*                         pointer cur; */
+      header = *headerp;
+    } while (0 == (1 & header));
+    goto thread;
+  }
+  assert (FALSE);
+done:
+  return;
+}
 
-/*                         cur = (pointer)header; */
-/*                         header = *(word*)cur; */
-/*                         *(word*)cur = (word)new; */
-/*                 } while (0 == (1 & header)); */
-/*                 *headerp = header; */
-/*                 goto thread; */
-/*         } */
-/*         assert (FALSE); */
-/* done: */
-/*         return; */
-/* } */
+static void updateBackwardPointersAndSlide (GC_state s) {
+  pointer back;
+  pointer front;
+  size_t gap;
+  GC_header header;
+  GC_header *headerp;
+  pointer p;
+  size_t size;
 
-/* static void updateBackwardPointersAndSlide (GC_state s) { */
-/*         pointer back; */
-/*         pointer front; */
-/*         uint gap; */
-/*         Header header; */
-/*         pointer p; */
-/*         uint size; */
+  if (DEBUG_MARK_COMPACT)
+    fprintf (stderr, "Update backward pointers and slide.\n");
+  front = alignFrontier (s, s->heap.start);
+  back = s->heap.start + s->heap.oldGenSize;
+  gap = 0;
+updateObject:
+  if (DEBUG_MARK_COMPACT)
+    fprintf (stderr, "updateObject  front = "FMTPTR"  back = "FMTPTR"\n",
+             (uintptr_t)front, (uintptr_t)back);
+  if (front == back)
+    goto done;
+  headerp = (GC_header*)front;
+  header = *headerp;
+  if (0 == header) {
+    /* We're looking at an array.  Move to the header. */
+    p = front + GC_ARRAY_HEADER_SIZE;
+    headerp = (GC_header*)(p - GC_HEADER_SIZE);
+    header = *headerp;
+  } else
+    p = front + GC_HEADER_SIZE;
+  if (1 == (1 & header)) {
+    /* It's a header */
+    if (MARK_MASK & header) {
+      /* It is marked, but has no backward pointers to it.
+       * Unmark it.
+       */
+unmark:
+      size = objectSize (s, p);
+      /* unmark */
+      if (DEBUG_MARK_COMPACT)
+        fprintf (stderr, "unmarking "FMTPTR" of size %zu\n",
+                 (uintptr_t)p, size);
+      *headerp = header & ~MARK_MASK;
+      /* slide */
+      if (DEBUG_MARK_COMPACT)
+        fprintf (stderr, "sliding "FMTPTR" down %zu\n",
+                 (uintptr_t)front, gap);
+      GC_memcpy (front, front - gap, size);
+      front += size;
+      goto updateObject;
+    } else {
+      /* It's not marked. */
+      size = objectSize (s, p);
+      if (DEBUG_MARK_COMPACT)
+        fprintf (stderr, "skipping "FMTPTR" of size %zu\n",
+                 (uintptr_t)p, size);
+      gap += size;
+      front += size;
+      goto updateObject;
+    }
+  } else {
+    pointer new;
+    objptr newObjptr;
 
-/*         if (DEBUG_MARK_COMPACT) */
-/*                 fprintf (stderr, "Update backward pointers and slide.\n"); */
-/*         front = alignFrontier (s, s->heap.start); */
-/*         back = s->heap.start + s->oldGenSize; */
-/*         gap = 0; */
-/* updateObject: */
-/*         if (DEBUG_MARK_COMPACT) */
-/*                 fprintf (stderr, "updateObject  front = 0x%08x  back = 0x%08x\n", */
-/*                                 (uint)front, (uint)back); */
-/*         if (front == back) */
-/*                 goto done; */
-/*         header = *(word*)front; */
-/*         if (0 == header) { */
-/*                 /\* We're looking at an array.  Move to the header. *\/ */
-/*                 p = front + 3 * WORD_SIZE; */
-/*                 header = *(Header*)(p - WORD_SIZE); */
-/*         } else  */
-/*                 p = front + WORD_SIZE; */
-/*         if (1 == (1 & header)) { */
-/*                 /\* It's a header *\/ */
-/*                 if (MARK_MASK & header) { */
-/*                         /\* It is marked, but has no backward pointers to it. */
-/*                          * Unmark it. */
-/*                          *\/ */
-/* unmark: */
-/*                         *GC_getHeaderp (p) = header & ~MARK_MASK; */
-/*                         size = objectSize (s, p); */
-/*                         if (DEBUG_MARK_COMPACT) */
-/*                                 fprintf (stderr, "unmarking 0x%08x of size %u\n",  */
-/*                                                 (uint)p, size); */
-/*                         /\* slide *\/ */
-/*                         if (DEBUG_MARK_COMPACT) */
-/*                                 fprintf (stderr, "sliding 0x%08x down %u\n", */
-/*                                                 (uint)front, gap); */
-/*                         copy (front, front - gap, size); */
-/*                         front += size; */
-/*                         goto updateObject; */
-/*                 } else { */
-/*                         /\* It's not marked. *\/ */
-/*                         size = objectSize (s, p); */
-/*                         if (DEBUG_MARK_COMPACT) */
-/*                                 fprintf (stderr, "skipping 0x%08x of size %u\n", */
-/*                                                 (uint)p, size); */
-/*                         gap += size; */
-/*                         front += size; */
-/*                         goto updateObject; */
-/*                 } */
-/*         } else { */
-/*                 pointer new; */
+    assert (0 == (1 & header));
+    /* It's a pointer.  This object must be live.  Fix all the
+     * backward pointers to it.  Then unmark it.
+     */
+    new = p - gap;
+    newObjptr = pointerToObjptr (new, s->heap.start);
+    do {
+      pointer cur;
+      objptr curObjptr;
+      
+      threadInternalCopy ((pointer)(&curObjptr), (pointer)headerp);
+      cur = objptrToPointer (curObjptr, s->heap.start);
 
-/*                 /\* It's a pointer.  This object must be live.  Fix all the */
-/*                  * backward pointers to it.  Then unmark it. */
-/*                  *\/ */
-/*                 new = p - gap; */
-/*                 do { */
-/*                         pointer cur; */
+      threadInternalCopy ((pointer)headerp, cur);
+      *((objptr*)cur) = newObjptr;
 
-/*                         assert (0 == (3 & header)); */
-/*                         cur = (pointer)header; */
-/*                         header = *(word*)cur; */
-/*                         *(word*)cur = (word)new; */
-/*                 } while (0 == (1 & header)); */
-/*                 /\* The header will be stored by unmark. *\/ */
-/*                 goto unmark; */
-/*         } */
-/*         assert (FALSE); */
-/* done: */
-/*         s->oldGenSize = front - gap - s->heap.start; */
-/*         if (DEBUG_MARK_COMPACT) */
-/*                 fprintf (stderr, "bytesLive = %u\n", s->bytesLive); */
-/*         return; */
-/* } */
+      header = *headerp;
+    } while (0 == (1 & header));
+    /* The unmarked header will be stored by unmark. */
+    goto unmark;
+  }
+  assert (FALSE);
+done:
+  s->heap.oldGenSize = front - gap - s->heap.start;
+  if (DEBUG_MARK_COMPACT)
+    fprintf (stderr, "oldGenSize = %zu\n", s->heap.oldGenSize);
+  return;
+}
 
 static void majorMarkCompactGC (GC_state s) {
   struct rusage ru_start;
@@ -289,9 +308,9 @@
   } else {
     foreachGlobalObjptr (s, dfsMarkFalse);
   }
-/*   foreachGlobal (s, threadInternal); */
-/*   updateForwardPointers (s); */
-/*   updateBackwardPointersAndSlide (s); */
+  foreachGlobalObjptr (s, threadInternalObjptr);
+  updateForwardPointers (s);
+  updateBackwardPointersAndSlide (s);
   clearCrossMap (s);
   s->cumulativeStatistics.bytesMarkCompacted += s->heap.oldGenSize;
   s->lastMajorStatistics.kind = GC_MARK_COMPACT;