Fix hprof dumping from DDMS.
Hprof needs to use Get32 and Get64 (or handle every single type specially) ---
you can't GetInt on a char[] field, say, like this code used to do.
Change-Id: I37eda049b7f341f8ad3c8326b9bcf2997efd7b04
diff --git a/src/dalvik_system_VMDebug.cc b/src/dalvik_system_VMDebug.cc
index 7461fc4..65126e7 100644
--- a/src/dalvik_system_VMDebug.cc
+++ b/src/dalvik_system_VMDebug.cc
@@ -197,7 +197,7 @@
}
}
- int result = hprof::hprofDumpHeap(filename.c_str(), fd, false);
+ int result = hprof::DumpHeap(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");
@@ -206,8 +206,7 @@
}
void VMDebug_dumpHprofDataDdms(JNIEnv* env, jclass) {
- UNIMPLEMENTED(WARNING);
- int result = hprof::hprofDumpHeap("[DDMS]", -1, true);
+ int result = hprof::DumpHeap("[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 a7047ac..20fc426 100644
--- a/src/hprof/hprof.cc
+++ b/src/hprof/hprof.cc
@@ -247,7 +247,7 @@
CHECK(obj != NULL);
CHECK(arg != NULL);
hprof_context_t *ctx = (hprof_context_t *)arg;
- hprofDumpHeapObject(ctx, obj);
+ DumpHeapObject(ctx, obj);
}
/*
@@ -262,7 +262,7 @@
*
* Returns 0 on success, or an error code on failure.
*/
-int hprofDumpHeap(const char* fileName, int fd, bool directToDdms)
+int DumpHeap(const char* fileName, int fd, bool directToDdms)
{
hprof_context_t *ctx;
int success;
diff --git a/src/hprof/hprof.h b/src/hprof/hprof.h
index 897a996..e26e2cf 100644
--- a/src/hprof/hprof.h
+++ b/src/hprof/hprof.h
@@ -173,7 +173,7 @@
int hprofMarkRootObject(hprof_context_t *ctx,
const Object *obj, jobject jniObj);
-int hprofDumpHeapObject(hprof_context_t *ctx, const Object *obj);
+int DumpHeapObject(hprof_context_t *ctx, const Object *obj);
void hprofContextInit(hprof_context_t *ctx, char *fileName, int fd,
bool writeHeader, bool directToDdms);
@@ -208,7 +208,7 @@
bool directToDdms);
bool hprofShutdown(hprof_context_t *ctx);
void hprofFreeContext(hprof_context_t *ctx);
-int hprofDumpHeap(const char* fileName, int fd, bool directToDdms);
+int DumpHeap(const char* fileName, int fd, bool directToDdms);
} // namespace hprof
diff --git a/src/hprof/hprof_heap.cc b/src/hprof/hprof_heap.cc
index 571167d..5c23bbb 100644
--- a/src/hprof/hprof_heap.cc
+++ b/src/hprof/hprof_heap.cc
@@ -216,260 +216,243 @@
return HPROF_NULL_STACK_TRACE;
}
-int hprofDumpHeapObject(hprof_context_t *ctx, const Object *obj)
-{
- Class* clazz;
- hprof_record_t *rec = &ctx->curRec;
- HprofHeapId desiredHeap;
+int DumpHeapObject(hprof_context_t* ctx, const Object* obj) {
+ Class* clazz;
+ hprof_record_t *rec = &ctx->curRec;
- desiredHeap = false ? HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP; // TODO: zygote objects?
+ HprofHeapId desiredHeap = false ? HPROF_HEAP_ZYGOTE : HPROF_HEAP_APP; // TODO: zygote objects?
- if (ctx->objectsInSegment >= OBJECTS_PER_SEGMENT ||
- rec->length >= BYTES_PER_SEGMENT)
- {
- /* This flushes the old segment and starts a new one.
- */
- hprofStartNewRecord(ctx, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
- ctx->objectsInSegment = 0;
+ if (ctx->objectsInSegment >= OBJECTS_PER_SEGMENT || rec->length >= BYTES_PER_SEGMENT) {
+ /* This flushes the old segment and starts a new one.
+ */
+ hprofStartNewRecord(ctx, HPROF_TAG_HEAP_DUMP_SEGMENT, HPROF_TIME);
+ ctx->objectsInSegment = 0;
- /* Starting a new HEAP_DUMP resets the heap to default.
- */
- ctx->currentHeap = HPROF_HEAP_DEFAULT;
+ /* Starting a new HEAP_DUMP resets the heap to default.
+ */
+ ctx->currentHeap = HPROF_HEAP_DEFAULT;
+ }
+
+ if (desiredHeap != ctx->currentHeap) {
+ hprof_string_id nameId;
+
+ /* This object is in a different heap than the current one.
+ * Emit a HEAP_DUMP_INFO tag to change heaps.
+ */
+ hprofAddU1ToRecord(rec, HPROF_HEAP_DUMP_INFO);
+ hprofAddU4ToRecord(rec, (uint32_t)desiredHeap); // uint32_t: heap id
+ switch (desiredHeap) {
+ case HPROF_HEAP_APP:
+ nameId = hprofLookupStringId("app");
+ break;
+ case HPROF_HEAP_ZYGOTE:
+ nameId = hprofLookupStringId("zygote");
+ break;
+ default:
+ /* Internal error. */
+ LOG(ERROR) << "Unexpected desiredHeap";
+ nameId = hprofLookupStringId("<ILLEGAL>");
+ break;
}
+ hprofAddIdToRecord(rec, nameId);
+ ctx->currentHeap = desiredHeap;
+ }
- if (desiredHeap != ctx->currentHeap) {
- hprof_string_id nameId;
+ clazz = obj->GetClass();
- /* This object is in a different heap than the current one.
- * Emit a HEAP_DUMP_INFO tag to change heaps.
+ 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.
*/
- hprofAddU1ToRecord(rec, HPROF_HEAP_DUMP_INFO);
- hprofAddU4ToRecord(rec, (uint32_t)desiredHeap); // uint32_t: heap id
- switch (desiredHeap) {
- case HPROF_HEAP_APP:
- nameId = hprofLookupStringId("app");
- break;
- case HPROF_HEAP_ZYGOTE:
- nameId = hprofLookupStringId("zygote");
- break;
- default:
- /* Internal error. */
- LOG(ERROR) << "Unexpected desiredHeap";
- nameId = hprofLookupStringId("<ILLEGAL>");
- break;
+ hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
+ hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+ hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+ hprofAddU4ToRecord(rec, byteLength);
+ hprofAddU1ToRecord(rec, hprof_basic_byte);
+ for (int i = 0; i < byteLength; i++) {
+ hprofAddU1ToRecord(rec, 0);
}
- hprofAddIdToRecord(rec, nameId);
- ctx->currentHeap = desiredHeap;
- }
+ }
- clazz = obj->GetClass();
+ hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
+ hprofAddIdToRecord(rec, hprofLookupClassId(thisClass));
+ hprofAddU4ToRecord(rec, stackTraceSerialNumber(thisClass));
+ hprofAddIdToRecord(rec, hprofLookupClassId(thisClass->GetSuperClass()));
+ hprofAddIdToRecord(rec, (hprof_object_id)thisClass->GetClassLoader());
+ hprofAddIdToRecord(rec, (hprof_object_id)0); // no signer
+ hprofAddIdToRecord(rec, (hprof_object_id)0); // no prot domain
+ hprofAddIdToRecord(rec, (hprof_id)0); // reserved
+ hprofAddIdToRecord(rec, (hprof_id)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.
+ hprofAddU4ToRecord(rec, sizeof(Class)); // instance size
+ } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) {
+ hprofAddU4ToRecord(rec, 0);
+ } else {
+ hprofAddU4ToRecord(rec, thisClass->GetObjectSize()); // instance size
+ }
- 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.
+ hprofAddU2ToRecord(rec, 0); // empty const pool
+
+ /* Static fields
+ */
+ if (sFieldCount == 0) {
+ hprofAddU2ToRecord(rec, (uint16_t)0);
+ } else {
+ hprofAddU2ToRecord(rec, (uint16_t)(sFieldCount+1));
+ hprofAddIdToRecord(rec, hprofLookupStringId(STATIC_OVERHEAD_NAME));
+ hprofAddU1ToRecord(rec, hprof_basic_object);
+ hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
+
+ for (size_t i = 0; i < sFieldCount; ++i) {
+ Field* f = thisClass->GetStaticField(i);
+
+ size_t size;
+ hprof_basic_type t = signatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
+ hprofAddIdToRecord(rec, hprofLookupStringId(f->GetName()));
+ hprofAddU1ToRecord(rec, t);
+ if (size == 1) {
+ hprofAddU1ToRecord(rec, static_cast<uint8_t>(f->Get32(NULL)));
+ } else if (size == 2) {
+ hprofAddU2ToRecord(rec, static_cast<uint16_t>(f->Get32(NULL)));
+ } else if (size == 4) {
+ hprofAddU4ToRecord(rec, f->Get32(NULL));
+ } else if (size == 8) {
+ hprofAddU8ToRecord(rec, f->Get64(NULL));
+ } else {
+ CHECK(false);
+ }
+ }
+ }
+
+ /* Instance fields for this class (no superclass fields)
+ */
+ int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields();
+ hprofAddU2ToRecord(rec, (uint16_t)iFieldCount);
+ for (int i = 0; i < iFieldCount; ++i) {
+ Field* f = thisClass->GetInstanceField(i);
+ hprof_basic_type t = signatureToBasicTypeAndSize(f->GetTypeDescriptor(), NULL);
+ hprofAddIdToRecord(rec, hprofLookupStringId(f->GetName()));
+ hprofAddU1ToRecord(rec, t);
+ }
+ } else if (clazz->IsArrayClass()) {
+ Array *aobj = (Array *)obj;
+ uint32_t length = aobj->GetLength();
+
+ if (obj->IsObjectArray()) {
+ /* obj is an object array.
*/
- } 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.
- */
- hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
- hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
- hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
- hprofAddU4ToRecord(rec, byteLength);
- hprofAddU1ToRecord(rec, hprof_basic_byte);
- for (int i = 0; i < byteLength; i++) {
- hprofAddU1ToRecord(rec, 0);
- }
- }
+ hprofAddU1ToRecord(rec, HPROF_OBJECT_ARRAY_DUMP);
- hprofAddU1ToRecord(rec, HPROF_CLASS_DUMP);
- hprofAddIdToRecord(rec, hprofLookupClassId(thisClass));
- hprofAddU4ToRecord(rec, stackTraceSerialNumber(thisClass));
- hprofAddIdToRecord(rec, hprofLookupClassId(thisClass->GetSuperClass()));
- hprofAddIdToRecord(rec, (hprof_object_id)thisClass->GetClassLoader());
- hprofAddIdToRecord(rec, (hprof_object_id)0); // no signer
- hprofAddIdToRecord(rec, (hprof_object_id)0); // no prot domain
- hprofAddIdToRecord(rec, (hprof_id)0); // reserved
- hprofAddIdToRecord(rec, (hprof_id)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.
- hprofAddU4ToRecord(rec, sizeof(Class)); // instance size
- } else if (thisClass->IsArrayClass() || thisClass->IsPrimitive()) {
- hprofAddU4ToRecord(rec, 0);
- } else {
- hprofAddU4ToRecord(rec, thisClass->GetObjectSize()); // instance size
- }
+ hprofAddIdToRecord(rec, (hprof_object_id)obj);
+ hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+ hprofAddU4ToRecord(rec, length);
+ hprofAddIdToRecord(rec, hprofLookupClassId(clazz));
- hprofAddU2ToRecord(rec, 0); // empty const pool
+ /* Dump the elements, which are always objects or NULL.
+ */
+ hprofAddIdListToRecord(rec, (const hprof_object_id *)aobj->GetRawData(), length);
+ } else {
+ size_t size;
+ hprof_basic_type t = primitiveToBasicTypeAndSize(clazz->GetComponentType()->GetPrimitiveType(), &size);
- /* Static fields
- */
- if (sFieldCount == 0) {
- hprofAddU2ToRecord(rec, (uint16_t)0);
- } else {
- hprofAddU2ToRecord(rec, (uint16_t)(sFieldCount+1));
- hprofAddIdToRecord(rec,
- hprofLookupStringId(STATIC_OVERHEAD_NAME));
- hprofAddU1ToRecord(rec, hprof_basic_object);
- hprofAddIdToRecord(rec, CLASS_STATICS_ID(obj));
-
- for (size_t i = 0; i < sFieldCount; ++i) {
- hprof_basic_type t;
- size_t size;
- Field* f = thisClass->GetStaticField(i);
-
- t = signatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
- hprofAddIdToRecord(rec, hprofLookupStringId(f->GetName()));
- hprofAddU1ToRecord(rec, t);
- if (size == 1) {
- hprofAddU1ToRecord(rec, (uint8_t)f->GetByte(NULL));
- } else if (size == 2) {
- hprofAddU2ToRecord(rec, (uint16_t)f->GetShort(NULL));
- } else if (size == 4) {
- hprofAddU4ToRecord(rec, (uint32_t)f->GetInt(NULL));
- } else if (size == 8) {
- hprofAddU8ToRecord(rec, (uint64_t)f->GetLong(NULL));
- } else {
- CHECK(false);
- }
- }
- }
-
- /* Instance fields for this class (no superclass fields)
- */
- int iFieldCount = thisClass->IsObjectClass() ? 0 : thisClass->NumInstanceFields();
- hprofAddU2ToRecord(rec, (uint16_t)iFieldCount);
- for (int i = 0; i < iFieldCount; ++i) {
- Field* f = thisClass->GetInstanceField(i);
- hprof_basic_type t;
-
- t = signatureToBasicTypeAndSize(f->GetTypeDescriptor(), NULL);
- hprofAddIdToRecord(rec, hprofLookupStringId(f->GetName()));
- hprofAddU1ToRecord(rec, t);
- }
- } else if (clazz->IsArrayClass()) {
- Array *aobj = (Array *)obj;
- uint32_t length = aobj->GetLength();
-
- if (obj->IsObjectArray()) {
- /* obj is an object array.
- */
- hprofAddU1ToRecord(rec, HPROF_OBJECT_ARRAY_DUMP);
-
- hprofAddIdToRecord(rec, (hprof_object_id)obj);
- hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
- hprofAddU4ToRecord(rec, length);
- hprofAddIdToRecord(rec, hprofLookupClassId(clazz));
-
- /* Dump the elements, which are always objects or NULL.
- */
- hprofAddIdListToRecord(rec,
- (const hprof_object_id *)aobj->GetRawData(), length);
- } else {
- hprof_basic_type t;
- size_t size;
-
- t = primitiveToBasicTypeAndSize(clazz->GetComponentType()->
- GetPrimitiveType(), &size);
-
- /* obj is a primitive array.
- */
+ /* obj is a primitive array.
+ */
#if DUMP_PRIM_DATA
- hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
+ hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_DUMP);
#else
- hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_NODATA_DUMP);
+ hprofAddU1ToRecord(rec, HPROF_PRIMITIVE_ARRAY_NODATA_DUMP);
#endif
- hprofAddIdToRecord(rec, (hprof_object_id)obj);
- hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
- hprofAddU4ToRecord(rec, length);
- hprofAddU1ToRecord(rec, t);
+ hprofAddIdToRecord(rec, (hprof_object_id)obj);
+ hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+ hprofAddU4ToRecord(rec, length);
+ hprofAddU1ToRecord(rec, t);
#if DUMP_PRIM_DATA
- /* Dump the raw, packed element values.
- */
- if (size == 1) {
- hprofAddU1ListToRecord(rec, (const uint8_t *)aobj->GetRawData(),
- length);
- } else if (size == 2) {
- hprofAddU2ListToRecord(rec, (const uint16_t *)(void *)aobj->GetRawData(),
- length);
- } else if (size == 4) {
- hprofAddU4ListToRecord(rec, (const uint32_t *)(void *)aobj->GetRawData(),
- length);
- } else if (size == 8) {
- hprofAddU8ListToRecord(rec, (const uint64_t *)aobj->GetRawData(),
- length);
- }
-#endif
- }
- } else {
-
- /* obj is an instance object.
- */
- hprofAddU1ToRecord(rec, HPROF_INSTANCE_DUMP);
- hprofAddIdToRecord(rec, (hprof_object_id)obj);
- hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
- hprofAddIdToRecord(rec, hprofLookupClassId(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;
- 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.
- */
- 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;
-
- (void) signatureToBasicTypeAndSize(f->GetTypeDescriptor(), &size);
- if (size == 1) {
- hprofAddU1ToRecord(rec, f->GetByte(obj));
- } else if (size == 2) {
- hprofAddU2ToRecord(rec, f->GetChar(obj));
- } else if (size == 4) {
- hprofAddU4ToRecord(rec, f->GetInt(obj));
- } else if (size == 8) {
- hprofAddU8ToRecord(rec, f->GetLong(obj));
- } else {
- CHECK(false);
- }
- }
-
- sclass = sclass->GetSuperClass();
- }
-
- /* Patch the instance field length.
- */
- size_t savedLen = rec->length;
- rec->length = sizePatchOffset;
- hprofAddU4ToRecord(rec, savedLen - (sizePatchOffset + 4));
- rec->length = savedLen;
+ /* Dump the raw, packed element values.
+ */
+ if (size == 1) {
+ hprofAddU1ListToRecord(rec, (const uint8_t *)aobj->GetRawData(), length);
+ } else if (size == 2) {
+ hprofAddU2ListToRecord(rec, (const uint16_t *)(void *)aobj->GetRawData(), length);
+ } else if (size == 4) {
+ hprofAddU4ListToRecord(rec, (const uint32_t *)(void *)aobj->GetRawData(), length);
+ } else if (size == 8) {
+ hprofAddU8ListToRecord(rec, (const uint64_t *)aobj->GetRawData(), length);
}
+#endif
+ }
+ } else {
+
+ /* obj is an instance object.
+ */
+ hprofAddU1ToRecord(rec, HPROF_INSTANCE_DUMP);
+ hprofAddIdToRecord(rec, (hprof_object_id)obj);
+ hprofAddU4ToRecord(rec, stackTraceSerialNumber(obj));
+ hprofAddIdToRecord(rec, hprofLookupClassId(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;
+ 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.
+ */
+ 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) {
+ hprofAddU1ToRecord(rec, f->Get32(obj));
+ } else if (size == 2) {
+ hprofAddU2ToRecord(rec, f->Get32(obj));
+ } else if (size == 4) {
+ hprofAddU4ToRecord(rec, f->Get32(obj));
+ } else if (size == 8) {
+ hprofAddU8ToRecord(rec, f->Get64(obj));
+ } else {
+ CHECK(false);
+ }
+ }
+
+ sclass = sclass->GetSuperClass();
+ }
+
+ /* Patch the instance field length.
+ */
+ size_t savedLen = rec->length;
+ rec->length = sizePatchOffset;
+ hprofAddU4ToRecord(rec, savedLen - (sizePatchOffset + 4));
+ rec->length = savedLen;
}
+ }
- ctx->objectsInSegment++;
+ ctx->objectsInSegment++;
- return 0;
+ return 0;
}
} // namespace hprof