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: 44 explicit ModUnionClearCardSetVisitor(ModUnionTable::CardSet* const cleared_cards) 45 : cleared_cards_(cleared_cards) { 46 } 47 48 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: 60 explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards) 61 : cleared_cards_(cleared_cards) { 62 } 63 64 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: 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. 81 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: 97 ModUnionScanImageRootVisitor(MarkHeapReferenceCallback* callback, void* arg) 98 : callback_(callback), arg_(arg) {} 99 100 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 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: 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. 128 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: 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 152 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: 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. 173 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: 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 206 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 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 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 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 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). 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 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