blob: 8bc1ced13cbbd3055a5a90ea58921aeb9e489301 [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
19#include "base/stl_util.h"
20#include "card_table-inl.h"
21#include "heap_bitmap.h"
Mathieu Chartier11409ae2013-09-23 11:49:36 -070022#include "gc/collector/mark_sweep.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070023#include "gc/collector/mark_sweep-inl.h"
24#include "gc/heap.h"
25#include "gc/space/space.h"
Brian Carlstromea46f952013-07-30 01:26:50 -070026#include "mirror/art_field-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070027#include "mirror/object-inl.h"
28#include "mirror/class-inl.h"
Ian Rogers1d54e732013-05-02 21:10:01 -070029#include "mirror/object_array-inl.h"
30#include "space_bitmap-inl.h"
31#include "thread.h"
32#include "UniquePtr.h"
33
Brian Carlstrom3e3d5912013-07-18 00:19:45 -070034using ::art::mirror::Object;
Ian Rogers1d54e732013-05-02 21:10:01 -070035
36namespace art {
37namespace gc {
38namespace accounting {
39
Ian Rogers1d54e732013-05-02 21:10:01 -070040class ModUnionClearCardSetVisitor {
41 public:
Mathieu Chartier0a9dc052013-07-25 11:01:28 -070042 explicit ModUnionClearCardSetVisitor(ModUnionTable::CardSet* const cleared_cards)
Ian Rogers1d54e732013-05-02 21:10:01 -070043 : cleared_cards_(cleared_cards) {
44 }
45
Brian Carlstromdf629502013-07-17 22:39:56 -070046 inline void operator()(byte* card, byte expected_value, byte new_value) const {
Ian Rogers1d54e732013-05-02 21:10:01 -070047 if (expected_value == CardTable::kCardDirty) {
48 cleared_cards_->insert(card);
49 }
50 }
51
52 private:
Mathieu Chartier0a9dc052013-07-25 11:01:28 -070053 ModUnionTable::CardSet* const cleared_cards_;
Ian Rogers1d54e732013-05-02 21:10:01 -070054};
55
56class ModUnionClearCardVisitor {
57 public:
58 explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
59 : cleared_cards_(cleared_cards) {
60 }
61
Brian Carlstromdf629502013-07-17 22:39:56 -070062 void operator()(byte* card, byte expected_card, byte new_card) const {
Ian Rogers1d54e732013-05-02 21:10:01 -070063 if (expected_card == CardTable::kCardDirty) {
64 cleared_cards_->push_back(card);
65 }
66 }
67 private:
68 std::vector<byte*>* const cleared_cards_;
69};
70
Mathieu Chartier11409ae2013-09-23 11:49:36 -070071class ModUnionUpdateObjectReferencesVisitor {
Ian Rogers1d54e732013-05-02 21:10:01 -070072 public:
Mathieu Chartier815873e2014-02-13 18:02:13 -080073 ModUnionUpdateObjectReferencesVisitor(MarkObjectCallback* callback, void* arg)
Mathieu Chartier83c8ee02014-01-28 14:50:23 -080074 : callback_(callback),
Mathieu Chartier11409ae2013-09-23 11:49:36 -070075 arg_(arg) {
76 }
Ian Rogers1d54e732013-05-02 21:10:01 -070077
Mathieu Chartier11409ae2013-09-23 11:49:36 -070078 // Extra parameters are required since we use this same visitor signature for checking objects.
79 void operator()(Object* obj, Object* ref, const MemberOffset& offset,
80 bool /* is_static */) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
81 // Only add the reference if it is non null and fits our criteria.
82 if (ref != nullptr) {
Mathieu Chartier815873e2014-02-13 18:02:13 -080083 Object* new_ref = callback_(ref, arg_);
Mathieu Chartier11409ae2013-09-23 11:49:36 -070084 if (new_ref != ref) {
Ian Rogersef7d42f2014-01-06 12:55:46 -080085 // Use SetFieldObjectWithoutWriteBarrier to avoid card mark as an optimization which
86 // reduces dirtied pages and improves performance.
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010087 if (Runtime::Current()->IsActiveTransaction()) {
88 obj->SetFieldObjectWithoutWriteBarrier<true>(offset, new_ref, true);
89 } else {
90 obj->SetFieldObjectWithoutWriteBarrier<false>(offset, new_ref, true);
91 }
Mathieu Chartier11409ae2013-09-23 11:49:36 -070092 }
93 }
Ian Rogers1d54e732013-05-02 21:10:01 -070094 }
95
96 private:
Mathieu Chartier815873e2014-02-13 18:02:13 -080097 MarkObjectCallback* const callback_;
Mathieu Chartier11409ae2013-09-23 11:49:36 -070098 void* arg_;
Ian Rogers1d54e732013-05-02 21:10:01 -070099};
100
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700101class ModUnionScanImageRootVisitor {
102 public:
Mathieu Chartier815873e2014-02-13 18:02:13 -0800103 ModUnionScanImageRootVisitor(MarkObjectCallback* callback, void* arg)
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800104 : callback_(callback), arg_(arg) {}
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700105
106 void operator()(Object* root) const
107 EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
108 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
109 DCHECK(root != NULL);
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800110 ModUnionUpdateObjectReferencesVisitor ref_visitor(callback_, arg_);
Mathieu Chartier0e54cd02014-03-20 12:41:23 -0700111 collector::MarkSweep::VisitObjectReferences<kMovingClasses>(root, ref_visitor);
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700112 }
113
114 private:
Mathieu Chartier815873e2014-02-13 18:02:13 -0800115 MarkObjectCallback* const callback_;
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800116 void* const arg_;
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700117};
118
119void ModUnionTableReferenceCache::ClearCards() {
Ian Rogers1d54e732013-05-02 21:10:01 -0700120 CardTable* card_table = GetHeap()->GetCardTable();
121 ModUnionClearCardSetVisitor visitor(&cleared_cards_);
122 // Clear dirty cards in the this space and update the corresponding mod-union bits.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700123 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700124}
125
126class AddToReferenceArrayVisitor {
127 public:
128 explicit AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800129 std::vector<mirror::HeapReference<Object>*>* references)
130 : mod_union_table_(mod_union_table), references_(references) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700131 }
132
133 // Extra parameters are required since we use this same visitor signature for checking objects.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700134 void operator()(Object* obj, Object* ref, const MemberOffset& offset,
Brian Carlstromdf629502013-07-17 22:39:56 -0700135 bool /* is_static */) const {
Ian Rogers1d54e732013-05-02 21:10:01 -0700136 // Only add the reference if it is non null and fits our criteria.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700137 if (ref != nullptr && mod_union_table_->AddReference(obj, ref)) {
138 // Push the adddress of the reference.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800139 references_->push_back(obj->GetFieldObjectReferenceAddr(offset));
Ian Rogers1d54e732013-05-02 21:10:01 -0700140 }
141 }
142
143 private:
144 ModUnionTableReferenceCache* const mod_union_table_;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800145 std::vector<mirror::HeapReference<Object>*>* const references_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700146};
147
148class ModUnionReferenceVisitor {
149 public:
150 explicit ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
Ian Rogersef7d42f2014-01-06 12:55:46 -0800151 std::vector<mirror::HeapReference<Object>*>* references)
Ian Rogers1d54e732013-05-02 21:10:01 -0700152 : mod_union_table_(mod_union_table),
153 references_(references) {
154 }
155
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700156 void operator()(Object* obj) const
Ian Rogers1d54e732013-05-02 21:10:01 -0700157 SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
158 DCHECK(obj != NULL);
159 // We don't have an early exit since we use the visitor pattern, an early
160 // exit should significantly speed this up.
161 AddToReferenceArrayVisitor visitor(mod_union_table_, references_);
Mathieu Chartier0e54cd02014-03-20 12:41:23 -0700162 collector::MarkSweep::VisitObjectReferences<kMovingClasses>(obj, visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700163 }
164 private:
165 ModUnionTableReferenceCache* const mod_union_table_;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800166 std::vector<mirror::HeapReference<Object>*>* const references_;
Ian Rogers1d54e732013-05-02 21:10:01 -0700167};
168
169class CheckReferenceVisitor {
170 public:
171 explicit CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
172 const std::set<const Object*>& references)
173 : mod_union_table_(mod_union_table),
174 references_(references) {
175 }
176
177 // Extra parameters are required since we use this same visitor signature for checking objects.
Ian Rogersef7d42f2014-01-06 12:55:46 -0800178 void operator()(Object* obj, Object* ref,
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700179 const MemberOffset& /* offset */, bool /* is_static */) const
Ian Rogers1d54e732013-05-02 21:10:01 -0700180 SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
181 Heap* heap = mod_union_table_->GetHeap();
182 if (ref != NULL && mod_union_table_->AddReference(obj, ref) &&
183 references_.find(ref) == references_.end()) {
184 space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
185 space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
186 LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << PrettyTypeOf(obj) << ")"
187 << "References " << reinterpret_cast<const void*>(ref)
188 << "(" << PrettyTypeOf(ref) << ") without being in mod-union table";
189 LOG(INFO) << "FromSpace " << from_space->GetName() << " type " << from_space->GetGcRetentionPolicy();
190 LOG(INFO) << "ToSpace " << to_space->GetName() << " type " << to_space->GetGcRetentionPolicy();
191 mod_union_table_->GetHeap()->DumpSpaces();
192 LOG(FATAL) << "FATAL ERROR";
193 }
194 }
195
196 private:
197 ModUnionTableReferenceCache* const mod_union_table_;
198 const std::set<const Object*>& references_;
199};
200
201class ModUnionCheckReferences {
202 public:
Brian Carlstromdf629502013-07-17 22:39:56 -0700203 explicit ModUnionCheckReferences(ModUnionTableReferenceCache* mod_union_table,
204 const std::set<const Object*>& references)
Ian Rogers1d54e732013-05-02 21:10:01 -0700205 EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
206 : mod_union_table_(mod_union_table), references_(references) {
207 }
208
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700209 void operator()(Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
Ian Rogers1d54e732013-05-02 21:10:01 -0700210 Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
211 DCHECK(obj != NULL);
212 CheckReferenceVisitor visitor(mod_union_table_, references_);
Mathieu Chartier0e54cd02014-03-20 12:41:23 -0700213 collector::MarkSweep::VisitObjectReferences<kMovingClasses>(obj, visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700214 }
215
216 private:
217 ModUnionTableReferenceCache* const mod_union_table_;
218 const std::set<const Object*>& references_;
219};
220
221void ModUnionTableReferenceCache::Verify() {
222 // Start by checking that everything in the mod union table is marked.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700223 for (const auto& ref_pair : references_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800224 for (mirror::HeapReference<Object>* ref : ref_pair.second) {
225 CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
Ian Rogers1d54e732013-05-02 21:10:01 -0700226 }
227 }
228
229 // Check the references of each clean card which is also in the mod union table.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700230 CardTable* card_table = heap_->GetCardTable();
231 SpaceBitmap* live_bitmap = space_->GetLiveBitmap();
232 for (const auto& ref_pair : references_) {
233 const byte* card = ref_pair.first;
Ian Rogers1d54e732013-05-02 21:10:01 -0700234 if (*card == CardTable::kCardClean) {
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700235 std::set<const Object*> reference_set;
Ian Rogersef7d42f2014-01-06 12:55:46 -0800236 for (mirror::HeapReference<Object>* obj_ptr : ref_pair.second) {
237 reference_set.insert(obj_ptr->AsMirrorPtr());
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700238 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700239 ModUnionCheckReferences visitor(this, reference_set);
240 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700241 live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700242 }
243 }
244}
245
246void ModUnionTableReferenceCache::Dump(std::ostream& os) {
247 CardTable* card_table = heap_->GetCardTable();
Ian Rogers1d54e732013-05-02 21:10:01 -0700248 os << "ModUnionTable cleared cards: [";
Mathieu Chartier02e25112013-08-14 16:14:24 -0700249 for (byte* card_addr : cleared_cards_) {
250 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
Ian Rogers1d54e732013-05-02 21:10:01 -0700251 uintptr_t end = start + CardTable::kCardSize;
252 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
253 }
254 os << "]\nModUnionTable references: [";
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700255 for (const auto& ref_pair : references_) {
256 const byte* card_addr = ref_pair.first;
Mathieu Chartier02e25112013-08-14 16:14:24 -0700257 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
Ian Rogers1d54e732013-05-02 21:10:01 -0700258 uintptr_t end = start + CardTable::kCardSize;
259 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
Ian Rogersef7d42f2014-01-06 12:55:46 -0800260 for (mirror::HeapReference<Object>* ref : ref_pair.second) {
261 os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ",";
Ian Rogers1d54e732013-05-02 21:10:01 -0700262 }
263 os << "},";
264 }
265}
266
Mathieu Chartier815873e2014-02-13 18:02:13 -0800267void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectCallback* callback,
268 void* arg) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700269 Heap* heap = GetHeap();
270 CardTable* card_table = heap->GetCardTable();
271
Ian Rogersef7d42f2014-01-06 12:55:46 -0800272 std::vector<mirror::HeapReference<Object>*> cards_references;
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700273 ModUnionReferenceVisitor add_visitor(this, &cards_references);
Ian Rogers1d54e732013-05-02 21:10:01 -0700274
Mathieu Chartier02e25112013-08-14 16:14:24 -0700275 for (const auto& card : cleared_cards_) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700276 // Clear and re-compute alloc space references associated with this card.
277 cards_references.clear();
278 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
279 uintptr_t end = start + CardTable::kCardSize;
Mathieu Chartier02e25112013-08-14 16:14:24 -0700280 auto* space = heap->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
281 DCHECK(space != nullptr);
282 SpaceBitmap* live_bitmap = space->GetLiveBitmap();
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700283 live_bitmap->VisitMarkedRange(start, end, add_visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700284
285 // Update the corresponding references for the card.
Mathieu Chartier02e25112013-08-14 16:14:24 -0700286 auto found = references_.find(card);
Ian Rogers1d54e732013-05-02 21:10:01 -0700287 if (found == references_.end()) {
288 if (cards_references.empty()) {
289 // No reason to add empty array.
290 continue;
291 }
292 references_.Put(card, cards_references);
293 } else {
294 found->second = cards_references;
295 }
296 }
297 cleared_cards_.clear();
Ian Rogers1d54e732013-05-02 21:10:01 -0700298 size_t count = 0;
Mathieu Chartier02e25112013-08-14 16:14:24 -0700299 for (const auto& ref : references_) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800300 for (mirror::HeapReference<Object>* obj_ptr : ref.second) {
301 Object* obj = obj_ptr->AsMirrorPtr();
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700302 if (obj != nullptr) {
Mathieu Chartier815873e2014-02-13 18:02:13 -0800303 Object* new_obj = callback(obj, arg);
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700304 // Avoid dirtying pages in the image unless necessary.
305 if (new_obj != obj) {
Ian Rogersef7d42f2014-01-06 12:55:46 -0800306 obj_ptr->Assign(new_obj);
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700307 }
308 }
Ian Rogers1d54e732013-05-02 21:10:01 -0700309 }
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700310 count += ref.second.size();
Ian Rogers1d54e732013-05-02 21:10:01 -0700311 }
312 if (VLOG_IS_ON(heap)) {
313 VLOG(gc) << "Marked " << count << " references in mod union table";
314 }
315}
316
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700317void ModUnionTableCardCache::ClearCards() {
Ian Rogers1d54e732013-05-02 21:10:01 -0700318 CardTable* card_table = GetHeap()->GetCardTable();
319 ModUnionClearCardSetVisitor visitor(&cleared_cards_);
320 // Clear dirty cards in the this space and update the corresponding mod-union bits.
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700321 card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700322}
323
324// Mark all references to the alloc space(s).
Mathieu Chartier815873e2014-02-13 18:02:13 -0800325void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectCallback* callback, void* arg) {
Ian Rogers1d54e732013-05-02 21:10:01 -0700326 CardTable* card_table = heap_->GetCardTable();
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800327 ModUnionScanImageRootVisitor scan_visitor(callback, arg);
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700328 SpaceBitmap* bitmap = space_->GetLiveBitmap();
Mathieu Chartier02e25112013-08-14 16:14:24 -0700329 for (const byte* card_addr : cleared_cards_) {
Mathieu Chartier11409ae2013-09-23 11:49:36 -0700330 uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
331 DCHECK(space_->HasAddress(reinterpret_cast<Object*>(start)));
332 bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
Ian Rogers1d54e732013-05-02 21:10:01 -0700333 }
334}
335
336void ModUnionTableCardCache::Dump(std::ostream& os) {
337 CardTable* card_table = heap_->GetCardTable();
Ian Rogers1d54e732013-05-02 21:10:01 -0700338 os << "ModUnionTable dirty cards: [";
Mathieu Chartier02e25112013-08-14 16:14:24 -0700339 for (const byte* card_addr : cleared_cards_) {
340 auto start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
341 auto end = start + CardTable::kCardSize;
Mathieu Chartier590fee92013-09-13 13:46:47 -0700342 os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "\n";
Ian Rogers1d54e732013-05-02 21:10:01 -0700343 }
344 os << "]";
345}
346
347} // namespace accounting
348} // namespace gc
349} // namespace art