Improve reference table dumping.
1. Show the newest entry first; I always assume the top is the newest.
2. Use human-readable type names.
3. Improve the human-readable type name code to show _which_ Class (i.e.
java.lang.Class<java.lang.String> rather than just java.lang.Class).
4. Make it clear when we're reporting the number of elements in an array.
5. Show the first few characters of a string.
6. Show the length of a string if we truncate it.
(I've also removed some redundant casts and improved const-correctness.)
Example:
Last 10 entries in JNI local reference table:
16: 0x40f8ec70 java.lang.String "android.permissi... (41 chars)
15: 0x40f8d450 android.os.Parcel
14: 0x40f8eb90 java.lang.String "BlackSurface"
13: 0x408caca0 android.view.SurfaceSession
12: 0x40f8eb60 android.view.Surface
11: 0x406bc6f0 java.lang.Class<com.android.server.SystemServer>
10: 0x406c0278 java.lang.String "com/android/serv... (31 chars)
9: 0x4015d488 dalvik.system.PathClassLoader
8: 0x40148de8 java.lang.Class<java.lang.ClassLoader>
7: 0x406bc560 java.lang.String[]
JNI local reference table summary (17 entries):
6 of java.lang.Class<com.android.server.SystemServer> (5 unique instances)
5 of java.lang.String (5 unique instances)
1 of java.lang.String[]
1 of java.lang.String[] (2 elements)
1 of dalvik.system.PathClassLoader
1 of android.os.Parcel
1 of android.view.SurfaceSession
1 of android.view.Surface
Change-Id: I56494104cd0daada3ecc1e610f1c94df1e11c640
diff --git a/vm/Misc.cpp b/vm/Misc.cpp
index 3b1179e..3cbd563 100644
--- a/vm/Misc.cpp
+++ b/vm/Misc.cpp
@@ -266,6 +266,23 @@
return result;
}
+std::string dvmHumanReadableType(const Object* obj)
+{
+ if (obj == NULL) {
+ return "(null)";
+ }
+ if (obj->clazz == NULL) {
+ /* should only be possible right after a plain dvmMalloc() */
+ return "(raw)";
+ }
+ std::string result(dvmHumanReadableDescriptor(obj->clazz->descriptor));
+ if (dvmIsClassObject(obj)) {
+ const ClassObject* clazz = reinterpret_cast<const ClassObject*>(obj);
+ result += "<" + dvmHumanReadableDescriptor(clazz->descriptor) + ">";
+ }
+ return result;
+}
+
/*
* Return a newly-allocated string for the "dot version" of the class
* name for the given type descriptor. That is, The initial "L" and
diff --git a/vm/Misc.h b/vm/Misc.h
index 8d7aa4c..f861c6c 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -147,6 +147,14 @@
*/
std::string dvmHumanReadableDescriptor(const char* descriptor);
+/**
+ * Returns a human-readable string form of the name of the class of
+ * the given object. So given a java.lang.String, the output would
+ * be "java.lang.String". Given an array of int, the output would be "int[]".
+ * Given String.class, the output would be "java.lang.Class<java.lang.String>".
+ */
+std::string dvmHumanReadableType(const Object* obj);
+
/*
* Return a newly-allocated string for the "dot version" of the class
* name for the given type descriptor. That is, The initial "L" and
diff --git a/vm/ReferenceTable.cpp b/vm/ReferenceTable.cpp
index 764093f..1438bdc 100644
--- a/vm/ReferenceTable.cpp
+++ b/vm/ReferenceTable.cpp
@@ -209,24 +209,23 @@
return;
}
- /* handle "raw" dvmMalloc case */
- const char* descriptor =
- (obj->clazz != NULL) ? obj->clazz->descriptor : "(raw)";
-
- char elemStr[16];
-
- if (elems != 0) {
- snprintf(elemStr, sizeof(elemStr), " [%zd]", elems);
+ std::string className;
+ if (obj->clazz == NULL) {
+ /* handle "raw" dvmMalloc case */
+ className = "(raw)";
} else {
- elemStr[0] = '\0';
+ className = dvmHumanReadableType(obj);
+ if (elems != 0) {
+ className += dvmStringPrintf(" (%zd elements)", elems);
+ }
}
+ size_t total = identical + equiv + 1;
+ std::string msg(dvmStringPrintf("%5d of %s", total, className.c_str()));
if (identical + equiv != 0) {
- LOGW("%5d of %s%s (%d unique)", identical + equiv +1,
- descriptor, elemStr, equiv +1);
- } else {
- LOGW("%5d of %s%s", identical + equiv +1, descriptor, elemStr);
+ msg += dvmStringPrintf(" (%d unique instances)", equiv + 1);
}
+ LOGW("%s", msg.c_str());
}
/*
@@ -248,32 +247,47 @@
*/
const size_t kLast = 10;
LOGW("Last %d entries in %s reference table:", kLast, descr);
- int start = count - kLast;
- if (start < 0)
- start = 0;
+ int first = count - kLast;
+ if (first < 0) {
+ first = 0;
+ }
- size_t idx, elems;
- for (idx = start; idx < count; idx++) {
+ 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->clazz == NULL) {
/* should only be possible right after a plain dvmMalloc() */
size_t size = dvmObjectSizeInHeap(ref);
- LOGW("%5d: %p cls=(raw) (%zd bytes)", idx, ref, size);
- } else if (dvmIsClassObject(ref)) {
- ClassObject* clazz = (ClassObject*) ref;
- LOGW("%5d: %p cls=%s '%s'", idx, ref, ref->clazz->descriptor,
- clazz->descriptor);
- } else if (elems != 0) {
- LOGW("%5d: %p cls=%s [%zd]",
- idx, ref, ref->clazz->descriptor, elems);
- } else {
- LOGW("%5d: %p cls=%s", idx, ref, ref->clazz->descriptor);
+ LOGW("%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) {
+ extras += dvmStringPrintf(" (%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 {
+ extras += dvmStringPrintf("... (%d chars)", dvmStringLen(str));
+ }
+ free(s);
+ }
+ LOGW("%5d: %p %s%s", idx, ref, className.c_str(), extras.c_str());
}
/*
@@ -307,6 +321,8 @@
LOGW("%s reference table summary (%d entries):", descr, count);
size_t equiv, identical;
equiv = identical = 0;
+ size_t idx;
+ size_t elems;
for (idx = 1; idx < count; idx++) {
elems = getElementCount(refs[idx-1]);
diff --git a/vm/UtfString.cpp b/vm/UtfString.cpp
index 5666507..05bac53 100644
--- a/vm/UtfString.cpp
+++ b/vm/UtfString.cpp
@@ -211,8 +211,8 @@
}
int len = dvmGetFieldInt(strObj, STRING_FIELDOFF_COUNT);
int offset = dvmGetFieldInt(strObj, STRING_FIELDOFF_OFFSET);
- ArrayObject* chars = (ArrayObject*) dvmGetFieldObject(strObj,
- STRING_FIELDOFF_VALUE);
+ ArrayObject* chars =
+ (ArrayObject*) dvmGetFieldObject(strObj, STRING_FIELDOFF_VALUE);
hashCode = computeUtf16Hash((u2*)(void*)chars->contents + offset, len);
dvmSetFieldInt(strObj, STRING_FIELDOFF_HASHCODE, hashCode);
return hashCode;
@@ -281,29 +281,25 @@
*
* Returns NULL if the object is NULL.
*/
-char* dvmCreateCstrFromString(StringObject* jstr)
+char* dvmCreateCstrFromString(const StringObject* jstr)
{
- char* newStr;
- ArrayObject* chars;
- int len, byteLen, offset;
- const u2* data;
-
assert(gDvm.classJavaLangString != NULL);
-
- if (jstr == NULL)
+ if (jstr == NULL) {
return NULL;
+ }
- len = dvmGetFieldInt((Object*) jstr, STRING_FIELDOFF_COUNT);
- offset = dvmGetFieldInt((Object*) jstr, STRING_FIELDOFF_OFFSET);
- chars = (ArrayObject*) dvmGetFieldObject((Object*) jstr,
- STRING_FIELDOFF_VALUE);
- data = (const u2*)(void*)chars->contents + offset;
+ int len = dvmGetFieldInt(jstr, STRING_FIELDOFF_COUNT);
+ int offset = dvmGetFieldInt(jstr, STRING_FIELDOFF_OFFSET);
+ ArrayObject* chars =
+ (ArrayObject*) dvmGetFieldObject(jstr, STRING_FIELDOFF_VALUE);
+ const u2* data = (const u2*)(void*)chars->contents + offset;
assert(offset + len <= (int) chars->length);
- byteLen = utf16_utf8ByteLen(data, len);
- newStr = (char*) malloc(byteLen+1);
- if (newStr == NULL)
+ int byteLen = utf16_utf8ByteLen(data, len);
+ char* newStr = (char*) malloc(byteLen+1);
+ if (newStr == NULL) {
return NULL;
+ }
convertUtf16ToUtf8(newStr, data, len);
return newStr;
@@ -313,12 +309,10 @@
* Create a UTF-8 C string from a region of a java/lang/String. (Used by
* the JNI GetStringUTFRegion call.)
*/
-void dvmCreateCstrFromStringRegion(StringObject* jstr, int start, int len,
- char* buf)
+void dvmCreateCstrFromStringRegion(const StringObject* jstr,
+ int start, int len, char* buf)
{
- const u2* data;
-
- data = dvmStringChars(jstr) + start;
+ const u2* data = dvmStringChars(jstr) + start;
convertUtf16ToUtf8(buf, data, len);
}
@@ -327,22 +321,18 @@
*
* Does not include the terminating null byte.
*/
-int dvmStringUtf8ByteLen(StringObject* jstr)
+int dvmStringUtf8ByteLen(const StringObject* jstr)
{
- ArrayObject* chars;
- int len, offset;
- const u2* data;
-
assert(gDvm.classJavaLangString != NULL);
-
- if (jstr == NULL)
+ if (jstr == NULL) {
return 0; // should we throw something? assert?
+ }
- len = dvmGetFieldInt((Object*) jstr, STRING_FIELDOFF_COUNT);
- offset = dvmGetFieldInt((Object*) jstr, STRING_FIELDOFF_OFFSET);
- chars = (ArrayObject*) dvmGetFieldObject((Object*) jstr,
- STRING_FIELDOFF_VALUE);
- data = (const u2*)(void*)chars->contents + offset;
+ int len = dvmGetFieldInt(jstr, STRING_FIELDOFF_COUNT);
+ int offset = dvmGetFieldInt(jstr, STRING_FIELDOFF_OFFSET);
+ ArrayObject* chars =
+ (ArrayObject*) dvmGetFieldObject(jstr, STRING_FIELDOFF_VALUE);
+ const u2* data = (const u2*)(void*)chars->contents + offset;
assert(offset + len <= (int) chars->length);
return utf16_utf8ByteLen(data, len);
@@ -351,31 +341,27 @@
/*
* Get the string's length.
*/
-int dvmStringLen(StringObject* jstr)
+int dvmStringLen(const StringObject* jstr)
{
- return dvmGetFieldInt((Object*) jstr, STRING_FIELDOFF_COUNT);
+ return dvmGetFieldInt(jstr, STRING_FIELDOFF_COUNT);
}
/*
* Get the char[] object from the String.
*/
-ArrayObject* dvmStringCharArray(StringObject* jstr)
+ArrayObject* dvmStringCharArray(const StringObject* jstr)
{
- return (ArrayObject*) dvmGetFieldObject((Object*) jstr,
- STRING_FIELDOFF_VALUE);
+ return (ArrayObject*) dvmGetFieldObject(jstr, STRING_FIELDOFF_VALUE);
}
/*
* Get the string's data.
*/
-const u2* dvmStringChars(StringObject* jstr)
+const u2* dvmStringChars(const StringObject* jstr)
{
- ArrayObject* chars;
- int offset;
-
- offset = dvmGetFieldInt((Object*) jstr, STRING_FIELDOFF_OFFSET);
- chars = (ArrayObject*) dvmGetFieldObject((Object*) jstr,
- STRING_FIELDOFF_VALUE);
+ int offset = dvmGetFieldInt(jstr, STRING_FIELDOFF_OFFSET);
+ ArrayObject* chars =
+ (ArrayObject*) dvmGetFieldObject(jstr, STRING_FIELDOFF_VALUE);
return (const u2*)(void*)chars->contents + offset;
}
@@ -391,24 +377,22 @@
{
const StringObject* strObj1 = (const StringObject*) vstrObj1;
const StringObject* strObj2 = (const StringObject*) vstrObj2;
- ArrayObject* chars1;
- ArrayObject* chars2;
- int len1, len2, offset1, offset2;
assert(gDvm.classJavaLangString != NULL);
/* get offset and length into char array; all values are in 16-bit units */
- len1 = dvmGetFieldInt((Object*) strObj1, STRING_FIELDOFF_COUNT);
- offset1 = dvmGetFieldInt((Object*) strObj1, STRING_FIELDOFF_OFFSET);
- len2 = dvmGetFieldInt((Object*) strObj2, STRING_FIELDOFF_COUNT);
- offset2 = dvmGetFieldInt((Object*) strObj2, STRING_FIELDOFF_OFFSET);
- if (len1 != len2)
+ int len1 = dvmGetFieldInt(strObj1, STRING_FIELDOFF_COUNT);
+ int offset1 = dvmGetFieldInt(strObj1, STRING_FIELDOFF_OFFSET);
+ int len2 = dvmGetFieldInt(strObj2, STRING_FIELDOFF_COUNT);
+ int offset2 = dvmGetFieldInt(strObj2, STRING_FIELDOFF_OFFSET);
+ if (len1 != len2) {
return len1 - len2;
+ }
- chars1 = (ArrayObject*) dvmGetFieldObject((Object*) strObj1,
- STRING_FIELDOFF_VALUE);
- chars2 = (ArrayObject*) dvmGetFieldObject((Object*) strObj2,
- STRING_FIELDOFF_VALUE);
+ ArrayObject* chars1 =
+ (ArrayObject*) dvmGetFieldObject(strObj1, STRING_FIELDOFF_VALUE);
+ ArrayObject* chars2 =
+ (ArrayObject*) dvmGetFieldObject(strObj2, STRING_FIELDOFF_VALUE);
/* damage here actually indicates a broken java/lang/String */
assert(offset1 + len1 <= (int) chars1->length);
diff --git a/vm/UtfString.h b/vm/UtfString.h
index 13832df..b236ce5 100644
--- a/vm/UtfString.h
+++ b/vm/UtfString.h
@@ -123,35 +123,35 @@
*
* Returns NULL if "jstr" is NULL.
*/
-char* dvmCreateCstrFromString(StringObject* jstr);
+char* dvmCreateCstrFromString(const StringObject* jstr);
/*
* Create a UTF-8 C string from a region of a java/lang/String. (Used by
* the JNI GetStringUTFRegion call.)
*/
-void dvmCreateCstrFromStringRegion(StringObject* jstr, int start, int len,
- char* buf);
+void dvmCreateCstrFromStringRegion(const StringObject* jstr,
+ int start, int len, char* buf);
/*
* Compute the length in bytes of the modified UTF-8 representation of a
* string.
*/
-int dvmStringUtf8ByteLen(StringObject* jstr);
+int dvmStringUtf8ByteLen(const StringObject* jstr);
/*
* Get the length in Unicode characters of a string.
*/
-int dvmStringLen(StringObject* jstr);
+int dvmStringLen(const StringObject* jstr);
/*
* Get the char[] object from the String.
*/
-ArrayObject* dvmStringCharArray(StringObject* jstr);
+ArrayObject* dvmStringCharArray(const StringObject* jstr);
/*
* Get a pointer to the Unicode data.
*/
-const u2* dvmStringChars(StringObject* jstr);
+const u2* dvmStringChars(const StringObject* jstr);
/*
* Compare two string objects. (This is a dvmHashTableLookup() callback.)
diff --git a/vm/interp/Stack.cpp b/vm/interp/Stack.cpp
index 3c0d9da..98c209b 100644
--- a/vm/interp/Stack.cpp
+++ b/vm/interp/Stack.cpp
@@ -637,7 +637,7 @@
std::string expectedClassName(dvmHumanReadableDescriptor(expected->descriptor));
std::string actualClassName;
if (arg != NULL) {
- actualClassName = dvmHumanReadableDescriptor(arg->clazz->descriptor);
+ actualClassName = dvmHumanReadableType(arg);
} else {
actualClassName = "null";
}
@@ -1163,11 +1163,8 @@
if (obj->clazz != gDvm.classJavaLangClass) {
// I(16573) - waiting on <0xf5feda38> (a java.util.LinkedList)
- msg += "(a " + dvmHumanReadableDescriptor(obj->clazz->descriptor) + ")";
- } else {
- // I(16573) - waiting on <0xf5ed54f8> (java.lang.Class<java.lang.ref.ReferenceQueue>)
- ClassObject* clazz = reinterpret_cast<ClassObject*>(obj);
- msg += "(java.lang.Class<" + dvmHumanReadableDescriptor(clazz->descriptor) + ">)";
+ // I(16573) - waiting on <0xf5ed54f8> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
+ msg += "(a " + dvmHumanReadableType(obj) + ")";
}
if (thread != NULL) {
diff --git a/vm/native/InternalNative.cpp b/vm/native/InternalNative.cpp
index 708deab..7ba1a64 100644
--- a/vm/native/InternalNative.cpp
+++ b/vm/native/InternalNative.cpp
@@ -165,12 +165,7 @@
}
std::string expectedClassName(dvmHumanReadableDescriptor(clazz->descriptor));
- std::string actualClassName;
- if (obj != NULL) {
- actualClassName = dvmHumanReadableDescriptor(obj->clazz->descriptor);
- } else {
- actualClassName = "null";
- }
+ std::string actualClassName(dvmHumanReadableType(obj));
dvmThrowExceptionFmt(exceptionClass, "expected receiver of type %s, but got %s",
expectedClassName.c_str(), actualClassName.c_str());
return false;