Divide up hprof code by classes.

This divides the _class, _heap, _output and _string files
among hprof.cc and hprof_record.cc.

This removes the use of mutex locks on class and string
collections. This does not otherwise change the body of any
functions, just which files they live in.

Change-Id: I88521529dbe3e00bd88ec0030a6105dceda9500d
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 7ded084..968228b 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -122,10 +122,7 @@
 	src/heap.cc \
 	src/heap_bitmap.cc \
 	src/hprof/hprof.cc \
-	src/hprof/hprof_class.cc \
-	src/hprof/hprof_heap.cc \
-	src/hprof/hprof_output.cc \
-	src/hprof/hprof_string.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 d00f6f9..db1b637 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -25,10 +25,13 @@
 #include "hprof.h"
 #include "heap.h"
 #include "debugger.h"
+#include "object.h"
 #include "stringprintf.h"
-#include "thread_list.h"
+#include "unordered_map.h"
+#include "unordered_set.h"
 #include "logging.h"
 
+#include <cutils/open_memstream.h>
 #include <sys/uio.h>
 #include <string.h>
 #include <unistd.h>
@@ -41,6 +44,459 @@
 
 namespace hprof {
 
+#define HPROF_MAGIC_STRING  "JAVA PROFILE 1.0.3"
+
+/*
+ * Initialize an Hprof.
+ */
+Hprof::Hprof(const char *outputFileName, int fd, bool writeHeader, bool directToDdms)
+    : 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_(NULL),
+      file_data_ptr_(NULL),
+      file_data_size_(0),
+      mem_fp_(NULL),
+      fd_(0),
+      next_string_id_(0x400000) {
+  // 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).
+  FILE *fp = open_memstream(&file_data_ptr_, &file_data_size_);
+  if (fp == NULL) {
+    // not expected
+    LOG(ERROR) << StringPrintf("hprof: open_memstream failed: %s", strerror(errno));
+    CHECK(false);
+  }
+
+  direct_to_ddms_ = directToDdms;
+  file_name_ = strdup(outputFileName);
+  mem_fp_ = fp;
+  fd_ = fd;
+
+  current_record_.alloc_length_ = 128;
+  current_record_.body_ = (unsigned char *)malloc(current_record_.alloc_length_);
+  // TODO check for/return an error
+
+  if (writeHeader) {
+    char magic[] = HPROF_MAGIC_STRING;
+    unsigned char buf[4];
+
+    // Write the file header.
+    // U1: NUL-terminated magic string.
+    fwrite(magic, 1, sizeof(magic), fp);
+
+    // U4: size of identifiers.  We're using addresses as IDs, so make sure a pointer fits.
+    U4_TO_BUF_BE(buf, 0, sizeof(void *));
+    fwrite(buf, 1, sizeof(uint32_t), fp);
+
+    // The current time, in milliseconds since 0:00 GMT, 1/1/70.
+    struct timeval now;
+    uint64_t nowMs;
+    if (gettimeofday(&now, NULL) < 0) {
+      nowMs = 0;
+    } else {
+      nowMs = (uint64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
+    }
+
+    // U4: high word of the 64-bit time.
+    U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs >> 32));
+    fwrite(buf, 1, sizeof(uint32_t), fp);
+
+    // U4: low word of the 64-bit time.
+    U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs & 0xffffffffULL));
+    fwrite(buf, 1, sizeof(uint32_t), fp); //xxx fix the time
+  }
+}
+
+int Hprof::StartNewRecord(uint8_t tag, uint32_t time) {
+  HprofRecord *rec = &current_record_;
+
+  int err = rec->Flush(mem_fp_);
+  if (err != 0) {
+    return err;
+  } else if (rec->dirty_) {
+    return UNIQUE_ERROR();
+  }
+
+  rec->dirty_ = true;
+  rec->tag_ = tag;
+  rec->time_ = time;
+  rec->length_ = 0;
+  return 0;
+}
+
+int Hprof::FlushCurrentRecord() {
+  return current_record_.Flush(mem_fp_);
+}
+
+// Set DUMP_PRIM_DATA to 1 if you want to include the contents
+// of primitive arrays (byte arrays, character arrays, etc.)
+// in heap dumps.  This can be a large amount of data.
+#define DUMP_PRIM_DATA 1
+
+#define OBJECTS_PER_SEGMENT     ((size_t)128)
+#define BYTES_PER_SEGMENT       ((size_t)4096)
+
+// The static field-name for the synthetic object generated to account
+// for class static overhead.
+#define STATIC_OVERHEAD_NAME    "$staticOverhead"
+// The ID for the synthetic object generated to account for class static overhead.
+#define CLASS_STATICS_ID(clazz) ((HprofObjectId)(((uint32_t)(clazz)) | 1))
+
+HprofBasicType Hprof::SignatureToBasicTypeAndSize(const char *sig, size_t *sizeOut) {
+  char c = sig[0];
+  HprofBasicType ret;
+  size_t size;
+
+  switch (c) {
+  case '[':
+  case 'L': ret = hprof_basic_object;  size = 4; break;
+  case 'Z': ret = hprof_basic_boolean; size = 1; break;
+  case 'C': ret = hprof_basic_char;    size = 2; break;
+  case 'F': ret = hprof_basic_float;   size = 4; break;
+  case 'D': ret = hprof_basic_double;  size = 8; break;
+  case 'B': ret = hprof_basic_byte;    size = 1; break;
+  case 'S': ret = hprof_basic_short;   size = 2; break;
+  default: CHECK(false);
+  case 'I': ret = hprof_basic_int;     size = 4; break;
+  case 'J': ret = hprof_basic_long;    size = 8; break;
+  }
+
+  if (sizeOut != NULL) {
+    *sizeOut = size;
+  }
+
+  return ret;
+}
+
+HprofBasicType Hprof::PrimitiveToBasicTypeAndSize(Primitive::Type prim, size_t *sizeOut) {
+  HprofBasicType ret;
+  size_t size;
+
+  switch (prim) {
+  case Primitive::kPrimBoolean: ret = hprof_basic_boolean; size = 1; break;
+  case Primitive::kPrimChar:    ret = hprof_basic_char;    size = 2; break;
+  case Primitive::kPrimFloat:   ret = hprof_basic_float;   size = 4; break;
+  case Primitive::kPrimDouble:  ret = hprof_basic_double;  size = 8; break;
+  case Primitive::kPrimByte:    ret = hprof_basic_byte;    size = 1; break;
+  case Primitive::kPrimShort:   ret = hprof_basic_short;   size = 2; break;
+  default: CHECK(false);
+  case Primitive::kPrimInt:     ret = hprof_basic_int;     size = 4; break;
+  case Primitive::kPrimLong:    ret = hprof_basic_long;    size = 8; break;
+  }
+
+  if (sizeOut != NULL) {
+    *sizeOut = size;
+  }
+
+  return ret;
+}
+
+// Always called when marking objects, but only does
+// something when ctx->gc_scan_state_ is non-zero, which is usually
+// only true when marking the root set or unreachable
+// objects.  Used to add rootset references to obj.
+int Hprof::MarkRootObject(const Object *obj, jobject jniObj) {
+  HprofRecord *rec = &current_record_;
+  int err; // TODO: we may return this uninitialized
+  HprofHeapTag heapTag = (HprofHeapTag)gc_scan_state_;
+
+  if (heapTag == 0) {
+    return 0;
+  }
+
+  if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->length_ >= BYTES_PER_SEGMENT) {
+    // This flushes the old segment and starts a new one.
+    StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
+    objects_in_segment_ = 0;
+  }
+
+  switch (heapTag) {
+  // ID: object ID
+  case HPROF_ROOT_UNKNOWN:
+  case HPROF_ROOT_STICKY_CLASS:
+  case HPROF_ROOT_MONITOR_USED:
+  case HPROF_ROOT_INTERNED_STRING:
+  case HPROF_ROOT_FINALIZING:
+  case HPROF_ROOT_DEBUGGER:
+  case HPROF_ROOT_REFERENCE_CLEANUP:
+  case HPROF_ROOT_VM_INTERNAL:
+    rec->AddU1(heapTag);
+    rec->AddId((HprofObjectId)obj);
+    break;
+
+  // ID: object ID
+  // ID: JNI global ref ID
+  case HPROF_ROOT_JNI_GLOBAL:
+    rec->AddU1(heapTag);
+    rec->AddId((HprofObjectId)obj);
+    rec->AddId((HprofId)jniObj);
+    break;
+
+  // ID: object ID
+  // U4: thread serial number
+  // U4: frame number in stack trace (-1 for empty)
+  case HPROF_ROOT_JNI_LOCAL:
+  case HPROF_ROOT_JNI_MONITOR:
+  case HPROF_ROOT_JAVA_FRAME:
+    rec->AddU1(heapTag);
+    rec->AddId((HprofObjectId)obj);
+    rec->AddU4(gc_thread_serial_number_);
+    rec->AddU4((uint32_t)-1);
+    break;
+
+  // ID: object ID
+  // U4: thread serial number
+  case HPROF_ROOT_NATIVE_STACK:
+  case HPROF_ROOT_THREAD_BLOCK:
+    rec->AddU1(heapTag);
+    rec->AddId((HprofObjectId)obj);
+    rec->AddU4(gc_thread_serial_number_);
+    break;
+
+  // ID: thread object ID
+  // U4: thread serial number
+  // U4: stack trace serial number
+  case HPROF_ROOT_THREAD_OBJECT:
+    rec->AddU1(heapTag);
+    rec->AddId((HprofObjectId)obj);
+    rec->AddU4(gc_thread_serial_number_);
+    rec->AddU4((uint32_t)-1);    //xxx
+    break;
+
+  default:
+    err = 0;
+    break;
+  }
+
+  objects_in_segment_++;
+  return err;
+}
+
+int Hprof::StackTraceSerialNumber(const void *obj) {
+  return HPROF_NULL_STACK_TRACE;
+}
+
+int Hprof::DumpHeapObject(const Object* obj) {
+  HprofRecord *rec = &current_record_;
+  HprofHeapId desiredHeap = false ? HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP; // TODO: zygote objects?
+
+  if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->length_ >= BYTES_PER_SEGMENT) {
+    // This flushes the old segment and starts a new one.
+    StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
+    objects_in_segment_ = 0;
+
+    // Starting a new HEAP_DUMP resets the heap to default.
+    current_heap_ = HPROF_HEAP_DEFAULT;
+  }
+
+  if (desiredHeap != current_heap_) {
+    HprofStringId nameId;
+
+    // This object is in a different heap than the current one.
+    // Emit a HEAP_DUMP_INFO tag to change heaps.
+    rec->AddU1(HPROF_HEAP_DUMP_INFO);
+    rec->AddU4((uint32_t)desiredHeap);   // uint32_t: heap id
+    switch (desiredHeap) {
+    case HPROF_HEAP_APP:
+      nameId = LookupStringId("app");
+      break;
+    case HPROF_HEAP_ZYGOTE:
+      nameId = LookupStringId("zygote");
+      break;
+    default:
+      // Internal error
+      LOG(ERROR) << "Unexpected desiredHeap";
+      nameId = LookupStringId("<ILLEGAL>");
+      break;
+    }
+    rec->AddId(nameId);
+    current_heap_ = desiredHeap;
+  }
+
+  Class* clazz = obj->GetClass();
+  if (clazz == NULL) {
+    // This object will bother HprofReader, because it has a NULL
+    // class, so just don't dump it. It could be
+    // gDvm.unlinkedJavaLangClass or it could be an object just
+    // allocated which hasn't been initialized yet.
+  } else {
+    if (obj->IsClass()) {
+      Class* thisClass = (Class*)obj;
+      // obj is a ClassObject.
+      size_t sFieldCount = thisClass->NumStaticFields();
+      if (sFieldCount != 0) {
+        int byteLength = sFieldCount*sizeof(JValue); // TODO bogus; fields are packed
+        // Create a byte array to reflect the allocation of the
+        // StaticField array at the end of this class.
+        rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
+        rec->AddId(CLASS_STATICS_ID(obj));
+        rec->AddU4(StackTraceSerialNumber(obj));
+        rec->AddU4(byteLength);
+        rec->AddU1(hprof_basic_byte);
+        for (int i = 0; i < byteLength; i++) {
+          rec->AddU1(0);
+        }
+      }
+
+      rec->AddU1(HPROF_CLASS_DUMP);
+      rec->AddId(LookupClassId(thisClass));
+      rec->AddU4(StackTraceSerialNumber(thisClass));
+      rec->AddId(LookupClassId(thisClass->GetSuperClass()));
+      rec->AddId((HprofObjectId)thisClass->GetClassLoader());
+      rec->AddId((HprofObjectId)0);    // no signer
+      rec->AddId((HprofObjectId)0);    // no prot domain
+      rec->AddId((HprofId)0);           // reserved
+      rec->AddId((HprofId)0);           // reserved
+      if (obj->IsClassClass()) {
+        // ClassObjects have their static fields appended, so aren't all the same size.
+        // But they're at least this size.
+        rec->AddU4(sizeof(Class)); // instance size
+      } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) {
+        rec->AddU4(0);
+      } else {
+        rec->AddU4(thisClass->GetObjectSize()); // instance size
+      }
+
+      rec->AddU2(0); // empty const pool
+
+      // Static fields
+      if (sFieldCount == 0) {
+        rec->AddU2((uint16_t)0);
+      } else {
+        rec->AddU2((uint16_t)(sFieldCount+1));
+        rec->AddId(LookupStringId(STATIC_OVERHEAD_NAME));
+        rec->AddU1(hprof_basic_object);
+        rec->AddId(CLASS_STATICS_ID(obj));
+
+        for (size_t i = 0; i < sFieldCount; ++i) {
+          Field* f = thisClass->GetStaticField(i);
+
+          size_t size;
+          HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
+          rec->AddId(LookupStringId(f->GetName()));
+          rec->AddU1(t);
+          if (size == 1) {
+            rec->AddU1(static_cast<uint8_t>(f->Get32(NULL)));
+          } else if (size == 2) {
+            rec->AddU2(static_cast<uint16_t>(f->Get32(NULL)));
+          } else if (size == 4) {
+            rec->AddU4(f->Get32(NULL));
+          } else if (size == 8) {
+            rec->AddU8(f->Get64(NULL));
+          } else {
+            CHECK(false);
+          }
+        }
+      }
+
+      // Instance fields for this class (no superclass fields)
+      int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields();
+      rec->AddU2((uint16_t)iFieldCount);
+      for (int i = 0; i < iFieldCount; ++i) {
+        Field* f = thisClass->GetInstanceField(i);
+        HprofBasicType t = SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), NULL);
+        rec->AddId(LookupStringId(f->GetName()));
+        rec->AddU1(t);
+      }
+    } else if (clazz->IsArrayClass()) {
+      Array *aobj = (Array *)obj;
+      uint32_t length = aobj->GetLength();
+
+      if (obj->IsObjectArray()) {
+        // obj is an object array.
+        rec->AddU1(HPROF_OBJECT_ARRAY_DUMP);
+
+        rec->AddId((HprofObjectId)obj);
+        rec->AddU4(StackTraceSerialNumber(obj));
+        rec->AddU4(length);
+        rec->AddId(LookupClassId(clazz));
+
+        // Dump the elements, which are always objects or NULL.
+        rec->AddIdList((const HprofObjectId *)aobj->GetRawData(), length);
+      } else {
+        size_t size;
+        HprofBasicType t = PrimitiveToBasicTypeAndSize(clazz->GetComponentType()->GetPrimitiveType(), &size);
+
+        // obj is a primitive array.
+#if DUMP_PRIM_DATA
+        rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
+#else
+        rec->AddU1(HPROF_PRIMITIVE_ARRAY_NODATA_DUMP);
+#endif
+
+        rec->AddId((HprofObjectId)obj);
+        rec->AddU4(StackTraceSerialNumber(obj));
+        rec->AddU4(length);
+        rec->AddU1(t);
+
+#if DUMP_PRIM_DATA
+        // Dump the raw, packed element values.
+        if (size == 1) {
+          rec->AddU1List((const uint8_t *)aobj->GetRawData(), length);
+        } else if (size == 2) {
+          rec->AddU2List((const uint16_t *)(void *)aobj->GetRawData(), length);
+        } else if (size == 4) {
+          rec->AddU4List((const uint32_t *)(void *)aobj->GetRawData(), length);
+        } else if (size == 8) {
+          rec->AddU8List((const uint64_t *)aobj->GetRawData(), length);
+        }
+#endif
+      }
+    } else {
+
+      // obj is an instance object.
+      rec->AddU1(HPROF_INSTANCE_DUMP);
+      rec->AddId((HprofObjectId)obj);
+      rec->AddU4(StackTraceSerialNumber(obj));
+      rec->AddId(LookupClassId(clazz));
+
+      // Reserve some space for the length of the instance data, which we won't
+      // know until we're done writing it.
+      size_t sizePatchOffset = rec->length_;
+      rec->AddU4(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.
+      const Class* sclass = clazz;
+      while (!sclass->IsObjectClass()) {
+        int ifieldCount = sclass->NumInstanceFields();
+        for (int i = 0; i < ifieldCount; i++) {
+          Field* f = sclass->GetInstanceField(i);
+          size_t size;
+          SignatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
+          if (size == 1) {
+            rec->AddU1(f->Get32(obj));
+          } else if (size == 2) {
+            rec->AddU2(f->Get32(obj));
+          } else if (size == 4) {
+            rec->AddU4(f->Get32(obj));
+          } else if (size == 8) {
+            rec->AddU8(f->Get64(obj));
+          } else {
+            CHECK(false);
+          }
+        }
+
+        sclass = sclass->GetSuperClass();
+      }
+
+      // Patch the instance field length.
+      size_t savedLen = rec->length_;
+      rec->length_ = sizePatchOffset;
+      rec->AddU4(savedLen - (sizePatchOffset + 4));
+      rec->length_ = savedLen;
+    }
+  }
+
+  objects_in_segment_++;
+  return 0;
+}
+
 #define kHeadSuffix "-hptemp"
 
 // TODO: use File::WriteFully
