1 /*
2 * Copyright (C) 2012 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 "mod_union_table.h"
18
19 #include <memory>
20
21 #include "base/stl_util.h"
22 #include "bitmap-inl.h"
23 #include "card_table-inl.h"
24 #include "gc/accounting/space_bitmap-inl.h"
25 #include "gc/heap.h"
26 #include "gc/space/image_space.h"
27 #include "gc/space/space.h"
28 #include "mirror/object-inl.h"
29 #include "mirror/object-refvisitor-inl.h"
30 #include "space_bitmap-inl.h"
31 #include "thread-inl.h"
32
33 namespace art {
34 namespace gc {
35 namespace accounting {
36
37 class ModUnionAddToCardSetVisitor {
38 public:
ModUnionAddToCardSetVisitor(ModUnionTable::CardSet * const cleared_cards)39 explicit ModUnionAddToCardSetVisitor(ModUnionTable::CardSet* const cleared_cards)
40 : cleared_cards_(cleared_cards) {}
41
operator ()(uint8_t * card,uint8_t expected_value,uint8_t new_value ATTRIBUTE_UNUSED) const42 inline void operator()(uint8_t* card,
43 uint8_t expected_value,
44 uint8_t new_value ATTRIBUTE_UNUSED) const {
45 if (expected_value == CardTable::kCardDirty) {
46 cleared_cards_->insert(card);
47 }
48 }
49
50 private:
51 ModUnionTable::CardSet* const cleared_cards_;
52 };
53
54 class ModUnionAddToCardBitmapVisitor {
55 public:
ModUnionAddToCardBitmapVisitor(ModUnionTable::CardBitmap * bitmap,CardTable * card_table)56 ModUnionAddToCardBitmapVisitor(ModUnionTable::CardBitmap* bitmap, CardTable* card_table)
57 : bitmap_(bitmap), card_table_(card_table) {}
58
operator ()(uint8_t * card,uint8_t expected_value,uint8_t new_value ATTRIBUTE_UNUSED) const59 inline void operator()(uint8_t* card,
60 uint8_t expected_value,
61 uint8_t new_value ATTRIBUTE_UNUSED) const {
62 if (expected_value == CardTable::kCardDirty) {
63 // We want the address the card represents, not the address of the card.
64 bitmap_->Set(reinterpret_cast<uintptr_t>(card_table_->AddrFromCard(card)));
65 }
66 }
67
68 private:
69 ModUnionTable::CardBitmap* const bitmap_;
70 CardTable* const card_table_;
71 };
72
73 class ModUnionAddToCardVectorVisitor {
74 public:
ModUnionAddToCardVectorVisitor(std::vector<uint8_t * > * cleared_cards)75 explicit ModUnionAddToCardVectorVisitor(std::vector<uint8_t*>* cleared_cards)
76 : cleared_cards_(cleared_cards) {
77 }
78
operator ()(uint8_t * card,uint8_t expected_card,uint8_t new_card ATTRIBUTE_UNUSED) const79 void operator()(uint8_t* card, uint8_t expected_card, uint8_t new_card ATTRIBUTE_UNUSED) const {
80 if (expected_card == CardTable::kCardDirty) {
81 cleared_cards_->push_back(card);
82 }
83 }
84
85 private:
86 std::vector<uint8_t*>* const cleared_cards_;
87 };
88
89 class ModUnionUpdateObjectReferencesVisitor {
90 public:
ModUnionUpdateObjectReferencesVisitor(MarkObjectVisitor * visitor,space::ContinuousSpace * from_space,space::ContinuousSpace * immune_space,bool * contains_reference_to_other_space)91 ModUnionUpdateObjectReferencesVisitor(MarkObjectVisitor* visitor,
92 space::ContinuousSpace* from_space,
93 space::ContinuousSpace* immune_space,
94 bool* contains_reference_to_other_space)
95 : visitor_(visitor),
96 from_space_(from_space),
97 immune_space_(immune_space),
98 contains_reference_to_other_space_(contains_reference_to_other_space) {}
99
100 // Extra parameters are required since we use this same visitor signature for checking objects.
operator ()(mirror::Object * obj,MemberOffset offset,bool is_static ATTRIBUTE_UNUSED) const101 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
102 REQUIRES_SHARED(Locks::mutator_lock_) {
103 MarkReference(obj->GetFieldObjectReferenceAddr(offset));
104 }
105
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root) const106 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
107 REQUIRES_SHARED(Locks::mutator_lock_) {
108 VisitRoot(root);
109 }
110
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const111 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
112 REQUIRES_SHARED(Locks::mutator_lock_) {
113 MarkReference(root);
114 }
115
116 private:
117 template<bool kPoisonReferences>
MarkReference(mirror::ObjectReference<kPoisonReferences,mirror::Object> * obj_ptr) const118 void MarkReference(mirror::ObjectReference<kPoisonReferences, mirror::Object>* obj_ptr) const
119 REQUIRES_SHARED(Locks::mutator_lock_) {
120 // Only add the reference if it is non null and fits our criteria.
121 mirror::Object* ref = obj_ptr->AsMirrorPtr();
122 if (ref != nullptr && !from_space_->HasAddress(ref) && !immune_space_->HasAddress(ref)) {
123 *contains_reference_to_other_space_ = true;
124 mirror::Object* new_object = visitor_->MarkObject(ref);
125 if (ref != new_object) {
126 obj_ptr->Assign(new_object);
127 }
128 }
129 }
130
131 MarkObjectVisitor* const visitor_;
132 // Space which we are scanning
133 space::ContinuousSpace* const from_space_;
134 space::ContinuousSpace* const immune_space_;
135 // Set if we have any references to another space.
136 bool* const contains_reference_to_other_space_;
137 };
138
139 class ModUnionScanImageRootVisitor {
140 public:
141 // Immune space is any other space which we don't care about references to. Currently this is
142 // the image space in the case of the zygote mod union table.
ModUnionScanImageRootVisitor(MarkObjectVisitor * visitor,space::ContinuousSpace * from_space,space::ContinuousSpace * immune_space,bool * contains_reference_to_other_space)143 ModUnionScanImageRootVisitor(MarkObjectVisitor* visitor,
144 space::ContinuousSpace* from_space,
145 space::ContinuousSpace* immune_space,
146 bool* contains_reference_to_other_space)
147 : visitor_(visitor),
148 from_space_(from_space),
149 immune_space_(immune_space),
150 contains_reference_to_other_space_(contains_reference_to_other_space) {}
151
operator ()(mirror::Object * root) const152 void operator()(mirror::Object* root) const
153 REQUIRES(Locks::heap_bitmap_lock_)
154 REQUIRES_SHARED(Locks::mutator_lock_) {
155 DCHECK(root != nullptr);
156 ModUnionUpdateObjectReferencesVisitor ref_visitor(visitor_,
157 from_space_,
158 immune_space_,
159 contains_reference_to_other_space_);
160 root->VisitReferences(ref_visitor, VoidFunctor());
161 }
162
163 private:
164 MarkObjectVisitor* const visitor_;
165 // Space which we are scanning
166 space::ContinuousSpace* const from_space_;
167 space::ContinuousSpace* const immune_space_;
168 // Set if we have any references to another space.
169 bool* const contains_reference_to_other_space_;
170 };
171
ProcessCards()172 void ModUnionTableReferenceCache::ProcessCards() {
173 CardTable* card_table = GetHeap()->GetCardTable();
174 ModUnionAddToCardSetVisitor visitor(&cleared_cards_);
175 // Clear dirty cards in the this space and update the corresponding mod-union bits.
176 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
177 }
178
ClearTable()179 void ModUnionTableReferenceCache::ClearTable() {
180 cleared_cards_.clear();
181 references_.clear();
182 }
183
184 class AddToReferenceArrayVisitor {
185 public:
AddToReferenceArrayVisitor(ModUnionTableReferenceCache * mod_union_table,MarkObjectVisitor * visitor,std::vector<mirror::HeapReference<mirror::Object> * > * references,bool * has_target_reference)186 AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
187 MarkObjectVisitor* visitor,
188 std::vector<mirror::HeapReference<mirror::Object>*>* references,
189 bool* has_target_reference)
190 : mod_union_table_(mod_union_table),
191 visitor_(visitor),
192 references_(references),
193 has_target_reference_(has_target_reference) {}
194
195 // Extra parameters are required since we use this same visitor signature for checking objects.
operator ()(mirror::Object * obj,MemberOffset offset,bool is_static ATTRIBUTE_UNUSED) const196 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
197 REQUIRES_SHARED(Locks::mutator_lock_) {
198 mirror::HeapReference<mirror::Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
199 mirror::Object* ref = ref_ptr->AsMirrorPtr();
200 // Only add the reference if it is non null and fits our criteria.
201 if (ref != nullptr && mod_union_table_->ShouldAddReference(ref)) {
202 // Push the adddress of the reference.
203 references_->push_back(ref_ptr);
204 }
205 }
206
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root) const207 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
208 REQUIRES_SHARED(Locks::mutator_lock_) {
209 if (!root->IsNull()) {
210 VisitRoot(root);
211 }
212 }
213
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const214 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
215 REQUIRES_SHARED(Locks::mutator_lock_) {
216 if (mod_union_table_->ShouldAddReference(root->AsMirrorPtr())) {
217 *has_target_reference_ = true;
218 // TODO: Add MarkCompressedReference callback here.
219 mirror::Object* old_ref = root->AsMirrorPtr();
220 mirror::Object* new_ref = visitor_->MarkObject(old_ref);
221 if (old_ref != new_ref) {
222 root->Assign(new_ref);
223 }
224 }
225 }
226
227 private:
228 ModUnionTableReferenceCache* const mod_union_table_;
229 MarkObjectVisitor* const visitor_;
230 std::vector<mirror::HeapReference<mirror::Object>*>* const references_;
231 bool* const has_target_reference_;
232 };
233
234 class ModUnionReferenceVisitor {
235 public:
ModUnionReferenceVisitor(ModUnionTableReferenceCache * const mod_union_table,MarkObjectVisitor * visitor,std::vector<mirror::HeapReference<mirror::Object> * > * references,bool * has_target_reference)236 ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
237 MarkObjectVisitor* visitor,
238 std::vector<mirror::HeapReference<mirror::Object>*>* references,
239 bool* has_target_reference)
240 : mod_union_table_(mod_union_table),
241 visitor_(visitor),
242 references_(references),
243 has_target_reference_(has_target_reference) {}
244
operator ()(mirror::Object * obj) const245 void operator()(mirror::Object* obj) const
246 REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
247 // We don't have an early exit since we use the visitor pattern, an early
248 // exit should significantly speed this up.
249 AddToReferenceArrayVisitor visitor(mod_union_table_,
250 visitor_,
251 references_,
252 has_target_reference_);
253 obj->VisitReferences(visitor, VoidFunctor());
254 }
255
256 private:
257 ModUnionTableReferenceCache* const mod_union_table_;
258 MarkObjectVisitor* const visitor_;
259 std::vector<mirror::HeapReference<mirror::Object>*>* const references_;
260 bool* const has_target_reference_;
261 };
262
263 class CheckReferenceVisitor {
264 public:
CheckReferenceVisitor(ModUnionTableReferenceCache * mod_union_table,const std::set<mirror::Object * > & references)265 CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
266 const std::set<mirror::Object*>& references)
267 : mod_union_table_(mod_union_table),
268 references_(references) {}
269
270 // Extra parameters are required since we use this same visitor signature for checking objects.
operator ()(mirror::Object * obj,MemberOffset offset,bool is_static ATTRIBUTE_UNUSED) const271 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
272 REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
273 mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
274 if (ref != nullptr &&
275 mod_union_table_->ShouldAddReference(ref) &&
276 references_.find(ref) == references_.end()) {
277 Heap* heap = mod_union_table_->GetHeap();
278 space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
279 space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
280 LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << obj->PrettyTypeOf()
281 << ")" << "References "
282 << reinterpret_cast<const void*>(ref) << "(" << mirror::Object::PrettyTypeOf(ref)
283 << ") without being in mod-union table";
284 LOG(INFO) << "FromSpace " << from_space->GetName() << " type "
285 << from_space->GetGcRetentionPolicy();
286 LOG(INFO) << "ToSpace " << to_space->GetName() << " type "
287 << to_space->GetGcRetentionPolicy();
288 heap->DumpSpaces(LOG_STREAM(INFO));
289 LOG(FATAL) << "FATAL ERROR";
290 }
291 }
292
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root) const293 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
294 REQUIRES_SHARED(Locks::mutator_lock_) {
295 if (kIsDebugBuild && !root->IsNull()) {
296 VisitRoot(root);
297 }
298 }
299
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const300 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
301 REQUIRES_SHARED(Locks::mutator_lock_) {
302 DCHECK(!mod_union_table_->ShouldAddReference(root->AsMirrorPtr()));
303 }
304
305 private:
306 ModUnionTableReferenceCache* const mod_union_table_;
307 const std::set<mirror::Object*>& references_;
308 };
309
310 class ModUnionCheckReferences {
311 public:
ModUnionCheckReferences(ModUnionTableReferenceCache * mod_union_table,const std::set<mirror::Object * > & references)312 ModUnionCheckReferences(ModUnionTableReferenceCache* mod_union_table,
313 const std::set<mirror::Object*>& references)
314 REQUIRES(Locks::heap_bitmap_lock_)
315 : mod_union_table_(mod_union_table), references_(references) {}
316
operator ()(mirror::Object * obj) const317 void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
318 Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
319 CheckReferenceVisitor visitor(mod_union_table_, references_);
320 obj->VisitReferences(visitor, VoidFunctor());
321 }
322
323 private:
324 ModUnionTableReferenceCache* const mod_union_table_;
325 const std::set<mirror::Object*>& references_;
326 };
327
328 class EmptyMarkObjectVisitor : public MarkObjectVisitor {
329 public:
MarkObject(mirror::Object * obj)330 mirror::Object* MarkObject(mirror::Object* obj) OVERRIDE {return obj;}
MarkHeapReference(mirror::HeapReference<mirror::Object> *,bool)331 void MarkHeapReference(mirror::HeapReference<mirror::Object>*, bool) OVERRIDE {}
332 };
333
FilterCards()334 void ModUnionTable::FilterCards() {
335 EmptyMarkObjectVisitor visitor;
336 // Use empty visitor since filtering is automatically done by UpdateAndMarkReferences.
337 UpdateAndMarkReferences(&visitor);
338 }
339
Verify()340 void ModUnionTableReferenceCache::Verify() {
341 // Start by checking that everything in the mod union table is marked.
342 for (const auto& ref_pair : references_) {
343 for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
344 CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
345 }
346 }
347
348 // Check the references of each clean card which is also in the mod union table.
349 CardTable* card_table = heap_->GetCardTable();
350 ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
351 for (const auto& ref_pair : references_) {
352 const uint8_t* card = ref_pair.first;
353 if (*card == CardTable::kCardClean) {
354 std::set<mirror::Object*> reference_set;
355 for (mirror::HeapReference<mirror::Object>* obj_ptr : ref_pair.second) {
356 reference_set.insert(obj_ptr->AsMirrorPtr());
357 }
358 ModUnionCheckReferences visitor(this, reference_set);
359 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
360 live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
361 }
362 }
363 }
364
Dump(std::ostream & os)365 void ModUnionTableReferenceCache::Dump(std::ostream& os) {
366 CardTable* card_table = heap_->GetCardTable();
367 os << "ModUnionTable cleared cards: [";
368 for (uint8_t* card_addr : cleared_cards_) {
369 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
370 uintptr_t end = start + CardTable::kCardSize;
371 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
372 }
373 os << "]\nModUnionTable references: [";
374 for (const auto& ref_pair : references_) {
375 const uint8_t* card_addr = ref_pair.first;
376 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
377 uintptr_t end = start + CardTable::kCardSize;
378 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
379 for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
380 os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ",";
381 }
382 os << "},";
383 }
384 }
385
VisitObjects(ObjectCallback * callback,void * arg)386 void ModUnionTableReferenceCache::VisitObjects(ObjectCallback* callback, void* arg) {
387 CardTable* const card_table = heap_->GetCardTable();
388 ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
389 for (uint8_t* card : cleared_cards_) {
390 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
391 uintptr_t end = start + CardTable::kCardSize;
392 live_bitmap->VisitMarkedRange(start,
393 end,
394 [this, callback, arg](mirror::Object* obj) {
395 callback(obj, arg);
396 });
397 }
398 // This may visit the same card twice, TODO avoid this.
399 for (const auto& pair : references_) {
400 const uint8_t* card = pair.first;
401 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
402 uintptr_t end = start + CardTable::kCardSize;
403 live_bitmap->VisitMarkedRange(start,
404 end,
405 [this, callback, arg](mirror::Object* obj) {
406 callback(obj, arg);
407 });
408 }
409 }
410
UpdateAndMarkReferences(MarkObjectVisitor * visitor)411 void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
412 CardTable* const card_table = heap_->GetCardTable();
413 std::vector<mirror::HeapReference<mirror::Object>*> cards_references;
414 // If has_target_reference is true then there was a GcRoot compressed reference which wasn't
415 // added. In this case we need to keep the card dirty.
416 // We don't know if the GcRoot addresses will remain constant, for example, classloaders have a
417 // hash set of GcRoot which may be resized or modified.
418 bool has_target_reference;
419 ModUnionReferenceVisitor add_visitor(this, visitor, &cards_references, &has_target_reference);
420 CardSet new_cleared_cards;
421 for (uint8_t* card : cleared_cards_) {
422 // Clear and re-compute alloc space references associated with this card.
423 cards_references.clear();
424 has_target_reference = false;
425 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
426 uintptr_t end = start + CardTable::kCardSize;
427 space::ContinuousSpace* space =
428 heap_->FindContinuousSpaceFromObject(reinterpret_cast<mirror::Object*>(start), false);
429 DCHECK(space != nullptr);
430 ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
431 live_bitmap->VisitMarkedRange(start, end, add_visitor);
432 // Update the corresponding references for the card.
433 auto found = references_.find(card);
434 if (found == references_.end()) {
435 // Don't add card for an empty reference array.
436 if (!cards_references.empty()) {
437 references_.Put(card, cards_references);
438 }
439 } else {
440 if (cards_references.empty()) {
441 references_.erase(found);
442 } else {
443 found->second = cards_references;
444 }
445 }
446 if (has_target_reference) {
447 // Keep this card for next time since it contains a GcRoot which matches the
448 // ShouldAddReference criteria. This usually occurs for class loaders.
449 new_cleared_cards.insert(card);
450 }
451 }
452 cleared_cards_ = std::move(new_cleared_cards);
453 size_t count = 0;
454 for (auto it = references_.begin(); it != references_.end();) {
455 std::vector<mirror::HeapReference<mirror::Object>*>& references = it->second;
456 // Since there is no card mark for setting a reference to null, we check each reference.
457 // If all of the references of a card are null then we can remove that card. This is racy
458 // with the mutators, but handled by rescanning dirty cards.
459 bool all_null = true;
460 for (mirror::HeapReference<mirror::Object>* obj_ptr : references) {
461 if (obj_ptr->AsMirrorPtr() != nullptr) {
462 all_null = false;
463 visitor->MarkHeapReference(obj_ptr, /*do_atomic_update*/ false);
464 }
465 }
466 count += references.size();
467 if (!all_null) {
468 ++it;
469 } else {
470 // All null references, erase the array from the set.
471 it = references_.erase(it);
472 }
473 }
474 if (VLOG_IS_ON(heap)) {
475 VLOG(gc) << "Marked " << count << " references in mod union table";
476 }
477 }
478
ModUnionTableCardCache(const std::string & name,Heap * heap,space::ContinuousSpace * space)479 ModUnionTableCardCache::ModUnionTableCardCache(const std::string& name,
480 Heap* heap,
481 space::ContinuousSpace* space)
482 : ModUnionTable(name, heap, space) {
483 // Normally here we could use End() instead of Limit(), but for testing we may want to have a
484 // mod-union table for a space which can still grow.
485 if (!space->IsImageSpace()) {
486 CHECK_ALIGNED(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize);
487 }
488 card_bitmap_.reset(CardBitmap::Create(
489 "mod union bitmap", reinterpret_cast<uintptr_t>(space->Begin()),
490 RoundUp(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize)));
491 }
492
493 class CardBitVisitor {
494 public:
CardBitVisitor(MarkObjectVisitor * visitor,space::ContinuousSpace * space,space::ContinuousSpace * immune_space,ModUnionTable::CardBitmap * card_bitmap)495 CardBitVisitor(MarkObjectVisitor* visitor,
496 space::ContinuousSpace* space,
497 space::ContinuousSpace* immune_space,
498 ModUnionTable::CardBitmap* card_bitmap)
499 : visitor_(visitor),
500 space_(space),
501 immune_space_(immune_space),
502 bitmap_(space->GetLiveBitmap()),
503 card_bitmap_(card_bitmap) {
504 DCHECK(immune_space_ != nullptr);
505 }
506
operator ()(size_t bit_index) const507 void operator()(size_t bit_index) const {
508 const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
509 DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
510 << start << " " << *space_;
511 bool reference_to_other_space = false;
512 ModUnionScanImageRootVisitor scan_visitor(visitor_, space_, immune_space_,
513 &reference_to_other_space);
514 bitmap_->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
515 if (!reference_to_other_space) {
516 // No non null reference to another space, clear the bit.
517 card_bitmap_->ClearBit(bit_index);
518 }
519 }
520
521 private:
522 MarkObjectVisitor* const visitor_;
523 space::ContinuousSpace* const space_;
524 space::ContinuousSpace* const immune_space_;
525 ContinuousSpaceBitmap* const bitmap_;
526 ModUnionTable::CardBitmap* const card_bitmap_;
527 };
528
ProcessCards()529 void ModUnionTableCardCache::ProcessCards() {
530 CardTable* const card_table = GetHeap()->GetCardTable();
531 ModUnionAddToCardBitmapVisitor visitor(card_bitmap_.get(), card_table);
532 // Clear dirty cards in the this space and update the corresponding mod-union bits.
533 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
534 }
535
ClearTable()536 void ModUnionTableCardCache::ClearTable() {
537 card_bitmap_->Bitmap::Clear();
538 }
539
540 // Mark all references to the alloc space(s).
UpdateAndMarkReferences(MarkObjectVisitor * visitor)541 void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
542 // TODO: Needs better support for multi-images? b/26317072
543 space::ImageSpace* image_space =
544 heap_->GetBootImageSpaces().empty() ? nullptr : heap_->GetBootImageSpaces()[0];
545 // If we don't have an image space, just pass in space_ as the immune space. Pass in the same
546 // space_ instead of image_space to avoid a null check in ModUnionUpdateObjectReferencesVisitor.
547 CardBitVisitor bit_visitor(visitor, space_, image_space != nullptr ? image_space : space_,
548 card_bitmap_.get());
549 card_bitmap_->VisitSetBits(
550 0, RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize, bit_visitor);
551 }
552
VisitObjects(ObjectCallback * callback,void * arg)553 void ModUnionTableCardCache::VisitObjects(ObjectCallback* callback, void* arg) {
554 card_bitmap_->VisitSetBits(
555 0,
556 RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize,
557 [this, callback, arg](size_t bit_index) {
558 const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
559 DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
560 << start << " " << *space_;
561 space_->GetLiveBitmap()->VisitMarkedRange(start,
562 start + CardTable::kCardSize,
563 [this, callback, arg](mirror::Object* obj) {
564 callback(obj, arg);
565 });
566 });
567 }
568
Dump(std::ostream & os)569 void ModUnionTableCardCache::Dump(std::ostream& os) {
570 os << "ModUnionTable dirty cards: [";
571 // TODO: Find cleaner way of doing this.
572 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
573 addr += CardTable::kCardSize) {
574 if (card_bitmap_->Test(reinterpret_cast<uintptr_t>(addr))) {
575 os << reinterpret_cast<void*>(addr) << "-"
576 << reinterpret_cast<void*>(addr + CardTable::kCardSize) << "\n";
577 }
578 }
579 os << "]";
580 }
581
SetCards()582 void ModUnionTableCardCache::SetCards() {
583 // Only clean up to the end since there cannot be any objects past the End() of the space.
584 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
585 addr += CardTable::kCardSize) {
586 card_bitmap_->Set(reinterpret_cast<uintptr_t>(addr));
587 }
588 }
589
ContainsCardFor(uintptr_t addr)590 bool ModUnionTableCardCache::ContainsCardFor(uintptr_t addr) {
591 return card_bitmap_->Test(addr);
592 }
593
SetCards()594 void ModUnionTableReferenceCache::SetCards() {
595 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
596 addr += CardTable::kCardSize) {
597 cleared_cards_.insert(heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr)));
598 }
599 }
600
ContainsCardFor(uintptr_t addr)601 bool ModUnionTableReferenceCache::ContainsCardFor(uintptr_t addr) {
602 auto* card_ptr = heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr));
603 return cleared_cards_.find(card_ptr) != cleared_cards_.end() ||
604 references_.find(card_ptr) != references_.end();
605 }
606
607 } // namespace accounting
608 } // namespace gc
609 } // namespace art
610