• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include "Dalvik.h"
18 #include "HeapBitmap.h"
19 #include "clz.h"
20 #include <sys/mman.h>   /* for PROT_* */
21 
22 /*
23  * Initialize a HeapBitmap so that it points to a bitmap large
24  * enough to cover a heap at <base> of <maxSize> bytes, where
25  * objects are guaranteed to be HB_OBJECT_ALIGNMENT-aligned.
26  */
27 bool
dvmHeapBitmapInit(HeapBitmap * hb,const void * base,size_t maxSize,const char * name)28 dvmHeapBitmapInit(HeapBitmap *hb, const void *base, size_t maxSize,
29         const char *name)
30 {
31     void *bits;
32     size_t bitsLen;
33 
34     assert(hb != NULL);
35     assert(name != NULL);
36     bitsLen = HB_OFFSET_TO_INDEX(maxSize) * sizeof(*hb->bits);
37     bits = dvmAllocRegion(bitsLen, PROT_READ | PROT_WRITE, name);
38     if (bits == NULL) {
39         LOGE("Could not mmap %zd-byte ashmem region '%s'", bitsLen, name);
40         return false;
41     }
42     hb->bits = bits;
43     hb->bitsLen = hb->allocLen = bitsLen;
44     hb->base = (uintptr_t)base;
45     hb->max = hb->base - 1;
46     return true;
47 }
48 
49 /*
50  * Clean up any resources associated with the bitmap.
51  */
52 void
dvmHeapBitmapDelete(HeapBitmap * hb)53 dvmHeapBitmapDelete(HeapBitmap *hb)
54 {
55     assert(hb != NULL);
56 
57     if (hb->bits != NULL) {
58         munmap((char *)hb->bits, hb->allocLen);
59     }
60     memset(hb, 0, sizeof(*hb));
61 }
62 
63 /*
64  * Fill the bitmap with zeroes.  Returns the bitmap's memory to
65  * the system as a side-effect.
66  */
67 void
dvmHeapBitmapZero(HeapBitmap * hb)68 dvmHeapBitmapZero(HeapBitmap *hb)
69 {
70     assert(hb != NULL);
71 
72     if (hb->bits != NULL) {
73         /* This returns the memory to the system.
74          * Successive page faults will return zeroed memory.
75          */
76         madvise(hb->bits, hb->bitsLen, MADV_DONTNEED);
77         hb->max = hb->base - 1;
78     }
79 }
80 
81 /*
82  * Walk through the bitmaps in increasing address order, and find the
83  * object pointers that correspond to garbage objects.  Call
84  * <callback> zero or more times with lists of these object pointers.
85  *
86  * The callback is permitted to increase the bitmap's max; the walk
87  * will use the updated max as a terminating condition,
88  */
dvmHeapBitmapSweepWalk(const HeapBitmap * liveHb,const HeapBitmap * markHb,BitmapSweepCallback * callback,void * callbackArg)89 void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
90                             BitmapSweepCallback *callback, void *callbackArg)
91 {
92     static const size_t kPointerBufSize = 128;
93     void *pointerBuf[kPointerBufSize];
94     void **pb = pointerBuf;
95     size_t index;
96     size_t i;
97 
98 #define FLUSH_POINTERBUF() \
99     do { \
100         (*callback)(pb - pointerBuf, (void **)pointerBuf, \
101                     callbackArg); \
102         pb = pointerBuf; \
103     } while (false)
104 
105 #define DECODE_BITS(hb_, bits_, update_index_) \
106     do { \
107         if (UNLIKELY(bits_ != 0)) { \
108             static const unsigned long kHighBit = \
109                     (unsigned long)1 << (HB_BITS_PER_WORD - 1); \
110             const uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + hb_->base; \
111 /*TODO: hold onto ptrBase so we can shrink max later if possible */ \
112 /*TODO: see if this is likely or unlikely */ \
113             while (bits_ != 0) { \
114                 const int rshift = CLZ(bits_); \
115                 bits_ &= ~(kHighBit >> rshift); \
116                 *pb++ = (void *)(ptrBase + rshift * HB_OBJECT_ALIGNMENT); \
117             } \
118             /* Make sure that there are always enough slots available */ \
119             /* for an entire word of 1s. */ \
120             if (kPointerBufSize - (pb - pointerBuf) < HB_BITS_PER_WORD) { \
121                 FLUSH_POINTERBUF(); \
122                 if (update_index_) { \
123                     /* The callback may have caused hb_->max to grow. */ \
124                     index = HB_OFFSET_TO_INDEX(hb_->max - hb_->base); \
125                 } \
126             } \
127         } \
128     } while (false)
129 
130     assert(liveHb != NULL);
131     assert(liveHb->bits != NULL);
132     assert(markHb != NULL);
133     assert(markHb->bits != NULL);
134     assert(callback != NULL);
135 
136     if (liveHb->base != markHb->base) {
137         LOGW("dvmHeapBitmapSweepWalk: bitmaps cover different heaps (%zd != %zd)",
138              liveHb->base, markHb->base);
139         return;
140     }
141     if (liveHb->bitsLen != markHb->bitsLen) {
142         LOGW("dvmHeapBitmapSweepWalk: size of bitmaps differ (%zd != %zd)",
143              liveHb->bitsLen, markHb->bitsLen);
144         return;
145     }
146     if (liveHb->max < liveHb->base && markHb->max < markHb->base) {
147         /* Easy case; both are obviously empty.
148          */
149         return;
150     }
151 
152     /* First, walk along the section of the bitmaps that may be the same.
153      */
154     if (liveHb->max >= liveHb->base && markHb->max >= markHb->base) {
155         unsigned long *live, *mark;
156         uintptr_t offset;
157 
158         offset = ((liveHb->max < markHb->max) ? liveHb->max : markHb->max) - liveHb->base;
159 //TODO: keep track of which (and whether) one is longer for later
160         index = HB_OFFSET_TO_INDEX(offset);
161 
162         live = liveHb->bits;
163         mark = markHb->bits;
164         for (i = 0; i <= index; i++) {
165 //TODO: unroll this. pile up a few in locals?
166             unsigned long garbage = live[i] & ~mark[i];
167             DECODE_BITS(liveHb, garbage, false);
168 //BUG: if the callback was called, either max could have changed.
169         }
170         /* The next index to look at.
171          */
172         index++;
173     } else {
174         /* One of the bitmaps is empty.
175          */
176         index = 0;
177     }
178 
179     /* If one bitmap's max is larger, walk through the rest of the
180      * set bits.
181      */
182 const HeapBitmap *longHb;
183 unsigned long *p;
184 //TODO: may be the same size, in which case this is wasted work
185     longHb = (liveHb->max > markHb->max) ? liveHb : markHb;
186     i = index;
187     index = HB_OFFSET_TO_INDEX(longHb->max - longHb->base);
188     p = longHb->bits + i;
189     for (/* i = i */; i <= index; i++) {
190 //TODO: unroll this
191         unsigned long bits = *p++;
192         DECODE_BITS(longHb, bits, true);
193     }
194 
195     if (pb > pointerBuf) {
196         FLUSH_POINTERBUF();
197     }
198 #undef FLUSH_POINTERBUF
199 #undef DECODE_BITS
200 }
201