Home | History | Annotate | Download | only in alloc
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 #ifndef _DALVIK_HEAP_BITMAP
     17 #define _DALVIK_HEAP_BITMAP
     18 
     19 #include <limits.h>
     20 #include <stdint.h>
     21 #include "clz.h"
     22 
     23 #define HB_OBJECT_ALIGNMENT 8
     24 #define HB_BITS_PER_WORD (sizeof(unsigned long) * CHAR_BIT)
     25 
     26 /* <offset> is the difference from .base to a pointer address.
     27  * <index> is the index of .bits that contains the bit representing
     28  *         <offset>.
     29  */
     30 #define HB_OFFSET_TO_INDEX(offset_) \
     31     ((uintptr_t)(offset_) / HB_OBJECT_ALIGNMENT / HB_BITS_PER_WORD)
     32 #define HB_INDEX_TO_OFFSET(index_) \
     33     ((uintptr_t)(index_) * HB_OBJECT_ALIGNMENT * HB_BITS_PER_WORD)
     34 
     35 #define HB_OFFSET_TO_BYTE_INDEX(offset_) \
     36   (HB_OFFSET_TO_INDEX(offset_) * sizeof(*((HeapBitmap *)0)->bits))
     37 
     38 /* Pack the bits in backwards so they come out in address order
     39  * when using CLZ.
     40  */
     41 #define HB_OFFSET_TO_MASK(offset_) \
     42     (1 << \
     43         (31-(((uintptr_t)(offset_) / HB_OBJECT_ALIGNMENT) % HB_BITS_PER_WORD)))
     44 
     45 /* Return the maximum offset (exclusive) that <hb> can represent.
     46  */
     47 #define HB_MAX_OFFSET(hb_) \
     48     HB_INDEX_TO_OFFSET((hb_)->bitsLen / sizeof(*(hb_)->bits))
     49 
     50 #define HB_INLINE_PROTO(p) \
     51     static inline p __attribute__((always_inline)); \
     52     static inline p
     53 
     54 typedef struct {
     55     /* The bitmap data, which points to an mmap()ed area of zeroed
     56      * anonymous memory.
     57      */
     58     unsigned long *bits;
     59 
     60     /* The size of the used memory pointed to by bits, in bytes.  This
     61      * value changes when the bitmap is shrunk.
     62      */
     63     size_t bitsLen;
     64 
     65     /* The real size of the memory pointed to by bits.  This is the
     66      * number of bytes we requested from the allocator and does not
     67      * change.
     68      */
     69     size_t allocLen;
     70 
     71     /* The base address, which corresponds to the first bit in
     72      * the bitmap.
     73      */
     74     uintptr_t base;
     75 
     76     /* The highest pointer value ever returned by an allocation
     77      * from this heap.  I.e., the highest address that may correspond
     78      * to a set bit.  If there are no bits set, (max < base).
     79      */
     80     uintptr_t max;
     81 } HeapBitmap;
     82 
     83 typedef void BitmapCallback(void *addr, void *arg);
     84 typedef void BitmapScanCallback(void *addr, void *finger, void *arg);
     85 typedef void BitmapSweepCallback(size_t numPtrs, void **ptrs, void *arg);
     86 
     87 /*
     88  * Initialize a HeapBitmap so that it points to a bitmap large
     89  * enough to cover a heap at <base> of <maxSize> bytes, where
     90  * objects are guaranteed to be HB_OBJECT_ALIGNMENT-aligned.
     91  */
     92 bool dvmHeapBitmapInit(HeapBitmap *hb, const void *base, size_t maxSize,
     93         const char *name);
     94 
     95 /*
     96  * Clean up any resources associated with the bitmap.
     97  */
     98 void dvmHeapBitmapDelete(HeapBitmap *hb);
     99 
    100 /*
    101  * Fill the bitmap with zeroes.  Returns the bitmap's memory to
    102  * the system as a side-effect.
    103  */
    104 void dvmHeapBitmapZero(HeapBitmap *hb);
    105 
    106 /*
    107  * Visits set bits in address order.  The callback is not permitted to
    108  * change the bitmap bits or max during the traversal.
    109  */
    110 HB_INLINE_PROTO(
    111     void
    112     dvmHeapBitmapWalk(const HeapBitmap *bitmap,
    113                       BitmapCallback *callback, void *arg)
    114 )
    115 {
    116     assert(bitmap != NULL);
    117     assert(bitmap->bits != NULL);
    118     assert(callback != NULL);
    119     uintptr_t end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
    120     uintptr_t i;
    121     for (i = 0; i <= end; ++i) {
    122         unsigned long word = bitmap->bits[i];
    123         if (UNLIKELY(word != 0)) {
    124             unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
    125             uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + bitmap->base;
    126             while (word != 0) {
    127                 const int shift = CLZ(word);
    128                 void *addr = (void *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
    129                 (*callback)(addr, arg);
    130                 word &= ~(highBit >> shift);
    131             }
    132         }
    133     }
    134 }
    135 
    136 /*
    137  * Similar to dvmHeapBitmapWalk but the callback routine is permitted
    138  * to change the bitmap bits and max during traversal.  Used by the
    139  * the root marking scan exclusively.
    140  *
    141  * The callback is invoked with a finger argument.  The finger is a
    142  * pointer to an address not yet visited by the traversal.  If the
    143  * callback sets a bit for an address at or above the finger, this
    144  * address will be visited by the traversal.  If the callback sets a
    145  * bit for an address below the finger, this address will not be
    146  * visited.
    147  */
    148 HB_INLINE_PROTO(
    149     void
    150     dvmHeapBitmapScanWalk(HeapBitmap *bitmap,
    151                           BitmapScanCallback *callback, void *arg)
    152 )
    153 {
    154     assert(bitmap != NULL);
    155     assert(bitmap->bits != NULL);
    156     assert(callback != NULL);
    157     uintptr_t end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
    158     uintptr_t i;
    159     for (i = 0; i <= end; ++i) {
    160         unsigned long word = bitmap->bits[i];
    161         if (UNLIKELY(word != 0)) {
    162             unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
    163             uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + bitmap->base;
    164             void *finger = (void *)(HB_INDEX_TO_OFFSET(i + 1) + bitmap->base);
    165             while (word != 0) {
    166                 const int shift = CLZ(word);
    167                 void *addr = (void *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
    168                 (*callback)(addr, finger, arg);
    169                 word &= ~(highBit >> shift);
    170             }
    171             end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
    172         }
    173     }
    174 }
    175 
    176 /*
    177  * Walk through the bitmaps in increasing address order, and find the
    178  * object pointers that correspond to garbage objects.  Call
    179  * <callback> zero or more times with lists of these object pointers.
    180  *
    181  * The callback is permitted to increase the bitmap's max; the walk
    182  * will use the updated max as a terminating condition.
    183  */
    184 void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
    185                             BitmapSweepCallback *callback, void *callbackArg);
    186 
    187 /*
    188  * Return true iff <obj> is within the range of pointers that this
    189  * bitmap could potentially cover, even if a bit has not been set
    190  * for it.
    191  */
    192 HB_INLINE_PROTO(
    193     bool
    194     dvmHeapBitmapCoversAddress(const HeapBitmap *hb, const void *obj)
    195 )
    196 {
    197     assert(hb != NULL);
    198 
    199     if (obj != NULL) {
    200         const uintptr_t offset = (uintptr_t)obj - hb->base;
    201         const size_t index = HB_OFFSET_TO_INDEX(offset);
    202         return index < hb->bitsLen / sizeof(*hb->bits);
    203     }
    204     return false;
    205 }
    206 
    207 /*
    208  * Internal function; do not call directly.
    209  */
    210 HB_INLINE_PROTO(
    211     unsigned long
    212     _heapBitmapModifyObjectBit(HeapBitmap *hb, const void *obj,
    213             bool setBit, bool returnOld)
    214 )
    215 {
    216     const uintptr_t offset = (uintptr_t)obj - hb->base;
    217     const size_t index = HB_OFFSET_TO_INDEX(offset);
    218     const unsigned long mask = HB_OFFSET_TO_MASK(offset);
    219 
    220     assert(hb->bits != NULL);
    221     assert((uintptr_t)obj >= hb->base);
    222     assert(index < hb->bitsLen / sizeof(*hb->bits));
    223 
    224     if (setBit) {
    225         if ((uintptr_t)obj > hb->max) {
    226             hb->max = (uintptr_t)obj;
    227         }
    228         if (returnOld) {
    229             unsigned long *p = hb->bits + index;
    230             const unsigned long word = *p;
    231             *p |= mask;
    232             return word & mask;
    233         } else {
    234             hb->bits[index] |= mask;
    235         }
    236     } else {
    237         hb->bits[index] &= ~mask;
    238     }
    239     return false;
    240 }
    241 
    242 /*
    243  * Sets the bit corresponding to <obj>, and returns the previous value
    244  * of that bit (as zero or non-zero). Does no range checking to see if
    245  * <obj> is outside of the coverage of the bitmap.
    246  *
    247  * NOTE: casting this value to a bool is dangerous, because higher
    248  * set bits will be lost.
    249  */
    250 HB_INLINE_PROTO(
    251     unsigned long
    252     dvmHeapBitmapSetAndReturnObjectBit(HeapBitmap *hb, const void *obj)
    253 )
    254 {
    255     return _heapBitmapModifyObjectBit(hb, obj, true, true);
    256 }
    257 
    258 /*
    259  * Sets the bit corresponding to <obj>, and widens the range of seen
    260  * pointers if necessary.  Does no range checking.
    261  */
    262 HB_INLINE_PROTO(
    263     void
    264     dvmHeapBitmapSetObjectBit(HeapBitmap *hb, const void *obj)
    265 )
    266 {
    267     (void)_heapBitmapModifyObjectBit(hb, obj, true, false);
    268 }
    269 
    270 /*
    271  * Clears the bit corresponding to <obj>.  Does no range checking.
    272  */
    273 HB_INLINE_PROTO(
    274     void
    275     dvmHeapBitmapClearObjectBit(HeapBitmap *hb, const void *obj)
    276 )
    277 {
    278     (void)_heapBitmapModifyObjectBit(hb, obj, false, false);
    279 }
    280 
    281 /*
    282  * Returns the current value of the bit corresponding to <obj>,
    283  * as zero or non-zero.  Does no range checking.
    284  *
    285  * NOTE: casting this value to a bool is dangerous, because higher
    286  * set bits will be lost.
    287  */
    288 HB_INLINE_PROTO(
    289     unsigned long
    290     dvmHeapBitmapIsObjectBitSet(const HeapBitmap *hb, const void *obj)
    291 )
    292 {
    293     assert(dvmHeapBitmapCoversAddress(hb, obj));
    294     assert(hb->bits != NULL);
    295     assert((uintptr_t)obj >= hb->base);
    296 
    297     if ((uintptr_t)obj <= hb->max) {
    298         const uintptr_t offset = (uintptr_t)obj - hb->base;
    299         return hb->bits[HB_OFFSET_TO_INDEX(offset)] & HB_OFFSET_TO_MASK(offset);
    300     } else {
    301         return 0;
    302     }
    303 }
    304 
    305 #undef HB_INLINE_PROTO
    306 
    307 #endif  // _DALVIK_HEAP_BITMAP
    308