[project @ 2004-08-13 13:04:50 by simonmar]
[ghc-hetmet.git] / ghc / rts / GC.c
index f127808..adb36cc 100644 (file)
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: GC.c,v 1.160 2003/09/23 15:31:02 simonmar Exp $
+ * $Id: GC.c,v 1.168 2004/08/13 13:09:49 simonmar Exp $
  *
  * (c) The GHC Team 1998-2003
  *
@@ -13,7 +13,8 @@
 #include "RtsUtils.h"
 #include "Apply.h"
 #include "Storage.h"
-#include "StoragePriv.h"
+#include "LdvProfile.h"
+#include "Updates.h"
 #include "Stats.h"
 #include "Schedule.h"
 #include "SchedAPI.h"          // for ReverCAFs prototype
@@ -23,7 +24,6 @@
 #include "ProfHeap.h"
 #include "SchedAPI.h"
 #include "Weak.h"
-#include "StablePriv.h"
 #include "Prelude.h"
 #include "ParTicky.h"          // ToDo: move into Rts.h
 #include "GCCompact.h"
@@ -44,7 +44,6 @@
 #endif
 
 #include "RetainerProfile.h"
-#include "LdvProfile.h"
 
 #include <string.h>
 
@@ -142,11 +141,13 @@ static void         mark_root               ( StgClosure **root );
 
 // Use a register argument for evacuate, if available.
 #if __GNUC__ >= 2
-static StgClosure * evacuate (StgClosure *q) __attribute__((regparm(1)));
+#define REGPARM1 __attribute__((regparm(1)))
 #else
-static StgClosure * evacuate (StgClosure *q);
+#define REGPARM1
 #endif
 
+REGPARM1 static StgClosure * evacuate (StgClosure *q);
+
 static void         zero_static_object_list ( StgClosure* first_static );
 static void         zero_mutable_list       ( StgMutClosure *first );
 
@@ -190,31 +191,31 @@ static rtsBool mark_stack_overflowed;
 static bdescr *oldgen_scan_bd;
 static StgPtr  oldgen_scan;
 
-static inline rtsBool
+STATIC_INLINE rtsBool
 mark_stack_empty(void)
 {
     return mark_sp == mark_stack;
 }
 
-static inline rtsBool
+STATIC_INLINE rtsBool
 mark_stack_full(void)
 {
     return mark_sp >= mark_splim;
 }
 
-static inline void
+STATIC_INLINE void
 reset_mark_stack(void)
 {
     mark_sp = mark_stack;
 }
 
-static inline void
+STATIC_INLINE void
 push_mark_stack(StgPtr p)
 {
     *mark_sp++ = p;
 }
 
-static inline StgPtr
+STATIC_INLINE StgPtr
 pop_mark_stack(void)
 {
     return *--mark_sp;
@@ -445,11 +446,18 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
              // don't forget to fill it with zeros!
              memset(bitmap, 0, bitmap_size);
              
-             // for each block in this step, point to its bitmap from the
+             // For each block in this step, point to its bitmap from the
              // block descriptor.
              for (bd=stp->blocks; bd != NULL; bd = bd->link) {
                  bd->u.bitmap = bitmap;
                  bitmap += BLOCK_SIZE_W / (sizeof(W_)*BITS_PER_BYTE);
+
+                 // Also at this point we set the BF_COMPACTED flag
+                 // for this block.  The invariant is that
+                 // BF_COMPACTED is always unset, except during GC
+                 // when it is set on those blocks which will be
+                 // compacted.
+                 bd->flags |= BF_COMPACTED;
              }
          }
       }
@@ -576,17 +584,6 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
    */
   markStablePtrTable(mark_root);
 
