blob: ffeff623e4626fbee32712587f37753b06a2bc51 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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"
Carl Shapirof1461cb2010-07-29 19:51:53 -070019#include <sys/mman.h> /* for PROT_* */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080020
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080021/*
22 * Initialize a HeapBitmap so that it points to a bitmap large
23 * enough to cover a heap at <base> of <maxSize> bytes, where
24 * objects are guaranteed to be HB_OBJECT_ALIGNMENT-aligned.
25 */
26bool
27dvmHeapBitmapInit(HeapBitmap *hb, const void *base, size_t maxSize,
28 const char *name)
29{
30 void *bits;
31 size_t bitsLen;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080032
33 assert(hb != NULL);
Carl Shapiro3db1ad32010-07-12 16:09:54 -070034 assert(name != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080035 bitsLen = HB_OFFSET_TO_INDEX(maxSize) * sizeof(*hb->bits);
Carl Shapiro3db1ad32010-07-12 16:09:54 -070036 bits = dvmAllocRegion(bitsLen, PROT_READ | PROT_WRITE, name);
37 if (bits == NULL) {
38 LOGE("Could not mmap %zd-byte ashmem region '%s'", bitsLen, name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080039 return false;
40 }
Carl Shapirofc75f3e2010-12-07 11:43:38 -080041 hb->bits = (unsigned long *)bits;
Carl Shapiro8d724802010-02-14 18:40:47 -080042 hb->bitsLen = hb->allocLen = bitsLen;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080043 hb->base = (uintptr_t)base;
44 hb->max = hb->base - 1;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080045 return true;
46}
47
48/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080049 * Clean up any resources associated with the bitmap.
50 */
51void
52dvmHeapBitmapDelete(HeapBitmap *hb)
53{
54 assert(hb != NULL);
55
56 if (hb->bits != NULL) {
Carl Shapiro8d724802010-02-14 18:40:47 -080057 munmap((char *)hb->bits, hb->allocLen);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080058 }
59 memset(hb, 0, sizeof(*hb));
60}
61
62/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080063 * Fill the bitmap with zeroes. Returns the bitmap's memory to
64 * the system as a side-effect.
65 */
66void
67dvmHeapBitmapZero(HeapBitmap *hb)
68{
69 assert(hb != NULL);
70
71 if (hb->bits != NULL) {
72 /* This returns the memory to the system.
73 * Successive page faults will return zeroed memory.
74 */
75 madvise(hb->bits, hb->bitsLen, MADV_DONTNEED);
76 hb->max = hb->base - 1;
77 }
78}
79
80/*
Carl Shapiroc38b7ed2011-02-08 17:43:43 -080081 * Return true iff <obj> is within the range of pointers that this
82 * bitmap could potentially cover, even if a bit has not been set
83 * for it.
84 */
85bool dvmHeapBitmapCoversAddress(const HeapBitmap *hb, const void *obj)
86{
87 assert(hb != NULL);
88 if (obj != NULL) {
89 const uintptr_t offset = (uintptr_t)obj - hb->base;
90 const size_t index = HB_OFFSET_TO_INDEX(offset);
91 return index < hb->bitsLen / sizeof(*hb->bits);
92 }
93 return false;
94}
95
96/*
97 * Visits set bits in address order. The callback is not permitted to
98 * change the bitmap bits or max during the traversal.
99 */
100void dvmHeapBitmapWalk(const HeapBitmap *bitmap, BitmapCallback *callback,
101 void *arg)
102{
103 uintptr_t end;
104 uintptr_t i;
105
106 assert(bitmap != NULL);
107 assert(bitmap->bits != NULL);
108 assert(callback != NULL);
109 end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
110 for (i = 0; i <= end; ++i) {
111 unsigned long word = bitmap->bits[i];
112 if (UNLIKELY(word != 0)) {
113 unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
114 uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + bitmap->base;
115 while (word != 0) {
116 const int shift = CLZ(word);
117 void *addr = (void *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
118 (*callback)(addr, arg);
119 word &= ~(highBit >> shift);
120 }
121 }
122 }
123}
124
125/*
126 * Similar to dvmHeapBitmapWalk but the callback routine is permitted
127 * to change the bitmap bits and max during traversal. Used by the
128 * the root marking scan exclusively.
129 *
130 * The callback is invoked with a finger argument. The finger is a
131 * pointer to an address not yet visited by the traversal. If the
132 * callback sets a bit for an address at or above the finger, this
133 * address will be visited by the traversal. If the callback sets a
134 * bit for an address below the finger, this address will not be
135 * visited.
136 */
137void dvmHeapBitmapScanWalk(HeapBitmap *bitmap,
Carl Shapiro6c355e52011-03-02 15:43:39 -0800138 uintptr_t base, uintptr_t max,
Carl Shapiroc38b7ed2011-02-08 17:43:43 -0800139 BitmapScanCallback *callback, void *arg)
140{
141 assert(bitmap != NULL);
142 assert(bitmap->bits != NULL);
143 assert(callback != NULL);
Carl Shapiro6c355e52011-03-02 15:43:39 -0800144 assert(base <= max);
145 assert(base >= bitmap->base);
146 assert(max <= bitmap->max);
147 uintptr_t end = HB_OFFSET_TO_INDEX(max - base);
Carl Shapiroc38b7ed2011-02-08 17:43:43 -0800148 uintptr_t i;
149 for (i = 0; i <= end; ++i) {
150 unsigned long word = bitmap->bits[i];
151 if (UNLIKELY(word != 0)) {
152 unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
153 uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + bitmap->base;
154 void *finger = (void *)(HB_INDEX_TO_OFFSET(i + 1) + bitmap->base);
155 while (word != 0) {
156 const int shift = CLZ(word);
157 void *addr = (void *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
158 (*callback)(addr, finger, arg);
159 word &= ~(highBit >> shift);
160 }
161 end = HB_OFFSET_TO_INDEX(bitmap->max - bitmap->base);
162 }
163 }
164}
165
166/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800167 * Walk through the bitmaps in increasing address order, and find the
Barry Hayes1c206f62010-07-21 12:03:02 -0700168 * object pointers that correspond to garbage objects. Call
169 * <callback> zero or more times with lists of these object pointers.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800170 *
Carl Shapiro879011d2010-12-02 16:41:28 -0800171 * The callback is not permitted to increase the max of either bitmap.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800172 */
Barry Hayes1c206f62010-07-21 12:03:02 -0700173void dvmHeapBitmapSweepWalk(const HeapBitmap *liveHb, const HeapBitmap *markHb,
Carl Shapiro21260712010-12-09 15:24:11 -0800174 uintptr_t base, uintptr_t max,
Carl Shapiro57ee2702010-08-27 13:06:48 -0700175 BitmapSweepCallback *callback, void *callbackArg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800176{
Carl Shapiroc6eb9672010-12-08 15:40:24 -0800177 void *pointerBuf[4 * HB_BITS_PER_WORD];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800178 void **pb = pointerBuf;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800179 size_t i;
Carl Shapiro21260712010-12-09 15:24:11 -0800180 size_t start, end;
Carl Shapiro879011d2010-12-02 16:41:28 -0800181 unsigned long *live, *mark;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800182
Barry Hayes1c206f62010-07-21 12:03:02 -0700183 assert(liveHb != NULL);
184 assert(liveHb->bits != NULL);
185 assert(markHb != NULL);
186 assert(markHb->bits != NULL);
Carl Shapirof6426e32010-11-30 20:55:32 -0800187 assert(liveHb->base == markHb->base);
188 assert(liveHb->bitsLen == markHb->bitsLen);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800189 assert(callback != NULL);
Carl Shapiro21260712010-12-09 15:24:11 -0800190 assert(base <= max);
191 assert(base >= liveHb->base);
192 assert(max <= liveHb->max);
Carl Shapirof6426e32010-11-30 20:55:32 -0800193 if (liveHb->max < liveHb->base) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800194 /* Easy case; both are obviously empty.
195 */
Carl Shapiro006346e2010-07-29 20:39:50 -0700196 return;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800197 }
Carl Shapiro21260712010-12-09 15:24:11 -0800198 start = HB_OFFSET_TO_INDEX(base - liveHb->base);
199 end = HB_OFFSET_TO_INDEX(max - liveHb->base);
Carl Shapirof6426e32010-11-30 20:55:32 -0800200 live = liveHb->bits;
201 mark = markHb->bits;
Carl Shapiro21260712010-12-09 15:24:11 -0800202 for (i = start; i <= end; i++) {
Carl Shapirof6426e32010-11-30 20:55:32 -0800203 unsigned long garbage = live[i] & ~mark[i];
Carl Shapiro879011d2010-12-02 16:41:28 -0800204 if (UNLIKELY(garbage != 0)) {
205 unsigned long highBit = 1 << (HB_BITS_PER_WORD - 1);
206 uintptr_t ptrBase = HB_INDEX_TO_OFFSET(i) + liveHb->base;
207 while (garbage != 0) {
208 int shift = CLZ(garbage);
209 garbage &= ~(highBit >> shift);
210 *pb++ = (void *)(ptrBase + shift * HB_OBJECT_ALIGNMENT);
211 }
212 /* Make sure that there are always enough slots available */
213 /* for an entire word of 1s. */
Carl Shapiro1c3e0972010-12-08 17:17:45 -0800214 if (pb >= &pointerBuf[NELEM(pointerBuf) - HB_BITS_PER_WORD]) {
Carl Shapiro879011d2010-12-02 16:41:28 -0800215 (*callback)(pb - pointerBuf, pointerBuf, callbackArg);
216 pb = pointerBuf;
217 }
218 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800219 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800220 if (pb > pointerBuf) {
Carl Shapiro879011d2010-12-02 16:41:28 -0800221 (*callback)(pb - pointerBuf, pointerBuf, callbackArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800222 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800223}