1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2013 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #include "reference_queue.h"
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "accounting/card_table-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
21*795d594fSAndroid Build Coastguard Worker #include "collector/concurrent_copying.h"
22*795d594fSAndroid Build Coastguard Worker #include "heap.h"
23*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
25*795d594fSAndroid Build Coastguard Worker #include "mirror/reference-inl.h"
26*795d594fSAndroid Build Coastguard Worker #include "object_callbacks.h"
27*795d594fSAndroid Build Coastguard Worker
28*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
29*795d594fSAndroid Build Coastguard Worker namespace gc {
30*795d594fSAndroid Build Coastguard Worker
ReferenceQueue(Mutex * lock)31*795d594fSAndroid Build Coastguard Worker ReferenceQueue::ReferenceQueue(Mutex* lock) : lock_(lock), list_(nullptr) {
32*795d594fSAndroid Build Coastguard Worker }
33*795d594fSAndroid Build Coastguard Worker
AtomicEnqueueIfNotEnqueued(Thread * self,ObjPtr<mirror::Reference> ref)34*795d594fSAndroid Build Coastguard Worker void ReferenceQueue::AtomicEnqueueIfNotEnqueued(Thread* self, ObjPtr<mirror::Reference> ref) {
35*795d594fSAndroid Build Coastguard Worker DCHECK(ref != nullptr);
36*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *lock_);
37*795d594fSAndroid Build Coastguard Worker if (ref->IsUnprocessed()) {
38*795d594fSAndroid Build Coastguard Worker EnqueueReference(ref);
39*795d594fSAndroid Build Coastguard Worker }
40*795d594fSAndroid Build Coastguard Worker }
41*795d594fSAndroid Build Coastguard Worker
EnqueueReference(ObjPtr<mirror::Reference> ref)42*795d594fSAndroid Build Coastguard Worker void ReferenceQueue::EnqueueReference(ObjPtr<mirror::Reference> ref) {
43*795d594fSAndroid Build Coastguard Worker DCHECK(ref != nullptr);
44*795d594fSAndroid Build Coastguard Worker CHECK(ref->IsUnprocessed());
45*795d594fSAndroid Build Coastguard Worker if (IsEmpty()) {
46*795d594fSAndroid Build Coastguard Worker // 1 element cyclic queue, ie: Reference ref = ..; ref.pendingNext = ref;
47*795d594fSAndroid Build Coastguard Worker list_ = ref.Ptr();
48*795d594fSAndroid Build Coastguard Worker } else {
49*795d594fSAndroid Build Coastguard Worker // The list is owned by the GC, everything that has been inserted must already be at least
50*795d594fSAndroid Build Coastguard Worker // gray.
51*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> head = list_->GetPendingNext<kWithoutReadBarrier>();
52*795d594fSAndroid Build Coastguard Worker DCHECK(head != nullptr);
53*795d594fSAndroid Build Coastguard Worker ref->SetPendingNext(head);
54*795d594fSAndroid Build Coastguard Worker }
55*795d594fSAndroid Build Coastguard Worker // Add the reference in the middle to preserve the cycle.
56*795d594fSAndroid Build Coastguard Worker list_->SetPendingNext(ref);
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker
DequeuePendingReference()59*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> ReferenceQueue::DequeuePendingReference() {
60*795d594fSAndroid Build Coastguard Worker DCHECK(!IsEmpty());
61*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> ref = list_->GetPendingNext<kWithoutReadBarrier>();
62*795d594fSAndroid Build Coastguard Worker DCHECK(ref != nullptr);
63*795d594fSAndroid Build Coastguard Worker // Note: the following code is thread-safe because it is only called from ProcessReferences which
64*795d594fSAndroid Build Coastguard Worker // is single threaded.
65*795d594fSAndroid Build Coastguard Worker if (list_ == ref) {
66*795d594fSAndroid Build Coastguard Worker list_ = nullptr;
67*795d594fSAndroid Build Coastguard Worker } else {
68*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> next = ref->GetPendingNext<kWithoutReadBarrier>();
69*795d594fSAndroid Build Coastguard Worker list_->SetPendingNext(next);
70*795d594fSAndroid Build Coastguard Worker }
71*795d594fSAndroid Build Coastguard Worker ref->SetPendingNext(nullptr);
72*795d594fSAndroid Build Coastguard Worker return ref;
73*795d594fSAndroid Build Coastguard Worker }
74*795d594fSAndroid Build Coastguard Worker
75*795d594fSAndroid Build Coastguard Worker // This must be called whenever DequeuePendingReference is called.
DisableReadBarrierForReference(ObjPtr<mirror::Reference> ref,std::memory_order order)76*795d594fSAndroid Build Coastguard Worker void ReferenceQueue::DisableReadBarrierForReference(ObjPtr<mirror::Reference> ref,
77*795d594fSAndroid Build Coastguard Worker std::memory_order order) {
78*795d594fSAndroid Build Coastguard Worker Heap* heap = Runtime::Current()->GetHeap();
79*795d594fSAndroid Build Coastguard Worker if (kUseBakerReadBarrier && heap->CurrentCollectorType() == kCollectorTypeCC &&
80*795d594fSAndroid Build Coastguard Worker heap->ConcurrentCopyingCollector()->IsActive()) {
81*795d594fSAndroid Build Coastguard Worker // Change the gray ptr we left in ConcurrentCopying::ProcessMarkStackRef() to non-gray.
82*795d594fSAndroid Build Coastguard Worker // We check IsActive() above because we don't want to do this when the zygote compaction
83*795d594fSAndroid Build Coastguard Worker // collector (SemiSpace) is running.
84*795d594fSAndroid Build Coastguard Worker CHECK(ref != nullptr);
85*795d594fSAndroid Build Coastguard Worker collector::ConcurrentCopying* concurrent_copying = heap->ConcurrentCopyingCollector();
86*795d594fSAndroid Build Coastguard Worker uint32_t rb_state = ref->GetReadBarrierState();
87*795d594fSAndroid Build Coastguard Worker if (rb_state == ReadBarrier::GrayState()) {
88*795d594fSAndroid Build Coastguard Worker ref->AtomicSetReadBarrierState(ReadBarrier::GrayState(), ReadBarrier::NonGrayState(), order);
89*795d594fSAndroid Build Coastguard Worker CHECK_EQ(ref->GetReadBarrierState(), ReadBarrier::NonGrayState());
90*795d594fSAndroid Build Coastguard Worker } else {
91*795d594fSAndroid Build Coastguard Worker // In ConcurrentCopying::ProcessMarkStackRef() we may leave a non-gray reference in the queue
92*795d594fSAndroid Build Coastguard Worker // and find it here, which is OK.
93*795d594fSAndroid Build Coastguard Worker CHECK_EQ(rb_state, ReadBarrier::NonGrayState()) << "ref=" << ref << " rb_state=" << rb_state;
94*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> referent = ref->GetReferent<kWithoutReadBarrier>();
95*795d594fSAndroid Build Coastguard Worker // The referent could be null if it's cleared by a mutator (Reference.clear()).
96*795d594fSAndroid Build Coastguard Worker if (referent != nullptr) {
97*795d594fSAndroid Build Coastguard Worker CHECK(concurrent_copying->IsInToSpace(referent.Ptr()))
98*795d594fSAndroid Build Coastguard Worker << "ref=" << ref << " rb_state=" << ref->GetReadBarrierState()
99*795d594fSAndroid Build Coastguard Worker << " referent=" << referent;
100*795d594fSAndroid Build Coastguard Worker }
101*795d594fSAndroid Build Coastguard Worker }
102*795d594fSAndroid Build Coastguard Worker }
103*795d594fSAndroid Build Coastguard Worker }
104*795d594fSAndroid Build Coastguard Worker
Dump(std::ostream & os) const105*795d594fSAndroid Build Coastguard Worker void ReferenceQueue::Dump(std::ostream& os) const {
106*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> cur = list_;
107*795d594fSAndroid Build Coastguard Worker os << "Reference starting at list_=" << list_ << "\n";
108*795d594fSAndroid Build Coastguard Worker if (cur == nullptr) {
109*795d594fSAndroid Build Coastguard Worker return;
110*795d594fSAndroid Build Coastguard Worker }
111*795d594fSAndroid Build Coastguard Worker do {
112*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> pending_next = cur->GetPendingNext();
113*795d594fSAndroid Build Coastguard Worker os << "Reference= " << cur << " PendingNext=" << pending_next;
114*795d594fSAndroid Build Coastguard Worker if (cur->IsFinalizerReferenceInstance()) {
115*795d594fSAndroid Build Coastguard Worker os << " Zombie=" << cur->AsFinalizerReference()->GetZombie();
116*795d594fSAndroid Build Coastguard Worker }
117*795d594fSAndroid Build Coastguard Worker os << "\n";
118*795d594fSAndroid Build Coastguard Worker cur = pending_next;
119*795d594fSAndroid Build Coastguard Worker } while (cur != list_);
120*795d594fSAndroid Build Coastguard Worker }
121*795d594fSAndroid Build Coastguard Worker
GetLength() const122*795d594fSAndroid Build Coastguard Worker size_t ReferenceQueue::GetLength() const {
123*795d594fSAndroid Build Coastguard Worker size_t count = 0;
124*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> cur = list_;
125*795d594fSAndroid Build Coastguard Worker if (cur != nullptr) {
126*795d594fSAndroid Build Coastguard Worker do {
127*795d594fSAndroid Build Coastguard Worker ++count;
128*795d594fSAndroid Build Coastguard Worker cur = cur->GetPendingNext();
129*795d594fSAndroid Build Coastguard Worker } while (cur != list_);
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker return count;
132*795d594fSAndroid Build Coastguard Worker }
133*795d594fSAndroid Build Coastguard Worker
ClearWhiteReferences(ReferenceQueue * cleared_references,collector::GarbageCollector * collector,bool report_cleared)134*795d594fSAndroid Build Coastguard Worker void ReferenceQueue::ClearWhiteReferences(ReferenceQueue* cleared_references,
135*795d594fSAndroid Build Coastguard Worker collector::GarbageCollector* collector,
136*795d594fSAndroid Build Coastguard Worker bool report_cleared) {
137*795d594fSAndroid Build Coastguard Worker while (!IsEmpty()) {
138*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> ref = DequeuePendingReference();
139*795d594fSAndroid Build Coastguard Worker mirror::HeapReference<mirror::Object>* referent_addr = ref->GetReferentReferenceAddr();
140*795d594fSAndroid Build Coastguard Worker // do_atomic_update is false because this happens during the reference processing phase where
141*795d594fSAndroid Build Coastguard Worker // Reference.clear() would block.
142*795d594fSAndroid Build Coastguard Worker if (!collector->IsNullOrMarkedHeapReference(referent_addr, /*do_atomic_update=*/false)) {
143*795d594fSAndroid Build Coastguard Worker // Referent is white, clear it.
144*795d594fSAndroid Build Coastguard Worker if (Runtime::Current()->IsActiveTransaction()) {
145*795d594fSAndroid Build Coastguard Worker ref->ClearReferent<true>();
146*795d594fSAndroid Build Coastguard Worker } else {
147*795d594fSAndroid Build Coastguard Worker ref->ClearReferent<false>();
148*795d594fSAndroid Build Coastguard Worker }
149*795d594fSAndroid Build Coastguard Worker cleared_references->EnqueueReference(ref);
150*795d594fSAndroid Build Coastguard Worker if (report_cleared) {
151*795d594fSAndroid Build Coastguard Worker static bool already_reported = false;
152*795d594fSAndroid Build Coastguard Worker if (!already_reported) {
153*795d594fSAndroid Build Coastguard Worker // TODO: Maybe do this only if the queue is non-null?
154*795d594fSAndroid Build Coastguard Worker LOG(WARNING)
155*795d594fSAndroid Build Coastguard Worker << "Cleared Reference was only reachable from finalizer (only reported once)";
156*795d594fSAndroid Build Coastguard Worker already_reported = true;
157*795d594fSAndroid Build Coastguard Worker }
158*795d594fSAndroid Build Coastguard Worker }
159*795d594fSAndroid Build Coastguard Worker }
160*795d594fSAndroid Build Coastguard Worker // Delay disabling the read barrier until here so that the ClearReferent call above in
161*795d594fSAndroid Build Coastguard Worker // transaction mode will trigger the read barrier.
162*795d594fSAndroid Build Coastguard Worker DisableReadBarrierForReference(ref, std::memory_order_relaxed);
163*795d594fSAndroid Build Coastguard Worker }
164*795d594fSAndroid Build Coastguard Worker }
165*795d594fSAndroid Build Coastguard Worker
EnqueueFinalizerReferences(ReferenceQueue * cleared_references,collector::GarbageCollector * collector)166*795d594fSAndroid Build Coastguard Worker FinalizerStats ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue* cleared_references,
167*795d594fSAndroid Build Coastguard Worker collector::GarbageCollector* collector) {
168*795d594fSAndroid Build Coastguard Worker uint32_t num_refs(0), num_enqueued(0);
169*795d594fSAndroid Build Coastguard Worker while (!IsEmpty()) {
170*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::FinalizerReference> ref = DequeuePendingReference()->AsFinalizerReference();
171*795d594fSAndroid Build Coastguard Worker ++num_refs;
172*795d594fSAndroid Build Coastguard Worker mirror::HeapReference<mirror::Object>* referent_addr = ref->GetReferentReferenceAddr();
173*795d594fSAndroid Build Coastguard Worker // do_atomic_update is false because this happens during the reference processing phase where
174*795d594fSAndroid Build Coastguard Worker // Reference.clear() would block.
175*795d594fSAndroid Build Coastguard Worker if (!collector->IsNullOrMarkedHeapReference(referent_addr, /*do_atomic_update=*/false)) {
176*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Object> forward_address = collector->MarkObject(referent_addr->AsMirrorPtr());
177*795d594fSAndroid Build Coastguard Worker // Move the updated referent to the zombie field.
178*795d594fSAndroid Build Coastguard Worker if (Runtime::Current()->IsActiveTransaction()) {
179*795d594fSAndroid Build Coastguard Worker ref->SetZombie<true>(forward_address);
180*795d594fSAndroid Build Coastguard Worker ref->ClearReferent<true>();
181*795d594fSAndroid Build Coastguard Worker } else {
182*795d594fSAndroid Build Coastguard Worker ref->SetZombie<false>(forward_address);
183*795d594fSAndroid Build Coastguard Worker ref->ClearReferent<false>();
184*795d594fSAndroid Build Coastguard Worker }
185*795d594fSAndroid Build Coastguard Worker cleared_references->EnqueueReference(ref);
186*795d594fSAndroid Build Coastguard Worker ++num_enqueued;
187*795d594fSAndroid Build Coastguard Worker }
188*795d594fSAndroid Build Coastguard Worker // Delay disabling the read barrier until here so that the ClearReferent call above in
189*795d594fSAndroid Build Coastguard Worker // transaction mode will trigger the read barrier.
190*795d594fSAndroid Build Coastguard Worker DisableReadBarrierForReference(ref->AsReference(), std::memory_order_relaxed);
191*795d594fSAndroid Build Coastguard Worker }
192*795d594fSAndroid Build Coastguard Worker return FinalizerStats(num_refs, num_enqueued);
193*795d594fSAndroid Build Coastguard Worker }
194*795d594fSAndroid Build Coastguard Worker
ForwardSoftReferences(MarkObjectVisitor * visitor)195*795d594fSAndroid Build Coastguard Worker uint32_t ReferenceQueue::ForwardSoftReferences(MarkObjectVisitor* visitor) {
196*795d594fSAndroid Build Coastguard Worker uint32_t num_refs(0);
197*795d594fSAndroid Build Coastguard Worker Thread* self = Thread::Current();
198*795d594fSAndroid Build Coastguard Worker static constexpr int SR_BUF_SIZE = 32;
199*795d594fSAndroid Build Coastguard Worker ObjPtr<mirror::Reference> buf[SR_BUF_SIZE];
200*795d594fSAndroid Build Coastguard Worker int n_entries;
201*795d594fSAndroid Build Coastguard Worker bool empty;
202*795d594fSAndroid Build Coastguard Worker do {
203*795d594fSAndroid Build Coastguard Worker {
204*795d594fSAndroid Build Coastguard Worker // Acquire lock only a few times and hold it as briefly as possible.
205*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, *lock_);
206*795d594fSAndroid Build Coastguard Worker empty = IsEmpty();
207*795d594fSAndroid Build Coastguard Worker for (n_entries = 0; n_entries < SR_BUF_SIZE && !empty; ++n_entries) {
208*795d594fSAndroid Build Coastguard Worker // Dequeuing the Reference here means it could possibly be enqueued again during this GC.
209*795d594fSAndroid Build Coastguard Worker // That's unlikely and benign.
210*795d594fSAndroid Build Coastguard Worker buf[n_entries] = DequeuePendingReference();
211*795d594fSAndroid Build Coastguard Worker empty = IsEmpty();
212*795d594fSAndroid Build Coastguard Worker }
213*795d594fSAndroid Build Coastguard Worker }
214*795d594fSAndroid Build Coastguard Worker for (int i = 0; i < n_entries; ++i) {
215*795d594fSAndroid Build Coastguard Worker mirror::HeapReference<mirror::Object>* referent_addr = buf[i]->GetReferentReferenceAddr();
216*795d594fSAndroid Build Coastguard Worker if (referent_addr->AsMirrorPtr() != nullptr) {
217*795d594fSAndroid Build Coastguard Worker visitor->MarkHeapReference(referent_addr, /*do_atomic_update=*/ true);
218*795d594fSAndroid Build Coastguard Worker ++num_refs;
219*795d594fSAndroid Build Coastguard Worker }
220*795d594fSAndroid Build Coastguard Worker DisableReadBarrierForReference(buf[i]->AsReference(), std::memory_order_release);
221*795d594fSAndroid Build Coastguard Worker }
222*795d594fSAndroid Build Coastguard Worker } while (!empty);
223*795d594fSAndroid Build Coastguard Worker return num_refs;
224*795d594fSAndroid Build Coastguard Worker }
225*795d594fSAndroid Build Coastguard Worker
UpdateRoots(IsMarkedVisitor * visitor)226*795d594fSAndroid Build Coastguard Worker void ReferenceQueue::UpdateRoots(IsMarkedVisitor* visitor) {
227*795d594fSAndroid Build Coastguard Worker if (list_ != nullptr) {
228*795d594fSAndroid Build Coastguard Worker list_ = down_cast<mirror::Reference*>(visitor->IsMarked(list_));
229*795d594fSAndroid Build Coastguard Worker }
230*795d594fSAndroid Build Coastguard Worker }
231*795d594fSAndroid Build Coastguard Worker
232*795d594fSAndroid Build Coastguard Worker } // namespace gc
233*795d594fSAndroid Build Coastguard Worker } // namespace art
234