[project @ 2005-03-10 14:03:28 by simonmar]
[ghc-hetmet.git] / ghc / rts / GC.c
index 735b051..1f67fd4 100644 (file)
@@ -26,6 +26,7 @@
 #include "ParTicky.h"          // ToDo: move into Rts.h
 #include "GCCompact.h"
 #include "Signals.h"
+#include "STM.h"
 #if defined(GRAN) || defined(PAR)
 # include "GranSimRts.h"
 # include "ParallelRts.h"
@@ -147,7 +148,6 @@ static void         mark_root               ( StgClosure **root );
 REGPARM1 static StgClosure * evacuate (StgClosure *q);
 
 static void         zero_static_object_list ( StgClosure* first_static );
-static void         zero_mutable_list       ( StgMutClosure *first );
 
 static rtsBool      traverse_weak_ptr_list  ( void );
 static void         mark_weak_ptr_list      ( StgWeak **list );
@@ -162,7 +162,6 @@ static rtsBool scavenge_one            ( StgPtr p );
 static void    scavenge_large          ( step * );
 static void    scavenge_static         ( void );
 static void    scavenge_mutable_list   ( generation *g );
-static void    scavenge_mut_once_list  ( generation *g );
 
 static void    scavenge_large_bitmap   ( StgPtr p, 
                                         StgLargeBitmap *large_bitmap, 
@@ -264,7 +263,7 @@ gc_alloc_block(step *stp)
    (and all younger generations):
 
      - follow all pointers in the root set.  the root set includes all 
-       mutable objects in all generations (mutable_list and mut_once_list).
+       mutable objects in all generations (mutable_list).
 
      - for each pointer, evacuate the object it points to into either
 
@@ -276,7 +275,7 @@ gc_alloc_block(step *stp)
          When we evacuate an object we attempt to evacuate
          everything it points to into the same generation - this is
          achieved by setting evac_gen to the desired generation.  If
-         we can't do this, then an entry in the mut_once list has to
+         we can't do this, then an entry in the mut list has to
          be made for the cross-generation pointer.
 
        + if the object is already in a generation > N, then leave
@@ -314,6 +313,9 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
   blockUserSignals();
 #endif
 
+  // tell the STM to discard any cached closures its hoping to re-use
+  stmPreGCHook();
+
   // tell the stats department that we've started a GC 
   stat_startGC();
 
@@ -365,13 +367,6 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
   static_objects = END_OF_STATIC_LIST;
   scavenged_static_objects = END_OF_STATIC_LIST;
 
-  /* zero the mutable list for the oldest generation (see comment by
-   * zero_mutable_list below).
-   */
-  if (major_gc) { 
-    zero_mutable_list(generations[RtsFlags.GcFlags.generations-1].mut_once_list);
-  }
-
   /* Save the old to-space if we're doing a two-space collection
    */
   if (RtsFlags.GcFlags.generations == 1) {
@@ -389,8 +384,14 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
   // collecting.
   //
   for (g = 0; g <= N; g++) {
-    generations[g].mut_once_list = END_MUT_LIST;
-    generations[g].mut_list = END_MUT_LIST;
+
+    // throw away the mutable list.  Invariant: the mutable list
+    // always has at least one block; this means we can avoid a check for
+    // NULL in recordMutable().
+    if (g != 0) {
+       freeChain(generations[g].mut_list);
+       generations[g].mut_list = allocBlock();
+    }
 
     for (s = 0; s < generations[g].n_steps; s++) {
 
@@ -513,23 +514,12 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
     int st;
     for (g = RtsFlags.GcFlags.generations-1; g > N; g--) {
       generations[g].saved_mut_list = generations[g].mut_list;
-      generations[g].mut_list = END_MUT_LIST;
-    }
-
-    // Do the mut-once lists first 
-    for (g = RtsFlags.GcFlags.generations-1; g > N; g--) {
-      IF_PAR_DEBUG(verbose,
-                  printMutOnceList(&generations[g]));
-      scavenge_mut_once_list(&generations[g]);
-      evac_gen = g;
-      for (st = generations[g].n_steps-1; st >= 0; st--) {
-       scavenge(&generations[g].steps[st]);
-      }
+      generations[g].mut_list = allocBlock(); 
+        // mut_list always has at least one block.
     }
 
     for (g = RtsFlags.GcFlags.generations-1; g > N; g--) {
-      IF_PAR_DEBUG(verbose,
-                  printMutableList(&generations[g]));
+      IF_PAR_DEBUG(verbose, printMutableList(&generations[g]));
       scavenge_mutable_list(&generations[g]);
       evac_gen = g;
       for (st = generations[g].n_steps-1; st >= 0; st--) {
@@ -715,6 +705,14 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
       generations[g].collections++; // for stats 
     }
 
+    // Count the mutable list as bytes "copied" for the purposes of
+    // stats.  Every mutable list is copied during every GC.
+    if (g > 0) {
+       for (bd = generations[g].mut_list; bd != NULL; bd = bd->link) {
+           copied += (bd->free - bd->start) * sizeof(StgWord);
+       }
+    }
+
     for (s = 0; s < generations[g].n_steps; s++) {
       bdescr *next;
       stp = &generations[g].steps[s];
@@ -1236,7 +1234,7 @@ traverse_weak_ptr_list(void)
          prev = &old_all_threads;
          for (t = old_all_threads; t != END_TSO_QUEUE; t = next) {
              
-             (StgClosure *)tmp = isAlive((StgClosure *)t);
+             tmp = (StgTSO *)isAlive((StgClosure *)t);
              
              if (tmp != NULL) {
                  t = tmp;
@@ -1283,7 +1281,7 @@ traverse_weak_ptr_list(void)
          StgTSO *t, *tmp, *next;
          for (t = old_all_threads; t != END_TSO_QUEUE; t = next) {
              next = t->global_link;
-             (StgClosure *)tmp = evacuate((StgClosure *)t);
+             tmp = (StgTSO *)evacuate((StgClosure *)t);
              tmp->global_link = resurrected_threads;
              resurrected_threads = tmp;
          }
@@ -1322,7 +1320,7 @@ mark_weak_ptr_list ( StgWeak **list )
       // w might be WEAK, EVACUATED, or DEAD_WEAK (actually CON_STATIC) here
       ASSERT(w->header.info == &stg_DEAD_WEAK_info 
             || get_itbl(w)->type == WEAK || get_itbl(w)->type == EVACUATED);
-      (StgClosure *)w = evacuate((StgClosure *)w);
+      w = (StgWeak *)evacuate((StgClosure *)w);
       *last_w = w;
       last_w = &(w->link);
   }
@@ -1417,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);
@@ -1584,39 +1580,6 @@ evacuate_large(StgPtr p)
 }
 
 /* -----------------------------------------------------------------------------
-   Adding a MUT_CONS to an older generation.
-
-   This is necessary from time to time when we end up with an
-   old-to-new generation pointer in a non-mutable object.  We defer
-   the promotion until the next GC.
-   -------------------------------------------------------------------------- */
-
-static StgClosure *
-mkMutCons(StgClosure *ptr, generation *gen)
-{
-  StgMutVar *q;
-  step *stp;
-
-  stp = &gen->steps[0];
-
-  /* chain a new block onto the to-space for the destination step if
-   * necessary.
-   */
-  if (stp->hp + sizeofW(StgIndOldGen) >= stp->hpLim) {
-    gc_alloc_block(stp);
-  }
-
-  q = (StgMutVar *)stp->hp;
-  stp->hp += sizeofW(StgMutVar);
-
-  SET_HDR(q,&stg_MUT_CONS_info,CCS_GC);
-  q->var = ptr;
-  recordOldToNewPtrs((StgMutClosure *)q);
-
-  return (StgClosure *)q;
-}
-
-/* -----------------------------------------------------------------------------
    Evacuate
 
    This is called (eventually) for every live object in the system.
@@ -1712,6 +1675,9 @@ loop:
        return q;
     }
 
+    /* Object is not already evacuated. */
+    ASSERT((bd->flags & BF_EVACUATED) == 0);
+
     stp = bd->step->to;
   }
 #ifdef DEBUG
@@ -1746,10 +1712,10 @@ loop:
   case FUN_1_0:
   case FUN_0_1:
   case CONSTR_1_0:
+  case THUNK_1_0:
+  case THUNK_0_1:
     return copy(q,sizeofW(StgHeader)+1,stp);
 
-  case THUNK_1_0:              // here because of MIN_UPD_SIZE 
-  case THUNK_0_1:
   case THUNK_1_1:
   case THUNK_0_2:
   case THUNK_2_0:
@@ -1881,6 +1847,9 @@ loop:
   case UPDATE_FRAME:
   case STOP_FRAME:
   case CATCH_FRAME:
+  case CATCH_STM_FRAME:
+  case CATCH_RETRY_FRAME:
+  case ATOMICALLY_FRAME:
     // shouldn't see these 
     barf("evacuate: stack frame at %p\n", q);
 
@@ -1914,6 +1883,7 @@ loop:
 
   case MUT_ARR_PTRS:
   case MUT_ARR_PTRS_FROZEN:
+  case MUT_ARR_PTRS_FROZEN0:
       // just copy the block 
       return copy(q,mut_arr_ptrs_sizeW((StgMutArrPtrs *)q),stp);
 
@@ -1989,6 +1959,18 @@ loop:
     return to;
 #endif
 
+  case TREC_HEADER: 
+    return copy(q,sizeofW(StgTRecHeader),stp);
+
+  case TVAR_WAIT_QUEUE:
+    return copy(q,sizeofW(StgTVarWaitQueue),stp);
+
+  case TVAR:
+    return copy(q,sizeofW(StgTVar),stp);
+    
+  case TREC_CHUNK:
+    return copy(q,sizeofW(StgTRecChunk),stp);
+
   default:
     barf("evacuate: strange closure type %d", (int)(info->type));
   }
@@ -2136,10 +2118,10 @@ selector_loop:
 
          // check that we don't recurse too much, re-using the
          // depth bound also used in evacuate().
-         thunk_selector_depth++;
-         if (thunk_selector_depth > MAX_THUNK_SELECTOR_DEPTH) {
+         if (thunk_selector_depth >= MAX_THUNK_SELECTOR_DEPTH) {
              break;
          }
+         thunk_selector_depth++;
 
          val = eval_thunk_selector(info->layout.selector_offset, 
                                    (StgSelector *)selectee);
@@ -2303,7 +2285,7 @@ scavenge_thunk_srt(const StgInfoTable *info)
     StgThunkInfoTable *thunk_info;
 
     thunk_info = itbl_to_thunk_itbl(info);
-    scavenge_srt((StgClosure **)thunk_info->srt, thunk_info->i.srt_bitmap);
+    scavenge_srt((StgClosure **)GET_SRT(thunk_info), thunk_info->i.srt_bitmap);
 }
 
 STATIC_INLINE void
@@ -2312,7 +2294,7 @@ scavenge_fun_srt(const StgInfoTable *info)
     StgFunInfoTable *fun_info;
 
     fun_info = itbl_to_fun_itbl(info);
-    scavenge_srt((StgClosure **)fun_info->f.srt, fun_info->i.srt_bitmap);
+    scavenge_srt((StgClosure **)GET_FUN_SRT(fun_info), fun_info->i.srt_bitmap);
 }
 
 STATIC_INLINE void
@@ -2321,7 +2303,7 @@ scavenge_ret_srt(const StgInfoTable *info)
     StgRetInfoTable *ret_info;
 
     ret_info = itbl_to_ret_itbl(info);
-    scavenge_srt((StgClosure **)ret_info->srt, ret_info->i.srt_bitmap);
+    scavenge_srt((StgClosure **)GET_SRT(ret_info), ret_info->i.srt_bitmap);
 }
 
 /* -----------------------------------------------------------------------------
@@ -2332,7 +2314,7 @@ static void
 scavengeTSO (StgTSO *tso)
 {
     // chase the link field for any TSOs on the same queue 
-    (StgClosure *)tso->link = evacuate((StgClosure *)tso->link);
+    tso->link = (StgTSO *)evacuate((StgClosure *)tso->link);
     if (   tso->why_blocked == BlockedOnMVar
        || tso->why_blocked == BlockedOnBlackHole
        || tso->why_blocked == BlockedOnException
@@ -2348,6 +2330,9 @@ scavengeTSO (StgTSO *tso)
            (StgTSO *)evacuate((StgClosure *)tso->blocked_exceptions);
     }
     
+    // scavange current transaction record
+    tso->trec = (StgTRecHeader *)evacuate((StgClosure *)tso->trec);
+    
     // scavenge this thread's stack 
     scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
 }
@@ -2371,8 +2356,8 @@ scavenge_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
        size = BITMAP_SIZE(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       size = ((StgLargeBitmap *)fun_info->f.bitmap)->size;
-       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
+       size = GET_FUN_LARGE_BITMAP(fun_info)->size;
+       scavenge_large_bitmap(p, GET_FUN_LARGE_BITMAP(fun_info), size);
        p += size;
        break;
     default:
@@ -2381,7 +2366,7 @@ scavenge_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
     small_bitmap:
        while (size > 0) {
            if ((bitmap & 1) == 0) {
-               (StgClosure *)*p = evacuate((StgClosure *)*p);
+               *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
            }
            p++;
            bitmap = bitmap >> 1;
@@ -2411,7 +2396,7 @@ scavenge_PAP (StgPAP *pap)
        bitmap = BITMAP_BITS(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
+       scavenge_large_bitmap(p, GET_FUN_LARGE_BITMAP(fun_info), size);
        p += size;
        break;
     case ARG_BCO:
@@ -2424,7 +2409,7 @@ scavenge_PAP (StgPAP *pap)
        size = pap->n_args;
        while (size > 0) {
            if ((bitmap & 1) == 0) {
-               (StgClosure *)*p = evacuate((StgClosure *)*p);
+               *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
            }
            p++;
            bitmap = bitmap >> 1;
@@ -2483,18 +2468,14 @@ scavenge(step *stp)
     switch (info->type) {
 
     case MVAR:
-       /* treat MVars specially, because we don't want to evacuate the
-        * mut_link field in the middle of the closure.
-        */
     { 
        StgMVar *mvar = ((StgMVar *)p);
        evac_gen = 0;
-       (StgClosure *)mvar->head = evacuate((StgClosure *)mvar->head);
-       (StgClosure *)mvar->tail = evacuate((StgClosure *)mvar->tail);
-       (StgClosure *)mvar->value = evacuate((StgClosure *)mvar->value);
+       mvar->head = (StgTSO *)evacuate((StgClosure *)mvar->head);
+       mvar->tail = (StgTSO *)evacuate((StgClosure *)mvar->tail);
+       mvar->value = evacuate((StgClosure *)mvar->value);
        evac_gen = saved_evac_gen;
-       recordMutable((StgMutClosure *)mvar);
-       failed_to_evac = rtsFalse; // mutable.
+       failed_to_evac = rtsTrue; // mutable.
        p += sizeofW(StgMVar);
        break;
     }
@@ -2517,7 +2498,7 @@ scavenge(step *stp)
     case THUNK_1_0:
        scavenge_thunk_srt(info);
        ((StgClosure *)p)->payload[0] = evacuate(((StgClosure *)p)->payload[0]);
-       p += sizeofW(StgHeader) + 2; // MIN_UPD_SIZE 
+       p += sizeofW(StgHeader) + 1;
        break;
        
     case FUN_1_0:
@@ -2529,7 +2510,7 @@ scavenge(step *stp)
        
     case THUNK_0_1:
        scavenge_thunk_srt(info);
-       p += sizeofW(StgHeader) + 2; // MIN_UPD_SIZE 
+       p += sizeofW(StgHeader) + 1;
        break;
        
     case FUN_0_1:
@@ -2580,7 +2561,7 @@ scavenge(step *stp)
 
        end = (P_)((StgClosure *)p)->payload + info->layout.payload.ptrs;
        for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        }
        p += info->layout.payload.nptrs;
        break;
