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 "bitmap-inl.h"
23 #include "card_table-inl.h"
24 #include "gc/accounting/space_bitmap-inl.h"
25 #include "gc/heap.h"
26 #include "gc/space/image_space.h"
27 #include "gc/space/space.h"
28 #include "mirror/object-inl.h"
29 #include "mirror/object-refvisitor-inl.h"
30 #include "object_callbacks.h"
31 #include "space_bitmap-inl.h"
32 #include "thread-current-inl.h"
33
34 namespace art {
35 namespace gc {
36 namespace accounting {
37
38 class ModUnionAddToCardSetVisitor {
39 public:
ModUnionAddToCardSetVisitor(ModUnionTable::CardSet * const cleared_cards)40 explicit ModUnionAddToCardSetVisitor(ModUnionTable::CardSet* const cleared_cards)
41 : cleared_cards_(cleared_cards) {}
42
operator ()(uint8_t * card,uint8_t expected_value,uint8_t new_value ATTRIBUTE_UNUSED) const43 inline void operator()(uint8_t* card,
44 uint8_t expected_value,
45 uint8_t new_value ATTRIBUTE_UNUSED) 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 ModUnionAddToCardBitmapVisitor {
56 public:
ModUnionAddToCardBitmapVisitor(ModUnionTable::CardBitmap * bitmap,CardTable * card_table)57 ModUnionAddToCardBitmapVisitor(ModUnionTable::CardBitmap* bitmap, CardTable* card_table)
58 : bitmap_(bitmap), card_table_(card_table) {}
59
operator ()(uint8_t * card,uint8_t expected_value,uint8_t new_value ATTRIBUTE_UNUSED) const60 inline void operator()(uint8_t* card,
61 uint8_t expected_value,
62 uint8_t new_value ATTRIBUTE_UNUSED) const {
63 if (expected_value == CardTable::kCardDirty) {
64 // We want the address the card represents, not the address of the card.
65 bitmap_->Set(reinterpret_cast<uintptr_t>(card_table_->AddrFromCard(card)));
66 }
67 }
68
69 private:
70 ModUnionTable::CardBitmap* const bitmap_;
71 CardTable* const card_table_;
72 };
73
74 class ModUnionAddToCardVectorVisitor {
75 public:
ModUnionAddToCardVectorVisitor(std::vector<uint8_t * > * cleared_cards)76 explicit ModUnionAddToCardVectorVisitor(std::vector<uint8_t*>* cleared_cards)
77 : cleared_cards_(cleared_cards) {
78 }
79
operator ()(uint8_t * card,uint8_t expected_card,uint8_t new_card ATTRIBUTE_UNUSED) const80 void operator()(uint8_t* card, uint8_t expected_card, uint8_t new_card ATTRIBUTE_UNUSED) const {
81 if (expected_card == CardTable::kCardDirty) {
82 cleared_cards_->push_back(card);
83 }
84 }
85
86 private:
87 std::vector<uint8_t*>* const cleared_cards_;
88 };
89
90 class ModUnionUpdateObjectReferencesVisitor {
91 public:
ModUnionUpdateObjectReferencesVisitor(MarkObjectVisitor * visitor,space::ContinuousSpace * from_space,space::ContinuousSpace * immune_space,bool * contains_reference_to_other_space)92 ModUnionUpdateObjectReferencesVisitor(MarkObjectVisitor* visitor,
93 space::ContinuousSpace* from_space,
94 space::ContinuousSpace* immune_space,
95 bool* contains_reference_to_other_space)
96 : visitor_(visitor),
97 from_space_(from_space),
98 immune_space_(immune_space),
99 contains_reference_to_other_space_(contains_reference_to_other_space) {}
100
101 // 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) const102 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
103 REQUIRES_SHARED(Locks::mutator_lock_) {
104 MarkReference(obj->GetFieldObjectReferenceAddr(offset));
105 }
106
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root) const107 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
108 REQUIRES_SHARED(Locks::mutator_lock_) {
109 VisitRoot(root);
110 }
111
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const112 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
113 REQUIRES_SHARED(Locks::mutator_lock_) {
114 MarkReference(root);
115 }
116
117 private:
118 template<bool kPoisonReferences>
MarkReference(mirror::ObjectReference<kPoisonReferences,mirror::Object> * obj_ptr) const119 void MarkReference(mirror::ObjectReference<kPoisonReferences, mirror::Object>* obj_ptr) const
120 REQUIRES_SHARED(Locks::mutator_lock_) {
121 // Only add the reference if it is non null and fits our criteria.
122 mirror::Object* ref = obj_ptr->AsMirrorPtr();
123 if (ref != nullptr && !from_space_->HasAddress(ref) && !immune_space_->HasAddress(ref)) {
124 *contains_reference_to_other_space_ = true;
125 mirror::Object* new_object = visitor_->MarkObject(ref);
126 if (ref != new_object) {
127 obj_ptr->Assign(new_object);
128 }
129 }
130 }
131
132 MarkObjectVisitor* const visitor_;
133 // Space which we are scanning
134 space::ContinuousSpace* const from_space_;
135 space::ContinuousSpace* const immune_space_;
136 // Set if we have any references to another space.
137 bool* const contains_reference_to_other_space_;
138 };
139
140 class ModUnionScanImageRootVisitor {
141 public:
142 // Immune space is any other space which we don't care about references to. Currently this is
143 // 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)144 ModUnionScanImageRootVisitor(MarkObjectVisitor* visitor,
145 space::ContinuousSpace* from_space,
146 space::ContinuousSpace* immune_space,
147 bool* contains_reference_to_other_space)
148 : visitor_(visitor),
149 from_space_(from_space),
150 immune_space_(immune_space),
151 contains_reference_to_other_space_(contains_reference_to_other_space) {}
152
operator ()(mirror::Object * root) const153 void operator()(mirror::Object* root) const
154 REQUIRES(Locks::heap_bitmap_lock_)
155 REQUIRES_SHARED(Locks::mutator_lock_) {
156 DCHECK(root != nullptr);
157 ModUnionUpdateObjectReferencesVisitor ref_visitor(visitor_,
158 from_space_,
159 immune_space_,
160 contains_reference_to_other_space_);
161 root->VisitReferences(ref_visitor, VoidFunctor());
162 }
163
164 private:
165 MarkObjectVisitor* const visitor_;
166 // Space which we are scanning
167 space::ContinuousSpace* const from_space_;
168 space::ContinuousSpace* const immune_space_;
169 // Set if we have any references to another space.
170 bool* const contains_reference_to_other_space_;
171 };
172
ProcessCards()173 void ModUnionTableReferenceCache::ProcessCards() {
174 CardTable* card_table = GetHeap()->GetCardTable();
175 ModUnionAddToCardSetVisitor visitor(&cleared_cards_);
176 // Clear dirty cards in the this space and update the corresponding mod-union bits.
177 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
178 }
179
ClearTable()180 void ModUnionTableReferenceCache::ClearTable() {
181 cleared_cards_.clear();
182 references_.clear();
183 }
184
185 class AddToReferenceArrayVisitor {
186 public:
AddToReferenceArrayVisitor(ModUnionTableReferenceCache * mod_union_table,MarkObjectVisitor * visitor,std::vector<mirror::HeapReference<mirror::Object> * > * references,bool * has_target_reference)187 AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
188 MarkObjectVisitor* visitor,
189 std::vector<mirror::HeapReference<mirror::Object>*>* references,
190 bool* has_target_reference)
191 : mod_union_table_(mod_union_table),
192 visitor_(visitor),
193 references_(references),
194 has_target_reference_(has_target_reference) {}
195
196 // 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) const197 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
198 REQUIRES_SHARED(Locks::mutator_lock_) {
199 mirror::HeapReference<mirror::Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
200 mirror::Object* ref = ref_ptr->AsMirrorPtr();
201 // Only add the reference if it is non null and fits our criteria.
202 if (ref != nullptr && mod_union_table_->ShouldAddReference(ref)) {
203 // Push the adddress of the reference.
204 references_->push_back(ref_ptr);
205 }
206 }
207
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root) const208 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
209 REQUIRES_SHARED(Locks::mutator_lock_) {
210 if (!root->IsNull()) {
211 VisitRoot(root);
212 }
213 }
214
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const215 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
216 REQUIRES_SHARED(Locks::mutator_lock_) {
217 if (mod_union_table_->ShouldAddReference(root->AsMirrorPtr())) {
218 *has_target_reference_ = true;
219 // TODO: Add MarkCompressedReference callback here.
220 mirror::Object* old_ref = root->AsMirrorPtr();
221 mirror::Object* new_ref = visitor_->MarkObject(old_ref);
222 if (old_ref != new_ref) {
223 root->Assign(new_ref);
224 }
225 }
226 }
227
228 private:
229 ModUnionTableReferenceCache* const mod_union_table_;
230 MarkObjectVisitor* const visitor_;
231 std::vector<mirror::HeapReference<mirror::Object>*>* const references_;
232 bool* const has_target_reference_;
233 };
234
235 class ModUnionReferenceVisitor {
236 public:
ModUnionReferenceVisitor(ModUnionTableReferenceCache * const mod_union_table,MarkObjectVisitor * visitor,std::vector<mirror::HeapReference<mirror::Object> * > * references,bool * has_target_reference)237 ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
238 MarkObjectVisitor* visitor,
239 std::vector<mirror::HeapReference<mirror::Object>*>* references,
240 bool* has_target_reference)
241 : mod_union_table_(mod_union_table),
242 visitor_(visitor),
243 references_(references),
244 has_target_reference_(has_target_reference) {}
245
operator ()(mirror::Object * obj) const246 void operator()(mirror::Object* obj) const
247 REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
248 // We don't have an early exit since we use the visitor pattern, an early
249 // exit should significantly speed this up.
250 AddToReferenceArrayVisitor visitor(mod_union_table_,
251 visitor_,
252 references_,
253 has_target_reference_);
254 obj->VisitReferences(visitor, VoidFunctor());
255 }
256
257 private:
258 ModUnionTableReferenceCache* const mod_union_table_;
259 MarkObjectVisitor* const visitor_;
260 std::vector<mirror::HeapReference<mirror::Object>*>* const references_;
261 bool* const has_target_reference_;
262 };
263
264 class CheckReferenceVisitor {
265 public:
CheckReferenceVisitor(ModUnionTableReferenceCache * mod_union_table,const std::set<mirror::Object * > & references)266 CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
267 const std::set<mirror::Object*>& references)
268 : mod_union_table_(mod_union_table),
269 references_(references) {}
270
271 // 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) const272 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
273 REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
274 mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
275 if (ref != nullptr &&
276 mod_union_table_->ShouldAddReference(ref) &&
277 references_.find(ref) == references_.end()) {
278 Heap* heap = mod_union_table_->GetHeap();
279 space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
280 space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
281 LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << obj->PrettyTypeOf()
282 << ")" << "References "
283 << reinterpret_cast<const void*>(ref) << "(" << mirror::Object::PrettyTypeOf(ref)
284 << ") without being in mod-union table";
285 LOG(INFO) << "FromSpace " << from_space->GetName() << " type "
286 << from_space->GetGcRetentionPolicy();
287 LOG(INFO) << "ToSpace " << to_space->GetName() << " type "
288 << to_space->GetGcRetentionPolicy();
289 heap->DumpSpaces(LOG_STREAM(INFO));
290 LOG(FATAL) << "FATAL ERROR";
291 }
292 }
293
VisitRootIfNonNull(mirror::CompressedReference<mirror::Object> * root) const294 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
295 REQUIRES_SHARED(Locks::mutator_lock_) {
296 if (kIsDebugBuild && !root->IsNull()) {
297 VisitRoot(root);
298 }
299 }
300
VisitRoot(mirror::CompressedReference<mirror::Object> * root) const301 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
302 REQUIRES_SHARED(Locks::mutator_lock_) {
303 DCHECK(!mod_union_table_->ShouldAddReference(root->AsMirrorPtr()));
304 }
305
306 private:
307 ModUnionTableReferenceCache* const mod_union_table_;
308 const std::set<mirror::Object*>& references_;
309 };
310
311 class ModUnionCheckReferences {
312 public:
ModUnionCheckReferences(ModUnionTableReferenceCache * mod_union_table,const std::set<mirror::Object * > & references)313 ModUnionCheckReferences(ModUnionTableReferenceCache* mod_union_table,
314 const std::set<mirror::Object*>& references)
315 REQUIRES(Locks::heap_bitmap_lock_)
316 : mod_union_table_(mod_union_table), references_(references) {}
317
operator ()(mirror::Object * obj) const318 void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
319 Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
320 CheckReferenceVisitor visitor(mod_union_table_, references_);
321 obj->VisitReferences(visitor, VoidFunctor());
322 }
323
324 private:
325 ModUnionTableReferenceCache* const mod_union_table_;
326 const std::set<mirror::Object*>& references_;
327 };
328
329 class EmptyMarkObjectVisitor : public MarkObjectVisitor {
330 public:
MarkObject(mirror::Object * obj)331 mirror::Object* MarkObject(mirror::Object* obj) OVERRIDE {return obj;}
MarkHeapReference(mirror::HeapReference<mirror::Object> *,bool)332 void MarkHeapReference(mirror::HeapReference<mirror::Object>*, bool) OVERRIDE {}
333 };
334
FilterCards()335 void ModUnionTable::FilterCards() {
336 EmptyMarkObjectVisitor visitor;
337 // Use empty visitor since filtering is automatically done by UpdateAndMarkReferences.
338 UpdateAndMarkReferences(&visitor);
339 }
340
Verify()341 void ModUnionTableReferenceCache::Verify() {
342 // Start by checking that everything in the mod union table is marked.
343 for (const auto& ref_pair : references_) {
344 for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
345 CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
346 }
347 }
348
349 // Check the references of each clean card which is also in the mod union table.
350 CardTable* card_table = heap_->GetCardTable();
351 ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
352 for (const auto& ref_pair : references_) {
353 const uint8_t* card = ref_pair.first;
354 if (*card == CardTable::kCardClean) {
355 std::set<mirror::Object*> reference_set;
356 for (mirror::HeapReference<mirror::Object>* obj_ptr : ref_pair.second) {
357 reference_set.insert(obj_ptr->AsMirrorPtr());
358 }
359 ModUnionCheckReferences visitor(this, reference_set);
360 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
361 live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
362 }
363 }
364 }
365
Dump(std::ostream & os)366 void ModUnionTableReferenceCache::Dump(std::ostream& os) {
367 CardTable* card_table = heap_->GetCardTable();
368 os << "ModUnionTable cleared cards: [";
369 for (uint8_t* card_addr : cleared_cards_) {
370 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
371 uintptr_t end = start + CardTable::kCardSize;
372 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
373 }
374 os << "]\nModUnionTable references: [";
375 for (const auto& ref_pair : references_) {
376 const uint8_t* card_addr = ref_pair.first;
377 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
378 uintptr_t end = start + CardTable::kCardSize;
379 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
380 for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
381 os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ",";
382 }
383 os << "},";
384 }
385 }
386
VisitObjects(ObjectCallback callback,void * arg)387 void ModUnionTableReferenceCache::VisitObjects(ObjectCallback callback, void* arg) {
388 CardTable* const card_table = heap_->GetCardTable();
389 ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
390 for (uint8_t* card : cleared_cards_) {
391 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
392 uintptr_t end = start + CardTable::kCardSize;
393 live_bitmap->VisitMarkedRange(start,
394 end,
395 [callback, arg](mirror::Object* obj) {
396 callback(obj, arg);
397 });
398 }
399 // This may visit the same card twice, TODO avoid this.
400 for (const auto& pair : references_) {
401 const uint8_t* card = pair.first;
402 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
403 uintptr_t end = start + CardTable::kCardSize;
404 live_bitmap->VisitMarkedRange(start,
405 end,
406 [callback, arg](mirror::Object* obj) {
407 callback(obj, arg);
408 });
409 }
410 }
411
UpdateAndMarkReferences(MarkObjectVisitor * visitor)412 void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
413 CardTable* const card_table = heap_->GetCardTable();
414 std::vector<mirror::HeapReference<mirror::Object>*> cards_references;
415 // If has_target_reference is true then there was a GcRoot compressed reference which wasn't
416 // added. In this case we need to keep the card dirty.
417 // We don't know if the GcRoot addresses will remain constant, for example, classloaders have a
418 // hash set of GcRoot which may be resized or modified.
419 bool has_target_reference;
420 ModUnionReferenceVisitor add_visitor(this, visitor, &cards_references, &has_target_reference);
421 CardSet new_cleared_cards;
422 for (uint8_t* card : cleared_cards_) {
423 // Clear and re-compute alloc space references associated with this card.
424 cards_references.clear();
425 has_target_reference = false;
426 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
427 uintptr_t end = start + CardTable::kCardSize;
428 space::ContinuousSpace* space =
429 heap_->FindContinuousSpaceFromObject(reinterpret_cast<mirror::Object*>(start), false);
430 DCHECK(space != nullptr);
431 ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
432 live_bitmap->VisitMarkedRange(start, end, add_visitor);
433 // Update the corresponding references for the card.
434 auto found = references_.find(card);
435 if (found == references_.end()) {
436 // Don't add card for an empty reference array.
437 if (!cards_references.empty()) {
438 references_.Put(card, cards_references);
439 }
440 } else {
441 if (cards_references.empty()) {
442 references_.erase(found);
443 } else {
444 found->second = cards_references;
445 }
446 }
447 if (has_target_reference) {
448 // Keep this card for next time since it contains a GcRoot which matches the
449 // ShouldAddReference criteria. This usually occurs for class loaders.
450 new_cleared_cards.insert(card);
451 }
452 }
453 cleared_cards_ = std::move(new_cleared_cards);
454 size_t count = 0;
455 for (auto it = references_.begin(); it != references_.end();) {
456 std::vector<mirror::HeapReference<mirror::Object>*>& references = it->second;
457 // Since there is no card mark for setting a reference to null, we check each reference.
458 // If all of the references of a card are null then we can remove that card. This is racy
459 // with the mutators, but handled by rescanning dirty cards.
460 bool all_null = true;
461 for (mirror::HeapReference<mirror::Object>* obj_ptr : references) {
462 if (obj_ptr->AsMirrorPtr() != nullptr) {
463 all_null = false;
464 visitor->MarkHeapReference(obj_ptr, /*do_atomic_update*/ false);
465 }
466 }
467 count += references.size();
468 if (!all_null) {
469 ++it;
470 } else {
471 // All null references, erase the array from the set.
472 it = references_.erase(it);
473 }
474 }
475 if (VLOG_IS_ON(heap)) {
476 VLOG(gc) << "Marked " << count << " references in mod union table";
477 }
478 }
479
ModUnionTableCardCache(const std::string & name,Heap * heap,space::ContinuousSpace * space)480 ModUnionTableCardCache::ModUnionTableCardCache(const std::string& name,
481 Heap* heap,
482 space::ContinuousSpace* space)
483 : ModUnionTable(name, heap, space) {
484 // Normally here we could use End() instead of Limit(), but for testing we may want to have a
485 // mod-union table for a space which can still grow.
486 if (!space->IsImageSpace()) {
487 CHECK_ALIGNED(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize);
488 }
489 card_bitmap_.reset(CardBitmap::Create(
490 "mod union bitmap", reinterpret_cast<uintptr_t>(space->Begin()),
491 RoundUp(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize)));
492 }
493
494 class CardBitVisitor {
495 public:
CardBitVisitor(MarkObjectVisitor * visitor,space::ContinuousSpace * space,space::ContinuousSpace * immune_space,ModUnionTable::CardBitmap * card_bitmap)496 CardBitVisitor(MarkObjectVisitor* visitor,
497 space::ContinuousSpace* space,
498 space::ContinuousSpace* immune_space,
499 ModUnionTable::CardBitmap* card_bitmap)
500 : visitor_(visitor),
501 space_(space),
502 immune_space_(immune_space),
503 bitmap_(space->GetLiveBitmap()),
504 card_bitmap_(card_bitmap) {
505 DCHECK(immune_space_ != nullptr);
506 }
507
operator ()(size_t bit_index) const508 void operator()(size_t bit_index) const {
509 const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
510 DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
511 << start << " " << *space_;
512 bool reference_to_other_space = false;
513 ModUnionScanImageRootVisitor scan_visitor(visitor_, space_, immune_space_,
514 &reference_to_other_space);
515 bitmap_->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
516 if (!reference_to_other_space) {
517 // No non null reference to another space, clear the bit.
518 card_bitmap_->ClearBit(bit_index);
519 }
520 }
521
522 private:
523 MarkObjectVisitor* const visitor_;
524 space::ContinuousSpace* const space_;
525 space::ContinuousSpace* const immune_space_;
526 ContinuousSpaceBitmap* const bitmap_;
527 ModUnionTable::CardBitmap* const card_bitmap_;
528 };
529
ProcessCards()530 void ModUnionTableCardCache::ProcessCards() {
531 CardTable* const card_table = GetHeap()->GetCardTable();
532 ModUnionAddToCardBitmapVisitor visitor(card_bitmap_.get(), card_table);
533 // Clear dirty cards in the this space and update the corresponding mod-union bits.
534 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
535 }
536
ClearTable()537 void ModUnionTableCardCache::ClearTable() {
538 card_bitmap_->Bitmap::Clear();
539 }
540
541 // Mark all references to the alloc space(s).
UpdateAndMarkReferences(MarkObjectVisitor * visitor)542 void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
543 // TODO: Needs better support for multi-images? b/26317072
544 space::ImageSpace* image_space =
545 heap_->GetBootImageSpaces().empty() ? nullptr : heap_->GetBootImageSpaces()[0];
546 // If we don't have an image space, just pass in space_ as the immune space. Pass in the same
547 // space_ instead of image_space to avoid a null check in ModUnionUpdateObjectReferencesVisitor.
548 CardBitVisitor bit_visitor(visitor, space_, image_space != nullptr ? image_space : space_,
549 card_bitmap_.get());
550 card_bitmap_->VisitSetBits(
551 0, RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize, bit_visitor);
552 }
553
VisitObjects(ObjectCallback callback,void * arg)554 void ModUnionTableCardCache::VisitObjects(ObjectCallback callback, void* arg) {
555 card_bitmap_->VisitSetBits(
556 0,
557 RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize,
558 [this, callback, arg](size_t bit_index) {
559 const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
560 DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
561 << start << " " << *space_;
562 space_->GetLiveBitmap()->VisitMarkedRange(start,
563 start + CardTable::kCardSize,
564 [callback, arg](mirror::Object* obj) {
565 callback(obj, arg);
566 });
567 });
568 }
569
Dump(std::ostream & os)570 void ModUnionTableCardCache::Dump(std::ostream& os) {
571 os << "ModUnionTable dirty cards: [";
572 // TODO: Find cleaner way of doing this.
573 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
574 addr += CardTable::kCardSize) {
575 if (card_bitmap_->Test(reinterpret_cast<uintptr_t>(addr))) {
576 os << reinterpret_cast<void*>(addr) << "-"
577 << reinterpret_cast<void*>(addr + CardTable::kCardSize) << "\n";
578 }
579 }
580 os << "]";
581 }
582
SetCards()583 void ModUnionTableCardCache::SetCards() {
584 // Only clean up to the end since there cannot be any objects past the End() of the space.
585 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
586 addr += CardTable::kCardSize) {
587 card_bitmap_->Set(reinterpret_cast<uintptr_t>(addr));
588 }
589 }
590
ContainsCardFor(uintptr_t addr)591 bool ModUnionTableCardCache::ContainsCardFor(uintptr_t addr) {
592 return card_bitmap_->Test(addr);
593 }
594
SetCards()595 void ModUnionTableReferenceCache::SetCards() {
596 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
597 addr += CardTable::kCardSize) {
598 cleared_cards_.insert(heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr)));
599 }
600 }
601
ContainsCardFor(uintptr_t addr)602 bool ModUnionTableReferenceCache::ContainsCardFor(uintptr_t addr) {
603 auto* card_ptr = heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr));
604 return cleared_cards_.find(card_ptr) != cleared_cards_.end() ||
605 references_.find(card_ptr) != references_.end();
606 }
607
608 } // namespace accounting
609 } // namespace gc
610 } // namespace art
611