Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(976)

Unified Diff: runtime/vm/heap_profiler.cc

Issue 10452006: Implement a heap profiler for the Dart managed heap. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: added basic test code Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/heap_profiler.cc
diff --git a/runtime/vm/heap_profiler.cc b/runtime/vm/heap_profiler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e4d2c6cae91000f03a967473b1fa7615c7729e0d
--- /dev/null
+++ b/runtime/vm/heap_profiler.cc
@@ -0,0 +1,715 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/heap_profiler.h"
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+
+#include "vm/dart_api_state.h"
+#include "vm/object.h"
+#include "vm/raw_object.h"
+#include "vm/stack_frame.h"
+#include "vm/unicode.h"
+
+namespace dart {
+
+HeapProfiler::Buffer::~Buffer() {
+ delete[] data_;
+}
+
+
+void HeapProfiler::Buffer::Write(const uint8_t* data, intptr_t size) {
+ EnsureCapacity(size);
+ memmove(&data_[size_], data, size);
+ size_ += size;
turnidge 2012/06/12 17:02:19 It's a bit confusing to me to have both "name_" an
cshapiro 2012/06/14 00:08:36 I see where you are coming from. I would like thi
+}
+
+
+void HeapProfiler::Buffer::EnsureCapacity(intptr_t size) {
+ if ((size + size_) > capacity_) {
+ intptr_t new_capacity = Utils::RoundUpToPowerOfTwo(capacity_ + size);
+ uint8_t* new_data = new uint8_t[new_capacity];
+ memmove(new_data, data_, size_);
+ capacity_ = new_capacity;
+ data_ = new_data;
+ }
+}
+
+
+void HeapProfiler::Record::Write(const uint8_t* value, intptr_t size) {
+ body_.Write(value, size);
+}
+
+
+void HeapProfiler::Record::Write8(uint8_t value) {
+ body_.Write(&value, sizeof(value));
+}
+
+
+void HeapProfiler::Record::Write16(uint16_t value) {
+ value = htons(value);
+ body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+}
+
+
+void HeapProfiler::Record::Write32(uint32_t value) {
+ value = htonl(value);
+ body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+}
+
+
+void HeapProfiler::Record::Write64(uint64_t value) {
+ uint16_t x = 0xFF;
+ if (*reinterpret_cast<uint8_t*>(&x) == 0xFF) {
+ uint64_t hi = static_cast<uint64_t>(htonl(value & 0xFFFFFFFF)) << 32;
+ uint64_t lo = htonl(value >> 32);
+ value = hi | lo;
+ }
+ body_.Write(reinterpret_cast<uint8_t*>(&value), sizeof(value));
+}
+
+
+void HeapProfiler::Record::WritePointer(const void* value) {
+ if (sizeof(value) == 4) {
+ Write32(reinterpret_cast<uint32_t>(value));
+ } else {
+ ASSERT(sizeof(value) == 8);
+ Write64(reinterpret_cast<uint64_t>(value));
+ }
+}
+
+
+HeapProfiler::SubRecord::SubRecord(uint8_t sub_tag, HeapProfiler* profiler)
+ : record_(profiler->heap_dump_record_) {
+ record_->Write8(sub_tag);
+}
+
+
+HeapProfiler::SubRecord::~SubRecord() {
+}
+
+
+void HeapProfiler::SubRecord::Write(const uint8_t* value, intptr_t size) {
+ record_->Write(value, size);
+}
+
+
+void HeapProfiler::SubRecord::Write8(uint8_t value) {
+ record_->Write8(value);
+}
+
+
+void HeapProfiler::SubRecord::Write16(uint16_t value) {
+ record_->Write16(value);
+}
+
+
+void HeapProfiler::SubRecord::Write32(uint32_t value) {
+ record_->Write32(value);
+}
+
+
+void HeapProfiler::SubRecord::Write64(uint64_t value) {
+ record_->Write64(value);
+}
+
+
+void HeapProfiler::SubRecord::WritePointer(const void* value) {
+ record_->WritePointer(value);
+}
+
+
+HeapProfiler::HeapProfiler(Dart_HeapProfileWriteCallback callback, void* stream)
+ : write_callback_(callback),
+ output_stream_(stream),
+ heap_dump_record_(NULL) {
+ WriteHeader();
+ WriteStackTrace();
+ heap_dump_record_ = new Record(kHeapDump, this);
+}
+
+
+HeapProfiler::~HeapProfiler() {
+ delete heap_dump_record_;
+}
+
+
+const RawObject* HeapProfiler::ObjectId(const RawObject* raw_obj) {
+ if (!raw_obj->IsHeapObject()) {
+ // To describe an immediate object in HPROF we record its value
+ // and write fake INSTANCE_DUMP subrecord in the HEAP_DUMP record.
+ const RawSmi* raw_smi = reinterpret_cast<const RawSmi*>(raw_obj);
+ if (smi_table_.find(raw_smi) == smi_table_.end()) {
+ smi_table_.insert(raw_smi);
+ }
+ } else if (raw_obj->GetClassId() == kNullClassId) {
+ // Instances of the Null type are translated to NULL so they can
+ // be printed as "null" in HAT.
+ return NULL;
+ }
+ return raw_obj;
+}
+
+
+const RawClass* HeapProfiler::ClassId(const RawClass* raw_class) {
+ // A unique LOAD_CLASS record must be written for each class object.
+ if (class_table_.find(raw_class) == class_table_.end()) {
+ class_table_.insert(raw_class);
+ WriteLoadClass(raw_class);
+ }
+ return raw_class;
+}
+
+
+// A built-in class may have its name encoded in a C-string. These
+// strings should only be found in class objects. We emit a unique
+// STRING_IN_UTF8 so HAT will properly display the class name.
+const char* HeapProfiler::StringId(const char* c_string) {
+ const RawString* ptr = reinterpret_cast<const RawString*>(c_string);
+ if (string_table_.find(ptr) == string_table_.end()) {
+ string_table_.insert(ptr);
+ WriteStringInUtf8(c_string);
+ }
+ return c_string;
+}
+
+
+const RawString* HeapProfiler::StringId(const RawString* raw_string) {
+ // A unique STRING_IN_UTF8 record must be written for each string
+ // object.
+ if (string_table_.find(raw_string) == string_table_.end()) {
+ string_table_.insert(raw_string);
+ WriteStringInUtf8(raw_string);
+ }
+ return raw_string;
+}
+
+
+void HeapProfiler::WriteRoot(const RawObject* raw_obj) {
+ SubRecord sub(kRootUnknown, this);
+ sub.WritePointer(ObjectId(raw_obj));
+}
+
+
+void HeapProfiler::WriteObject(const RawObject* raw_obj) {
+ ASSERT(raw_obj->IsHeapObject());
+ if (FreeListElement::IsSpecialClass(raw_obj)) {
+ // Free space has an object-like encoding. Heap profiles only
+ // care about live objects so we skip over these records.
+ return;
+ }
+ ObjectKind kind = raw_obj->ptr()->class_->ptr()->instance_kind_;
+ switch (kind) {
+ case Class::kInstanceKind: {
+ WriteClassDump(reinterpret_cast<const RawClass*>(raw_obj));
+ break;
+ }
+ case Array::kInstanceKind:
+ case ImmutableArray::kInstanceKind: {
+ WriteObjectArrayDump(reinterpret_cast<const RawArray*>(raw_obj));
+ break;
+ }
+ case Int8Array::kInstanceKind:
+ case Uint8Array::kInstanceKind: {
+ const RawInt8Array* raw_int8_array =
+ reinterpret_cast<const RawInt8Array*>(raw_obj);
+ WritePrimitiveArrayDump(raw_int8_array,
+ kByte,
+ &raw_int8_array->data_[0]);
+ break;
+ }
+ case Int16Array::kInstanceKind:
+ case Uint16Array::kInstanceKind: {
+ const RawInt16Array* raw_int16_array =
+ reinterpret_cast<const RawInt16Array*>(raw_obj);
+ WritePrimitiveArrayDump(raw_int16_array,
+ kShort,
+ &raw_int16_array->data_[0]);
+ break;
+ }
+ case Int32Array::kInstanceKind:
+ case Uint32Array::kInstanceKind: {
+ const RawInt32Array* raw_int32_array =
+ reinterpret_cast<const RawInt32Array*>(raw_obj);
+ WritePrimitiveArrayDump(raw_int32_array,
+ kInt,
+ &raw_int32_array->data_[0]);
+ break;
+ }
+ case Int64Array::kInstanceKind:
+ case Uint64Array::kInstanceKind: {
+ const RawInt64Array* raw_int64_array =
+ reinterpret_cast<const RawInt64Array*>(raw_obj);
+ WritePrimitiveArrayDump(raw_int64_array,
+ kLong,
+ &raw_int64_array->data_[0]);
+ break;
+ }
+ case Float32Array::kInstanceKind: {
+ const RawFloat32Array* raw_float32_array =
+ reinterpret_cast<const RawFloat32Array*>(raw_obj);
+ WritePrimitiveArrayDump(raw_float32_array,
+ kFloat,
+ &raw_float32_array->data_[0]);
+ break;
+ }
+ case Float64Array::kInstanceKind: {
+ const RawFloat64Array* raw_float64_array =
+ reinterpret_cast<const RawFloat64Array*>(raw_obj);
+ WritePrimitiveArrayDump(raw_float64_array,
+ kDouble,
+ &raw_float64_array->data_[0]);
+ break;
+ }
+ case OneByteString::kInstanceKind:
+ case TwoByteString::kInstanceKind:
+ case FourByteString::kInstanceKind:
+ case ExternalOneByteString::kInstanceKind:
+ case ExternalTwoByteString::kInstanceKind:
+ case ExternalFourByteString::kInstanceKind: {
+ WriteInstanceDump(StringId(reinterpret_cast<const RawString*>(raw_obj)));
+ break;
+ }
+ default:
+ WriteInstanceDump(raw_obj);
+ }
+}
+
+
+void HeapProfiler::Write(const void* data, intptr_t size) {
+ (*write_callback_)(data, size, output_stream_);
+}
+
+
+// Header
+//
+// Format:
+// [u1]* - format name
+// u4 - size of identifiers
+// u4 - high word of number of milliseconds since 0:00 GMT, 1/1/70
+// u4 - low word of number of milliseconds since 0:00 GMT, 1/1/70
+void HeapProfiler::WriteHeader() {
+ const char magic[] = "JAVA PROFILE 1.0.1";
+ Write(magic, sizeof(magic));
+ uint32_t size = htonl(kWordSize);
+ Write(&size, sizeof(size));
+ uint64_t milliseconds = OS::GetCurrentTimeMillis();
+ uint32_t hi = htonl((uint32_t)((milliseconds >> 32) & 0x00000000FFFFFFFF));
+ Write(&hi, sizeof(hi));
+ uint32_t lo = htonl((uint32_t)(milliseconds & 0x00000000FFFFFFFF));
+ Write(&lo, sizeof(lo));
+}
+
+
+// Record
+//
+// Format:
+// 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 u4 field and belong
+// to this record
+// [u1]* - BODY: as many bytes as specified in the above u4 field
+void HeapProfiler::WriteRecord(const Record& record) {
+ uint8_t tag = record.Tag();
+ Write(&tag, sizeof(tag));
+ uint32_t time = htonl(record.Time());
+ Write(&time, sizeof(time));
+ uint32_t length = htonl(record.Length());
+ Write(&length, sizeof(length));
+ Write(record.Body(), record.Length());
+}
+
+
+// STRING IN UTF8 - 0x01
+//
+// Format:
+// ID - ID for this string
+// [u1]* - UTF8 characters for string (NOT NULL terminated)
+void HeapProfiler::WriteStringInUtf8(const RawString* raw_string) {
+ intptr_t length = 0;
+ char* characters = NULL;
+ ObjectKind kind = raw_string->ptr()->class_->ptr()->instance_kind_;
+ if (kind == OneByteString::kInstanceKind) {
+ const RawOneByteString* onestr =
+ reinterpret_cast<const RawOneByteString*>(raw_string);
+ for (intptr_t i = 0; i < Smi::Value(onestr->ptr()->length_); ++i) {
+ length += Utf8::Length(onestr->ptr()->data_[i]);
+ }
+ characters = new char[length];
+ for (intptr_t i = 0, j = 0; i < Smi::Value(onestr->ptr()->length_); ++i) {
+ int32_t ch = onestr->ptr()->data_[i];
+ j += Utf8::Encode(ch, &characters[j]);
+ }
+ } else if (kind == TwoByteString::kInstanceKind) {
+ const RawTwoByteString* twostr =
+ reinterpret_cast<const RawTwoByteString*>(raw_string);
+ for (intptr_t i = 0; i < Smi::Value(twostr->ptr()->length_); ++i) {
+ length += Utf8::Length(twostr->ptr()->data_[i]);
+ }
+ characters = new char[length];
+ for (intptr_t i = 0, j = 0; i < Smi::Value(twostr->ptr()->length_); ++i) {
+ int32_t ch = twostr->ptr()->data_[i];
+ j += Utf8::Encode(ch, &characters[j]);
+ }
+ } else {
+ ASSERT(kind == FourByteString::kInstanceKind);
+ const RawFourByteString* fourstr =
+ reinterpret_cast<const RawFourByteString*>(raw_string);
+ for (intptr_t i = 0; i < Smi::Value(fourstr->ptr()->length_); ++i) {
+ length += Utf8::Length(fourstr->ptr()->data_[i]);
+ }
+ characters = new char[length];
+ for (intptr_t i = 0, j = 0; i < Smi::Value(fourstr->ptr()->length_); ++i) {
+ int32_t ch = fourstr->ptr()->data_[i];
+ j += Utf8::Encode(ch, &characters[j]);
+ }
+ }
+ Record record(kStringInUtf8, this);
+ record.WritePointer(ObjectId(raw_string));
+ for (intptr_t i = 0; i < length; ++i) {
+ record.Write8(characters[i]);
+ }
+ delete[] characters;
+}
+
+
+void HeapProfiler::WriteStringInUtf8(const char* c_string) {
+ Record record(kStringInUtf8, this);
+ record.WritePointer(c_string);
+ for (; *c_string != '\0'; ++c_string) {
+ record.Write8(*c_string);
+ }
+}
+
+
+// LOAD CLASS - 0x02
+//
+// Format:
+// u4 - class serial number (always > 0)
+// ID - class object ID
+// u4 - stack trace serial number
+// ID - class name string ID
+void HeapProfiler::WriteLoadClass(const RawClass* raw_class) {
+ Record record(kLoadClass, this);
+ // class serial number (always > 0)
+ record.Write32(1);
+ // class object ID
+ record.WritePointer(raw_class);
+ // stack trace serial number
+ record.Write32(0);
+ if (raw_class->ptr()->name_ == String::null()) {
+ intptr_t class_index = Object::GetSingletonClassIndex(raw_class);
+ const char* name = Object::GetSingletonClassName(class_index);
+ record.WritePointer(StringId(name));
+ } else {
+ record.WritePointer(StringId(raw_class->ptr()->name_));
+ }
+}
+
+
+// STACK TRACE - 0x05
+//
+// u4 - stack trace serial number
+// u4 - thread serial number
+// u4 - number of frames
+// [ID]* - series of stack frame ID's
+void HeapProfiler::WriteStackTrace() {
+ Record record(kStackTrace, this);
+ // stack trace serial number
+ record.Write32(0);
+ // thread serial number
+ record.Write32(0);
+ // number of frames
+ record.Write32(0);
+}
+
+
+// HEAP SUMMARY - 0x07
+//
+// Format:
+// u4 - total live bytes
+// u4 - total live instances
+// u8 - total bytes allocated
+// u8 - total instances allocated
+void HeapProfiler::WriteHeapSummary(uint32_t total_live_bytes,
+ uint32_t total_live_instances,
+ uint64_t total_bytes_allocated,
+ uint64_t total_instances_allocated) {
+ Record record(kHeapSummary, this);
+ record.Write32(total_live_bytes);
+ record.Write32(total_live_instances);
+ record.Write32(total_bytes_allocated);
+ record.Write32(total_instances_allocated);
+}
+
+
+// HEAP DUMP - 0x0C
+//
+// Format:
+// []*
+void HeapProfiler::WriteHeapDump() {
+ Record record(kHeapDump, this);
+}
+
+
+// CLASS DUMP - 0x20
+//
+// Format:
+// ID - class object ID
+// u4 - stack trace serial number
+// ID - super class object ID
+// ID - class loader object ID
+// ID - signers object ID
+// ID - protection domain object ID
+// ID - reserved
+// ID - reserved
+// u4 - instance size (in bytes)
+// u2 - size of constant pool and number of records that follow:
+// u2 - constant pool index
+// u1 - type of entry: (See Basic Type)
+// value - value of entry (u1, u2, u4, or u8 based on type of entry)
+// u2 - Number of static fields:
+// ID - static field name string ID
+// u1 - type of field: (See Basic Type)
+// value - value of entry (u1, u2, u4, or u8 based on type of field)
+// u2 - Number of instance fields (not including super class's)
+// ID - field name string ID
+// u1 - type of field: (See Basic Type)
+void HeapProfiler::WriteClassDump(const RawClass* raw_class) {
+ SubRecord sub(kClassDump, this);
+ // class object ID
+ sub.WritePointer(ClassId(raw_class));
+ // stack trace serial number
+ sub.Write32(0);
+ // super class object ID
+ if (raw_class == raw_class->ptr()->class_) {
+ sub.WritePointer(NULL);
+ } else {
+ sub.WritePointer(ClassId(raw_class->ptr()->class_));
+ }
+ // class loader object ID
+ sub.WritePointer(NULL);
+ // signers object ID
+ sub.WritePointer(NULL);
+ // protection domain object ID
+ sub.WritePointer(NULL);
+ // reserved
+ sub.WritePointer(NULL);
+ // reserved
+ sub.WritePointer(NULL);
+
+ intptr_t num_static_fields = 0;
+ intptr_t num_instance_fields = 0;
+
+ RawArray* raw_array = raw_class->ptr()->fields_;
+ if (raw_array != Array::null()) {
+ for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) {
+ RawField* raw_field =
+ reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
+ if (raw_field->ptr()->is_static_) {
+ ++num_static_fields;
+ } else {
+ ++num_instance_fields;
+ }
+ }
+ }
+ // instance size (in bytes)
+ sub.Write32(sizeof(RawClass));
turnidge 2012/06/12 17:02:19 What is the instance size supposed to mean for a c
cshapiro 2012/06/14 00:08:36 It is the size of instances, not the size of the c
+ // size of constant pool and number of records that follow:
+ sub.Write16(0);
+ // Number of static fields
+ sub.Write16(num_static_fields);
+ // Static fields:
+ if (raw_array != Array::null()) {
+ for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) {
+ RawField* raw_field =
+ reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
+ if (raw_field->ptr()->is_static_) {
+ ASSERT(raw_field->ptr()->name_ != String::null());
+ // static field name string ID
+ sub.WritePointer(StringId(raw_field->ptr()->name_));
+ // type of static field
+ sub.Write8(kObject);
+ // value of entry
+ sub.WritePointer(ObjectId(raw_field->ptr()->value_));
+ }
+ }
+ }
+ // Number of instance fields (not include super class's)
+ sub.Write16(num_instance_fields);
+ // Instance fields:
+ if (raw_array != Array::null()) {
+ for (intptr_t i = 0; i < Smi::Value(raw_array->ptr()->length_); ++i) {
+ RawField* raw_field =
+ reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
+ if (!raw_field->ptr()->is_static_) {
+ ASSERT(raw_field->ptr()->name_ != String::null());
+ // field name string ID
+ sub.WritePointer(StringId(raw_field->ptr()->name_));
+ // type of field
+ sub.Write8(kObject);
+ }
+ }
+ }
+}
+
+
+// INSTANCE DUMP - 0x21
+//
+// Format:
+// ID - object ID
+// u4 - stack trace serial number
+// ID - class object ID
+// u4 - number of bytes that follow
+// [value]* - instance field values (this class, followed by super class, etc)
+void HeapProfiler::WriteInstanceDump(const RawObject* raw_obj) {
+ SubRecord sub(kInstanceDump, this);
+ // object ID
+ sub.WritePointer(raw_obj);
+ // stack trace serial number
+ sub.Write32(0);
+ // class object ID
+ sub.WritePointer(ClassId(raw_obj->ptr()->class_));
+ // number of bytes that follow
+ intptr_t num_instance_fields = 0;
+ for (RawClass* cls = raw_obj->ptr()->class_;
+ cls != cls->ptr()->class_;
+ cls = cls->ptr()->class_) {
+ RawArray* raw_array = cls->ptr()->fields_;
+ if (raw_array != Array::null()) {
+ intptr_t length = Smi::Value(raw_array->ptr()->length_);
+ for (intptr_t i = 0; i < length; ++i) {
+ RawField* raw_field =
+ reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
+ if (!raw_field->ptr()->is_static_) {
+ ++num_instance_fields;
+ }
+ }
+ }
+ }
+ sub.Write32(num_instance_fields * kWordSize);
+ // instance field values (this class, followed by super class, etc)
+ for (RawClass* cls = raw_obj->ptr()->class_;
+ cls != cls->ptr()->class_;
+ cls = cls->ptr()->class_) {
+ RawArray* raw_array = cls->ptr()->fields_;
+ if (raw_array != Array::null()) {
+ intptr_t length = Smi::Value(raw_array->ptr()->length_);
+ uint8_t* base = reinterpret_cast<uint8_t*>(raw_obj->ptr());
+ for (intptr_t i = 0; i < length; ++i) {
+ RawField* raw_field =
+ reinterpret_cast<RawField*>(raw_array->ptr()->data()[i]);
+ if (!raw_field->ptr()->is_static_) {
+ intptr_t offset =
+ Smi::Value(reinterpret_cast<RawSmi*>(raw_field->ptr()->value_));
+ RawObject* ptr = *reinterpret_cast<RawObject**>(base + offset);
+ sub.WritePointer(ObjectId(ptr));
+ }
+ }
+ }
+ }
+}
+
+
+// OBJECT ARRAY DUMP - 0x22
+//
+// Format:
+// ID - array object ID
+// u4 - stack trace serial number
+// u4 - number of elements
+// ID - array class object ID
+// [ID]* - elements
+void HeapProfiler::WriteObjectArrayDump(const RawArray* raw_array) {
+ SubRecord sub(kObjectArrayDump, this);
+ // array object ID
+ sub.WritePointer(raw_array);
+ // stack trace serial number
+ sub.Write32(0);
+ // number of elements
+ intptr_t length = Smi::Value(raw_array->ptr()->length_);
+ sub.Write32(length);
+ // array class object ID
+ sub.WritePointer(NULL);
+ // elements
+ for (intptr_t i = 0; i < length; ++i) {
+ sub.WritePointer(ObjectId(raw_array->ptr()->data()[i]));
+ }
+}
+
+
+// PRIMITIVE ARRAY DUMP - 0x23
+//
+// Format:
+// ID - array object ID
+// u4 - stack trace serial number
+// u4 - number of elements
+// u1 - element type
+// [u1]* - elements
+void HeapProfiler::WritePrimitiveArrayDump(const RawByteArray* raw_byte_array,
+ uint8_t tag,
+ const void* data) {
+ SubRecord sub(kPrimitiveArrayDump, this);
+ // array object ID
+ sub.WritePointer(raw_byte_array);
+ // stack trace serial number
+ sub.Write32(0);
+ // number of elements
+ intptr_t length = Smi::Value(raw_byte_array->ptr()->length_);
+ sub.Write32(length);
+ // element type
+ sub.Write8(tag);
+ // elements (packed)
+ for (intptr_t i = 0; i < length; ++i) {
+ if (tag == kByte) {
+ sub.Write8(reinterpret_cast<const int8_t*>(data)[i]);
+ } else if (tag == kShort) {
+ sub.Write16(reinterpret_cast<const int16_t*>(data)[i]);
+ break;
+ } else if (tag == kInt || tag == kFloat) {
+ sub.Write32(reinterpret_cast<const int32_t*>(data)[i]);
+ } else {
+ ASSERT(tag == kLong || tag == kDouble);
+ sub.Write64(reinterpret_cast<const int64_t*>(data)[i]);
+ }
+ }
+}
+
+
+void HeapProfilerRootVisitor::VisitPointers(RawObject** first,
+ RawObject** last) {
+ for (RawObject** current = first; current <= last; current++) {
+ RawObject* raw_obj = *current;
+ if (raw_obj->IsHeapObject()) {
+ // Skip visits of FreeListElements.
+ if (FreeListElement::IsSpecialClass(raw_obj)) {
+ // Only the class of the free list element should ever be visited.
+ ASSERT(first == last);
+ return;
+ }
+ uword obj_addr = RawObject::ToAddr(raw_obj);
+ if (!Isolate::Current()->heap()->Contains(obj_addr) &&
+ !Dart::vm_isolate()->heap()->Contains(obj_addr)) {
+ FATAL1("Invalid object pointer encountered 0x%lx\n", obj_addr);
+ }
+ }
+ profiler_->WriteRoot(raw_obj);
+ }
+}
+
+
+void HeapProfilerWeakRootVisitor::VisitHandle(uword addr) {
+ FinalizablePersistentHandle* handle =
+ reinterpret_cast<FinalizablePersistentHandle*>(addr);
+ RawObject* raw_obj = handle->raw();
+ visitor_->VisitPointer(&raw_obj);
+}
+
+
+void HeapProfilerObjectVisitor::VisitObject(RawObject* raw_obj) {
+ profiler_->WriteObject(raw_obj);
+}
+
+} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698