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