Back to index

lightning-sunbird  0.9+nobinonly
allchblk.c
Go to the documentation of this file.
00001 /* 
00002  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00003  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
00004  * Copyright (c) 1998 by Silicon Graphics.  All rights reserved.
00005  *
00006  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00007  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00008  *
00009  * Permission is hereby granted to use or copy this program
00010  * for any purpose,  provided the above notices are retained on all copies.
00011  * Permission to modify the code and to distribute modified code is granted,
00012  * provided the above notices are retained, and a notice that the code was
00013  * modified is included with the above copyright notice.
00014  */
00015 /* Boehm, August 9, 1995 5:08 pm PDT */
00016 
00017 #define DEBUG
00018 #undef DEBUG
00019 #include <stdio.h>
00020 #include "gc_priv.h"
00021 
00022 
00023 /*
00024  * allocate/free routines for heap blocks
00025  * Note that everything called from outside the garbage collector
00026  * should be prepared to abort at any point as the result of a signal.
00027  */
00028 
00029 /*
00030  * Free heap blocks are kept on a list sorted by address.
00031  * The hb_hdr.hbh_sz field of a free heap block contains the length
00032  * (in bytes) of the entire block.
00033  * Neighbors are coalesced.
00034  */
00035  
00036 # define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
00037               /* largest block we will allocate starting on a black   */
00038               /* listed block.  Must be >= HBLKSIZE.                  */
00039 
00040 struct hblk * GC_hblkfreelist = 0;
00041 
00042 struct hblk *GC_savhbp = (struct hblk *)0;  /* heap block preceding next */
00043                                     /* block to be examined by   */
00044                                     /* GC_allochblk.                */
00045 
00046 # if !defined(NO_DEBUGGING)
00047 void GC_print_hblkfreelist()
00048 {
00049     struct hblk * h = GC_hblkfreelist;
00050     word total_free = 0;
00051     hdr * hhdr = HDR(h);
00052     word sz;
00053     
00054     while (h != 0) {
00055         sz = hhdr -> hb_sz;
00056        GC_printf2("0x%lx size %lu ", (unsigned long)h, (unsigned long)sz);
00057        total_free += sz;
00058         if (GC_is_black_listed(h, HBLKSIZE) != 0) {
00059              GC_printf0("start black listed\n");
00060         } else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
00061              GC_printf0("partially black listed\n");
00062         } else {
00063              GC_printf0("not black listed\n");
00064         }
00065         h = hhdr -> hb_next;
00066         hhdr = HDR(h);
00067     }
00068     GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
00069 }
00070 
00071 # endif /* NO_DEBUGGING */
00072 
00073 /* Initialize hdr for a block containing the indicated size and       */
00074 /* kind of objects.                                            */
00075 /* Return FALSE on failure.                                    */
00076 static GC_bool setup_header(hhdr, sz, kind, flags)
00077 register hdr * hhdr;
00078 word sz;      /* object size in words */
00079 int kind;
00080 unsigned char flags;
00081 {
00082     register word descr;
00083     
00084     /* Add description of valid object pointers */
00085       if (!GC_add_map_entry(sz)) return(FALSE);
00086       hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
00087       
00088     /* Set size, kind and mark proc fields */
00089       hhdr -> hb_sz = sz;
00090       hhdr -> hb_obj_kind = kind;
00091       hhdr -> hb_flags = flags;
00092       descr = GC_obj_kinds[kind].ok_descriptor;
00093       if (GC_obj_kinds[kind].ok_relocate_descr) descr += WORDS_TO_BYTES(sz);
00094       hhdr -> hb_descr = descr;
00095       
00096     /* Clear mark bits */
00097       GC_clear_hdr_marks(hhdr);
00098       
00099     hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
00100     return(TRUE);
00101 }
00102 
00103 #ifdef EXACT_FIRST
00104 #   define LAST_TRIP 2
00105 #else
00106 #   define LAST_TRIP 1
00107 #endif
00108 
00109 word GC_max_hblk_size = HBLKSIZE;
00110        
00111 /*
00112  * Allocate (and return pointer to) a heap block
00113  *   for objects of size sz words.
00114  *
00115  * NOTE: We set obj_map field in header correctly.
00116  *       Caller is resposnsible for building an object freelist in block.
00117  *
00118  * We clear the block if it is destined for large objects, and if
00119  * kind requires that newly allocated objects be cleared.
00120  */
00121 struct hblk *
00122 GC_allochblk(sz, kind, flags)
00123 word sz;
00124 int kind;
00125 unsigned char flags;  /* IGNORE_OFF_PAGE or 0 */
00126 {
00127     register struct hblk *thishbp;
00128     register hdr * thishdr;        /* Header corr. to thishbp */
00129     register struct hblk *hbp;
00130     register hdr * hhdr;           /* Header corr. to hbp */
00131     struct hblk *prevhbp;
00132     register hdr * phdr;           /* Header corr. to prevhbp */
00133     signed_word size_needed;    /* number of bytes in requested objects */
00134     signed_word size_avail; /* bytes available in this block   */
00135     int trip_count = 0;
00136 
00137     size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
00138     if ((word)size_needed >  GC_max_hblk_size)
00139        GC_max_hblk_size = size_needed;
00140 
00141     /* search for a big enough block in free list */
00142        hbp = GC_savhbp;
00143        hhdr = HDR(hbp);
00144        for(;;) {
00145 
00146            prevhbp = hbp;
00147            phdr = hhdr;
00148            hbp = (prevhbp == 0? GC_hblkfreelist : phdr->hb_next);
00149            hhdr = HDR(hbp);
00150 
00151            if( prevhbp == GC_savhbp) {
00152               if (trip_count == LAST_TRIP) return(0);
00153               ++trip_count;
00154            }
00155 
00156            if( hbp == 0 ) continue;
00157 
00158            size_avail = hhdr->hb_sz;
00159 #          ifdef EXACT_FIRST
00160               if (trip_count <= 1 && size_avail != size_needed) continue;
00161 #          endif
00162            if (size_avail < size_needed) continue;
00163 #          ifdef PRESERVE_LAST
00164               if (size_avail != size_needed
00165                   && !GC_incremental
00166                   && (word)size_needed <= GC_max_hblk_size/2
00167                   && GC_in_last_heap_sect((ptr_t)hbp)
00168                   && GC_should_collect()) {
00169                   continue;
00170               } 
00171 #          endif
00172            /* If the next heap block is obviously better, go on.      */
00173            /* This prevents us from disassembling a single large block */
00174            /* to get tiny blocks.                              */
00175            {
00176              signed_word next_size;
00177              
00178              thishbp = hhdr -> hb_next;
00179              if (thishbp == 0) thishbp = GC_hblkfreelist; 
00180              thishdr = HDR(thishbp);
00181              next_size = (signed_word)(thishdr -> hb_sz);
00182              if (next_size < size_avail
00183                  && next_size >= size_needed
00184                  && !GC_is_black_listed(thishbp, (word)size_needed)) {
00185                  continue;
00186              }
00187            }
00188            if ( !IS_UNCOLLECTABLE(kind) &&
00189                 (kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC)) {
00190              struct hblk * lasthbp = hbp;
00191              ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
00192              signed_word orig_avail = size_avail;
00193              signed_word eff_size_needed = ((flags & IGNORE_OFF_PAGE)?
00194                                           HBLKSIZE
00195                                           : size_needed);
00196              
00197              
00198              while ((ptr_t)lasthbp <= search_end
00199                     && (thishbp = GC_is_black_listed(lasthbp,
00200                                                 (word)eff_size_needed))) {
00201                lasthbp = thishbp;
00202              }
00203              size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
00204              thishbp = lasthbp;
00205              if (size_avail >= size_needed) {
00206                if (thishbp != hbp && GC_install_header(thishbp)) {
00207                  /* Split the block at thishbp */
00208                      thishdr = HDR(thishbp);
00209                      /* GC_invalidate_map not needed, since we will   */
00210                      /* allocate this block.                          */
00211                     thishdr -> hb_next = hhdr -> hb_next;
00212                     thishdr -> hb_sz = size_avail;
00213                     hhdr -> hb_sz = (ptr_t)thishbp - (ptr_t)hbp;
00214                     hhdr -> hb_next = thishbp;
00215                 /* Advance to thishbp */
00216                     prevhbp = hbp;
00217                     phdr = hhdr;
00218                     hbp = thishbp;
00219                     hhdr = thishdr;
00220               }
00221              } else if (size_needed > (signed_word)BL_LIMIT
00222                         && orig_avail - size_needed
00223                          > (signed_word)BL_LIMIT) {
00224                /* Punt, since anything else risks unreasonable heap growth. */
00225                WARN("Needed to allocate blacklisted block at 0x%lx\n",
00226                    (word)hbp);
00227                thishbp = hbp;
00228                size_avail = orig_avail;
00229              } else if (size_avail == 0
00230                       && size_needed == HBLKSIZE
00231                       && prevhbp != 0) {
00232 #             ifndef FIND_LEAK
00233                 static unsigned count = 0;
00234                 
00235                 /* The block is completely blacklisted.  We need      */
00236                 /* to drop some such blocks, since otherwise we spend */
00237                 /* all our time traversing them if pointerfree */
00238                 /* blocks are unpopular.                       */
00239                  /* A dropped block will be reconsidered at next GC.  */
00240                  if ((++count & 3) == 0) {
00241                    /* Allocate and drop the block in small chunks, to */
00242                    /* maximize the chance that we will recover some   */
00243                    /* later.                                          */
00244                      struct hblk * limit = hbp + (hhdr->hb_sz/HBLKSIZE);
00245                      struct hblk * h;
00246                      
00247                     GC_words_wasted += hhdr->hb_sz;
00248                      phdr -> hb_next = hhdr -> hb_next;
00249                      for (h = hbp; h < limit; h++) {
00250                        if (h == hbp || GC_install_header(h)) {
00251                          hhdr = HDR(h);
00252                          (void) setup_header(
00253                               hhdr,
00254                                      BYTES_TO_WORDS(HBLKSIZE - HDR_BYTES),
00255                                      PTRFREE, 0); /* Cant fail */
00256                               if (GC_debugging_started) {
00257                                 BZERO(hbp + HDR_BYTES, HBLKSIZE - HDR_BYTES);
00258                               }
00259                        }
00260                      }
00261                    /* Restore hbp to point at free block */
00262                      if (GC_savhbp == hbp) GC_savhbp = prevhbp;
00263                      hbp = prevhbp;
00264                      hhdr = phdr;
00265                      if (hbp == GC_savhbp) --trip_count;
00266                  }
00267 #             endif
00268              }
00269            }
00270            if( size_avail >= size_needed ) {
00271               /* found a big enough block       */
00272               /* let thishbp --> the block      */
00273               /* set prevhbp, hbp to bracket it */
00274                   thishbp = hbp;
00275                   thishdr = hhdr;
00276                   if( size_avail == size_needed ) {
00277                      hbp = hhdr->hb_next;
00278                      hhdr = HDR(hbp);
00279                   } else {
00280                      hbp = (struct hblk *)
00281                          (((word)thishbp) + size_needed);
00282                      if (!GC_install_header(hbp)) {
00283                          hbp = thishbp;
00284                          continue;
00285                      }
00286                      hhdr = HDR(hbp);
00287                      GC_invalidate_map(hhdr);
00288                      hhdr->hb_next = thishdr->hb_next;
00289                      hhdr->hb_sz = size_avail - size_needed;
00290                   }
00291               /* remove *thishbp from hblk freelist */
00292                   if( prevhbp == 0 ) {
00293                      GC_hblkfreelist = hbp;
00294                   } else {
00295                      phdr->hb_next = hbp;
00296                   }
00297               /* save current list search position */
00298                   GC_savhbp = hbp;
00299               break;
00300            }
00301        }
00302        
00303     /* Notify virtual dirty bit implementation that we are about to write. */
00304        GC_write_hint(thishbp);
00305        /* This should deal better with large blocks.    */
00306     
00307     /* Add it to map of valid blocks */
00308        if (!GC_install_counts(thishbp, (word)size_needed)) return(0);
00309        /* This leaks memory under very rare conditions. */
00310               
00311     /* Set up header */
00312         if (!setup_header(thishdr, sz, kind, flags)) {
00313             GC_remove_counts(thishbp, (word)size_needed);
00314             return(0); /* ditto */
00315         }
00316         
00317     /* Clear block if necessary */
00318        if (GC_debugging_started
00319            || sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) {
00320            BZERO(thishbp + HDR_BYTES,  size_needed - HDR_BYTES);
00321        }
00322 
00323     /* We just successfully allocated a block.  Restart count of      */
00324     /* consecutive failures.                                          */
00325     {
00326        extern unsigned GC_fail_count;
00327        
00328        GC_fail_count = 0;
00329     }
00330     
00331     return( thishbp );
00332 }
00333  
00334 struct hblk * GC_freehblk_ptr = 0;  /* Search position hint for GC_freehblk */
00335 
00336 /*
00337  * Free a heap block.
00338  *
00339  * Coalesce the block with its neighbors if possible.
00340  *
00341  * All mark words are assumed to be cleared.
00342  */
00343 void
00344 GC_freehblk(p)
00345 register struct hblk *p;
00346 {
00347 register hdr *phdr;  /* Header corresponding to p */
00348 register struct hblk *hbp, *prevhbp;
00349 register hdr *hhdr, *prevhdr;
00350 register signed_word size;
00351 
00352     /* GC_savhbp may become invalid due to coalescing.  Clear it. */
00353        GC_savhbp = (struct hblk *)0;
00354 
00355     phdr = HDR(p);
00356     size = phdr->hb_sz;
00357     size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
00358     GC_remove_counts(p, (word)size);
00359     phdr->hb_sz = size;
00360     GC_invalidate_map(phdr);
00361     prevhbp = 0;
00362     
00363     /* The following optimization was suggested by David Detlefs.     */
00364     /* Note that the header cannot be NIL, since there cannot be an   */
00365     /* intervening  call to GC_freehblk without resetting             */
00366     /* GC_freehblk_ptr.                                               */
00367     if (GC_freehblk_ptr != 0 &&
00368        HDR(GC_freehblk_ptr)->hb_map == GC_invalid_map &&
00369        (ptr_t)GC_freehblk_ptr < (ptr_t)p) {
00370       hbp = GC_freehblk_ptr;
00371     } else {
00372       hbp = GC_hblkfreelist;
00373     };
00374     hhdr = HDR(hbp);
00375 
00376     while( (hbp != 0) && (hbp < p) ) {
00377        prevhbp = hbp;
00378        prevhdr = hhdr;
00379        hbp = hhdr->hb_next;
00380        hhdr = HDR(hbp);
00381     }
00382     GC_freehblk_ptr = prevhbp;
00383     
00384     /* Check for duplicate deallocation in the easy case */
00385       if (hbp != 0 && (ptr_t)p + size > (ptr_t)hbp
00386         || prevhbp != 0 && (ptr_t)prevhbp + prevhdr->hb_sz > (ptr_t)p) {
00387         GC_printf1("Duplicate large block deallocation of 0x%lx\n",
00388                  (unsigned long) p);
00389         GC_printf2("Surrounding free blocks are 0x%lx and 0x%lx\n",
00390                  (unsigned long) prevhbp, (unsigned long) hbp);
00391       }
00392 
00393     /* Coalesce with successor, if possible */
00394       if( (((word)p)+size) == ((word)hbp) ) {
00395        phdr->hb_next = hhdr->hb_next;
00396        phdr->hb_sz += hhdr->hb_sz;
00397        GC_remove_header(hbp);
00398       } else {
00399        phdr->hb_next = hbp;
00400       }
00401 
00402     
00403     if( prevhbp == 0 ) {
00404        GC_hblkfreelist = p;
00405     } else if( (((word)prevhbp) + prevhdr->hb_sz)
00406               == ((word)p) ) {
00407       /* Coalesce with predecessor */
00408        prevhdr->hb_next = phdr->hb_next;
00409        prevhdr->hb_sz += phdr->hb_sz;
00410        GC_remove_header(p);
00411     } else {
00412        prevhdr->hb_next = p;
00413     }
00414 }
00415