blob: b5c988aaa53399f7c3d6885998bb24435e97a0ef [file] [log] [blame]
Elliott Hughes11e45072011-08-16 17:40:46 -07001/*
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
Elliott Hughes6c1a3942011-08-17 15:00:06 -070019#include "indirect_reference_table.h"
20
Elliott Hughes11e45072011-08-16 17:40:46 -070021#include "object.h"
22
23namespace art {
24
25ReferenceTable::ReferenceTable(const char* name,
26 size_t initial_size, size_t max_size)
27 : name_(name), max_size_(max_size) {
28 CHECK_LE(initial_size, max_size);
29 entries_.reserve(initial_size);
30}
31
Elliott Hughes75770752011-08-24 17:52:38 -070032void ReferenceTable::Add(const Object* obj) {
Elliott Hughes11e45072011-08-16 17:40:46 -070033 DCHECK(obj != NULL);
34 if (entries_.size() == max_size_) {
35 LOG(FATAL) << "ReferenceTable '" << name_ << "' "
36 << "overflowed (" << max_size_ << " entries)";
37 }
38 entries_.push_back(obj);
39}
40
Elliott Hughes75770752011-08-24 17:52:38 -070041void ReferenceTable::Remove(const Object* obj) {
Elliott Hughes11e45072011-08-16 17:40:46 -070042 // We iterate backwards on the assumption that references are LIFO.
43 for (int i = entries_.size() - 1; i >= 0; --i) {
44 if (entries_[i] == obj) {
45 entries_.erase(entries_.begin() + i);
46 return;
47 }
48 }
49}
50
Carl Shapiro5b1982d2011-08-16 18:35:19 -070051// If "obj" is an array, return the number of elements in the array.
52// Otherwise, return zero.
Elliott Hughes11e45072011-08-16 17:40:46 -070053size_t GetElementCount(const Object* obj) {
54 if (obj == NULL || obj == kClearedJniWeakGlobal || !obj->IsArray()) {
55 return 0;
56 }
57 return obj->AsArray()->GetLength();
58}
59
60struct ObjectComparator {
Elliott Hughes75770752011-08-24 17:52:38 -070061 bool operator()(const Object* obj1, const Object* obj2){
Elliott Hughes11e45072011-08-16 17:40:46 -070062 // Ensure null references and cleared jweaks appear at the end.
63 if (obj1 == NULL) {
64 return true;
65 } else if (obj2 == NULL) {
66 return false;
67 }
68 if (obj1 == kClearedJniWeakGlobal) {
69 return true;
70 } else if (obj2 == kClearedJniWeakGlobal) {
71 return false;
72 }
73
74 // Sort by class...
75 if (obj1->GetClass() != obj2->GetClass()) {
76 return reinterpret_cast<uintptr_t>(obj1->GetClass()) <
77 reinterpret_cast<uintptr_t>(obj2->GetClass());
78 } else {
79 // ...then by size...
80 size_t count1 = obj1->SizeOf();
81 size_t count2 = obj2->SizeOf();
82 if (count1 != count2) {
83 return count1 < count2;
84 } else {
85 // ...and finally by address.
86 return reinterpret_cast<uintptr_t>(obj1) <
87 reinterpret_cast<uintptr_t>(obj2);
88 }
89 }
90 }
91};
92
Carl Shapiro5b1982d2011-08-16 18:35:19 -070093// Log an object with some additional info.
94//
95// Pass in the number of elements in the array (or 0 if this is not an
96// array object), and the number of additional objects that are identical
97// or equivalent to the original.
Elliott Hughes11e45072011-08-16 17:40:46 -070098void LogSummaryLine(const Object* obj, size_t elems, int identical, int equiv) {
99 if (obj == NULL) {
100 LOG(WARNING) << " NULL reference (count=" << equiv << ")";
101 return;
102 }
103 if (obj == kClearedJniWeakGlobal) {
104 LOG(WARNING) << " cleared jweak (count=" << equiv << ")";
105 return;
106 }
107
108 std::string className(PrettyType(obj));
109 if (obj->IsClass()) {
110 // We're summarizing multiple instances, so using the exemplar
111 // Class' type parameter here would be misleading.
112 className = "java.lang.Class";
113 }
114 if (elems != 0) {
115 StringAppendF(&className, " (%zd elements)", elems);
116 }
117
118 size_t total = identical + equiv + 1;
119 std::string msg(StringPrintf("%5d of %s", total, className.c_str()));
120 if (identical + equiv != 0) {
121 StringAppendF(&msg, " (%d unique instances)", equiv + 1);
122 }
123 LOG(WARNING) << " " << msg;
124}
125
126size_t ReferenceTable::Size() const {
127 return entries_.size();
128}
129
Elliott Hughes11e45072011-08-16 17:40:46 -0700130void ReferenceTable::Dump() const {
131 LOG(WARNING) << name_ << " reference table dump:";
Elliott Hughes6c1a3942011-08-17 15:00:06 -0700132 Dump(entries_);
133}
Elliott Hughes11e45072011-08-16 17:40:46 -0700134
Elliott Hughes75770752011-08-24 17:52:38 -0700135void ReferenceTable::Dump(const std::vector<const Object*>& entries) {
Elliott Hughes6c1a3942011-08-17 15:00:06 -0700136 if (entries.empty()) {
Elliott Hughes11e45072011-08-16 17:40:46 -0700137 LOG(WARNING) << " (empty)";
138 return;
139 }
140
141 // Dump the most recent N entries.
142 const size_t kLast = 10;
Elliott Hughes6c1a3942011-08-17 15:00:06 -0700143 size_t count = entries.size();
Elliott Hughes11e45072011-08-16 17:40:46 -0700144 int first = count - kLast;
145 if (first < 0) {
146 first = 0;
147 }
148 LOG(WARNING) << " Last " << (count - first) << " entries (of " << count << "):";
149 for (int idx = count - 1; idx >= first; --idx) {
Elliott Hughes6c1a3942011-08-17 15:00:06 -0700150 const Object* ref = entries[idx];
Elliott Hughes11e45072011-08-16 17:40:46 -0700151 if (ref == NULL) {
152 continue;
153 }
154 if (ref == kClearedJniWeakGlobal) {
155 LOG(WARNING) << StringPrintf(" %5d: cleared jweak", idx);
156 continue;
157 }
158 if (ref->GetClass() == NULL) {
159 // should only be possible right after a plain dvmMalloc().
160 size_t size = ref->SizeOf();
161 LOG(WARNING) << StringPrintf(" %5d: %p (raw) (%zd bytes)", idx, ref, size);
162 continue;
163 }
164
165 std::string className(PrettyType(ref));
166
167 std::string extras;
168 size_t elems = GetElementCount(ref);
169 if (elems != 0) {
170 StringAppendF(&extras, " (%zd elements)", elems);
171 }
172#if 0
173 // TODO: support dumping string data.
174 else if (ref->GetClass() == gDvm.classJavaLangString) {
175 const StringObject* str = reinterpret_cast<const StringObject*>(ref);
176 extras += " \"";
177 size_t count = 0;
178 char* s = dvmCreateCstrFromString(str);
179 char* p = s;
180 for (; *p && count < 16; ++p, ++count) {
181 extras += *p;
182 }
183 if (*p == 0) {
184 extras += "\"";
185 } else {
186 StringAppendF(&extras, "... (%d chars)", str->length());
187 }
188 free(s);
189 }
190#endif
191 LOG(WARNING) << StringPrintf(" %5d: ", idx) << ref << " " << className << extras;
192 }
193
194 // Make a copy of the table and sort it.
Elliott Hughes75770752011-08-24 17:52:38 -0700195 std::vector<const Object*> sorted_entries(entries.begin(), entries.end());
Elliott Hughes11e45072011-08-16 17:40:46 -0700196 std::sort(sorted_entries.begin(), sorted_entries.end(), ObjectComparator());
197
198 // Remove any uninteresting stuff from the list. The sort moved them all to the end.
199 while (!sorted_entries.empty() && sorted_entries.back() == NULL) {
200 sorted_entries.pop_back();
201 }
202 while (!sorted_entries.empty() && sorted_entries.back() == kClearedJniWeakGlobal) {
203 sorted_entries.pop_back();
204 }
205 if (sorted_entries.empty()) {
206 return;
207 }
208
209 // Dump a summary of the whole table.
210 LOG(WARNING) << " Summary:";
211 size_t equiv = 0;
212 size_t identical = 0;
213 for (size_t idx = 1; idx < count; idx++) {
Elliott Hughes75770752011-08-24 17:52:38 -0700214 const Object* prev = sorted_entries[idx-1];
215 const Object* current = sorted_entries[idx];
Elliott Hughes11e45072011-08-16 17:40:46 -0700216 size_t elems = GetElementCount(prev);
217 if (current == prev) {
218 // Same reference, added more than once.
219 identical++;
220 } else if (current->GetClass() == prev->GetClass() && GetElementCount(current) == elems) {
221 // Same class / element count, different object.
222 equiv++;
223 } else {
224 // Different class.
225 LogSummaryLine(prev, elems, identical, equiv);
226 equiv = identical = 0;
227 }
228 }
229 // Handle the last entry.
230 LogSummaryLine(sorted_entries.back(), GetElementCount(sorted_entries.back()), identical, equiv);
231}
232
233} // namespace art