blob: 85fee73fd04eed7452b3044a7af548ef85f0d334 [file] [log] [blame]
Carl Shapiro69759ea2011-07-21 18:13:35 -07001// Copyright (C) 2008 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070015#include "object_bitmap.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070016
17#include <sys/mman.h>
18
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070019#include "logging.h"
20#include "scoped_ptr.h"
Carl Shapiro69759ea2011-07-21 18:13:35 -070021
22namespace art {
23
24#define CLZ(x) __builtin_clz(x)
25
26HeapBitmap* HeapBitmap::Create(byte* base, size_t length) {
27 scoped_ptr<HeapBitmap> bitmap(new HeapBitmap(base, length));
28 if (!bitmap->Init(base, length)) {
29 return NULL;
30 } else {
31 return bitmap.release();
32 }
33}
34
35// Initialize a HeapBitmap so that it points to a bitmap large enough
36// to cover a heap at <base> of <maxSize> bytes, where objects are
37// guaranteed to be kAlignment-aligned.
38bool HeapBitmap::Init(const byte* base, size_t max_size) {
39 CHECK(base != NULL);
40 size_t length = HB_OFFSET_TO_INDEX(max_size) * kWordSize;
41 void* words = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
42 if (words == MAP_FAILED) {
43 LOG(ERROR) << "mmap failed";
44 return false;
45 }
46 words_ = static_cast<unsigned long*>(words);
47 num_bytes_ = length;
48 base_ = reinterpret_cast<uintptr_t>(base);
49 max_ = base_ - 1;
50 return true;
51}
52
53// Clean up any resources associated with the bitmap.
54HeapBitmap::~HeapBitmap() {
55 if (words_ != NULL) {
56 int result = munmap(words_, num_bytes_);
57 if (result == -1) {
58 PLOG(WARNING) << "munmap failed";
59 }
60 words_ = NULL;
61 }
62}
63
64// Fill the bitmap with zeroes. Returns the bitmap's memory to the
65// system as a side-effect.
66void HeapBitmap::Clear() {
67 if (words_ != NULL) {
68 // This returns the memory to the system. Successive page faults
69 // will return zeroed memory.
70 int result = madvise(words_, num_bytes_, MADV_DONTNEED);
71 if (result == -1) {
72 PLOG(WARNING) << "madvise failed";
73 }
74 max_ = base_ - 1;
75 }
76}
77
78// Return true iff <obj> is within the range of pointers that this
79// bitmap could potentially cover, even if a bit has not been set for
80// it.
81bool HeapBitmap::HasAddress(const void* obj) const {
82 if (obj != NULL) {
83 const uintptr_t offset = (uintptr_t)obj - base_;
84 const size_t index = HB_OFFSET_TO_INDEX(offset);
85 return index < num_bytes_ / kWordSize;
86 }
87 return false;
88}
89
90// Visits set bits in address order. The callback is not permitted to
91// change the bitmap bits or max during the traversal.
92void HeapBitmap::Walk(HeapBitmap::Callback* callback, void* arg) {
93 CHECK(words_ != NULL);
94 CHECK(callback != NULL);
95 uintptr_t end = HB_OFFSET_TO_INDEX(max_ - base_);
96 for (uintptr_t i = 0; i <= end; ++i) {
97 unsigned long word = words_[i];
98 if (word != 0) {
99 unsigned long high_bit = 1 << (kBitsPerWord - 1);
100 uintptr_t ptr_base = HB_INDEX_TO_OFFSET(i) + base_;
101 while (word != 0) {
102 const int shift = CLZ(word);
103 Object* obj = (Object *)(ptr_base + shift * kAlignment);
104 (*callback)(obj, arg);
105 word &= ~(high_bit >> shift);
106 }
107 }
108 }
109}
110
111// Similar to Walk but the callback routine is permitted to change the
112// bitmap bits and max during traversal. Used by the the root marking
113// scan exclusively.
114//
115// The callback is invoked with a finger argument. The finger is a
116// pointer to an address not yet visited by the traversal. If the
117// callback sets a bit for an address at or above the finger, this
118// address will be visited by the traversal. If the callback sets a
119// bit for an address below the finger, this address will not be
120// visited.
121void HeapBitmap::ScanWalk(uintptr_t base, uintptr_t max,
122 ScanCallback* callback, void* arg) {
123 CHECK(words_ != NULL);
124 CHECK(callback != NULL);
125 CHECK(base <= max);
126 CHECK(base >= base_);
127 CHECK(max <= max_);
128 uintptr_t end = HB_OFFSET_TO_INDEX(max - base);
129 for (uintptr_t i = 0; i <= end; ++i) {
130 unsigned long word = words_[i];
131 if (word != 0) {
132 unsigned long high_bit = 1 << (kBitsPerWord - 1);
133 uintptr_t ptr_base = HB_INDEX_TO_OFFSET(i) + base_;
134 void* finger = (void*)(HB_INDEX_TO_OFFSET(i + 1) + base_);
135 while (word != 0) {
136 const int shift = CLZ(word);
137 Object* obj = (Object*)(ptr_base + shift * kAlignment);
138 (*callback)(obj, finger, arg);
139 word &= ~(high_bit >> shift);
140 }
141 end = HB_OFFSET_TO_INDEX(max_ - base_);
142 }
143 }
144}
145
146// Walk through the bitmaps in increasing address order, and find the
147// object pointers that correspond to garbage objects. Call
148// <callback> zero or more times with lists of these object pointers.
149//
150// The callback is not permitted to increase the max of either bitmap.
151void HeapBitmap::SweepWalk(const HeapBitmap& live_bitmap,
152 const HeapBitmap& mark_bitmap,
153 uintptr_t base, uintptr_t max,
154 HeapBitmap::SweepCallback* callback, void* arg) {
155 CHECK(live_bitmap.words_ != NULL);
156 CHECK(mark_bitmap.words_ != NULL);
157 CHECK(live_bitmap.base_ == mark_bitmap.base_);
158 CHECK(live_bitmap.num_bytes_ == mark_bitmap.num_bytes_);
159 CHECK(callback != NULL);
160 CHECK(base <= max);
161 CHECK(base >= live_bitmap.base_);
162 CHECK(max <= live_bitmap.max_);
163 if (live_bitmap.max_ < live_bitmap.base_) {
164 // Easy case; both are obviously empty.
165 // TODO: this should never happen
166 return;
167 }
168 void* pointer_buf[4 * kBitsPerWord];
169 void** pb = pointer_buf;
170 size_t start = HB_OFFSET_TO_INDEX(base - live_bitmap.base_);
171 size_t end = HB_OFFSET_TO_INDEX(max - live_bitmap.base_);
172 unsigned long* live = live_bitmap.words_;
173 unsigned long* mark = mark_bitmap.words_;
174 for (size_t i = start; i <= end; i++) {
175 unsigned long garbage = live[i] & ~mark[i];
176 if (garbage != 0) {
177 unsigned long high_bit = 1 << (kBitsPerWord - 1);
178 uintptr_t ptr_base = HB_INDEX_TO_OFFSET(i) + live_bitmap.base_;
179 while (garbage != 0) {
180 int shift = CLZ(garbage);
181 garbage &= ~(high_bit >> shift);
182 *pb++ = (void*)(ptr_base + shift * kAlignment);
183 }
184 // Make sure that there are always enough slots available for an
185 // entire word of one bits.
186 if (pb >= &pointer_buf[ARRAYSIZE_UNSAFE(pointer_buf) - kBitsPerWord]) {
187 (*callback)(pb - pointer_buf, pointer_buf, arg);
188 pb = pointer_buf;
189 }
190 }
191 }
192 if (pb > pointer_buf) {
193 (*callback)(pb - pointer_buf, pointer_buf, arg);
194 }
195}
196
197} // namespace art