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