Clean up the hprof implementation a bit.

Change-Id: I9e6622cd5ec10fe8af6553f72095bf3dee00afdd
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 064aa52..c99f93f 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -150,7 +150,6 @@
 	src/heap.cc \
 	src/heap_bitmap.cc \
 	src/hprof/hprof.cc \
-	src/hprof/hprof_record.cc \
 	src/image.cc \
 	src/image_writer.cc \
 	src/indirect_reference_table.cc \
diff --git a/src/hprof/hprof.cc b/src/hprof/hprof.cc
index 02f80c1..03e3a6c 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -24,46 +24,364 @@
 
 #include "hprof.h"
 
+#include <cutils/open_memstream.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <set>
+
 #include "class_linker.h"
 #include "debugger.h"
+#include "file.h"
+#include "globals.h"
 #include "heap.h"
 #include "logging.h"
 #include "object.h"
 #include "object_utils.h"
+#include "safe_map.h"
 #include "scoped_heap_lock.h"
 #include "stringprintf.h"
-
-#include <cutils/open_memstream.h>
-#include <sys/uio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <time.h>
+#include "thread_list.h"
 
 namespace art {
 
 namespace hprof {
 
-#define HPROF_MAGIC_STRING  "JAVA PROFILE 1.0.3"
+#define UNIQUE_ERROR -((((uintptr_t)__func__) << 16 | __LINE__) & (0x7fffffff))
 
-/*
- * Initialize an Hprof.
- */
-Hprof::Hprof(const char* outputFileName, int fd, bool writeHeader, bool directToDdms)
+#define HPROF_TIME 0
+#define HPROF_NULL_STACK_TRACE   0
+#define HPROF_NULL_THREAD        0
+
+#define U2_TO_BUF_BE(buf, offset, value) \
+    do { \
+      unsigned char* buf_ = (unsigned char*)(buf); \
+      int offset_ = (int)(offset); \
+      uint16_t value_ = (uint16_t)(value); \
+      buf_[offset_ + 0] = (unsigned char)(value_ >>  8); \
+      buf_[offset_ + 1] = (unsigned char)(value_      ); \
+    } while (0)
+
+#define U4_TO_BUF_BE(buf, offset, value) \
+    do { \
+      unsigned char* buf_ = (unsigned char*)(buf); \
+      int offset_ = (int)(offset); \
+      uint32_t value_ = (uint32_t)(value); \
+      buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \
+      buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \
+      buf_[offset_ + 2] = (unsigned char)(value_ >>  8); \
+      buf_[offset_ + 3] = (unsigned char)(value_      ); \
+    } while (0)
+
+#define U8_TO_BUF_BE(buf, offset, value) \
+    do { \
+      unsigned char* buf_ = (unsigned char*)(buf); \
+      int offset_ = (int)(offset); \
+      uint64_t value_ = (uint64_t)(value); \
+      buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \
+      buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \
+      buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \
+      buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \
+      buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \
+      buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \
+      buf_[offset_ + 6] = (unsigned char)(value_ >>  8); \
+      buf_[offset_ + 7] = (unsigned char)(value_      ); \
+    } while (0)
+
+enum HprofTag {
+  HPROF_TAG_STRING = 0x01,
+  HPROF_TAG_LOAD_CLASS = 0x02,
+  HPROF_TAG_UNLOAD_CLASS = 0x03,
+  HPROF_TAG_STACK_FRAME = 0x04,
+  HPROF_TAG_STACK_TRACE = 0x05,
+  HPROF_TAG_ALLOC_SITES = 0x06,
+  HPROF_TAG_HEAP_SUMMARY = 0x07,
+  HPROF_TAG_START_THREAD = 0x0A,
+  HPROF_TAG_END_THREAD = 0x0B,
+  HPROF_TAG_HEAP_DUMP = 0x0C,
+  HPROF_TAG_HEAP_DUMP_SEGMENT = 0x1C,
+  HPROF_TAG_HEAP_DUMP_END = 0x2C,
+  HPROF_TAG_CPU_SAMPLES = 0x0D,
+  HPROF_TAG_CONTROL_SETTINGS = 0x0E,
+};
+
+// Values for the first byte of HEAP_DUMP and HEAP_DUMP_SEGMENT records:
+enum HprofHeapTag {
+  // Traditional.
+  HPROF_ROOT_UNKNOWN = 0xFF,
+  HPROF_ROOT_JNI_GLOBAL = 0x01,
+  HPROF_ROOT_JNI_LOCAL = 0x02,
+  HPROF_ROOT_JAVA_FRAME = 0x03,
+  HPROF_ROOT_NATIVE_STACK = 0x04,
+  HPROF_ROOT_STICKY_CLASS = 0x05,
+  HPROF_ROOT_THREAD_BLOCK = 0x06,
+  HPROF_ROOT_MONITOR_USED = 0x07,
+  HPROF_ROOT_THREAD_OBJECT = 0x08,
+  HPROF_CLASS_DUMP = 0x20,
+  HPROF_INSTANCE_DUMP = 0x21,
+  HPROF_OBJECT_ARRAY_DUMP = 0x22,
+  HPROF_PRIMITIVE_ARRAY_DUMP = 0x23,
+
+  // Android.
+  HPROF_HEAP_DUMP_INFO = 0xfe,
+  HPROF_ROOT_INTERNED_STRING = 0x89,
+  HPROF_ROOT_FINALIZING = 0x8a,  // Obsolete.
+  HPROF_ROOT_DEBUGGER = 0x8b,
+  HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,  // Obsolete.
+  HPROF_ROOT_VM_INTERNAL = 0x8d,
+  HPROF_ROOT_JNI_MONITOR = 0x8e,
+  HPROF_UNREACHABLE = 0x90,  // Obsolete.
+  HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3,
+};
+
+enum HprofHeapId {
+  HPROF_HEAP_DEFAULT = 0,
+  HPROF_HEAP_ZYGOTE = 'Z',
+  HPROF_HEAP_APP = 'A'
+};
+
+enum HprofBasicType {
+  hprof_basic_object = 2,
+  hprof_basic_boolean = 4,
+  hprof_basic_char = 5,
+  hprof_basic_float = 6,
+  hprof_basic_double = 7,
+  hprof_basic_byte = 8,
+  hprof_basic_short = 9,
+  hprof_basic_int = 10,
+  hprof_basic_long = 11,
+};
+
+typedef uint32_t HprofId;
+typedef HprofId HprofStringId;
+typedef HprofId HprofObjectId;
+typedef HprofId HprofClassObjectId;
+typedef std::set<Class*> ClassSet;
+typedef std::set<Class*>::iterator ClassSetIterator;
+typedef SafeMap<std::string, size_t> StringMap;
+typedef SafeMap<std::string, size_t>::iterator StringMapIterator;
+
+// Represents a top-level hprof record, whose serialized format is:
+// U1  TAG: denoting the type of the record
+// U4  TIME: number of microseconds since the time stamp in the header
+// U4  LENGTH: number of bytes that follow this uint32_t field and belong to this record
+// U1* BODY: as many bytes as specified in the above uint32_t field
+class HprofRecord {
+ public:
+  int Flush(FILE* fp) {
+    if (dirty_) {
+      unsigned char headBuf[sizeof (uint8_t) + 2 * sizeof (uint32_t)];
+
+      headBuf[0] = tag_;
+      U4_TO_BUF_BE(headBuf, 1, time_);
+      U4_TO_BUF_BE(headBuf, 5, length_);
+
+      int nb = fwrite(headBuf, 1, sizeof(headBuf), fp);
+      if (nb != sizeof(headBuf)) {
+        return UNIQUE_ERROR;
+      }
+      nb = fwrite(body_, 1, length_, fp);
+      if (nb != (int)length_) {
+        return UNIQUE_ERROR;
+      }
+
+      dirty_ = false;
+    }
+    // TODO if we used less than half (or whatever) of allocLen, shrink the buffer.
+    return 0;
+  }
+
+  int AddU1(uint8_t value) {
+    int err = GuaranteeRecordAppend(1);
+    if (err != 0) {
+      return err;
+    }
+
+    body_[length_++] = value;
+    return 0;
+  }
+
+  int AddU2(uint16_t value) {
+    return AddU2List(&value, 1);
+  }
+
+  int AddU4(uint32_t value) {
+    return AddU4List(&value, 1);
+  }
+
+  int AddU8(uint64_t value) {
+    return AddU8List(&value, 1);
+  }
+
+  int AddId(HprofObjectId value) {
+    return AddU4((uint32_t) value);
+  }
+
+  int AddU1List(const uint8_t *values, size_t numValues) {
+    int err = GuaranteeRecordAppend(numValues);
+    if (err != 0) {
+      return err;
+    }
+
+    memcpy(body_ + length_, values, numValues);
+    length_ += numValues;
+    return 0;
+  }
+
+  int AddU2List(const uint16_t *values, size_t numValues) {
+    int err = GuaranteeRecordAppend(numValues * 2);
+    if (err != 0) {
+      return err;
+    }
+
+    unsigned char* insert = body_ + length_;
+    for (size_t i = 0; i < numValues; i++) {
+      U2_TO_BUF_BE(insert, 0, *values++);
+      insert += sizeof(*values);
+    }
+    length_ += numValues * 2;
+    return 0;
+  }
+
+  int AddU4List(const uint32_t *values, size_t numValues) {
+    int err = GuaranteeRecordAppend(numValues * 4);
+    if (err != 0) {
+      return err;
+    }
+
+    unsigned char* insert = body_ + length_;
+    for (size_t i = 0; i < numValues; i++) {
+      U4_TO_BUF_BE(insert, 0, *values++);
+      insert += sizeof(*values);
+    }
+    length_ += numValues * 4;
+    return 0;
+  }
+
+  int AddU8List(const uint64_t *values, size_t numValues) {
+    int err = GuaranteeRecordAppend(numValues * 8);
+    if (err != 0) {
+      return err;
+    }
+
+    unsigned char* insert = body_ + length_;
+    for (size_t i = 0; i < numValues; i++) {
+      U8_TO_BUF_BE(insert, 0, *values++);
+      insert += sizeof(*values);
+    }
+    length_ += numValues * 8;
+    return 0;
+  }
+
+  int AddIdList(const HprofObjectId *values, size_t numValues) {
+    return AddU4List((const uint32_t*) values, numValues);
+  }
+
+  int AddUtf8String(const char* str) {
+    // The terminating NUL character is NOT written.
+    return AddU1List((const uint8_t *)str, strlen(str));
+  }
+
+  unsigned char* body_;
+  uint32_t time_;
+  uint32_t length_;
+  size_t alloc_length_;
+  uint8_t tag_;
+  bool dirty_;
+
+ private:
+  int GuaranteeRecordAppend(size_t nmore) {
+    size_t minSize = length_ + nmore;
+    if (minSize > alloc_length_) {
+      size_t newAllocLen = alloc_length_ * 2;
+      if (newAllocLen < minSize) {
+        newAllocLen = alloc_length_ + nmore + nmore/2;
+      }
+      unsigned char* newBody = (unsigned char*)realloc(body_, newAllocLen);
+      if (newBody != NULL) {
+        body_ = newBody;
+        alloc_length_ = newAllocLen;
+      } else {
+        // TODO: set an error flag so future ops will fail
+        return UNIQUE_ERROR;
+      }
+    }
+
+    CHECK_LE(length_ + nmore, alloc_length_);
+    return 0;
+  }
+};
+
+class Hprof {
+ public:
+  Hprof(const char* output_filename, int fd, bool write_header, bool direct_to_ddms);
+  ~Hprof();
+
+  void VisitRoot(const Object* obj);
+  int DumpHeapObject(const Object *obj);
+  void Finish();
+
+ private:
+  int DumpClasses();
+  int DumpStrings();
+  int StartNewRecord(uint8_t tag, uint32_t time);
+  int FlushCurrentRecord();
+  int MarkRootObject(const Object *obj, jobject jniObj);
+  HprofClassObjectId LookupClassId(Class* c);
+  HprofStringId LookupStringId(String* string);
+  HprofStringId LookupStringId(const char* string);
+  HprofStringId LookupStringId(const std::string& string);
+  HprofStringId LookupClassNameId(Class* c);
+
+  // current_record_ *must* be first so that we can cast from a context to a record.
+  HprofRecord current_record_;
+
+  uint32_t gc_thread_serial_number_;
+  uint8_t gc_scan_state_;
+  HprofHeapId current_heap_; // which heap we're currently emitting
+  size_t objects_in_segment_;
+
+  // If direct_to_ddms_ is set, "file_name_" and "fd" will be ignored.
+  // Otherwise, "file_name_" must be valid, though if "fd" >= 0 it will
+  // only be used for debug messages.
+  bool direct_to_ddms_;
+  std::string file_name_;
+  char* file_data_ptr_;   // for open_memstream
+  size_t file_data_size_; // for open_memstream
+  FILE *mem_fp_;
+  int fd_;
+
+  ClassSet classes_;
+  size_t next_string_id_;
+  StringMap strings_;
+
+  DISALLOW_COPY_AND_ASSIGN(Hprof);
+};
+
+Hprof::Hprof(const char* output_filename, int fd, bool write_header, bool direct_to_ddms)
     : current_record_(),
       gc_thread_serial_number_(0),
       gc_scan_state_(0),
       current_heap_(HPROF_HEAP_DEFAULT),
       objects_in_segment_(0),
       direct_to_ddms_(0),
-      file_name_(outputFileName),
+      file_name_(output_filename),
       file_data_ptr_(NULL),
       file_data_size_(0),
       mem_fp_(NULL),
       fd_(0),
       next_string_id_(0x400000) {
+
+  LOG(INFO) << "hprof: heap dump starting (\"" << output_filename << "\", fd=" << fd
+            << ", write_header=" << write_header << ", direct_to_ddms=" << direct_to_ddms << ")";
+
   // Have to do this here, because it must happen after we
   // memset the struct (want to treat file_data_ptr_/file_data_size_
   // as read-only while the file is open).
@@ -73,7 +391,7 @@
     PLOG(FATAL) << "open_memstream failed";
   }
 
-  direct_to_ddms_ = directToDdms;
+  direct_to_ddms_ = direct_to_ddms;
   mem_fp_ = fp;
   fd_ = fd;
 
@@ -81,8 +399,8 @@
   current_record_.body_ = (unsigned char*)malloc(current_record_.alloc_length_);
   // TODO check for/return an error
 
-  if (writeHeader) {
-    char magic[] = HPROF_MAGIC_STRING;
+  if (write_header) {
+    char magic[] = "JAVA PROFILE 1.0.3";
     unsigned char buf[4];
 
     // Write the file header.
@@ -119,7 +437,7 @@
   if (err != 0) {
     return err;
   } else if (rec->dirty_) {
-    return UNIQUE_ERROR();
+    return UNIQUE_ERROR;
   }
 
   rec->dirty_ = true;
@@ -147,7 +465,7 @@
 // The ID for the synthetic object generated to account for class static overhead.
 #define CLASS_STATICS_ID(c) ((HprofObjectId)(((uint32_t)(c)) | 1))
 
-HprofBasicType Hprof::SignatureToBasicTypeAndSize(const char* sig, size_t* sizeOut) {
+static HprofBasicType SignatureToBasicTypeAndSize(const char* sig, size_t* sizeOut) {
   char c = sig[0];
   HprofBasicType ret;
   size_t size;
@@ -173,7 +491,7 @@
   return ret;
 }
 
-HprofBasicType Hprof::PrimitiveToBasicTypeAndSize(Primitive::Type prim, size_t *sizeOut) {
+static HprofBasicType PrimitiveToBasicTypeAndSize(Primitive::Type prim, size_t *sizeOut) {
   HprofBasicType ret;
   size_t size;
 
@@ -285,7 +603,7 @@
   return 0;
 }
 
-int Hprof::StackTraceSerialNumber(const void* /*obj*/) {
+static int StackTraceSerialNumber(const void* /*obj*/) {
   return HPROF_NULL_STACK_TRACE;
 }
 
@@ -531,10 +849,7 @@
   return 0;
 }
 
-/*
- * Finish up the hprof dump.  Returns true on success.
- */
-bool Hprof::Finish() {
+void Hprof::Finish() {
   // flush the "tail" portion of the output
   StartNewRecord(HPROF_TAG_HEAP_DUMP_END, HPROF_TIME);
   FlushCurrentRecord();
@@ -544,7 +859,6 @@
   headCtx.classes_ = classes_;
   headCtx.strings_ = strings_;
 
-  LOG(INFO) << StringPrintf("hprof: dumping heap strings to \"%s\".", file_name_.c_str());
   headCtx.DumpStrings();
   headCtx.DumpClasses();
 
@@ -576,33 +890,30 @@
     if (headCtx.fd_ >= 0) {
       outFd = dup(headCtx.fd_);
       if (outFd < 0) {
-        PLOG(ERROR) << StringPrintf("dup(%d) failed", headCtx.fd_);
-        // continue to fail-handler below
+        Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Couldn't dump heap; dup(%d) failed: %s", headCtx.fd_, strerror(errno));
+        return;
       }
     } else {
       outFd = open(file_name_.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0644);
       if (outFd < 0) {
-        PLOG(ERROR) << StringPrintf("can't open \"%s\"", headCtx.file_name_.c_str());
-        // continue to fail-handler below
+        Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Couldn't dump heap; open(\"%s\") failed: %s", headCtx.file_name_.c_str(), strerror(errno));
+        return;
       }
     }
-    if (outFd < 0) {
-      return false;
-    }
 
-    int result = sysWriteFully(outFd, headCtx.file_data_ptr_,
-        headCtx.file_data_size_, "hprof-head");
+    // TODO: just use writev(2)?
+    int result = sysWriteFully(outFd, headCtx.file_data_ptr_, headCtx.file_data_size_, "hprof-head");
     result |= sysWriteFully(outFd, file_data_ptr_, file_data_size_, "hprof-tail");
     close(outFd);
     if (result != 0) {
-      return false;
+      // TODO: better detail message.
+      Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Couldn't dump heap; check log output for details");
+      return;
     }
   }
 
   // throw out a log message for the benefit of "runhat"
   LOG(INFO) << "hprof: heap dump completed (" << PrettySize(headCtx.file_data_size_ + file_data_size_ + 1023) << ")";
-
-  return true;
 }
 
 Hprof::~Hprof() {
@@ -741,13 +1052,13 @@
   return 0;
 }
 
-void HprofRootVisitor(const Object* obj, void* arg) {
+static void HprofRootVisitor(const Object* obj, void* arg) {
   CHECK(arg != NULL);
   Hprof* hprof = (Hprof*)arg;
   hprof->VisitRoot(obj);
 }
 
-void HprofBitmapCallback(Object *obj, void *arg) {
+static void HprofBitmapCallback(Object *obj, void *arg) {
   CHECK(obj != NULL);
   CHECK(arg != NULL);
   Hprof *hprof = (Hprof*)arg;
@@ -763,10 +1074,8 @@
  *
  * If "direct_to_ddms_" is set, the other arguments are ignored, and data is
  * sent directly to DDMS.
- *
- * Returns 0 on success, or an error code on failure.
  */
-int DumpHeap(const char* fileName, int fd, bool directToDdms) {
+void DumpHeap(const char* fileName, int fd, bool direct_to_ddms) {
   CHECK(fileName != NULL);
   ScopedHeapLock heap_lock;
   ScopedThreadStateChange tsc(Thread::Current(), kRunnable);
@@ -775,13 +1084,12 @@
   thread_list->SuspendAll();
 
   Runtime* runtime = Runtime::Current();
-  Hprof hprof(fileName, fd, false, directToDdms);
+  Hprof hprof(fileName, fd, false, direct_to_ddms);
   runtime->VisitRoots(HprofRootVisitor, &hprof);
   runtime->GetHeap()->GetLiveBits()->Walk(HprofBitmapCallback, &hprof);
   // TODO: write a HEAP_SUMMARY record
-  int success = hprof.Finish() ? 0 : -1;
+  hprof.Finish();
   thread_list->ResumeAll();
-  return success;
 }
 
 }  // namespace hprof
diff --git a/src/hprof/hprof.h b/src/hprof/hprof.h
index e2f7ce1..c6222dc 100644
--- a/src/hprof/hprof.h
+++ b/src/hprof/hprof.h
@@ -13,219 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 #ifndef HPROF_HPROF_H_
 #define HPROF_HPROF_H_
 
-#include <stdio.h>
-
-#include <set>
-
-#include "file.h"
-#include "globals.h"
-#include "object.h"
-#include "safe_map.h"
-#include "thread_list.h"
-
 namespace art {
 
 namespace hprof {
 
-#define HPROF_ID_SIZE (sizeof (uint32_t))
-
-#define UNIQUE_ERROR() \
-    -((((uintptr_t)__func__) << 16 | __LINE__) & (0x7fffffff))
-
-#define HPROF_TIME 0
-#define HPROF_NULL_STACK_TRACE   0
-#define HPROF_NULL_THREAD        0
-
-#define U2_TO_BUF_BE(buf, offset, value) \
-    do { \
-        unsigned char* buf_ = (unsigned char*)(buf); \
-        int offset_ = (int)(offset); \
-        uint16_t value_ = (uint16_t)(value); \
-        buf_[offset_ + 0] = (unsigned char)(value_ >>  8); \
-        buf_[offset_ + 1] = (unsigned char)(value_      ); \
-    } while (0)
-
-#define U4_TO_BUF_BE(buf, offset, value) \
-    do { \
-        unsigned char* buf_ = (unsigned char*)(buf); \
-        int offset_ = (int)(offset); \
-        uint32_t value_ = (uint32_t)(value); \
-        buf_[offset_ + 0] = (unsigned char)(value_ >> 24); \
-        buf_[offset_ + 1] = (unsigned char)(value_ >> 16); \
-        buf_[offset_ + 2] = (unsigned char)(value_ >>  8); \
-        buf_[offset_ + 3] = (unsigned char)(value_      ); \
-    } while (0)
-
-#define U8_TO_BUF_BE(buf, offset, value) \
-    do { \
-        unsigned char* buf_ = (unsigned char*)(buf); \
-        int offset_ = (int)(offset); \
-        uint64_t value_ = (uint64_t)(value); \
-        buf_[offset_ + 0] = (unsigned char)(value_ >> 56); \
-        buf_[offset_ + 1] = (unsigned char)(value_ >> 48); \
-        buf_[offset_ + 2] = (unsigned char)(value_ >> 40); \
-        buf_[offset_ + 3] = (unsigned char)(value_ >> 32); \
-        buf_[offset_ + 4] = (unsigned char)(value_ >> 24); \
-        buf_[offset_ + 5] = (unsigned char)(value_ >> 16); \
-        buf_[offset_ + 6] = (unsigned char)(value_ >>  8); \
-        buf_[offset_ + 7] = (unsigned char)(value_      ); \
-    } while (0)
-
-typedef uint32_t HprofId;
-typedef HprofId HprofStringId;
-typedef HprofId HprofObjectId;
-typedef HprofId HprofClassObjectId;
-typedef std::set<Class*> ClassSet;
-typedef std::set<Class*>::iterator ClassSetIterator;
-typedef SafeMap<std::string, size_t> StringMap;
-typedef SafeMap<std::string, size_t>::iterator StringMapIterator;
-
-enum HprofBasicType {
-  hprof_basic_object = 2,
-  hprof_basic_boolean = 4,
-  hprof_basic_char = 5,
-  hprof_basic_float = 6,
-  hprof_basic_double = 7,
-  hprof_basic_byte = 8,
-  hprof_basic_short = 9,
-  hprof_basic_int = 10,
-  hprof_basic_long = 11,
-};
-
-enum HprofTag {
-  HPROF_TAG_STRING = 0x01,
-  HPROF_TAG_LOAD_CLASS = 0x02,
-  HPROF_TAG_UNLOAD_CLASS = 0x03,
-  HPROF_TAG_STACK_FRAME = 0x04,
-  HPROF_TAG_STACK_TRACE = 0x05,
-  HPROF_TAG_ALLOC_SITES = 0x06,
-  HPROF_TAG_HEAP_SUMMARY = 0x07,
-  HPROF_TAG_START_THREAD = 0x0A,
-  HPROF_TAG_END_THREAD = 0x0B,
-  HPROF_TAG_HEAP_DUMP = 0x0C,
-  HPROF_TAG_HEAP_DUMP_SEGMENT = 0x1C,
-  HPROF_TAG_HEAP_DUMP_END = 0x2C,
-  HPROF_TAG_CPU_SAMPLES = 0x0D,
-  HPROF_TAG_CONTROL_SETTINGS = 0x0E,
-};
-
-// Values for the first byte of HEAP_DUMP and HEAP_DUMP_SEGMENT records:
-enum HprofHeapTag {
-  /* standard */
-  HPROF_ROOT_UNKNOWN = 0xFF,
-  HPROF_ROOT_JNI_GLOBAL = 0x01,
-  HPROF_ROOT_JNI_LOCAL = 0x02,
-  HPROF_ROOT_JAVA_FRAME = 0x03,
-  HPROF_ROOT_NATIVE_STACK = 0x04,
-  HPROF_ROOT_STICKY_CLASS = 0x05,
-  HPROF_ROOT_THREAD_BLOCK = 0x06,
-  HPROF_ROOT_MONITOR_USED = 0x07,
-  HPROF_ROOT_THREAD_OBJECT = 0x08,
-  HPROF_CLASS_DUMP = 0x20,
-  HPROF_INSTANCE_DUMP = 0x21,
-  HPROF_OBJECT_ARRAY_DUMP = 0x22,
-  HPROF_PRIMITIVE_ARRAY_DUMP = 0x23,
-
-  /* Android */
-  HPROF_HEAP_DUMP_INFO = 0xfe,
-  HPROF_ROOT_INTERNED_STRING = 0x89,
-  HPROF_ROOT_FINALIZING = 0x8a,  /* obsolete */
-  HPROF_ROOT_DEBUGGER = 0x8b,
-  HPROF_ROOT_REFERENCE_CLEANUP = 0x8c,  /* obsolete */
-  HPROF_ROOT_VM_INTERNAL = 0x8d,
-  HPROF_ROOT_JNI_MONITOR = 0x8e,
-  HPROF_UNREACHABLE = 0x90,  /* obsolete */
-  HPROF_PRIMITIVE_ARRAY_NODATA_DUMP = 0xc3,
-};
-
-// Represents a top-level hprof record, whose serialized format is:
-// U1  TAG: denoting the type of the record
-// U4  TIME: number of microseconds since the time stamp in the header
-// U4  LENGTH: number of bytes that follow this uint32_t field and belong to this record
-// U1* BODY: as many bytes as specified in the above uint32_t field
-class HprofRecord {
- public:
-  int Flush(FILE *fp);
-  int AddU1(uint8_t value);
-  int AddU2(uint16_t value);
-  int AddU4(uint32_t value);
-  int AddU8(uint64_t value);
-  int AddId(HprofObjectId value);
-  int AddU1List(const uint8_t *values, size_t numValues);
-  int AddU2List(const uint16_t *values, size_t numValues);
-  int AddU4List(const uint32_t *values, size_t numValues);
-  int AddU8List(const uint64_t *values, size_t numValues);
-  int AddIdList(const HprofObjectId *values, size_t numValues);
-  int AddUtf8String(const char* str);
-
-  unsigned char* body_;
-  uint32_t time_;
-  uint32_t length_;
-  size_t alloc_length_;
-  uint8_t tag_;
-  bool dirty_;
-
- private:
-  int GuaranteeRecordAppend(size_t nmore);
-};
-
-enum HprofHeapId {
-  HPROF_HEAP_DEFAULT = 0,
-  HPROF_HEAP_ZYGOTE = 'Z',
-  HPROF_HEAP_APP = 'A'
-};
-
-class Hprof {
- public:
-  Hprof(const char* outputFileName, int fd, bool writeHeader, bool directToDdms);
-  ~Hprof();
-
-  void VisitRoot(const Object* obj);
-  int DumpHeapObject(const Object *obj);
-  bool Finish();
-
- private:
-  int DumpClasses();
-  int DumpStrings();
-  int StartNewRecord(uint8_t tag, uint32_t time);
-  int FlushCurrentRecord();
-  int MarkRootObject(const Object *obj, jobject jniObj);
-  HprofClassObjectId LookupClassId(Class* c);
-  HprofStringId LookupStringId(String* string);
-  HprofStringId LookupStringId(const char* string);
-  HprofStringId LookupStringId(const std::string& string);
-  HprofStringId LookupClassNameId(Class* c);
-  static HprofBasicType SignatureToBasicTypeAndSize(const char* sig, size_t* sizeOut);
-  static HprofBasicType PrimitiveToBasicTypeAndSize(Primitive::Type prim, size_t* sizeOut);
-  static int StackTraceSerialNumber(const void *obj);
-
-  // current_record_ *must* be first so that we can cast from a context to a record.
-  HprofRecord current_record_;
-
-  uint32_t gc_thread_serial_number_;
-  uint8_t gc_scan_state_;
-  HprofHeapId current_heap_; // which heap we're currently emitting
-  size_t objects_in_segment_;
-
-  // If direct_to_ddms_ is set, "file_name_" and "fd" will be ignored.
-  // Otherwise, "file_name_" must be valid, though if "fd" >= 0 it will
-  // only be used for debug messages.
-  bool direct_to_ddms_;
-  std::string file_name_;
-  char* file_data_ptr_;   // for open_memstream
-  size_t file_data_size_; // for open_memstream
-  FILE *mem_fp_;
-  int fd_;
-
-  ClassSet classes_;
-  size_t next_string_id_;
-  StringMap strings_;
-};
-
-int DumpHeap(const char* fileName, int fd, bool directToDdms);
+void DumpHeap(const char* filename, int fd, bool direct_to_ddms);
 
 }  // namespace hprof
 
diff --git a/src/hprof/hprof_record.cc b/src/hprof/hprof_record.cc
deleted file mode 100644
index ad4b43c..0000000
--- a/src/hprof/hprof_record.cc
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#include <sys/time.h>
-#include <time.h>
-#include <errno.h>
-#include <stdio.h>
-#include "hprof.h"
-#include "stringprintf.h"
-#include "logging.h"
-
-namespace art {
-
-namespace hprof {
-
-int HprofRecord::Flush(FILE *fp) {
-  if (dirty_) {
-    unsigned char headBuf[sizeof (uint8_t) + 2 * sizeof (uint32_t)];
-
-    headBuf[0] = tag_;
-    U4_TO_BUF_BE(headBuf, 1, time_);
-    U4_TO_BUF_BE(headBuf, 5, length_);
-
-    int nb = fwrite(headBuf, 1, sizeof(headBuf), fp);
-    if (nb != sizeof(headBuf)) {
-      return UNIQUE_ERROR();
-    }
-    nb = fwrite(body_, 1, length_, fp);
-    if (nb != (int)length_) {
-      return UNIQUE_ERROR();
-    }
-
-    dirty_ = false;
-  }
-  // TODO if we used less than half (or whatever) of allocLen, shrink the buffer.
-  return 0;
-}
-
-int HprofRecord::GuaranteeRecordAppend(size_t nmore) {
-  size_t minSize = length_ + nmore;
-  if (minSize > alloc_length_) {
-    size_t newAllocLen = alloc_length_ * 2;
-    if (newAllocLen < minSize) {
-      newAllocLen = alloc_length_ + nmore + nmore/2;
-    }
-    unsigned char* newBody = (unsigned char*)realloc(body_, newAllocLen);
-    if (newBody != NULL) {
-      body_ = newBody;
-      alloc_length_ = newAllocLen;
-    } else {
-      // TODO: set an error flag so future ops will fail
-      return UNIQUE_ERROR();
-    }
-  }
-
-  CHECK_LE(length_ + nmore, alloc_length_);
-  return 0;
-}
-
-int HprofRecord::AddU1List(const uint8_t *values, size_t numValues) {
-  int err = GuaranteeRecordAppend(numValues);
-  if (err != 0) {
-    return err;
-  }
-
-  memcpy(body_ + length_, values, numValues);
-  length_ += numValues;
-  return 0;
-}
-
-int HprofRecord::AddU1(uint8_t value) {
-  int err = GuaranteeRecordAppend(1);
-  if (err != 0) {
-    return err;
-  }
-
-  body_[length_++] = value;
-  return 0;
-}
-
-int HprofRecord::AddUtf8String(const char* str) {
-  // The terminating NUL character is NOT written.
-  return AddU1List((const uint8_t *)str, strlen(str));
-}
-
-int HprofRecord::AddU2List(const uint16_t *values, size_t numValues) {
-  int err = GuaranteeRecordAppend(numValues * 2);
-  if (err != 0) {
-    return err;
-  }
-
-  unsigned char* insert = body_ + length_;
-  for (size_t i = 0; i < numValues; i++) {
-    U2_TO_BUF_BE(insert, 0, *values++);
-    insert += sizeof(*values);
-  }
-  length_ += numValues * 2;
-  return 0;
-}
-
-int HprofRecord::AddU2(uint16_t value) {
-  return AddU2List(&value, 1);
-}
-
-int HprofRecord::AddIdList(const HprofObjectId *values, size_t numValues) {
-  return AddU4List((const uint32_t*) values, numValues);
-}
-
-int HprofRecord::AddU4List(const uint32_t *values, size_t numValues) {
-  int err = GuaranteeRecordAppend(numValues * 4);
-  if (err != 0) {
-    return err;
-  }
-
-  unsigned char* insert = body_ + length_;
-  for (size_t i = 0; i < numValues; i++) {
-    U4_TO_BUF_BE(insert, 0, *values++);
-    insert += sizeof(*values);
-  }
-  length_ += numValues * 4;
-  return 0;
-}
-
-int HprofRecord::AddU4(uint32_t value) {
-  return AddU4List(&value, 1);
-}
-
-int HprofRecord::AddId(HprofObjectId value) {
-  return AddU4((uint32_t) value);
-}
-
-int HprofRecord::AddU8List(const uint64_t *values, size_t numValues) {
-  int err = GuaranteeRecordAppend(numValues * 8);
-  if (err != 0) {
-    return err;
-  }
-
-  unsigned char* insert = body_ + length_;
-  for (size_t i = 0; i < numValues; i++) {
-    U8_TO_BUF_BE(insert, 0, *values++);
-    insert += sizeof(*values);
-  }
-  length_ += numValues * 8;
-  return 0;
-}
-
-int HprofRecord::AddU8(uint64_t value) {
-  return AddU8List(&value, 1);
-}
-
-}  // namespace hprof
-
-}  // namespace art
diff --git a/src/native/dalvik_system_VMDebug.cc b/src/native/dalvik_system_VMDebug.cc
index bb6f8bc..9b10cda 100644
--- a/src/native/dalvik_system_VMDebug.cc
+++ b/src/native/dalvik_system_VMDebug.cc
@@ -178,21 +178,11 @@
     }
   }
 
-  int result = hprof::DumpHeap(filename.c_str(), fd, false);
-  if (result != 0) {
-    // TODO: ideally we'd throw something more specific based on actual failure
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details: %d", result);
-    return;
-  }
+  hprof::DumpHeap(filename.c_str(), fd, false);
 }
 
 static void VMDebug_dumpHprofDataDdms(JNIEnv*, jclass) {
-  int result = hprof::DumpHeap("[DDMS]", -1, true);
-  if (result != 0) {
-    // TODO: ideally we'd throw something more specific based on actual failure
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;", "Failure during heap dump; check log output for details: %d", result);
-    return;
-  }
+  hprof::DumpHeap("[DDMS]", -1, true);
 }
 
 static void VMDebug_dumpReferenceTables(JNIEnv* env, jclass) {