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