-#ifdef INTERPRETER
-  { 
-      /* ToDo: To fix the caf leak, we need to make the commented out
-       * parts of this code do something sensible - as described in 
-       * the CAF document.
-       */
-      extern void markHugsObjects(void);
-      markHugsObjects();
-  }
-#endif
-
   /* -------------------------------------------------------------------------
    * Repeatedly scavenge all the areas we know about until there's no
    * more scavenging to be done.
@@ -751,7 +748,7 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
                // for a compacted step, just shift the new to-space
                // onto the front of the now-compacted existing blocks.
                for (bd = stp->to_blocks; bd != NULL; bd = bd->link) {
-                   bd->flags &= ~BF_EVACUATED; // now from-space 
+                   bd->flags &= ~BF_EVACUATED;  // now from-space 
                }
                // tack the new blocks on the end of the existing blocks
                if (stp->blocks == NULL) {
@@ -762,6 +759,11 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
                        if (next == NULL) {
                            bd->link = stp->to_blocks;
                        }
+                       // NB. this step might not be compacted next
+                       // time, so reset the BF_COMPACTED flags.
+                       // They are set before GC if we're going to
+                       // compact.  (search for BF_COMPACTED above).
+                       bd->flags &= ~BF_COMPACTED;
                    }
                }
                // add the new blocks to the block tally
@@ -771,7 +773,7 @@ GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
                stp->blocks = stp->to_blocks;
                stp->n_blocks = stp->n_to_blocks;
                for (bd = stp->blocks; bd != NULL; bd = bd->link) {
-                   bd->flags &= ~BF_EVACUATED; // now from-space 
+                   bd->flags &= ~BF_EVACUATED;  // now from-space 
                }
            }
            stp->to_blocks = NULL;
@@ -1294,6 +1296,7 @@ traverse_weak_ptr_list(void)
 
   default:
       barf("traverse_weak_ptr_list");
+      return rtsTrue;
   }
 
 }
@@ -1374,7 +1377,7 @@ isAlive(StgClosure *p)
     }
 
     // check the mark bit for compacted steps
-    if (bd->step->is_compacted && is_marked((P_)p,bd)) {
+    if ((bd->flags & BF_COMPACTED) && is_marked((P_)p,bd)) {
        return p;
     }
 
@@ -1413,19 +1416,19 @@ mark_root(StgClosure **root)
   *root = evacuate(*root);
 }
 
-static __inline__ void 
+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);
-    p->header.info = &stg_EVACUATED_info;
+    SET_INFO(p, &stg_EVACUATED_info);
     ((StgEvacuated *)p)->evacuee = dest;
 }
 
 
-static __inline__ StgClosure *
+STATIC_INLINE StgClosure *
 copy(StgClosure *src, nat size, step *stp)
 {
   P_ to, from, dest;
@@ -1531,7 +1534,7 @@ copyPart(StgClosure *src, nat size_to_reserve, nat size_to_copy, step *stp)
    -------------------------------------------------------------------------- */
 
 
