[project @ 1999-11-25 10:33:20 by simonpj]
[ghc-hetmet.git] / ghc / rts / GC.c
index 64108c9..ca0fbd1 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.45 1999/02/26 17:46:08 simonm Exp $
+ * $Id: GC.c,v 1.67 1999/11/18 16:02:21 sewardj Exp $
  *
  * (c) The GHC Team 1998-1999
  *
@@ -19,7 +19,7 @@
 #include "GC.h"
 #include "BlockAlloc.h"
 #include "Main.h"
-#include "DebugProf.h"
+#include "ProfHeap.h"
 #include "SchedAPI.h"
 #include "Weak.h"
 #include "StablePriv.h"
@@ -106,7 +106,7 @@ static void         zero_mutable_list       ( StgMutClosure *first );
 static void         revert_dead_CAFs        ( void );
 
 static rtsBool      traverse_weak_ptr_list  ( void );
-static void         cleanup_weak_ptr_list   ( void );
+static void         cleanup_weak_ptr_list   ( StgWeak **list );
 
 static void         scavenge_stack          ( StgPtr p, StgPtr stack_end );
 static void         scavenge_large          ( step *step );
@@ -162,21 +162,8 @@ void GarbageCollect(void (*get_roots)(void))
   CCCS = CCS_GC;
 #endif
 
-  /* We might have been called from Haskell land by _ccall_GC, in
-   * which case we need to call threadPaused() because the scheduler
-   * won't have done it.
-   */
-  if (CurrentTSO) { threadPaused(CurrentTSO); }
-
-  /* Approximate how much we allocated: number of blocks in the
-   * nursery + blocks allocated via allocate() - unused nusery blocks.
-   * This leaves a little slop at the end of each block, and doesn't
-   * take into account large objects (ToDo).
-   */
-  allocated = (nursery_blocks * BLOCK_SIZE_W) + allocated_bytes();
-  for ( bd = current_nursery->link; bd != NULL; bd = bd->link ) {
-    allocated -= BLOCK_SIZE_W;
-  }
+  /* Approximate how much we allocated */
+  allocated = calcAllocated();
 
   /* Figure out which generation to collect
    */
@@ -330,12 +317,6 @@ void GarbageCollect(void (*get_roots)(void))
   evac_gen = 0;
   get_roots();
 
-  /* And don't forget to mark the TSO if we got here direct from
-   * Haskell! */
-  if (CurrentTSO) {
-    CurrentTSO = (StgTSO *)MarkRoot((StgClosure *)CurrentTSO);
-  }
-
   /* Mark the weak pointer list, and prepare to detect dead weak
    * pointers.
    */
@@ -354,22 +335,7 @@ void GarbageCollect(void (*get_roots)(void))
        * the CAF document.
        */
       extern void markHugsObjects(void);
-#if 0
-      /* ToDo: This (undefined) function should contain the scavenge
-       * loop immediately below this block of code - but I'm not sure
-       * enough of the details to do this myself.
-       */
-      scavengeEverything();
-      /* revert dead CAFs and update enteredCAFs list */
-      revert_dead_CAFs();
-#endif      
       markHugsObjects();
-#if 0
-      /* This will keep the CAFs and the attached BCOs alive 
-       * but the values will have been reverted
-       */
-      scavengeEverything();
-#endif
   }
 #endif
 
@@ -431,12 +397,15 @@ void GarbageCollect(void (*get_roots)(void))
   /* Final traversal of the weak pointer list (see comment by
    * cleanUpWeakPtrList below).
    */
-  cleanup_weak_ptr_list();
+  cleanup_weak_ptr_list(&weak_ptr_list);
 
   /* Now see which stable names are still alive.
    */
   gcStablePtrTable(major_gc);
 
+  /* revert dead CAFs and update enteredCAFs list */
+  revert_dead_CAFs();
+  
   /* Set the maximum blocks for the oldest generation, based on twice
    * the amount of live data now, adjusted to fit the maximum heap
    * size if necessary.  
@@ -665,10 +634,7 @@ void GarbageCollect(void (*get_roots)(void))
     }
   }
 
-  /* revert dead CAFs and update enteredCAFs list */
-  revert_dead_CAFs();
-  
-  /* mark the garbage collected CAFs as dead */
+ /* mark the garbage collected CAFs as dead */
 #ifdef DEBUG
   if (major_gc) { gcCAFs(); }
 #endif