@@ -2588,10 +2569,10 @@ scavenge(step *stp)
 
     case BCO: {
        StgBCO *bco = (StgBCO *)p;
-       (StgClosure *)bco->instrs = evacuate((StgClosure *)bco->instrs);
-       (StgClosure *)bco->literals = evacuate((StgClosure *)bco->literals);
-       (StgClosure *)bco->ptrs = evacuate((StgClosure *)bco->ptrs);
-       (StgClosure *)bco->itbls = evacuate((StgClosure *)bco->itbls);
+       bco->instrs = (StgArrWords *)evacuate((StgClosure *)bco->instrs);
+       bco->literals = (StgArrWords *)evacuate((StgClosure *)bco->literals);
+       bco->ptrs = (StgMutArrPtrs *)evacuate((StgClosure *)bco->ptrs);
+       bco->itbls = (StgArrWords *)evacuate((StgClosure *)bco->itbls);
        p += bco_sizeW(bco);
        break;
     }
@@ -2614,27 +2595,15 @@ scavenge(step *stp)
       }
        // fall through 
     case IND_OLDGEN_PERM:
-       ((StgIndOldGen *)p)->indirectee = 
-           evacuate(((StgIndOldGen *)p)->indirectee);
-       if (failed_to_evac) {
-           failed_to_evac = rtsFalse;
-           recordOldToNewPtrs((StgMutClosure *)p);
-       }
-       p += sizeofW(StgIndOldGen);
+       ((StgInd *)p)->indirectee = evacuate(((StgInd *)p)->indirectee);
+       p += sizeofW(StgInd);
        break;
 
     case MUT_VAR:
        evac_gen = 0;
        ((StgMutVar *)p)->var = evacuate(((StgMutVar *)p)->var);
        evac_gen = saved_evac_gen;
