refactoring
[ghc-hetmet.git] / rts / sm / Scav.c
index 080c750..1640edd 100644 (file)
@@ -31,8 +31,6 @@ static void scavenge_large_bitmap (StgPtr p,
                                   StgLargeBitmap *large_bitmap, 
                                   nat size );
 
-static void scavenge_block (bdescr *bd, StgPtr scan);
-
 
 /* Similar to scavenge_large_bitmap(), but we don't write back the
  * pointers we get back from evacuate().
@@ -136,6 +134,10 @@ scavenge_fun_srt(const StgInfoTable *info)
 static void
 scavengeTSO (StgTSO *tso)
 {
+    rtsBool saved_eager = gct->eager_promotion;
+
+    gct->eager_promotion = rtsFalse;
+
     if (   tso->why_blocked == BlockedOnMVar
        || tso->why_blocked == BlockedOnBlackHole
        || tso->why_blocked == BlockedOnException
@@ -156,6 +158,14 @@ scavengeTSO (StgTSO *tso)
     
     // scavenge this thread's stack 
     scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
+
+    if (gct->failed_to_evac) {
+        tso->flags |= TSO_DIRTY;
+    } else {
+        tso->flags &= ~TSO_DIRTY;
+    }
+
+    gct->eager_promotion = saved_eager;
 }
 
 /* -----------------------------------------------------------------------------
@@ -252,429 +262,6 @@ scavenge_AP (StgAP *ap)
 }
 
 /* -----------------------------------------------------------------------------
-   Scavenge a block from the given scan pointer up to bd->free.
-
-   evac_gen is set by the caller to be either zero (for a step in a
-   generation < N) or G where G is the generation of the step being
-   scavenged.  
-
-   We sometimes temporarily change evac_gen back to zero if we're
-   scavenging a mutable object where eager promotion isn't such a good
-   idea.  
-   -------------------------------------------------------------------------- */
-
-static void
-scavenge_block (bdescr *bd, StgPtr scan)
-{
-  StgPtr p, q;
-  StgInfoTable *info;
-  nat saved_evac_gen;
-
-  p = scan;
-  
-  debugTrace(DEBUG_gc, "scavenging block %p (gen %d, step %d) @ %p",
-            bd->start, bd->gen_no, bd->step->no, scan);
-
-  gct->evac_gen = bd->gen_no;
-  saved_evac_gen = gct->evac_gen;
-  gct->failed_to_evac = rtsFalse;
-
-  // we might be evacuating into the very object that we're
-  // scavenging, so we have to check the real bd->free pointer each
-  // time around the loop.
-  while (p < bd->free) {
-
-    ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
-    info = get_itbl((StgClosure *)p);
-    
-    ASSERT(gct->thunk_selector_depth == 0);
-
-    q = p;
-    switch (info->type) {
-
-    case MVAR_CLEAN:
-    case MVAR_DIRTY:
-    { 
-       rtsBool saved_eager_promotion = gct->eager_promotion;
-
-       StgMVar *mvar = ((StgMVar *)p);
-       gct->eager_promotion = rtsFalse;
-       evacuate((StgClosure **)&mvar->head);
-       evacuate((StgClosure **)&mvar->tail);
-       evacuate((StgClosure **)&mvar->value);
-       gct->eager_promotion = saved_eager_promotion;
-
-       if (gct->failed_to_evac) {
-           mvar->header.info = &stg_MVAR_DIRTY_info;
-       } else {
-           mvar->header.info = &stg_MVAR_CLEAN_info;
-       }
-       p += sizeofW(StgMVar);
-       break;
-    }
-
-    case FUN_2_0:
-       scavenge_fun_srt(info);
-       evacuate(&((StgClosure *)p)->payload[1]);
-       evacuate(&((StgClosure *)p)->payload[0]);
-       p += sizeofW(StgHeader) + 2;
-       break;
-
-    case THUNK_2_0:
-       scavenge_thunk_srt(info);
-       evacuate(&((StgThunk *)p)->payload[1]);
-       evacuate(&((StgThunk *)p)->payload[0]);
-       p += sizeofW(StgThunk) + 2;
-       break;
-
-    case CONSTR_2_0:
-       evacuate(&((StgClosure *)p)->payload[1]);
-       evacuate(&((StgClosure *)p)->payload[0]);
-       p += sizeofW(StgHeader) + 2;
-       break;
-       
-    case THUNK_1_0:
-       scavenge_thunk_srt(info);
-       evacuate(&((StgThunk *)p)->payload[0]);
-       p += sizeofW(StgThunk) + 1;
-       break;
-       
-    case FUN_1_0:
-       scavenge_fun_srt(info);
-    case CONSTR_1_0:
-       evacuate(&((StgClosure *)p)->payload[0]);
-       p += sizeofW(StgHeader) + 1;
-       break;
-       
-    case THUNK_0_1:
-       scavenge_thunk_srt(info);
-       p += sizeofW(StgThunk) + 1;
-       break;
-       
-    case FUN_0_1:
-       scavenge_fun_srt(info);
-    case CONSTR_0_1:
-       p += sizeofW(StgHeader) + 1;
-       break;
-       
-    case THUNK_0_2:
-       scavenge_thunk_srt(info);
-       p += sizeofW(StgThunk) + 2;
-       break;
-       
-    case FUN_0_2:
-       scavenge_fun_srt(info);
-    case CONSTR_0_2:
-       p += sizeofW(StgHeader) + 2;
-       break;
-       
-    case THUNK_1_1:
-       scavenge_thunk_srt(info);
-       evacuate(&((StgThunk *)p)->payload[0]);
-       p += sizeofW(StgThunk) + 2;
-       break;
-
-    case FUN_1_1:
-       scavenge_fun_srt(info);
-    case CONSTR_1_1:
-       evacuate(&((StgClosure *)p)->payload[0]);
-       p += sizeofW(StgHeader) + 2;
-       break;
-       
-    case FUN:
-       scavenge_fun_srt(info);
-       goto gen_obj;
-
-    case THUNK:
-    {
-       StgPtr end;
-
-       scavenge_thunk_srt(info);
-       end = (P_)((StgThunk *)p)->payload + info->layout.payload.ptrs;
-       for (p = (P_)((StgThunk *)p)->payload; p < end; p++) {
-           evacuate((StgClosure **)p);
-       }
-       p += info->layout.payload.nptrs;
-       break;
-    }
-       
-    gen_obj:
-    case CONSTR:
-    case WEAK:
-    case STABLE_NAME:
-    {
-       StgPtr end;
-
-       end = (P_)((StgClosure *)p)->payload + info->layout.payload.ptrs;
-       for (p = (P_)((StgClosure *)p)->payload; p < end; p++) {
-           evacuate((StgClosure **)p);
-       }
-       p += info->layout.payload.nptrs;
-       break;
-    }
-
-    case BCO: {
-       StgBCO *bco = (StgBCO *)p;
-       evacuate((StgClosure **)&bco->instrs);
-       evacuate((StgClosure **)&bco->literals);
-       evacuate((StgClosure **)&bco->ptrs);
-       p += bco_sizeW(bco);
-       break;
-    }
-
-    case IND_PERM:
-      if (bd->gen_no != 0) {
-#ifdef PROFILING
-        // @LDV profiling
-        // No need to call LDV_recordDead_FILL_SLOP_DYNAMIC() because an 
-        // IND_OLDGEN_PERM closure is larger than an IND_PERM closure.
-        LDV_recordDead((StgClosure *)p, sizeofW(StgInd));
-#endif        
-        // 
-        // Todo: maybe use SET_HDR() and remove LDV_RECORD_CREATE()?
-        //
-       SET_INFO(((StgClosure *)p), &stg_IND_OLDGEN_PERM_info);
-
-        // We pretend that p has just been created.
-        LDV_RECORD_CREATE((StgClosure *)p);
-      }
-       // fall through 
-    case IND_OLDGEN_PERM:
-       evacuate(&((StgInd *)p)->indirectee);
-       p += sizeofW(StgInd);
-       break;
-
-    case MUT_VAR_CLEAN:
-    case MUT_VAR_DIRTY: {
-       rtsBool saved_eager_promotion = gct->eager_promotion;
-
-       gct->eager_promotion = rtsFalse;
-       evacuate(&((StgMutVar *)p)->var);
-       gct->eager_promotion = saved_eager_promotion;
-
-       if (gct->failed_to_evac) {
-           ((StgClosure *)q)->header.info = &stg_MUT_VAR_DIRTY_info;
-       } else {
-           ((StgClosure *)q)->header.info = &stg_MUT_VAR_CLEAN_info;
-       }
-       p += sizeofW(StgMutVar);
-       break;
-    }
-
-    case CAF_BLACKHOLE:
-    case SE_CAF_BLACKHOLE:
-    case SE_BLACKHOLE:
-    case BLACKHOLE:
-       p += BLACKHOLE_sizeW();
-       break;
-
-    case THUNK_SELECTOR:
-    { 
-       StgSelector *s = (StgSelector *)p;
-       evacuate(&s->selectee);
-       p += THUNK_SELECTOR_sizeW();
-       break;
-    }
-
-    // A chunk of stack saved in a heap object
-    case AP_STACK:
-    {
-       StgAP_STACK *ap = (StgAP_STACK *)p;
-
-       evacuate(&ap->fun);
-       scavenge_stack((StgPtr)ap->payload, (StgPtr)ap->payload + ap->size);
-       p = (StgPtr)ap->payload + ap->size;
-       break;
-    }
-
-    case PAP:
-       p = scavenge_PAP((StgPAP *)p);
-       break;
-
-    case AP:
-       p = scavenge_AP((StgAP *)p);
-       break;
-
-    case ARR_WORDS:
-       // nothing to follow 
-       p += arr_words_sizeW((StgArrWords *)p);
-       break;
-
-    case MUT_ARR_PTRS_CLEAN:
-    case MUT_ARR_PTRS_DIRTY:
-       // follow everything 
-    {
-       StgPtr next;
-       rtsBool saved_eager;
-
-       // We don't eagerly promote objects pointed to by a mutable
-       // array, but if we find the array only points to objects in
-       // the same or an older generation, we mark it "clean" and
-       // avoid traversing it during minor GCs.
-       saved_eager = gct->eager_promotion;
-       gct->eager_promotion = rtsFalse;
-       next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
-       for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-           evacuate((StgClosure **)p);
-       }
-       gct->eager_promotion = saved_eager;
-
-       if (gct->failed_to_evac) {
-           ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_DIRTY_info;
-       } else {
-           ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_CLEAN_info;
-       }
-
-       gct->failed_to_evac = rtsTrue; // always put it on the mutable list.
-       break;
-    }
-
-    case MUT_ARR_PTRS_FROZEN:
-    case MUT_ARR_PTRS_FROZEN0:
-       // follow everything 
-    {
-       StgPtr next;
-
-       next = p + mut_arr_ptrs_sizeW((StgMutArrPtrs*)p);
-       for (p = (P_)((StgMutArrPtrs *)p)->payload; p < next; p++) {
-           evacuate((StgClosure **)p);
-       }
-
-       // If we're going to put this object on the mutable list, then
-       // set its info ptr to MUT_ARR_PTRS_FROZEN0 to indicate that.
-       if (gct->failed_to_evac) {
-           ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_FROZEN0_info;
-       } else {
-           ((StgClosure *)q)->header.info = &stg_MUT_ARR_PTRS_FROZEN_info;
-       }
-       break;
-    }
-
-    case TSO:
-    { 
-       StgTSO *tso = (StgTSO *)p;
-       rtsBool saved_eager = gct->eager_promotion;
-
-       gct->eager_promotion = rtsFalse;
-       scavengeTSO(tso);
-       gct->eager_promotion = saved_eager;
-
-       if (gct->failed_to_evac) {
-           tso->flags |= TSO_DIRTY;
-       } else {
-           tso->flags &= ~TSO_DIRTY;
-       }
-
-       gct->failed_to_evac = rtsTrue; // always on the mutable list
-       p += tso_sizeW(tso);
-       break;
-    }
-
-    case TVAR_WATCH_QUEUE:
-      {
-       StgTVarWatchQueue *wq = ((StgTVarWatchQueue *) p);
-       gct->evac_gen = 0;
-       evacuate((StgClosure **)&wq->closure);
-       evacuate((StgClosure **)&wq->next_queue_entry);
-       evacuate((StgClosure **)&wq->prev_queue_entry);
-       gct->evac_gen = saved_evac_gen;
-       gct->failed_to_evac = rtsTrue; // mutable
-       p += sizeofW(StgTVarWatchQueue);
-       break;
-      }
-
-    case TVAR:
-      {
-       StgTVar *tvar = ((StgTVar *) p);
-       gct->evac_gen = 0;
-       evacuate((StgClosure **)&tvar->current_value);
-       evacuate((StgClosure **)&tvar->first_watch_queue_entry);
-       gct->evac_gen = saved_evac_gen;
-       gct->failed_to_evac = rtsTrue; // mutable
-       p += sizeofW(StgTVar);
-       break;
-      }
-
-    case TREC_HEADER:
-      {
-        StgTRecHeader *trec = ((StgTRecHeader *) p);
-        gct->evac_gen = 0;
-       evacuate((StgClosure **)&trec->enclosing_trec);
-       evacuate((StgClosure **)&trec->current_chunk);
-       evacuate((StgClosure **)&trec->invariants_to_check);
-       gct->evac_gen = saved_evac_gen;
-       gct->failed_to_evac = rtsTrue; // mutable
-       p += sizeofW(StgTRecHeader);
-        break;
-      }
-
-    case TREC_CHUNK:
-      {
-       StgWord i;
-       StgTRecChunk *tc = ((StgTRecChunk *) p);
-       TRecEntry *e = &(tc -> entries[0]);
-       gct->evac_gen = 0;
-       evacuate((StgClosure **)&tc->prev_chunk);
-       for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
-         evacuate((StgClosure **)&e->tvar);
-         evacuate((StgClosure **)&e->expected_value);
-         evacuate((StgClosure **)&e->new_value);
-       }
-       gct->evac_gen = saved_evac_gen;
-       gct->failed_to_evac = rtsTrue; // mutable
-       p += sizeofW(StgTRecChunk);
-       break;
-      }
-
-    case ATOMIC_INVARIANT:
-      {
-        StgAtomicInvariant *invariant = ((StgAtomicInvariant *) p);
-        gct->evac_gen = 0;
-       evacuate(&invariant->code);
-       evacuate((StgClosure **)&invariant->last_execution);
-       gct->evac_gen = saved_evac_gen;
-       gct->failed_to_evac = rtsTrue; // mutable
-       p += sizeofW(StgAtomicInvariant);
-        break;
-      }
-
-    case INVARIANT_CHECK_QUEUE:
-      {
-        StgInvariantCheckQueue *queue = ((StgInvariantCheckQueue *) p);
-        gct->evac_gen = 0;
-       evacuate((StgClosure **)&queue->invariant);
-       evacuate((StgClosure **)&queue->my_execution);
-       evacuate((StgClosure **)&queue->next_queue_entry);
-       gct->evac_gen = saved_evac_gen;
-       gct->failed_to_evac = rtsTrue; // mutable
-       p += sizeofW(StgInvariantCheckQueue);
-        break;
-      }
-
-    default:
-       barf("scavenge: unimplemented/strange closure type %d @ %p", 
-            info->type, p);
-    }
-
-    /*
-     * 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 (gct->failed_to_evac) {
-       gct->failed_to_evac = rtsFalse;
-       if (bd->gen_no > 0) {
-           recordMutableGen_GC((StgClosure *)q, &generations[bd->gen_no]);
-       }
-    }
-  }
-
-  debugTrace(DEBUG_gc, "   scavenged %ld bytes", (bd->free - scan) * sizeof(W_));
-}    
-
-/* -----------------------------------------------------------------------------
    Scavenge everything on the mark stack.
 
    This is slightly different from scavenge():
@@ -687,10 +274,10 @@ scavenge_mark_stack(void)
 {
     StgPtr p, q;
     StgInfoTable *info;
-    nat saved_evac_gen;
+    step *saved_evac_step;
 
-    gct->evac_gen = oldest_gen->no;
-    saved_evac_gen = gct->evac_gen;
+    gct->evac_step = &oldest_gen->steps[0];
+    saved_evac_step = gct->evac_step;
 
 linear_scan:
     while (!mark_stack_empty()) {
@@ -700,7 +287,7 @@ linear_scan:
        info = get_itbl((StgClosure *)p);
        
        q = p;
-       switch (info->type) {
+        switch (((volatile StgWord *)info)[1] & 0xffff) {
            
         case MVAR_CLEAN:
         case MVAR_DIRTY:
@@ -919,19 +506,7 @@ linear_scan:
 
        case TSO:
        { 
-           StgTSO *tso = (StgTSO *)p;
-           rtsBool saved_eager = gct->eager_promotion;
-
-           gct->eager_promotion = rtsFalse;
-           scavengeTSO(tso);
-           gct->eager_promotion = saved_eager;
-           
-           if (gct->failed_to_evac) {
-               tso->flags |= TSO_DIRTY;
-           } else {
-               tso->flags &= ~TSO_DIRTY;
-           }
-           
+            scavengeTSO((StgTSO*)p);
            gct->failed_to_evac = rtsTrue; // always on the mutable list
            break;
        }
@@ -939,11 +514,11 @@ linear_scan:
        case TVAR_WATCH_QUEUE:
          {
            StgTVarWatchQueue *wq = ((StgTVarWatchQueue *) p);
-           gct->evac_gen = 0;
+           gct->evac_step = 0;
             evacuate((StgClosure **)&wq->closure);
            evacuate((StgClosure **)&wq->next_queue_entry);
            evacuate((StgClosure **)&wq->prev_queue_entry);
-           gct->evac_gen = saved_evac_gen;
+           gct->evac_step = saved_evac_step;
            gct->failed_to_evac = rtsTrue; // mutable
            break;
          }
@@ -951,10 +526,10 @@ linear_scan:
        case TVAR:
          {
            StgTVar *tvar = ((StgTVar *) p);
-           gct->evac_gen = 0;
+           gct->evac_step = 0;
            evacuate((StgClosure **)&tvar->current_value);
            evacuate((StgClosure **)&tvar->first_watch_queue_entry);
-           gct->evac_gen = saved_evac_gen;
+           gct->evac_step = saved_evac_step;
            gct->failed_to_evac = rtsTrue; // mutable
            break;
          }
@@ -964,14 +539,14 @@ linear_scan:
            StgWord i;
            StgTRecChunk *tc = ((StgTRecChunk *) p);
            TRecEntry *e = &(tc -> entries[0]);
-           gct->evac_gen = 0;
+           gct->evac_step = 0;
            evacuate((StgClosure **)&tc->prev_chunk);
            for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
              evacuate((StgClosure **)&e->tvar);
              evacuate((StgClosure **)&e->expected_value);
              evacuate((StgClosure **)&e->new_value);
            }
-           gct->evac_gen = saved_evac_gen;
+           gct->evac_step = saved_evac_step;
            gct->failed_to_evac = rtsTrue; // mutable
            break;
          }
@@ -979,11 +554,11 @@ linear_scan:
        case TREC_HEADER:
          {
            StgTRecHeader *trec = ((StgTRecHeader *) p);
-           gct->evac_gen = 0;
+           gct->evac_step = 0;
            evacuate((StgClosure **)&trec->enclosing_trec);
            evacuate((StgClosure **)&trec->current_chunk);
            evacuate((StgClosure **)&trec->invariants_to_check);
-           gct->evac_gen = saved_evac_gen;
+           gct->evac_step = saved_evac_step;
            gct->failed_to_evac = rtsTrue; // mutable
            break;
          }
@@ -991,10 +566,10 @@ linear_scan:
         case ATOMIC_INVARIANT:
           {
             StgAtomicInvariant *invariant = ((StgAtomicInvariant *) p);
-            gct->evac_gen = 0;
+            gct->evac_step = 0;
            evacuate(&invariant->code);
            evacuate((StgClosure **)&invariant->last_execution);
-           gct->evac_gen = saved_evac_gen;
+           gct->evac_step = saved_evac_step;
            gct->failed_to_evac = rtsTrue; // mutable
             break;
           }
@@ -1002,11 +577,11 @@ linear_scan:
         case INVARIANT_CHECK_QUEUE:
           {
             StgInvariantCheckQueue *queue = ((StgInvariantCheckQueue *) p);
-            gct->evac_gen = 0;
+            gct->evac_step = 0;
            evacuate((StgClosure **)&queue->invariant);
            evacuate((StgClosure **)&queue->my_execution);
             evacuate((StgClosure **)&queue->next_queue_entry);
-           gct->evac_gen = saved_evac_gen;
+           gct->evac_step = saved_evac_step;
            gct->failed_to_evac = rtsTrue; // mutable
             break;
           }
@@ -1018,8 +593,8 @@ linear_scan:
 
        if (gct->failed_to_evac) {
            gct->failed_to_evac = rtsFalse;
-           if (gct->evac_gen > 0) {
-               recordMutableGen_GC((StgClosure *)q, &generations[gct->evac_gen]);
+           if (gct->evac_step) {
+               recordMutableGen_GC((StgClosure *)q, gct->evac_step->gen);
            }
        }
        
@@ -1079,7 +654,7 @@ static rtsBool
 scavenge_one(StgPtr p)
 {
     const StgInfoTable *info;
-    nat saved_evac_gen = gct->evac_gen;
+    step *saved_evac_step = gct->evac_step;
     rtsBool no_luck;
     
     ASSERT(LOOKS_LIKE_CLOSURE_PTR(p));
@@ -1251,19 +826,7 @@ scavenge_one(StgPtr p)
 
     case TSO:
     {
-       StgTSO *tso = (StgTSO *)p;
-       rtsBool saved_eager = gct->eager_promotion;
-
-       gct->eager_promotion = rtsFalse;
-       scavengeTSO(tso);
-       gct->eager_promotion = saved_eager;
-
-       if (gct->failed_to_evac) {
-           tso->flags |= TSO_DIRTY;
-       } else {
-           tso->flags &= ~TSO_DIRTY;
-       }
-
+       scavengeTSO((StgTSO*)p);
        gct->failed_to_evac = rtsTrue; // always on the mutable list
        break;
     }
@@ -1271,11 +834,11 @@ scavenge_one(StgPtr p)
     case TVAR_WATCH_QUEUE:
       {
        StgTVarWatchQueue *wq = ((StgTVarWatchQueue *) p);
-       gct->evac_gen = 0;
+       gct->evac_step = 0;
         evacuate((StgClosure **)&wq->closure);
         evacuate((StgClosure **)&wq->next_queue_entry);
         evacuate((StgClosure **)&wq->prev_queue_entry);
-       gct->evac_gen = saved_evac_gen;
+       gct->evac_step = saved_evac_step;
        gct->failed_to_evac = rtsTrue; // mutable
        break;
       }
@@ -1283,10 +846,10 @@ scavenge_one(StgPtr p)
     case TVAR:
       {
        StgTVar *tvar = ((StgTVar *) p);
-       gct->evac_gen = 0;
+       gct->evac_step = 0;
        evacuate((StgClosure **)&tvar->current_value);
         evacuate((StgClosure **)&tvar->first_watch_queue_entry);
-       gct->evac_gen = saved_evac_gen;
+       gct->evac_step = saved_evac_step;
        gct->failed_to_evac = rtsTrue; // mutable
        break;
       }
@@ -1294,11 +857,11 @@ scavenge_one(StgPtr p)
     case TREC_HEADER:
       {
         StgTRecHeader *trec = ((StgTRecHeader *) p);
-        gct->evac_gen = 0;
+        gct->evac_step = 0;
        evacuate((StgClosure **)&trec->enclosing_trec);
        evacuate((StgClosure **)&trec->current_chunk);
         evacuate((StgClosure **)&trec->invariants_to_check);
-       gct->evac_gen = saved_evac_gen;
+       gct->evac_step = saved_evac_step;
        gct->failed_to_evac = rtsTrue; // mutable
         break;
       }
@@ -1308,14 +871,14 @@ scavenge_one(StgPtr p)
        StgWord i;
        StgTRecChunk *tc = ((StgTRecChunk *) p);
        TRecEntry *e = &(tc -> entries[0]);
-       gct->evac_gen = 0;
+       gct->evac_step = 0;
        evacuate((StgClosure **)&tc->prev_chunk);
        for (i = 0; i < tc -> next_entry_idx; i ++, e++ ) {
          evacuate((StgClosure **)&e->tvar);
          evacuate((StgClosure **)&e->expected_value);
          evacuate((StgClosure **)&e->new_value);
        }
-       gct->evac_gen = saved_evac_gen;
+       gct->evac_step = saved_evac_step;
        gct->failed_to_evac = rtsTrue; // mutable
        break;
       }
@@ -1323,10 +886,10 @@ scavenge_one(StgPtr p)
     case ATOMIC_INVARIANT:
     {
       StgAtomicInvariant *invariant = ((StgAtomicInvariant *) p);
-      gct->evac_gen = 0;
+      gct->evac_step = 0;
       evacuate(&invariant->code);
       evacuate((StgClosure **)&invariant->last_execution);
-      gct->evac_gen = saved_evac_gen;
+      gct->evac_step = saved_evac_step;
       gct->failed_to_evac = rtsTrue; // mutable
       break;
     }
@@ -1334,11 +897,11 @@ scavenge_one(StgPtr p)
     case INVARIANT_CHECK_QUEUE:
     {
       StgInvariantCheckQueue *queue = ((StgInvariantCheckQueue *) p);
-      gct->evac_gen = 0;
+      gct->evac_step = 0;
       evacuate((StgClosure **)&queue->invariant);
       evacuate((StgClosure **)&queue->my_execution);
       evacuate((StgClosure **)&queue->next_queue_entry);
-      gct->evac_gen = saved_evac_gen;
+      gct->evac_step = saved_evac_step;
       gct->failed_to_evac = rtsTrue; // mutable
       break;
     }
@@ -1413,7 +976,7 @@ scavenge_mutable_list(generation *gen)
 
     bd = gen->saved_mut_list;
 
-    gct->evac_gen = gen->no;
+    gct->evac_step = &gen->steps[0];
     for (; bd != NULL; bd = bd->link) {
        for (q = bd->start; q < bd->free; q++) {
            p = (StgPtr)*q;
@@ -1477,7 +1040,7 @@ scavenge_mutable_list(generation *gen)
     }
 
     // free the old mut_list
-    freeChain(gen->saved_mut_list);
+    freeChain_sync(gen->saved_mut_list);
     gen->saved_mut_list = NULL;
 }
 
@@ -1497,7 +1060,7 @@ scavenge_static(void)
 
   /* Always evacuate straight to the oldest generation for static
    * objects */
