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: 41 explicit ModUnionAddToCardSetVisitor(ModUnionTable::CardSet* const cleared_cards) 42 : cleared_cards_(cleared_cards) {} 43 44 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: 58 ModUnionAddToCardBitmapVisitor(ModUnionTable::CardBitmap* bitmap, CardTable* card_table) 59 : bitmap_(bitmap), card_table_(card_table) {} 60 61 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: 77 explicit ModUnionAddToCardVectorVisitor(std::vector<uint8_t*>* cleared_cards) 78 : cleared_cards_(cleared_cards) { 79 } 80 81 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: 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. 103 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 108 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const 109 REQUIRES_SHARED(Locks::mutator_lock_) { 110 VisitRoot(root); 111 } 112 113 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> 120 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. 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 154 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 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 181 void ModUnionTableReferenceCache::ClearTable() { 182 cleared_cards_.clear(); 183 references_.clear(); 184 } 185 186 class AddToReferenceArrayVisitor { 187 public: 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. 198 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 209 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const 210 REQUIRES_SHARED(Locks::mutator_lock_) { 211 if (!root->IsNull()) { 212 VisitRoot(root); 213 } 214 } 215 216 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: 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 247 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: 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. 273 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 295 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 302 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: 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 319 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: 332 mirror::Object* MarkObject(mirror::Object* obj) override {return obj;} 333 void MarkHeapReference(mirror::HeapReference<mirror::Object>*, bool) override {} 334 }; 335 336 void ModUnionTable::FilterCards() { 337 EmptyMarkObjectVisitor visitor; 338 // Use empty visitor since filtering is automatically done by UpdateAndMarkReferences. 339 UpdateAndMarkReferences(&visitor); 340 } 341 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 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 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 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 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: 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 509 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 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 538 void ModUnionTableCardCache::ClearTable() { 539 card_bitmap_->Bitmap::Clear(); 540 } 541 542 // Mark all references to the alloc space(s). 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 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 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 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 592 bool ModUnionTableCardCache::ContainsCardFor(uintptr_t addr) { 593 return card_bitmap_->Test(addr); 594 } 595 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 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