[project @ 2003-10-22 15:00:59 by simonmar]
authorsimonmar <unknown>
Wed, 22 Oct 2003 15:01:00 +0000 (15:01 +0000)
committersimonmar <unknown>
Wed, 22 Oct 2003 15:01:00 +0000 (15:01 +0000)
Fix a nasty bug in the GC mutable list handling, which shows up when
an array is frozen and then unsafeThaw#'d.  The array could end up on
the mutable list twice.

Fixes SourceForge bug #819116.

ghc/rts/GC.c
ghc/rts/PrimOps.hc

index f127808..b90461c 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.160 2003/09/23 15:31:02 simonmar Exp $
+ * $Id: GC.c,v 1.161 2003/10/22 15:00:59 simonmar Exp $
  *
  * (c) The GHC Team 1998-2003
  *
@@ -2674,6 +2674,11 @@ scavenge(step *stp)
        // false, but that breaks some assumptions (eg. every
        // closure on the mutable list is supposed to have the MUT
        // flag set, and MUT_ARR_PTRS_FROZEN doesn't).
+
+       // Set the mut_link field to NULL, so that we will put this
+       // array back on the mutable list if it is subsequently thawed
+       // by unsafeThaw#.
+       ((StgMutArrPtrs*)p)->mut_link = NULL;
        break;
     }
 
@@ -2980,6 +2985,10 @@ linear_scan:
            for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
                (StgClosure *)*p = evacuate((StgClosure *)*p);
            }
+           // Set the mut_link field to NULL, so that we will put this
+           // array on the mutable list if it is subsequently thawed
+           // by unsafeThaw#.
+           ((StgMutArrPtrs*)p)->mut_link = NULL;
            break;
        }
 
@@ -3202,6 +3211,10 @@ scavenge_one(StgPtr p)
        for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
            (StgClosure *)*p = evacuate((StgClosure *)*p);
        }
+       // Set the mut_link field to NULL, so that we will put this
+       // array on the mutable list if it is subsequently thawed
+       // by unsafeThaw#.
+       ((StgMutArrPtrs*)p)->mut_link = NULL;
        break;
     }
 
@@ -3406,6 +3419,9 @@ scavenge_mutable_list(generation *gen)
          (StgClosure *)*q = evacuate((StgClosure *)*q);
        }
        evac_gen = 0;
+       // Set the mut_link field to NULL, so that we will put this
+       // array back on the mutable list if it is subsequently thawed
+       // by unsafeThaw#.
        p->mut_link = NULL;
        if (failed_to_evac) {
            failed_to_evac = rtsFalse;
index 45fd2cf..48f5cac 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: PrimOps.hc,v 1.114 2003/10/01 10:57:41 wolfgang Exp $
+ * $Id: PrimOps.hc,v 1.115 2003/10/22 15:01:00 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2002
  *
@@ -402,7 +402,22 @@ FN_(unsafeThawArrayzh_fast)
 {
   FB_
   SET_INFO((StgClosure *)R1.cl,&stg_MUT_ARR_PTRS_info);
-  recordMutable((StgMutClosure*)R1.cl);
+
+  // SUBTLETY TO DO WITH THE OLD GEN MUTABLE LIST
+  //
+  // A MUT_ARR_PTRS lives on the mutable list, but a MUT_ARR_PTRS_FROZEN 
+  // normally doesn't.  However, when we freeze a MUT_ARR_PTRS, we leave
+  // it on the mutable list for the GC to remove (removing something from
+  // the mutable list is not easy, because the mut_list is only singly-linked).
+  // 
+  // So, when we thaw a MUT_ARR_PTRS_FROZEN, we must cope with two cases:
+  // either it is on a mut_list, or it isn't.  We adopt the convention that
+  // the mut_link field is NULL if it isn't on a mut_list, and the GC
+  // maintains this invariant.
+  //
+  if (((StgMutArrPtrs *)R1.cl)->mut_link == NULL) {
+       recordMutable((StgMutClosure*)R1.cl);
+  }
 
   TICK_RET_UNBOXED_TUP(1);
   RET_P(R1.p);