-       recordMutable((StgMutClosure *)p);
-       failed_to_evac = rtsFalse; // mutable anyhow
-       p += sizeofW(StgMutVar);
-       break;
-
-    case MUT_CONS:
-       // ignore these
-       failed_to_evac = rtsFalse; // mutable anyhow
+       failed_to_evac = rtsTrue; // mutable anyhow
        p += sizeofW(StgMutVar);
        break;
 
@@ -2648,10 +2617,9 @@ scavenge(step *stp)
     case BLACKHOLE_BQ:
     { 
        StgBlockingQueue *bh = (StgBlockingQueue *)p;
-       (StgClosure *)bh->blocking_queue = 
-           evacuate((StgClosure *)bh->blocking_queue);
-       recordMutable((StgMutClosure *)bh);
-       failed_to_evac = rtsFalse;
+       bh->blocking_queue = 
+           (StgTSO *)evacuate((StgClosure *)bh->blocking_queue);
+       failed_to_evac = rtsTrue;
        p += BLACKHOLE_sizeW();
        break;
     }
@@ -2693,27 +2661,22 @@ scavenge(step *stp)
        evac_gen = 0;           // repeatedly mutable 
        next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
        for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        }
        evac_gen = saved_evac_gen;
-       recordMutable((StgMutClosure *)q);
-       failed_to_evac = rtsFalse; // mutable anyhow.
+       failed_to_evac = rtsTrue; // mutable anyhow.
        break;
     }
 
     case MUT_ARR_PTRS_FROZEN:
+    case MUT_ARR_PTRS_FROZEN0:
        // follow everything 
     {
        StgPtr next;
 
-       // 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;
-
        next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
        for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        }
        // it's tempting to recordMutable() if failed_to_evac is
        // false, but that breaks some assumptions (eg. every
@@ -2728,8 +2691,7 @@ scavenge(step *stp)
        evac_gen = 0;
        scavengeTSO(tso);
        evac_gen = saved_evac_gen;
-       recordMutable((StgMutClosure *)tso);
-       failed_to_evac = rtsFalse; // mutable anyhow.
+       failed_to_evac = rtsTrue; // mutable anyhow.
        p += tso_sizeW(tso);
        break;
     }
@@ -2745,8 +2707,7 @@ scavenge(step *stp)
        StgRBH *rbh = (StgRBH *)p;
        (StgClosure *)rbh->blocking_queue = 
            evacuate((StgClosure *)rbh->blocking_queue);
-       recordMutable((StgMutClosure *)to);
-       failed_to_evac = rtsFalse;  // mutable anyhow.
+       failed_to_evac = rtsTrue;  // mutable anyhow.
        IF_DEBUG(gc,
                 debugBelch("@@ scavenge: RBH %p (%s) (new blocking_queue link=%p)",
                       p, info_type(p), (StgClosure *)rbh->blocking_queue));
@@ -2764,10 +2725,6 @@ scavenge(step *stp)
        // follow the link to the rest of the blocking queue 
        (StgClosure *)bf->link = 
            evacuate((StgClosure *)bf->link);
-       if (failed_to_evac) {
-           failed_to_evac = rtsFalse;
-           recordMutable((StgMutClosure *)bf);
-       }
        IF_DEBUG(gc,
                 debugBelch("@@ scavenge: %p (%s); node is now %p; exciting, isn't it",
                       bf, info_type((StgClosure *)bf), 
@@ -2788,10 +2745,6 @@ scavenge(step *stp)
        StgFetchMeBlockingQueue *fmbq = (StgFetchMeBlockingQueue *)p;
        (StgClosure *)fmbq->blocking_queue = 
            evacuate((StgClosure *)fmbq->blocking_queue);
-       if (failed_to_evac) {
-           failed_to_evac = rtsFalse;
-           recordMutable((StgMutClosure *)fmbq);
-       }
        IF_DEBUG(gc,
                 debugBelch("@@ scavenge: %p (%s) exciting, isn't it",
                       p, info_type((StgClosure *)p)));
@@ -2800,18 +2753,76 @@ scavenge(step *stp)
     }
 #endif
 
+    case TVAR_WAIT_QUEUE:
+      {
+       StgTVarWaitQueue *wq = ((StgTVarWaitQueue *) p);
+       evac_gen = 0;
+       wq->waiting_tso = (StgTSO *)evacuate((StgClosure*)wq->waiting_tso);
+       wq->next_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)wq->next_queue_entry);
+       wq->prev_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)wq->prev_queue_entry);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+       p += sizeofW(StgTVarWaitQueue);
+       break;
+      }
+
+    case TVAR:
+      {
+       StgTVar *tvar = ((StgTVar *) p);
+       evac_gen = 0;
+       tvar->current_value = evacuate((StgClosure*)tvar->current_value);
+       tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+       p += sizeofW(StgTVar);
+       break;
+      }
+
+    case TREC_HEADER:
+      {
+        StgTRecHeader *trec = ((StgTRecHeader *) p);
+        evac_gen = 0;
+       trec->enclosing_trec = (StgTRecHeader *)evacuate((StgClosure*)trec->enclosing_trec);
+       trec->current_chunk = (StgTRecChunk *)evacuate((StgClosure*)trec->current_chunk);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+       p += sizeofW(StgTRecHeader);
+        break;
+      }
+
+    case TREC_CHUNK:
+      {
+       StgWord i;
+       StgTRecChunk *tc = ((StgTRecChunk *) p);
+       TRecEntry *e = &(tc -> entries[0]);
+       evac_gen = 0;
+       tc->prev_chunk = (StgTRecChunk *)evacuate((StgClosure*)tc->prev_chunk);
+       for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
+         e->tvar = (StgTVar *)evacuate((StgClosure*)e->tvar);
+         e->expected_value = evacuate((StgClosure*)e->expected_value);
+         e->new_value = evacuate((StgClosure*)e->new_value);
+       }
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+       p += sizeofW(StgTRecChunk);
+       break;
+      }
+
     default:
        barf("scavenge: unimplemented/strange closure type %d @ %p", 
             info->type, p);
     }
 
