xref: /aosp_15_r20/art/runtime/reference_table.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2008 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "reference_table.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
20*795d594fSAndroid Build Coastguard Worker 
21*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
23*795d594fSAndroid Build Coastguard Worker #include "gc/allocation_record.h"
24*795d594fSAndroid Build Coastguard Worker #include "gc/heap.h"
25*795d594fSAndroid Build Coastguard Worker #include "indirect_reference_table.h"
26*795d594fSAndroid Build Coastguard Worker #include "mirror/array-inl.h"
27*795d594fSAndroid Build Coastguard Worker #include "mirror/array.h"
28*795d594fSAndroid Build Coastguard Worker #include "mirror/class-inl.h"
29*795d594fSAndroid Build Coastguard Worker #include "mirror/class.h"
30*795d594fSAndroid Build Coastguard Worker #include "mirror/object-inl.h"
31*795d594fSAndroid Build Coastguard Worker #include "mirror/string-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "runtime-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "thread.h"
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker using android::base::StringAppendF;
38*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
39*795d594fSAndroid Build Coastguard Worker 
ReferenceTable(const char * name,size_t initial_size,size_t max_size)40*795d594fSAndroid Build Coastguard Worker ReferenceTable::ReferenceTable(const char* name, size_t initial_size, size_t max_size)
41*795d594fSAndroid Build Coastguard Worker     : name_(name), max_size_(max_size) {
42*795d594fSAndroid Build Coastguard Worker   CHECK_LE(initial_size, max_size);
43*795d594fSAndroid Build Coastguard Worker   entries_.reserve(initial_size);
44*795d594fSAndroid Build Coastguard Worker }
45*795d594fSAndroid Build Coastguard Worker 
~ReferenceTable()46*795d594fSAndroid Build Coastguard Worker ReferenceTable::~ReferenceTable() {
47*795d594fSAndroid Build Coastguard Worker }
48*795d594fSAndroid Build Coastguard Worker 
Add(ObjPtr<mirror::Object> obj)49*795d594fSAndroid Build Coastguard Worker void ReferenceTable::Add(ObjPtr<mirror::Object> obj) {
50*795d594fSAndroid Build Coastguard Worker   DCHECK(obj != nullptr);
51*795d594fSAndroid Build Coastguard Worker   VerifyObject(obj);
52*795d594fSAndroid Build Coastguard Worker   if (entries_.size() >= max_size_) {
53*795d594fSAndroid Build Coastguard Worker     LOG(FATAL) << "ReferenceTable '" << name_ << "' "
54*795d594fSAndroid Build Coastguard Worker                << "overflowed (" << max_size_ << " entries)";
55*795d594fSAndroid Build Coastguard Worker   }
56*795d594fSAndroid Build Coastguard Worker   entries_.push_back(GcRoot<mirror::Object>(obj));
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker 
Remove(ObjPtr<mirror::Object> obj)59*795d594fSAndroid Build Coastguard Worker void ReferenceTable::Remove(ObjPtr<mirror::Object> obj) {
60*795d594fSAndroid Build Coastguard Worker   // We iterate backwards on the assumption that references are LIFO.
61*795d594fSAndroid Build Coastguard Worker   for (int i = entries_.size() - 1; i >= 0; --i) {
62*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::Object> entry = entries_[i].Read();
63*795d594fSAndroid Build Coastguard Worker     if (entry == obj) {
64*795d594fSAndroid Build Coastguard Worker       entries_.erase(entries_.begin() + i);
65*795d594fSAndroid Build Coastguard Worker       return;
66*795d594fSAndroid Build Coastguard Worker     }
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker }
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker // If "obj" is an array, return the number of elements in the array.
71*795d594fSAndroid Build Coastguard Worker // Otherwise, return zero.
GetElementCount(ObjPtr<mirror::Object> obj)72*795d594fSAndroid Build Coastguard Worker static size_t GetElementCount(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
73*795d594fSAndroid Build Coastguard Worker   // We assume the special cleared value isn't an array in the if statement below.
74*795d594fSAndroid Build Coastguard Worker   DCHECK(!Runtime::Current()->GetClearedJniWeakGlobal()->IsArrayInstance());
75*795d594fSAndroid Build Coastguard Worker   if (obj == nullptr || !obj->IsArrayInstance()) {
76*795d594fSAndroid Build Coastguard Worker     return 0;
77*795d594fSAndroid Build Coastguard Worker   }
78*795d594fSAndroid Build Coastguard Worker   return obj->AsArray()->GetLength();
79*795d594fSAndroid Build Coastguard Worker }
80*795d594fSAndroid Build Coastguard Worker 
81*795d594fSAndroid Build Coastguard Worker // Log an object with some additional info.
82*795d594fSAndroid Build Coastguard Worker //
83*795d594fSAndroid Build Coastguard Worker // Pass in the number of elements in the array (or 0 if this is not an
84*795d594fSAndroid Build Coastguard Worker // array object), and the number of additional objects that are identical
85*795d594fSAndroid Build Coastguard Worker // or equivalent to the original.
DumpSummaryLine(std::ostream & os,ObjPtr<mirror::Object> obj,size_t element_count,int identical,int equiv)86*795d594fSAndroid Build Coastguard Worker static void DumpSummaryLine(std::ostream& os, ObjPtr<mirror::Object> obj, size_t element_count,
87*795d594fSAndroid Build Coastguard Worker                             int identical, int equiv)
88*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
89*795d594fSAndroid Build Coastguard Worker   if (obj == nullptr) {
90*795d594fSAndroid Build Coastguard Worker     os << "    null reference (count=" << equiv << ")\n";
91*795d594fSAndroid Build Coastguard Worker     return;
92*795d594fSAndroid Build Coastguard Worker   }
93*795d594fSAndroid Build Coastguard Worker   if (Runtime::Current()->IsClearedJniWeakGlobal(obj)) {
94*795d594fSAndroid Build Coastguard Worker     os << "    cleared jweak (count=" << equiv << ")\n";
95*795d594fSAndroid Build Coastguard Worker     return;
96*795d594fSAndroid Build Coastguard Worker   }
97*795d594fSAndroid Build Coastguard Worker 
98*795d594fSAndroid Build Coastguard Worker   std::string className(obj->PrettyTypeOf());
99*795d594fSAndroid Build Coastguard Worker   if (obj->IsClass()) {
100*795d594fSAndroid Build Coastguard Worker     // We're summarizing multiple instances, so using the exemplar
101*795d594fSAndroid Build Coastguard Worker     // Class' type parameter here would be misleading.
102*795d594fSAndroid Build Coastguard Worker     className = "java.lang.Class";
103*795d594fSAndroid Build Coastguard Worker   }
104*795d594fSAndroid Build Coastguard Worker   if (element_count != 0) {
105*795d594fSAndroid Build Coastguard Worker     StringAppendF(&className, " (%zd elements)", element_count);
106*795d594fSAndroid Build Coastguard Worker   }
107*795d594fSAndroid Build Coastguard Worker 
108*795d594fSAndroid Build Coastguard Worker   size_t total = identical + equiv + 1;
109*795d594fSAndroid Build Coastguard Worker   std::string msg(StringPrintf("%5zd of %s", total, className.c_str()));
110*795d594fSAndroid Build Coastguard Worker   if (identical + equiv != 0) {
111*795d594fSAndroid Build Coastguard Worker     StringAppendF(&msg, " (%d unique instances)", equiv + 1);
112*795d594fSAndroid Build Coastguard Worker   }
113*795d594fSAndroid Build Coastguard Worker   os << "    " << msg << "\n";
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker 
Size() const116*795d594fSAndroid Build Coastguard Worker size_t ReferenceTable::Size() const {
117*795d594fSAndroid Build Coastguard Worker   return entries_.size();
118*795d594fSAndroid Build Coastguard Worker }
119*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & os)120*795d594fSAndroid Build Coastguard Worker void ReferenceTable::Dump(std::ostream& os) {
121*795d594fSAndroid Build Coastguard Worker   os << name_ << " reference table dump:\n";
122*795d594fSAndroid Build Coastguard Worker   Dump(os, entries_);
123*795d594fSAndroid Build Coastguard Worker }
124*795d594fSAndroid Build Coastguard Worker 
Dump(std::ostream & os,Table & entries)125*795d594fSAndroid Build Coastguard Worker void ReferenceTable::Dump(std::ostream& os, Table& entries) {
126*795d594fSAndroid Build Coastguard Worker   // Compare GC roots, first by class, then size, then address.
127*795d594fSAndroid Build Coastguard Worker   struct GcRootComparator {
128*795d594fSAndroid Build Coastguard Worker     bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2) const
129*795d594fSAndroid Build Coastguard Worker       // TODO: enable analysis when analysis can work with the STL.
130*795d594fSAndroid Build Coastguard Worker         NO_THREAD_SAFETY_ANALYSIS {
131*795d594fSAndroid Build Coastguard Worker       Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
132*795d594fSAndroid Build Coastguard Worker       // These GC roots are already forwarded in ReferenceTable::Dump. We sort by class since there
133*795d594fSAndroid Build Coastguard Worker       // are no suspend points which can happen during the sorting process. This works since
134*795d594fSAndroid Build Coastguard Worker       // we are guaranteed that the addresses of obj1, obj2, obj1->GetClass, obj2->GetClass wont
135*795d594fSAndroid Build Coastguard Worker       // change during the sorting process. The classes are forwarded by ref->GetClass().
136*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Object> obj1 = root1.Read<kWithoutReadBarrier>();
137*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Object> obj2 = root2.Read<kWithoutReadBarrier>();
138*795d594fSAndroid Build Coastguard Worker       DCHECK(obj1 != nullptr);
139*795d594fSAndroid Build Coastguard Worker       DCHECK(obj2 != nullptr);
140*795d594fSAndroid Build Coastguard Worker       Runtime* runtime = Runtime::Current();
141*795d594fSAndroid Build Coastguard Worker       DCHECK(!runtime->IsClearedJniWeakGlobal(obj1));
142*795d594fSAndroid Build Coastguard Worker       DCHECK(!runtime->IsClearedJniWeakGlobal(obj2));
143*795d594fSAndroid Build Coastguard Worker       // Sort by class...
144*795d594fSAndroid Build Coastguard Worker       if (obj1->GetClass() != obj2->GetClass()) {
145*795d594fSAndroid Build Coastguard Worker         return obj1->GetClass() < obj2->GetClass();
146*795d594fSAndroid Build Coastguard Worker       }
147*795d594fSAndroid Build Coastguard Worker       // ...then by size...
148*795d594fSAndroid Build Coastguard Worker       const size_t size1 = obj1->SizeOf();
149*795d594fSAndroid Build Coastguard Worker       const size_t size2 = obj2->SizeOf();
150*795d594fSAndroid Build Coastguard Worker       if (size1 != size2) {
151*795d594fSAndroid Build Coastguard Worker         return size1 < size2;
152*795d594fSAndroid Build Coastguard Worker       }
153*795d594fSAndroid Build Coastguard Worker       // ...and finally by address.
154*795d594fSAndroid Build Coastguard Worker       return obj1.Ptr() < obj2.Ptr();
155*795d594fSAndroid Build Coastguard Worker     }
156*795d594fSAndroid Build Coastguard Worker   };
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker   if (entries.empty()) {
159*795d594fSAndroid Build Coastguard Worker     os << "  (empty)\n";
160*795d594fSAndroid Build Coastguard Worker     return;
161*795d594fSAndroid Build Coastguard Worker   }
162*795d594fSAndroid Build Coastguard Worker 
163*795d594fSAndroid Build Coastguard Worker   // Dump the most recent N entries.
164*795d594fSAndroid Build Coastguard Worker   const size_t kLast = 10;
165*795d594fSAndroid Build Coastguard Worker   size_t count = entries.size();
166*795d594fSAndroid Build Coastguard Worker   int first = count - kLast;
167*795d594fSAndroid Build Coastguard Worker   if (first < 0) {
168*795d594fSAndroid Build Coastguard Worker     first = 0;
169*795d594fSAndroid Build Coastguard Worker   }
170*795d594fSAndroid Build Coastguard Worker   os << "  Last " << (count - first) << " entries (of " << count << "):\n";
171*795d594fSAndroid Build Coastguard Worker   Runtime* runtime = Runtime::Current();
172*795d594fSAndroid Build Coastguard Worker   for (int idx = count - 1; idx >= first; --idx) {
173*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::Object> ref = entries[idx].Read();
174*795d594fSAndroid Build Coastguard Worker     if (ref == nullptr) {
175*795d594fSAndroid Build Coastguard Worker       continue;
176*795d594fSAndroid Build Coastguard Worker     }
177*795d594fSAndroid Build Coastguard Worker     if (runtime->IsClearedJniWeakGlobal(ref)) {
178*795d594fSAndroid Build Coastguard Worker       os << StringPrintf("    %5d: cleared jweak\n", idx);
179*795d594fSAndroid Build Coastguard Worker       continue;
180*795d594fSAndroid Build Coastguard Worker     }
181*795d594fSAndroid Build Coastguard Worker     if (ref->GetClass() == nullptr) {
182*795d594fSAndroid Build Coastguard Worker       // should only be possible right after a plain dvmMalloc().
183*795d594fSAndroid Build Coastguard Worker       size_t size = ref->SizeOf();
184*795d594fSAndroid Build Coastguard Worker       os << StringPrintf("    %5d: %p (raw) (%zd bytes)\n", idx, ref.Ptr(), size);
185*795d594fSAndroid Build Coastguard Worker       continue;
186*795d594fSAndroid Build Coastguard Worker     }
187*795d594fSAndroid Build Coastguard Worker 
188*795d594fSAndroid Build Coastguard Worker     std::string className(ref->PrettyTypeOf());
189*795d594fSAndroid Build Coastguard Worker 
190*795d594fSAndroid Build Coastguard Worker     std::string extras;
191*795d594fSAndroid Build Coastguard Worker     size_t element_count = GetElementCount(ref);
192*795d594fSAndroid Build Coastguard Worker     if (element_count != 0) {
193*795d594fSAndroid Build Coastguard Worker       StringAppendF(&extras, " (%zd elements)", element_count);
194*795d594fSAndroid Build Coastguard Worker     } else if (ref->GetClass()->IsStringClass()) {
195*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::String> s = ref->AsString();
196*795d594fSAndroid Build Coastguard Worker       std::string utf8(s->ToModifiedUtf8());
197*795d594fSAndroid Build Coastguard Worker       if (s->GetLength() <= 16) {
198*795d594fSAndroid Build Coastguard Worker         StringAppendF(&extras, " \"%s\"", utf8.c_str());
199*795d594fSAndroid Build Coastguard Worker       } else {
200*795d594fSAndroid Build Coastguard Worker         StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
201*795d594fSAndroid Build Coastguard Worker       }
202*795d594fSAndroid Build Coastguard Worker     } else if (ref->IsReferenceInstance()) {
203*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Object> referent = ref->AsReference()->GetReferent();
204*795d594fSAndroid Build Coastguard Worker       if (referent == nullptr) {
205*795d594fSAndroid Build Coastguard Worker         extras = " (referent is null)";
206*795d594fSAndroid Build Coastguard Worker       } else {
207*795d594fSAndroid Build Coastguard Worker         extras = StringPrintf(" (referent is a %s)", referent->PrettyTypeOf().c_str());
208*795d594fSAndroid Build Coastguard Worker       }
209*795d594fSAndroid Build Coastguard Worker     }
210*795d594fSAndroid Build Coastguard Worker     os << StringPrintf("    %5d: ", idx) << ref << " " << className << extras << "\n";
211*795d594fSAndroid Build Coastguard Worker     if (runtime->GetHeap()->IsAllocTrackingEnabled()) {
212*795d594fSAndroid Build Coastguard Worker       MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
213*795d594fSAndroid Build Coastguard Worker 
214*795d594fSAndroid Build Coastguard Worker       gc::AllocRecordObjectMap* records = runtime->GetHeap()->GetAllocationRecords();
215*795d594fSAndroid Build Coastguard Worker       DCHECK(records != nullptr);
216*795d594fSAndroid Build Coastguard Worker       // It's annoying that this is a list. But this code should be very uncommon to be executed.
217*795d594fSAndroid Build Coastguard Worker 
218*795d594fSAndroid Build Coastguard Worker       auto print_stack = [&](ObjPtr<mirror::Object> to_print, const std::string& msg)
219*795d594fSAndroid Build Coastguard Worker           REQUIRES_SHARED(Locks::mutator_lock_)
220*795d594fSAndroid Build Coastguard Worker           REQUIRES(Locks::alloc_tracker_lock_) {
221*795d594fSAndroid Build Coastguard Worker         for (auto it = records->Begin(), end = records->End(); it != end; ++it) {
222*795d594fSAndroid Build Coastguard Worker           GcRoot<mirror::Object>& stack_for_object = it->first;
223*795d594fSAndroid Build Coastguard Worker           gc::AllocRecord& record = it->second;
224*795d594fSAndroid Build Coastguard Worker           if (stack_for_object.Read() == to_print.Ptr()) {
225*795d594fSAndroid Build Coastguard Worker             os << "          " << msg << "\n";
226*795d594fSAndroid Build Coastguard Worker             const gc::AllocRecordStackTrace* trace = record.GetStackTrace();
227*795d594fSAndroid Build Coastguard Worker             size_t depth = trace->GetDepth();
228*795d594fSAndroid Build Coastguard Worker             if (depth == 0) {
229*795d594fSAndroid Build Coastguard Worker               os << "            (No managed frames)\n";
230*795d594fSAndroid Build Coastguard Worker             } else {
231*795d594fSAndroid Build Coastguard Worker               for (size_t i = 0; i < depth; ++i) {
232*795d594fSAndroid Build Coastguard Worker                 const gc::AllocRecordStackTraceElement& frame = trace->GetStackElement(i);
233*795d594fSAndroid Build Coastguard Worker                 os << "            ";
234*795d594fSAndroid Build Coastguard Worker                 if (frame.GetMethod() == nullptr) {
235*795d594fSAndroid Build Coastguard Worker                   os << "(missing method data)\n";
236*795d594fSAndroid Build Coastguard Worker                   continue;
237*795d594fSAndroid Build Coastguard Worker                 }
238*795d594fSAndroid Build Coastguard Worker                 os << frame.GetMethod()->PrettyMethod(true)
239*795d594fSAndroid Build Coastguard Worker                    << ":"
240*795d594fSAndroid Build Coastguard Worker                    << frame.ComputeLineNumber()
241*795d594fSAndroid Build Coastguard Worker                    << "\n";
242*795d594fSAndroid Build Coastguard Worker               }
243*795d594fSAndroid Build Coastguard Worker             }
244*795d594fSAndroid Build Coastguard Worker             break;
245*795d594fSAndroid Build Coastguard Worker           }
246*795d594fSAndroid Build Coastguard Worker         }
247*795d594fSAndroid Build Coastguard Worker       };
248*795d594fSAndroid Build Coastguard Worker       // Print the stack trace of the ref.
249*795d594fSAndroid Build Coastguard Worker       print_stack(ref, "Allocated at:");
250*795d594fSAndroid Build Coastguard Worker 
251*795d594fSAndroid Build Coastguard Worker       // If it's a reference, see if we have data about the referent.
252*795d594fSAndroid Build Coastguard Worker       if (ref->IsReferenceInstance()) {
253*795d594fSAndroid Build Coastguard Worker         ObjPtr<mirror::Object> referent = ref->AsReference()->GetReferent();
254*795d594fSAndroid Build Coastguard Worker         if (referent != nullptr) {
255*795d594fSAndroid Build Coastguard Worker           print_stack(referent, "Referent allocated at:");
256*795d594fSAndroid Build Coastguard Worker         }
257*795d594fSAndroid Build Coastguard Worker       }
258*795d594fSAndroid Build Coastguard Worker     }
259*795d594fSAndroid Build Coastguard Worker   }
260*795d594fSAndroid Build Coastguard Worker 
261*795d594fSAndroid Build Coastguard Worker   // Make a copy of the table and sort it, only adding non null and not cleared elements.
262*795d594fSAndroid Build Coastguard Worker   Table sorted_entries;
263*795d594fSAndroid Build Coastguard Worker   for (GcRoot<mirror::Object>& root : entries) {
264*795d594fSAndroid Build Coastguard Worker     if (!root.IsNull() && !runtime->IsClearedJniWeakGlobal(root.Read())) {
265*795d594fSAndroid Build Coastguard Worker       sorted_entries.push_back(root);
266*795d594fSAndroid Build Coastguard Worker     }
267*795d594fSAndroid Build Coastguard Worker   }
268*795d594fSAndroid Build Coastguard Worker   if (sorted_entries.empty()) {
269*795d594fSAndroid Build Coastguard Worker     return;
270*795d594fSAndroid Build Coastguard Worker   }
271*795d594fSAndroid Build Coastguard Worker   std::sort(sorted_entries.begin(), sorted_entries.end(), GcRootComparator());
272*795d594fSAndroid Build Coastguard Worker 
273*795d594fSAndroid Build Coastguard Worker   class SummaryElement {
274*795d594fSAndroid Build Coastguard Worker    public:
275*795d594fSAndroid Build Coastguard Worker     GcRoot<mirror::Object> root;
276*795d594fSAndroid Build Coastguard Worker     size_t equiv;
277*795d594fSAndroid Build Coastguard Worker     size_t identical;
278*795d594fSAndroid Build Coastguard Worker 
279*795d594fSAndroid Build Coastguard Worker     SummaryElement() : equiv(0), identical(0) {}
280*795d594fSAndroid Build Coastguard Worker     SummaryElement(SummaryElement&& ref) noexcept {
281*795d594fSAndroid Build Coastguard Worker       root = ref.root;
282*795d594fSAndroid Build Coastguard Worker       equiv = ref.equiv;
283*795d594fSAndroid Build Coastguard Worker       identical = ref.identical;
284*795d594fSAndroid Build Coastguard Worker     }
285*795d594fSAndroid Build Coastguard Worker     SummaryElement(const SummaryElement&) = default;
286*795d594fSAndroid Build Coastguard Worker     SummaryElement& operator=(SummaryElement&&) = default;
287*795d594fSAndroid Build Coastguard Worker 
288*795d594fSAndroid Build Coastguard Worker     void Reset(GcRoot<mirror::Object>& _root) {
289*795d594fSAndroid Build Coastguard Worker       root = _root;
290*795d594fSAndroid Build Coastguard Worker       equiv = 0;
291*795d594fSAndroid Build Coastguard Worker       identical = 0;
292*795d594fSAndroid Build Coastguard Worker     }
293*795d594fSAndroid Build Coastguard Worker   };
294*795d594fSAndroid Build Coastguard Worker   std::vector<SummaryElement> sorted_summaries;
295*795d594fSAndroid Build Coastguard Worker   {
296*795d594fSAndroid Build Coastguard Worker     SummaryElement prev;
297*795d594fSAndroid Build Coastguard Worker 
298*795d594fSAndroid Build Coastguard Worker     for (GcRoot<mirror::Object>& root : sorted_entries) {
299*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Object> current = root.Read<kWithoutReadBarrier>();
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker       if (UNLIKELY(prev.root.IsNull())) {
302*795d594fSAndroid Build Coastguard Worker         prev.Reset(root);
303*795d594fSAndroid Build Coastguard Worker         continue;
304*795d594fSAndroid Build Coastguard Worker       }
305*795d594fSAndroid Build Coastguard Worker 
306*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::Object> prevObj = prev.root.Read<kWithoutReadBarrier>();
307*795d594fSAndroid Build Coastguard Worker       if (current == prevObj) {
308*795d594fSAndroid Build Coastguard Worker         // Same reference, added more than once.
309*795d594fSAndroid Build Coastguard Worker         ++prev.identical;
310*795d594fSAndroid Build Coastguard Worker       } else if (current->GetClass() == prevObj->GetClass() &&
311*795d594fSAndroid Build Coastguard Worker           GetElementCount(current) == GetElementCount(prevObj)) {
312*795d594fSAndroid Build Coastguard Worker         // Same class / element count, different object.
313*795d594fSAndroid Build Coastguard Worker         ++prev.equiv;
314*795d594fSAndroid Build Coastguard Worker       } else {
315*795d594fSAndroid Build Coastguard Worker         sorted_summaries.push_back(prev);
316*795d594fSAndroid Build Coastguard Worker         prev.Reset(root);
317*795d594fSAndroid Build Coastguard Worker       }
318*795d594fSAndroid Build Coastguard Worker       prev.root = root;
319*795d594fSAndroid Build Coastguard Worker     }
320*795d594fSAndroid Build Coastguard Worker     sorted_summaries.push_back(prev);
321*795d594fSAndroid Build Coastguard Worker 
322*795d594fSAndroid Build Coastguard Worker     // Compare summary elements, first by combined count, then by identical (indicating leaks),
323*795d594fSAndroid Build Coastguard Worker     // then by class (and size and address).
324*795d594fSAndroid Build Coastguard Worker     struct SummaryElementComparator {
325*795d594fSAndroid Build Coastguard Worker       GcRootComparator gc_root_cmp;
326*795d594fSAndroid Build Coastguard Worker 
327*795d594fSAndroid Build Coastguard Worker       bool operator()(SummaryElement& elem1, SummaryElement& elem2) const
328*795d594fSAndroid Build Coastguard Worker           NO_THREAD_SAFETY_ANALYSIS {
329*795d594fSAndroid Build Coastguard Worker         Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
330*795d594fSAndroid Build Coastguard Worker 
331*795d594fSAndroid Build Coastguard Worker         size_t count1 = elem1.equiv + elem1.identical;
332*795d594fSAndroid Build Coastguard Worker         size_t count2 = elem2.equiv + elem2.identical;
333*795d594fSAndroid Build Coastguard Worker         if (count1 != count2) {
334*795d594fSAndroid Build Coastguard Worker           return count1 > count2;
335*795d594fSAndroid Build Coastguard Worker         }
336*795d594fSAndroid Build Coastguard Worker 
337*795d594fSAndroid Build Coastguard Worker         if (elem1.identical != elem2.identical) {
338*795d594fSAndroid Build Coastguard Worker           return elem1.identical > elem2.identical;
339*795d594fSAndroid Build Coastguard Worker         }
340*795d594fSAndroid Build Coastguard Worker 
341*795d594fSAndroid Build Coastguard Worker         // Otherwise, compare the GC roots as before.
342*795d594fSAndroid Build Coastguard Worker         return gc_root_cmp(elem1.root, elem2.root);
343*795d594fSAndroid Build Coastguard Worker       }
344*795d594fSAndroid Build Coastguard Worker     };
345*795d594fSAndroid Build Coastguard Worker     std::sort(sorted_summaries.begin(), sorted_summaries.end(), SummaryElementComparator());
346*795d594fSAndroid Build Coastguard Worker   }
347*795d594fSAndroid Build Coastguard Worker 
348*795d594fSAndroid Build Coastguard Worker   // Dump a summary of the whole table.
349*795d594fSAndroid Build Coastguard Worker   os << "  Summary:\n";
350*795d594fSAndroid Build Coastguard Worker   for (SummaryElement& elem : sorted_summaries) {
351*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::Object> elemObj = elem.root.Read<kWithoutReadBarrier>();
352*795d594fSAndroid Build Coastguard Worker     DumpSummaryLine(os, elemObj, GetElementCount(elemObj), elem.identical, elem.equiv);
353*795d594fSAndroid Build Coastguard Worker   }
354*795d594fSAndroid Build Coastguard Worker }
355*795d594fSAndroid Build Coastguard Worker 
VisitRoots(RootVisitor * visitor,const RootInfo & root_info)356*795d594fSAndroid Build Coastguard Worker void ReferenceTable::VisitRoots(RootVisitor* visitor, const RootInfo& root_info) {
357*795d594fSAndroid Build Coastguard Worker   BufferedRootVisitor<kDefaultBufferedRootCount> buffered_visitor(visitor, root_info);
358*795d594fSAndroid Build Coastguard Worker   for (GcRoot<mirror::Object>& root : entries_) {
359*795d594fSAndroid Build Coastguard Worker     buffered_visitor.VisitRoot(root);
360*795d594fSAndroid Build Coastguard Worker   }
361*795d594fSAndroid Build Coastguard Worker }
362*795d594fSAndroid Build Coastguard Worker 
363*795d594fSAndroid Build Coastguard Worker }  // namespace art
364