LCOV - code coverage report
Current view: top level - mm/boehm-gc - headers.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 149 176 84.7 %
Date: 2015-06-10 18:10:59 Functions: 14 14 100.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             :  * Copyright (c) 1996 by Silicon Graphics.  All rights reserved.
       5             :  *
       6             :  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
       7             :  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
       8             :  *
       9             :  * Permission is hereby granted to use or copy this program
      10             :  * for any purpose,  provided the above notices are retained on all copies.
      11             :  * Permission to modify the code and to distribute modified code is granted,
      12             :  * provided the above notices are retained, and a notice that the code was
      13             :  * modified is included with the above copyright notice.
      14             :  */
      15             : 
      16             : #include "private/gc_priv.h"
      17             : 
      18             : /*
      19             :  * This implements:
      20             :  * 1. allocation of heap block headers
      21             :  * 2. A map from addresses to heap block addresses to heap block headers
      22             :  *
      23             :  * Access speed is crucial.  We implement an index structure based on a 2
      24             :  * level tree.
      25             :  */
      26             : 
      27             : STATIC bottom_index * GC_all_bottom_indices = 0;
      28             :                                 /* Pointer to first (lowest addr) */
      29             :                                 /* bottom_index.                  */
      30             : 
      31             : STATIC bottom_index * GC_all_bottom_indices_end = 0;
      32             :                                 /* Pointer to last (highest addr) */
      33             :                                 /* bottom_index.                  */
      34             : 
      35             : /* Non-macro version of header location routine */
      36     1372854 : GC_INNER hdr * GC_find_header(ptr_t h)
      37             : {
      38             : #   ifdef HASH_TL
      39             :         hdr * result;
      40     1372854 :         GET_HDR(h, result);
      41     1372854 :         return(result);
      42             : #   else
      43             :         return(HDR_INNER(h));
      44             : #   endif
      45             : }
      46             : 
      47             : /* Handle a header cache miss.  Returns a pointer to the        */
      48             : /* header corresponding to p, if p can possibly be a valid      */
      49             : /* object pointer, and 0 otherwise.                             */
      50             : /* GUARANTEED to return 0 for a pointer past the first page     */
      51             : /* of an object unless both GC_all_interior_pointers is set     */
      52             : /* and p is in fact a valid object pointer.                     */
      53             : /* Never returns a pointer to a free hblk.                      */
      54             : GC_INNER hdr *
      55             : #ifdef PRINT_BLACK_LIST
      56             :   GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce, ptr_t source)
      57             : #else
      58     1335041 :   GC_header_cache_miss(ptr_t p, hdr_cache_entry *hce)
      59             : #endif
      60             : {
      61             :   hdr *hhdr;
      62             :   HC_MISS();
      63     1335041 :   GET_HDR(p, hhdr);
      64     1335041 :   if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
      65      925491 :     if (GC_all_interior_pointers) {
      66           0 :       if (hhdr != 0) {
      67           0 :         ptr_t current = p;
      68             : 
      69           0 :         current = (ptr_t)HBLKPTR(current);
      70             :         do {
      71           0 :             current = current - HBLKSIZE*(word)hhdr;
      72           0 :             hhdr = HDR(current);
      73           0 :         } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
      74             :         /* current points to near the start of the large object */
      75           0 :         if (hhdr -> hb_flags & IGNORE_OFF_PAGE)
      76           0 :             return 0;
      77           0 :         if (HBLK_IS_FREE(hhdr)
      78           0 :             || p - current >= (ptrdiff_t)(hhdr->hb_sz)) {
      79           0 :             GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
      80             :             /* Pointer past the end of the block */
      81           0 :             return 0;
      82             :         }
      83             :       } else {
      84           0 :         GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
      85             :         /* And return zero: */
      86             :       }
      87             :       GC_ASSERT(hhdr == 0 || !HBLK_IS_FREE(hhdr));
      88           0 :       return hhdr;
      89             :       /* Pointers past the first page are probably too rare     */
      90             :       /* to add them to the cache.  We don't.                   */
      91             :       /* And correctness relies on the fact that we don't.      */
      92             :     } else {
      93      925491 :       if (hhdr == 0) {
      94      925486 :         GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
      95             :       }
      96      925491 :       return 0;
      97             :     }
      98             :   } else {
      99      409550 :     if (HBLK_IS_FREE(hhdr)) {
     100         770 :       GC_ADD_TO_BLACK_LIST_NORMAL(p, source);
     101         770 :       return 0;
     102             :     } else {
     103      408780 :       hce -> block_addr = (word)(p) >> LOG_HBLKSIZE;
     104      408780 :       hce -> hce_hdr = hhdr;
     105      408780 :       return hhdr;
     106             :     }
     107             :   }
     108             : }
     109             : 
     110             : /* Routines to dynamically allocate collector data structures that will */
     111             : /* never be freed.                                                       */
     112             : 
     113             : static ptr_t scratch_free_ptr = 0;
     114             : 
     115             : /* GC_scratch_last_end_ptr is end point of last obtained scratch area.  */
     116             : /* GC_scratch_end_ptr is end point of current scratch area.             */
     117             : 
     118       43662 : GC_INNER ptr_t GC_scratch_alloc(size_t bytes)
     119             : {
     120       43662 :     register ptr_t result = scratch_free_ptr;
     121             : 
     122       43662 :     bytes += GRANULE_BYTES-1;
     123       43662 :     bytes &= ~(GRANULE_BYTES-1);
     124       43662 :     scratch_free_ptr += bytes;
     125       43662 :     if (scratch_free_ptr <= GC_scratch_end_ptr) {
     126       42823 :         return(result);
     127             :     }
     128             :     {
     129         839 :         word bytes_to_get = MINHINCR * HBLKSIZE;
     130             : 
     131         839 :         if (bytes_to_get <= bytes) {
     132             :           /* Undo the damage, and get memory directly */
     133         169 :             bytes_to_get = bytes;
     134             : #           ifdef USE_MMAP
     135             :                 bytes_to_get += GC_page_size - 1;
     136             :                 bytes_to_get &= ~(GC_page_size - 1);
     137             : #           endif
     138         169 :             result = (ptr_t)GET_MEM(bytes_to_get);
     139             :             GC_add_to_our_memory(result, bytes_to_get);
     140         169 :             scratch_free_ptr -= bytes;
     141         169 :             GC_scratch_last_end_ptr = result + bytes;
     142         169 :             return(result);
     143             :         }
     144         670 :         result = (ptr_t)GET_MEM(bytes_to_get);
     145             :         GC_add_to_our_memory(result, bytes_to_get);
     146         670 :         if (result == 0) {
     147           0 :             if (GC_print_stats)
     148           0 :                 GC_log_printf("Out of memory - trying to allocate less\n");
     149           0 :             scratch_free_ptr -= bytes;
     150           0 :             bytes_to_get = bytes;
     151             : #           ifdef USE_MMAP
     152             :                 bytes_to_get += GC_page_size - 1;
     153             :                 bytes_to_get &= ~(GC_page_size - 1);
     154             : #           endif
     155           0 :             result = (ptr_t)GET_MEM(bytes_to_get);
     156             :             GC_add_to_our_memory(result, bytes_to_get);
     157           0 :             return result;
     158             :         }
     159         670 :         scratch_free_ptr = result;
     160         670 :         GC_scratch_end_ptr = scratch_free_ptr + bytes_to_get;
     161         670 :         GC_scratch_last_end_ptr = GC_scratch_end_ptr;
     162         670 :         return(GC_scratch_alloc(bytes));
     163             :     }
     164             : }
     165             : 
     166             : static hdr * hdr_free_list = 0;
     167             : 
     168             : /* Return an uninitialized header */
     169       49177 : static hdr * alloc_hdr(void)
     170             : {
     171             :     register hdr * result;
     172             : 
     173       49177 :     if (hdr_free_list == 0) {
     174       37220 :         result = (hdr *) GC_scratch_alloc((word)(sizeof(hdr)));
     175             :     } else {
     176       11957 :         result = hdr_free_list;
     177       11957 :         hdr_free_list = (hdr *) (result -> hb_next);
     178             :     }
     179       49177 :     return(result);
     180             : }
     181             : 
     182       27529 : GC_INLINE void free_hdr(hdr * hhdr)
     183             : {
     184       27529 :     hhdr -> hb_next = (struct hblk *) hdr_free_list;
     185       27529 :     hdr_free_list = hhdr;
     186       27529 : }
     187             : 
     188             : #ifdef COUNT_HDR_CACHE_HITS
     189             :   /* Used for debugging/profiling (the symbols are externally visible). */
     190             :   word GC_hdr_cache_hits = 0;
     191             :   word GC_hdr_cache_misses = 0;
     192             : #endif
     193             : 
     194         163 : GC_INNER void GC_init_headers(void)
     195             : {
     196             :     register unsigned i;
     197             : 
     198         163 :     GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index));
     199         163 :     if (GC_all_nils == NULL) {
     200           0 :       GC_err_printf("Insufficient memory for GC_all_nils\n");
     201           0 :       EXIT();
     202             :     }
     203         163 :     BZERO(GC_all_nils, sizeof(bottom_index));
     204      333987 :     for (i = 0; i < TOP_SZ; i++) {
     205      333824 :         GC_top_index[i] = GC_all_nils;
     206             :     }
     207         163 : }
     208             : 
     209             : /* Make sure that there is a bottom level index block for address addr  */
     210             : /* Return FALSE on failure.                                             */
     211      153375 : static GC_bool get_index(word addr)
     212             : {
     213      153375 :     word hi = (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
     214             :     bottom_index * r;
     215             :     bottom_index * p;
     216             :     bottom_index ** prev;
     217             :     bottom_index *pi;
     218             : 
     219             : #   ifdef HASH_TL
     220      153375 :       word i = TL_HASH(hi);
     221             :       bottom_index * old;
     222             : 
     223      153375 :       old = p = GC_top_index[i];
     224      306750 :       while(p != GC_all_nils) {
     225      153151 :           if (p -> key == hi) return(TRUE);
     226           0 :           p = p -> hash_link;
     227             :       }
     228         224 :       r = (bottom_index*)GC_scratch_alloc((word)(sizeof (bottom_index)));
     229         224 :       if (r == 0) return(FALSE);
     230         224 :       BZERO(r, sizeof (bottom_index));
     231         224 :       r -> hash_link = old;
     232         224 :       GC_top_index[i] = r;
     233             : #   else
     234             :       if (GC_top_index[hi] != GC_all_nils) return(TRUE);
     235             :       r = (bottom_index*)GC_scratch_alloc((word)(sizeof (bottom_index)));
     236             :       if (r == 0) return(FALSE);
     237             :       GC_top_index[hi] = r;
     238             :       BZERO(r, sizeof (bottom_index));
     239             : #   endif
     240         224 :     r -> key = hi;
     241             :     /* Add it to the list of bottom indices */
     242         224 :       prev = &GC_all_bottom_indices;    /* pointer to p */
     243         224 :       pi = 0;                           /* bottom_index preceding p */
     244         825 :       while ((p = *prev) != 0 && p -> key < hi) {
     245         377 :         pi = p;
     246         377 :         prev = &(p -> asc_link);
     247             :       }
     248         224 :       r -> desc_link = pi;
     249         224 :       if (0 == p) {
     250         209 :         GC_all_bottom_indices_end = r;
     251             :       } else {
     252          15 :         p -> desc_link = r;
     253             :       }
     254         224 :       r -> asc_link = p;
     255         224 :       *prev = r;
     256         224 :     return(TRUE);
     257             : }
     258             : 
     259             : /* Install a header for block h.        */
     260             : /* The header is uninitialized.         */
     261             : /* Returns the header or 0 on failure.  */
     262       49177 : GC_INNER struct hblkhdr * GC_install_header(struct hblk *h)
     263             : {
     264             :     hdr * result;
     265             : 
     266       49177 :     if (!get_index((word) h)) return(0);
     267       49177 :     result = alloc_hdr();
     268       49177 :     if (result) {
     269       49177 :       SET_HDR(h, result);
     270             : #     ifdef USE_MUNMAP
     271             :         result -> hb_last_reclaimed = (unsigned short)GC_gc_no;
     272             : #     endif
     273             :     }
     274       49177 :     return(result);
     275             : }
     276             : 
     277             : /* Set up forwarding counts for block h of size sz */
     278       52091 : GC_INNER GC_bool GC_install_counts(struct hblk *h, size_t sz/* bytes */)
     279             : {
     280             :     struct hblk * hbp;
     281             :     word i;
     282             : 
     283      104198 :     for (hbp = h; (char *)hbp < (char *)h + sz; hbp += BOTTOM_SZ) {
     284       52107 :         if (!get_index((word) hbp)) return(FALSE);
     285             :     }
     286       52091 :     if (!get_index((word)h + sz - 1)) return(FALSE);
     287       77394 :     for (hbp = h + 1; (char *)hbp < (char *)h + sz; hbp += 1) {
     288       25303 :         i = HBLK_PTR_DIFF(hbp, h);
     289       25303 :         SET_HDR(hbp, (hdr *)(i > MAX_JUMP? MAX_JUMP : i));
     290             :     }
     291       52091 :     return(TRUE);
     292             : }
     293             : 
     294             : /* Remove the header for block h */
     295       27529 : GC_INNER void GC_remove_header(struct hblk *h)
     296             : {
     297             :     hdr **ha;
     298       27529 :     GET_HDR_ADDR(h, ha);
     299       27529 :     free_hdr(*ha);
     300       27529 :     *ha = 0;
     301       27529 : }
     302             : 
     303             : /* Remove forwarding counts for h */
     304       31050 : GC_INNER void GC_remove_counts(struct hblk *h, size_t sz/* bytes */)
     305             : {
     306             :     register struct hblk * hbp;
     307      159134 :     for (hbp = h+1; (char *)hbp < (char *)h + sz; hbp += 1) {
     308      128084 :         SET_HDR(hbp, 0);
     309             :     }
     310       31050 : }
     311             : 
     312             : /* Apply fn to all allocated blocks */
     313             : /*VARARGS1*/
     314         504 : void GC_apply_to_all_blocks(void (*fn)(struct hblk *h, word client_data),
     315             :                             word client_data)
     316             : {
     317             :     signed_word j;
     318             :     bottom_index * index_p;
     319             : 
     320        1836 :     for (index_p = GC_all_bottom_indices; index_p != 0;
     321         828 :          index_p = index_p -> asc_link) {
     322      763948 :         for (j = BOTTOM_SZ-1; j >= 0;) {
     323      762292 :             if (!IS_FORWARDING_ADDR_OR_NIL(index_p->index[j])) {
     324      154564 :                 if (!HBLK_IS_FREE(index_p->index[j])) {
     325      152798 :                     (*fn)(((struct hblk *)
     326      152798 :                               (((index_p->key << LOG_BOTTOM_SZ) + (word)j)
     327             :                                << LOG_HBLKSIZE)),
     328             :                           client_data);
     329             :                 }
     330      154564 :                 j--;
     331      607728 :              } else if (index_p->index[j] == 0) {
     332      604862 :                 j--;
     333             :              } else {
     334        2866 :                 j -= (signed_word)(index_p->index[j]);
     335             :              }
     336             :          }
     337             :      }
     338         504 : }
     339             : 
     340             : /* Get the next valid block whose address is at least h */
     341             : /* Return 0 if there is none.                           */
     342        1115 : GC_INNER struct hblk * GC_next_used_block(struct hblk *h)
     343             : {
     344             :     register bottom_index * bi;
     345        1115 :     register word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
     346             : 
     347        1115 :     GET_BI(h, bi);
     348        1115 :     if (bi == GC_all_nils) {
     349         258 :         register word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
     350         258 :         bi = GC_all_bottom_indices;
     351         258 :         while (bi != 0 && bi -> key < hi) bi = bi -> asc_link;
     352         258 :         j = 0;
     353             :     }
     354        2545 :     while(bi != 0) {
     355      297644 :         while (j < BOTTOM_SZ) {
     356      296157 :             hdr * hhdr = bi -> index[j];
     357      296157 :             if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
     358      294406 :                 j++;
     359             :             } else {
     360        1751 :                 if (!HBLK_IS_FREE(hhdr)) {
     361         857 :                     return((struct hblk *)
     362         857 :                               (((bi -> key << LOG_BOTTOM_SZ) + j)
     363             :                                << LOG_HBLKSIZE));
     364             :                 } else {
     365         894 :                     j += divHBLKSZ(hhdr -> hb_sz);
     366             :                 }
     367             :             }
     368             :         }
     369         315 :         j = 0;
     370         315 :         bi = bi -> asc_link;
     371             :     }
     372         258 :     return(0);
     373             : }
     374             : 
     375             : /* Get the last (highest address) block whose address is        */
     376             : /* at most h.  Return 0 if there is none.                       */
     377             : /* Unlike the above, this may return a free block.              */
     378         424 : GC_INNER struct hblk * GC_prev_block(struct hblk *h)
     379             : {
     380             :     register bottom_index * bi;
     381         424 :     register signed_word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
     382             : 
     383         424 :     GET_BI(h, bi);
     384         424 :     if (bi == GC_all_nils) {
     385           0 :         register word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
     386           0 :         bi = GC_all_bottom_indices_end;
     387           0 :         while (bi != 0 && bi -> key > hi) bi = bi -> desc_link;
     388           0 :         j = BOTTOM_SZ - 1;
     389             :     }
     390        1034 :     while(bi != 0) {
     391      118698 :         while (j >= 0) {
     392      118067 :             hdr * hhdr = bi -> index[j];
     393      118067 :             if (0 == hhdr) {
     394      117807 :                 --j;
     395         260 :             } else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
     396           1 :                 j -= (signed_word)hhdr;
     397             :             } else {
     398         259 :                 return((struct hblk *)
     399         259 :                           (((bi -> key << LOG_BOTTOM_SZ) + j)
     400             :                                << LOG_HBLKSIZE));
     401             :             }
     402             :         }
     403         186 :         j = BOTTOM_SZ - 1;
     404         186 :         bi = bi -> desc_link;
     405             :     }
     406         165 :     return(0);
     407             : }

Generated by: LCOV version 1.11