*/
bool dvmAddToReferenceTable(ReferenceTable* pRef, Object* obj)
{
- assert(dvmIsValidObject(obj));
assert(obj != NULL);
+ assert(dvmIsHeapAddress(obj));
assert(pRef->table != NULL);
assert(pRef->allocEntries <= pRef->maxEntries);
if (pRef->nextEntry == pRef->table + pRef->allocEntries) {
/* reached end of allocated space; did we hit buffer max? */
if (pRef->nextEntry == pRef->table + pRef->maxEntries) {
- LOGW("ReferenceTable overflow (max=%d)\n", pRef->maxEntries);
+ ALOGW("ReferenceTable overflow (max=%d)", pRef->maxEntries);
return false;
}
newTable = (Object**) realloc(pRef->table, newSize * sizeof(Object*));
if (newTable == NULL) {
- LOGE("Unable to expand ref table (from %d to %d %d-byte entries)\n",
+ ALOGE("Unable to expand ref table (from %d to %d %d-byte entries)",
pRef->allocEntries, newSize, sizeof(Object*));
return false;
}
- LOGVV("Growing %p from %d to %d\n", pRef, pRef->allocEntries, newSize);
+ LOGVV("Growing %p from %d to %d", pRef, pRef->allocEntries, newSize);
/* update entries; adjust "nextEntry" in case memory moved */
pRef->nextEntry = newTable + (pRef->nextEntry - pRef->table);
if (moveCount != 0) {
/* remove from middle, slide the rest down */
memmove(ptr, ptr+1, moveCount * sizeof(Object*));
- //LOGV("LREF delete %p, shift %d down\n", obj, moveCount);
+ //ALOGV("LREF delete %p, shift %d down", obj, moveCount);
} else {
/* last entry, falls off the end */
- //LOGV("LREF delete %p from end\n", obj);
+ //ALOGV("LREF delete %p from end", obj);
}
return true;
static size_t getElementCount(const Object* obj)
{
const ArrayObject* arrayObj = (ArrayObject*) obj;
- if (arrayObj == NULL || arrayObj->clazz == NULL || !dvmIsArray(arrayObj))
+ if (arrayObj == NULL || arrayObj == kClearedJniWeakGlobal ||
+ arrayObj->clazz == NULL || !dvmIsArray(arrayObj)) {
return 0;
+ }
return arrayObj->length;
}
const Object* obj1 = *((Object* const*) vobj1);
const Object* obj2 = *((Object* const*) vobj2);
- /* ensure null references appear at the end */
+ // Ensure null references and cleared jweaks appear at the end.
if (obj1 == NULL) {
if (obj2 == NULL) {
return 0;
} else if (obj2 == NULL) {
return -1;
}
+ if (obj1 == kClearedJniWeakGlobal) {
+ if (obj2 == kClearedJniWeakGlobal) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else if (obj2 == kClearedJniWeakGlobal) {
+ return -1;
+ }
if (obj1->clazz != obj2->clazz) {
return (u1*)obj1->clazz - (u1*)obj2->clazz;
* array object), and the number of additional objects that are identical
* or equivalent to the original.
*/
-static void logObject(const Object* obj, size_t elems, int identical, int equiv)
+static void logSummaryLine(const Object* obj, size_t elems, int identical, int equiv)
{
if (obj == NULL) {
- LOGW(" NULL reference (count=%d)\n", equiv);
+ ALOGW(" NULL reference (count=%d)", equiv);
+ return;
+ }
+ if (obj == kClearedJniWeakGlobal) {
+ ALOGW(" cleared jweak (count=%d)", equiv);
return;
}
- /* handle "raw" dvmMalloc case */
- const char* descriptor =
- (obj->clazz != NULL) ? obj->clazz->descriptor : "(raw)";
-
- char elemStr[16];
-
+ std::string className(dvmHumanReadableType(obj));
+ if (obj->clazz == gDvm.classJavaLangClass) {
+ // We're summarizing multiple instances, so using the exemplar
+ // Class' type parameter here would be misleading.
+ className = "java.lang.Class";
+ }
if (elems != 0) {
- snprintf(elemStr, sizeof(elemStr), " [%zd]", elems);
- } else {
- elemStr[0] = '\0';
+ StringAppendF(&className, " (%zd elements)", elems);
}
+ size_t total = identical + equiv + 1;
+ std::string msg(StringPrintf("%5d of %s", total, className.c_str()));
if (identical + equiv != 0) {
- LOGW("%5d of %s%s (%d unique)\n", identical + equiv +1,
- descriptor, elemStr, equiv +1);
- } else {
- LOGW("%5d of %s%s\n", identical + equiv +1, descriptor, elemStr);
+ StringAppendF(&msg, " (%d unique instances)", equiv + 1);
}
+ ALOGW(" %s", msg.c_str());
}
/*
void dvmDumpReferenceTableContents(Object* const* refs, size_t count,
const char* descr)
{
+ ALOGW("%s reference table (%p) dump:", descr, refs);
+
if (count == 0) {
- LOGW("%s reference table has no entries\n", descr);
+ ALOGW(" (empty)");
return;
}
- /*
- * Dump the most recent N entries.
- */
+ // Dump the most recent N entries.
const size_t kLast = 10;
- LOGW("Last %d entries in %s reference table:\n", kLast, descr);
- int start = count - kLast;
- if (start < 0)
- start = 0;
-
- size_t idx, elems;
- for (idx = start; idx < count; idx++) {
+ int first = count - kLast;
+ if (first < 0) {
+ first = 0;
+ }
+ ALOGW(" Last %d entries (of %d):", (count - first), count);
+ for (int idx = count - 1; idx >= first; --idx) {
const Object* ref = refs[idx];
- if (ref == NULL)
+ if (ref == NULL) {
continue;
-
- elems = getElementCount(ref);
-
+ }
+ if (ref == kClearedJniWeakGlobal) {
+ ALOGW(" %5d: cleared jweak", idx);
+ continue;
+ }
if (ref->clazz == NULL) {
- /* should only be possible right after a plain dvmMalloc() */
+ // should only be possible right after a plain dvmMalloc().
size_t size = dvmObjectSizeInHeap(ref);
- LOGW("%5d: %p cls=(raw) (%zd bytes)\n", idx, ref, size);
- } else if (dvmIsClassObject(ref)) {
- ClassObject* clazz = (ClassObject*) ref;
- LOGW("%5d: %p cls=%s '%s'\n", idx, ref, ref->clazz->descriptor,
- clazz->descriptor);
- } else if (elems != 0) {
- LOGW("%5d: %p cls=%s [%zd]\n",
- idx, ref, ref->clazz->descriptor, elems);
- } else {
- LOGW("%5d: %p cls=%s\n", idx, ref, ref->clazz->descriptor);
+ ALOGW(" %5d: %p (raw) (%zd bytes)", idx, ref, size);
+ continue;
}
+
+ std::string className(dvmHumanReadableType(ref));
+
+ std::string extras;
+ size_t elems = getElementCount(ref);
+ if (elems != 0) {
+ StringAppendF(&extras, " (%zd elements)", elems);
+ } else if (ref->clazz == gDvm.classJavaLangString) {
+ const StringObject* str =
+ reinterpret_cast<const StringObject*>(ref);
+ extras += " \"";
+ size_t count = 0;
+ char* s = dvmCreateCstrFromString(str);
+ char* p = s;
+ for (; *p && count < 16; ++p, ++count) {
+ extras += *p;
+ }
+ if (*p == 0) {
+ extras += "\"";
+ } else {
+ StringAppendF(&extras, "... (%d chars)", str->length());
+ }
+ free(s);
+ }
+ ALOGW(" %5d: %p %s%s", idx, ref, className.c_str(), extras.c_str());
}
- /*
- * Make a copy of the table, and sort it.
- */
+ // Make a copy of the table, and sort it.
Object** tableCopy = (Object**)malloc(sizeof(Object*) * count);
if (tableCopy == NULL) {
- LOGE("Unable to copy table with %d elements\n", count);
+ ALOGE("Unable to copy table with %d elements", count);
return;
}
memcpy(tableCopy, refs, sizeof(Object*) * count);
qsort(tableCopy, count, sizeof(Object*), compareObject);
refs = tableCopy; // use sorted list
- /*
- * Find and remove any "holes" in the list. The sort moved them all
- * to the end.
- *
- * A table with nothing but NULL entries should have count==0, which
- * was handled above, so this operation should not leave us with an
- * empty list.
- */
- while (refs[count-1] == NULL) {
- count--;
+ // Remove any uninteresting stuff from the list. The sort moved them all to the end.
+ while (count > 0 && refs[count-1] == NULL) {
+ --count;
+ }
+ while (count > 0 && refs[count-1] == kClearedJniWeakGlobal) {
+ --count;
+ }
+ if (count == 0) {
+ return;
}
- assert(count > 0);
- /*
- * Dump uniquified table summary.
- */
- LOGW("%s reference table summary (%d entries):\n", descr, count);
+ // Dump a summary of the whole table.
+ ALOGW(" Summary:");
size_t equiv, identical;
equiv = identical = 0;
+ size_t idx;
+ size_t elems;
for (idx = 1; idx < count; idx++) {
elems = getElementCount(refs[idx-1]);
if (refs[idx] == refs[idx-1]) {
- /* same reference, added more than once */
+ // same reference, added more than once.
identical++;
} else if (refs[idx]->clazz == refs[idx-1]->clazz &&
getElementCount(refs[idx]) == elems)
{
- /* same class / element count, different object */
+ // same class / element count, different object.
equiv++;
} else {
- /* different class */
- logObject(refs[idx-1], elems, identical, equiv);
+ // different class.
+ logSummaryLine(refs[idx-1], elems, identical, equiv);
equiv = identical = 0;
}
}
- /* handle the last entry (everything above outputs refs[i-1]) */
+ // Handle the last entry (everything above outputs refs[i-1]).
elems = getElementCount(refs[idx-1]);
- logObject(refs[count-1], elems, identical, equiv);
+ logSummaryLine(refs[count-1], elems, identical, equiv);
free(tableCopy);
}