Add a reference table dump call.

This adds a hidden method to android.os.Debug that causes the contents
of various reference tables to be dumped.  Currently it's the local,
global, and pinned array tables from JNI.

Bug 2075355
diff --git a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
index 365388a..f9411ca 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -284,10 +284,18 @@
     public static native boolean cacheRegisterMap(String classAndMethodDesc);
 
     /**
-     * Crashes the VM.  Seriously.  Dumps the stack trace for the current
-     * thread and then aborts the VM so you can see the native stack trace.
-     * Useful for figuring out how you got somewhere when lots of native
-     * code is involved.
+     * Dumps the contents of the VM reference tables (e.g. JNI locals and
+     * globals) to the log file.
+     *
+     * @hide
+     */
+    public static native void dumpReferenceTables();
+
+    /**
+     * Crashes the VM.  Seriously.  Dumps the interpreter stack trace for
+     * the current thread and then aborts the VM so you can see the native
+     * stack trace.  Useful for figuring out how you got somewhere when
+     * lots of native code is involved.
      *
      * @hide
      */
diff --git a/vm/Jni.c b/vm/Jni.c
index 54a1f45..1dcea10 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -1123,6 +1123,27 @@
 }
 
 /*
+ * Dump the contents of the JNI reference tables to the log file.
+ *
+ * We only dump the local refs associated with the current thread.
+ */
+void dvmDumpJniReferenceTables(void)
+{
+    Thread* self = dvmThreadSelf();
+    JNIEnv* env = self->jniEnv;
+    ReferenceTable* pLocalRefs = getLocalRefTable(env);
+
+#ifdef USE_INDIRECT_REF
+    dvmDumpIndirectRefTable(pLocalRefs, "JNI local");
+    dvmDumpIndirectRefTable(&gDvm.jniGlobalRefTable, "JNI global");
+#else
+    dvmDumpReferenceTable(pLocalRefs, "JNI local");
+    dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
+#endif
+    dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
+}
+
+/*
  * GC helper function to mark all JNI global references.
  *
  * We're currently handling the "pin" table here too.
diff --git a/vm/JniInternal.h b/vm/JniInternal.h
index 3c15ce4..302dcb0 100644
--- a/vm/JniInternal.h
+++ b/vm/JniInternal.h
@@ -201,6 +201,12 @@
  */
 void dvmReleaseJniMonitors(Thread* self);
 
+/*
+ * Dump the contents of the JNI reference tables to the log file.
+ *
+ * The local ref tables associated with other threads are not included.
+ */
+void dvmDumpJniReferenceTables(void);
 
 /*
  * This mask is applied to weak global reference values returned to
diff --git a/vm/ReferenceTable.c b/vm/ReferenceTable.c
index a8010a2..b47d775 100644
--- a/vm/ReferenceTable.c
+++ b/vm/ReferenceTable.c
@@ -213,7 +213,7 @@
     int i;
 
     if (count == 0) {
-        LOGW("Reference table has no entries\n");
+        LOGW("%s reference table has no entries\n", descr);
         return;
     }
     assert(count > 0);
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index 8aa371d..c2439a3 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -699,6 +699,23 @@
 }
 
 /*
+ * static void dumpReferenceTables()
+ */
+static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
+    JValue* pResult)
+{
+    UNUSED_PARAMETER(args);
+    UNUSED_PARAMETER(pResult);
+
+    LOGI("--- reference table dump ---\n");
+    dvmDumpJniReferenceTables();
+    // could dump thread's internalLocalRefTable, probably not useful
+    // ditto for thread's jniMonitorRefTable
+    LOGI("---\n");
+    RETURN_VOID();
+}
+
+/*
  * static void crash()
  *
  * Dump the current thread's interpreted stack and abort the VM.  Useful
@@ -765,6 +782,8 @@
         Dalvik_dalvik_system_VMDebug_dumpHprofData },
     { "cacheRegisterMap",           "(Ljava/lang/String;)Z",
         Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
+    { "dumpReferenceTables",        "()V",
+        Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
     { "crash",                      "()V",
         Dalvik_dalvik_system_VMDebug_crash },
     { NULL, NULL, NULL },