Home | History | Annotate | Download | only in accounting
      1 /*
      2  * Copyright (C) 2012 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 "mod_union_table.h"
     18 
     19 #include <memory>
     20 
     21 #include "base/stl_util.h"
     22 #include "card_table-inl.h"
     23 #include "heap_bitmap.h"
     24 #include "gc/accounting/space_bitmap-inl.h"
     25 #include "gc/collector/mark_sweep.h"
     26 #include "gc/collector/mark_sweep-inl.h"
     27 #include "gc/heap.h"
     28 #include "gc/space/space.h"
     29 #include "mirror/art_field-inl.h"
     30 #include "mirror/object-inl.h"
     31 #include "mirror/class-inl.h"
     32 #include "mirror/object_array-inl.h"
     33 #include "space_bitmap-inl.h"
     34 #include "thread.h"
     35 
     36 using ::art::mirror::Object;
     37 
     38 namespace art {
     39 namespace gc {
     40 namespace accounting {
     41 
     42 class ModUnionClearCardSetVisitor {
     43  public:
     44   explicit ModUnionClearCardSetVisitor(ModUnionTable::CardSet* const cleared_cards)
     45     : cleared_cards_(cleared_cards) {
     46   }
     47 
     48   inline void operator()(byte* card, byte expected_value, byte new_value) const {
     49     if (expected_value == CardTable::kCardDirty) {
     50       cleared_cards_->insert(card);
     51     }
     52   }
     53 
     54  private:
     55   ModUnionTable::CardSet* const cleared_cards_;
     56 };
     57 
     58 class ModUnionClearCardVisitor {
     59  public:
     60   explicit ModUnionClearCardVisitor(std::vector<byte*>* cleared_cards)
     61     : cleared_cards_(cleared_cards) {
     62   }
     63 
     64   void operator()(byte* card, byte expected_card, byte new_card) const {
     65     if (expected_card == CardTable::kCardDirty) {
     66       cleared_cards_->push_back(card);
     67     }
     68   }
     69  private:
     70   std::vector<byte*>* const cleared_cards_;
     71 };
     72 
     73 class ModUnionUpdateObjectReferencesVisitor {
     74  public:
     75   ModUnionUpdateObjectReferencesVisitor(MarkHeapReferenceCallback* callback, void* arg)
     76     : callback_(callback),
     77       arg_(arg) {
     78   }
     79 
     80   // Extra parameters are required since we use this same visitor signature for checking objects.
     81   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
     82       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     83     // Only add the reference if it is non null and fits our criteria.
     84     mirror::HeapReference<Object>* obj_ptr = obj->GetFieldObjectReferenceAddr(offset);
     85     if (obj_ptr->AsMirrorPtr() != nullptr) {
     86       callback_(obj_ptr, arg_);
     87     }
     88   }
     89 
     90  private:
     91   MarkHeapReferenceCallback* const callback_;
     92   void* arg_;
     93 };
     94 
     95 class ModUnionScanImageRootVisitor {
     96  public:
     97   ModUnionScanImageRootVisitor(MarkHeapReferenceCallback* callback, void* arg)
     98       : callback_(callback), arg_(arg) {}
     99 
    100   void operator()(Object* root) const
    101       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
    102       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    103     DCHECK(root != NULL);
    104     ModUnionUpdateObjectReferencesVisitor ref_visitor(callback_, arg_);
    105     root->VisitReferences<kMovingClasses>(ref_visitor, VoidFunctor());
    106   }
    107 
    108  private:
    109   MarkHeapReferenceCallback* const callback_;
    110   void* const arg_;
    111 };
    112 
    113 void ModUnionTableReferenceCache::ClearCards() {
    114   CardTable* card_table = GetHeap()->GetCardTable();
    115   ModUnionClearCardSetVisitor visitor(&cleared_cards_);
    116   // Clear dirty cards in the this space and update the corresponding mod-union bits.
    117   card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
    118 }
    119 
    120 class AddToReferenceArrayVisitor {
    121  public:
    122   explicit AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
    123                                       std::vector<mirror::HeapReference<Object>*>* references)
    124     : mod_union_table_(mod_union_table), references_(references) {
    125   }
    126 
    127   // Extra parameters are required since we use this same visitor signature for checking objects.
    128   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
    129       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    130     mirror::HeapReference<Object>* ref_ptr = obj->GetFieldObjectReferenceAddr(offset);
    131     mirror::Object* ref = ref_ptr->AsMirrorPtr();
    132     // Only add the reference if it is non null and fits our criteria.
    133     if (ref != nullptr && mod_union_table_->ShouldAddReference(ref)) {
    134       // Push the adddress of the reference.
    135       references_->push_back(ref_ptr);
    136     }
    137   }
    138 
    139  private:
    140   ModUnionTableReferenceCache* const mod_union_table_;
    141   std::vector<mirror::HeapReference<Object>*>* const references_;
    142 };
    143 
    144 class ModUnionReferenceVisitor {
    145  public:
    146   explicit ModUnionReferenceVisitor(ModUnionTableReferenceCache* const mod_union_table,
    147                                     std::vector<mirror::HeapReference<Object>*>* references)
    148     : mod_union_table_(mod_union_table),
    149       references_(references) {
    150   }
    151 
    152   void operator()(Object* obj) const
    153       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
    154     // We don't have an early exit since we use the visitor pattern, an early
    155     // exit should significantly speed this up.
    156     AddToReferenceArrayVisitor visitor(mod_union_table_, references_);
    157     obj->VisitReferences<kMovingClasses>(visitor, VoidFunctor());
    158   }
    159  private:
    160   ModUnionTableReferenceCache* const mod_union_table_;
    161   std::vector<mirror::HeapReference<Object>*>* const references_;
    162 };
    163 
    164 class CheckReferenceVisitor {
    165  public:
    166   explicit CheckReferenceVisitor(ModUnionTableReferenceCache* mod_union_table,
    167                                  const std::set<const Object*>& references)
    168     : mod_union_table_(mod_union_table),
    169       references_(references) {
    170   }
    171 
    172   // Extra parameters are required since we use this same visitor signature for checking objects.
    173   void operator()(Object* obj, MemberOffset offset, bool /*is_static*/) const
    174       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_) {
    175     mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
    176     if (ref != nullptr && mod_union_table_->ShouldAddReference(ref) &&
    177         references_.find(ref) == references_.end()) {
    178       Heap* heap = mod_union_table_->GetHeap();
    179       space::ContinuousSpace* from_space = heap->FindContinuousSpaceFromObject(obj, false);
    180       space::ContinuousSpace* to_space = heap->FindContinuousSpaceFromObject(ref, false);
    181       LOG(INFO) << "Object " << reinterpret_cast<const void*>(obj) << "(" << PrettyTypeOf(obj)
    182           << ")" << "References " << reinterpret_cast<const void*>(ref) << "(" << PrettyTypeOf(ref)
    183           << ") without being in mod-union table";
    184       LOG(INFO) << "FromSpace " << from_space->GetName() << " type "
    185           << from_space->GetGcRetentionPolicy();
    186       LOG(INFO) << "ToSpace " << to_space->GetName() << " type "
    187           << to_space->GetGcRetentionPolicy();
    188       heap->DumpSpaces(LOG(INFO));
    189       LOG(FATAL) << "FATAL ERROR";
    190     }
    191   }
    192 
    193  private:
    194   ModUnionTableReferenceCache* const mod_union_table_;
    195   const std::set<const Object*>& references_;
    196 };
    197 
    198 class ModUnionCheckReferences {
    199  public:
    200   explicit ModUnionCheckReferences(ModUnionTableReferenceCache* mod_union_table,
    201                                    const std::set<const Object*>& references)
    202       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
    203       : mod_union_table_(mod_union_table), references_(references) {
    204   }
    205 
    206   void operator()(Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
    207     Locks::heap_bitmap_lock_->AssertSharedHeld(Thread::Current());
    208     CheckReferenceVisitor visitor(mod_union_table_, references_);
    209     obj->VisitReferences<kMovingClasses>(visitor, VoidFunctor());
    210   }
    211 
    212  private:
    213   ModUnionTableReferenceCache* const mod_union_table_;
    214   const std::set<const Object*>& references_;
    215 };
    216 
    217 void ModUnionTableReferenceCache::Verify() {
    218   // Start by checking that everything in the mod union table is marked.
    219   for (const auto& ref_pair : references_) {
    220     for (mirror::HeapReference<Object>* ref : ref_pair.second) {
    221       CHECK(heap_->IsLiveObjectLocked(ref->AsMirrorPtr()));
    222     }
    223   }
    224 
    225   // Check the references of each clean card which is also in the mod union table.
    226   CardTable* card_table = heap_->GetCardTable();
    227   ContinuousSpaceBitmap* live_bitmap = space_->GetLiveBitmap();
    228   for (const auto& ref_pair : references_) {
    229     const byte* card = ref_pair.first;
    230     if (*card == CardTable::kCardClean) {
    231       std::set<const Object*> reference_set;
    232       for (mirror::HeapReference<Object>* obj_ptr : ref_pair.second) {
    233         reference_set.insert(obj_ptr->AsMirrorPtr());
    234       }
    235       ModUnionCheckReferences visitor(this, reference_set);
    236       uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
    237       live_bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, visitor);
    238     }
    239   }
    240 }
    241 
    242 void ModUnionTableReferenceCache::Dump(std::ostream& os) {
    243   CardTable* card_table = heap_->GetCardTable();
    244   os << "ModUnionTable cleared cards: [";
    245   for (byte* card_addr : cleared_cards_) {
    246     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
    247     uintptr_t end = start + CardTable::kCardSize;
    248     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << ",";
    249   }
    250   os << "]\nModUnionTable references: [";
    251   for (const auto& ref_pair : references_) {
    252     const byte* card_addr = ref_pair.first;
    253     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
    254     uintptr_t end = start + CardTable::kCardSize;
    255     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "->{";
    256     for (mirror::HeapReference<Object>* ref : ref_pair.second) {
    257       os << reinterpret_cast<const void*>(ref->AsMirrorPtr()) << ",";
    258     }
    259     os << "},";
    260   }
    261 }
    262 
    263 void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
    264                                                           void* arg) {
    265   CardTable* card_table = heap_->GetCardTable();
    266 
    267   std::vector<mirror::HeapReference<Object>*> cards_references;
    268   ModUnionReferenceVisitor add_visitor(this, &cards_references);
    269 
    270   for (const auto& card : cleared_cards_) {
    271     // Clear and re-compute alloc space references associated with this card.
    272     cards_references.clear();
    273     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card));
    274     uintptr_t end = start + CardTable::kCardSize;
    275     auto* space = heap_->FindContinuousSpaceFromObject(reinterpret_cast<Object*>(start), false);
    276     DCHECK(space != nullptr);
    277     ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap();
    278     live_bitmap->VisitMarkedRange(start, end, add_visitor);
    279 
    280     // Update the corresponding references for the card.
    281     auto found = references_.find(card);
    282     if (found == references_.end()) {
    283       if (cards_references.empty()) {
    284         // No reason to add empty array.
    285         continue;
    286       }
    287       references_.Put(card, cards_references);
    288     } else {
    289       found->second = cards_references;
    290     }
    291   }
    292   cleared_cards_.clear();
    293   size_t count = 0;
    294   for (const auto& ref : references_) {
    295     for (mirror::HeapReference<Object>* obj_ptr : ref.second) {
    296       callback(obj_ptr, arg);
    297     }
    298     count += ref.second.size();
    299   }
    300   if (VLOG_IS_ON(heap)) {
    301     VLOG(gc) << "Marked " << count << " references in mod union table";
    302   }
    303 }
    304 
    305 void ModUnionTableCardCache::ClearCards() {
    306   CardTable* card_table = GetHeap()->GetCardTable();
    307   ModUnionClearCardSetVisitor visitor(&cleared_cards_);
    308   // Clear dirty cards in the this space and update the corresponding mod-union bits.
    309   card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
    310 }
    311 
    312 // Mark all references to the alloc space(s).
    313 void ModUnionTableCardCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
    314                                                      void* arg) {
    315   CardTable* card_table = heap_->GetCardTable();
    316   ModUnionScanImageRootVisitor scan_visitor(callback, arg);
    317   ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
    318   for (const byte* card_addr : cleared_cards_) {
    319     uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
    320     DCHECK(space_->HasAddress(reinterpret_cast<Object*>(start)));
    321     bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
    322   }
    323 }
    324 
    325 void ModUnionTableCardCache::Dump(std::ostream& os) {
    326   CardTable* card_table = heap_->GetCardTable();
    327   os << "ModUnionTable dirty cards: [";
    328   for (const byte* card_addr : cleared_cards_) {
    329     auto start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
    330     auto end = start + CardTable::kCardSize;
    331     os << reinterpret_cast<void*>(start) << "-" << reinterpret_cast<void*>(end) << "\n";
    332   }
    333   os << "]";
    334 }
    335 
    336 }  // namespace accounting
    337 }  // namespace gc
    338 }  // namespace art
    339