@@ -680,13 +646,7 @@ void GarbageCollect(void (*get_roots)(void))
 
   /* Reset the nursery
    */
-  for (bd = g0s0->blocks; bd; bd = bd->link) {
-    bd->free = bd->start;
-    ASSERT(bd->gen == g0);
-    ASSERT(bd->step == g0s0);
-    IF_DEBUG(sanity,memset(bd->start, 0xaa, BLOCK_SIZE));
-  }
-  current_nursery = g0s0->blocks;
+  resetNurseries();
 
   /* start any pending finalizers */
   scheduleFinalizers(old_weak_ptr_list);
@@ -704,6 +664,7 @@ void GarbageCollect(void (*get_roots)(void))
 
   /* restore enclosing cost centre */
 #ifdef PROFILING
+  heapCensus();
   CCCS = prev_CCS;
 #endif
 
@@ -799,8 +760,8 @@ traverse_weak_ptr_list(void)
    * of pending finalizers later on.
    */
   if (flag == rtsFalse) {
+    cleanup_weak_ptr_list(&old_weak_ptr_list);
     for (w = old_weak_ptr_list; w; w = w->link) {
-      w->value = evacuate(w->value);
       w->finalizer = evacuate(w->finalizer);
     }
     weak_done = rtsTrue;
@@ -822,12 +783,12 @@ traverse_weak_ptr_list(void)
    -------------------------------------------------------------------------- */
 
 static void
-cleanup_weak_ptr_list ( void )
+cleanup_weak_ptr_list ( StgWeak **list )
 {
   StgWeak *w, **last_w;
 
-  last_w = &weak_ptr_list;
-  for (w = weak_ptr_list; w; w = w->link) {
+  last_w = list;
+  for (w = *list; w; w = w->link) {
 
     if (get_itbl(w)->type == EVACUATED) {
       w = (StgWeak *)((StgEvacuated *)w)->evacuee;
@@ -851,7 +812,7 @@ cleanup_weak_ptr_list ( void )
 StgClosure *
 isAlive(StgClosure *p)
 {
-  StgInfoTable *info;
+  const StgInfoTable *info;
 
   while (1) {
 
@@ -1125,7 +1086,7 @@ evacuate(StgClosure *q)
   const StgInfoTable *info;
 
 loop:
-  if (!LOOKS_LIKE_STATIC(q)) {
+  if (HEAP_ALLOCED(q)) {
     bd = Bdescr((P_)q);
     if (bd->gen->no > N) {
       /* Can't evacuate this object, because it's in a generation
@@ -1141,16 +1102,30 @@ loop:
     }
     step = bd->step->to;
   }
+#ifdef DEBUG
+  else step = NULL; /* make sure copy() will crash if HEAP_ALLOCED is wrong */
+#endif
 
   /* make sure the info pointer is into text space */
   ASSERT(q && (LOOKS_LIKE_GHC_INFO(GET_INFO(q))
               || IS_HUGS_CONSTR_INFO(GET_INFO(q))));
-
   info = get_itbl(q);
+
   switch (info -> type) {
 
   case BCO:
-    return copy(q,bco_sizeW(stgCast(StgBCO*,q)),step);
+    {
+      nat size = bco_sizeW((StgBCO*)q);
+
+      if (size >= LARGE_OBJECT_THRESHOLD/sizeof(W_)) {
+       evacuate_large((P_)q, rtsFalse);
+       to = q;
+      } else {
+       /* just copy the block */
+       to = copy(q,size,step);
+      }
+      return to;
+    }
 
   case MUT_VAR:
     ASSERT(q->header.info != &MUT_CONS_info);
@@ -1200,6 +1175,8 @@ loop:
     return copy(q,sizeW_fromITBL(info),step);
 
   case CAF_BLACKHOLE:
+  case SE_CAF_BLACKHOLE:
+  case SE_BLACKHOLE:
   case BLACKHOLE:
     return copyPart(q,BLACKHOLE_sizeW(),sizeofW(StgHeader),step);
 
@@ -1224,11 +1201,11 @@ loop:
       case CONSTR_0_2:
       case CONSTR_STATIC:
        { 
-         StgNat32 offset = info->layout.selector_offset;
+         StgWord32 offset = info->layout.selector_offset;
 
          /* check that the size is in range */
          ASSERT(offset < 
-                (StgNat32)(selectee_info->layout.payload.ptrs + 
+                (StgWord32)(selectee_info->layout.payload.ptrs + 
                            selectee_info->layout.payload.nptrs));
 
          /* perform the selection! */
@@ -1238,7 +1215,7 @@ loop:
           * with the evacuation, just update the source address with
           * a pointer to the (evacuated) constructor field.
           */
-         if (IS_USER_PTR(q)) {
+         if (HEAP_ALLOCED(q)) {
            bdescr *bd = Bdescr((P_)q);
            if (bd->evacuated) {
              if (bd->gen->no < evac_gen) {
@@ -1282,13 +1259,16 @@ loop:
        /* aargh - do recursively???? */
       case CAF_UNENTERED:
       case CAF_BLACKHOLE:
+      case SE_CAF_BLACKHOLE:
+      case SE_BLACKHOLE:
       case BLACKHOLE:
       case BLACKHOLE_BQ:
        /* not evaluated yet */
        break;
 
       default:
-       barf("evacuate: THUNK_SELECTOR: strange selectee");
+       barf("evacuate: THUNK_SELECTOR: strange selectee %d",
+            (int)(selectee_info->type));
       }
     }
     return copy(q,THUNK_SELECTOR_sizeW(),step);
@@ -1299,30 +1279,35 @@ loop:
     q = ((StgInd*)q)->indirectee;
     goto loop;
 
-    /* ToDo: optimise STATIC_LINK for known cases.
-       - FUN_STATIC       : payload[0]
-       - THUNK_STATIC     : payload[1]
-       - IND_STATIC       : payload[1]
-    */
   case THUNK_STATIC:
+    if (info->srt_len > 0 && major_gc && 
+       THUNK_STATIC_LINK((StgClosure *)q) == NULL) {
+      THUNK_STATIC_LINK((StgClosure *)q) = static_objects;
+      static_objects = (StgClosure *)q;
+    }
+    return q;
+
   case FUN_STATIC:
-    if (info->srt_len == 0) {  /* small optimisation */
-      return q;
+    if (info->srt_len > 0 && major_gc && 
+       FUN_STATIC_LINK((StgClosure *)q) == NULL) {
+      FUN_STATIC_LINK((StgClosure *)q) = static_objects;
+      static_objects = (StgClosure *)q;
     }
-    /* fall through */
-  case CONSTR_STATIC:
+    return q;
+
   case IND_STATIC:
-    /* don't want to evacuate these, but we do want to follow pointers
-     * from SRTs  - see scavenge_static.
-     */
+    if (major_gc && IND_STATIC_LINK((StgClosure *)q) == NULL) {
+      IND_STATIC_LINK((StgClosure *)q) = static_objects;
+      static_objects = (StgClosure *)q;
+    }
+    return q;
 
-    /* put the object on the static list, if necessary.
-     */
+  case CONSTR_STATIC:
     if (major_gc && STATIC_LINK(info,(StgClosure *)q) == NULL) {
       STATIC_LINK(info,(StgClosure *)q) = static_objects;
       static_objects = (StgClosure *)q;
     }
-    /* fall through */
+    return q;
 
   case CONSTR_INTLIKE:
   case CONSTR_CHARLIKE:
@@ -1438,7 +1423,7 @@ loop:
     return q;
 
   default:
-    barf("evacuate: strange closure type");
+    barf("evacuate: strange closure type %d", (int)(info->type));
   }
 
   barf("evacuate");
@@ -1488,7 +1473,7 @@ relocate_TSO(StgTSO *src, StgTSO *dest)
       break;
 
     default:
-      barf("relocate_TSO");
+      barf("relocate_TSO %d", (int)(get_itbl(su)->type));
     }
     break;
   }
@@ -1508,7 +1493,24 @@ scavenge_srt(const StgInfoTable *info)
   srt = stgCast(StgClosure **,info->srt);
   srt_end = srt + info->srt_len;
   for (; srt < srt_end; srt++) {
-    evacuate(*srt);
+    /* Special-case to handle references to closures hiding out in DLLs, since
+       double indirections required to get at those. The code generator knows
+       which is which when generating the SRT, so it stores the (indirect)
+       reference to the DLL closure in the table by first adding one to it.
+       We check for this here, and undo the addition before evacuating it.
+
+       If the SRT entry hasn't got bit 0 set, the SRT entry points to a
+       closure that's fixed at link-time, and no extra magic is required.
+    */
+#ifdef ENABLE_WIN32_DLL_SUPPORT
+    if ( stgCast(unsigned long,*srt) & 0x1 ) {
+       evacuate(*stgCast(StgClosure**,(stgCast(unsigned long, *srt) & ~0x1)));
+    } else {
+       evacuate(*srt);
+    }
+#else
+       evacuate(*srt);
+#endif
   }
 }
 
@@ -1643,10 +1645,6 @@ scavenge(step *step)
     case WEAK:
     case FOREIGN:
     case STABLE_NAME:
-    case IND_PERM:
-    case IND_OLDGEN_PERM:
-    case CAF_UNENTERED:
-    case CAF_ENTERED:
       {
        StgPtr end;
 
@@ -1658,6 +1656,52 @@ scavenge(step *step)
        break;
       }
 
+    case IND_PERM:
+      if (step->gen->no != 0) {
+       SET_INFO(((StgClosure *)p), &IND_OLDGEN_PERM_info);
+      }
+      /* 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);
+      break;
+
+    case CAF_UNENTERED:
+      {
+       StgCAF *caf = (StgCAF *)p;
+
+       caf->body = evacuate(caf->body);
+       if (failed_to_evac) {
+         failed_to_evac = rtsFalse;
+         recordOldToNewPtrs((StgMutClosure *)p);
+       } else {
+         caf->mut_link = NULL;
+       }
+        p += sizeofW(StgCAF);
+       break;
+      }
+
+    case CAF_ENTERED:
+      {
+       StgCAF *caf = (StgCAF *)p;
+
+       caf->body = evacuate(caf->body);
+       caf->value = evacuate(caf->value);
+       if (failed_to_evac) {
+         failed_to_evac = rtsFalse;
+         recordOldToNewPtrs((StgMutClosure *)p);
+       } else {
+         caf->mut_link = NULL;
+       }
+        p += sizeofW(StgCAF);
+       break;
+      }
+
     case MUT_VAR:
       /* ignore MUT_CONSs */
       if (((StgMutVar *)p)->header.info != &MUT_CONS_info) {
@@ -1669,6 +1713,8 @@ scavenge(step *step)
       break;
 
     case CAF_BLACKHOLE:
+    case SE_CAF_BLACKHOLE:
+    case SE_BLACKHOLE:
     case BLACKHOLE:
        p += BLACKHOLE_sizeW();
        break;
@@ -1779,6 +1825,10 @@ scavenge(step *step)
        evac_gen = 0;
        /* chase the link field for any TSOs on the same queue */
        (StgClosure *)tso->link = evacuate((StgClosure *)tso->link);
+       if (   tso->why_blocked == BlockedOnMVar
+           || tso->why_blocked == BlockedOnBlackHole) {
+         tso->block_info.closure = evacuate(tso->block_info.closure);
+       }
        /* scavenge this thread's stack */
        scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
        evac_gen = saved_evac_gen;
@@ -1819,7 +1869,7 @@ scavenge(step *step)
 static rtsBool
 scavenge_one(StgClosure *p)
 {
-  StgInfoTable *info;
+  const StgInfoTable *info;
   rtsBool no_luck;
 
   ASSERT(p && (LOOKS_LIKE_GHC_INFO(GET_INFO(p))
@@ -1852,7 +1902,6 @@ scavenge_one(StgClosure *p)
   case IND_PERM:
   case IND_OLDGEN_PERM:
   case CAF_UNENTERED:
-  case CAF_ENTERED:
     {
       StgPtr q, end;
       
@@ -1864,6 +1913,8 @@ scavenge_one(StgClosure *p)
     }
 
   case CAF_BLACKHOLE:
+  case SE_CAF_BLACKHOLE:
+  case SE_BLACKHOLE:
   case BLACKHOLE:
       break;
 
@@ -1916,7 +1967,7 @@ scavenge_one(StgClosure *p)
 static void
 scavenge_mut_once_list(generation *gen)
 {
-  StgInfoTable *info;
+  const StgInfoTable *info;
   StgMutClosure *p, *next, *new_list;
 
   p = gen->mut_once_list;
@@ -2005,9 +2056,38 @@ scavenge_mut_once_list(generation *gen)
       } 
       continue;
       
+    case CAF_ENTERED:
+      { 
+       StgCAF *caf = (StgCAF *)p;
+       caf->body  = evacuate(caf->body);
+       caf->value = evacuate(caf->value);
+       if (failed_to_evac) {
+         failed_to_evac = rtsFalse;
+         p->mut_link = new_list;
+         new_list = p;
+       } else {
+         p->mut_link = NULL;
+       }
+      }
+      continue;
+
+    case CAF_UNENTERED:
+      { 
+       StgCAF *caf = (StgCAF *)p;
+       caf->body  = evacuate(caf->body);
+       if (failed_to_evac) {
+         failed_to_evac = rtsFalse;
+         p->mut_link = new_list;
+         new_list = p;
+       } else {
+          p->mut_link = NULL;
+        }
+      }
+      continue;
+
     default:
       /* shouldn't have anything else on the mutables list */
-      barf("scavenge_mut_once_list: strange object?");
+      barf("scavenge_mut_once_list: strange object? %d", (int)(info->type));
     }
   }
 
@@ -2018,7 +2098,7 @@ scavenge_mut_once_list(generation *gen)
 static void
 scavenge_mutable_list(generation *gen)
 {
-  StgInfoTable *info;
+  const StgInfoTable *info;
   StgMutClosure *p, *next;
 
   p = gen->saved_mut_list;
@@ -2095,19 +2175,15 @@ scavenge_mutable_list(generation *gen)
       }
 
     case TSO:
-      /* follow ptrs and remove this from the mutable list */
       { 
        StgTSO *tso = (StgTSO *)p;
 
-       /* Don't bother scavenging if this thread is dead 
-        */
-       if (!(tso->whatNext == ThreadComplete ||
-             tso->whatNext == ThreadKilled)) {
-         /* Don't need to chase the link field for any TSOs on the
-          * same queue. Just scavenge this thread's stack 
-          */
-         scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
+       (StgClosure *)tso->link = evacuate((StgClosure *)tso->link);
+       if (   tso->why_blocked == BlockedOnMVar
+           || tso->why_blocked == BlockedOnBlackHole) {
+         tso->block_info.closure = evacuate(tso->block_info.closure);
        }
+       scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
 
        /* Don't take this TSO off the mutable list - it might still
         * point to some younger objects (because we set evac_gen to 0
@@ -2128,9 +2204,30 @@ scavenge_mutable_list(generation *gen)
        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;
+
     default:
       /* shouldn't have anything else on the mutables list */
-      barf("scavenge_mut_list: strange object?");
+      barf("scavenge_mutable_list: strange object? %d", (int)(info->type));
     }
   }
 }
@@ -2225,7 +2322,7 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
 {
   StgPtr q;
   const StgInfoTable* info;
-  StgNat32 bitmap;
+  StgWord32 bitmap;
 
   /* 
    * Each time around this loop, we are looking at a chunk of stack
@@ -2234,24 +2331,22 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
    */
 
   while (p < stack_end) {
-    q = *stgCast(StgPtr*,p);
+    q = *(P_ *)p;
 
     /* If we've got a tag, skip over that many words on the stack */
-    if (IS_ARG_TAG(stgCast(StgWord,q))) {
+    if (IS_ARG_TAG((W_)q)) {
       p += ARG_SIZE(q);
       p++; continue;
     }
      
     /* Is q a pointer to a closure?
      */
-    if (! LOOKS_LIKE_GHC_INFO(q)) {
-
+    if (! LOOKS_LIKE_GHC_INFO(q) ) {
 #ifdef DEBUG
-      if (LOOKS_LIKE_STATIC(q)) { /* Is it a static closure? */
+      if ( 0 && LOOKS_LIKE_STATIC_CLOSURE(q) ) {  /* Is it a static closure? */
        ASSERT(closure_STATIC(stgCast(StgClosure*,q)));
-      } 
-      /* otherwise, must be a pointer into the allocation space.
-       */
+      }
+      /* otherwise, must be a pointer into the allocation space. */
 #endif
 
       (StgClosure *)*p = evacuate((StgClosure *)q);
@@ -2264,14 +2359,14 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
      * record.  All activation records have 'bitmap' style layout
      * info.
      */
-    info  = get_itbl(stgCast(StgClosure*,p));
+    info  = get_itbl((StgClosure *)p);
       
     switch (info->type) {
        
       /* Dynamic bitmap: the mask is stored on the stack */
     case RET_DYN:
-      bitmap = stgCast(StgRetDyn*,p)->liveness;
-      p      = &payloadWord(stgCast(StgRetDyn*,p),0);
+      bitmap = ((StgRetDyn *)p)->liveness;
+      p      = (P_)&((StgRetDyn *)p)->payload[0];
       goto small_bitmap;
 
       /* probably a slow-entry point return address: */
@@ -2288,7 +2383,7 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
       {
        StgUpdateFrame *frame = (StgUpdateFrame *)p;
        StgClosure *to;
-       StgClosureType type = get_itbl(frame->updatee)->type;
+       nat type = get_itbl(frame->updatee)->type;
 
        p += sizeofW(StgUpdateFrame);
        if (type == EVACUATED) {
@@ -2325,6 +2420,8 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
            recordMutable((StgMutClosure *)to);
            continue;
          default:
+            /* will never be SE_{,CAF_}BLACKHOLE, since we
+               don't push an update frame for single-entry thunks.  KSW 1999-01. */
            barf("scavenge_stack: UPDATE_FRAME updatee");
          }
        }
@@ -2480,6 +2577,10 @@ scavenge_large(step *step)
        tso = (StgTSO *)p;
        /* chase the link field for any TSOs on the same queue */
        (StgClosure *)tso->link = evacuate((StgClosure *)tso->link);
+       if (   tso->why_blocked == BlockedOnMVar
+           || tso->why_blocked == BlockedOnBlackHole) {
+         tso->block_info.closure = evacuate(tso->block_info.closure);
+       }
        /* scavenge this thread's stack */
        scavenge_stack(tso->sp, &(tso->stack[tso->stack_size]));
        continue;
@@ -2539,6 +2640,7 @@ void RevertCAFs(void)
     caf->value = stgCast(StgClosure*,0xdeadbeef);
     caf->link  = stgCast(StgCAF*,0xdeadbeef);
   }
+  enteredCAFs = END_CAF_LIST;
 }
 
 void revert_dead_CAFs(void)
@@ -2546,28 +2648,19 @@ void revert_dead_CAFs(void)
     StgCAF* caf = enteredCAFs;
     enteredCAFs = END_CAF_LIST;
     while (caf != END_CAF_LIST) {
-       StgCAF* next = caf->link;
-
-       switch(GET_INFO(caf)->type) {
-       case EVACUATED:
-           {
-               /* This object has been evacuated, it must be live. */
-               StgCAF* new = stgCast(StgCAF*,stgCast(StgEvacuated*,caf)->evacuee);
-               new->link = enteredCAFs;
-               enteredCAFs = new;
-               break;
-           }
-       case CAF_ENTERED:
-           {
-               SET_INFO(caf,&CAF_UNENTERED_info);
-               caf->value = stgCast(StgClosure*,0xdeadbeef);
-               caf->link  = stgCast(StgCAF*,0xdeadbeef);
-               break;
-           }
-       default:
-               barf("revert_dead_CAFs: enteredCAFs list corrupted");
-       } 
-       caf = next;
+        StgCAF *next, *new;
+        next = caf->link;
+        new = (StgCAF*)isAlive((StgClosure*)caf);
+        if (new) {
+           new->link = enteredCAFs;
+           enteredCAFs = new;
+        } else {
+           /* ASSERT(0); */
+           SET_INFO(caf,&CAF_UNENTERED_info);
+           caf->value = (StgClosure*)0xdeadbeef;
+           caf->link  = (StgCAF*)0xdeadbeef;
+        } 
+        caf = next;
     }
 }
 
@@ -2662,6 +2755,9 @@ threadLazyBlackHole(StgTSO *tso)
 
       if (bh->header.info != &BLACKHOLE_BQ_info &&
          bh->header.info != &CAF_BLACKHOLE_info) {
+#if (!defined(LAZY_BLACKHOLING)) && defined(DEBUG)
+        fprintf(stderr,"Unexpected lazy BHing required at 0x%04x\n",(int)bh);
+#endif
        SET_INFO(bh,&BLACKHOLE_info);
       }
 
@@ -2716,7 +2812,8 @@ threadSqueezeStack(StgTSO *tso)
    */
   
   next_frame = NULL;
-  while ((P_)frame < bottom - 1) {  /* bottom - 1 is the STOP_FRAME */
+  /* bottom - sizeof(StgStopFrame) is the STOP_FRAME */
+  while ((P_)frame < bottom - sizeofW(StgStopFrame)) {  
     prev_frame = frame->link;
     frame->link = next_frame;
     next_frame = frame;
@@ -2784,7 +2881,12 @@ threadSqueezeStack(StgTSO *tso)
        * slower --SDM
        */
 #if 0 /* do it properly... */
-      if (GET_INFO(updatee_bypass) == BLACKHOLE_BQ_info) {
+#  if (!defined(LAZY_BLACKHOLING)) && defined(DEBUG)
+#    error Unimplemented lazy BH warning.  (KSW 1999-01)
+#  endif
+      if (GET_INFO(updatee_bypass) == BLACKHOLE_BQ_info
+         || GET_INFO(updatee_bypass) == CAF_BLACKHOLE_info
+         ) {
        /* Sigh.  It has one.  Don't lose those threads! */
          if (GET_INFO(updatee_keep) == BLACKHOLE_BQ_info) {
          /* Urgh.  Two queues.  Merge them. */
@@ -2809,7 +2911,11 @@ threadSqueezeStack(StgTSO *tso)
 #endif
 
       TICK_UPD_SQUEEZED();
-      UPD_IND(updatee_bypass, updatee_keep); /* this wakes the threads up */
+      /* wasn't there something about update squeezing and ticky to be
+       * sorted out?  oh yes: we aren't counting each enter properly
+       * in this case.  See the log somewhere.  KSW 1999-04-21
+       */
+      UPD_IND_NOLOCK(updatee_bypass, updatee_keep); /* this wakes the threads up */
       
       sp = (P_)frame - 1;      /* sp = stuff to slide */
       displacement += sizeofW(StgUpdateFrame);
@@ -2822,8 +2928,12 @@ threadSqueezeStack(StgTSO *tso)
        */
       if (is_update_frame) {
        StgBlockingQueue *bh = (StgBlockingQueue *)frame->updatee;
-       if (bh->header.info != &BLACKHOLE_BQ_info &&
+       if (bh->header.info != &BLACKHOLE_info &&
+           bh->header.info != &BLACKHOLE_BQ_info &&
            bh->header.info != &CAF_BLACKHOLE_info) {
+#if (!defined(LAZY_BLACKHOLING)) && defined(DEBUG)
+          fprintf(stderr,"Unexpected lazy BHing required at 0x%04x\n",(int)bh);
+#endif
          SET_INFO(bh,&BLACKHOLE_info);
        }
       }