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