-  gct->evac_gen = oldest_gen->no;
+  gct->evac_step = &oldest_gen->steps[0];
 
   /* keep going until we've scavenged all the objects on the linked
      list... */
@@ -1774,9 +1337,9 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
 /*-----------------------------------------------------------------------------
   scavenge the large object list.
 
-  evac_gen set by caller; similar games played with evac_gen as with
+  evac_step set by caller; similar games played with evac_step as with
   scavenge() - see comment at the top of scavenge().  Most large
-  objects are (repeatedly) mutable, so most of the time evac_gen will
+  objects are (repeatedly) mutable, so most of the time evac_step will
   be zero.
   --------------------------------------------------------------------------- */
 
@@ -1786,7 +1349,7 @@ scavenge_large (step_workspace *ws)
     bdescr *bd;
     StgPtr p;
 
-    gct->evac_gen = ws->stp->gen_no;
+    gct->evac_step = ws->stp;
 
     bd = ws->todo_large_objects;
     
@@ -1813,6 +1376,15 @@ scavenge_large (step_workspace *ws)
 }
 
 /* ----------------------------------------------------------------------------
+   Scavenge a block
+   ------------------------------------------------------------------------- */
+
+#define MINOR_GC
+#include "Scav.c-inc"
+#undef MINOR_GC
+#include "Scav.c-inc"
+
+/* ----------------------------------------------------------------------------
    Find the oldest full block to scavenge, and scavenge it.
    ------------------------------------------------------------------------- */
 
