blob: 228d1dc6683ce07af11c64f379e320af72e10a0f [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"
22#include "card_table-inl.h"
23#include "heap_bitmap.h"
Mathieu Chartiera8e8f9c2014-04-09 14:51:05 -070024#include "gc/accounting/space_bitmap-inl.h"
Mathieu Chartier11409ae2013-09-23 11:49:36 -070025#include "gc/collector/mark_sweep.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070026#include "gc/collector/mark_sweep-inl.h"
27#include "gc/heap.h"
28#include "gc/space/space.h"
Brian Carlstromea46f952013-07-30 01:26:50 -070029#include "mirror/art_field-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070030#include "mirror/object-inl.h"
31#include "mirror/class-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070032#include "mirror/object_array-inl.h"
33#include "space_bitmap-inl.h"
34#include "thread.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070035
Brian Carlstrom3e3d5912013-07-18 00:19:45 -070036using ::art::mirror::Object;
Ian Rogers1d54e732013-05-02 21:10:01 -070037
38namespace art {
39namespace gc {
40namespace accounting {
41
Ian Rogers1d54e732013-05-02 21:10:01 -070042class ModUnionClearCardSetVisitor {
43 public:
Mathieu Chartier0a9dc052013-07-25 11:01:28 -070044 explicit ModUnionClearCardSetVisitor(ModUnionTable::CardSet* const cleared_cards)
Ian Rogers1d54e732013-05-02 21:10:01 -070045 : cleared_cards_(cleared_cards) {
46 }
47
Brian Carlstromdf629502013-07-17 22:39:56 -070048 inline void operator()(byte* card, byte expected_value, byte new_value) const {
Ian Rogers1d54e732013-05-02 21:10:01 -070049 if (expected_value == CardTable::kCardDirty) {
50 cleared_cards_->insert(card);
51 }
52 }
53
54 private:
Mathieu Chartier0a9dc052013-07-25 11:01:28 -070055 ModUnionTable::CardSet* const cleared_cards_;
Ian Rogers1d54e732013-05-02 21:10:01 -070056};
57
58class ModUnionClearCardVisitor {
59 public:
60 explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
61 : cleared_cards_(cleared_cards) {
62 }
63
Brian Carlstromdf629502013-07-17 22:39:56 -070064 void operator()(byte* card, byte expected_card, byte new_card) const {
Ian Rogers1d54e732013-05-02 21:10:01 -070065 if (expected_card == CardTable::kCardDirty) {
66 cleared_cards_->push_back(card);
67 }
68 }
69 private:
70 std::vector<byte*>* const cleared_cards_;
71};
72
Mathieu Chartier11409ae2013-09-23 11:49:36 -070073class ModUnionUpdateObjectReferencesVisitor {
Ian Rogers1d54e732013-05-02 21:10:01 -070074 public:
Mathieu Chartier407f7022014-02-18 14:37:05 -080075 ModUnionUpdateObjectReferencesVisitor(MarkHeapReferenceCallback* callback, void* arg)
Mathieu Chartier83c8ee02014-01-28 14:50:23 -080076 : callback_(callback),
Mathieu Chartier11409ae2013-09-23 11:49:36 -070077 arg_(arg) {
78 }
Ian Rogers1d54e732013-05-02 21:10:01 -070079
Mathieu Chartier11409ae2013-09-23 11:49:36 -070080 // Extra parameters are required since we use this same visitor signature for checking objects.
Mathieu Chartier4aeec172014-03-27 16:09:46 -070081 void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
Mathieu Chartier407f7022014-02-18 14:37:05 -080082 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
Mathieu Chartier11409ae2013-09-23 11:49:36 -070083 // Only add the reference if it is non null and fits our criteria.
Mathieu Chartier407f7022014-02-18 14:37:05 -080084 mirror::HeapReference<Object>* obj_ptr = obj->GetFieldObjectReferenceAddr(offset);
85 if (obj_ptr->AsMirrorPtr() != nullptr) {
86 callback_(obj_ptr, arg_);
Mathieu Chartier11409ae2013-09-23 11:49:36 -070087 }
Ian Rogers1d54e732013-05-02 21:10:01 -070088 }
89
90 private:
Mathieu Chartier407f7022014-02-18 14:37:05 -080091 MarkHeapReferenceCallback* const callback_;
Mathieu Chartier11409ae2013-09-23 11:49:36 -070092 void* arg_;
Ian Rogers1d54e732013-05-02 21:10:01 -070093};
94
Mathieu Chartier11409ae2013-09-23 11:49:36 -070095class ModUnionScanImageRootVisitor {
96 public:
Mathieu Chartier407f7022014-02-18 14:37:05 -080097 ModUnionScanImageRootVisitor(MarkHeapReferenceCallback* callback, void* arg)
Mathieu Chartier83c8ee02014-01-28 14:50:23 -080098 : callback_(callback), arg_(arg) {}
Mathieu Chartier11409ae2013-09-23 11:49:36 -070099
100 void operator()(Object* root) const
101 EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
102 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
103 DCHECK(root != NULL);
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800104 ModUnionUpdateObjectReferencesVisitor ref_visitor(callback_, arg_);
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700105 root->VisitReferences<kMovingClasses>(ref_visitor, VoidFunctor());
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700106 }
107
108 private:
Mathieu Chartier407f7022014-02-18 14:37:05 -0800109 MarkHeapReferenceCallback* const callback_;
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800110 void* const arg_;
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700111};
112
113void ModUnionTableReferenceCache::ClearCards() {
Ian Rogers1d54e732013-05-02 21:10:01 -0700114 CardTable* card_table = GetHeap()->GetCardTable();
115 ModUnionClearCardSetVisitor visitor(&cleared_cards_);
116 // Clear dirty cards in the this space and update the corresponding mod-union bits.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700117 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700118}
119
120class AddToReferenceArrayVisitor {
121 public:
122 explicit AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800123 std::vector<mirror::HeapReference<Object>*>* references)
124 : mod_union_table_(mod_union_table), references_(references) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700125 }
126
127 // Extra parameters are required since we use this same visitor signature for checking objects.
Mathieu Chartier4aeec172014-03-27 16:09:46 -0700128 void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
Mathieu Chartier407f7022014-02-18 14:37:05 -0800129 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
130 mirror::HeapReference<Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
131 mirror::Object* ref = ref_ptr->AsMirrorPtr();
Ian Rogers1d54e732013-05-02 21:10:01 -0700132 // Only add the reference if it is non null and fits our criteria.
Mathieu Chartier4aeec172014-03-27 16:09:46 -0700133 if (ref != nullptr && mod_union_table_->ShouldAddReference(ref)) {
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700134 // Push the adddress of the reference.
Mathieu Chartier407f7022014-02-18 14:37:05 -0800135 references_->push_back(ref_ptr);
Ian Rogers1d54e732013-05-02 21:10:01 -0700136 }
137 }
138
139 private:
140 ModUnionTableReferenceCache* const mod_union_table_;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800141 std::vector<mirror::HeapReference<Object>*>* const references_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700142};
143
144class ModUnionReferenceVisitor {
145 public:
146 explicit ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800147 std::vector<mirror::HeapReference<Object>*>* references)
Ian Rogers1d54e732013-05-02 21:10:01 -0700148 : mod_union_table_(mod_union_table),
149 references_(references) {
150 }
151
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700152 void operator()(Object* obj) const
Ian Rogers1d54e732013-05-02 21:10:01 -0700153 SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700154 // We don't have an early exit since we use the visitor pattern, an early
155 // exit should significantly speed this up.
156 AddToReferenceArrayVisitor visitor(mod_union_table_, references_);
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700157 obj->VisitReferences<kMovingClasses>(visitor, VoidFunctor());
Ian Rogers1d54e732013-05-02 21:10:01 -0700158 }
159 private:
160 ModUnionTableReferenceCache* const mod_union_table_;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800161 std::vector<mirror::HeapReference<Object>*>* const references_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700162};
163
164class CheckReferenceVisitor {
165 public:
166 explicit CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
167 const std::set<const Object*>& references)
168 : mod_union_table_(mod_union_table),
169 references_(references) {
170 }
171
172 // Extra parameters are required since we use this same visitor signature for checking objects.
Mathieu Chartier4aeec172014-03-27 16:09:46 -0700173 void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
Ian Rogers1d54e732013-05-02 21:10:01 -0700174 SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700175 mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
Mathieu Chartier4aeec172014-03-27 16:09:46 -0700176 if (ref != nullptr && mod_union_table_->ShouldAddReference(ref) &&
Ian Rogers1d54e732013-05-02 21:10:01 -0700177 references_.find(ref) == references_.end()) {
Mathieu Chartier407f7022014-02-18 14:37:05 -0800178 Heap* heap = mod_union_table_->GetHeap();
Ian Rogers1d54e732013-05-02 21:10:01 -0700179 space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
180 space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
Mathieu Chartier407f7022014-02-18 14:37:05 -0800181 LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << PrettyTypeOf(obj)
182 << ")" << "References " << reinterpret_cast<const void*>(ref) << "(" << PrettyTypeOf(ref)
183 << ") without being in mod-union table";
184 LOG(INFO) << "FromSpace " << from_space->GetName() << " type "
185 << from_space->GetGcRetentionPolicy();
186 LOG(INFO) << "ToSpace " << to_space->GetName() << " type "
187 << to_space->GetGcRetentionPolicy();
188 heap->DumpSpaces();
Ian Rogers1d54e732013-05-02 21:10:01 -0700189 LOG(FATAL) << "FATAL ERROR";
190 }
191 }
192
193 private:
194 ModUnionTableReferenceCache* const mod_union_table_;
195 const std::set<const Object*>& references_;
196};
197
198class ModUnionCheckReferences {
199 public:
Brian Carlstromdf629502013-07-17 22:39:56 -0700200 explicit ModUnionCheckReferences(ModUnionTableReferenceCache* mod_union_table,
201 const std::set<const Object*>& references)
Ian Rogers1d54e732013-05-02 21:10:01 -0700202 EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
203 : mod_union_table_(mod_union_table), references_(references) {
204 }
205
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700206 void operator()(Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
Ian Rogers1d54e732013-05-02 21:10:01 -0700207 Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
Ian Rogers1d54e732013-05-02 21:10:01 -0700208 CheckReferenceVisitor visitor(mod_union_table_, references_);
Ian Rogersb0fa5dc2014-04-28 16:47:08 -0700209 obj->VisitReferences<kMovingClasses>(visitor, VoidFunctor());
Ian Rogers1d54e732013-05-02 21:10:01 -0700210 }
211
212 private:
213 ModUnionTableReferenceCache* const mod_union_table_;
214 const std::set<const Object*>& references_;
215};
216
217void ModUnionTableReferenceCache::Verify() {
218 // Start by checking that everything in the mod union table is marked.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700219 for (const auto& ref_pair : references_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800220 for (mirror::HeapReference<Object>* ref : ref_pair.second) {
221 CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
Ian Rogers1d54e732013-05-02 21:10:01 -0700222 }
223 }
224
225 // Check the references of each clean card which is also in the mod union table.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700226 CardTable* card_table = heap_->GetCardTable();
Mathieu Chartiera8e8f9c2014-04-09 14:51:05 -0700227 ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700228 for (const auto& ref_pair : references_) {
229 const byte* card = ref_pair.first;
Ian Rogers1d54e732013-05-02 21:10:01 -0700230 if (*card == CardTable::kCardClean) {
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700231 std::set<const Object*> reference_set;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800232 for (mirror::HeapReference<Object>* obj_ptr : ref_pair.second) {
233 reference_set.insert(obj_ptr->AsMirrorPtr());
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700234 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700235 ModUnionCheckReferences visitor(this, reference_set);
236 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700237 live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700238 }
239 }
240}
241
242void ModUnionTableReferenceCache::Dump(std::ostream& os) {
243 CardTable* card_table = heap_->GetCardTable();
Ian Rogers1d54e732013-05-02 21:10:01 -0700244 os << "ModUnionTable cleared cards: [";
Mathieu Chartier02e25112013-08-14 16:14:24 -0700245 for (byte* card_addr : cleared_cards_) {
246 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
Ian Rogers1d54e732013-05-02 21:10:01 -0700247 uintptr_t end = start + CardTable::kCardSize;
248 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
249 }
250 os << "]\nModUnionTable references: [";
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700251 for (const auto& ref_pair : references_) {
252 const byte* card_addr = ref_pair.first;
Mathieu Chartier02e25112013-08-14 16:14:24 -0700253 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
Ian Rogers1d54e732013-05-02 21:10:01 -0700254 uintptr_t end = start + CardTable::kCardSize;
255 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
Ian Rogersef7d42f2014-01-06 12:55:46 -0800256 for (mirror::HeapReference<Object>* ref : ref_pair.second) {
257 os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ",";
Ian Rogers1d54e732013-05-02 21:10:01 -0700258 }
259 os << "},";
260 }
261}
262
Mathieu Chartier407f7022014-02-18 14:37:05 -0800263void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
Mathieu Chartier815873e2014-02-13 18:02:13 -0800264 void* arg) {
Mathieu Chartier4aeec172014-03-27 16:09:46 -0700265 CardTable* card_table = heap_->GetCardTable();
Ian Rogers1d54e732013-05-02 21:10:01 -0700266
Ian Rogersef7d42f2014-01-06 12:55:46 -0800267 std::vector<mirror::HeapReference<Object>*> cards_references;
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700268 ModUnionReferenceVisitor add_visitor(this, &cards_references);
Ian Rogers1d54e732013-05-02 21:10:01 -0700269
Mathieu Chartier02e25112013-08-14 16:14:24 -0700270 for (const auto& card : cleared_cards_) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700271 // Clear and re-compute alloc space references associated with this card.
272 cards_references.clear();
273 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
274 uintptr_t end = start + CardTable::kCardSize;
Mathieu Chartier4aeec172014-03-27 16:09:46 -0700275 auto* space = heap_->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
Mathieu Chartier02e25112013-08-14 16:14:24 -0700276 DCHECK(space != nullptr);
Mathieu Chartiera8e8f9c2014-04-09 14:51:05 -0700277 ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700278 live_bitmap->VisitMarkedRange(start, end, add_visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700279
280 // Update the corresponding references for the card.
Mathieu Chartier02e25112013-08-14 16:14:24 -0700281 auto found = references_.find(card);
Ian Rogers1d54e732013-05-02 21:10:01 -0700282 if (found == references_.end()) {
283 if (cards_references.empty()) {
284 // No reason to add empty array.
285 continue;
286 }
287 references_.Put(card, cards_references);
288 } else {
289 found->second = cards_references;
290 }
291 }
292 cleared_cards_.clear();
Ian Rogers1d54e732013-05-02 21:10:01 -0700293 size_t count = 0;
Mathieu Chartier02e25112013-08-14 16:14:24 -0700294 for (const auto& ref : references_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800295 for (mirror::HeapReference<Object>* obj_ptr : ref.second) {
Mathieu Chartier407f7022014-02-18 14:37:05 -0800296 callback(obj_ptr, arg);
Ian Rogers1d54e732013-05-02 21:10:01 -0700297 }
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700298 count += ref.second.size();
Ian Rogers1d54e732013-05-02 21:10:01 -0700299 }
300 if (VLOG_IS_ON(heap)) {
301 VLOG(gc) << "Marked " << count << " references in mod union table";
302 }
303}
304
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700305void ModUnionTableCardCache::ClearCards() {
Ian Rogers1d54e732013-05-02 21:10:01 -0700306 CardTable* card_table = GetHeap()->GetCardTable();
307 ModUnionClearCardSetVisitor visitor(&cleared_cards_);
308 // Clear dirty cards in the this space and update the corresponding mod-union bits.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700309 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700310}
311
312// Mark all references to the alloc space(s).
Mathieu Chartier407f7022014-02-18 14:37:05 -0800313void ModUnionTableCardCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
314 void* arg) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700315 CardTable* card_table = heap_->GetCardTable();
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800316 ModUnionScanImageRootVisitor scan_visitor(callback, arg);
Mathieu Chartiera8e8f9c2014-04-09 14:51:05 -0700317 ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
Mathieu Chartier02e25112013-08-14 16:14:24 -0700318 for (const byte* card_addr : cleared_cards_) {
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700319 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
320 DCHECK(space_->HasAddress(reinterpret_cast<Object*>(start)));
321 bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700322 }
323}
324
325void ModUnionTableCardCache::Dump(std::ostream& os) {
326 CardTable* card_table = heap_->GetCardTable();
Ian Rogers1d54e732013-05-02 21:10:01 -0700327 os << "ModUnionTable dirty cards: [";
Mathieu Chartier02e25112013-08-14 16:14:24 -0700328 for (const byte* card_addr : cleared_cards_) {
329 auto start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
330 auto end = start + CardTable::kCardSize;
Mathieu Chartier590fee92013-09-13 13:46:47 -0700331 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "\n";
Ian Rogers1d54e732013-05-02 21:10:01 -0700332 }
333 os << "]";
334}
335
336} // namespace accounting
337} // namespace gc
338} // namespace art