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;