-static inline void
+STATIC_INLINE void
 evacuate_large(StgPtr p)
 {
   bdescr *bd = Bdescr(p);
@@ -1657,7 +1660,7 @@ mkMutCons(StgClosure *ptr, generation *gen)
    extra reads/writes than we save.
    -------------------------------------------------------------------------- */
 
-static StgClosure *
+REGPARM1 static StgClosure *
 evacuate(StgClosure *q)
 {
   StgClosure *to;
@@ -1699,7 +1702,7 @@ loop:
     /* If the object is in a step that we're compacting, then we
      * need to use an alternative evacuate procedure.
      */
-    if (bd->step->is_compacted) {
+    if (bd->flags & BF_COMPACTED) {
        if (!is_marked((P_)q,bd)) {
            mark((P_)q,bd);
            if (mark_stack_full()) {
@@ -2010,6 +2013,22 @@ loop:
    thunk is unchanged.
    -------------------------------------------------------------------------- */
 
+static inline rtsBool
+is_to_space ( StgClosure *p )
+{
+    bdescr *bd;
+
+    bd = Bdescr((StgPtr)p);
+    if (HEAP_ALLOCED(p) &&
+       ((bd->flags & BF_EVACUATED) 
+        || ((bd->flags & BF_COMPACTED) &&
+            is_marked((P_)p,bd)))) {
+       return rtsTrue;
+    } else {
+       return rtsFalse;
+    }
+}    
+
 static StgClosure *
 eval_thunk_selector( nat field, StgSelector * p )
 {
@@ -2042,17 +2061,30 @@ selector_loop:
     // eval_thunk_selector().  There are various ways this could
     // happen:
     //
-    // - following an IND_STATIC
+    // 1. following an IND_STATIC
     //
-    // - when the old generation is compacted, the mark phase updates
-    //   from-space pointers to be to-space pointers, and we can't
-    //   reliably tell which we're following (eg. from an IND_STATIC).
+    // 2. when the old generation is compacted, the mark phase updates
+    //    from-space pointers to be to-space pointers, and we can't
+    //    reliably tell which we're following (eg. from an IND_STATIC).
     // 
-    // So we use the block-descriptor test to find out if we're in
-    // to-space.
+    // 3. compacting GC again: if we're looking at a constructor in
+    //    the compacted generation, it might point directly to objects
+    //    in to-space.  We must bale out here, otherwise doing the selection
+    //    will result in a to-space pointer being returned.
+    //
+    //  (1) is dealt with using a BF_EVACUATED test on the
+    //  selectee. (2) and (3): we can tell if we're looking at an
+    //  object in the compacted generation that might point to
+    //  to-space objects by testing that (a) it is BF_COMPACTED, (b)
+    //  the compacted generation is being collected, and (c) the
+    //  object is marked.  Only a marked object may have pointers that
+    //  point to to-space objects, because that happens when
+    //  scavenging.
+    //
+    //  The to-space test is now embodied in the in_to_space() inline
+    //  function, as it is re-used below.
     //
-    if (HEAP_ALLOCED(selectee) &&
-       Bdescr((StgPtr)selectee)->flags & BF_EVACUATED) {
+    if (is_to_space(selectee)) {
        goto bale_out;
     }
 
@@ -2070,9 +2102,21 @@ selector_loop:
          ASSERT(field <  (StgWord32)(info->layout.payload.ptrs + 
                                      info->layout.payload.nptrs));
          
-         // ToDo: shouldn't we test whether this pointer is in
-         // to-space?
-         return selectee->payload[field];
+         // Select the right field from the constructor, and check
+         // that the result isn't in to-space.  It might be in
+         // to-space if, for example, this constructor contains
+         // pointers to younger-gen objects (and is on the mut-once
+         // list).
+         //
+         { 
+             StgClosure *q;
+             q = selectee->payload[field];
+             if (is_to_space(q)) {
+                 goto bale_out;
+             } else {
+                 return q;
+             }
+         }
 
       case IND:
       case IND_PERM:
@@ -2116,15 +2160,15 @@ selector_loop:
              // For the purposes of LDV profiling, we have destroyed
              // the original selector thunk.
              SET_INFO(p, info_ptr);
-             LDV_recordDead_FILL_SLOP_DYNAMIC(selectee);
+             LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(selectee);
 #endif
              ((StgInd *)selectee)->indirectee = val;
              SET_INFO(selectee,&stg_IND_info);
-#ifdef PROFILING
+
              // For the purposes of LDV profiling, we have created an
              // indirection.
-             LDV_recordCreate(selectee);
-#endif
+             LDV_RECORD_CREATE(selectee);
+
              selectee = val;
              goto selector_loop;
          }
@@ -2215,7 +2259,7 @@ scavenge_large_srt_bitmap( StgLargeSRT *large_srt )
  * srt field in the info table.  That's ok, because we'll
  * never dereference it.
  */
-static inline void
+STATIC_INLINE void
 scavenge_srt (StgClosure **srt, nat srt_bitmap)
 {
   nat bitmap;
@@ -2255,7 +2299,7 @@ scavenge_srt (StgClosure **srt, nat srt_bitmap)
 }
 
 
-static inline void
+STATIC_INLINE void
 scavenge_thunk_srt(const StgInfoTable *info)
 {
     StgThunkInfoTable *thunk_info;
@@ -2264,16 +2308,16 @@ scavenge_thunk_srt(const StgInfoTable *info)
     scavenge_srt((StgClosure **)thunk_info->srt, thunk_info->i.srt_bitmap);
 }
 
-static inline void
+STATIC_INLINE void
 scavenge_fun_srt(const StgInfoTable *info)
 {
     StgFunInfoTable *fun_info;
 
     fun_info = itbl_to_fun_itbl(info);
-    scavenge_srt((StgClosure **)fun_info->srt, fun_info->i.srt_bitmap);
+    scavenge_srt((StgClosure **)fun_info->f.srt, fun_info->i.srt_bitmap);
 }
 
-static inline void
+STATIC_INLINE void
 scavenge_ret_srt(const StgInfoTable *info)
 {
     StgRetInfoTable *ret_info;
@@ -2315,7 +2359,7 @@ scavengeTSO (StgTSO *tso)
    in PAPs.
    -------------------------------------------------------------------------- */
 
-static inline StgPtr
+STATIC_INLINE StgPtr
 scavenge_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
 {
     StgPtr p;
@@ -2323,19 +2367,19 @@ scavenge_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
     nat size;
 
     p = (StgPtr)args;
-    switch (fun_info->fun_type) {
+    switch (fun_info->f.fun_type) {
     case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->bitmap);
-       size = BITMAP_SIZE(fun_info->bitmap);
+       bitmap = BITMAP_BITS(fun_info->f.bitmap);
+       size = BITMAP_SIZE(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       size = ((StgLargeBitmap *)fun_info->bitmap)->size;
-       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+       size = ((StgLargeBitmap *)fun_info->f.bitmap)->size;
+       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
        p += size;
        break;
     default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
-       size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->fun_type]);
+       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
+       size = BITMAP_SIZE(stg_arg_bitmaps[fun_info->f.fun_type]);
     small_bitmap:
        while (size > 0) {
            if ((bitmap & 1) == 0) {
@@ -2350,7 +2394,7 @@ scavenge_arg_block (StgFunInfoTable *fun_info, StgClosure **args)
     return p;
 }
 
-static inline StgPtr
+STATIC_INLINE StgPtr
 scavenge_PAP (StgPAP *pap)
 {
     StgPtr p;
@@ -2364,12 +2408,12 @@ scavenge_PAP (StgPAP *pap)
     p = (StgPtr)pap->payload;
     size = pap->n_args;
 
-    switch (fun_info->fun_type) {
+    switch (fun_info->f.fun_type) {
     case ARG_GEN:
-       bitmap = BITMAP_BITS(fun_info->bitmap);
+       bitmap = BITMAP_BITS(fun_info->f.bitmap);
        goto small_bitmap;
     case ARG_GEN_BIG:
-       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->bitmap, size);
+       scavenge_large_bitmap(p, (StgLargeBitmap *)fun_info->f.bitmap, size);
        p += size;
        break;
     case ARG_BCO:
@@ -2377,7 +2421,7 @@ scavenge_PAP (StgPAP *pap)
        p += size;
        break;
     default:
-       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->fun_type]);
+       bitmap = BITMAP_BITS(stg_arg_bitmaps[fun_info->f.fun_type]);
     small_bitmap:
        size = pap->n_args;
        while (size > 0) {
@@ -2563,14 +2607,12 @@ scavenge(step *stp)
         LDV_recordDead((StgClosure *)p, sizeofW(StgInd));
 #endif        
         // 
-        // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
+        // Todo: maybe use SET_HDR() and remove LDV_RECORD_CREATE()?
         //
        SET_INFO(((StgClosure *)p), &stg_IND_OLDGEN_PERM_info);
-#ifdef PROFILING
-        // @LDV profiling
+
         // We pretend that p has just been created.
-        LDV_recordCreate((StgClosure *)p);
-#endif
+        LDV_RECORD_CREATE((StgClosure *)p);
       }
        // fall through 
     case IND_OLDGEN_PERM:
@@ -2666,6 +2708,11 @@ scavenge(step *stp)
     {
        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);
@@ -2976,6 +3023,11 @@ linear_scan:
        {
            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);
@@ -3198,6 +3250,11 @@ scavenge_one(StgPtr p)
        // 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);
@@ -3406,6 +3463,9 @@ scavenge_mutable_list(generation *gen)
          (StgClosure *)*q = evacuate((StgClosure *)*q);
        }
        evac_gen = 0;
+       // Set the mut_link field to NULL, so that we will put this
+       // array back on the mutable list if it is subsequently thawed
+       // by unsafeThaw#.
        p->mut_link = NULL;
        if (failed_to_evac) {
            failed_to_evac = rtsFalse;
@@ -3655,7 +3715,7 @@ scavenge_large_bitmap( StgPtr p, StgLargeBitmap *large_bitmap, nat size )
     }
 }
 
-static inline StgPtr
+STATIC_INLINE StgPtr
 scavenge_small_bitmap (StgPtr p, nat size, StgWord bitmap)
 {
     while (size > 0) {
@@ -3755,16 +3815,16 @@ scavenge_stack(StgPtr p, StgPtr stack_end)
        dyn = ((StgRetDyn *)p)->liveness;
 
        // traverse the bitmap first
-       bitmap = GET_LIVENESS(dyn);
+       bitmap = RET_DYN_LIVENESS(dyn);
        p      = (P_)&((StgRetDyn *)p)->payload[0];
        size   = RET_DYN_BITMAP_SIZE;
        p = scavenge_small_bitmap(p, size, bitmap);
 
        // skip over the non-ptr words
-       p += GET_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
+       p += RET_DYN_NONPTRS(dyn) + RET_DYN_NONPTR_REGS_SIZE;
        
        // follow the ptr words
-       for (size = GET_PTRS(dyn); size > 0; size--) {
+       for (size = RET_DYN_PTRS(dyn); size > 0; size--) {
            (StgClosure *)*p = evacuate((StgClosure *)*p);
            p++;
        }
@@ -3875,7 +3935,7 @@ revertCAFs( void )
     for (c = (StgIndStatic *)caf_list; c != NULL; 
         c = (StgIndStatic *)c->static_link) 
     {
-       c->header.info = c->saved_info;
+       SET_INFO(c, c->saved_info);
        c->saved_info = NULL;
        // could, but not necessary: c->static_link = NULL; 
     }
@@ -3996,11 +4056,9 @@ threadLazyBlackHole(StgTSO *tso)
                LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)bh);
 #endif
                SET_INFO(bh,&stg_BLACKHOLE_info);
-#ifdef PROFILING
-               // @LDV profiling
+
                // We pretend that bh has just been created.
-               LDV_recordCreate(bh);
-#endif
+               LDV_RECORD_CREATE(bh);
            }
            
            frame = (StgClosure *) ((StgUpdateFrame *)frame + 1);
@@ -4143,12 +4201,11 @@ threadSqueezeStack(StgTSO *tso)
                    // We pretend that bh is now dead.
                    LDV_recordDead_FILL_SLOP_DYNAMIC((StgClosure *)bh);
 #endif
-                   // Todo: maybe use SET_HDR() and remove LDV_recordCreate()?
+                   // Todo: maybe use SET_HDR() and remove LDV_RECORD_CREATE()?
                    SET_INFO(bh,&stg_BLACKHOLE_info);
-#ifdef PROFILING
+
                    // We pretend that bh has just been created.
-                   LDV_recordCreate(bh);
-#endif
+                   LDV_RECORD_CREATE(bh);
                }
 
                prev_was_update_frame = rtsTrue;
@@ -4203,20 +4260,20 @@ done_traversing:
        void *gap_start, *next_gap_start, *gap_end;
        nat chunk_size;
 
-       next_gap_start = (void *)gap + sizeof(StgUpdateFrame);
+       next_gap_start = (void *)((unsigned char*)gap + sizeof(StgUpdateFrame));
        sp = next_gap_start;
 
        while ((StgPtr)gap > tso->sp) {
 
            // we're working in *bytes* now...
            gap_start = next_gap_start;
-           gap_end = gap_start - gap->gap_size * sizeof(W_);
+           gap_end = (void*) ((unsigned char*)gap_start - gap->gap_size * sizeof(W_));
 
            gap = gap->next_gap;
-           next_gap_start = (void *)gap + sizeof(StgUpdateFrame);
+           next_gap_start = (void *)((unsigned char*)gap + sizeof(StgUpdateFrame));
 
-           chunk_size = gap_end - next_gap_start;
-           sp -= chunk_size;
+           chunk_size = (unsigned char*)gap_end - (unsigned char*)next_gap_start;
+           (unsigned char*)sp -= chunk_size;
            memmove(sp, next_gap_start, chunk_size);
        }
 
@@ -4277,7 +4334,7 @@ printMutableList(generation *gen)
   fputc('\n', stderr);
 }
 
-static inline rtsBool
+STATIC_INLINE rtsBool
 maybeLarge(StgClosure *closure)
 {
   StgInfoTable *info = get_itbl(closure);