-    /* If we didn't manage to promote all the objects pointed to by
-     * the current object, then we have to designate this object as
-     * mutable (because it contains old-to-new generation pointers).
+    /*
+     * We need to record the current object on the mutable list if
+     *  (a) It is actually mutable, or 
+     *  (b) It contains pointers to a younger generation.
+     * Case (b) arises if we didn't manage to promote everything that
+     * the current object points to into the current generation.
      */
     if (failed_to_evac) {
        failed_to_evac = rtsFalse;
-       mkMutCons((StgClosure *)q, &generations[evac_gen]);
+       recordMutableGen((StgClosure *)q, stp->gen);
     }
   }
 
@@ -2848,17 +2859,14 @@ linear_scan:
        switch (info->type) {
            
        case MVAR:
-           /* treat MVars specially, because we don't want to evacuate the
-            * mut_link field in the middle of the closure.
-            */
        {
            StgMVar *mvar = ((StgMVar *)p);
            evac_gen = 0;
-           (StgClosure *)mvar->head = evacuate((StgClosure *)mvar->head);
-           (StgClosure *)mvar->tail = evacuate((StgClosure *)mvar->tail);
-           (StgClosure *)mvar->value = evacuate((StgClosure *)mvar->value);
+           mvar->head = (StgTSO *)evacuate((StgClosure *)mvar->head);
+           mvar->tail = (StgTSO *)evacuate((StgClosure *)mvar->tail);
+           mvar->value = evacuate((StgClosure *)mvar->value);
            evac_gen = saved_evac_gen;
-           failed_to_evac = rtsFalse; // mutable.
+           failed_to_evac = rtsTrue; // mutable.
            break;
        }
 
@@ -2921,17 +2929,17 @@ linear_scan:
            
            end = (P_)((StgClosure *)p)->payload + info->layout.payload.ptrs;
            for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
-               (StgClosure *)*p = evacuate((StgClosure *)*p);
+               *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
            }
            break;
        }
 
        case BCO: {
            StgBCO *bco = (StgBCO *)p;
-           (StgClosure *)bco->instrs = evacuate((StgClosure *)bco->instrs);
-           (StgClosure *)bco->literals = evacuate((StgClosure *)bco->literals);
-           (StgClosure *)bco->ptrs = evacuate((StgClosure *)bco->ptrs);
-           (StgClosure *)bco->itbls = evacuate((StgClosure *)bco->itbls);
+           bco->instrs = (StgArrWords *)evacuate((StgClosure *)bco->instrs);
+           bco->literals = (StgArrWords *)evacuate((StgClosure *)bco->literals);
+           bco->ptrs = (StgMutArrPtrs *)evacuate((StgClosure *)bco->ptrs);
+           bco->itbls = (StgArrWords *)evacuate((StgClosure *)bco->itbls);
            break;
        }
 
@@ -2943,24 +2951,15 @@ linear_scan:
 
        case IND_OLDGEN:
        case IND_OLDGEN_PERM:
-           ((StgIndOldGen *)p)->indirectee = 
-               evacuate(((StgIndOldGen *)p)->indirectee);
-           if (failed_to_evac) {
-               recordOldToNewPtrs((StgMutClosure *)p);
-           }
-           failed_to_evac = rtsFalse;
+           ((StgInd *)p)->indirectee = 
+               evacuate(((StgInd *)p)->indirectee);
            break;
 
        case MUT_VAR:
            evac_gen = 0;
            ((StgMutVar *)p)->var = evacuate(((StgMutVar *)p)->var);
            evac_gen = saved_evac_gen;
-           failed_to_evac = rtsFalse;
-           break;
-
-       case MUT_CONS:
-           // ignore these
-           failed_to_evac = rtsFalse;
+           failed_to_evac = rtsTrue;
            break;
 
        case CAF_BLACKHOLE:
@@ -2973,9 +2972,9 @@ linear_scan:
        case BLACKHOLE_BQ:
        { 
            StgBlockingQueue *bh = (StgBlockingQueue *)p;
-           (StgClosure *)bh->blocking_queue = 
-               evacuate((StgClosure *)bh->blocking_queue);
-           failed_to_evac = rtsFalse;
+           bh->blocking_queue = 
+               (StgTSO *)evacuate((StgClosure *)bh->blocking_queue);
+           failed_to_evac = rtsTrue;
            break;
        }
 
@@ -3009,26 +3008,22 @@ linear_scan:
            evac_gen = 0;               // repeatedly mutable 
            next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
            for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-               (StgClosure *)*p = evacuate((StgClosure *)*p);
+               *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
            }
            evac_gen = saved_evac_gen;
-           failed_to_evac = rtsFalse; // mutable anyhow.
+           failed_to_evac = rtsTrue; // mutable anyhow.
            break;
        }
 
        case MUT_ARR_PTRS_FROZEN:
+       case MUT_ARR_PTRS_FROZEN0:
            // follow everything 
        {
            StgPtr next;
            
-           // 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;
-
            next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
            for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-               (StgClosure *)*p = evacuate((StgClosure *)*p);
+               *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
            }
            break;
        }
@@ -3039,7 +3034,7 @@ linear_scan:
            evac_gen = 0;
            scavengeTSO(tso);
            evac_gen = saved_evac_gen;
-           failed_to_evac = rtsFalse;
+           failed_to_evac = rtsTrue;
            break;
        }
 
@@ -3052,10 +3047,9 @@ linear_scan:
            StgInfoTable *rip = get_closure_info(p, &size, &ptrs, &nonptrs, &vhs, str);
 #endif
            StgRBH *rbh = (StgRBH *)p;
-           (StgClosure *)rbh->blocking_queue = 
-               evacuate((StgClosure *)rbh->blocking_queue);
-           recordMutable((StgMutClosure *)rbh);
-           failed_to_evac = rtsFalse;  // mutable anyhow.
+           bh->blocking_queue = 
+               (StgTSO *)evacuate((StgClosure *)bh->blocking_queue);
+           failed_to_evac = rtsTrue;  // mutable anyhow.
            IF_DEBUG(gc,
                     debugBelch("@@ scavenge: RBH %p (%s) (new blocking_queue link=%p)",
                           p, info_type(p), (StgClosure *)rbh->blocking_queue));
@@ -3071,10 +3065,6 @@ linear_scan:
            // follow the link to the rest of the blocking queue 
            (StgClosure *)bf->link = 
                evacuate((StgClosure *)bf->link);
