Home | History | Annotate | Download | only in gc
      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