Back to index

plt-scheme  4.2.1
gc_hdrs.h
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  *
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 use or copy this program
00009  * for any purpose,  provided the above notices are retained on all copies.
00010  * Permission to modify the code and to distribute modified code is granted,
00011  * provided the above notices are retained, and a notice that the code was
00012  * modified is included with the above copyright notice.
00013  */
00014 /* Boehm, July 11, 1995 11:54 am PDT */
00015 # ifndef GC_HEADERS_H
00016 # define GC_HEADERS_H
00017 typedef struct hblkhdr hdr;
00018 
00019 # if CPP_WORDSZ != 32 && CPP_WORDSZ < 36
00020        --> Get a real machine.
00021 # endif
00022 
00023 /*
00024  * The 2 level tree data structure that is used to find block headers.
00025  * If there are more than 32 bits in a pointer, the top level is a hash
00026  * table.
00027  *
00028  * This defines HDR, GET_HDR, and SET_HDR, the main macros used to
00029  * retrieve and set object headers.
00030  *
00031  * Since 5.0 alpha 5, we can also take advantage of a header lookup
00032  * cache.  This is a locally declared direct mapped cache, used inside
00033  * the marker.  The HC_GET_HDR macro uses and maintains this
00034  * cache.  Assuming we get reasonable hit rates, this shaves a few
00035  * memory references from each pointer validation.
00036  */
00037 
00038 # if CPP_WORDSZ > 32
00039 #   define HASH_TL
00040 # endif
00041 
00042 /* Define appropriate out-degrees for each of the two tree levels     */
00043 # ifdef SMALL_CONFIG
00044 #   define LOG_BOTTOM_SZ 11
00045        /* Keep top index size reasonable with smaller blocks. */
00046 # else
00047 #   define LOG_BOTTOM_SZ 10
00048 # endif
00049 # ifndef HASH_TL
00050 #   define LOG_TOP_SZ (WORDSZ - LOG_BOTTOM_SZ - LOG_HBLKSIZE)
00051 # else
00052 #   define LOG_TOP_SZ 11
00053 # endif
00054 # define TOP_SZ (1 << LOG_TOP_SZ)
00055 # define BOTTOM_SZ (1 << LOG_BOTTOM_SZ)
00056 
00057 #ifndef SMALL_CONFIG
00058 # define USE_HDR_CACHE
00059 #endif
00060 
00061 /* #define COUNT_HDR_CACHE_HITS  */
00062 
00063 extern hdr * GC_invalid_header; /* header for an imaginary block      */
00064                             /* containing no objects.          */
00065 
00066 
00067 /* Check whether p and corresponding hhdr point to long or invalid    */
00068 /* object.  If so, advance hhdr    to                                 */
00069 /* beginning of      block, or set hhdr to GC_invalid_header.         */
00070 #define ADVANCE(p, hhdr, source) \
00071            { \
00072              hdr * new_hdr = GC_invalid_header; \
00073               p = GC_find_start(p, hhdr, &new_hdr); \
00074              hhdr = new_hdr; \
00075            }
00076 
00077 #ifdef USE_HDR_CACHE
00078 
00079 # ifdef COUNT_HDR_CACHE_HITS
00080     extern word GC_hdr_cache_hits;
00081     extern word GC_hdr_cache_misses;
00082 #   define HC_HIT() ++GC_hdr_cache_hits
00083 #   define HC_MISS() ++GC_hdr_cache_misses
00084 # else
00085 #   define HC_HIT()
00086 #   define HC_MISS()
00087 # endif
00088 
00089   typedef struct hce {
00090     word block_addr;        /* right shifted by LOG_HBLKSIZE */
00091     hdr * hce_hdr;
00092   } hdr_cache_entry;
00093 
00094 # define HDR_CACHE_SIZE 8  /* power of 2 */
00095 
00096 # define DECLARE_HDR_CACHE \
00097        hdr_cache_entry hdr_cache[HDR_CACHE_SIZE]
00098 
00099 # define INIT_HDR_CACHE BZERO(hdr_cache, sizeof(hdr_cache));
00100 
00101 # define HCE(h) hdr_cache + (((word)(h) >> LOG_HBLKSIZE) & (HDR_CACHE_SIZE-1))
00102 
00103 # define HCE_VALID_FOR(hce,h) ((hce) -> block_addr == \
00104                             ((word)(h) >> LOG_HBLKSIZE))
00105 
00106 # define HCE_HDR(h) ((hce) -> hce_hdr)
00107 
00108 
00109 /* Analogous to GET_HDR, except that in the case of large objects, it */
00110 /* Returns the header for the object beginning, and updates p.        */
00111 /* Returns GC_invalid_header instead of 0.  All of this saves a branch       */
00112 /* in the fast path.                                           */
00113 # define HC_GET_HDR(p, hhdr, source) \
00114        { \
00115          hdr_cache_entry * hce = HCE(p); \
00116          if (HCE_VALID_FOR(hce, p)) { \
00117            HC_HIT(); \
00118            hhdr = hce -> hce_hdr; \
00119          } else { \
00120            HC_MISS(); \
00121            GET_HDR(p, hhdr); \
00122             if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \
00123              ADVANCE(p, hhdr, source); \
00124            } else { \
00125              hce -> block_addr = (word)(p) >> LOG_HBLKSIZE; \
00126              hce -> hce_hdr = hhdr; \
00127            } \
00128          } \
00129        }
00130 
00131 #else /* !USE_HDR_CACHE */
00132 
00133 # define DECLARE_HDR_CACHE
00134 
00135 # define INIT_HDR_CACHE
00136 
00137 # define HC_GET_HDR(p, hhdr, source) \
00138        { \
00139          GET_HDR(p, hhdr); \
00140           if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { \
00141            ADVANCE(p, hhdr, source); \
00142          } \
00143        }
00144 #endif
00145 
00146 typedef struct bi {
00147     hdr * index[BOTTOM_SZ];
00148        /*
00149         * The bottom level index contains one of three kinds of values:
00150         * 0 means we're not responsible for this block,
00151         *   or this is a block other than the first one in a free block.
00152         * 1 < (long)X <= MAX_JUMP means the block starts at least
00153         *        X * HBLKSIZE bytes before the current address.
00154         * A valid pointer points to a hdr structure. (The above can't be
00155         * valid pointers due to the GET_MEM return convention.)
00156         */
00157     struct bi * asc_link;   /* All indices are linked in       */
00158                             /* ascending order...              */
00159     struct bi * desc_link;  /* ... and in descending order.    */
00160     word key;               /* high order address bits. */
00161 # ifdef HASH_TL
00162     struct bi * hash_link;  /* Hash chain link.         */
00163 # endif
00164 } bottom_index;
00165 
00166 /* extern bottom_index GC_all_nils; - really part of GC_arrays */
00167 
00168 /* extern bottom_index * GC_top_index []; - really part of GC_arrays */
00169                             /* Each entry points to a bottom_index.   */
00170                             /* On a 32 bit machine, it points to      */
00171                             /* the index for a set of high order      */
00172                             /* bits equal to the index.  For longer   */
00173                             /* addresses, we hash the high order      */
00174                             /* bits to compute the index in    */
00175                             /* GC_top_index, and each entry points    */
00176                             /* to a hash chain.                */
00177                             /* The last entry in each chain is */
00178                             /* GC_all_nils.                           */
00179 
00180 
00181 # define MAX_JUMP (HBLKSIZE - 1)
00182 
00183 # define HDR_FROM_BI(bi, p) \
00184               ((bi)->index[((word)(p) >> LOG_HBLKSIZE) & (BOTTOM_SZ - 1)])
00185 # ifndef HASH_TL
00186 #   define BI(p) (GC_top_index \
00187               [(word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE)])
00188 #   define HDR_INNER(p) HDR_FROM_BI(BI(p),p)
00189 #   ifdef SMALL_CONFIG
00190 #      define HDR(p) GC_find_header((ptr_t)(p))
00191 #   else
00192 #      define HDR(p) HDR_INNER(p)
00193 #   endif
00194 #   define GET_BI(p, bottom_indx) (bottom_indx) = BI(p)
00195 #   define GET_HDR(p, hhdr) (hhdr) = HDR(p)
00196 #   define SET_HDR(p, hhdr) HDR_INNER(p) = (hhdr)
00197 #   define GET_HDR_ADDR(p, ha) (ha) = &(HDR_INNER(p))
00198 # else /* hash */
00199 /*  Hash function for tree top level */
00200 #   define TL_HASH(hi) ((hi) & (TOP_SZ - 1))
00201 /*  Set bottom_indx to point to the bottom index for address p */
00202 #   define GET_BI(p, bottom_indx) \
00203        { \
00204            register word hi = \
00205                (word)(p) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); \
00206            register bottom_index * _bi = GC_top_index[TL_HASH(hi)]; \
00207            \
00208            while (_bi -> key != hi && _bi != GC_all_nils) \
00209               _bi = _bi -> hash_link; \
00210            (bottom_indx) = _bi; \
00211        }
00212 #   define GET_HDR_ADDR(p, ha) \
00213        { \
00214            register bottom_index * bi; \
00215            \
00216            GET_BI(p, bi);   \
00217            (ha) = &(HDR_FROM_BI(bi, p)); \
00218        }
00219 #   define GET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
00220                            (hhdr) = *_ha; }
00221 #   define SET_HDR(p, hhdr) { register hdr ** _ha; GET_HDR_ADDR(p, _ha); \
00222                            *_ha = (hhdr); }
00223 #   define HDR(p) GC_find_header((ptr_t)(p))
00224 # endif
00225                          
00226 /* Is the result a forwarding address to someplace closer to the      */
00227 /* beginning of the block or NIL?                              */
00228 # define IS_FORWARDING_ADDR_OR_NIL(hhdr) ((unsigned long) (hhdr) <= MAX_JUMP)
00229 
00230 /* Get an HBLKSIZE aligned address closer to the beginning of the block */
00231 /* h.  Assumes hhdr == HDR(h) and IS_FORWARDING_ADDR(hhdr).           */
00232 # define FORWARDED_ADDR(h, hhdr) ((struct hblk *)(h) - (unsigned long)(hhdr))
00233 # endif /*  GC_HEADERS_H */