LCOV - code coverage report
Current view: top level - mm/boehm-gc - blacklst.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 82 101 81.2 %
Date: 2017-07-14 10:03:36 Functions: 9 12 75.0 %

          Line data    Source code
       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             : 
      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, even though 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             : STATIC word * GC_old_normal_bl = NULL;
      41             :                 /* Nonstack false references seen at last full          */
      42             :                 /* collection.                                          */
      43             : STATIC word * GC_incomplete_normal_bl = NULL;
      44             :                 /* Nonstack false references seen since last            */
      45             :                 /* full collection.                                     */
      46             : STATIC word * GC_old_stack_bl = NULL;
      47             : STATIC word * GC_incomplete_stack_bl = NULL;
      48             : 
      49             : STATIC word GC_total_stack_black_listed = 0;
      50             :                         /* Number of bytes on stack blacklist.  */
      51             : 
      52             : GC_INNER word GC_black_list_spacing = MINHINCR * HBLKSIZE;
      53             :                         /* Initial rough guess. */
      54             : 
      55             : STATIC void GC_clear_bl(word *);
      56             : 
      57           0 : GC_INNER void GC_default_print_heap_obj_proc(ptr_t p)
      58             : {
      59           0 :     ptr_t base = GC_base(p);
      60           0 :     int kind = HDR(base)->hb_obj_kind;
      61             : 
      62           0 :     GC_err_printf("object at %p of appr. %lu bytes (%s)\n",
      63             :                   base, (unsigned long)GC_size(base),
      64             :                   kind == PTRFREE ? "atomic" :
      65           0 :                     IS_UNCOLLECTABLE(kind) ? "uncollectable" : "composite");
      66           0 : }
      67             : 
      68             : GC_INNER void (*GC_print_heap_obj)(ptr_t p) = GC_default_print_heap_obj_proc;
      69             : 
      70             : #ifdef PRINT_BLACK_LIST
      71             :   STATIC void GC_print_blacklisted_ptr(word p, ptr_t source,
      72             :                                        const char *kind_str)
      73             :   {
      74             :     ptr_t base = GC_base(source);
      75             : 
      76             :     if (0 == base) {
      77             :         GC_err_printf("Black listing (%s) %p referenced from %p in %s\n",
      78             :                       kind_str, (ptr_t)p, source,
      79             :                       NULL != source ? "root set" : "register");
      80             :     } else {
      81             :         /* FIXME: We can't call the debug version of GC_print_heap_obj  */
      82             :         /* (with PRINT_CALL_CHAIN) here because the lock is held and    */
      83             :         /* the world is stopped.                                        */
      84             :         GC_err_printf("Black listing (%s) %p referenced from %p in"
      85             :                       " object at %p of appr. %lu bytes\n",
      86             :                       kind_str, (ptr_t)p, source,
      87             :                       base, (unsigned long)GC_size(base));
      88             :     }
      89             :   }
      90             : #endif /* PRINT_BLACK_LIST */
      91             : 
      92         163 : GC_INNER void GC_bl_init_no_interiors(void)
      93             : {
      94         163 :   if (GC_incomplete_normal_bl == 0) {
      95         163 :     GC_old_normal_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
      96         163 :     GC_incomplete_normal_bl = (word *)GC_scratch_alloc(
      97             :                                                   sizeof(page_hash_table));
      98         163 :     if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
      99           0 :       GC_err_printf("Insufficient memory for black list\n");
     100           0 :       EXIT();
     101             :     }
     102         163 :     GC_clear_bl(GC_old_normal_bl);
     103         163 :     GC_clear_bl(GC_incomplete_normal_bl);
     104             :   }
     105         163 : }
     106             : 
     107         163 : GC_INNER void GC_bl_init(void)
     108             : {
     109         163 :     if (!GC_all_interior_pointers) {
     110         163 :       GC_bl_init_no_interiors();
     111             :     }
     112         163 :     GC_old_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
     113         163 :     GC_incomplete_stack_bl = (word *)GC_scratch_alloc(sizeof(page_hash_table));
     114         163 :     if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
     115           0 :         GC_err_printf("Insufficient memory for black list\n");
     116           0 :         EXIT();
     117             :     }
     118         163 :     GC_clear_bl(GC_old_stack_bl);
     119         163 :     GC_clear_bl(GC_incomplete_stack_bl);
     120         163 : }
     121             : 
     122        1140 : STATIC void GC_clear_bl(word *doomed)
     123             : {
     124        1140 :     BZERO(doomed, sizeof(page_hash_table));
     125        1140 : }
     126             : 
     127           0 : STATIC void GC_copy_bl(word *old, word *new)
     128             : {
     129           0 :     BCOPY(old, new, sizeof(page_hash_table));
     130           0 : }
     131             : 
     132             : static word total_stack_black_listed(void);
     133             : 
     134             : /* Signal the completion of a collection.  Turn the incomplete black    */
     135             : /* lists into new black lists, etc.                                     */
     136         244 : GC_INNER void GC_promote_black_lists(void)
     137             : {
     138         244 :     word * very_old_normal_bl = GC_old_normal_bl;
     139         244 :     word * very_old_stack_bl = GC_old_stack_bl;
     140             : 
     141         244 :     GC_old_normal_bl = GC_incomplete_normal_bl;
     142         244 :     GC_old_stack_bl = GC_incomplete_stack_bl;
     143         244 :     if (!GC_all_interior_pointers) {
     144         244 :       GC_clear_bl(very_old_normal_bl);
     145             :     }
     146         244 :     GC_clear_bl(very_old_stack_bl);
     147         244 :     GC_incomplete_normal_bl = very_old_normal_bl;
     148         244 :     GC_incomplete_stack_bl = very_old_stack_bl;
     149         244 :     GC_total_stack_black_listed = total_stack_black_listed();
     150         244 :     GC_VERBOSE_LOG_PRINTF(
     151             :                 "%lu bytes in heap blacklisted for interior pointers\n",
     152             :                 (unsigned long)GC_total_stack_black_listed);
     153         244 :     if (GC_total_stack_black_listed != 0) {
     154          16 :         GC_black_list_spacing =
     155          16 :                 HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
     156             :     }
     157         244 :     if (GC_black_list_spacing < 3 * HBLKSIZE) {
     158           0 :         GC_black_list_spacing = 3 * HBLKSIZE;
     159             :     }
     160         244 :     if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
     161           1 :         GC_black_list_spacing = MAXHINCR * HBLKSIZE;
     162             :         /* Makes it easier to allocate really huge blocks, which otherwise */
     163             :         /* may have problems with nonuniform blacklist distributions.      */
     164             :         /* This way we should always succeed immediately after growing the */
     165             :         /* heap.                                                           */
     166             :     }
     167         244 : }
     168             : 
     169           0 : GC_INNER void GC_unpromote_black_lists(void)
     170             : {
     171           0 :     if (!GC_all_interior_pointers) {
     172           0 :       GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
     173             :     }
     174           0 :     GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl);
     175           0 : }
     176             : 
     177             : /* P is not a valid pointer reference, but it falls inside      */
     178             : /* the plausible heap bounds.                                   */
     179             : /* Add it to the normal incomplete black list if appropriate.   */
     180             : #ifdef PRINT_BLACK_LIST
     181             :   GC_INNER void GC_add_to_black_list_normal(word p, ptr_t source)
     182             : #else
     183      598770 :   GC_INNER void GC_add_to_black_list_normal(word p)
     184             : #endif
     185             : {
     186      598770 :   if (GC_modws_valid_offsets[p & (sizeof(word)-1)]) {
     187      582721 :     word index = PHT_HASH((word)p);
     188             : 
     189      582721 :     if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
     190             : #     ifdef PRINT_BLACK_LIST
     191             :         if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
     192             :           GC_print_blacklisted_ptr(p, source, "normal");
     193             :         }
     194             : #     endif
     195      612197 :       set_pht_entry_from_index(GC_incomplete_normal_bl, index);
     196             :     } /* else this is probably just an interior pointer to an allocated */
     197             :       /* object, and isn't worth black listing.                         */
     198             :   }
     199      647775 : }
     200             : 
     201             : /* And the same for false pointers from the stack. */
     202             : #ifdef PRINT_BLACK_LIST
     203             :   GC_INNER void GC_add_to_black_list_stack(word p, ptr_t source)
     204             : #else
     205        4534 :   GC_INNER void GC_add_to_black_list_stack(word p)
     206             : #endif
     207             : {
     208        4534 :   word index = PHT_HASH((word)p);
     209             : 
     210        4534 :   if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
     211             : #   ifdef PRINT_BLACK_LIST
     212             :       if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
     213             :         GC_print_blacklisted_ptr(p, source, "stack");
     214             :       }
     215             : #   endif
     216        4534 :     set_pht_entry_from_index(GC_incomplete_stack_bl, index);
     217             :   }
     218        4534 : }
     219             : 
     220             : /*
     221             :  * Is the block starting at h of size len bytes black listed?   If so,
     222             :  * return the address of the next plausible r such that (r, len) might not
     223             :  * be black listed.  (R may not actually be in the heap.  We guarantee only
     224             :  * that every smaller value of r after h is also black listed.)
     225             :  * If (h,len) is not black listed, return 0.
     226             :  * Knows about the structure of the black list hash tables.
     227             :  */
     228       34322 : struct hblk * GC_is_black_listed(struct hblk *h, word len)
     229             : {
     230       34322 :     word index = PHT_HASH((word)h);
     231             :     word i;
     232             :     word nblocks;
     233             : 
     234      102947 :     if (!GC_all_interior_pointers
     235       34322 :         && (get_pht_entry_from_index(GC_old_normal_bl, index)
     236       34303 :             || get_pht_entry_from_index(GC_incomplete_normal_bl, index))) {
     237          31 :       return (h+1);
     238             :     }
     239             : 
     240       34291 :     nblocks = divHBLKSZ(len);
     241       34291 :     for (i = 0;;) {
     242      100969 :         if (GC_old_stack_bl[divWORDSZ(index)] == 0
     243       34473 :             && GC_incomplete_stack_bl[divWORDSZ(index)] == 0) {
     244             :             /* An easy case */
     245       31806 :           i += WORDSZ - modWORDSZ(index);
     246             :         } else {
     247        5765 :           if (get_pht_entry_from_index(GC_old_stack_bl, index)
     248        2881 :               || get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
     249          11 :             return(h+i+1);
     250             :           }
     251        2873 :           i++;
     252             :         }
     253       34679 :         if (i >= nblocks) break;
     254         399 :         index = PHT_HASH((word)(h+i));
     255         399 :     }
     256       34280 :     return(0);
     257             : }
     258             : 
     259             : /* Return the number of blacklisted blocks in a given range.    */
     260             : /* Used only for statistical purposes.                          */
     261             : /* Looks only at the GC_incomplete_stack_bl.                    */
     262         489 : STATIC word GC_number_stack_black_listed(struct hblk *start,
     263             :                                          struct hblk *endp1)
     264             : {
     265             :     register struct hblk * h;
     266         489 :     word result = 0;
     267             : 
     268      142428 :     for (h = start; (word)h < (word)endp1; h++) {
     269      141939 :         word index = PHT_HASH((word)h);
     270             : 
     271      141939 :         if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
     272             :     }
     273         489 :     return(result);
     274             : }
     275             : 
     276             : /* Return the total number of (stack) black-listed bytes. */
     277         244 : static word total_stack_black_listed(void)
     278             : {
     279             :     register unsigned i;
     280         244 :     word total = 0;
     281             : 
     282         733 :     for (i = 0; i < GC_n_heap_sects; i++) {
     283         489 :         struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
     284         489 :         struct hblk * endp1 = start + GC_heap_sects[i].hs_bytes/HBLKSIZE;
     285             : 
     286         489 :         total += GC_number_stack_black_listed(start, endp1);
     287             :     }
     288         244 :     return(total * HBLKSIZE);
     289             : }

Generated by: LCOV version 1.11