@@ -1825,8 +1397,8 @@ scavenge_find_global_work (void)
     step_workspace *ws;
 
     flag = rtsFalse;
-    for (g = RtsFlags.GcFlags.generations; --g >= 0; ) {
-       for (s = generations[g].n_steps; --s >= 0; ) {
+    for (g = RtsFlags.GcFlags.generations-1; g >= 0; g--) {
+       for (s = generations[g].n_steps-1; s >= 0; s--) {
            if (g == 0 && s == 0 && RtsFlags.GcFlags.generations > 1) { 
                continue; 
            }
@@ -1843,7 +1415,11 @@ scavenge_find_global_work (void)
                // to scavenge the whole thing and then push it on
                // our scavd list.  This saves pushing out the
                // scan_bd block, which might be partial.
-               scavenge_block(bd, bd->start);
+               if (N == 0) {
+                   scavenge_block0(bd, bd->start);
+               } else {
+                   scavenge_block(bd, bd->start);
+               }
                push_scan_block(bd, ws);
                return rtsTrue;
            }
@@ -1881,6 +1457,11 @@ scavenge_find_local_work (void)
            }
            ws = &gct->steps[g][s];
 
+            if (ws->todo_bd != NULL)
+            {
+                ws->todo_bd->free = ws->todo_free;
+            }
+
            // If we have a todo block and no scan block, start
            // scanning the todo block.
            if (ws->scan_bd == NULL && ws->todo_bd != NULL)
@@ -1893,7 +1474,11 @@ scavenge_find_local_work (void)
            // scavenge everything up to the free pointer.
            if (ws->scan != NULL && ws->scan < ws->scan_bd->free)
            {
-               scavenge_block(ws->scan_bd, ws->scan);
+               if (N == 0) {
+                   scavenge_block0(ws->scan_bd, ws->scan);
+               } else {
+                   scavenge_block(ws->scan_bd, ws->scan);
+               }
                ws->scan = ws->scan_bd->free;
                flag = rtsTrue;
            }
@@ -1976,8 +1561,8 @@ any_work (void)
     // Check for global work in any step.  We don't need to check for
     // local work, because we have already exited scavenge_loop(),
     // which means there is no local work for this thread.
-    for (g = RtsFlags.GcFlags.generations; --g >= 0; ) {
-       for (s = generations[g].n_steps; --s >= 0; ) {
+    for (g = RtsFlags.GcFlags.generations-1; g >= 0; g--) {
+       for (s = generations[g].n_steps-1; s >= 0; s--) {
            if (g == 0 && s == 0 && RtsFlags.GcFlags.generations > 1) { 
                continue; 
            }