-           if (failed_to_evac) {
-               failed_to_evac = rtsFalse;
-               recordMutable((StgMutClosure *)bf);
-           }
            IF_DEBUG(gc,
                     debugBelch("@@ scavenge: %p (%s); node is now %p; exciting, isn't it",
                           bf, info_type((StgClosure *)bf), 
@@ -3093,10 +3083,6 @@ linear_scan:
            StgFetchMeBlockingQueue *fmbq = (StgFetchMeBlockingQueue *)p;
            (StgClosure *)fmbq->blocking_queue = 
                evacuate((StgClosure *)fmbq->blocking_queue);
-           if (failed_to_evac) {
-               failed_to_evac = rtsFalse;
-               recordMutable((StgMutClosure *)fmbq);
-           }
            IF_DEBUG(gc,
                     debugBelch("@@ scavenge: %p (%s) exciting, isn't it",
                           p, info_type((StgClosure *)p)));
@@ -3104,6 +3090,57 @@ linear_scan:
        }
 #endif // PAR
 
+       case TVAR_WAIT_QUEUE:
+         {
+           StgTVarWaitQueue *wq = ((StgTVarWaitQueue *) p);
+           evac_gen = 0;
+           wq->waiting_tso = (StgTSO *)evacuate((StgClosure*)wq->waiting_tso);
+           wq->next_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)wq->next_queue_entry);
+           wq->prev_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)wq->prev_queue_entry);
+           evac_gen = saved_evac_gen;
+           failed_to_evac = rtsTrue; // mutable
+           break;
+         }
+         
+       case TVAR:
+         {
+           StgTVar *tvar = ((StgTVar *) p);
+           evac_gen = 0;
+           tvar->current_value = evacuate((StgClosure*)tvar->current_value);
+           tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
+           evac_gen = saved_evac_gen;
+           failed_to_evac = rtsTrue; // mutable
+           break;
+         }
+         
+       case TREC_CHUNK:
+         {
+           StgWord i;
+           StgTRecChunk *tc = ((StgTRecChunk *) p);
+           TRecEntry *e = &(tc -> entries[0]);
+           evac_gen = 0;
+           tc->prev_chunk = (StgTRecChunk *)evacuate((StgClosure*)tc->prev_chunk);
+           for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
+             e->tvar = (StgTVar *)evacuate((StgClosure*)e->tvar);
+             e->expected_value = evacuate((StgClosure*)e->expected_value);
+             e->new_value = evacuate((StgClosure*)e->new_value);
+           }
+           evac_gen = saved_evac_gen;
+           failed_to_evac = rtsTrue; // mutable
+           break;
+         }
+
+       case TREC_HEADER:
+         {
+           StgTRecHeader *trec = ((StgTRecHeader *) p);
+           evac_gen = 0;
+           trec->enclosing_trec = (StgTRecHeader *)evacuate((StgClosure*)trec->enclosing_trec);
+           trec->current_chunk = (StgTRecChunk *)evacuate((StgClosure*)trec->current_chunk);
+           evac_gen = saved_evac_gen;
+           failed_to_evac = rtsTrue; // mutable
+           break;
+         }
+
        default:
            barf("scavenge_mark_stack: unimplemented/strange closure type %d @ %p", 
                 info->type, p);
@@ -3111,7 +3148,7 @@ linear_scan:
 
        if (failed_to_evac) {
            failed_to_evac = rtsFalse;
-           mkMutCons((StgClosure *)q, &generations[evac_gen]);
+           recordMutableGen((StgClosure *)q, &generations[evac_gen]);
        }
        
        // mark the next bit to indicate "scavenged"
@@ -3178,6 +3215,18 @@ scavenge_one(StgPtr p)
     
     switch (info->type) {
        
+    case MVAR:
+    { 
+       StgMVar *mvar = ((StgMVar *)p);
+       evac_gen = 0;
+       mvar->head = (StgTSO *)evacuate((StgClosure *)mvar->head);
+       mvar->tail = (StgTSO *)evacuate((StgClosure *)mvar->tail);
+       mvar->value = evacuate((StgClosure *)mvar->value);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable.
+       break;
+    }
+
     case FUN:
     case FUN_1_0:                      // hardly worth specialising these guys
     case FUN_0_1:
@@ -3199,23 +3248,39 @@ scavenge_one(StgPtr p)
     case WEAK:
     case FOREIGN:
     case IND_PERM:
-    case IND_OLDGEN_PERM:
     {
        StgPtr q, end;
        
        end = (StgPtr)((StgClosure *)p)->payload + info->layout.payload.ptrs;
        for (q = (StgPtr)((StgClosure *)p)->payload; q < end; q++) {
-           (StgClosure *)*q = evacuate((StgClosure *)*q);
+           *q = (StgWord)(StgPtr)evacuate((StgClosure *)*q);
        }
        break;
     }
     
+    case MUT_VAR:
+       evac_gen = 0;
+       ((StgMutVar *)p)->var = evacuate(((StgMutVar *)p)->var);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable anyhow
+       break;
+
     case CAF_BLACKHOLE:
     case SE_CAF_BLACKHOLE:
     case SE_BLACKHOLE:
     case BLACKHOLE:
        break;
        
+    case BLACKHOLE_BQ:
+    { 
+       StgBlockingQueue *bh = (StgBlockingQueue *)p;
+       evac_gen = 0;           // repeatedly mutable 
+       bh->blocking_queue = 
+           (StgTSO *)evacuate((StgClosure *)bh->blocking_queue);
+       failed_to_evac = rtsTrue;
+       break;
+    }
+
     case THUNK_SELECTOR:
     { 
        StgSelector *s = (StgSelector *)p;
@@ -3223,6 +3288,21 @@ scavenge_one(StgPtr p)
        break;
     }
     
+    case AP_STACK:
+    {
+       StgAP_STACK *ap = (StgAP_STACK *)p;
+
+       ap->fun = evacuate(ap->fun);
+       scavenge_stack((StgPtr)ap->payload, (StgPtr)ap->payload + ap->size);
+       p = (StgPtr)ap->payload + ap->size;
+       break;
+    }
+
+    case PAP:
+    case AP:
+       p = scavenge_PAP((StgPAP *)p);
+       break;
+
     case ARR_WORDS:
        // nothing to follow 
        break;
@@ -3233,29 +3313,24 @@ scavenge_one(StgPtr p)
        StgPtr next;
       
        evac_gen = 0;           // repeatedly mutable 
-       recordMutable((StgMutClosure *)p);
        next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
        for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        }
        evac_gen = saved_evac_gen;
-       failed_to_evac = rtsFalse;
+       failed_to_evac = rtsTrue;
        break;
     }
 
     case MUT_ARR_PTRS_FROZEN:
+    case MUT_ARR_PTRS_FROZEN0:
     {
        // follow everything 
        StgPtr next;
       
-       // 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;
-
        next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
        for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        }
        break;
     }
@@ -3266,83 +3341,133 @@ scavenge_one(StgPtr p)
       
        evac_gen = 0;           // repeatedly mutable 
        scavengeTSO(tso);
-       recordMutable((StgMutClosure *)tso);
        evac_gen = saved_evac_gen;
-       failed_to_evac = rtsFalse;
+       failed_to_evac = rtsTrue;
        break;
     }
   
