[project @ 2005-02-11 14:01:30 by simonmar]
authorsimonmar <unknown>
Fri, 11 Feb 2005 14:01:30 +0000 (14:01 +0000)
committersimonmar <unknown>
Fri, 11 Feb 2005 14:01:30 +0000 (14:01 +0000)
Careful with mutable list entries that point to THUNKs: the thunk
might be updated, and the resulting IND_OLDGEN will be on the mutable
list twice.

We previously avoided this problem by having an extra MUT_CONS object
on the mutable list pointing to the THUNK, so that we could tell the
difference between the entry on the mutable list that used to be the
THUNK, and the new entry for the IND_OLDGEN.

We don't have MUT_CONS any more (this was part of the cleanup from
separating the mutable list from the heap).  So, now, when scavenging
an IND_OLDGEN on the mutable list, we check whether it is pointing to
an already-evacuated object.  This is a bit crude, but at least it is
a localised hack.

ghc/rts/GC.c

index 8830582..a470f32 100644 (file)
@@ -1415,8 +1415,6 @@ mark_root(StgClosure **root)
 STATIC_INLINE void 
 upd_evacuee(StgClosure *p, StgClosure *dest)
 {
-    // Source object must be in from-space:
-    ASSERT((Bdescr((P_)p)->flags & BF_EVACUATED) == 0);
     // not true: (ToDo: perhaps it should be)
     // ASSERT(Bdescr((P_)dest)->flags & BF_EVACUATED);
     SET_INFO(p, &stg_EVACUATED_info);
@@ -1677,6 +1675,9 @@ loop:
        return q;
     }
 
+    /* Object is not already evacuated. */
+    ASSERT((bd->flags & BF_EVACUATED) == 0);
+
     stp = bd->step->to;
   }
 #ifdef DEBUG
@@ -3452,11 +3453,21 @@ scavenge_one(StgPtr p)
     case IND_OLDGEN:
     case IND_OLDGEN_PERM:
     case IND_STATIC:
-      /* Try to pull the indirectee into this generation, so we can
-       * remove the indirection from the mutable list.  
-       */
-      ((StgInd *)p)->indirectee = evacuate(((StgInd *)p)->indirectee);
-      
+    {
+       /* Careful here: a THUNK can be on the mutable list because
+        * it contains pointers to young gen objects.  If such a thunk
+        * is updated, the IND_OLDGEN will be added to the mutable
+        * list again, and we'll scavenge it twice.  evacuate()
+        * doesn't check whether the object has already been
+        * evacuated, so we perform that check here.
+        */
+       StgClosure *q = ((StgInd *)p)->indirectee;
+       if (HEAP_ALLOCED(q) && Bdescr((StgPtr)q)->flags & BF_EVACUATED) {
+           break;
+       }
+       ((StgInd *)p)->indirectee = evacuate(q);
+    }
+
 #if 0 && defined(DEBUG)
       if (RtsFlags.DebugFlags.gc) 
       /* Debugging code to print out the size of the thing we just