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