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 "card_table-inl.h"
23 #include "heap_bitmap.h"
24 #include "gc/accounting/space_bitmap-inl.h"
25 #include "gc/collector/mark_sweep.h"
26 #include "gc/collector/mark_sweep-inl.h"
27 #include "gc/heap.h"
28 #include "gc/space/space.h"
29 #include "mirror/art_field-inl.h"
30 #include "mirror/object-inl.h"
31 #include "mirror/class-inl.h"
32 #include "mirror/object_array-inl.h"
33 #include "space_bitmap-inl.h"
34 #include "thread.h"
35 
36 using ::art::mirror::Object;
37 
38 namespace art {
39 namespace gc {
40 namespace accounting {
41 
42 class ModUnionClearCardSetVisitor {
43  public:
ModUnionClearCardSetVisitor(ModUnionTable::CardSet * const cleared_cards)44   explicit ModUnionClearCardSetVisitor(ModUnionTable::CardSet* const cleared_cards)
45     : cleared_cards_(cleared_cards) {
46   }
47 
operator ()(byte * card,byte expected_value,byte new_value) const48   inline void operator()(byte* card, byte expected_value, byte new_value) const {
49     if (expected_value == CardTable::kCardDirty) {
50       cleared_cards_->insert(card);
51     }
52   }
53 
54  private:
55   ModUnionTable::CardSet* const cleared_cards_;
56 };
57 
58 class ModUnionClearCardVisitor {
59  public:
ModUnionClearCardVisitor(std::vector<byte * > * cleared_cards)60   explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
61     : cleared_cards_(cleared_cards) {
62   }
63 
operator ()(byte * card,byte expected_card,byte new_card) const64   void operator()(byte* card, byte expected_card, byte new_card) const {
65     if (expected_card == CardTable::kCardDirty) {
66       cleared_cards_->push_back(card);
67     }
68   }
69  private:
70   std::vector<byte*>* const cleared_cards_;
71 };
72 
73 class ModUnionUpdateObjectReferencesVisitor {
74  public:
ModUnionUpdateObjectReferencesVisitor(MarkHeapReferenceCallback * callback,void * arg)75   ModUnionUpdateObjectReferencesVisitor(MarkHeapReferenceCallback* callback, void* arg)
76     : callback_(callback),
77       arg_(arg) {
78   }
79 
80   // Extra parameters are required since we use this same visitor signature for checking objects.
operator ()(Object * obj,MemberOffset offset,bool) const81   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
82       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
83     // Only add the reference if it is non null and fits our criteria.
84     mirror::HeapReference<Object>* obj_ptr = obj->GetFieldObjectReferenceAddr(offset);
85     if (obj_ptr->AsMirrorPtr() != nullptr) {
86       callback_(obj_ptr, arg_);
87     }
88   }
89 
90  private:
91   MarkHeapReferenceCallback* const callback_;
92   void* arg_;
93 };
94 
95 class ModUnionScanImageRootVisitor {
96  public:
ModUnionScanImageRootVisitor(MarkHeapReferenceCallback * callback,void * arg)97   ModUnionScanImageRootVisitor(MarkHeapReferenceCallback* callback, void* arg)
98       : callback_(callback), arg_(arg) {}
99 
operator ()(Object * root) const100   void operator()(Object* root) const
101       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
102       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
103     DCHECK(root != NULL);
104     ModUnionUpdateObjectReferencesVisitor ref_visitor(callback_, arg_);
105     root->VisitReferences<kMovingClasses>(ref_visitor, VoidFunctor());
106   }
107 
108  private:
109   MarkHeapReferenceCallback* const callback_;
110   void* const arg_;
111 };
112 
ClearCards()113 void ModUnionTableReferenceCache::ClearCards() {
114   CardTable* card_table = GetHeap()->GetCardTable();
115   ModUnionClearCardSetVisitor visitor(&cleared_cards_);
116   // Clear dirty cards in the this space and update the corresponding mod-union bits.
117   card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
118 }
119 
120 class AddToReferenceArrayVisitor {
121  public:
AddToReferenceArrayVisitor(ModUnionTableReferenceCache * mod_union_table,std::vector<mirror::HeapReference<Object> * > * references)122   explicit AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
123                                       std::vector<mirror::HeapReference<Object>*>* references)
124     : mod_union_table_(mod_union_table), references_(references) {
125   }
126 
127   // Extra parameters are required since we use this same visitor signature for checking objects.
operator ()(Object * obj,MemberOffset offset,bool) const128   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
129       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
130     mirror::HeapReference<Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
131     mirror::Object* ref = ref_ptr->AsMirrorPtr();
132     // Only add the reference if it is non null and fits our criteria.
133     if (ref != nullptr && mod_union_table_->ShouldAddReference(ref)) {
134       // Push the adddress of the reference.
135       references_->push_back(ref_ptr);
136     }
137   }
138 
139  private:
140   ModUnionTableReferenceCache* const mod_union_table_;
141   std::vector<mirror::HeapReference<Object>*>* const references_;
142 };
143 
144 class ModUnionReferenceVisitor {
145  public:
ModUnionReferenceVisitor(ModUnionTableReferenceCache * const mod_union_table,std::vector<mirror::HeapReference<Object> * > * references)146   explicit ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
147                                     std::vector<mirror::HeapReference<Object>*>* references)
148     : mod_union_table_(mod_union_table),
149       references_(references) {
150   }
151 
operator ()(Object * obj) const152   void operator()(Object* obj) const
153       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
154     // We don't have an early exit since we use the visitor pattern, an early
155     // exit should significantly speed this up.
156     AddToReferenceArrayVisitor visitor(mod_union_table_, references_);
157     obj->VisitReferences<kMovingClasses>(visitor, VoidFunctor());
158   }
159  private:
160   ModUnionTableReferenceCache* const mod_union_table_;
161   std::vector<mirror::HeapReference<Object>*>* const references_;
162 };
163 
164 class CheckReferenceVisitor {
165  public:
CheckReferenceVisitor(ModUnionTableReferenceCache * mod_union_table,const std::set<const Object * > & references)166   explicit CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
167                                  const std::set<const Object*>& references)
168     : mod_union_table_(mod_union_table),
169       references_(references) {
170   }
171 
172   // Extra parameters are required since we use this same visitor signature for checking objects.
operator ()(Object * obj,MemberOffset offset,bool) const173   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
174       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
175     mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
176     if (ref != nullptr && mod_union_table_->ShouldAddReference(ref) &&
177         references_.find(ref) == references_.end()) {
178       Heap* heap = mod_union_table_->GetHeap();
179       space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
180       space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
181       LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << PrettyTypeOf(obj)
182           << ")" << "References " << reinterpret_cast<const void*>(ref) << "(" << PrettyTypeOf(ref)
183           << ") without being in mod-union table";
184       LOG(INFO) << "FromSpace " << from_space->GetName() << " type "
185           << from_space->GetGcRetentionPolicy();
186       LOG(INFO) << "ToSpace " << to_space->GetName() << " type "
187           << to_space->GetGcRetentionPolicy();
188       heap->DumpSpaces(LOG(INFO));
189       LOG(FATAL) << "FATAL ERROR";
190     }
191   }
192 
193  private:
194   ModUnionTableReferenceCache* const mod_union_table_;
195   const std::set<const Object*>& references_;
196 };
197 
198 class ModUnionCheckReferences {
199  public:
ModUnionCheckReferences(ModUnionTableReferenceCache * mod_union_table,const std::set<const Object * > & references)200   explicit ModUnionCheckReferences(ModUnionTableReferenceCache* mod_union_table,
201                                    const std::set<const Object*>& references)
202       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
203       : mod_union_table_(mod_union_table), references_(references) {
204   }
205 
operator ()(Object * obj) const206   void operator()(Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
207     Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
208     CheckReferenceVisitor visitor(mod_union_table_, references_);
209     obj->VisitReferences<kMovingClasses>(visitor, VoidFunctor());
210   }
211 
212  private:
213   ModUnionTableReferenceCache* const mod_union_table_;
214   const std::set<const Object*>& references_;
215 };
216 
Verify()217 void ModUnionTableReferenceCache::Verify() {
218   // Start by checking that everything in the mod union table is marked.
219   for (const auto& ref_pair : references_) {
220     for (mirror::HeapReference<Object>* ref : ref_pair.second) {
221       CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
222     }
223   }
224 
225   // Check the references of each clean card which is also in the mod union table.
226   CardTable* card_table = heap_->GetCardTable();
227   ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
228   for (const auto& ref_pair : references_) {
229     const byte* card = ref_pair.first;
230     if (*card == CardTable::kCardClean) {
231       std::set<const Object*> reference_set;
232       for (mirror::HeapReference<Object>* obj_ptr : ref_pair.second) {
233         reference_set.insert(obj_ptr->AsMirrorPtr());
234       }
235       ModUnionCheckReferences visitor(this, reference_set);
236       uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
237       live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
238     }
239   }
240 }
241 
Dump(std::ostream & os)242 void ModUnionTableReferenceCache::Dump(std::ostream& os) {
243   CardTable* card_table = heap_->GetCardTable();
244   os << "ModUnionTable cleared cards: [";
245   for (byte* card_addr : cleared_cards_) {
246     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
247     uintptr_t end = start + CardTable::kCardSize;
248     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
249   }
250   os << "]\nModUnionTable references: [";
251   for (const auto& ref_pair : references_) {
252     const byte* card_addr = ref_pair.first;
253     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
254     uintptr_t end = start + CardTable::kCardSize;
255     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
256     for (mirror::HeapReference<Object>* ref : ref_pair.second) {
257       os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ",";
258     }
259     os << "},";
260   }
261 }
262 
UpdateAndMarkReferences(MarkHeapReferenceCallback * callback,void * arg)263 void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
264                                                           void* arg) {
265   CardTable* card_table = heap_->GetCardTable();
266 
267   std::vector<mirror::HeapReference<Object>*> cards_references;
268   ModUnionReferenceVisitor add_visitor(this, &cards_references);
269 
270   for (const auto& card : cleared_cards_) {
271     // Clear and re-compute alloc space references associated with this card.
272     cards_references.clear();
273     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
274     uintptr_t end = start + CardTable::kCardSize;
275     auto* space = heap_->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
276     DCHECK(space != nullptr);
277     ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
278     live_bitmap->VisitMarkedRange(start, end, add_visitor);
279 
280     // Update the corresponding references for the card.
281     auto found = references_.find(card);
282     if (found == references_.end()) {
283       if (cards_references.empty()) {
284         // No reason to add empty array.
285         continue;
286       }
287       references_.Put(card, cards_references);
288     } else {
289       found->second = cards_references;
290     }
291   }
292   cleared_cards_.clear();
293   size_t count = 0;
294   for (const auto& ref : references_) {
295     for (mirror::HeapReference<Object>* obj_ptr : ref.second) {
296       callback(obj_ptr, arg);
297     }
298     count += ref.second.size();
299   }
300   if (VLOG_IS_ON(heap)) {
301     VLOG(gc) << "Marked " << count << " references in mod union table";
302   }
303 }
304 
ClearCards()305 void ModUnionTableCardCache::ClearCards() {
306   CardTable* card_table = GetHeap()->GetCardTable();
307   ModUnionClearCardSetVisitor visitor(&cleared_cards_);
308   // Clear dirty cards in the this space and update the corresponding mod-union bits.
309   card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
310 }
311 
312 // Mark all references to the alloc space(s).
UpdateAndMarkReferences(MarkHeapReferenceCallback * callback,void * arg)313 void ModUnionTableCardCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
314                                                      void* arg) {
315   CardTable* card_table = heap_->GetCardTable();
316   ModUnionScanImageRootVisitor scan_visitor(callback, arg);
317   ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
318   for (const byte* card_addr : cleared_cards_) {
319     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
320     DCHECK(space_->HasAddress(reinterpret_cast<Object*>(start)));
321     bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
322   }
323 }
324 
Dump(std::ostream & os)325 void ModUnionTableCardCache::Dump(std::ostream& os) {
326   CardTable* card_table = heap_->GetCardTable();
327   os << "ModUnionTable dirty cards: [";
328   for (const byte* card_addr : cleared_cards_) {
329     auto start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
330     auto end = start + CardTable::kCardSize;
331     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "\n";
332   }
333   os << "]";
334 }
335 
336 }  // namespace accounting
337 }  // namespace gc
338 }  // namespace art
339