Hi Simon,

Here's a HEAD patch for the block allocator that removes (I think ;-])
the more subtle O(N^2) portion of the allocator namely when performing
block descriptor initialisation.

I should also comment that I think there's a bug in the merge of
my original patch with HEAD where BF_ALLOCATED was switched to BF_FREE -
I think I'm correct in saying that if you do this, then the last block
descriptor in a block chunk must also have it's flags set to BF_FREE
so that predecessor coalescing may occur (in addition on allocation
these must also be cleared). I've remedied this (I hope ;-]) in the
attached patch.

Let me know your thoughts!

Cheers

Andy

On Sun, 5 Jun 2005, Andrew Cheadle wrote:

>Hi Simon,
>
>Here's a patch for the block allocator that reduces the coalescing
>algorithm from O(N^2) to N.
>
>I created the mods and tested them on my 6.2 builds and then prop'd them
>to the current 6.4 CVS HEAD. When I get a chance and HEAD is unb0rked
>I'll test them on it. Hopefully the attached patch as is fine though ;-)
>Any problems/bugs/idiocy let me know!
>
>Cheers
>
>Andy
>
>*********************************************************************
>*  Andrew Cheadle                    email:  [EMAIL PROTECTED] *
>*  Department of Computing           http://www.doc.ic.ac.uk/~amc4/ *
>*  Imperial College                                                 *
>*  University of London                                             *
>*********************************************************************

*********************************************************************
*  Andrew Cheadle                    email:  [EMAIL PROTECTED] *
*  Department of Computing           http://www.doc.ic.ac.uk/~amc4/ *
*  Imperial College                                                 *
*  University of London                                             *
*********************************************************************
diff -r -rcs --exclude=CVS ../clean/fptools/ghc/includes/Block.h 
ghc/includes/Block.h
*** ../clean/fptools/ghc/includes/Block.h       2005-06-13 13:29:48.000000000 
+0100
--- ghc/includes/Block.h        2005-06-30 10:22:48.652917328 +0100
***************
*** 87,92 ****
--- 87,94 ----
  #define BF_COMPACTED 8
  /* Block is free, and on the free list */
  #define BF_FREE      16
+ /* Block is in process of being freed, and on a temporary free list */
+ #define BF_FREEING   32
  
  /* Finding the block descriptor for a given block -------------------------- 
*/
  
***************
*** 159,164 ****
--- 161,180 ----
    *list = bd;
  }
  
+ INLINE_HEADER void
+ dbl_unlink_from(bdescr *bd, bdescr **list)
+ {
+   if (bd->u.back) {
+     bd->u.back->link = bd->link;
+   }
+   if (bd->link) {
+     bd->link->u.back = bd->u.back;
+   }
+   if (*list == bd) {
+     *list = bd->link;
+   }
+ }
+ 
  /* Initialisation ---------------------------------------------------------- 
*/
  
  extern void initBlockAllocator(void);
***************
*** 172,177 ****
--- 188,194 ----
  
  extern void freeGroup(bdescr *p);
  extern void freeChain(bdescr *p);
+ extern void prepareToFreeChain(bdescr **list_head, bdescr **list_tail, bdescr 
*p);
  
  /* Round a value to megablocks --------------------------------------------- 
*/
  
diff -r -rcs --exclude=CVS ../clean/fptools/ghc/rts/Arena.c ghc/rts/Arena.c
*** ../clean/fptools/ghc/rts/Arena.c    2005-02-23 10:59:17.000000000 +0000
--- ghc/rts/Arena.c     2005-06-28 12:04:14.000000000 +0100
***************
*** 107,114 ****
        next = bd->link;
        arena_blocks -= bd->blocks;
        ASSERT(arena_blocks >= 0);
-       freeGroup(bd);
      }
      stgFree(arena);
  }
  
--- 107,114 ----
        next = bd->link;
        arena_blocks -= bd->blocks;
        ASSERT(arena_blocks >= 0);
      }
+     freeChain(arena->current);
      stgFree(arena);
  }
  
diff -r -rcs --exclude=CVS ../clean/fptools/ghc/rts/BlockAlloc.c 
ghc/rts/BlockAlloc.c
*** ../clean/fptools/ghc/rts/BlockAlloc.c       2005-06-13 13:29:49.000000000 
+0100
--- ghc/rts/BlockAlloc.c        2005-07-02 10:41:20.411311384 +0100
***************
*** 27,32 ****
--- 27,33 ----
  static void    initMBlock(void *mblock);
  static bdescr *allocMegaGroup(nat mblocks);
  static void    freeMegaGroup(bdescr *bd);
