111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes/*
211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * Copyright (C) 2008 The Android Open Source Project
311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes *
411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * you may not use this file except in compliance with the License.
611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * You may obtain a copy of the License at
711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes *
811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes *
1011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * Unless required by applicable law or agreed to in writing, software
1111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * See the License for the specific language governing permissions and
1411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes * limitations under the License.
1511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes */
1611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
1711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes#include "reference_table.h"
1811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
1976b6167407c2b6f5d40ad895b2793a6b037f54b2Elliott Hughes#include "base/mutex.h"
206c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes#include "indirect_reference_table.h"
212dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "mirror/array.h"
222dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "mirror/array-inl.h"
232dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "mirror/class.h"
242dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "mirror/class-inl.h"
252dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "mirror/object-inl.h"
26b0fa5dc7769c1e054032f39de0a3f6d6dd06f8cfIan Rogers#include "mirror/string-inl.h"
272dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "thread.h"
282dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers#include "utils.h"
2911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
3011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughesnamespace art {
3111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
32bb1e8f0a07c12a8b0a2dd3cab6a1a7e825a54c6fElliott HughesReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max_size)
33bb1e8f0a07c12a8b0a2dd3cab6a1a7e825a54c6fElliott Hughes    : name_(name), max_size_(max_size) {
3411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  CHECK_LE(initial_size, max_size);
3511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  entries_.reserve(initial_size);
3611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}
3711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
38c1674ed06662420213441ff2b818f2f71f9098dcElliott HughesReferenceTable::~ReferenceTable() {
39c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes}
40c1674ed06662420213441ff2b818f2f71f9098dcElliott Hughes
41423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartiervoid ReferenceTable::Add(mirror::Object* obj) {
4211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  DCHECK(obj != NULL);
43c645f1ddb7c40bea6a38eda4b3f83f6b6dec405bMathieu Chartier  VerifyObject(obj);
44423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartier  if (entries_.size() >= max_size_) {
4511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    LOG(FATAL) << "ReferenceTable '" << name_ << "' "
4611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes               << "overflowed (" << max_size_ << " entries)";
4711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
4894f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi  entries_.push_back(GcRoot<mirror::Object>(obj));
4911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}
5011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
51423d2a3dcbb260b020efb5da59f784c9f02accbfMathieu Chartiervoid ReferenceTable::Remove(mirror::Object* obj) {
5211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  // We iterate backwards on the assumption that references are LIFO.
5311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  for (int i = entries_.size() - 1; i >= 0; --i) {
5494f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    mirror::Object* entry = entries_[i].Read();
55ea2e1bd713ca8295ba4fcd01e77a3ce532ea61e4Hiroshi Yamauchi    if (entry == obj) {
5611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      entries_.erase(entries_.begin() + i);
5711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      return;
5811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
5911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
6011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}
6111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
625b1982d2b41ab7a664fb04117539f29eadafa773Carl Shapiro// If "obj" is an array, return the number of elements in the array.
635b1982d2b41ab7a664fb04117539f29eadafa773Carl Shapiro// Otherwise, return zero.
64ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogersstatic size_t GetElementCount(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
65b63ec393a5c4ba2be1d34dd871cda811eaa803c7Brian Carlstrom  if (obj == NULL || obj == kClearedJniWeakGlobal || !obj->IsArrayInstance()) {
6611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    return 0;
6711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
6811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  return obj->AsArray()->GetLength();
6911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}
7011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
7111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughesstruct ObjectComparator {
7294f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi  bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2)
7300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers    // TODO: enable analysis when analysis can work with the STL.
7400f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers      NO_THREAD_SAFETY_ANALYSIS {
7581d425b0b232962441616f8b14f73620bffef5e5Ian Rogers    Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
7694f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    mirror::Object* obj1 = root1.Read<kWithoutReadBarrier>();
7794f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    mirror::Object* obj2 = root2.Read<kWithoutReadBarrier>();
7811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    // Ensure null references and cleared jweaks appear at the end.
7911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    if (obj1 == NULL) {
8011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      return true;
8111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    } else if (obj2 == NULL) {
8211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      return false;
8311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
8411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    if (obj1 == kClearedJniWeakGlobal) {
8511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      return true;
8611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    } else if (obj2 == kClearedJniWeakGlobal) {
8711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      return false;
8811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
8911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
9011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    // Sort by class...
9111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    if (obj1->GetClass() != obj2->GetClass()) {
9216abc5f28ac9792fd1ba2c82f123cfd871cddbdbBrian Carlstrom      return obj1->GetClass()->IdentityHashCode() < obj2->GetClass()->IdentityHashCode();
9311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    } else {
9411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      // ...then by size...
9511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      size_t count1 = obj1->SizeOf();
9611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      size_t count2 = obj2->SizeOf();
9711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      if (count1 != count2) {
9811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes        return count1 < count2;
9911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      } else {
10000f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        // ...and finally by identity hash code.
10100f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers        return obj1->IdentityHashCode() < obj2->IdentityHashCode();
10211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      }
10311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
10411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
10511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes};
10611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
1075b1982d2b41ab7a664fb04117539f29eadafa773Carl Shapiro// Log an object with some additional info.
1085b1982d2b41ab7a664fb04117539f29eadafa773Carl Shapiro//
1095b1982d2b41ab7a664fb04117539f29eadafa773Carl Shapiro// Pass in the number of elements in the array (or 0 if this is not an
1105b1982d2b41ab7a664fb04117539f29eadafa773Carl Shapiro// array object), and the number of additional objects that are identical
1115b1982d2b41ab7a664fb04117539f29eadafa773Carl Shapiro// or equivalent to the original.
112ef7d42fca18c16fbaf103822ad16f23246e2905dIan Rogersstatic void DumpSummaryLine(std::ostream& os, mirror::Object* obj, size_t element_count,
11300f7d0eaa6bd93d33bf0c1429bf4ba0b3f28abacIan Rogers                            int identical, int equiv)
114b726dcb581bf72da46527378ccb6889020f0e6e9Ian Rogers    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
11511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  if (obj == NULL) {
11673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    os << "    NULL reference (count=" << equiv << ")\n";
11711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    return;
11811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
11911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  if (obj == kClearedJniWeakGlobal) {
12073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    os << "    cleared jweak (count=" << equiv << ")\n";
12111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    return;
12211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
12311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
12454e7df1896a4066cbb9fe6f72249829f0b8c49c6Elliott Hughes  std::string className(PrettyTypeOf(obj));
12511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  if (obj->IsClass()) {
12611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    // We're summarizing multiple instances, so using the exemplar
12711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    // Class' type parameter here would be misleading.
12811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    className = "java.lang.Class";
12911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
13073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes  if (element_count != 0) {
13173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    StringAppendF(&className, " (%zd elements)", element_count);
13211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
13311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
13411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  size_t total = identical + equiv + 1;
135215f3144be114ac27002059330d903bf1ff5a592Elliott Hughes  std::string msg(StringPrintf("%5zd of %s", total, className.c_str()));
13611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  if (identical + equiv != 0) {
13711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    StringAppendF(&msg, " (%d unique instances)", equiv + 1);
13811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
13973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes  os << "    " << msg << "\n";
14011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}
14111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
14211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughessize_t ReferenceTable::Size() const {
14311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  return entries_.size();
14411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}
14511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
146ea2e1bd713ca8295ba4fcd01e77a3ce532ea61e4Hiroshi Yamauchivoid ReferenceTable::Dump(std::ostream& os) {
14773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes  os << name_ << " reference table dump:\n";
14873e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes  Dump(os, entries_);
1496c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes}
15011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
151ea2e1bd713ca8295ba4fcd01e77a3ce532ea61e4Hiroshi Yamauchivoid ReferenceTable::Dump(std::ostream& os, Table& entries) {
1526c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes  if (entries.empty()) {
15373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    os << "  (empty)\n";
15411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    return;
15511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
15611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
15711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  // Dump the most recent N entries.
15811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  const size_t kLast = 10;
1596c1a394b47c85c8d1723fc3b156a3b1b0b29a757Elliott Hughes  size_t count = entries.size();
16011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  int first = count - kLast;
16111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  if (first < 0) {
16211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    first = 0;
16311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
16473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes  os << "  Last " << (count - first) << " entries (of " << count << "):\n";
16511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  for (int idx = count - 1; idx >= first; --idx) {
16694f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    mirror::Object* ref = entries[idx].Read();
16711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    if (ref == NULL) {
16811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      continue;
16911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
17011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    if (ref == kClearedJniWeakGlobal) {
17173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes      os << StringPrintf("    %5d: cleared jweak\n", idx);
17211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      continue;
17311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
17411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    if (ref->GetClass() == NULL) {
17511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      // should only be possible right after a plain dvmMalloc().
17611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      size_t size = ref->SizeOf();
17773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes      os << StringPrintf("    %5d: %p (raw) (%zd bytes)\n", idx, ref, size);
17811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      continue;
17911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
18011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
18154e7df1896a4066cbb9fe6f72249829f0b8c49c6Elliott Hughes    std::string className(PrettyTypeOf(ref));
18211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
18311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    std::string extras;
18473e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    size_t element_count = GetElementCount(ref);
18573e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    if (element_count != 0) {
18673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes      StringAppendF(&extras, " (%zd elements)", element_count);
18773e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    } else if (ref->GetClass()->IsStringClass()) {
1882dd0e2cea360bc9206eb88ecc40d259e796c239dIan Rogers      mirror::String* s = const_cast<mirror::Object*>(ref)->AsString();
18973e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes      std::string utf8(s->ToModifiedUtf8());
19073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes      if (s->GetLength() <= 16) {
19173e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes        StringAppendF(&extras, " \"%s\"", utf8.c_str());
19211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      } else {
19373e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes        StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
19411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      }
19511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
19673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    os << StringPrintf("    %5d: ", idx) << ref << " " << className << extras << "\n";
19711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
19811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
19911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  // Make a copy of the table and sort it.
200ea2e1bd713ca8295ba4fcd01e77a3ce532ea61e4Hiroshi Yamauchi  Table sorted_entries;
201ea2e1bd713ca8295ba4fcd01e77a3ce532ea61e4Hiroshi Yamauchi  for (size_t i = 0; i < entries.size(); ++i) {
20294f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    mirror::Object* entry = entries[i].Read();
20394f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    sorted_entries.push_back(GcRoot<mirror::Object>(entry));
204ea2e1bd713ca8295ba4fcd01e77a3ce532ea61e4Hiroshi Yamauchi  }
20511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  std::sort(sorted_entries.begin(), sorted_entries.end(), ObjectComparator());
20611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
20711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  // Remove any uninteresting stuff from the list. The sort moved them all to the end.
20894f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi  while (!sorted_entries.empty() && sorted_entries.back().IsNull()) {
20911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    sorted_entries.pop_back();
21011e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
21194f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi  while (!sorted_entries.empty() &&
21294f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi         sorted_entries.back().Read<kWithoutReadBarrier>() == kClearedJniWeakGlobal) {
21311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    sorted_entries.pop_back();
21411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
21511e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  if (sorted_entries.empty()) {
21611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    return;
21711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
21811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
21911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  // Dump a summary of the whole table.
22073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes  os << "  Summary:\n";
22111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  size_t equiv = 0;
22211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  size_t identical = 0;
22311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  for (size_t idx = 1; idx < count; idx++) {
22494f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    mirror::Object* prev = sorted_entries[idx-1].Read<kWithoutReadBarrier>();
22594f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi    mirror::Object* current = sorted_entries[idx].Read<kWithoutReadBarrier>();
22673e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    size_t element_count = GetElementCount(prev);
22711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    if (current == prev) {
22811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      // Same reference, added more than once.
22911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      identical++;
23073e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes    } else if (current->GetClass() == prev->GetClass() && GetElementCount(current) == element_count) {
23111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      // Same class / element count, different object.
23211e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      equiv++;
23311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    } else {
23411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      // Different class.
23573e66f73f5093b64f2b023ebbb85916a13d5c937Elliott Hughes      DumpSummaryLine(os, prev, element_count, identical, equiv);
23611e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes      equiv = identical = 0;
23711e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes    }
23811e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  }
23911e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes  // Handle the last entry.
24094f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi  DumpSummaryLine(os, sorted_entries.back().Read<kWithoutReadBarrier>(),
24194f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi                  GetElementCount(sorted_entries.back().Read<kWithoutReadBarrier>()),
24294f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi                  identical, equiv);
24311e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}
24411e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes
24512f7423a2bb4bfab76700d84eb6d4338d211983aMathieu Chartiervoid ReferenceTable::VisitRoots(RootCallback* visitor, void* arg, const RootInfo& root_info) {
24694f7b49578b6aaa80de8ffed230648d601393905Hiroshi Yamauchi  for (GcRoot<mirror::Object>& root : entries_) {
24712f7423a2bb4bfab76700d84eb6d4338d211983aMathieu Chartier    root.VisitRoot(visitor, arg, root_info);
248410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes  }
249410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes}
250410c0c876f326e14c176a39ba21fc4dd3f7db8abElliott Hughes
25111e45077acba2e757799a00b3be9d63fec36a7ccElliott Hughes}  // namespace art
252