-    case AP_STACK:
-    {
-       StgAP_STACK *ap = (StgAP_STACK *)p;
-
-       ap->fun = evacuate(ap->fun);
-       scavenge_stack((StgPtr)ap->payload, (StgPtr)ap->payload + ap->size);
-       p = (StgPtr)ap->payload + ap->size;
+#if defined(PAR)
+    case RBH: // cf. BLACKHOLE_BQ
+    { 
+#if 0
+       nat size, ptrs, nonptrs, vhs;
+       char str[80];
+       StgInfoTable *rip = get_closure_info(p, &size, &ptrs, &nonptrs, &vhs, str);
+#endif
+       StgRBH *rbh = (StgRBH *)p;
+       (StgClosure *)rbh->blocking_queue = 
+           evacuate((StgClosure *)rbh->blocking_queue);
+       failed_to_evac = rtsTrue;  // mutable anyhow.
+       IF_DEBUG(gc,
+                debugBelch("@@ scavenge: RBH %p (%s) (new blocking_queue link=%p)",
+                      p, info_type(p), (StgClosure *)rbh->blocking_queue));
+       // ToDo: use size of reverted closure here!
        break;
     }
 
-    case PAP:
-    case AP:
-       p = scavenge_PAP((StgPAP *)p);
-       break;
-
-    case IND_OLDGEN:
-       // This might happen if for instance a MUT_CONS was pointing to a
-       // THUNK which has since been updated.  The IND_OLDGEN will
-       // be on the mutable list anyway, so we don't need to do anything
-       // here.
+    case BLOCKED_FETCH:
+    { 
+       StgBlockedFetch *bf = (StgBlockedFetch *)p;
+       // follow the pointer to the node which is being demanded 
+       (StgClosure *)bf->node = 
+           evacuate((StgClosure *)bf->node);
+       // follow the link to the rest of the blocking queue 
+       (StgClosure *)bf->link = 
+           evacuate((StgClosure *)bf->link);
+       IF_DEBUG(gc,
+                debugBelch("@@ scavenge: %p (%s); node is now %p; exciting, isn't it",
+                      bf, info_type((StgClosure *)bf), 
+                      bf->node, info_type(bf->node)));
        break;
+    }
 
-    default:
-       barf("scavenge_one: strange object %d", (int)(info->type));
-    }    
-
-    no_luck = failed_to_evac;
-    failed_to_evac = rtsFalse;
-    return (no_luck);
-}
-
-/* -----------------------------------------------------------------------------
-   Scavenging mutable lists.
+#ifdef DIST
+    case REMOTE_REF:
+#endif
+    case FETCH_ME:
+       break; // nothing to do in this case
 
-   We treat the mutable list of each generation > N (i.e. all the
-   generations older than the one being collected) as roots.  We also
-   remove non-mutable objects from the mutable list at this point.
-   -------------------------------------------------------------------------- */
+    case FETCH_ME_BQ: // cf. BLACKHOLE_BQ
+    { 
+       StgFetchMeBlockingQueue *fmbq = (StgFetchMeBlockingQueue *)p;
+       (StgClosure *)fmbq->blocking_queue = 
+           evacuate((StgClosure *)fmbq->blocking_queue);
+       IF_DEBUG(gc,
+                debugBelch("@@ scavenge: %p (%s) exciting, isn't it",
+                      p, info_type((StgClosure *)p)));
+       break;
+    }
+#endif
 
-static void
-scavenge_mut_once_list(generation *gen)
-{
-  const StgInfoTable *info;
-  StgMutClosure *p, *next, *new_list;
+    case TVAR_WAIT_QUEUE:
+      {
+       StgTVarWaitQueue *wq = ((StgTVarWaitQueue *) p);
+       evac_gen = 0;
+       wq->waiting_tso = (StgTSO *)evacuate((StgClosure*)wq->waiting_tso);
+       wq->next_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)wq->next_queue_entry);
+       wq->prev_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)wq->prev_queue_entry);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+       break;
+      }
 
-  p = gen->mut_once_list;
-  new_list = END_MUT_LIST;
-  next = p->mut_link;
+    case TVAR:
+      {
+       StgTVar *tvar = ((StgTVar *) p);
+       evac_gen = 0;
+       tvar->current_value = evacuate((StgClosure*)tvar->current_value);
+       tvar->first_wait_queue_entry = (StgTVarWaitQueue *)evacuate((StgClosure*)tvar->first_wait_queue_entry);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+       break;
+      }
 
-  evac_gen = gen->no;
-  failed_to_evac = rtsFalse;
+    case TREC_HEADER:
+      {
+        StgTRecHeader *trec = ((StgTRecHeader *) p);
+        evac_gen = 0;
+       trec->enclosing_trec = (StgTRecHeader *)evacuate((StgClosure*)trec->enclosing_trec);
+       trec->current_chunk = (StgTRecChunk *)evacuate((StgClosure*)trec->current_chunk);
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+        break;
+      }
 
-  for (; p != END_MUT_LIST; p = next, next = p->mut_link) {
+    case TREC_CHUNK:
+      {
+       StgWord i;
+       StgTRecChunk *tc = ((StgTRecChunk *) p);
+       TRecEntry *e = &(tc -> entries[0]);
+       evac_gen = 0;
+       tc->prev_chunk = (StgTRecChunk *)evacuate((StgClosure*)tc->prev_chunk);
+       for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
+         e->tvar = (StgTVar *)evacuate((StgClosure*)e->tvar);
+         e->expected_value = evacuate((StgClosure*)e->expected_value);
+         e->new_value = evacuate((StgClosure*)e->new_value);
+       }
+       evac_gen = saved_evac_gen;
+       failed_to_evac = rtsTrue; // mutable
+       break;
+      }
 
-    ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
-    info = get_itbl(p);
-    /*
-    if (info->type==RBH)
-      info = REVERT_INFOPTR(info); // if it's an RBH, look at the orig closure
-    */
-    switch(info->type) {
-      
     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.  
-       */
-      ((StgIndOldGen *)p)->indirectee = 
-        evacuate(((StgIndOldGen *)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
@@ -3368,237 +3493,50 @@ scavenge_mut_once_list(generation *gen)
        debugBelch("evac IND_OLDGEN: %ld bytes", size * sizeof(W_));
       }
 #endif
-
-      /* failed_to_evac might happen if we've got more than two
-       * generations, we're collecting only generation 0, the
-       * indirection resides in generation 2 and the indirectee is
-       * in generation 1.
-       */
-      if (failed_to_evac) {
-       failed_to_evac = rtsFalse;
-       p->mut_link = new_list;
-       new_list = p;
-      } else {
-       /* the mut_link field of an IND_STATIC is overloaded as the
-        * static link field too (it just so happens that we don't need
-        * both at the same time), so we need to NULL it out when
-        * removing this object from the mutable list because the static
-        * link fields are all assumed to be NULL before doing a major
-        * collection. 
-        */
-       p->mut_link = NULL;
-      }
-      continue;
-
-    case MUT_CONS:
-       /* MUT_CONS is a kind of MUT_VAR, except it that we try to remove
-        * it from the mutable list if possible by promoting whatever it
-        * points to.
-        */
-       if (scavenge_one((StgPtr)((StgMutVar *)p)->var)) {
-           /* didn't manage to promote everything, so put the
-            * MUT_CONS back on the list.
-            */
-           p->mut_link = new_list;
-           new_list = p;
-       }
-       continue;
+      break;
 
     default:
-      // shouldn't have anything else on the mutables list 
-      barf("scavenge_mut_once_list: strange object? %d", (int)(info->type));
-    }
-  }
+       barf("scavenge_one: strange object %d", (int)(info->type));
+    }    
 
-  gen->mut_once_list = new_list;
+    no_luck = failed_to_evac;
+    failed_to_evac = rtsFalse;
+    return (no_luck);
 }
 