+ static void    initTempFreeListGroup(bdescr *list);
  
  static bdescr *free_list = NULL;
  
***************
*** 36,42 ****
  
  void initBlockAllocator(void)
  {
!     // The free list starts off NULL
  }
  
  /* 
-----------------------------------------------------------------------------
--- 37,43 ----
  
  void initBlockAllocator(void)
  {
!   // The free list starts off NULL
  }
  
  /* 
-----------------------------------------------------------------------------
***************
*** 46,60 ****
  STATIC_INLINE void
  initGroupTail(nat n, bdescr *head, bdescr *tail)
  {
!     bdescr *bd;
!     nat i;
  
!     for (i=0, bd = tail; i < n; i++, bd++) {
!       bd->flags  = 0;
!       bd->free   = 0;
!       bd->blocks = 0;
!       bd->link   = head;
!     }
  }
  
  STATIC_INLINE void
--- 47,61 ----
  STATIC_INLINE void
  initGroupTail(nat n, bdescr *head, bdescr *tail)
  {
!   bdescr *bd;
!   nat i;
  
!   for (i=0, bd = tail; i < n; i++, bd++) {
!     bd->flags  = 0;
!     bd->free   = 0;
!     bd->blocks = 0;
!     bd->link   = head;
!   }
  }
  
  STATIC_INLINE void
***************
*** 65,71 ****
      head->free   = head->start;
      head->link   = NULL;
      head->flags  = 0;
!     initGroupTail( n-1, head, head+1 );
    }
  }
  
--- 66,72 ----
      head->free   = head->start;
      head->link   = NULL;
      head->flags  = 0;
!     initGroupTail(n - 1, head, head + 1);
    }
  }
  
***************
*** 93,102 ****
--- 94,106 ----
        bd->flags = 0;
        bd->free  = bd->start;
        bd->link  = NULL;
+       /* Not quite true - must clear tail block flags! */
+       ((bdescr *)(bd + bd->blocks - 1))->flags = 0;
        return bd;
      }
      if (bd->blocks >  n) {    /* block too big... */
        bd->blocks -= n;                /* take a chunk off the *end* */
+       ((bdescr *)(bd + bd->blocks - 1))->flags = BF_FREE;
        bd += bd->blocks;
        initGroup(n, bd);               /* initialise it */
        return bd;
***************
*** 206,289 ****
  /* coalesce the group p with its predecessor and successor groups, if possible
   *
   * Returns NULL if no coalescing was done, otherwise returns a
!  * pointer to the newly enlarged group p.
   */
  
  STATIC_INLINE bdescr *
! coalesce(bdescr *p)
  {
!     bdescr *first, *q, *result = NULL;
      
!     /* Get first megablock descriptor */
!     first = FIRST_BDESCR(MBLOCK_ROUND_DOWN(p->start));
      
!     /* Attempt to coalesce with predecessor if not the first block */
!     if (p != first) {
!       q = p - 1;
!       if (!q->blocks) {   // not a block head?
!           q = q->link;    // find the head.
!       }
!       /* Predecessor is free? */
!       if (q->flags & BF_FREE) {
!           q->blocks += p->blocks;
!           initGroupTail( p->blocks, q, p );
!           p = result = q;
!       }
      }
  
!     /* Attempt to coalesce with successor if not the last block */
!     q = p + p->blocks;
!     if (q != first + BLOCKS_PER_MBLOCK) {
!       /* Successor is free */
!       if (q->flags & BF_FREE) {
!           if (result) {
!               /* p is on free_list, q is on free_list, unlink
!                * q completely and patch up list
!                */
!               if (q->u.back) {
!                   q->u.back->link = q->link;
!               }
!               if (q->link) {
!                   q->link->u.back = q->u.back;
!               }
!               if (free_list == q) {
!                   free_list = q->link;
!               }
!           } else {
!               /* p is not on free_list just assume q's links */
!               p->u.back = q->u.back;
!               if (p->u.back) {
!                   p->u.back->link = p;
!               }
!               p->link = q->link;
!               if (p->link) {
!                   p->link->u.back = p;
!               }
!               if (q == free_list) {
!                   free_list = p;
!                   free_list->u.back = NULL;
!               }
!           }
!           
!           p->blocks += q->blocks;
!           initGroupTail( q->blocks, p, q );
!           result = p;
!       }
      }
      
!     return result;
  }
  
  void
  freeGroup(bdescr *p)
  {
    /* are we dealing with a megablock group? */
    if (p->blocks > BLOCKS_PER_MBLOCK) {
      freeMegaGroup(p);
      return;
    }
  
!   p->flags = BF_FREE;
    p->u.back = NULL;
    p->link = NULL;
    p->step = NULL;
--- 210,307 ----
  /* coalesce the group p with its predecessor and successor groups, if possible
   *
   * Returns NULL if no coalescing was done, otherwise returns a
!  * pointer to the newly enlarged group p moved from free_list to
!  * list if necessary.
   */
  
  STATIC_INLINE bdescr *
! coalesce(bdescr *p, bdescr **list)
  {
!   bdescr *first, *q, *result = NULL;
      
!   /* Get first megablock descriptor */
!   first = FIRST_BDESCR(MBLOCK_ROUND_DOWN(p->start));
      
!   /* Attempt to coalesce with predecessor if not the first block */
!   if (p != first) {
!     q = p - 1;
!     if (!q->blocks) { // not a block head?
!       q = q->link;    // find the head.
      }
+     /* Predecessor is free? */
+     if (q->flags & BF_FREE || q->flags & BF_FREEING) {
+       q->blocks += p->blocks;
+       p = q + (q->blocks - 1);
+       p->link = q;
+       p->flags = BF_FREEING;
+       p->blocks = 0;
+       if (q->flags & BF_FREE) {
+         q->flags = BF_FREEING;
+         dbl_unlink_from(q, &free_list);
+         dbl_link_onto(q, list);
+       }
+       p = result = q;
+     }
+   }
  
!   /* Attempt to coalesce with successor if not the last block */
!   q = p + p->blocks;
!   if (q != first + BLOCKS_PER_MBLOCK) {
!     /* Successor is free */
!     if (q->flags & BF_FREE) {
!       /* q is on free_list, unlink q */
!       dbl_unlink_from(q, &free_list);
!       if (!result) {
!         dbl_link_onto(p, list);
!       }
!       p->blocks += q->blocks;
!       q = p + (p->blocks - 1);
!       q->flags = BF_FREEING;
!       q->link = p;
!       q->blocks = 0;
!       result = p;
!     } else if (q->flags & BF_FREEING) {
!       if (result) {
!         /* p is on list, q is on list, unlink q */
!         dbl_unlink_from(q, list);
!       } else {
!         /* p is not on list just assume q's links */
!         p->u.back = q->u.back;
!         if (p->u.back) {
!           p->u.back->link = p;
!         }
!         p->link = q->link;
!         if (p->link) {
!           p->link->u.back = p;
!         }
!         if (q == *list) {
!           *list = p;
!           (*list)->u.back = NULL;
!         }
!       }
!       p->blocks += q->blocks;
!       q = p + (p->blocks - 1);
!       q->link = p;
!       q->blocks = 0;
!       result = p;
      }
+   }
      
!   return result;
  }
  
  void
  freeGroup(bdescr *p)
  {
+   bdescr *list = NULL;
+ 
    /* are we dealing with a megablock group? */
    if (p->blocks > BLOCKS_PER_MBLOCK) {
      freeMegaGroup(p);
      return;
    }
  
!   p->flags = BF_FREEING;
    p->u.back = NULL;
    p->link = NULL;
    p->step = NULL;
***************
*** 291,298 ****
    /* fill the block group with garbage if sanity checking is on */
    IF_DEBUG(sanity,memset(p->start, 0xaa, p->blocks * BLOCK_SIZE));
  
!   if (!coalesce(p)) {
      dbl_link_onto(p, &free_list);
    }
  
    IF_DEBUG(sanity, checkFreeListSanity());
--- 309,355 ----
    /* fill the block group with garbage if sanity checking is on */
    IF_DEBUG(sanity,memset(p->start, 0xaa, p->blocks * BLOCK_SIZE));
  
!   if (!coalesce(p, &list)) {
!     p->flags = BF_FREE;
      dbl_link_onto(p, &free_list);
+     p += p->blocks - 1;
+     p->flags = BF_FREE;
+   } else {
+     initTempFreeListGroup(list);
+   }
+ 
+   IF_DEBUG(sanity, checkFreeListSanity());
+ }
+ 
+ static void
+ tempFreeGroup(bdescr *p, bdescr **list)
+ {
+   /* are we dealing with a megablock group? */
+   if (p->blocks > BLOCKS_PER_MBLOCK) {
+     nat n;
+     void *q = p;
+ 
+     n = ((bdescr *)q)->blocks * BLOCK_SIZE / MBLOCK_SIZE + 1;
+     for (; n > 0; q += MBLOCK_SIZE, n--) {
+       initMBlock(MBLOCK_ROUND_DOWN(q));
+       initGroup(BLOCKS_PER_MBLOCK, (bdescr *)q);
+       tempFreeGroup((bdescr *)q, list);
+     }
+     return;
+   }
+ 
+   p->flags = BF_FREEING;
+   p->u.back = NULL;
+   p->link = NULL;
+   p->step = NULL;
+   p->gen_no = 0;
+   /* fill the block group with garbage if sanity checking is on */
+   IF_DEBUG(sanity,memset(p->start, 0xaa, p->blocks * BLOCK_SIZE));
+ 
+   if (!coalesce(p, list)) {
+     dbl_link_onto(p, list);
+     p += p->blocks - 1;
+     p->flags = BF_FREEING;
    }
  
    IF_DEBUG(sanity, checkFreeListSanity());
***************
*** 301,306 ****
--- 358,364 ----
  static void
  freeMegaGroup(bdescr *p)
  {
+   bdescr *temp_free_list = NULL;
    nat n;
    void *q = p;
  
***************
*** 308,326 ****
    for (; n > 0; q += MBLOCK_SIZE, n--) {
      initMBlock(MBLOCK_ROUND_DOWN(q));
      initGroup(BLOCKS_PER_MBLOCK, (bdescr *)q);
!     freeGroup((bdescr *)q);
    }
  }
  
  void
  freeChain(bdescr *bd)
  {
!   bdescr *next_bd;
    while (bd != NULL) {
      next_bd = bd->link;
!     freeGroup(bd);
      bd = next_bd;
    }
  }
  
  static void
--- 366,406 ----
    for (; n > 0; q += MBLOCK_SIZE, n--) {
      initMBlock(MBLOCK_ROUND_DOWN(q));
      initGroup(BLOCKS_PER_MBLOCK, (bdescr *)q);
!     tempFreeGroup((bdescr *)q, &temp_free_list);
    }
+ 
+   initTempFreeListGroup(temp_free_list);
  }
  
  void
  freeChain(bdescr *bd)
  {
!   bdescr *next_bd, *temp_free_list = NULL;
! 
    while (bd != NULL) {
      next_bd = bd->link;
!     tempFreeGroup(bd, &temp_free_list);
      bd = next_bd;
    }
+ 
+   initTempFreeListGroup(temp_free_list);
+ }
+ 
+ void
+ prepareToFreeChain(bdescr **list_head, bdescr **list_tail, bdescr *bd)
+ {
+   if (!*list_tail) {
+     *list_head = bd;
+   } else {
+     (*list_tail)->link = bd;
+   }
+ 
+   if (bd) {
+     do {
+       *list_tail = bd;
+       bd = bd->link;
+     } while (bd);
+   }
  }
  
  static void
***************
*** 342,347 ****
--- 422,449 ----
    }
  }
  
