blob: 2d73a714218aaae73719a37c0e95946c23556eb7 [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
97void ReferenceQueue::ClearWhiteReferences(ReferenceQueue& cleared_references, RootVisitor visitor,
98 void* arg) {
99 while (!IsEmpty()) {
100 mirror::Object* ref = DequeuePendingReference();
101 mirror::Object* referent = heap_->GetReferenceReferent(ref);
102 if (referent != nullptr) {
103 mirror::Object* forward_address = visitor(referent, arg);
104 if (forward_address == nullptr) {
105 // Referent is white, clear it.
106 heap_->ClearReferenceReferent(ref);
107 if (heap_->IsEnqueuable(ref)) {
108 cleared_references.EnqueuePendingReference(ref);
109 }
110 } else if (referent != forward_address) {
111 // Object moved, need to updated the referrent.
112 heap_->SetReferenceReferent(ref, forward_address);
113 }
114 }
115 }
116}
117
118void ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue& cleared_references,
119 RootVisitor is_marked_callback,
120 RootVisitor recursive_mark_callback, void* arg) {
121 while (!IsEmpty()) {
122 mirror::Object* ref = DequeuePendingReference();
123 mirror::Object* referent = heap_->GetReferenceReferent(ref);
124 if (referent != nullptr) {
125 mirror::Object* forward_address = is_marked_callback(referent, arg);
126 // If the referent isn't marked, mark it and update the
127 if (forward_address == nullptr) {
128 forward_address = recursive_mark_callback(referent, arg);
129 // If the referent is non-null the reference must queuable.
130 DCHECK(heap_->IsEnqueuable(ref));
131 // Move the updated referent to the zombie field.
132 ref->SetFieldObject(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
133 heap_->ClearReferenceReferent(ref);
134 cleared_references.EnqueueReference(ref);
135 } else if (referent != forward_address) {
136 heap_->SetReferenceReferent(ref, forward_address);
137 }
138 }
139 }
140}
141
142void ReferenceQueue::PreserveSomeSoftReferences(RootVisitor preserve_callback, void* arg) {
143 ReferenceQueue cleared(heap_);
144 while (!IsEmpty()) {
145 mirror::Object* ref = DequeuePendingReference();
146 mirror::Object* referent = heap_->GetReferenceReferent(ref);
147 if (referent != nullptr) {
148 mirror::Object* forward_address = preserve_callback(referent, arg);
149 if (forward_address == nullptr) {
150 // Either the reference isn't marked or we don't wish to preserve it.
151 cleared.EnqueuePendingReference(ref);
152 } else {
153 heap_->SetReferenceReferent(ref, forward_address);
154 }
155 }
156 }
157 list_ = cleared.GetList();
158}
159
160} // namespace gc
161} // namespace art
162