test-heap-profiler.cc revision a7e24c173cf37484693b9abb38e494fa7bd7baeb
1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Copyright 2009 the V8 project authors. All rights reserved.
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block//
3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Tests for heap profiler
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef ENABLE_LOGGING_AND_PROFILING
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "heap-profiler.h"
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "string-stream.h"
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "cctest.h"
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace i = v8::internal;
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::ClustersCoarser;
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsCluster;
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsRetainerTree;
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsClusterTree;
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::RetainerHeapProfile;
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CompileAndRunScript(const char *src) {
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Script::Compile(v8::String::New(src))->Run();
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace {
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ConstructorHeapProfileTestHelper()
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : i::ConstructorHeapProfile(),
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))),
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_count_(0) {
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Call(const JSObjectsCluster& cluster,
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            const i::NumberAndSizeInfo& number_and_size) {
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (f_name_->Equals(cluster.constructor())) {
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CHECK_EQ(f_count_, 0);
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_count_ = number_and_size.number();
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CHECK_GT(f_count_, 0);
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int f_count() { return f_count_; }
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::Handle<i::String> f_name_;
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int f_count_;
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ConstructorProfile) {
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Handle<v8::Context> env = v8::Context::New();
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileAndRunScript(
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function F() {}  // A constructor\n"
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var f1 = new F();\n"
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var f2 = new F();\n");
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ConstructorHeapProfileTestHelper cons_profile;
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::AssertNoAllocation no_alloc;
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapIterator iterator;
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (iterator.has_next()) {
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::HeapObject* obj = iterator.next();
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cons_profile.CollectStats(obj);
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, cons_profile.f_count());
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cons_profile.PrintStats();
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(2, cons_profile.f_count());
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree,
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            i::String* constructor,
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            int instance,
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSObjectsCluster* ref1 = NULL,
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSObjectsCluster* ref2 = NULL,
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSObjectsCluster* ref3 = NULL) {
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsClusterTree::Locator o_loc;
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc);
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc);
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc);
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree::Locator loc;
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  tree->Insert(o, &loc);
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  loc.set_value(o_tree);
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return o;
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void AddSelfReferenceToTree(JSObjectsRetainerTree* tree,
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   JSObjectsCluster* self_ref) {
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree::Locator loc;
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(tree->Find(*self_ref, &loc));
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsClusterTree::Locator o_loc;
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(NULL, loc.value());
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  loc.value()->Insert(*self_ref, &o_loc);
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic inline void CheckEqualsHelper(const char* file, int line,
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* expected_source,
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& expected,
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* value_source,
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& value) {
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (JSObjectsCluster::Compare(expected, value) != 0) {
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::HeapStringAllocator allocator;
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::StringStream stream(&allocator);
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("#  Expected: ");
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    expected.DebugPrint(&stream);
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("\n#  Found: ");
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    value.DebugPrint(&stream);
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s",
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             expected_source, value_source,
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             *stream.ToCString());
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic inline void CheckNonEqualsHelper(const char* file, int line,
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* expected_source,
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& expected,
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* value_source,
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& value) {
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (JSObjectsCluster::Compare(expected, value) == 0) {
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::HeapStringAllocator allocator;
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::StringStream stream(&allocator);
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("# !Expected: ");
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    expected.DebugPrint(&stream);
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("\n#  Found: ");
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    value.DebugPrint(&stream);
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s",
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             expected_source, value_source,
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             *stream.ToCString());
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserSimple) {
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Handle<v8::Context> env = v8::Context::New();
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster function(i::Heap::function_class_symbol());
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A")));
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B")));
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o3 <- A, B
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o3 =
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b);
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o4 <- B, A
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o4 =
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a);
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o5 <- A, B, Function
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o5 =
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500,
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &a, &b, &function);
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserMultipleConstructors) {
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Handle<v8::Context> env = v8::Context::New();
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster function(i::Heap::function_class_symbol());
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a1 <- Function
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a1 =
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function);
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a2 <- Function
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a2 =
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function);
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserPathsTraversal) {
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Handle<v8::Context> env = v8::Context::New();
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // On the following graph:
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // p
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   <- o21 <- o11 <-
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // q                  o
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   <- o22 <- o12 <-
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we expect that coarser will deduce equivalences: p ~ q ~ r,
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o21 ~ o22, and o11 ~ o12.
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o =
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o11 =
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o12 =
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o21 =
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11);
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o22 =
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12);
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21);
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22);
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22);
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserSelf) {
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Handle<v8::Context> env = v8::Context::New();
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // On the following graph:
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // p (self-referencing)
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //          <- o1     <-
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // q (self-referencing)   o
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //          <- o2     <-
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r (self-referencing)
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o =
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1);
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &p);
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1, &o2);
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &q);
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2);
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &r);
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1));
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p));
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace {
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass RetainerProfilePrinter : public RetainerHeapProfile::Printer {
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void PrintRetainers(const JSObjectsCluster& cluster,
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      const i::StringStream& retainers) {
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cluster.Print(&stream_);
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Add("%s", *(retainers.ToCString()));
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Put('\0');
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* GetRetainers(const char* constructor) {
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    FillLines();
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const size_t cons_len = strlen(constructor);
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for (int i = 0; i < lines_.length(); ++i) {
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (strncmp(constructor, lines_[i], cons_len) == 0 &&
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          lines_[i][cons_len] == ',') {
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return lines_[i] + cons_len + 1;
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void FillLines() {
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (lines_.length() > 0) return;
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Put('\0');
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_str_ = stream_.ToCString();
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const char* pos = *stream_str_;
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    while (pos != NULL && *pos != '\0') {
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      lines_.Add(pos);
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      pos = strchr(pos, '\0');
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (pos != NULL) ++pos;
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapStringAllocator allocator_;
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::StringStream stream_;
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::SmartPointer<const char> stream_str_;
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::List<const char*> lines_;
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(RetainerProfile) {
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Handle<v8::Context> env = v8::Context::New();
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileAndRunScript(
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function A() {}\n"
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function B(x) { this.x = x; }\n"
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function C(x) { this.x1 = x; this.x2 = x; }\n"
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var a = new A();\n"
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var b1 = new B(a), b2 = new B(a);\n"
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var c = new C(a);");
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerHeapProfile ret_profile;
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::AssertNoAllocation no_alloc;
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapIterator iterator;
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while (iterator.has_next()) {
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::HeapObject* obj = iterator.next();
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ret_profile.CollectStats(obj);
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerProfilePrinter printer;
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ret_profile.DebugPrintStats(&printer);
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* retainers_of_a = printer.GetRetainers("A");
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The order of retainers is unspecified, so we check string length, and
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // verify each retainer separately.
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(static_cast<int>(strlen("(global property);1,B;2,C;2")),
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block           static_cast<int>(strlen(retainers_of_a)));
389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "(global property);1") != NULL);
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "B;2") != NULL);
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "C;2") != NULL);
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ("(global property);2", printer.GetRetainers("B"));
393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ("(global property);1", printer.GetRetainers("C"));
394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // ENABLE_LOGGING_AND_PROFILING
397