+ static void
+ initTempFreeListGroup(bdescr *list)
+ {
+   bdescr *bd, *tail_bd = NULL;
+   nat blocks;
+   
+   for (bd = list; bd; bd = bd->link) {
+     blocks = bd->blocks - 1;
+     initGroupTail(blocks, bd, bd + 1);
+     bd->flags = BF_FREE;
+     tail_bd = bd + blocks;
+     tail_bd->flags = BF_FREE;
+     tail_bd = bd;
+   }
+ 
+   tail_bd->link = free_list;
+   if (free_list) {
+     free_list->u.back = tail_bd;
+   }
+   free_list = list;
+ }
+ 
  /* 
-----------------------------------------------------------------------------
     Debugging
     -------------------------------------------------------------------------- 
*/
***************
*** 350,362 ****
  static void
  checkWellFormedGroup(bdescr *bd)
  {
!     nat i;
  
!     for (i = 1; i < bd->blocks; i++) {
!       ASSERT(bd[i].blocks == 0);
!       ASSERT(bd[i].free   == 0);
!       ASSERT(bd[i].link   == bd);
!     }
  }
  
  void
--- 452,464 ----
  static void
  checkWellFormedGroup(bdescr *bd)
  {
!   nat i;
  
!   for (i = 1; i < bd->blocks; i++) {
!     ASSERT(bd[i].blocks == 0);
!     ASSERT(bd[i].free   == 0);
!     ASSERT(bd[i].link   == bd);
!   }
  }
  
  void