+/* -----------------------------------------------------------------------------
+   Scavenging mutable lists.
+
+   We treat the mutable list of each generation > N (i.e. all the
+   generations older than the one being collected) as roots.  We also
+   remove non-mutable objects from the mutable list at this point.
+   -------------------------------------------------------------------------- */
 
 static void
 scavenge_mutable_list(generation *gen)
 {
-  const StgInfoTable *info;
-  StgMutClosure *p, *next;
-
-  p = gen->saved_mut_list;
-  next = p->mut_link;
-
-  evac_gen = 0;
-  failed_to_evac = rtsFalse;
-
-  for (; p != END_MUT_LIST; p = next, next = p->mut_link) {
-
-    ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
-    info = get_itbl(p);
-    /*
-    if (info->type==RBH)
-      info = REVERT_INFOPTR(info); // if it's an RBH, look at the orig closure
-    */
-    switch(info->type) {
-      
-    case MUT_ARR_PTRS:
-      // follow everything 
-      p->mut_link = gen->mut_list;
-      gen->mut_list = p;
-      {
-       StgPtr end, q;
-       
-       end = (P_)p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
-       for (q = (P_)((StgMutArrPtrs *)p)->payload; q < end; q++) {
-         (StgClosure *)*q = evacuate((StgClosure *)*q);
-       }
-       continue;
-      }
-      
-      // Happens if a MUT_ARR_PTRS in the old generation is frozen
-    case MUT_ARR_PTRS_FROZEN:
-      {
-       StgPtr end, q;
-       
-       evac_gen = gen->no;
-       end = (P_)p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
-       for (q = (P_)((StgMutArrPtrs *)p)->payload; q < end; q++) {
-         (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;
-           mkMutCons((StgClosure *)p, gen);
-       }
-       continue;
-      }
-       
-    case MUT_VAR:
-       ((StgMutVar *)p)->var = evacuate(((StgMutVar *)p)->var);
-       p->mut_link = gen->mut_list;
-       gen->mut_list = p;
-       continue;
-
-    case MVAR:
-      {
-       StgMVar *mvar = (StgMVar *)p;
-       (StgClosure *)mvar->head = evacuate((StgClosure *)mvar->head);
-       (StgClosure *)mvar->tail = evacuate((StgClosure *)mvar->tail);
-       (StgClosure *)mvar->value = evacuate((StgClosure *)mvar->value);
-       p->mut_link = gen->mut_list;
-       gen->mut_list = p;
-       continue;
-      }
-
-    case TSO:
-      { 
-       StgTSO *tso = (StgTSO *)p;
-
-       scavengeTSO(tso);
-
-       /* Don't take this TSO off the mutable list - it might still
-        * point to some younger objects (because we set evac_gen to 0
-        * above). 
-        */
-       tso->mut_link = gen->mut_list;
-       gen->mut_list = (StgMutClosure *)tso;
-       continue;
-      }
-      
-    case BLACKHOLE_BQ:
-      { 
-       StgBlockingQueue *bh = (StgBlockingQueue *)p;
-       (StgClosure *)bh->blocking_queue = 
-         evacuate((StgClosure *)bh->blocking_queue);
-       p->mut_link = gen->mut_list;
-       gen->mut_list = p;
-       continue;
-      }
-
-      /* Happens if a BLACKHOLE_BQ in the old generation is updated: 
-       */
-    case IND_OLDGEN:
-    case IND_OLDGEN_PERM:
-      /* Try to pull the indirectee into this generation, so we can
-       * remove the indirection from the mutable list.  
-       */
-      evac_gen = gen->no;
-      ((StgIndOldGen *)p)->indirectee = 
-        evacuate(((StgIndOldGen *)p)->indirectee);
-      evac_gen = 0;
-
-      if (failed_to_evac) {
-       failed_to_evac = rtsFalse;
-       p->mut_link = gen->mut_once_list;
-       gen->mut_once_list = p;
-      } else {
-       p->mut_link = NULL;
-      }
-      continue;
-
-#if defined(PAR)
-    // HWL: check whether all of these are necessary
-
-    case RBH: // cf. BLACKHOLE_BQ
-      { 
-       // nat size, ptrs, nonptrs, vhs;
-       // char str[80];
-       // StgInfoTable *rip = get_closure_info(p, &size, &ptrs, &nonptrs, &vhs, str);
-       StgRBH *rbh = (StgRBH *)p;
-       (StgClosure *)rbh->blocking_queue = 
-         evacuate((StgClosure *)rbh->blocking_queue);
-       if (failed_to_evac) {
-         failed_to_evac = rtsFalse;
-         recordMutable((StgMutClosure *)rbh);
-       }
-       // ToDo: use size of reverted closure here!
-       p += BLACKHOLE_sizeW(); 
-       break;
-      }
-
-    case BLOCKED_FETCH:
-      { 
-       StgBlockedFetch *bf = (StgBlockedFetch *)p;
-       // follow the pointer to the node which is being demanded 
-       (StgClosure *)bf->node = 
-         evacuate((StgClosure *)bf->node);
-       // follow the link to the rest of the blocking queue 
-       (StgClosure *)bf->link = 
-         evacuate((StgClosure *)bf->link);
-       if (failed_to_evac) {
-         failed_to_evac = rtsFalse;
-         recordMutable((StgMutClosure *)bf);
-       }
-       p += sizeofW(StgBlockedFetch);
-       break;
-      }
+    bdescr *bd;
+    StgPtr p, q;
 
-#ifdef DIST
-    case REMOTE_REF:
-      barf("scavenge_mutable_list: REMOTE_REF %d", (int)(info->type));
-#endif
-    case FETCH_ME:
-      p += sizeofW(StgFetchMe);
-      break; // nothing to do in this case
+    bd = gen->saved_mut_list;
 
-    case FETCH_ME_BQ: // cf. BLACKHOLE_BQ
-      { 
-       StgFetchMeBlockingQueue *fmbq = (StgFetchMeBlockingQueue *)p;
-       (StgClosure *)fmbq->blocking_queue = 
-         evacuate((StgClosure *)fmbq->blocking_queue);
-       if (failed_to_evac) {
-         failed_to_evac = rtsFalse;
-         recordMutable((StgMutClosure *)fmbq);
+    evac_gen = gen->no;
+    for (; bd != NULL; bd = bd->link) {
+       for (q = bd->start; q < bd->free; q++) {
+           p = (StgPtr)*q;
+           ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
+           if (scavenge_one(p)) {
+               /* didn't manage to promote everything, so put the
+                * object back on the list.
+                */
+               recordMutableGen((StgClosure *)p,gen);
+           }
        }
-       p += sizeofW(StgFetchMeBlockingQueue);
-       break;
-      }
-#endif
-
-    default:
-      // shouldn't have anything else on the mutables list 
-      barf("scavenge_mutable_list: strange object? %d", (int)(info->type));
     }
-  }
+
+    // free the old mut_list
+    freeChain(gen->saved_mut_list);
+    gen->saved_mut_list = NULL;
 }
 
 
@@ -3639,15 +3577,13 @@ scavenge_static(void)
        ind->indirectee = evacuate(ind->indirectee);
 
        /* might fail to evacuate it, in which case we have to pop it
-        * back on the mutable list (and take it off the
-        * scavenged_static list because the static link and mut link
-        * pointers are one and the same).
+        * back on the mutable list of the oldest generation.  We
+        * leave it *on* the scavenged_static_objects list, though,
+        * in case we visit this object again.
         */
        if (failed_to_evac) {
          failed_to_evac = rtsFalse;
-         scavenged_static_objects = IND_STATIC_LINK(p);
-         ((StgMutClosure *)ind)->mut_link = oldest_gen->mut_once_list;
-         oldest_gen->mut_once_list = (StgMutClosure *)ind;
+         recordMutableGen((StgClosure *)p,oldest_gen);
        }
        break;
       }
@@ -3667,7 +3603,7 @@ scavenge_static(void)
        next = (P_)p->payload + info->layout.payload.ptrs;
        // evacuate the pointers 
        for (q = (P_)p->payload; q < next; q++) {
-         (StgClosure *)*q = evacuate((StgClosure *)*q);
+           *q = (StgWord)(StgPtr)evacuate((StgClosure *)*q);
        }
        break;
       }
@@ -3700,7 +3636,7 @@ scavenge_large_bitmap( StgPtr p, StgLargeBitmap *large_bitmap, nat size )
     bitmap = large_bitmap->bitmap[b];
     for (i = 0; i < size; ) {
        if ((bitmap & 1) == 0) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        }
        i++;
        p++;
@@ -3718,7 +3654,7 @@ scavenge_small_bitmap (StgPtr p, nat size, StgWord bitmap)
 {
     while (size > 0) {
        if ((bitmap & 1) == 0) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        }
        p++;
        bitmap = bitmap >> 1;
@@ -3760,6 +3696,9 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
        continue;
 
       // small bitmap (< 32 entries, or 64 on a 64-bit machine) 
+    case CATCH_STM_FRAME:
+    case CATCH_RETRY_FRAME:
+    case ATOMICALLY_FRAME:
     case STOP_FRAME:
     case CATCH_FRAME:
     case RET_SMALL:
@@ -3772,7 +3711,7 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
        p = scavenge_small_bitmap(p, size, bitmap);
 
     follow_srt:
-       scavenge_srt((StgClosure **)info->srt, info->i.srt_bitmap);
+       scavenge_srt((StgClosure **)GET_SRT(info), info->i.srt_bitmap);
        continue;
 
     case RET_BCO: {
@@ -3780,7 +3719,7 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
        nat size;
 
        p++;
-       (StgClosure *)*p = evacuate((StgClosure *)*p);
+       *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
        bco = (StgBCO *)*p;
        p++;
        size = BCO_BITMAP_SIZE(bco);
@@ -3795,9 +3734,9 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
     {
        nat size;
 
-       size = info->i.layout.large_bitmap->size;
+       size = GET_LARGE_BITMAP(&info->i)->size;
        p++;
-       scavenge_large_bitmap(p, info->i.layout.large_bitmap, size);
+       scavenge_large_bitmap(p, GET_LARGE_BITMAP(&info->i), size);
        p += size;
        // and don't forget to follow the SRT 
        goto follow_srt;
@@ -3823,7 +3762,7 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
        
        // follow the ptr words
        for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
-           (StgClosure *)*p = evacuate((StgClosure *)*p);
+           *p = (StgWord)(StgPtr)evacuate((StgClosure *)*p);
            p++;
        }
        continue;
@@ -3878,7 +3817,7 @@ scavenge_large(step *stp)
 
     p = bd->start;
     if (scavenge_one(p)) {
-       mkMutCons((StgClosure *)p, stp->gen);
+       recordMutableGen((StgClosure *)p, stp->gen);
     }
   }
 }
@@ -3901,26 +3840,6 @@ zero_static_object_list(StgClosure* first_static)
   }
 }
 
