• 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/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   // Use an unordered_set for constant time search of card in the second loop.
392   // We don't want to change cleared_cards_ to unordered so that traversals are
393   // sequential in address order.
394   // TODO: Optimize this.
395   std::unordered_set<const uint8_t*> card_lookup_map;
396   for (uint8_t* card : cleared_cards_) {
397     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
398     uintptr_t end = start + CardTable::kCardSize;
399     live_bitmap->VisitMarkedRange(start,
400                                   end,
401                                   [callback, arg](mirror::Object* obj) {
402       callback(obj, arg);
403     });
404     card_lookup_map.insert(card);
405   }
406   for (const auto& pair : references_) {
407     const uint8_t* card = pair.first;
408     if (card_lookup_map.find(card) != card_lookup_map.end()) {
409       continue;
410     }
411     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
412     uintptr_t end = start + CardTable::kCardSize;
413     live_bitmap->VisitMarkedRange(start,
414                                   end,
415                                   [callback, arg](mirror::Object* obj) {
416       callback(obj, arg);
417     });
418   }
419 }
420 
UpdateAndMarkReferences(MarkObjectVisitor * visitor)421 void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
422   CardTable* const card_table = heap_->GetCardTable();
423   std::vector<mirror::HeapReference<mirror::Object>*> cards_references;
424   // If has_target_reference is true then there was a GcRoot compressed reference which wasn't
425   // added. In this case we need to keep the card dirty.
426   // We don't know if the GcRoot addresses will remain constant, for example, classloaders have a
427   // hash set of GcRoot which may be resized or modified.
428   bool has_target_reference;
429   ModUnionReferenceVisitor add_visitor(this, visitor, &cards_references, &has_target_reference);
430   CardSet new_cleared_cards;
431   for (uint8_t* card : cleared_cards_) {
432     // Clear and re-compute alloc space references associated with this card.
433     cards_references.clear();
434     has_target_reference = false;
435     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
436     uintptr_t end = start + CardTable::kCardSize;
437     space::ContinuousSpace* space =
438         heap_->FindContinuousSpaceFromObject(reinterpret_cast<mirror::Object*>(start), false);
439     DCHECK(space != nullptr);
440     ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
441     live_bitmap->VisitMarkedRange(start, end, add_visitor);
442     // Update the corresponding references for the card.
443     auto found = references_.find(card);
444     if (found == references_.end()) {
445       // Don't add card for an empty reference array.
446       if (!cards_references.empty()) {
447         references_.Put(card, cards_references);
448       }
449     } else {
450       if (cards_references.empty()) {
451         references_.erase(found);
452       } else {
453         found->second = cards_references;
454       }
455     }
456     if (has_target_reference) {
457       // Keep this card for next time since it contains a GcRoot which matches the
458       // ShouldAddReference criteria. This usually occurs for class loaders.
459       new_cleared_cards.insert(card);
460     }
461   }
462   cleared_cards_ = std::move(new_cleared_cards);
463   size_t count = 0;
464   for (auto it = references_.begin(); it != references_.end();) {
465     std::vector<mirror::HeapReference<mirror::Object>*>& references = it->second;
466     // Since there is no card mark for setting a reference to null, we check each reference.
467     // If all of the references of a card are null then we can remove that card. This is racy
468     // with the mutators, but handled by rescanning dirty cards.
469     bool all_null = true;
470     for (mirror::HeapReference<mirror::Object>* obj_ptr : references) {
471       if (obj_ptr->AsMirrorPtr() != nullptr) {
472         all_null = false;
473         visitor->MarkHeapReference(obj_ptr, /*do_atomic_update=*/ false);
474       }
475     }
476     count += references.size();
477     if (!all_null) {
478       ++it;
479     } else {
480       // All null references, erase the array from the set.
481       it = references_.erase(it);
482     }
483   }
484   if (VLOG_IS_ON(heap)) {
485     VLOG(gc) << "Marked " << count << " references in mod union table";
486   }
487 }
488 
ModUnionTableCardCache(const std::string & name,Heap * heap,space::ContinuousSpace * space)489 ModUnionTableCardCache::ModUnionTableCardCache(const std::string& name,
490                                                Heap* heap,
491                                                space::ContinuousSpace* space)
492     : ModUnionTable(name, heap, space) {
493   // Normally here we could use End() instead of Limit(), but for testing we may want to have a
494   // mod-union table for a space which can still grow.
495   if (!space->IsImageSpace()) {
496     CHECK_ALIGNED(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize);
497   }
498   card_bitmap_.reset(CardBitmap::Create(
499       "mod union bitmap", reinterpret_cast<uintptr_t>(space->Begin()),
500       RoundUp(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize)));
501 }
502 
503 class CardBitVisitor {
504  public:
CardBitVisitor(MarkObjectVisitor * visitor,space::ContinuousSpace * space,space::ContinuousSpace * immune_space,ModUnionTable::CardBitmap * card_bitmap)505   CardBitVisitor(MarkObjectVisitor* visitor,
506                  space::ContinuousSpace* space,
507                  space::ContinuousSpace* immune_space,
508                  ModUnionTable::CardBitmap* card_bitmap)
509       : visitor_(visitor),
510         space_(space),
511         immune_space_(immune_space),
512         bitmap_(space->GetLiveBitmap()),
513         card_bitmap_(card_bitmap) {
514     DCHECK(immune_space_ != nullptr);
515   }
516 
operator ()(size_t bit_index) const517   void operator()(size_t bit_index) const {
518     const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
519     DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
520         << start << " " << *space_;
521     bool reference_to_other_space = false;
522     ModUnionScanImageRootVisitor scan_visitor(visitor_, space_, immune_space_,
523                                               &reference_to_other_space);
524     bitmap_->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
525     if (!reference_to_other_space) {
526       // No non null reference to another space, clear the bit.
527       card_bitmap_->ClearBit(bit_index);
528     }
529   }
530 
531  private:
532   MarkObjectVisitor* const visitor_;
533   space::ContinuousSpace* const space_;
534   space::ContinuousSpace* const immune_space_;
535   ContinuousSpaceBitmap* const bitmap_;
536   ModUnionTable::CardBitmap* const card_bitmap_;
537 };
538 
ProcessCards()539 void ModUnionTableCardCache::ProcessCards() {
540   CardTable* const card_table = GetHeap()->GetCardTable();
541   ModUnionAddToCardBitmapVisitor visitor(card_bitmap_.get(), card_table);
542   // Clear dirty cards in the this space and update the corresponding mod-union bits.
543   card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
544 }
545 
ClearTable()546 void ModUnionTableCardCache::ClearTable() {
547   card_bitmap_->Bitmap::Clear();
548 }
549 
550 // Mark all references to the alloc space(s).
UpdateAndMarkReferences(MarkObjectVisitor * visitor)551 void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
552   // TODO: Needs better support for multi-images? b/26317072
553   space::ImageSpace* image_space =
554       heap_->GetBootImageSpaces().empty() ? nullptr : heap_->GetBootImageSpaces()[0];
555   // If we don't have an image space, just pass in space_ as the immune space. Pass in the same
556   // space_ instead of image_space to avoid a null check in ModUnionUpdateObjectReferencesVisitor.
557   CardBitVisitor bit_visitor(visitor, space_, image_space != nullptr ? image_space : space_,
558       card_bitmap_.get());
559   card_bitmap_->VisitSetBits(
560       0, RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize, bit_visitor);
561 }
562 
VisitObjects(ObjectCallback callback,void * arg)563 void ModUnionTableCardCache::VisitObjects(ObjectCallback callback, void* arg) {
564   card_bitmap_->VisitSetBits(
565       0,
566       RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize,
567       [this, callback, arg](size_t bit_index) {
568         const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
569         DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
570             << start << " " << *space_;
571         space_->GetLiveBitmap()->VisitMarkedRange(start,
572                                                   start + CardTable::kCardSize,
573                                                   [callback, arg](mirror::Object* obj) {
574           callback(obj, arg);
575         });
576       });
577 }
578 
Dump(std::ostream & os)579 void ModUnionTableCardCache::Dump(std::ostream& os) {
580   os << "ModUnionTable dirty cards: [";
581   // TODO: Find cleaner way of doing this.
582   for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
583       addr += CardTable::kCardSize) {
584     if (card_bitmap_->Test(reinterpret_cast<uintptr_t>(addr))) {
585       os << reinterpret_cast<void*>(addr) << "-"
586          << reinterpret_cast<void*>(addr + CardTable::kCardSize) << "\n";
587     }
588   }
589   os << "]";
590 }
591 
SetCards()592 void ModUnionTableCardCache::SetCards() {
593   // Only clean up to the end since there cannot be any objects past the End() of the space.
594   for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
595        addr += CardTable::kCardSize) {
596     card_bitmap_->Set(reinterpret_cast<uintptr_t>(addr));
597   }
598 }
599 
ContainsCardFor(uintptr_t addr)600 bool ModUnionTableCardCache::ContainsCardFor(uintptr_t addr) {
601   return card_bitmap_->Test(addr);
602 }
603 
SetCards()604 void ModUnionTableReferenceCache::SetCards() {
605   for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
606        addr += CardTable::kCardSize) {
607     cleared_cards_.insert(heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr)));
608   }
609 }
610 
ContainsCardFor(uintptr_t addr)611 bool ModUnionTableReferenceCache::ContainsCardFor(uintptr_t addr) {
612   auto* card_ptr = heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr));
613   return cleared_cards_.find(card_ptr) != cleared_cards_.end() ||
614       references_.find(card_ptr) != references_.end();
615 }
616 
617 }  // namespace accounting
618 }  // namespace gc
619 }  // namespace art
620