diff -r -rcs --exclude=CVS ../clean/fptools/ghc/rts/GC.c ghc/rts/GC.c
*** ../clean/fptools/ghc/rts/GC.c       2005-06-06 09:49:07.000000000 +0100
--- ghc/rts/GC.c        2005-06-30 10:47:08.000000000 +0100
***************
*** 300,306 ****
  void
  GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
  {
!   bdescr *bd;
    step *stp;
    lnat live, allocated, collected = 0, copied = 0;
    lnat oldgen_saved_blocks = 0;
--- 300,306 ----
  void
  GarbageCollect ( void (*get_roots)(evac_fn), rtsBool force_major_gc )
  {
!   bdescr *bd, *free_bd_chain_hd = NULL, *free_bd_chain_tl = NULL;
    step *stp;
    lnat live, allocated, collected = 0, copied = 0;
    lnat oldgen_saved_blocks = 0;
***************
*** 396,402 ****
      // 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();
      }
  
--- 396,403 ----
      // always has at least one block; this means we can avoid a check for
      // NULL in recordMutable().
      if (g != 0) {
!         prepareToFreeChain(&free_bd_chain_hd, 
!                            &free_bd_chain_tl, generations[g].mut_list);
        generations[g].mut_list = allocBlock();
      }
  
***************
*** 528,533 ****
--- 529,539 ----
      for (g = RtsFlags.GcFlags.generations-1; g > N; g--) {
        IF_PAR_DEBUG(verbose, printMutableList(&generations[g]));
        scavenge_mutable_list(&generations[g]);
+       // free the old mut_list
+       prepareToFreeChain(&free_bd_chain_hd, 
+                          &free_bd_chain_tl, 
+                          generations[g].saved_mut_list);
+       generations[g].saved_mut_list = NULL;
        evac_gen = g;
        for (st = generations[g].n_steps-1; st >= 0; st--) {
        scavenge(&generations[g].steps[st]);
***************
*** 777,783 ****
                // add the new blocks to the block tally
                stp->n_blocks += stp->n_to_blocks;
            } else {
!               freeChain(stp->blocks);
                stp->blocks = stp->to_blocks;
                stp->n_blocks = stp->n_to_blocks;
                for (bd = stp->blocks; bd != NULL; bd = bd->link) {
--- 783,790 ----
                // add the new blocks to the block tally
                stp->n_blocks += stp->n_to_blocks;
            } else {
!                 prepareToFreeChain(&free_bd_chain_hd, 
!                                    &free_bd_chain_tl, stp->blocks);
                stp->blocks = stp->to_blocks;
                stp->n_blocks = stp->n_to_blocks;
                for (bd = stp->blocks; bd != NULL; bd = bd->link) {
***************
*** 793,803 ****
         * collection from large_objects.  Any objects left on
         * large_objects list are therefore dead, so we free them here.
         */
!       for (bd = stp->large_objects; bd != NULL; bd = next) {
!         next = bd->link;
!         freeGroup(bd);
!         bd = next;
!       }
  
        // update the count of blocks used by large objects
        for (bd = stp->scavenged_large_objects; bd != NULL; bd = bd->link) {
--- 800,807 ----
         * collection from large_objects.  Any objects left on
         * large_objects list are therefore dead, so we free them here.
         */
!         prepareToFreeChain(&free_bd_chain_hd, 
!                            &free_bd_chain_tl, stp->large_objects);
  
        // update the count of blocks used by large objects
        for (bd = stp->scavenged_large_objects; bd != NULL; bd = bd->link) {
***************
*** 910,918 ****
     * all have been copied into G0S1 now.  
     */
    if (small_alloc_list != NULL) {
!     freeChain(small_alloc_list);
    }
-   small_alloc_list = NULL;
    alloc_blocks = 0;
    alloc_Hp = NULL;
    alloc_HpLim = NULL;
--- 914,923 ----
     * all have been copied into G0S1 now.  
     */
    if (small_alloc_list != NULL) {
!     prepareToFreeChain(&free_bd_chain_hd, 
!                        &free_bd_chain_tl, small_alloc_list);
!     small_alloc_list = NULL;
    }
    alloc_blocks = 0;
    alloc_Hp = NULL;
    alloc_HpLim = NULL;
***************
*** 924,930 ****
    /* Free the mark stack.
     */
    if (mark_stack_bdescr != NULL) {
!       freeGroup(mark_stack_bdescr);
    }
  
    /* Free any bitmaps.
--- 929,936 ----
    /* Free the mark stack.
     */
    if (mark_stack_bdescr != NULL) {
!       prepareToFreeChain(&free_bd_chain_hd, 
!                          &free_bd_chain_tl, mark_stack_bdescr);
    }
  
    /* Free any bitmaps.
***************
*** 933,939 ****
        for (s = 0; s < generations[g].n_steps; s++) {
          stp = &generations[g].steps[s];
          if (stp->is_compacted && stp->bitmap != NULL) {
!             freeGroup(stp->bitmap);
          }
        }
    }
--- 939,946 ----
        for (s = 0; s < generations[g].n_steps; s++) {
          stp = &generations[g].steps[s];
          if (stp->is_compacted && stp->bitmap != NULL) {
!               prepareToFreeChain(&free_bd_chain_hd, 
!                                  &free_bd_chain_tl, stp->bitmap);
          }
        }
    }
***************
*** 945,956 ****
      nat blocks;
      
      if (old_to_blocks != NULL) {
!       freeChain(old_to_blocks);
      }
      for (bd = g0s0->to_blocks; bd != NULL; bd = bd->link) {
        bd->flags = 0;  // now from-space 
      }
  
      /* For a two-space collector, we need to resize the nursery. */
      
      /* set up a new nursery.  Allocate a nursery size based on a
--- 952,967 ----
      nat blocks;
      
      if (old_to_blocks != NULL) {
!       prepareToFreeChain(&free_bd_chain_hd, 
!                          &free_bd_chain_tl, old_to_blocks);
      }
      for (bd = g0s0->to_blocks; bd != NULL; bd = bd->link) {
        bd->flags = 0;  // now from-space 
      }
  
+     /* Free all the blocks collected during the collection cycle */
+     freeChain(free_bd_chain_hd);
+ 
      /* For a two-space collector, we need to resize the nursery. */
      
      /* set up a new nursery.  Allocate a nursery size based on a
***************
*** 997,1002 ****
--- 1008,1016 ----
       * allocation area to make best use of the memory available.
       */
  
+     /* Free all the blocks collected during the collection cycle */
+     freeChain(free_bd_chain_hd);
+ 
      if (RtsFlags.GcFlags.heapSizeSuggestion) {
        long blocks;
        nat needed = calcNeeded();      // approx blocks needed at next GC 
***************
*** 3653,3662 ****
            }
        }
      }
- 
-     // free the old mut_list
-     freeChain(gen->saved_mut_list);
-     gen->saved_mut_list = NULL;
  }
  
  
--- 3667,3672 ----
diff -r -rcs --exclude=CVS ../clean/fptools/ghc/rts/Storage.c ghc/rts/Storage.c
*** ../clean/fptools/ghc/rts/Storage.c  2005-05-12 12:36:50.000000000 +0100
--- ghc/rts/Storage.c   2005-06-28 12:05:32.000000000 +0100
***************
*** 480,498 ****
      stp->blocks = allocNursery(stp, stp->blocks, blocks-nursery_blocks);
    } 
    else {
!     bdescr *next_bd;
      
      IF_DEBUG(gc, debugBelch("Decreasing size of nursery to %d blocks\n", 
                         blocks));
  
      bd = stp->blocks;
      while (nursery_blocks > blocks) {
        next_bd = bd->link;
        next_bd->u.back = NULL;
        nursery_blocks -= bd->blocks; // might be a large block
!       freeGroup(bd);
        bd = next_bd;
      }
      stp->blocks = bd;
      // might have gone just under, by freeing a large block, so make
      // up the difference.
--- 480,501 ----
      stp->blocks = allocNursery(stp, stp->blocks, blocks-nursery_blocks);
    } 
    else {
!     bdescr *next_bd, *free_bd_chain = NULL;
      
      IF_DEBUG(gc, debugBelch("Decreasing size of nursery to %d blocks\n", 
                         blocks));
  
      bd = stp->blocks;
+ 
      while (nursery_blocks > blocks) {
        next_bd = bd->link;
        next_bd->u.back = NULL;
        nursery_blocks -= bd->blocks; // might be a large block
!         bd->link = free_bd_chain;
!         free_bd_chain = bd;
        bd = next_bd;
      }
+     freeChain(free_bd_chain);
      stp->blocks = bd;
      // might have gone just under, by freeing a large block, so make
      // up the difference.
_______________________________________________
Cvs-ghc mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/cvs-ghc

Reply via email to