[project @ 2002-07-10 09:28:54 by simonmar]
authorsimonmar <unknown>
Wed, 10 Jul 2002 09:28:56 +0000 (09:28 +0000)
committersimonmar <unknown>
Wed, 10 Jul 2002 09:28:56 +0000 (09:28 +0000)
Fix a GC bug.  In a "large block", only the block descriptor for the
head of the block has the fields step, gen_no and flags set.  So
whenever we want one of these fields in the descriptor for a random
object anywhere in the large block, we have to check whether it is in
the head block, and if not follow the link to the head block
descriptor.

evacuate() was doing this correctly, but isAlive() wasn't (and
goodness knows what other places are broken in this way - I identified
several other possible cases of the same bug).

So to try to make things more robust, when we allocate a large block
we now initialise the step, gen_no, and flags fields in the descriptor
for *every* sub-block, not just the first one.  Now, as long as you
only want one of these fields from the descriptor, there's no need to
try to find the block head.  evacuate() gets minutely faster, and
hopefully multiple obscure bugs are fixed by this.

ghc/rts/GC.c
ghc/rts/Schedule.c

index 208f7b7..80f7291 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.135 2002/04/23 06:34:27 sof Exp $
+ * $Id: GC.c,v 1.136 2002/07/10 09:28:54 simonmar Exp $
  *
  * (c) The GHC Team 1998-1999
  *
@@ -1286,6 +1286,7 @@ isAlive(StgClosure *p)
 
   loop:
     bd = Bdescr((P_)p);
+
     // ignore closures in generations that we're not collecting. 
     if (LOOKS_LIKE_STATIC(p) || bd->gen_no > N) {
        return p;
@@ -1596,9 +1597,6 @@ loop:
   if (HEAP_ALLOCED(q)) {
     bd = Bdescr((P_)q);
 
-    // not a group head: find the group head
-    if (bd->blocks == 0) { bd = bd->link; }
-
     if (bd->gen_no > N) {
        /* Can't evacuate this object, because it's in a generation
         * older than the ones we're collecting.  Let's hope that it's
index 530bdf9..756d476 100644 (file)
@@ -1,5 +1,5 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.146 2002/06/26 08:18:42 stolz Exp $
+ * $Id: Schedule.c,v 1.147 2002/07/10 09:28:56 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -1130,11 +1130,22 @@ schedule( void )
              }           
              cap->r.rCurrentNursery->u.back = bd;
 
-             // initialise it as a nursery block
-             bd->step = g0s0;
-             bd->gen_no = 0;
-             bd->flags = 0;
-             bd->free = bd->start;
+             // initialise it as a nursery block.  We initialise the
+             // step, gen_no, and flags field of *every* sub-block in
+             // this large block, because this is easier than making
+             // sure that we always find the block head of a large
+             // block whenever we call Bdescr() (eg. evacuate() and
+             // isAlive() in the GC would both have to do this, at
+             // least).
+             { 
+                 bdescr *x;
+                 for (x = bd; x < bd + blocks; x++) {
+                     x->step = g0s0;
+                     x->gen_no = 0;
+                     x->flags = 0;
+                     x->free = x->start;
+                 }
+             }
 
              // don't forget to update the block count in g0s0.
              g0s0->n_blocks += blocks;