blob: 14f59977d6338fe29c509ecd69f1af5aca6c7cd4 [file] [log] [blame]
Ian Rogers1d54e732013-05-02 21:10:01 -07001/*
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
Ian Rogers700a4022014-05-19 16:49:03 -070019#include <memory>
20
Ian Rogers1d54e732013-05-02 21:10:01 -070021#include "base/stl_util.h"
Mathieu Chartier4858a932015-01-23 13:18:53 -080022#include "bitmap-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070023#include "card_table-inl.h"
Mathieu Chartiera8e8f9c2014-04-09 14:51:05 -070024#include "gc/accounting/space_bitmap-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070025#include "gc/heap.h"
Lei Li3befba42015-01-23 16:37:59 +080026#include "gc/space/image_space.h"
Mathieu Chartier97509952015-07-13 14:35:43 -070027#include "gc/space/space.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070028#include "mirror/object-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070029#include "space_bitmap-inl.h"
Mathieu Chartierc8950822015-09-15 14:07:10 -070030#include "thread-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070031
32namespace art {
33namespace gc {
34namespace accounting {
35
Mathieu Chartier4858a932015-01-23 13:18:53 -080036class ModUnionAddToCardSetVisitor {
Ian Rogers1d54e732013-05-02 21:10:01 -070037 public:
Mathieu Chartier4858a932015-01-23 13:18:53 -080038 explicit ModUnionAddToCardSetVisitor(ModUnionTable::CardSet* const cleared_cards)
Mathieu Chartierc8950822015-09-15 14:07:10 -070039 : cleared_cards_(cleared_cards) {}
Ian Rogers1d54e732013-05-02 21:10:01 -070040
Mathieu Chartierc8950822015-09-15 14:07:10 -070041 inline void operator()(uint8_t* card,
42 uint8_t expected_value,
Mathieu Chartier4858a932015-01-23 13:18:53 -080043 uint8_t new_value ATTRIBUTE_UNUSED) const {
Ian Rogers1d54e732013-05-02 21:10:01 -070044 if (expected_value == CardTable::kCardDirty) {
45 cleared_cards_->insert(card);
46 }
47 }
48
49 private:
Mathieu Chartier0a9dc052013-07-25 11:01:28 -070050 ModUnionTable::CardSet* const cleared_cards_;
Ian Rogers1d54e732013-05-02 21:10:01 -070051};
52
Mathieu Chartier4858a932015-01-23 13:18:53 -080053class ModUnionAddToCardBitmapVisitor {
Ian Rogers1d54e732013-05-02 21:10:01 -070054 public:
Roland Levillain3887c462015-08-12 18:15:42 +010055 ModUnionAddToCardBitmapVisitor(ModUnionTable::CardBitmap* bitmap, CardTable* card_table)
Mathieu Chartierc8950822015-09-15 14:07:10 -070056 : bitmap_(bitmap), card_table_(card_table) {}
Ian Rogers1d54e732013-05-02 21:10:01 -070057
Mathieu Chartierc8950822015-09-15 14:07:10 -070058 inline void operator()(uint8_t* card,
59 uint8_t expected_value,
Mathieu Chartier4858a932015-01-23 13:18:53 -080060 uint8_t new_value ATTRIBUTE_UNUSED) const {
61 if (expected_value == CardTable::kCardDirty) {
62 // We want the address the card represents, not the address of the card.
63 bitmap_->Set(reinterpret_cast<uintptr_t>(card_table_->AddrFromCard(card)));
64 }
65 }
66
67 private:
68 ModUnionTable::CardBitmap* const bitmap_;
69 CardTable* const card_table_;
70};
71
72class ModUnionAddToCardVectorVisitor {
73 public:
74 explicit ModUnionAddToCardVectorVisitor(std::vector<uint8_t*>* cleared_cards)
75 : cleared_cards_(cleared_cards) {
76 }
77
78 void operator()(uint8_t* card, uint8_t expected_card, uint8_t new_card ATTRIBUTE_UNUSED) const {
Ian Rogers1d54e732013-05-02 21:10:01 -070079 if (expected_card == CardTable::kCardDirty) {
80 cleared_cards_->push_back(card);
81 }
82 }
Mathieu Chartier4858a932015-01-23 13:18:53 -080083
Ian Rogers1d54e732013-05-02 21:10:01 -070084 private:
Ian Rogers13735952014-10-08 12:43:28 -070085 std::vector<uint8_t*>* const cleared_cards_;
Ian Rogers1d54e732013-05-02 21:10:01 -070086};
87
Mathieu Chartier11409ae2013-09-23 11:49:36 -070088class ModUnionUpdateObjectReferencesVisitor {
Ian Rogers1d54e732013-05-02 21:10:01 -070089 public:
Mathieu Chartier97509952015-07-13 14:35:43 -070090 ModUnionUpdateObjectReferencesVisitor(MarkObjectVisitor* visitor,
Mathieu Chartiere4cab172014-08-19 18:24:04 -070091 space::ContinuousSpace* from_space,
Mathieu Chartier4858a932015-01-23 13:18:53 -080092 space::ContinuousSpace* immune_space,
Mathieu Chartiere4cab172014-08-19 18:24:04 -070093 bool* contains_reference_to_other_space)
Mathieu Chartierc8950822015-09-15 14:07:10 -070094 : visitor_(visitor),
95 from_space_(from_space),
96 immune_space_(immune_space),
97 contains_reference_to_other_space_(contains_reference_to_other_space) {}
Ian Rogers1d54e732013-05-02 21:10:01 -070098
Mathieu Chartier11409ae2013-09-23 11:49:36 -070099 // Extra parameters are required since we use this same visitor signature for checking objects.
Mathieu Chartierc8950822015-09-15 14:07:10 -0700100 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700101 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierd82e89e2015-08-05 10:10:07 -0700102 MarkReference(obj->GetFieldObjectReferenceAddr(offset));
Ian Rogers1d54e732013-05-02 21:10:01 -0700103 }
104
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700105 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700106 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierd82e89e2015-08-05 10:10:07 -0700107 VisitRoot(root);
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700108 }
109
110 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700111 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierd82e89e2015-08-05 10:10:07 -0700112 MarkReference(root);
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700113 }
114
Ian Rogers1d54e732013-05-02 21:10:01 -0700115 private:
Mathieu Chartierd82e89e2015-08-05 10:10:07 -0700116 template<bool kPoisonReferences>
117 void MarkReference(mirror::ObjectReference<kPoisonReferences, mirror::Object>* obj_ptr) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700118 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierd82e89e2015-08-05 10:10:07 -0700119 // Only add the reference if it is non null and fits our criteria.
120 mirror::Object* ref = obj_ptr->AsMirrorPtr();
121 if (ref != nullptr && !from_space_->HasAddress(ref) && !immune_space_->HasAddress(ref)) {
122 *contains_reference_to_other_space_ = true;
123 mirror::Object* new_object = visitor_->MarkObject(ref);
124 if (ref != new_object) {
125 obj_ptr->Assign(new_object);
126 }
127 }
128 }
129
Mathieu Chartier97509952015-07-13 14:35:43 -0700130 MarkObjectVisitor* const visitor_;
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700131 // Space which we are scanning
132 space::ContinuousSpace* const from_space_;
Mathieu Chartier4858a932015-01-23 13:18:53 -0800133 space::ContinuousSpace* const immune_space_;
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700134 // Set if we have any references to another space.
135 bool* const contains_reference_to_other_space_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700136};
137
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700138class ModUnionScanImageRootVisitor {
139 public:
Mathieu Chartier4858a932015-01-23 13:18:53 -0800140 // Immune space is any other space which we don't care about references to. Currently this is
141 // the image space in the case of the zygote mod union table.
Mathieu Chartier97509952015-07-13 14:35:43 -0700142 ModUnionScanImageRootVisitor(MarkObjectVisitor* visitor,
Mathieu Chartier4858a932015-01-23 13:18:53 -0800143 space::ContinuousSpace* from_space,
144 space::ContinuousSpace* immune_space,
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700145 bool* contains_reference_to_other_space)
Mathieu Chartierc8950822015-09-15 14:07:10 -0700146 : visitor_(visitor),
147 from_space_(from_space),
148 immune_space_(immune_space),
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700149 contains_reference_to_other_space_(contains_reference_to_other_space) {}
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700150
Mathieu Chartierc8950822015-09-15 14:07:10 -0700151 void operator()(mirror::Object* root) const
Mathieu Chartier90443472015-07-16 20:32:27 -0700152 REQUIRES(Locks::heap_bitmap_lock_)
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700153 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartier4858a932015-01-23 13:18:53 -0800154 DCHECK(root != nullptr);
Mathieu Chartierc8950822015-09-15 14:07:10 -0700155 ModUnionUpdateObjectReferencesVisitor ref_visitor(visitor_,
156 from_space_,
157 immune_space_,
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700158 contains_reference_to_other_space_);
Mathieu Chartier059ef3d2015-08-18 13:54:21 -0700159 root->VisitReferences(ref_visitor, VoidFunctor());
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700160 }
161
162 private:
Mathieu Chartier97509952015-07-13 14:35:43 -0700163 MarkObjectVisitor* const visitor_;
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700164 // Space which we are scanning
165 space::ContinuousSpace* const from_space_;
Mathieu Chartier4858a932015-01-23 13:18:53 -0800166 space::ContinuousSpace* const immune_space_;
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700167 // Set if we have any references to another space.
168 bool* const contains_reference_to_other_space_;
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700169};
170
171void ModUnionTableReferenceCache::ClearCards() {
Ian Rogers1d54e732013-05-02 21:10:01 -0700172 CardTable* card_table = GetHeap()->GetCardTable();
Mathieu Chartier4858a932015-01-23 13:18:53 -0800173 ModUnionAddToCardSetVisitor visitor(&cleared_cards_);
Ian Rogers1d54e732013-05-02 21:10:01 -0700174 // Clear dirty cards in the this space and update the corresponding mod-union bits.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700175 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700176}
177
Mathieu Chartier962cd7a2016-08-16 12:15:59 -0700178void ModUnionTableReferenceCache::ClearTable() {
179 cleared_cards_.clear();
180 references_.clear();
181}
182
Ian Rogers1d54e732013-05-02 21:10:01 -0700183class AddToReferenceArrayVisitor {
184 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100185 AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700186 MarkObjectVisitor* visitor,
Mathieu Chartierc8950822015-09-15 14:07:10 -0700187 std::vector<mirror::HeapReference<mirror::Object>*>* references,
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700188 bool* has_target_reference)
189 : mod_union_table_(mod_union_table),
190 visitor_(visitor),
191 references_(references),
192 has_target_reference_(has_target_reference) {}
Ian Rogers1d54e732013-05-02 21:10:01 -0700193
194 // Extra parameters are required since we use this same visitor signature for checking objects.
Mathieu Chartierc8950822015-09-15 14:07:10 -0700195 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700196 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierc8950822015-09-15 14:07:10 -0700197 mirror::HeapReference<mirror::Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
Mathieu Chartier407f7022014-02-18 14:37:05 -0800198 mirror::Object* ref = ref_ptr->AsMirrorPtr();
Ian Rogers1d54e732013-05-02 21:10:01 -0700199 // Only add the reference if it is non null and fits our criteria.
Mathieu Chartier4aeec172014-03-27 16:09:46 -0700200 if (ref != nullptr && mod_union_table_->ShouldAddReference(ref)) {
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700201 // Push the adddress of the reference.
Mathieu Chartier407f7022014-02-18 14:37:05 -0800202 references_->push_back(ref_ptr);
Ian Rogers1d54e732013-05-02 21:10:01 -0700203 }
204 }
205
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700206 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700207 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700208 if (!root->IsNull()) {
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700209 VisitRoot(root);
210 }
211 }
212
213 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700214 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700215 if (mod_union_table_->ShouldAddReference(root->AsMirrorPtr())) {
216 *has_target_reference_ = true;
217 // TODO: Add MarkCompressedReference callback here.
Mathieu Chartier56f9a892016-04-06 15:27:19 -0700218 mirror::Object* old_ref = root->AsMirrorPtr();
219 mirror::Object* new_ref = visitor_->MarkObject(old_ref);
220 if (old_ref != new_ref) {
221 root->Assign(new_ref);
222 }
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700223 }
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700224 }
225
Ian Rogers1d54e732013-05-02 21:10:01 -0700226 private:
227 ModUnionTableReferenceCache* const mod_union_table_;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700228 MarkObjectVisitor* const visitor_;
Mathieu Chartierc8950822015-09-15 14:07:10 -0700229 std::vector<mirror::HeapReference<mirror::Object>*>* const references_;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700230 bool* const has_target_reference_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700231};
232
233class ModUnionReferenceVisitor {
234 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100235 ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700236 MarkObjectVisitor* visitor,
Mathieu Chartierc8950822015-09-15 14:07:10 -0700237 std::vector<mirror::HeapReference<mirror::Object>*>* references,
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700238 bool* has_target_reference)
Roland Levillain3887c462015-08-12 18:15:42 +0100239 : mod_union_table_(mod_union_table),
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700240 visitor_(visitor),
241 references_(references),
242 has_target_reference_(has_target_reference) {}
Ian Rogers1d54e732013-05-02 21:10:01 -0700243
Mathieu Chartierc8950822015-09-15 14:07:10 -0700244 void operator()(mirror::Object* obj) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700245 REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700246 // We don't have an early exit since we use the visitor pattern, an early
247 // exit should significantly speed this up.
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700248 AddToReferenceArrayVisitor visitor(mod_union_table_,
249 visitor_,
250 references_,
251 has_target_reference_);
Mathieu Chartier059ef3d2015-08-18 13:54:21 -0700252 obj->VisitReferences(visitor, VoidFunctor());
Ian Rogers1d54e732013-05-02 21:10:01 -0700253 }
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700254
Ian Rogers1d54e732013-05-02 21:10:01 -0700255 private:
256 ModUnionTableReferenceCache* const mod_union_table_;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700257 MarkObjectVisitor* const visitor_;
Mathieu Chartierc8950822015-09-15 14:07:10 -0700258 std::vector<mirror::HeapReference<mirror::Object>*>* const references_;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700259 bool* const has_target_reference_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700260};
261
262class CheckReferenceVisitor {
263 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100264 CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
Mathieu Chartierc8950822015-09-15 14:07:10 -0700265 const std::set<mirror::Object*>& references)
Roland Levillain3887c462015-08-12 18:15:42 +0100266 : mod_union_table_(mod_union_table),
Mathieu Chartierc8950822015-09-15 14:07:10 -0700267 references_(references) {}
Ian Rogers1d54e732013-05-02 21:10:01 -0700268
269 // Extra parameters are required since we use this same visitor signature for checking objects.
Mathieu Chartierc8950822015-09-15 14:07:10 -0700270 void operator()(mirror::Object* obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700271 REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700272 mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
Mathieu Chartierc8950822015-09-15 14:07:10 -0700273 if (ref != nullptr &&
274 mod_union_table_->ShouldAddReference(ref) &&
Ian Rogers1d54e732013-05-02 21:10:01 -0700275 references_.find(ref) == references_.end()) {
Mathieu Chartier407f7022014-02-18 14:37:05 -0800276 Heap* heap = mod_union_table_->GetHeap();
Ian Rogers1d54e732013-05-02 21:10:01 -0700277 space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
278 space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
David Sehr709b0702016-10-13 09:12:37 -0700279 LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << obj->PrettyTypeOf()
280 << ")" << "References "
281 << reinterpret_cast<const void*>(ref) << "(" << mirror::Object::PrettyTypeOf(ref)
Mathieu Chartier407f7022014-02-18 14:37:05 -0800282 << ") without being in mod-union table";
283 LOG(INFO) << "FromSpace " << from_space->GetName() << " type "
284 << from_space->GetGcRetentionPolicy();
285 LOG(INFO) << "ToSpace " << to_space->GetName() << " type "
286 << to_space->GetGcRetentionPolicy();
Andreas Gampe3fec9ac2016-09-13 10:47:28 -0700287 heap->DumpSpaces(LOG_STREAM(INFO));
Ian Rogers1d54e732013-05-02 21:10:01 -0700288 LOG(FATAL) << "FATAL ERROR";
289 }
290 }
291
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700292 void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700293 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700294 if (kIsDebugBuild && !root->IsNull()) {
295 VisitRoot(root);
296 }
297 }
298
299 void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
Andreas Gampebdf7f1c2016-08-30 16:38:47 -0700300 REQUIRES_SHARED(Locks::mutator_lock_) {
Mathieu Chartierda7c6502015-07-23 16:01:26 -0700301 DCHECK(!mod_union_table_->ShouldAddReference(root->AsMirrorPtr()));
302 }
303
Ian Rogers1d54e732013-05-02 21:10:01 -0700304 private:
305 ModUnionTableReferenceCache* const mod_union_table_;
Mathieu Chartierc8950822015-09-15 14:07:10 -0700306 const std::set<mirror::Object*>& references_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700307};
308
309class ModUnionCheckReferences {
310 public:
Roland Levillain3887c462015-08-12 18:15:42 +0100311 ModUnionCheckReferences(ModUnionTableReferenceCache* mod_union_table,
Mathieu Chartierc8950822015-09-15 14:07:10 -0700312 const std::set<mirror::Object*>& references)
Mathieu Chartier90443472015-07-16 20:32:27 -0700313 REQUIRES(Locks::heap_bitmap_lock_)
Mathieu Chartierc8950822015-09-15 14:07:10 -0700314 : mod_union_table_(mod_union_table), references_(references) {}
Ian Rogers1d54e732013-05-02 21:10:01 -0700315
Mathieu Chartierc8950822015-09-15 14:07:10 -0700316 void operator()(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
Ian Rogers1d54e732013-05-02 21:10:01 -0700317 Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
Ian Rogers1d54e732013-05-02 21:10:01 -0700318 CheckReferenceVisitor visitor(mod_union_table_, references_);
Mathieu Chartier059ef3d2015-08-18 13:54:21 -0700319 obj->VisitReferences(visitor, VoidFunctor());
Ian Rogers1d54e732013-05-02 21:10:01 -0700320 }
321
322 private:
323 ModUnionTableReferenceCache* const mod_union_table_;
Mathieu Chartierc8950822015-09-15 14:07:10 -0700324 const std::set<mirror::Object*>& references_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700325};
326
Mathieu Chartier21328a12016-07-22 10:47:45 -0700327class EmptyMarkObjectVisitor : public MarkObjectVisitor {
328 public:
329 mirror::Object* MarkObject(mirror::Object* obj) OVERRIDE {return obj;}
330 void MarkHeapReference(mirror::HeapReference<mirror::Object>*) OVERRIDE {}
331};
332
333void ModUnionTable::FilterCards() {
334 EmptyMarkObjectVisitor visitor;
335 // Use empty visitor since filtering is automatically done by UpdateAndMarkReferences.
336 UpdateAndMarkReferences(&visitor);
337}
338
Ian Rogers1d54e732013-05-02 21:10:01 -0700339void ModUnionTableReferenceCache::Verify() {
340 // Start by checking that everything in the mod union table is marked.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700341 for (const auto& ref_pair : references_) {
Mathieu Chartierc8950822015-09-15 14:07:10 -0700342 for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800343 CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
Ian Rogers1d54e732013-05-02 21:10:01 -0700344 }
345 }
346
347 // Check the references of each clean card which is also in the mod union table.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700348 CardTable* card_table = heap_->GetCardTable();
Mathieu Chartiera8e8f9c2014-04-09 14:51:05 -0700349 ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700350 for (const auto& ref_pair : references_) {
Ian Rogers13735952014-10-08 12:43:28 -0700351 const uint8_t* card = ref_pair.first;
Ian Rogers1d54e732013-05-02 21:10:01 -0700352 if (*card == CardTable::kCardClean) {
Mathieu Chartierc8950822015-09-15 14:07:10 -0700353 std::set<mirror::Object*> reference_set;
354 for (mirror::HeapReference<mirror::Object>* obj_ptr : ref_pair.second) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800355 reference_set.insert(obj_ptr->AsMirrorPtr());
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700356 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700357 ModUnionCheckReferences visitor(this, reference_set);
358 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700359 live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700360 }
361 }
362}
363
364void ModUnionTableReferenceCache::Dump(std::ostream& os) {
365 CardTable* card_table = heap_->GetCardTable();
Ian Rogers1d54e732013-05-02 21:10:01 -0700366 os << "ModUnionTable cleared cards: [";
Ian Rogers13735952014-10-08 12:43:28 -0700367 for (uint8_t* card_addr : cleared_cards_) {
Mathieu Chartier02e25112013-08-14 16:14:24 -0700368 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
Ian Rogers1d54e732013-05-02 21:10:01 -0700369 uintptr_t end = start + CardTable::kCardSize;
370 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
371 }
372 os << "]\nModUnionTable references: [";
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700373 for (const auto& ref_pair : references_) {
Ian Rogers13735952014-10-08 12:43:28 -0700374 const uint8_t* card_addr = ref_pair.first;
Mathieu Chartier02e25112013-08-14 16:14:24 -0700375 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
Ian Rogers1d54e732013-05-02 21:10:01 -0700376 uintptr_t end = start + CardTable::kCardSize;
377 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
Mathieu Chartierc8950822015-09-15 14:07:10 -0700378 for (mirror::HeapReference<mirror::Object>* ref : ref_pair.second) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800379 os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ",";
Ian Rogers1d54e732013-05-02 21:10:01 -0700380 }
381 os << "},";
382 }
383}
384
Mathieu Chartier21328a12016-07-22 10:47:45 -0700385void ModUnionTableReferenceCache::VisitObjects(ObjectCallback* callback, void* arg) {
386 CardTable* const card_table = heap_->GetCardTable();
387 ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
388 for (uint8_t* card : cleared_cards_) {
389 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
390 uintptr_t end = start + CardTable::kCardSize;
391 live_bitmap->VisitMarkedRange(start,
392 end,
393 [this, callback, arg](mirror::Object* obj) {
394 callback(obj, arg);
395 });
396 }
397 // This may visit the same card twice, TODO avoid this.
398 for (const auto& pair : references_) {
399 const uint8_t* card = pair.first;
400 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
401 uintptr_t end = start + CardTable::kCardSize;
402 live_bitmap->VisitMarkedRange(start,
403 end,
404 [this, callback, arg](mirror::Object* obj) {
405 callback(obj, arg);
406 });
407 }
408}
409
Mathieu Chartier97509952015-07-13 14:35:43 -0700410void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700411 CardTable* const card_table = heap_->GetCardTable();
Mathieu Chartierc8950822015-09-15 14:07:10 -0700412 std::vector<mirror::HeapReference<mirror::Object>*> cards_references;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700413 // If has_target_reference is true then there was a GcRoot compressed reference which wasn't
414 // added. In this case we need to keep the card dirty.
415 // We don't know if the GcRoot addresses will remain constant, for example, classloaders have a
416 // hash set of GcRoot which may be resized or modified.
417 bool has_target_reference;
418 ModUnionReferenceVisitor add_visitor(this, visitor, &cards_references, &has_target_reference);
419 CardSet new_cleared_cards;
420 for (uint8_t* card : cleared_cards_) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700421 // Clear and re-compute alloc space references associated with this card.
422 cards_references.clear();
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700423 has_target_reference = false;
Ian Rogers1d54e732013-05-02 21:10:01 -0700424 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
425 uintptr_t end = start + CardTable::kCardSize;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700426 space::ContinuousSpace* space =
Mathieu Chartierc8950822015-09-15 14:07:10 -0700427 heap_->FindContinuousSpaceFromObject(reinterpret_cast<mirror::Object*>(start), false);
Mathieu Chartier02e25112013-08-14 16:14:24 -0700428 DCHECK(space != nullptr);
Mathieu Chartiera8e8f9c2014-04-09 14:51:05 -0700429 ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700430 live_bitmap->VisitMarkedRange(start, end, add_visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700431 // Update the corresponding references for the card.
Mathieu Chartier02e25112013-08-14 16:14:24 -0700432 auto found = references_.find(card);
Ian Rogers1d54e732013-05-02 21:10:01 -0700433 if (found == references_.end()) {
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700434 // Don't add card for an empty reference array.
435 if (!cards_references.empty()) {
436 references_.Put(card, cards_references);
Ian Rogers1d54e732013-05-02 21:10:01 -0700437 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700438 } else {
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700439 if (cards_references.empty()) {
440 references_.erase(found);
441 } else {
442 found->second = cards_references;
443 }
444 }
445 if (has_target_reference) {
446 // Keep this card for next time since it contains a GcRoot which matches the
447 // ShouldAddReference criteria. This usually occurs for class loaders.
448 new_cleared_cards.insert(card);
Ian Rogers1d54e732013-05-02 21:10:01 -0700449 }
450 }
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700451 cleared_cards_ = std::move(new_cleared_cards);
Ian Rogers1d54e732013-05-02 21:10:01 -0700452 size_t count = 0;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700453 for (auto it = references_.begin(); it != references_.end();) {
Mathieu Chartierc8950822015-09-15 14:07:10 -0700454 std::vector<mirror::HeapReference<mirror::Object>*>& references = it->second;
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700455 // Since there is no card mark for setting a reference to null, we check each reference.
456 // If all of the references of a card are null then we can remove that card. This is racy
457 // with the mutators, but handled by rescanning dirty cards.
458 bool all_null = true;
Mathieu Chartierc8950822015-09-15 14:07:10 -0700459 for (mirror::HeapReference<mirror::Object>* obj_ptr : references) {
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700460 if (obj_ptr->AsMirrorPtr() != nullptr) {
461 all_null = false;
462 visitor->MarkHeapReference(obj_ptr);
463 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700464 }
Mathieu Chartiera52f2f92015-08-16 14:37:04 -0700465 count += references.size();
466 if (!all_null) {
467 ++it;
468 } else {
469 // All null references, erase the array from the set.
470 it = references_.erase(it);
471 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700472 }
473 if (VLOG_IS_ON(heap)) {
474 VLOG(gc) << "Marked " << count << " references in mod union table";
475 }
476}
477
Mathieu Chartierc8950822015-09-15 14:07:10 -0700478ModUnionTableCardCache::ModUnionTableCardCache(const std::string& name,
479 Heap* heap,
Mathieu Chartier4858a932015-01-23 13:18:53 -0800480 space::ContinuousSpace* space)
481 : ModUnionTable(name, heap, space) {
482 // Normally here we could use End() instead of Limit(), but for testing we may want to have a
483 // mod-union table for a space which can still grow.
484 if (!space->IsImageSpace()) {
485 CHECK_ALIGNED(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize);
486 }
487 card_bitmap_.reset(CardBitmap::Create(
488 "mod union bitmap", reinterpret_cast<uintptr_t>(space->Begin()),
489 RoundUp(reinterpret_cast<uintptr_t>(space->Limit()), CardTable::kCardSize)));
490}
491
492class CardBitVisitor {
493 public:
Mathieu Chartierc8950822015-09-15 14:07:10 -0700494 CardBitVisitor(MarkObjectVisitor* visitor,
495 space::ContinuousSpace* space,
496 space::ContinuousSpace* immune_space,
497 ModUnionTable::CardBitmap* card_bitmap)
498 : visitor_(visitor),
499 space_(space),
500 immune_space_(immune_space),
501 bitmap_(space->GetLiveBitmap()),
502 card_bitmap_(card_bitmap) {
Mathieu Chartier4858a932015-01-23 13:18:53 -0800503 DCHECK(immune_space_ != nullptr);
504 }
505
506 void operator()(size_t bit_index) const {
507 const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
508 DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
509 << start << " " << *space_;
510 bool reference_to_other_space = false;
Mathieu Chartier97509952015-07-13 14:35:43 -0700511 ModUnionScanImageRootVisitor scan_visitor(visitor_, space_, immune_space_,
Mathieu Chartier4858a932015-01-23 13:18:53 -0800512 &reference_to_other_space);
513 bitmap_->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
514 if (!reference_to_other_space) {
515 // No non null reference to another space, clear the bit.
516 card_bitmap_->ClearBit(bit_index);
517 }
518 }
519
520 private:
Mathieu Chartier97509952015-07-13 14:35:43 -0700521 MarkObjectVisitor* const visitor_;
Mathieu Chartier4858a932015-01-23 13:18:53 -0800522 space::ContinuousSpace* const space_;
523 space::ContinuousSpace* const immune_space_;
524 ContinuousSpaceBitmap* const bitmap_;
525 ModUnionTable::CardBitmap* const card_bitmap_;
526};
527
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700528void ModUnionTableCardCache::ClearCards() {
Mathieu Chartier4858a932015-01-23 13:18:53 -0800529 CardTable* const card_table = GetHeap()->GetCardTable();
530 ModUnionAddToCardBitmapVisitor visitor(card_bitmap_.get(), card_table);
Ian Rogers1d54e732013-05-02 21:10:01 -0700531 // Clear dirty cards in the this space and update the corresponding mod-union bits.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700532 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700533}
534
Mathieu Chartier962cd7a2016-08-16 12:15:59 -0700535void ModUnionTableCardCache::ClearTable() {
536 card_bitmap_->Bitmap::Clear();
537}
538
Ian Rogers1d54e732013-05-02 21:10:01 -0700539// Mark all references to the alloc space(s).
Mathieu Chartier97509952015-07-13 14:35:43 -0700540void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
Jeff Haodcdc85b2015-12-04 14:06:18 -0800541 // TODO: Needs better support for multi-images? b/26317072
542 space::ImageSpace* image_space =
543 heap_->GetBootImageSpaces().empty() ? nullptr : heap_->GetBootImageSpaces()[0];
Mathieu Chartier4858a932015-01-23 13:18:53 -0800544 // If we don't have an image space, just pass in space_ as the immune space. Pass in the same
545 // space_ instead of image_space to avoid a null check in ModUnionUpdateObjectReferencesVisitor.
Mathieu Chartier97509952015-07-13 14:35:43 -0700546 CardBitVisitor bit_visitor(visitor, space_, image_space != nullptr ? image_space : space_,
Mathieu Chartier4858a932015-01-23 13:18:53 -0800547 card_bitmap_.get());
548 card_bitmap_->VisitSetBits(
Mathieu Chartier97509952015-07-13 14:35:43 -0700549 0, RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize, bit_visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700550}
551
Mathieu Chartier21328a12016-07-22 10:47:45 -0700552void ModUnionTableCardCache::VisitObjects(ObjectCallback* callback, void* arg) {
553 card_bitmap_->VisitSetBits(
554 0,
555 RoundUp(space_->Size(), CardTable::kCardSize) / CardTable::kCardSize,
556 [this, callback, arg](size_t bit_index) {
557 const uintptr_t start = card_bitmap_->AddrFromBitIndex(bit_index);
558 DCHECK(space_->HasAddress(reinterpret_cast<mirror::Object*>(start)))
559 << start << " " << *space_;
560 space_->GetLiveBitmap()->VisitMarkedRange(start,
561 start + CardTable::kCardSize,
562 [this, callback, arg](mirror::Object* obj) {
563 callback(obj, arg);
564 });
565 });
566}
567
Ian Rogers1d54e732013-05-02 21:10:01 -0700568void ModUnionTableCardCache::Dump(std::ostream& os) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700569 os << "ModUnionTable dirty cards: [";
Mathieu Chartier4858a932015-01-23 13:18:53 -0800570 // TODO: Find cleaner way of doing this.
571 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
572 addr += CardTable::kCardSize) {
573 if (card_bitmap_->Test(reinterpret_cast<uintptr_t>(addr))) {
574 os << reinterpret_cast<void*>(addr) << "-"
575 << reinterpret_cast<void*>(addr + CardTable::kCardSize) << "\n";
576 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700577 }
578 os << "]";
579}
580
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700581void ModUnionTableCardCache::SetCards() {
Mathieu Chartier4858a932015-01-23 13:18:53 -0800582 // Only clean up to the end since there cannot be any objects past the End() of the space.
Ian Rogers13735952014-10-08 12:43:28 -0700583 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700584 addr += CardTable::kCardSize) {
Mathieu Chartier4858a932015-01-23 13:18:53 -0800585 card_bitmap_->Set(reinterpret_cast<uintptr_t>(addr));
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700586 }
587}
588
Mathieu Chartier4858a932015-01-23 13:18:53 -0800589bool ModUnionTableCardCache::ContainsCardFor(uintptr_t addr) {
590 return card_bitmap_->Test(addr);
591}
592
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700593void ModUnionTableReferenceCache::SetCards() {
Mathieu Chartier4858a932015-01-23 13:18:53 -0800594 for (uint8_t* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
595 addr += CardTable::kCardSize) {
596 cleared_cards_.insert(heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr)));
597 }
598}
599
600bool ModUnionTableReferenceCache::ContainsCardFor(uintptr_t addr) {
601 auto* card_ptr = heap_->GetCardTable()->CardFromAddr(reinterpret_cast<void*>(addr));
602 return cleared_cards_.find(card_ptr) != cleared_cards_.end() ||
603 references_.find(card_ptr) != references_.end();
Mathieu Chartiere4cab172014-08-19 18:24:04 -0700604}
605
Ian Rogers1d54e732013-05-02 21:10:01 -0700606} // namespace accounting
607} // namespace gc
608} // namespace art