blob: fae4caccada497d02064fa979ed2044f430e3013 [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;
52 ref->SetFieldObject(pending_next_offset, ref, false);
53 list_ = ref;
54 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -080055 mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false);
Mathieu Chartier39e32612013-11-12 16:28:05 -080056 ref->SetFieldObject(pending_next_offset, head, false);
57 list_->SetFieldObject(pending_next_offset, ref, false);
58 }
59}
60
61mirror::Object* ReferenceQueue::DequeuePendingReference() {
62 DCHECK(!IsEmpty());
63 MemberOffset pending_next_offset = heap_->GetReferencePendingNextOffset();
Ian Rogersef7d42f2014-01-06 12:55:46 -080064 mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false);
Mathieu Chartier39e32612013-11-12 16:28:05 -080065 DCHECK(head != nullptr);
66 mirror::Object* ref;
67 // Note: the following code is thread-safe because it is only called from ProcessReferences which
68 // is single threaded.
69 if (list_ == head) {
70 ref = list_;
71 list_ = nullptr;
72 } else {
Ian Rogersef7d42f2014-01-06 12:55:46 -080073 mirror::Object* next = head->GetFieldObject<mirror::Object>(pending_next_offset, false);
Mathieu Chartier39e32612013-11-12 16:28:05 -080074 list_->SetFieldObject(pending_next_offset, next, false);
75 ref = head;
76 }
77 ref->SetFieldObject(pending_next_offset, nullptr, false);
78 return ref;
79}
80
81void ReferenceQueue::Dump(std::ostream& os) const {
82 mirror::Object* cur = list_;
83 os << "Reference starting at list_=" << list_ << "\n";
84 while (cur != nullptr) {
85 mirror::Object* pending_next =
Ian Rogersef7d42f2014-01-06 12:55:46 -080086 cur->GetFieldObject<mirror::Object>(heap_->GetReferencePendingNextOffset(), false);
Mathieu Chartier39e32612013-11-12 16:28:05 -080087 os << "PendingNext=" << pending_next;
88 if (cur->GetClass()->IsFinalizerReferenceClass()) {
89 os << " Zombie=" <<
Ian Rogersef7d42f2014-01-06 12:55:46 -080090 cur->GetFieldObject<mirror::Object>(heap_->GetFinalizerReferenceZombieOffset(), false);
Mathieu Chartier39e32612013-11-12 16:28:05 -080091 }
92 os << "\n";
93 cur = pending_next;
94 }
95}
96
Mathieu Chartier83c8ee02014-01-28 14:50:23 -080097void ReferenceQueue::ClearWhiteReferences(ReferenceQueue& cleared_references,
98 IsMarkedCallback* preserve_callback,
Mathieu Chartier39e32612013-11-12 16:28:05 -080099 void* arg) {
100 while (!IsEmpty()) {
101 mirror::Object* ref = DequeuePendingReference();
102 mirror::Object* referent = heap_->GetReferenceReferent(ref);
103 if (referent != nullptr) {
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800104 mirror::Object* forward_address = preserve_callback(referent, arg);
Mathieu Chartier39e32612013-11-12 16:28:05 -0800105 if (forward_address == nullptr) {
106 // Referent is white, clear it.
107 heap_->ClearReferenceReferent(ref);
108 if (heap_->IsEnqueuable(ref)) {
109 cleared_references.EnqueuePendingReference(ref);
110 }
111 } else if (referent != forward_address) {
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800112 // Object moved, need to updated the referent.
Mathieu Chartier39e32612013-11-12 16:28:05 -0800113 heap_->SetReferenceReferent(ref, forward_address);
114 }
115 }
116 }
117}
118
119void ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue& cleared_references,
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800120 IsMarkedCallback is_marked_callback,
121 MarkObjectCallback recursive_mark_callback,
122 void* arg) {
Mathieu Chartier39e32612013-11-12 16:28:05 -0800123 while (!IsEmpty()) {
124 mirror::Object* ref = DequeuePendingReference();
125 mirror::Object* referent = heap_->GetReferenceReferent(ref);
126 if (referent != nullptr) {
127 mirror::Object* forward_address = is_marked_callback(referent, arg);
128 // If the referent isn't marked, mark it and update the
129 if (forward_address == nullptr) {
130 forward_address = recursive_mark_callback(referent, arg);
131 // If the referent is non-null the reference must queuable.
132 DCHECK(heap_->IsEnqueuable(ref));
133 // Move the updated referent to the zombie field.
134 ref->SetFieldObject(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
135 heap_->ClearReferenceReferent(ref);
136 cleared_references.EnqueueReference(ref);
137 } else if (referent != forward_address) {
138 heap_->SetReferenceReferent(ref, forward_address);
139 }
140 }
141 }
142}
143
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800144void ReferenceQueue::PreserveSomeSoftReferences(IsMarkedCallback preserve_callback, void* arg) {
Mathieu Chartier39e32612013-11-12 16:28:05 -0800145 ReferenceQueue cleared(heap_);
146 while (!IsEmpty()) {
147 mirror::Object* ref = DequeuePendingReference();
148 mirror::Object* referent = heap_->GetReferenceReferent(ref);
149 if (referent != nullptr) {
150 mirror::Object* forward_address = preserve_callback(referent, arg);
151 if (forward_address == nullptr) {
152 // Either the reference isn't marked or we don't wish to preserve it.
153 cleared.EnqueuePendingReference(ref);
Mathieu Chartier83c8ee02014-01-28 14:50:23 -0800154 } else if (forward_address != referent) {
Mathieu Chartier39e32612013-11-12 16:28:05 -0800155 heap_->SetReferenceReferent(ref, forward_address);
156 }
157 }
158 }
159 list_ = cleared.GetList();
160}
161
162} // namespace gc
163} // namespace art
164