blob: 203701ff5ed9a59837cb40dd10f1a182521626e1 [file] [log] [blame]
Mathieu Chartier39e32612013-11-12 16:28:05 -08001/*
2 * Copyright (C) 2013 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 "reference_queue.h"
18
19#include "accounting/card_table-inl.h"
20#include "heap.h"
21#include "mirror/class-inl.h"
22#include "mirror/object-inl.h"
23
24namespace art {
25namespace gc {
26
27ReferenceQueue::ReferenceQueue(Heap* heap)
28 : lock_("reference queue lock"),
29 heap_(heap),
30 list_(nullptr) {
31}
32
33void ReferenceQueue::AtomicEnqueueIfNotEnqueued(Thread* self, mirror::Object* ref) {
34 DCHECK(ref != NULL);
35 MutexLock mu(self, lock_);
36 if (!heap_->IsEnqueued(ref)) {
37 EnqueuePendingReference(ref);
38 }
39}
40
41void ReferenceQueue::EnqueueReference(mirror::Object* ref) {
42 CHECK(heap_->IsEnqueuable(ref));
43 EnqueuePendingReference(ref);
44}
45
46void ReferenceQueue::EnqueuePendingReference(mirror::Object* ref) {
47 DCHECK(ref != NULL);
48 MemberOffset pending_next_offset = heap_->GetReferencePendingNextOffset();
49 DCHECK_NE(pending_next_offset.Uint32Value(), 0U);
50 if (IsEmpty()) {
51 // 1 element cyclic queue, ie: Reference ref = ..; ref.pendingNext = ref;
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010052 if (Runtime::Current()->IsActiveTransaction()) {
53 ref->SetFieldObject<true>(pending_next_offset, ref, false);
54 } else {
55 ref->SetFieldObject<false>(pending_next_offset, ref, false);
56 }
Mathieu Chartier39e32612013-11-12 16:28:05 -080057 list_ = ref;
58 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -080059 mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010060 if (Runtime::Current()->IsActiveTransaction()) {
61 ref->SetFieldObject<true>(pending_next_offset, head, false);
62 list_->SetFieldObject<true>(pending_next_offset, ref, false);
63 } else {
64 ref->SetFieldObject<false>(pending_next_offset, head, false);
65 list_->SetFieldObject<false>(pending_next_offset, ref, false);
66 }
Mathieu Chartier39e32612013-11-12 16:28:05 -080067 }
68}
69
70mirror::Object* ReferenceQueue::DequeuePendingReference() {
71 DCHECK(!IsEmpty());
72 MemberOffset pending_next_offset = heap_->GetReferencePendingNextOffset();
Ian Rogersef7d42f2014-01-06 12:55:46 -080073 mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false);
Mathieu Chartier39e32612013-11-12 16:28:05 -080074 DCHECK(head != nullptr);
75 mirror::Object* ref;
76 // Note: the following code is thread-safe because it is only called from ProcessReferences which
77 // is single threaded.
78 if (list_ == head) {
79 ref = list_;
80 list_ = nullptr;
81 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -080082 mirror::Object* next = head->GetFieldObject<mirror::Object>(pending_next_offset, false);
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010083 if (Runtime::Current()->IsActiveTransaction()) {
84 list_->SetFieldObject<true>(pending_next_offset, next, false);
85 } else {
86 list_->SetFieldObject<false>(pending_next_offset, next, false);
87 }
Mathieu Chartier39e32612013-11-12 16:28:05 -080088 ref = head;
89 }
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +010090 if (Runtime::Current()->IsActiveTransaction()) {
91 ref->SetFieldObject<true>(pending_next_offset, nullptr, false);
92 } else {
93 ref->SetFieldObject<false>(pending_next_offset, nullptr, false);
94 }
Mathieu Chartier39e32612013-11-12 16:28:05 -080095 return ref;
96}
97
98void ReferenceQueue::Dump(std::ostream& os) const {
99 mirror::Object* cur = list_;
100 os << "Reference starting at list_=" << list_ << "\n";
101 while (cur != nullptr) {
102 mirror::Object* pending_next =
Ian Rogersef7d42f2014-01-06 12:55:46 -0800103 cur->GetFieldObject<mirror::Object>(heap_->GetReferencePendingNextOffset(), false);
Mathieu Chartier39e32612013-11-12 16:28:05 -0800104 os << "PendingNext=" << pending_next;
105 if (cur->GetClass()->IsFinalizerReferenceClass()) {
106 os << " Zombie=" <<
Ian Rogersef7d42f2014-01-06 12:55:46 -0800107 cur->GetFieldObject<mirror::Object>(heap_->GetFinalizerReferenceZombieOffset(), false);
Mathieu Chartier39e32612013-11-12 16:28:05 -0800108 }
109 os << "\n";
110 cur = pending_next;
111 }
112}
113
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800114void ReferenceQueue::ClearWhiteReferences(ReferenceQueue& cleared_references,
115 IsMarkedCallback* preserve_callback,
Mathieu Chartier39e32612013-11-12 16:28:05 -0800116 void* arg) {
117 while (!IsEmpty()) {
118 mirror::Object* ref = DequeuePendingReference();
119 mirror::Object* referent = heap_->GetReferenceReferent(ref);
120 if (referent != nullptr) {
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800121 mirror::Object* forward_address = preserve_callback(referent, arg);
Mathieu Chartier39e32612013-11-12 16:28:05 -0800122 if (forward_address == nullptr) {
123 // Referent is white, clear it.
124 heap_->ClearReferenceReferent(ref);
125 if (heap_->IsEnqueuable(ref)) {
126 cleared_references.EnqueuePendingReference(ref);
127 }
128 } else if (referent != forward_address) {
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800129 // Object moved, need to updated the referent.
Mathieu Chartier39e32612013-11-12 16:28:05 -0800130 heap_->SetReferenceReferent(ref, forward_address);
131 }
132 }
133 }
134}
135
136void ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue& cleared_references,
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800137 IsMarkedCallback is_marked_callback,
138 MarkObjectCallback recursive_mark_callback,
139 void* arg) {
Mathieu Chartier39e32612013-11-12 16:28:05 -0800140 while (!IsEmpty()) {
141 mirror::Object* ref = DequeuePendingReference();
142 mirror::Object* referent = heap_->GetReferenceReferent(ref);
143 if (referent != nullptr) {
144 mirror::Object* forward_address = is_marked_callback(referent, arg);
145 // If the referent isn't marked, mark it and update the
146 if (forward_address == nullptr) {
147 forward_address = recursive_mark_callback(referent, arg);
148 // If the referent is non-null the reference must queuable.
149 DCHECK(heap_->IsEnqueuable(ref));
150 // Move the updated referent to the zombie field.
Sebastien Hertzd2fe10a2014-01-15 10:20:56 +0100151 if (Runtime::Current()->IsActiveTransaction()) {
152 ref->SetFieldObject<true>(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
153 } else {
154 ref->SetFieldObject<false>(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
155 }
Mathieu Chartier39e32612013-11-12 16:28:05 -0800156 heap_->ClearReferenceReferent(ref);
157 cleared_references.EnqueueReference(ref);
158 } else if (referent != forward_address) {
159 heap_->SetReferenceReferent(ref, forward_address);
160 }
161 }
162 }
163}
164
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800165void ReferenceQueue::PreserveSomeSoftReferences(IsMarkedCallback preserve_callback, void* arg) {
Mathieu Chartier39e32612013-11-12 16:28:05 -0800166 ReferenceQueue cleared(heap_);
167 while (!IsEmpty()) {
168 mirror::Object* ref = DequeuePendingReference();
169 mirror::Object* referent = heap_->GetReferenceReferent(ref);
170 if (referent != nullptr) {
171 mirror::Object* forward_address = preserve_callback(referent, arg);
172 if (forward_address == nullptr) {
173 // Either the reference isn't marked or we don't wish to preserve it.
174 cleared.EnqueuePendingReference(ref);
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800175 } else if (forward_address != referent) {
Mathieu Chartier39e32612013-11-12 16:28:05 -0800176 heap_->SetReferenceReferent(ref, forward_address);
177 }
178 }
179 }
180 list_ = cleared.GetList();
181}
182
183} // namespace gc
184} // namespace art
185