Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2008 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_table.h"
     18 
     19 #include "base/mutex.h"
     20 #include "indirect_reference_table.h"
     21 #include "mirror/array.h"
     22 #include "mirror/array-inl.h"
     23 #include "mirror/class.h"
     24 #include "mirror/class-inl.h"
     25 #include "mirror/object-inl.h"
     26 #include "mirror/string-inl.h"
     27 #include "runtime-inl.h"
     28 #include "thread.h"
     29 #include "utils.h"
     30 
     31 namespace art {
     32 
     33 ReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max_size)
     34     : name_(name), max_size_(max_size) {
     35   CHECK_LE(initial_size, max_size);
     36   entries_.reserve(initial_size);
     37 }
     38 
     39 ReferenceTable::~ReferenceTable() {
     40 }
     41 
     42 void ReferenceTable::Add(mirror::Object* obj) {
     43   DCHECK(obj != nullptr);
     44   VerifyObject(obj);
     45   if (entries_.size() >= max_size_) {
     46     LOG(FATAL) << "ReferenceTable '" << name_ << "' "
     47                << "overflowed (" << max_size_ << " entries)";
     48   }
     49   entries_.push_back(GcRoot<mirror::Object>(obj));
     50 }
     51 
     52 void ReferenceTable::Remove(mirror::Object* obj) {
     53   // We iterate backwards on the assumption that references are LIFO.
     54   for (int i = entries_.size() - 1; i >= 0; --i) {
     55     mirror::Object* entry = entries_[i].Read();
     56     if (entry == obj) {
     57       entries_.erase(entries_.begin() + i);
     58       return;
     59     }
     60   }
     61 }
     62 
     63 // If "obj" is an array, return the number of elements in the array.
     64 // Otherwise, return zero.
     65 static size_t GetElementCount(mirror::Object* obj) SHARED_REQUIRES(Locks::mutator_lock_) {
     66   // We assume the special cleared value isn't an array in the if statement below.
     67   DCHECK(!Runtime::Current()->GetClearedJniWeakGlobal()->IsArrayInstance());
     68   if (obj == nullptr || !obj->IsArrayInstance()) {
     69     return 0;
     70   }
     71   return obj->AsArray()->GetLength();
     72 }
     73 
     74 // Log an object with some additional info.
     75 //
     76 // Pass in the number of elements in the array (or 0 if this is not an
     77 // array object), and the number of additional objects that are identical
     78 // or equivalent to the original.
     79 static void DumpSummaryLine(std::ostream& os, mirror::Object* obj, size_t element_count,
     80                             int identical, int equiv)
     81     SHARED_REQUIRES(Locks::mutator_lock_) {
     82   if (obj == nullptr) {
     83     os << "    null reference (count=" << equiv << ")\n";
     84     return;
     85   }
     86   if (Runtime::Current()->IsClearedJniWeakGlobal(obj)) {
     87     os << "    cleared jweak (count=" << equiv << ")\n";
     88     return;
     89   }
     90 
     91   std::string className(PrettyTypeOf(obj));
     92   if (obj->IsClass()) {
     93     // We're summarizing multiple instances, so using the exemplar
     94     // Class' type parameter here would be misleading.
     95     className = "java.lang.Class";
     96   }
     97   if (element_count != 0) {
     98     StringAppendF(&className, " (%zd elements)", element_count);
     99   }
    100 
    101   size_t total = identical + equiv + 1;
    102   std::string msg(StringPrintf("%5zd of %s", total, className.c_str()));
    103   if (identical + equiv != 0) {
    104     StringAppendF(&msg, " (%d unique instances)", equiv + 1);
    105   }
    106   os << "    " << msg << "\n";
    107 }
    108 
    109 size_t ReferenceTable::Size() const {
    110   return entries_.size();
    111 }
    112 
    113 void ReferenceTable::Dump(std::ostream& os) {
    114   os << name_ << " reference table dump:\n";
    115   Dump(os, entries_);
    116 }
    117 
    118 void ReferenceTable::Dump(std::ostream& os, Table& entries) {
    119   // Compare GC roots, first by class, then size, then address.
    120   struct GcRootComparator {
    121     bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2) const
    122       // TODO: enable analysis when analysis can work with the STL.
    123         NO_THREAD_SAFETY_ANALYSIS {
    124       Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
    125       // These GC roots are already forwarded in ReferenceTable::Dump. We sort by class since there
    126       // are no suspend points which can happen during the sorting process. This works since
    127       // we are guaranteed that the addresses of obj1, obj2, obj1->GetClass, obj2->GetClass wont
    128       // change during the sorting process. The classes are forwarded by ref->GetClass().
    129       mirror::Object* obj1 = root1.Read<kWithoutReadBarrier>();
    130       mirror::Object* obj2 = root2.Read<kWithoutReadBarrier>();
    131       DCHECK(obj1 != nullptr);
    132       DCHECK(obj2 != nullptr);
    133       Runtime* runtime = Runtime::Current();
    134       DCHECK(!runtime->IsClearedJniWeakGlobal(obj1));
    135       DCHECK(!runtime->IsClearedJniWeakGlobal(obj2));
    136       // Sort by class...
    137       if (obj1->GetClass() != obj2->GetClass()) {
    138         return obj1->GetClass() < obj2->GetClass();
    139       }
    140       // ...then by size...
    141       const size_t size1 = obj1->SizeOf();
    142       const size_t size2 = obj2->SizeOf();
    143       if (size1 != size2) {
    144         return size1 < size2;
    145       }
    146       // ...and finally by address.
    147       return obj1 < obj2;
    148     }
    149   };
    150 
    151   if (entries.empty()) {
    152     os << "  (empty)\n";
    153     return;
    154   }
    155 
    156   // Dump the most recent N entries.
    157   const size_t kLast = 10;
    158   size_t count = entries.size();
    159   int first = count - kLast;
    160   if (first < 0) {
    161     first = 0;
    162   }
    163   os << "  Last " << (count - first) << " entries (of " << count << "):\n";
    164   Runtime* runtime = Runtime::Current();
    165   for (int idx = count - 1; idx >= first; --idx) {
    166     mirror::Object* ref = entries[idx].Read();
    167     if (ref == nullptr) {
    168       continue;
    169     }
    170     if (runtime->IsClearedJniWeakGlobal(ref)) {
    171       os << StringPrintf("    %5d: cleared jweak\n", idx);
    172       continue;
    173     }
    174     if (ref->GetClass() == nullptr) {
    175       // should only be possible right after a plain dvmMalloc().
    176       size_t size = ref->SizeOf();
    177       os << StringPrintf("    %5d: %p (raw) (%zd bytes)\n", idx, ref, size);
    178       continue;
    179     }
    180 
    181     std::string className(PrettyTypeOf(ref));
    182 
    183     std::string extras;
    184     size_t element_count = GetElementCount(ref);
    185     if (element_count != 0) {
    186       StringAppendF(&extras, " (%zd elements)", element_count);
    187     } else if (ref->GetClass()->IsStringClass()) {
    188       mirror::String* s = ref->AsString();
    189       std::string utf8(s->ToModifiedUtf8());
    190       if (s->GetLength() <= 16) {
    191         StringAppendF(&extras, " \"%s\"", utf8.c_str());
    192       } else {
    193         StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
    194       }
    195     } else if (ref->IsReferenceInstance()) {
    196       mirror::Object* referent = ref->AsReference()->GetReferent();
    197       if (referent == nullptr) {
    198         extras = " (storing null)";
    199       } else {
    200         extras = StringPrintf(" (storing a %s)", PrettyTypeOf(referent).c_str());
    201       }
    202     }
    203     os << StringPrintf("    %5d: ", idx) << ref << " " << className << extras << "\n";
    204   }
    205 
    206   // Make a copy of the table and sort it, only adding non null and not cleared elements.
    207   Table sorted_entries;
    208   for (GcRoot<mirror::Object>& root : entries) {
    209     if (!root.IsNull() && !runtime->IsClearedJniWeakGlobal(root.Read())) {
    210       sorted_entries.push_back(root);
    211     }
    212   }
    213   if (sorted_entries.empty()) {
    214     return;
    215   }
    216   std::sort(sorted_entries.begin(), sorted_entries.end(), GcRootComparator());
    217 
    218   // Dump a summary of the whole table.
    219   os << "  Summary:\n";
    220   size_t equiv = 0;
    221   size_t identical = 0;
    222   mirror::Object* prev = nullptr;
    223   for (GcRoot<mirror::Object>& root : sorted_entries) {
    224     mirror::Object* current = root.Read<kWithoutReadBarrier>();
    225     if (prev != nullptr) {
    226       const size_t element_count = GetElementCount(prev);
    227       if (current == prev) {
    228         // Same reference, added more than once.
    229         ++identical;
    230       } else if (current->GetClass() == prev->GetClass() &&
    231           GetElementCount(current) == element_count) {
    232         // Same class / element count, different object.
    233         ++equiv;
    234       } else {
    235         // Different class.
    236         DumpSummaryLine(os, prev, element_count, identical, equiv);
    237         equiv = 0;
    238         identical = 0;
    239       }
    240     }
    241     prev = current;
    242   }
    243   // Handle the last entry.
    244   DumpSummaryLine(os, prev, GetElementCount(prev), identical, equiv);
    245 }
    246 
    247 void ReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
    248   BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(visitor, root_info);
    249   for (GcRoot<mirror::Object>& root : entries_) {
    250     buffered_visitor.VisitRoot(root);
    251   }
    252 }
    253 
    254 }  // namespace art
    255