-/* This function is only needed because we share the mutable link
- * field with the static link field in an IND_STATIC, so we have to
- * zero the mut_link field before doing a major GC, which needs the
- * static link field.  
- *
- * It doesn't do any harm to zero all the mutable link fields on the
- * mutable list.
- */
-
-static void
-zero_mutable_list( StgMutClosure *first )
-{
-  StgMutClosure *next, *c;
-
-  for (c = first; c != END_MUT_LIST; c = next) {
-    next = c->mut_link;
-    c->mut_link = NULL;
-  }
-}
-
 /* -----------------------------------------------------------------------------
    Reverting CAFs
    -------------------------------------------------------------------------- */
@@ -3930,14 +3849,14 @@ revertCAFs( void )
 {
     StgIndStatic *c;
 
-    for (c = (StgIndStatic *)caf_list; c != NULL; 
+    for (c = (StgIndStatic *)revertible_caf_list; c != NULL; 
         c = (StgIndStatic *)c->static_link) 
     {
        SET_INFO(c, c->saved_info);
        c->saved_info = NULL;
        // could, but not necessary: c->static_link = NULL; 
     }
-    caf_list = NULL;
+    revertible_caf_list = NULL;
 }
 
 void
@@ -3950,6 +3869,11 @@ markCAFs( evac_fn evac )
     {
        evac(&c->indirectee);
     }
+    for (c = (StgIndStatic *)revertible_caf_list; c != NULL; 
+        c = (StgIndStatic *)c->static_link) 
+    {
+       evac(&c->indirectee);
+    }
 }
 
 /* -----------------------------------------------------------------------------
@@ -4067,7 +3991,7 @@ threadLazyBlackHole(StgTSO *tso)
            
            // normal stack frames; do nothing except advance the pointer
        default:
-           (StgPtr)frame += stack_frame_sizeW(frame);
+           frame = (StgClosure *)((StgPtr)frame + stack_frame_sizeW(frame));
        }
     }
 }
@@ -4271,7 +4195,7 @@ done_traversing:
            next_gap_start = (void *)((unsigned char*)gap + sizeof(StgUpdateFrame));
 
            chunk_size = (unsigned char*)gap_end - (unsigned char*)next_gap_start;
-           (unsigned char*)sp -= chunk_size;
+           sp -= chunk_size;
            memmove(sp, next_gap_start, chunk_size);
        }
 
@@ -4301,35 +4225,19 @@ threadPaused(StgTSO *tso)
 
 #if DEBUG
 void
-printMutOnceList(generation *gen)
-{
-  StgMutClosure *p, *next;
-
-  p = gen->mut_once_list;
-  next = p->mut_link;
-
-  debugBelch("@@ Mut once list %p: ", gen->mut_once_list);
-  for (; p != END_MUT_LIST; p = next, next = p->mut_link) {
-    debugBelch("%p (%s), ", 
-           p, info_type((StgClosure *)p));
-  }
-  debugBelch("\n");
-}
-
-void
 printMutableList(generation *gen)
 {
-  StgMutClosure *p, *next;
+    bdescr *bd;
+    StgPtr p;
 
-  p = gen->mut_list;
-  next = p->mut_link;
+    debugBelch("@@ Mutable list %p: ", gen->mut_list);
 
-  debugBelch("@@ Mutable list %p: ", gen->mut_list);
-  for (; p != END_MUT_LIST; p = next, next = p->mut_link) {
-    debugBelch("%p (%s), ",
-           p, info_type((StgClosure *)p));
-  }
-  debugBelch("\n");
+    for (bd = gen->mut_list; bd != NULL; bd = bd->link) {
+       for (p = bd->start; p < bd->free; p++) {
+           debugBelch("%p (%s), ", (void *)*p, info_type((StgClosure *)*p));
+       }
+    }
+    debugBelch("\n");
 }
 
 STATIC_INLINE rtsBool
@@ -4341,6 +4249,7 @@ maybeLarge(StgClosure *closure)
      see scavenge_large */
   return (info->type == MUT_ARR_PTRS ||
          info->type == MUT_ARR_PTRS_FROZEN ||
+         info->type == MUT_ARR_PTRS_FROZEN0 ||
          info->type == TSO ||
          info->type == ARR_WORDS);
 }