@@ -146,15 +602,6 @@
   free(file_data_ptr_);
 }
 
-/*
- * Visitor invoked on every root reference.
- */
-void HprofRootVisitor(const Object* obj, void* arg) {
-  CHECK(arg != NULL);
-  Hprof* hprof = (Hprof*)arg;
-  hprof->VisitRoot(obj);
-}
-
 void Hprof::VisitRoot(const Object* obj) {
   uint32_t threadId = 0;  // TODO
   /*RootType */ size_t type = 0; // TODO
@@ -188,10 +635,104 @@
   gc_thread_serial_number_ = 0;
 }
 
-/*
- * Visitor invoked on every heap object.
- */
-static void HprofBitmapCallback(Object *obj, void *arg) {
+HprofStringId Hprof::LookupStringId(String* string) {
+  return LookupStringId(string->ToModifiedUtf8());
+}
+
+HprofStringId Hprof::LookupStringId(const char* string) {
+  return LookupStringId(std::string(string));
+}
+
+HprofStringId Hprof::LookupStringId(std::string string) {
+  if (strings_.find(string) == strings_.end()) {
+    strings_[string] = next_string_id_++;
+  }
+  return strings_[string];
+}
+
+int Hprof::DumpStrings() {
+  HprofRecord *rec = &current_record_;
+
+  for (StringMapIterator it = strings_.begin(); it != strings_.end(); ++it) {
+    std::string string = (*it).first;
+    size_t id = (*it).second;
+
+    int err = StartNewRecord(HPROF_TAG_STRING, HPROF_TIME);
+    if (err != 0) {
+      return err;
+    }
+
+    // STRING format:
+    // ID:  ID for this string
+    // U1*: UTF8 characters for string (NOT NULL terminated)
+    //      (the record format encodes the length)
+    err = rec->AddU4(id);
+    if (err != 0) {
+      return err;
+    }
+    err = rec->AddUtf8String(string.c_str());
+    if (err != 0) {
+      return err;
+    }
+  }
+
+  return 0;
+}
+
+HprofStringId Hprof::LookupClassNameId(Class* clazz) {
+  return LookupStringId(PrettyDescriptor(clazz->GetDescriptor()));
+}
+
+HprofClassObjectId Hprof::LookupClassId(Class* clazz) {
+  if (clazz == NULL) {
+    // clazz is the superclass of java.lang.Object or a primitive
+    return (HprofClassObjectId)0;
+  }
+
+  std::pair<ClassSetIterator, bool> result = classes_.insert(clazz);
+  Class* present = *result.first;
+
+  // Make sure that we've assigned a string ID for this class' name
+  LookupClassNameId(clazz);
+
+  CHECK_EQ(present, clazz);
+  return (HprofStringId) present;
+}
+
+int Hprof::DumpClasses() {
+  HprofRecord *rec = &current_record_;
+  uint32_t nextSerialNumber = 1;
+
+  for (ClassSetIterator it = classes_.begin(); it != classes_.end(); ++it) {
+    Class* clazz = *it;
+    CHECK(clazz != NULL);
+
+    int err = StartNewRecord(HPROF_TAG_LOAD_CLASS, HPROF_TIME);
+    if (err != 0) {
+      return err;
+    }
+
+    // LOAD CLASS format:
+    // U4: class serial number (always > 0)
+    // ID: class object ID. We use the address of the class object structure as its ID.
+    // U4: stack trace serial number
+    // ID: class name string ID
+    rec->AddU4(nextSerialNumber++);
+    rec->AddId((HprofClassObjectId) clazz);
+    rec->AddU4(HPROF_NULL_STACK_TRACE);
+    rec->AddId(LookupClassNameId(clazz));
+  }
+
+  return 0;
+}
+
+void HprofRootVisitor(const Object* obj, void* arg) {
+  CHECK(arg != NULL);
+  Hprof* hprof = (Hprof*)arg;
+  hprof->VisitRoot(obj);
+}
+
+void HprofBitmapCallback(Object *obj, void *arg) {
   CHECK(obj != NULL);
   CHECK(arg != NULL);
   Hprof *hprof = (Hprof*)arg;
diff --git a/src/hprof/hprof.h b/src/hprof/hprof.h
index 38520cc..7378ec9 100644
--- a/src/hprof/hprof.h
+++ b/src/hprof/hprof.h
@@ -22,6 +22,7 @@
 #include "object.h"
 #include "unordered_map.h"
 #include "unordered_set.h"
+#include "thread_list.h"
 
 namespace art {
 
@@ -36,6 +37,41 @@
 #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;
@@ -129,6 +165,9 @@
   size_t alloc_length_;
   uint8_t tag_;
   bool dirty_;
+
+ private:
+  int GuaranteeRecordAppend(size_t nmore);
 };
 
 enum HprofHeapId {
@@ -157,6 +196,9 @@
   HprofStringId LookupStringId(const char* string);
   HprofStringId LookupStringId(std::string string);
   HprofStringId LookupClassNameId(Class* clazz);
+  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_;
@@ -176,11 +218,8 @@
   FILE *mem_fp_;
   int fd_;
 
-  mutable Mutex classes_lock_;
   ClassSet classes_;
-
   size_t next_string_id_;
-  mutable Mutex strings_lock_;
   StringMap strings_;
 };
 
diff --git a/src/hprof/hprof_class.cc b/src/hprof/hprof_class.cc
deleted file mode 100644
index 4286d29..0000000
--- a/src/hprof/hprof_class.cc
+++ /dev/null
@@ -1,81 +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.
- */
-/*
- * Class object pool
- */
-
-#include "hprof.h"
-#include "object.h"
-#include "logging.h"
-#include "unordered_set.h"
-
-namespace art {
-
-namespace hprof {
-
-HprofStringId Hprof::LookupClassNameId(Class* clazz) {
-  return LookupStringId(PrettyDescriptor(clazz->GetDescriptor()));
-}
-
-HprofClassObjectId Hprof::LookupClassId(Class* clazz) {
-  if (clazz == NULL) {
-    // clazz is the superclass of java.lang.Object or a primitive
-    return (HprofClassObjectId)0;
-  }
-
-  MutexLock mu(classes_lock_);
-
-  std::pair<ClassSetIterator, bool> result = classes_.insert(clazz);
-  Class* present = *result.first;
-
-  // Make sure that we've assigned a string ID for this class' name
-  LookupClassNameId(clazz);
-
-  CHECK_EQ(present, clazz);
-  return (HprofStringId) present;
-}
-
-int Hprof::DumpClasses() {
-  MutexLock mu(classes_lock_);
-  HprofRecord *rec = &current_record_;
-  uint32_t nextSerialNumber = 1;
-
-  for (ClassSetIterator it = classes_.begin(); it != classes_.end(); ++it) {
-    Class* clazz = *it;
-    CHECK(clazz != NULL);
-
-    int err = StartNewRecord(HPROF_TAG_LOAD_CLASS, HPROF_TIME);
-    if (err != 0) {
-      return err;
-    }
-
-    // LOAD CLASS format:
-    // U4: class serial number (always > 0)
-    // ID: class object ID. We use the address of the class object structure as its ID.
-    // U4: stack trace serial number
-    // ID: class name string ID
-    rec->AddU4(nextSerialNumber++);
-    rec->AddId((HprofClassObjectId) clazz);
-    rec->AddU4(HPROF_NULL_STACK_TRACE);
-    rec->AddId(LookupClassNameId(clazz));
-  }
-
-  return 0;
-}
-
-}  // namespace hprof
-
-}  // namespace art
diff --git a/src/hprof/hprof_heap.cc b/src/hprof/hprof_heap.cc
deleted file mode 100644
index 0b63e65..0000000
--- a/src/hprof/hprof_heap.cc
+++ /dev/null
@@ -1,394 +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.
- */
-/*
- * Heap object dump
- */
-#include "hprof.h"
-#include "primitive.h"
-#include "object.h"
-#include "logging.h"
-
-namespace art {
-
-namespace hprof {
-
-// Set DUMP_PRIM_DATA to 1 if you want to include the contents
-// of primitive arrays (byte arrays, character arrays, etc.)
-// in heap dumps.  This can be a large amount of data.
-#define DUMP_PRIM_DATA 1
-
-#define OBJECTS_PER_SEGMENT     ((size_t)128)
-#define BYTES_PER_SEGMENT       ((size_t)4096)
-
-// The static field-name for the synthetic object generated to account
-// for class static overhead.
-#define STATIC_OVERHEAD_NAME    "$staticOverhead"
-// The ID for the synthetic object generated to account for class static overhead.
-#define CLASS_STATICS_ID(clazz) ((HprofObjectId)(((uint32_t)(clazz)) | 1))
-
-static HprofBasicType signatureToBasicTypeAndSize(const char *sig, size_t *sizeOut) {
-  char c = sig[0];
-  HprofBasicType ret;
-  size_t size;
-
-  switch (c) {
-  case '[':
-  case 'L': ret = hprof_basic_object;  size = 4; break;
-  case 'Z': ret = hprof_basic_boolean; size = 1; break;
-  case 'C': ret = hprof_basic_char;    size = 2; break;
-  case 'F': ret = hprof_basic_float;   size = 4; break;
-  case 'D': ret = hprof_basic_double;  size = 8; break;
-  case 'B': ret = hprof_basic_byte;    size = 1; break;
-  case 'S': ret = hprof_basic_short;   size = 2; break;
-  default: CHECK(false);
-  case 'I': ret = hprof_basic_int;     size = 4; break;
-  case 'J': ret = hprof_basic_long;    size = 8; break;
-  }
-
-  if (sizeOut != NULL) {
-    *sizeOut = size;
-  }
-
-  return ret;
-}
-
-static HprofBasicType primitiveToBasicTypeAndSize(Primitive::Type prim, size_t *sizeOut) {
-  HprofBasicType ret;
-  size_t size;
-
-  switch (prim) {
-  case Primitive::kPrimBoolean: ret = hprof_basic_boolean; size = 1; break;
-  case Primitive::kPrimChar:    ret = hprof_basic_char;    size = 2; break;
-  case Primitive::kPrimFloat:   ret = hprof_basic_float;   size = 4; break;
-  case Primitive::kPrimDouble:  ret = hprof_basic_double;  size = 8; break;
-  case Primitive::kPrimByte:    ret = hprof_basic_byte;    size = 1; break;
-  case Primitive::kPrimShort:   ret = hprof_basic_short;   size = 2; break;
-  default: CHECK(false);
-  case Primitive::kPrimInt:     ret = hprof_basic_int;     size = 4; break;
-  case Primitive::kPrimLong:    ret = hprof_basic_long;    size = 8; break;
-  }
-
-  if (sizeOut != NULL) {
-    *sizeOut = size;
-  }
-
-  return ret;
-}
-
-// Always called when marking objects, but only does
-// something when ctx->gc_scan_state_ is non-zero, which is usually
-// only true when marking the root set or unreachable
-// objects.  Used to add rootset references to obj.
-int Hprof::MarkRootObject(const Object *obj, jobject jniObj) {
-  HprofRecord *rec = &current_record_;
-  int err; // TODO: we may return this uninitialized
-  HprofHeapTag heapTag = (HprofHeapTag)gc_scan_state_;
-
-  if (heapTag == 0) {
-    return 0;
-  }
-
-  if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->length_ >= BYTES_PER_SEGMENT) {
-    // This flushes the old segment and starts a new one.
-    StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
-    objects_in_segment_ = 0;
-  }
-
-  switch (heapTag) {
-  // ID: object ID
-  case HPROF_ROOT_UNKNOWN:
-  case HPROF_ROOT_STICKY_CLASS:
-  case HPROF_ROOT_MONITOR_USED:
-  case HPROF_ROOT_INTERNED_STRING:
-  case HPROF_ROOT_FINALIZING:
-  case HPROF_ROOT_DEBUGGER:
-  case HPROF_ROOT_REFERENCE_CLEANUP:
-  case HPROF_ROOT_VM_INTERNAL:
-    rec->AddU1(heapTag);
-    rec->AddId((HprofObjectId)obj);
-    break;
-
-  // ID: object ID
-  // ID: JNI global ref ID
-  case HPROF_ROOT_JNI_GLOBAL:
-    rec->AddU1(heapTag);
-    rec->AddId((HprofObjectId)obj);
-    rec->AddId((HprofId)jniObj);
-    break;
-
-  // ID: object ID
-  // U4: thread serial number
-  // U4: frame number in stack trace (-1 for empty)
-  case HPROF_ROOT_JNI_LOCAL:
-  case HPROF_ROOT_JNI_MONITOR:
-  case HPROF_ROOT_JAVA_FRAME:
-    rec->AddU1(heapTag);
-    rec->AddId((HprofObjectId)obj);
-    rec->AddU4(gc_thread_serial_number_);
-    rec->AddU4((uint32_t)-1);
-    break;
-
-  // ID: object ID
-  // U4: thread serial number
-  case HPROF_ROOT_NATIVE_STACK:
-  case HPROF_ROOT_THREAD_BLOCK:
-    rec->AddU1(heapTag);
-    rec->AddId((HprofObjectId)obj);
-    rec->AddU4(gc_thread_serial_number_);
-    break;
-
-  // ID: thread object ID
-  // U4: thread serial number
-  // U4: stack trace serial number
-  case HPROF_ROOT_THREAD_OBJECT:
-    rec->AddU1(heapTag);
-    rec->AddId((HprofObjectId)obj);
-    rec->AddU4(gc_thread_serial_number_);
-    rec->AddU4((uint32_t)-1);    //xxx
-    break;
-
-  default:
-    err = 0;
-    break;
-  }
-
-  objects_in_segment_++;
-  return err;
-}
-
-static int stackTraceSerialNumber(const void *obj) {
-  return HPROF_NULL_STACK_TRACE;
-}
-
-int Hprof::DumpHeapObject(const Object* obj) {
-  HprofRecord *rec = &current_record_;
-  HprofHeapId desiredHeap = false ? HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP; // TODO: zygote objects?
-
-  if (objects_in_segment_ >= OBJECTS_PER_SEGMENT || rec->length_ >= BYTES_PER_SEGMENT) {
-    // This flushes the old segment and starts a new one.
-    StartNewRecord(HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
-    objects_in_segment_ = 0;
-
-    // Starting a new HEAP_DUMP resets the heap to default.
-    current_heap_ = HPROF_HEAP_DEFAULT;
-  }
-
-  if (desiredHeap != current_heap_) {
-    HprofStringId nameId;
-
-    // This object is in a different heap than the current one.
-    // Emit a HEAP_DUMP_INFO tag to change heaps.
-    rec->AddU1(HPROF_HEAP_DUMP_INFO);
-    rec->AddU4((uint32_t)desiredHeap);   // uint32_t: heap id
-    switch (desiredHeap) {
-    case HPROF_HEAP_APP:
-      nameId = LookupStringId("app");
-      break;
-    case HPROF_HEAP_ZYGOTE:
-      nameId = LookupStringId("zygote");
-      break;
-    default:
-      // Internal error
-      LOG(ERROR) << "Unexpected desiredHeap";
-      nameId = LookupStringId("<ILLEGAL>");
-      break;
-    }
-    rec->AddId(nameId);
-    current_heap_ = desiredHeap;
-  }
-
-  Class* clazz = obj->GetClass();
-  if (clazz == NULL) {
-    // This object will bother HprofReader, because it has a NULL
-    // class, so just don't dump it. It could be
-    // gDvm.unlinkedJavaLangClass or it could be an object just
-    // allocated which hasn't been initialized yet.
-  } else {
-    if (obj->IsClass()) {
-      Class* thisClass = (Class*)obj;
-      // obj is a ClassObject.
-      size_t sFieldCount = thisClass->NumStaticFields();
-      if (sFieldCount != 0) {
-        int byteLength = sFieldCount*sizeof(JValue); // TODO bogus; fields are packed
-        // Create a byte array to reflect the allocation of the
-        // StaticField array at the end of this class.
-        rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
-        rec->AddId(CLASS_STATICS_ID(obj));
-        rec->AddU4(stackTraceSerialNumber(obj));
-        rec->AddU4(byteLength);
-        rec->AddU1(hprof_basic_byte);
-        for (int i = 0; i < byteLength; i++) {
-          rec->AddU1(0);
-        }
-      }
-
-      rec->AddU1(HPROF_CLASS_DUMP);
-      rec->AddId(LookupClassId(thisClass));
-      rec->AddU4(stackTraceSerialNumber(thisClass));
-      rec->AddId(LookupClassId(thisClass->GetSuperClass()));
-      rec->AddId((HprofObjectId)thisClass->GetClassLoader());
-      rec->AddId((HprofObjectId)0);    // no signer
-      rec->AddId((HprofObjectId)0);    // no prot domain
-      rec->AddId((HprofId)0);           // reserved
-      rec->AddId((HprofId)0);           // reserved
-      if (obj->IsClassClass()) {
-        // ClassObjects have their static fields appended, so aren't all the same size.
-        // But they're at least this size.
-        rec->AddU4(sizeof(Class)); // instance size
-      } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) {
-        rec->AddU4(0);
-      } else {
-        rec->AddU4(thisClass->GetObjectSize()); // instance size
-      }
-
-      rec->AddU2(0); // empty const pool
-
-      // Static fields
-      if (sFieldCount == 0) {
-        rec->AddU2((uint16_t)0);
-      } else {
-        rec->AddU2((uint16_t)(sFieldCount+1));
-        rec->AddId(LookupStringId(STATIC_OVERHEAD_NAME));
-        rec->AddU1(hprof_basic_object);
-        rec->AddId(CLASS_STATICS_ID(obj));
-
-        for (size_t i = 0; i < sFieldCount; ++i) {
-          Field* f = thisClass->GetStaticField(i);
-
-          size_t size;
-          HprofBasicType t = signatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
-          rec->AddId(LookupStringId(f->GetName()));
-          rec->AddU1(t);
-          if (size == 1) {
-            rec->AddU1(static_cast<uint8_t>(f->Get32(NULL)));
-          } else if (size == 2) {
-            rec->AddU2(static_cast<uint16_t>(f->Get32(NULL)));
-          } else if (size == 4) {
-            rec->AddU4(f->Get32(NULL));
-          } else if (size == 8) {
-            rec->AddU8(f->Get64(NULL));
-          } else {
-            CHECK(false);
-          }
-        }
-      }
-
-      // Instance fields for this class (no superclass fields)
-      int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields();
-      rec->AddU2((uint16_t)iFieldCount);
-      for (int i = 0; i < iFieldCount; ++i) {
-        Field* f = thisClass->GetInstanceField(i);
-        HprofBasicType t = signatureToBasicTypeAndSize(f->GetTypeDescriptor(), NULL);
-        rec->AddId(LookupStringId(f->GetName()));
-        rec->AddU1(t);
-      }
-    } else if (clazz->IsArrayClass()) {
-      Array *aobj = (Array *)obj;
-      uint32_t length = aobj->GetLength();
-
-      if (obj->IsObjectArray()) {
-        // obj is an object array.
-        rec->AddU1(HPROF_OBJECT_ARRAY_DUMP);
-
-        rec->AddId((HprofObjectId)obj);
-        rec->AddU4(stackTraceSerialNumber(obj));
-        rec->AddU4(length);
-        rec->AddId(LookupClassId(clazz));
-
-        // Dump the elements, which are always objects or NULL.
-        rec->AddIdList((const HprofObjectId *)aobj->GetRawData(), length);
-      } else {
-        size_t size;
-        HprofBasicType t = primitiveToBasicTypeAndSize(clazz->GetComponentType()->GetPrimitiveType(), &size);
-
-        // obj is a primitive array.
-#if DUMP_PRIM_DATA
-        rec->AddU1(HPROF_PRIMITIVE_ARRAY_DUMP);
-#else
-        rec->AddU1(HPROF_PRIMITIVE_ARRAY_NODATA_DUMP);
-#endif
-
-        rec->AddId((HprofObjectId)obj);
-        rec->AddU4(stackTraceSerialNumber(obj));
-        rec->AddU4(length);
-        rec->AddU1(t);
-
-#if DUMP_PRIM_DATA
-        // Dump the raw, packed element values.
-        if (size == 1) {
-          rec->AddU1List((const uint8_t *)aobj->GetRawData(), length);
-        } else if (size == 2) {
-          rec->AddU2List((const uint16_t *)(void *)aobj->GetRawData(), length);
-        } else if (size == 4) {
-          rec->AddU4List((const uint32_t *)(void *)aobj->GetRawData(), length);
-        } else if (size == 8) {
-          rec->AddU8List((const uint64_t *)aobj->GetRawData(), length);
-        }
-#endif
-      }
-    } else {
-
-      // obj is an instance object.
-      rec->AddU1(HPROF_INSTANCE_DUMP);
-      rec->AddId((HprofObjectId)obj);
-      rec->AddU4(stackTraceSerialNumber(obj));
-      rec->AddId(LookupClassId(clazz));
-
-      // Reserve some space for the length of the instance data, which we won't
-      // know until we're done writing it.
-      size_t sizePatchOffset = rec->length_;
-      rec->AddU4(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.
-      const Class* sclass = clazz;
-      while (!sclass->IsObjectClass()) {
-        int ifieldCount = sclass->NumInstanceFields();
-        for (int i = 0; i < ifieldCount; i++) {
-          Field* f = sclass->GetInstanceField(i);
-          size_t size;
-          signatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
-          if (size == 1) {
-            rec->AddU1(f->Get32(obj));
-          } else if (size == 2) {
-            rec->AddU2(f->Get32(obj));
-          } else if (size == 4) {
-            rec->AddU4(f->Get32(obj));
-          } else if (size == 8) {
-            rec->AddU8(f->Get64(obj));
-          } else {
-            CHECK(false);
-          }
-        }
-
-        sclass = sclass->GetSuperClass();
-      }
-
-      // Patch the instance field length.
-      size_t savedLen = rec->length_;
-      rec->length_ = sizePatchOffset;
-      rec->AddU4(savedLen - (sizePatchOffset + 4));
-      rec->length_ = savedLen;
-    }
-  }
-
-  objects_in_segment_++;
-  return 0;
-}
-
-}  // namespace hprof
-
-}  // namespace art
diff --git a/src/hprof/hprof_output.cc b/src/hprof/hprof_output.cc
deleted file mode 100644
index 3e26468..0000000
--- a/src/hprof/hprof_output.cc
+++ /dev/null
@@ -1,293 +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 <cutils/open_memstream.h>
-#include <time.h>
-#include <errno.h>
-#include <stdio.h>
-#include "hprof.h"
-#include "stringprintf.h"
-#include "logging.h"
-
-namespace art {
-
-namespace hprof {
-
-#define HPROF_MAGIC_STRING  "JAVA PROFILE 1.0.3"
-
-#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)
-
-/*
- * Initialize an Hprof.
- */
-Hprof::Hprof(const char *outputFileName, int fd, bool writeHeader, bool directToDdms)
-    : 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_(NULL),
-      file_data_ptr_(NULL),
-      file_data_size_(0),
-      mem_fp_(NULL),
-      fd_(0),
-      classes_lock_("hprof classes"),
-      next_string_id_(0x400000),
-      strings_lock_("hprof strings") {
-  // 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).
-  FILE *fp = open_memstream(&file_data_ptr_, &file_data_size_);
-  if (fp == NULL) {
-    // not expected
-    LOG(ERROR) << StringPrintf("hprof: open_memstream failed: %s", strerror(errno));
-    CHECK(false);
-  }
-
-  direct_to_ddms_ = directToDdms;
-  file_name_ = strdup(outputFileName);
-  mem_fp_ = fp;
-  fd_ = fd;
-
-  current_record_.alloc_length_ = 128;
-  current_record_.body_ = (unsigned char *)malloc(current_record_.alloc_length_);
-  // TODO check for/return an error
-
-  if (writeHeader) {
-    char magic[] = HPROF_MAGIC_STRING;
-    unsigned char buf[4];
-
-    // Write the file header.
-    // U1: NUL-terminated magic string.
-    fwrite(magic, 1, sizeof(magic), fp);
-
-    // U4: size of identifiers.  We're using addresses as IDs, so make sure a pointer fits.
-    U4_TO_BUF_BE(buf, 0, sizeof(void *));
-    fwrite(buf, 1, sizeof(uint32_t), fp);
-
-    // The current time, in milliseconds since 0:00 GMT, 1/1/70.
-    struct timeval now;
-    uint64_t nowMs;
-    if (gettimeofday(&now, NULL) < 0) {
-      nowMs = 0;
-    } else {
-      nowMs = (uint64_t)now.tv_sec * 1000 + now.tv_usec / 1000;
-    }
-
-    // U4: high word of the 64-bit time.
-    U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs >> 32));
-    fwrite(buf, 1, sizeof(uint32_t), fp);
-
-    // U4: low word of the 64-bit time.
-    U4_TO_BUF_BE(buf, 0, (uint32_t)(nowMs & 0xffffffffULL));
-    fwrite(buf, 1, sizeof(uint32_t), fp); //xxx fix the time
-  }
-}
-
-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 Hprof::FlushCurrentRecord() {
-  return current_record_.Flush(mem_fp_);
-}
-
-int Hprof::StartNewRecord(uint8_t tag, uint32_t time) {
-  HprofRecord *rec = &current_record_;
-
-  int err = rec->Flush(mem_fp_);
-  if (err != 0) {
-    return err;
-  } else if (rec->dirty_) {
-    return UNIQUE_ERROR();
-  }
-
-  rec->dirty_ = true;
-  rec->tag_ = tag;
-  rec->time_ = time;
-  rec->length_ = 0;
-  return 0;
-}
-
-static inline int guaranteeRecordAppend(HprofRecord *rec, size_t nmore) {
-  size_t minSize = rec->length_ + nmore;
-  if (minSize > rec->alloc_length_) {
-    size_t newAllocLen = rec->alloc_length_ * 2;
-    if (newAllocLen < minSize) {
-      newAllocLen = rec->alloc_length_ + nmore + nmore/2;
-    }
-    unsigned char *newBody = (unsigned char *)realloc(rec->body_, newAllocLen);
-    if (newBody != NULL) {
-      rec->body_ = newBody;
-      rec->alloc_length_ = newAllocLen;
-    } else {
-      // TODO: set an error flag so future ops will fail
-      return UNIQUE_ERROR();
-    }
-  }
-
-  CHECK_LE(rec->length_ + nmore, rec->alloc_length_);
-  return 0;
-}
-
-int HprofRecord::AddU1List(const uint8_t *values, size_t numValues) {
-  int err = guaranteeRecordAppend(this, numValues);
-  if (err != 0) {
-    return err;
-  }
-
-  memcpy(body_ + length_, values, numValues);
-  length_ += numValues;
-
-  return 0;
-}
-
-int HprofRecord::AddU1(uint8_t value) {
-  int err = guaranteeRecordAppend(this, 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(this, 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(this, 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(this, 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/hprof/hprof_record.cc b/src/hprof/hprof_record.cc
new file mode 100644
index 0000000..1813a44
--- /dev/null
+++ b/src/hprof/hprof_record.cc
@@ -0,0 +1,165 @@
+/*
+ * 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/hprof/hprof_string.cc b/src/hprof/hprof_string.cc
deleted file mode 100644
index 96acaf3..0000000
--- a/src/hprof/hprof_string.cc
+++ /dev/null
@@ -1,77 +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.
- */
-/*
- * Common string pool for the profiler
- */
-#include "hprof.h"
-#include "object.h"
-#include "unordered_map.h"
-#include "logging.h"
-
-namespace art {
-
-namespace hprof {
-
-HprofStringId Hprof::LookupStringId(String* string) {
-  return LookupStringId(string->ToModifiedUtf8());
-}
-
-HprofStringId Hprof::LookupStringId(const char* string) {
-  return LookupStringId(std::string(string));
-}
-
-HprofStringId Hprof::LookupStringId(std::string string) {
-  MutexLock mu(strings_lock_);
-  if (strings_.find(string) == strings_.end()) {
-    strings_[string] = next_string_id_++;
-  }
-  return strings_[string];
-}
-
-int Hprof::DumpStrings() {
-  MutexLock mu(strings_lock_);
-
-  HprofRecord *rec = &current_record_;
-
-  for (StringMapIterator it = strings_.begin(); it != strings_.end(); ++it) {
-    std::string string = (*it).first;
-    size_t id = (*it).second;
-
-    int err = StartNewRecord(HPROF_TAG_STRING, HPROF_TIME);
-    if (err != 0) {
-      return err;
-    }
-
-    // STRING format:
-    // ID:  ID for this string
-    // U1*: UTF8 characters for string (NOT NULL terminated)
-    //      (the record format encodes the length)
-    err = rec->AddU4(id);
-    if (err != 0) {
-      return err;
-    }
-    err = rec->AddUtf8String(string.c_str());
-    if (err != 0) {
-      return err;
-    }
-  }
-
-  return 0;
-}
-
-}  // namespace hprof
-
-}  // namespace art