Wire up hprof.

I tested this with test 074-gc-thrash, which creates a .hprof file
that can be read with hat.

Change-Id: Ie75b7a7cf3c2ee32189df47ab0129e99449ebc6c
diff --git a/src/dalvik_system_VMDebug.cc b/src/dalvik_system_VMDebug.cc
index 3c728f7..7461fc4 100644
--- a/src/dalvik_system_VMDebug.cc
+++ b/src/dalvik_system_VMDebug.cc
@@ -17,6 +17,7 @@
 #include "class_linker.h"
 #include "debugger.h"
 #include "jni_internal.h"
+#include "hprof/hprof.h"
 #include "ScopedUtfChars.h"
 #include "toStringArray.h"
 
@@ -196,8 +197,7 @@
     }
   }
 
-  UNIMPLEMENTED(WARNING);
-  int result = 0; //hprofDumpHeap(filename.c_str(), fd, false);
+  int result = hprof::hprofDumpHeap(filename.c_str(), fd, false);
   if (result != 0) {
     // TODO: ideally we'd throw something more specific based on actual failure
     jniThrowException(env, "Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details");
@@ -207,7 +207,7 @@
 
 void VMDebug_dumpHprofDataDdms(JNIEnv* env, jclass) {
   UNIMPLEMENTED(WARNING);
-  int result = 0; //hprofDumpHeap("[DDMS]", -1, true);
+  int result = hprof::hprofDumpHeap("[DDMS]", -1, true);
   if (result != 0) {
     // TODO: ideally we'd throw something more specific based on actual failure
     jniThrowException(env, "Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details");
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc
index 9415549..a7047ac 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -269,6 +269,7 @@
 
     CHECK(fileName != NULL);
     ScopedHeapLock lock;
+    ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
 
     ThreadList* thread_list = Runtime::Current()->GetThreadList();
     thread_list->SuspendAll();
diff --git a/src/hprof/hprof_class.cc b/src/hprof/hprof_class.cc
index 2e40ad4..e601e91 100644
--- a/src/hprof/hprof_class.cc
+++ b/src/hprof/hprof_class.cc
@@ -40,7 +40,7 @@
 }
 
 static int getPrettyClassNameId(Class* clazz) {
-    return hprofLookupStringId(PrettyClass(clazz));
+    return hprofLookupStringId(PrettyDescriptor(clazz->GetDescriptor()));
 }
 
 hprof_class_object_id hprofLookupClassId(Class* clazz) {
@@ -63,6 +63,7 @@
      */
     getPrettyClassNameId(clazz);
 
+    CHECK(present == clazz);
     return (hprof_string_id) present;
 }
 
diff --git a/src/hprof/hprof_heap.cc b/src/hprof/hprof_heap.cc
index 9545f7c..571167d 100644
--- a/src/hprof/hprof_heap.cc
+++ b/src/hprof/hprof_heap.cc
@@ -305,6 +305,8 @@
                 // aren't all the same size. But they're at least this
                 // size.
                 hprofAddU4ToRecord(rec, sizeof(Class)); // instance size
+            } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) {
+                hprofAddU4ToRecord(rec, 0);
             } else {
                 hprofAddU4ToRecord(rec, thisClass->GetObjectSize()); // instance size
             }
@@ -346,7 +348,7 @@
 
             /* Instance fields for this class (no superclass fields)
              */
-            int iFieldCount = thisClass->NumInstanceFields();
+            int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields();
             hprofAddU2ToRecord(rec, (uint16_t)iFieldCount);
             for (int i = 0; i < iFieldCount; ++i) {
                 Field* f = thisClass->GetInstanceField(i);
@@ -413,8 +415,6 @@
 #endif
             }
         } else {
-            const Class* sclass;
-            size_t sizePatchOffset, savedLen;
 
             /* obj is an instance object.
              */
@@ -427,14 +427,15 @@
              * data, which we won't know until we're done writing
              * it.
              */
-            sizePatchOffset = rec->length;
+            size_t sizePatchOffset = rec->length;
             hprofAddU4ToRecord(rec, 0x77777777);
 
             /* Write the instance data;  fields for this
              * class, followed by super class fields, and so on.
+             * Don't write the klass or monitor fields of Object.class.
              */
-            sclass = clazz;
-            while (sclass != NULL) {
+            const Class* sclass = clazz;
+            while (!sclass->IsObjectClass()) {
                 int ifieldCount = sclass->NumInstanceFields();
                 for (int i = 0; i < ifieldCount; i++) {
                     Field* f = sclass->GetInstanceField(i);
@@ -459,7 +460,7 @@
 
             /* Patch the instance field length.
              */
-            savedLen = rec->length;
+            size_t savedLen = rec->length;
             rec->length = sizePatchOffset;
             hprofAddU4ToRecord(rec, savedLen - (sizePatchOffset + 4));
             rec->length = savedLen;
diff --git a/src/hprof/hprof_string.cc b/src/hprof/hprof_string.cc
index f498b6d..bc1caf2 100644
--- a/src/hprof/hprof_string.cc
+++ b/src/hprof/hprof_string.cc
@@ -25,7 +25,7 @@
 
 namespace hprof {
 
-size_t next_string_id_ = 200001;
+size_t next_string_id_ = 0x400000;
 typedef std::tr1::unordered_map<std::string, size_t> StringMap;
 typedef std::tr1::unordered_map<std::string, size_t>::iterator StringMapIterator;
 static Mutex strings_lock_("hprof strings");
@@ -60,7 +60,7 @@
 
     hprof_record_t *rec = &ctx->curRec;
 
-    for (StringMapIterator   it = strings_.begin(); it != strings_.end(); ++it) {
+    for (StringMapIterator it = strings_.begin(); it != strings_.end(); ++it) {
         std::string string = (*it).first;
         size_t id = (*it).second;
 
diff --git a/src/object.h b/src/object.h
index 6610871..dd2c1ca 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1504,10 +1504,10 @@
   }
 
   size_t GetObjectSize() const {
-    CHECK(!IsVariableSize());
+    CHECK(!IsVariableSize()) << " class=" << PrettyTypeOf(this);
     DCHECK_EQ(sizeof(size_t), sizeof(int32_t));
     size_t result = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), false);
-    CHECK_GE(result, sizeof(Object));
+    CHECK_GE(result, sizeof(Object)) << " class=" << PrettyTypeOf(this);
     return result;
   }