root/gc/blacklst.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GC_default_print_heap_obj_proc
  2. GC_print_source_ptr
  3. GC_bl_init
  4. GC_clear_bl
  5. GC_copy_bl
  6. GC_promote_black_lists
  7. GC_unpromote_black_lists
  8. GC_add_to_black_list_normal
  9. GC_add_to_black_list_stack
  10. GC_is_black_listed
  11. GC_number_stack_black_listed
  12. total_stack_black_listed

   1 /* 
   2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
   3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
   4  *
   5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
   6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
   7  *
   8  * Permission is hereby granted to use or copy this program
   9  * for any purpose,  provided the above notices are retained on all copies.
  10  * Permission to modify the code and to distribute modified code is granted,
  11  * provided the above notices are retained, and a notice that the code was
  12  * modified is included with the above copyright notice.
  13  */
  14 /* Boehm, August 9, 1995 6:09 pm PDT */
  15 # include "private/gc_priv.h"
  16 
  17 /*
  18  * We maintain several hash tables of hblks that have had false hits.
  19  * Each contains one bit per hash bucket;  If any page in the bucket
  20  * has had a false hit, we assume that all of them have.
  21  * See the definition of page_hash_table in gc_private.h.
  22  * False hits from the stack(s) are much more dangerous than false hits
  23  * from elsewhere, since the former can pin a large object that spans the
  24  * block, eventhough it does not start on the dangerous block.
  25  */
  26  
  27 /*
  28  * Externally callable routines are:
  29  
  30  * GC_add_to_black_list_normal
  31  * GC_add_to_black_list_stack
  32  * GC_promote_black_lists
  33  * GC_is_black_listed
  34  *
  35  * All require that the allocator lock is held.
  36  */
  37 
  38 /* Pointers to individual tables.  We replace one table by another by   */
  39 /* switching these pointers.                                            */
  40 word * GC_old_normal_bl;
  41                 /* Nonstack false references seen at last full          */
  42                 /* collection.                                          */
  43 word * GC_incomplete_normal_bl;
  44                 /* Nonstack false references seen since last            */
  45                 /* full collection.                                     */
  46 word * GC_old_stack_bl;
  47 word * GC_incomplete_stack_bl;
  48 
  49 word GC_total_stack_black_listed;
  50 
  51 word GC_black_list_spacing = MINHINCR*HBLKSIZE;  /* Initial rough guess */
  52 
  53 void GC_clear_bl();
  54 
  55 # if defined(__STDC__) || defined(__cplusplus)
  56     void GC_default_print_heap_obj_proc(ptr_t p)
  57 # else
  58     void GC_default_print_heap_obj_proc(p)
  59     ptr_t p;
  60 # endif
  61 {
  62     ptr_t base = GC_base(p);
  63 
  64     GC_err_printf2("start: 0x%lx, appr. length: %ld", base, GC_size(base));
  65 }
  66 
  67 void (*GC_print_heap_obj) GC_PROTO((ptr_t p)) =
  68                                 GC_default_print_heap_obj_proc;
  69 
  70 void GC_print_source_ptr(p)
  71 ptr_t p;
  72 {
  73     ptr_t base = GC_base(p);
  74     if (0 == base) {
  75         if (0 == p) {
  76             GC_err_printf0("in register");
  77         } else {
  78             GC_err_printf0("in root set");
  79         }
  80     } else {
  81         GC_err_printf0("in object at ");
  82         (*GC_print_heap_obj)(base);
  83     }
  84 }
  85 
  86 void GC_bl_init()
  87 {
  88     if (!GC_all_interior_pointers) {
  89       GC_old_normal_bl = (word *)
  90                          GC_scratch_alloc((word)(sizeof (page_hash_table)));
  91       GC_incomplete_normal_bl = (word *)GC_scratch_alloc
  92                                         ((word)(sizeof(page_hash_table)));
  93       if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
  94         GC_err_printf0("Insufficient memory for black list\n");
  95         EXIT();
  96       }
  97       GC_clear_bl(GC_old_normal_bl);
  98       GC_clear_bl(GC_incomplete_normal_bl);
  99     }
 100     GC_old_stack_bl = (word *)GC_scratch_alloc((word)(sizeof(page_hash_table)));
 101     GC_incomplete_stack_bl = (word *)GC_scratch_alloc
 102                                         ((word)(sizeof(page_hash_table)));
 103     if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
 104         GC_err_printf0("Insufficient memory for black list\n");
 105         EXIT();
 106     }
 107     GC_clear_bl(GC_old_stack_bl);
 108     GC_clear_bl(GC_incomplete_stack_bl);
 109 }
 110                 
 111 void GC_clear_bl(doomed)
 112 word *doomed;
 113 {
 114     BZERO(doomed, sizeof(page_hash_table));
 115 }
 116 
 117 void GC_copy_bl(old, new)
 118 word *new, *old;
 119 {
 120     BCOPY(old, new, sizeof(page_hash_table));
 121 }
 122 
 123 static word total_stack_black_listed();
 124 
 125 /* Signal the completion of a collection.  Turn the incomplete black    */
 126 /* lists into new black lists, etc.                                     */                       
 127 void GC_promote_black_lists()
 128 {
 129     word * very_old_normal_bl = GC_old_normal_bl;
 130     word * very_old_stack_bl = GC_old_stack_bl;
 131     
 132     GC_old_normal_bl = GC_incomplete_normal_bl;
 133     GC_old_stack_bl = GC_incomplete_stack_bl;
 134     if (!GC_all_interior_pointers) {
 135       GC_clear_bl(very_old_normal_bl);
 136     }
 137     GC_clear_bl(very_old_stack_bl);
 138     GC_incomplete_normal_bl = very_old_normal_bl;
 139     GC_incomplete_stack_bl = very_old_stack_bl;
 140     GC_total_stack_black_listed = total_stack_black_listed();
 141 #   ifdef PRINTSTATS
 142         GC_printf1("%ld bytes in heap blacklisted for interior pointers\n",
 143                    (unsigned long)GC_total_stack_black_listed);
 144 #   endif
 145     if (GC_total_stack_black_listed != 0) {
 146         GC_black_list_spacing =
 147                 HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
 148     }
 149     if (GC_black_list_spacing < 3 * HBLKSIZE) {
 150         GC_black_list_spacing = 3 * HBLKSIZE;
 151     }
 152     if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
 153         GC_black_list_spacing = MAXHINCR * HBLKSIZE;
 154         /* Makes it easier to allocate really huge blocks, which otherwise */
 155         /* may have problems with nonuniform blacklist distributions.      */
 156         /* This way we should always succeed immediately after growing the */ 
 157         /* heap.                                                           */
 158     }
 159 }
 160 
 161 void GC_unpromote_black_lists()
 162 {
 163     if (!GC_all_interior_pointers) {
 164       GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
 165     }
 166     GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl);
 167 }
 168 
 169 /* P is not a valid pointer reference, but it falls inside      */
 170 /* the plausible heap bounds.                                   */
 171 /* Add it to the normal incomplete black list if appropriate.   */
 172 #ifdef PRINT_BLACK_LIST
 173   void GC_add_to_black_list_normal(p, source)
 174   ptr_t source;
 175 #else
 176   void GC_add_to_black_list_normal(p)
 177 #endif
 178 word p;
 179 {
 180     if (!(GC_modws_valid_offsets[p & (sizeof(word)-1)])) return;
 181     {
 182         register int index = PHT_HASH(p);
 183         
 184         if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
 185 #           ifdef PRINT_BLACK_LIST
 186                 if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
 187                   GC_err_printf2(
 188                         "Black listing (normal) 0x%lx referenced from 0x%lx ",
 189                         (unsigned long) p, (unsigned long) source);
 190                   GC_print_source_ptr(source);
 191                   GC_err_puts("\n");
 192                 }
 193 #           endif
 194             set_pht_entry_from_index(GC_incomplete_normal_bl, index);
 195         } /* else this is probably just an interior pointer to an allocated */
 196           /* object, and isn't worth black listing.                         */
 197     }
 198 }
 199 
 200 /* And the same for false pointers from the stack. */
 201 #ifdef PRINT_BLACK_LIST
 202   void GC_add_to_black_list_stack(p, source)
 203   ptr_t source;
 204 #else
 205   void GC_add_to_black_list_stack(p)
 206 #endif
 207 word p;
 208 {
 209     register int index = PHT_HASH(p);
 210         
 211     if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
 212 #       ifdef PRINT_BLACK_LIST
 213             if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
 214                   GC_err_printf2(
 215                         "Black listing (stack) 0x%lx referenced from 0x%lx ",
 216                         (unsigned long)p, (unsigned long)source);
 217                   GC_print_source_ptr(source);
 218                   GC_err_puts("\n");
 219             }
 220 #       endif
 221         set_pht_entry_from_index(GC_incomplete_stack_bl, index);
 222     }
 223 }
 224 
 225 /*
 226  * Is the block starting at h of size len bytes black listed?   If so,
 227  * return the address of the next plausible r such that (r, len) might not
 228  * be black listed.  (R may not actually be in the heap.  We guarantee only
 229  * that every smaller value of r after h is also black listed.)
 230  * If (h,len) is not black listed, return 0.
 231  * Knows about the structure of the black list hash tables.
 232  */
 233 struct hblk * GC_is_black_listed(h, len)
 234 struct hblk * h;
 235 word len;
 236 {
 237     register int index = PHT_HASH((word)h);
 238     register word i;
 239     word nblocks = divHBLKSZ(len);
 240 
 241     if (!GC_all_interior_pointers) {
 242       if (get_pht_entry_from_index(GC_old_normal_bl, index)
 243           || get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
 244         return(h+1);
 245       }
 246     }
 247     
 248     for (i = 0; ; ) {
 249         if (GC_old_stack_bl[divWORDSZ(index)] == 0
 250             && GC_incomplete_stack_bl[divWORDSZ(index)] == 0) {
 251             /* An easy case */
 252             i += WORDSZ - modWORDSZ(index);
 253         } else {
 254           if (get_pht_entry_from_index(GC_old_stack_bl, index)
 255               || get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
 256             return(h+i+1);
 257           }
 258           i++;
 259         }
 260         if (i >= nblocks) break;
 261         index = PHT_HASH((word)(h+i));
 262     }
 263     return(0);
 264 }
 265 
 266 
 267 /* Return the number of blacklisted blocks in a given range.    */
 268 /* Used only for statistical purposes.                          */
 269 /* Looks only at the GC_incomplete_stack_bl.                    */
 270 word GC_number_stack_black_listed(start, endp1)
 271 struct hblk *start, *endp1;
 272 {
 273     register struct hblk * h;
 274     word result = 0;
 275     
 276     for (h = start; h < endp1; h++) {
 277         register int index = PHT_HASH((word)h);
 278         
 279         if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
 280     }
 281     return(result);
 282 }
 283 
 284 
 285 /* Return the total number of (stack) black-listed bytes. */
 286 static word total_stack_black_listed()
 287 {
 288     register unsigned i;
 289     word total = 0;
 290     
 291     for (i = 0; i < GC_n_heap_sects; i++) {
 292         struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
 293         word len = (word) GC_heap_sects[i].hs_bytes;
 294         struct hblk * endp1 = start + len/HBLKSIZE;
 295         
 296         total += GC_number_stack_black_listed(start, endp1);
 297     }
 298     return(total * HBLKSIZE);
 299 }
 300 

/* [<][>][^][v][top][bottom][index][help] */