reference_queue.cc revision 8fa2dad7fe7909c8335101d6c8904ae997cdf29f
1/* 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#include "mirror/reference-inl.h" 24 25namespace art { 26namespace gc { 27 28ReferenceQueue::ReferenceQueue() 29 : lock_("reference queue lock"), 30 list_(nullptr) { 31} 32 33void ReferenceQueue::AtomicEnqueueIfNotEnqueued(Thread* self, mirror::Reference* ref) { 34 DCHECK(ref != NULL); 35 MutexLock mu(self, lock_); 36 if (!ref->IsEnqueued()) { 37 EnqueuePendingReference(ref); 38 } 39} 40 41void ReferenceQueue::EnqueueReference(mirror::Reference* ref) { 42 CHECK(ref->IsEnqueuable()); 43 EnqueuePendingReference(ref); 44} 45 46void ReferenceQueue::EnqueuePendingReference(mirror::Reference* ref) { 47 DCHECK(ref != NULL); 48 if (IsEmpty()) { 49 // 1 element cyclic queue, ie: Reference ref = ..; ref.pendingNext = ref; 50 list_ = ref; 51 } else { 52 mirror::Reference* head = list_->GetPendingNext(); 53 if (Runtime::Current()->IsActiveTransaction()) { 54 ref->SetPendingNext<true>(head); 55 } else { 56 ref->SetPendingNext<false>(head); 57 } 58 } 59 if (Runtime::Current()->IsActiveTransaction()) { 60 list_->SetPendingNext<true>(ref); 61 } else { 62 list_->SetPendingNext<false>(ref); 63 } 64} 65 66mirror::Reference* ReferenceQueue::DequeuePendingReference() { 67 DCHECK(!IsEmpty()); 68 mirror::Reference* head = list_->GetPendingNext(); 69 DCHECK(head != nullptr); 70 mirror::Reference* ref; 71 // Note: the following code is thread-safe because it is only called from ProcessReferences which 72 // is single threaded. 73 if (list_ == head) { 74 ref = list_; 75 list_ = nullptr; 76 } else { 77 mirror::Reference* next = head->GetPendingNext(); 78 if (Runtime::Current()->IsActiveTransaction()) { 79 list_->SetPendingNext<true>(next); 80 } else { 81 list_->SetPendingNext<false>(next); 82 } 83 ref = head; 84 } 85 if (Runtime::Current()->IsActiveTransaction()) { 86 ref->SetPendingNext<true>(nullptr); 87 } else { 88 ref->SetPendingNext<false>(nullptr); 89 } 90 return ref; 91} 92 93void ReferenceQueue::Dump(std::ostream& os) const { 94 mirror::Reference* cur = list_; 95 os << "Reference starting at list_=" << list_ << "\n"; 96 while (cur != nullptr) { 97 mirror::Reference* pending_next = cur->GetPendingNext(); 98 os << "PendingNext=" << pending_next; 99 if (cur->IsFinalizerReferenceInstance()) { 100 os << " Zombie=" << cur->AsFinalizerReference()->GetZombie(); 101 } 102 os << "\n"; 103 cur = pending_next; 104 } 105} 106 107void ReferenceQueue::ClearWhiteReferences(ReferenceQueue& cleared_references, 108 IsMarkedCallback* preserve_callback, 109 void* arg) { 110 while (!IsEmpty()) { 111 mirror::Reference* ref = DequeuePendingReference(); 112 mirror::Object* referent = ref->GetReferent(); 113 if (referent != nullptr) { 114 mirror::Object* forward_address = preserve_callback(referent, arg); 115 if (forward_address == nullptr) { 116 // Referent is white, clear it. 117 if (Runtime::Current()->IsActiveTransaction()) { 118 ref->ClearReferent<true>(); 119 } else { 120 ref->ClearReferent<false>(); 121 } 122 if (ref->IsEnqueuable()) { 123 cleared_references.EnqueuePendingReference(ref); 124 } 125 } else if (referent != forward_address) { 126 // Object moved, need to updated the referent. 127 ref->SetReferent<false>(forward_address); 128 } 129 } 130 } 131} 132 133void ReferenceQueue::EnqueueFinalizerReferences(ReferenceQueue& cleared_references, 134 IsMarkedCallback is_marked_callback, 135 MarkObjectCallback recursive_mark_callback, 136 void* arg) { 137 while (!IsEmpty()) { 138 mirror::FinalizerReference* ref = DequeuePendingReference()->AsFinalizerReference(); 139 mirror::Object* referent = ref->GetReferent(); 140 if (referent != nullptr) { 141 mirror::Object* forward_address = is_marked_callback(referent, arg); 142 // If the referent isn't marked, mark it and update the 143 if (forward_address == nullptr) { 144 forward_address = recursive_mark_callback(referent, arg); 145 // If the referent is non-null the reference must queuable. 146 DCHECK(ref->IsEnqueuable()); 147 // Move the updated referent to the zombie field. 148 if (Runtime::Current()->IsActiveTransaction()) { 149 ref->SetZombie<true>(forward_address); 150 ref->ClearReferent<true>(); 151 } else { 152 ref->SetZombie<false>(forward_address); 153 ref->ClearReferent<false>(); 154 } 155 cleared_references.EnqueueReference(ref); 156 } else if (referent != forward_address) { 157 ref->SetReferent<false>(forward_address); 158 } 159 } 160 } 161} 162 163void ReferenceQueue::PreserveSomeSoftReferences(IsMarkedCallback preserve_callback, void* arg) { 164 ReferenceQueue cleared; 165 while (!IsEmpty()) { 166 mirror::Reference* ref = DequeuePendingReference(); 167 mirror::Object* referent = ref->GetReferent(); 168 if (referent != nullptr) { 169 mirror::Object* forward_address = preserve_callback(referent, arg); 170 if (forward_address == nullptr) { 171 // Either the reference isn't marked or we don't wish to preserve it. 172 cleared.EnqueuePendingReference(ref); 173 } else if (forward_address != referent) { 174 ref->SetReferent<false>(forward_address); 175 } 176 } 177 } 178 list_ = cleared.GetList(); 179} 180 181} // namespace gc 182} // namespace art 183 184