C:/Users/Dennis/src/lang/russell.orig/src/gc/alloc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00003  * Copyright (c) 1991 by Xerox Corporation.  All rights reserved.
00004  *
00005  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00006  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00007  *
00008  * Permission is hereby granted to copy this garbage collector for any purpose,
00009  * provided the above notices are retained on all copies.
00010  *
00011  * This file contains the functions:
00012  *      static void clear_marks()
00013  *      void GC_gcollect_inner(force)
00014  *      void GC_gcollect()
00015  *      bool GC_expand_hp(n)
00016  *      ptr_t GC_allocobj(sz, kind)
00017  */
00018 
00019 
00020 # include <stdio.h>
00021 # include <signal.h>
00022 # include <sys/types.h>
00023 # include "gc_private.h"
00024 
00025 /*
00026  * This is a garbage collecting storage allocator
00027  * that should run on most UNIX systems.  The garbage
00028  * collector is overly conservative in that it may fail to GC_reclaim
00029  * inaccessible storage.  On the other hand, it does not assume
00030  * any runtime tag information.
00031  * We make the following assumptions:
00032  *  1.  We are running under something that looks like Berkeley UNIX,
00033  *      on one of the supported architectures.
00034  *  2.  For every accessible object, a pointer to it is stored in
00035  *          a) the stack segment, or
00036  *          b) the data or bss segment, or
00037  *          c) the registers, or
00038  *          d) an accessible block.
00039  *
00040  */
00041 
00042 /*
00043  * Separate free lists are maintained for different sized objects
00044  * up to MAXOBJSZ.
00045  * The call GC_allocobj(i,k) ensures that the freelist for
00046  * kind k objects of size i points to a non-empty
00047  * free list. It returns a pointer to the first entry on the free list.
00048  * In a single-threaded world, GC_allocobj may be called to allocate
00049  * an object of (small) size i as follows:
00050  *
00051  *            opp = &(GC_objfreelist[i]);
00052  *            if (*opp == 0) GC_allocobj(i, NORMAL);
00053  *            ptr = *opp;
00054  *            *opp = ptr->next;
00055  *
00056  * Note that this is very fast if the free list is non-empty; it should
00057  * only involve the execution of 4 or 5 simple instructions.
00058  * All composite objects on freelists are cleared, except for
00059  * their first word.
00060  */
00061 
00062 /*
00063  *  The allocator uses GC_allochblk to allocate large chunks of objects.
00064  * These chunks all start on addresses which are multiples of
00065  * HBLKSZ.   Each allocated chunk has an associated header,
00066  * which can be located quickly based on the address of the chunk.
00067  * (See headers.c for details.) 
00068  * This makes it possible to check quickly whether an
00069  * arbitrary address corresponds to an object administered by the
00070  * allocator.
00071  */
00072 
00073 word GC_non_gc_bytes = 0;  /* Number of bytes not intended to be collected */
00074 
00075 word GC_gc_no = 0;
00076 
00077 char * GC_copyright[] =
00078 {"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers",
00079 "Copyright (c) 1991,1992 by Xerox Corporation.  All rights reserved.",
00080 "THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
00081 " EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK."};
00082 
00083 
00084 /* some more variables */
00085 
00086 extern signed_word GC_mem_found;  /* Number of reclaimed longwords      */
00087                                   /* after garbage collection           */
00088 
00089 /* clear all mark bits in the header */
00090 void GC_clear_hdr_marks(hhdr)
00091 register hdr * hhdr;
00092 {
00093     bzero((char *)hhdr -> hb_marks, (int)(MARK_BITS_SZ*sizeof(word)));
00094 }
00095 
00096 /*
00097  * Clear all mark bits associated with block h.
00098  */
00099 /*ARGSUSED*/
00100 static void clear_marks_for_block(h, dummy)
00101 struct hblk *h;
00102 word dummy;
00103 {
00104     register hdr * hhdr = HDR(h);
00105     
00106     GC_clear_hdr_marks(hhdr);
00107 }
00108 
00109 /*
00110  * Clear mark bits in all allocated heap blocks
00111  */
00112 static void clear_marks()
00113 {
00114     GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
00115 }
00116 
00117 bool GC_dont_expand = 0;
00118 
00119 word GC_free_space_divisor = 4;
00120 
00121 /* Return the minimum number of words that must be allocated between    */
00122 /* collections to amortize the collection cost.                         */
00123 static word min_words_allocd()
00124 {
00125     int dummy;
00126 #   ifdef THREADS
00127         /* We punt, for now. */
00128         register signed_word stack_size = 10000;
00129 #   else
00130         register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
00131 #   endif
00132     register word total_root_size;  /* includes double stack size,      */
00133                                     /* since the stack is expensive     */
00134                                     /* to scan.                         */
00135     
00136     if (stack_size < 0) stack_size = -stack_size;
00137     total_root_size = 2 * stack_size + GC_root_size;
00138     return(BYTES_TO_WORDS(GC_heapsize + total_root_size)/GC_free_space_divisor);
00139 }
00140 
00141 /* Return the number of words allocated, adjusted for explicit storage  */
00142 /* management.  This number can be used in deciding when to trigger     */
00143 /* collections.                                                         */
00144 word GC_adj_words_allocd()
00145 {
00146     register signed_word result;
00147     register signed_word expl_managed =
00148                 BYTES_TO_WORDS((long)GC_non_gc_bytes
00149                                 - (long)GC_non_gc_bytes_at_gc);
00150     
00151     /* Don't count what was explicitly freed, or newly allocated for    */
00152     /* explicit management.  Note that deallocating an explicitly       */
00153     /* managed object should not alter result, assuming the client      */
00154     /* is playing by the rules.                                         */
00155     result = (signed_word)GC_words_allocd
00156              - (signed_word)GC_mem_freed - expl_managed;
00157     if (result > (signed_word)GC_words_allocd) result = GC_words_allocd;
00158         /* probably client bug or unfortunate scheduling */
00159     if (result < (signed_word)(GC_words_allocd >> 2)) {
00160         /* Always count at least 1/8 of the allocations.  We don't want */
00161         /* to collect too infrequently, since that would inhibit        */
00162         /* coalescing of free storage blocks.                           */
00163         /* This also makes us partially robust against client bugs.     */
00164         return(GC_words_allocd >> 3);
00165     } else {
00166         return(result);
00167     }
00168 }
00169 
00170 
00171 /* Clear up a few frames worth og garbage left at the top of the stack. */
00172 /* This is used to prevent us from accidentally treating garbade left   */
00173 /* on the stack by other parts of the collector as roots.  This         */
00174 /* differs from the code in misc.c, which actually tries to keep the    */
00175 /* stack clear of long-lived, client-generated garbage.                 */
00176 void GC_clear_a_few_frames()
00177 {
00178 #   define NWORDS 64
00179     word frames[NWORDS];
00180     register int i;
00181     
00182     for (i = 0; i < NWORDS; i++) frames[i] = 0;
00183 }
00184 
00185 /*
00186  * Restore inaccessible objects to the free list 
00187  * update GC_mem_found (number of reclaimed longwords after
00188  * garbage collection)
00189  * We assume we hold the allocation lock, and are not interruptable by
00190  * signals, if that matters.
00191  * If force is FALSE and we didn't do anything, return FALSE.
00192  * Otherwise return TRUE
00193  */
00194 bool GC_gcollect_inner(force)
00195 bool force;     /* Collect even if only a small amount of allocation    */
00196                 /* has taken place.  Otherwise we refuse, allowing the  */
00197                 /* heap to grow.                                        */
00198 {
00199 #   ifdef PRINTTIMES
00200         CLOCK_TYPE start_time;
00201         CLOCK_TYPE mark_time;
00202         CLOCK_TYPE done_time;
00203 #   endif
00204 
00205     if (!force && !GC_dont_expand
00206         && GC_adj_words_allocd() < min_words_allocd()) return(FALSE);
00207 #   ifdef PRINTTIMES
00208         GET_TIME(start_time);
00209 #   endif
00210 #   ifdef PRINTSTATS
00211         GC_printf2("Collection %lu reclaimed %ld bytes\n",
00212                   (unsigned long) GC_gc_no,
00213                   (long)WORDS_TO_BYTES(GC_mem_found));
00214 #   endif
00215     GC_gc_no++;
00216 #   ifdef GATHERSTATS
00217         GC_mem_found = 0;
00218         GC_composite_in_use = 0;
00219         GC_atomic_in_use = 0;
00220 #   endif
00221 #   ifdef PRINTSTATS
00222       GC_printf2("Collection number %lu after %lu allocated bytes ",
00223                 (unsigned long) GC_gc_no,
00224                 (unsigned long) WORDS_TO_BYTES(GC_words_allocd));
00225       GC_printf1("(heapsize = %lu bytes)\n",
00226                 (unsigned long) GC_heapsize);
00227       /* Printf arguments may be pushed in funny places.  Clear the     */
00228       /* space.                                                         */
00229       GC_printf0("");
00230 #   endif               
00231 
00232     clear_marks();
00233 
00234     STOP_WORLD();
00235 
00236     /* Mark from all roots.  */
00237         /* Minimize junk left in my registers and on the stack */
00238             GC_clear_a_few_frames();
00239             GC_noop(0,0,0,0,0,0);
00240         GC_mark_roots();
00241         GC_promote_black_lists();
00242 
00243     /* Check all debugged objects for consistency */
00244         if (GC_debugging_started) {
00245             GC_check_heap();
00246         }
00247         
00248     START_WORLD();
00249     
00250 #   ifdef PRINTTIMES
00251         GET_TIME(mark_time);
00252 #   endif
00253 
00254 
00255 #   ifdef FIND_LEAK
00256       /* Mark all objects on the free list.  All objects should be */
00257       /* marked when we're done.                                   */
00258         {
00259           register word size;           /* current object size          */
00260           register ptr_t p;     /* pointer to current object    */
00261           register struct hblk * h;     /* pointer to block containing *p */
00262           register hdr * hhdr;
00263           register int word_no;           /* "index" of *p in *q          */
00264           int kind;
00265 
00266           for (kind = 0; kind < GC_n_kinds; kind++) {
00267             for (size = 1; size <= MAXOBJSZ; size++) {
00268               for (p= GC_obj_kinds[kind].ok_freelist[size];
00269                    p != 0; p=obj_link(p)){
00270                 h = HBLKPTR(p);
00271                 hhdr = HDR(h);
00272                 word_no = (((word *)p) - ((word *)h));
00273                 set_mark_bit_from_hdr(hhdr, word_no);
00274               }
00275             }
00276           }
00277         }
00278       /* Check that everything is marked */
00279         GC_start_reclaim(TRUE);
00280 #   else
00281 
00282       GC_finalize();
00283 
00284       /* Clear free list mark bits, in case they got accidentally marked   */
00285       /* Note: HBLKPTR(p) == pointer to head of block containing *p        */
00286       /* Also subtract memory remaining from GC_mem_found count.           */
00287       /* Note that composite objects on free list are cleared.             */
00288       /* Thus accidentally marking a free list is not a problem;  only     */
00289       /* objects on the list itself will be marked, and that's fixed here. */
00290       {
00291         register word size;             /* current object size          */
00292         register ptr_t p;       /* pointer to current object    */
00293         register struct hblk * h;       /* pointer to block containing *p */
00294         register hdr * hhdr;
00295         register int word_no;           /* "index" of *p in *q          */
00296         int kind;
00297 
00298         for (kind = 0; kind < GC_n_kinds; kind++) {
00299           for (size = 1; size <= MAXOBJSZ; size++) {
00300             for (p= GC_obj_kinds[kind].ok_freelist[size];
00301                  p != 0; p=obj_link(p)){
00302                 h = HBLKPTR(p);
00303                 hhdr = HDR(h);
00304                 word_no = (((word *)p) - ((word *)h));
00305                 clear_mark_bit_from_hdr(hhdr, word_no);
00306                 GC_mem_found -= size;
00307             }
00308           }
00309         }
00310       }
00311 
00312 
00313 #     ifdef PRINTSTATS
00314         GC_printf1("Bytes recovered before GC_reclaim - f.l. count = %ld\n",
00315                   (long)WORDS_TO_BYTES(GC_mem_found));
00316 #     endif
00317 
00318     /* Reconstruct free lists to contain everything not marked */
00319       GC_start_reclaim(FALSE);
00320     
00321 #   endif /* FIND_LEAK */
00322 
00323 #   ifdef PRINTSTATS
00324         GC_printf2(
00325                   "Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
00326                   (long)WORDS_TO_BYTES(GC_mem_found),
00327                   (unsigned long)GC_heapsize);
00328         GC_printf2("%lu (atomic) + %lu (composite) bytes in use\n",
00329                    (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
00330                    (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
00331 #   endif
00332 
00333     /* Reset or increment counters for next cycle */
00334       GC_words_allocd_before_gc += GC_words_allocd;
00335       GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
00336       GC_words_allocd = 0;
00337       GC_mem_freed = 0;
00338 
00339   /* Get final time */
00340 #   ifdef PRINTTIMES
00341         GET_TIME(done_time);
00342         GC_printf2("Garbage collection took %lu + %lu msecs\n",
00343                    MS_TIME_DIFF(mark_time,start_time),
00344                    MS_TIME_DIFF(done_time,mark_time));
00345 #   endif
00346     return(TRUE);
00347 }
00348 
00349 /* Externally callable version of above */
00350 void GC_gcollect()
00351 {
00352     DCL_LOCK_STATE;
00353     
00354     DISABLE_SIGNALS();
00355     LOCK();
00356     if (!GC_is_initialized) GC_init_inner();
00357     /* Minimize junk left in my registers */
00358       GC_noop(0,0,0,0,0,0);
00359     (void) GC_gcollect_inner(TRUE);
00360     UNLOCK();
00361     ENABLE_SIGNALS();
00362 }
00363 
00364 /*
00365  * Use the chunk of memory starting at p of syze bytes as part of the heap.
00366  * Assumes p is HBLKSIZE aligned, and bytes is a multiple of HBLKSIZE.
00367  */
00368 void GC_add_to_heap(p, bytes)
00369 struct hblk *p;
00370 word bytes;
00371 {
00372     word words;
00373     
00374     GC_install_header(p);
00375     words = BYTES_TO_WORDS(bytes - HDR_BYTES);
00376     HDR(p) -> hb_sz = words;
00377     GC_freehblk(p);
00378     GC_heapsize += bytes;
00379     if ((ptr_t)p <= GC_least_plausible_heap_addr
00380         || GC_least_plausible_heap_addr == 0) {
00381         GC_least_plausible_heap_addr = (ptr_t)p - sizeof(word);
00382                 /* Making it a little smaller than necessary prevents   */
00383                 /* us from getting a false hit from the variable        */
00384                 /* itself.  There's some unintentional reflection       */
00385                 /* here.                                                */
00386     }
00387     if ((ptr_t)p + bytes >= GC_greatest_plausible_heap_addr) {
00388         GC_greatest_plausible_heap_addr = (ptr_t)p + bytes;
00389     }
00390 }
00391 
00392 ptr_t GC_least_plausible_heap_addr = (ptr_t)ONES;
00393 ptr_t GC_greatest_plausible_heap_addr = 0;
00394 
00395 ptr_t GC_max(x,y)
00396 ptr_t x, y;
00397 {
00398     return(x > y? x : y);
00399 }
00400 
00401 ptr_t GC_min(x,y)
00402 ptr_t x, y;
00403 {
00404     return(x < y? x : y);
00405 }
00406 
00407 /*
00408  * this explicitly increases the size of the heap.  It is used
00409  * internally, but my also be invoked from GC_expand_hp by the user.
00410  * The argument is in units of HBLKSIZE.
00411  * Returns FALSE on failure.
00412  */
00413 bool GC_expand_hp_inner(n)
00414 word n;
00415 {
00416     word bytes = n * HBLKSIZE;
00417     struct hblk * space = GET_MEM(bytes);
00418     word expansion_slop;        /* Number of bytes by which we expect the */
00419                                 /* heap to expand soon.                   */
00420 
00421     if (n > 2*GC_hincr) {
00422         GC_hincr = n/2;
00423     }
00424     if( space == 0 ) {
00425         return(FALSE);
00426     }
00427 #   ifdef PRINTSTATS
00428         GC_printf1("Increasing heap size by %lu\n",
00429                    (unsigned long)bytes);
00430 #   endif
00431     expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd());
00432     if (5 * HBLKSIZE * MAXHINCR > expansion_slop) {
00433         expansion_slop = 5 * HBLKSIZE * MAXHINCR;
00434     }
00435     if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
00436         || GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
00437         /* Assume the heap is growing up */
00438         GC_greatest_plausible_heap_addr =
00439             GC_max(GC_greatest_plausible_heap_addr,
00440                    (ptr_t)space + bytes + expansion_slop);
00441     } else {
00442         /* Heap is growing down */
00443         GC_least_plausible_heap_addr =
00444             GC_min(GC_least_plausible_heap_addr,
00445                    (ptr_t)space - expansion_slop);
00446     }
00447     GC_prev_heap_addr = GC_last_heap_addr;
00448     GC_last_heap_addr = (ptr_t)space;
00449     GC_add_to_heap(space, bytes);
00450     return(TRUE);
00451 }
00452 
00453 /* Really returns a bool, but it's externally visible, so that's clumsy. */
00454 int GC_expand_hp(n)
00455 int n;
00456 {
00457     int result;
00458     DCL_LOCK_STATE;
00459     
00460     DISABLE_SIGNALS();
00461     LOCK();
00462     if (!GC_is_initialized) GC_init_inner();
00463     result = (int)GC_expand_hp_inner((word)n);
00464     UNLOCK();
00465     ENABLE_SIGNALS();
00466     return(result);
00467 }
00468 
00469 void GC_collect_or_expand(needed_blocks)
00470 word needed_blocks;
00471 {
00472     static int count = 0;  /* How many failures? */
00473     
00474     if (GC_dont_gc || !GC_gcollect_inner(FALSE)) {
00475       if (!GC_expand_hp_inner(GC_hincr + needed_blocks)
00476         && !GC_expand_hp_inner(needed_blocks)) {
00477         if (count++ < 20) {
00478             WARN("Out of Memory!  Trying to continue ...\n");
00479             GC_gcollect_inner(TRUE);
00480         } else {
00481             GC_err_printf0("Out of Memory!  Giving up!\n");
00482             EXIT();
00483         }
00484       }
00485       update_GC_hincr;
00486     }
00487 }
00488 
00489 /*
00490  * Make sure the object free list for sz is not empty.
00491  * Return a pointer to the first object on the free list.
00492  * The object MUST BE REMOVED FROM THE FREE LIST BY THE CALLER.
00493  *
00494  */
00495 ptr_t GC_allocobj(sz, kind)
00496 word sz;
00497 int kind;
00498 {
00499     register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
00500     
00501     if (sz == 0) return(0);
00502 
00503     while (*flh == 0) {
00504       GC_continue_reclaim(sz, kind);
00505       if (*flh == 0) {
00506         GC_new_hblk(sz, kind);
00507       }
00508       if (*flh == 0) {
00509         GC_collect_or_expand((word)1);
00510       }
00511     }
00512     return(*flh);
00513 }

Generated on Fri Jan 25 10:39:45 2008 for russell by  doxygen 1.5.4