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