Index: test/cctest/test-heap-profiler.cc |
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc |
index ad242fe79c1bb0a8d9ebd1d0d35dd42ae84a0833..f1e9fcde2515bacf143c797abcc52227b80599f6 100644 |
--- a/test/cctest/test-heap-profiler.cc |
+++ b/test/cctest/test-heap-profiler.cc |
@@ -1258,4 +1258,141 @@ TEST(TakeHeapSnapshotAborting) { |
CHECK_GT(control.total(), 0); |
} |
+ |
+namespace { |
+ |
+class TestRetainedObjectInfo : public v8::RetainedObjectInfo { |
+ public: |
+ TestRetainedObjectInfo(int hash, |
+ const char* label, |
+ intptr_t element_count = -1, |
+ intptr_t size = -1) |
+ : disposed_(false), |
+ hash_(hash), |
+ label_(label), |
+ element_count_(element_count), |
+ size_(size) { |
+ instances.Add(this); |
+ } |
+ virtual ~TestRetainedObjectInfo() {} |
+ virtual void Dispose() { |
+ CHECK(!disposed_); |
+ disposed_ = true; |
+ } |
+ virtual bool IsEquivalent(RetainedObjectInfo* other) { |
+ return GetHash() == other->GetHash(); |
+ } |
+ virtual intptr_t GetHash() { return hash_; } |
+ virtual const char* GetLabel() { return label_; } |
+ virtual intptr_t GetElementCount() { return element_count_; } |
+ virtual intptr_t GetSizeInBytes() { return size_; } |
+ bool disposed() { return disposed_; } |
+ |
+ static v8::RetainedObjectInfo* WrapperInfoCallback( |
+ uint16_t class_id, v8::Handle<v8::Value> wrapper) { |
+ if (class_id == 1) { |
+ if (wrapper->IsString()) { |
+ v8::String::AsciiValue ascii(wrapper); |
+ if (strcmp(*ascii, "AAA") == 0) |
+ return new TestRetainedObjectInfo(1, "aaa", 100); |
+ else if (strcmp(*ascii, "BBB") == 0) |
+ return new TestRetainedObjectInfo(1, "aaa", 100); |
+ } |
+ } else if (class_id == 2) { |
+ if (wrapper->IsString()) { |
+ v8::String::AsciiValue ascii(wrapper); |
+ if (strcmp(*ascii, "CCC") == 0) |
+ return new TestRetainedObjectInfo(2, "ccc"); |
+ } |
+ } |
+ CHECK(false); |
+ return NULL; |
+ } |
+ |
+ static i::List<TestRetainedObjectInfo*> instances; |
+ |
+ private: |
+ bool disposed_; |
+ int category_; |
+ int hash_; |
+ const char* label_; |
+ intptr_t element_count_; |
+ intptr_t size_; |
+}; |
+ |
+ |
+i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances; |
+} |
+ |
+ |
+static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent, |
+ v8::HeapGraphNode::Type type, |
+ const char* name) { |
+ for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) { |
+ const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode(); |
+ if (node->GetType() == type && strcmp(name, |
+ const_cast<i::HeapEntry*>( |
+ reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) { |
+ return node; |
+ } |
+ } |
+ return NULL; |
+} |
+ |
+ |
+TEST(HeapSnapshotRetainedObjectInfo) { |
+ v8::HandleScope scope; |
+ LocalContext env; |
+ |
+ v8::HeapProfiler::DefineWrapperClass( |
+ 1, TestRetainedObjectInfo::WrapperInfoCallback); |
+ v8::HeapProfiler::DefineWrapperClass( |
+ 2, TestRetainedObjectInfo::WrapperInfoCallback); |
+ v8::Persistent<v8::String> p_AAA = |
+ v8::Persistent<v8::String>::New(v8_str("AAA")); |
+ p_AAA.SetWrapperClassId(1); |
+ v8::Persistent<v8::String> p_BBB = |
+ v8::Persistent<v8::String>::New(v8_str("BBB")); |
+ p_BBB.SetWrapperClassId(1); |
+ v8::Persistent<v8::String> p_CCC = |
+ v8::Persistent<v8::String>::New(v8_str("CCC")); |
+ p_CCC.SetWrapperClassId(2); |
+ CHECK_EQ(0, TestRetainedObjectInfo::instances.length()); |
+ const v8::HeapSnapshot* snapshot = |
+ v8::HeapProfiler::TakeSnapshot(v8::String::New("retained")); |
+ |
+ CHECK_EQ(3, TestRetainedObjectInfo::instances.length()); |
+ for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) { |
+ CHECK(TestRetainedObjectInfo::instances[i]->disposed()); |
+ delete TestRetainedObjectInfo::instances[i]; |
+ } |
+ |
+ const v8::HeapGraphNode* natives = GetNode( |
+ snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(Native objects)"); |
+ CHECK_NE(NULL, natives); |
+ CHECK_EQ(2, natives->GetChildrenCount()); |
+ const v8::HeapGraphNode* aaa = GetNode( |
+ natives, v8::HeapGraphNode::kNative, "aaa / 100 entries"); |
+ CHECK_NE(NULL, aaa); |
+ const v8::HeapGraphNode* ccc = GetNode( |
+ natives, v8::HeapGraphNode::kNative, "ccc"); |
+ CHECK_NE(NULL, ccc); |
+ |
+ CHECK_EQ(2, aaa->GetChildrenCount()); |
+ const v8::HeapGraphNode* n_AAA = GetNode( |
+ aaa, v8::HeapGraphNode::kString, "AAA"); |
+ CHECK_NE(NULL, n_AAA); |
+ const v8::HeapGraphNode* n_BBB = GetNode( |
+ aaa, v8::HeapGraphNode::kString, "BBB"); |
+ CHECK_NE(NULL, n_BBB); |
+ CHECK_EQ(1, ccc->GetChildrenCount()); |
+ const v8::HeapGraphNode* n_CCC = GetNode( |
+ ccc, v8::HeapGraphNode::kString, "CCC"); |
+ CHECK_NE(NULL, n_CCC); |
+ |
+ CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "Native")); |
+ CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "Native")); |
+ CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "Native")); |
+} |
+ |
#endif // ENABLE_LOGGING_AND_PROFILING |