test-heap-profiler.cc revision 3bec4d28b1f388dbc06a9c4276e1a03e86c52b04
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"
99dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen#include "snapshot.h"
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "string-stream.h"
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "cctest.h"
126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block#include "zone-inl.h"
139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen#include "../include/v8-profiler.h"
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace i = v8::internal;
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::ClustersCoarser;
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsCluster;
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsRetainerTree;
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::JSObjectsClusterTree;
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing i::RetainerHeapProfile;
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CompileAndRunScript(const char *src) {
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::Script::Compile(v8::String::New(src))->Run();
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace {
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ConstructorHeapProfileTestHelper()
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : i::ConstructorHeapProfile(),
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))),
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_count_(0) {
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Call(const JSObjectsCluster& cluster,
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            const i::NumberAndSizeInfo& number_and_size) {
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (f_name_->Equals(cluster.constructor())) {
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CHECK_EQ(f_count_, 0);
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_count_ = number_and_size.number();
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CHECK_GT(f_count_, 0);
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int f_count() { return f_count_; }
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::Handle<i::String> f_name_;
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int f_count_;
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ConstructorProfile) {
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileAndRunScript(
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function F() {}  // A constructor\n"
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var f1 = new F();\n"
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var f2 = new F();\n");
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ConstructorHeapProfileTestHelper cons_profile;
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::AssertNoAllocation no_alloc;
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapIterator iterator;
69d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cons_profile.CollectStats(obj);
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;
1463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster function(i::Heap::function_class_symbol());
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A")));
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B")));
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o3 <- A, B
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o3 =
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b);
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o4 <- B, A
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o4 =
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a);
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o5 <- A, B, Function
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o5 =
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500,
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &a, &b, &function);
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserMultipleConstructors) {
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
1843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster function(i::Heap::function_class_symbol());
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a1 <- Function
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a1 =
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function);
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a2 <- Function
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a2 =
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function);
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserPathsTraversal) {
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
2143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // On the following graph:
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // p
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   <- o21 <- o11 <-
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // q                  o
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   <- o22 <- o12 <-
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we expect that coarser will deduce equivalences: p ~ q ~ r,
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o21 ~ o22, and o11 ~ o12.
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o =
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o11 =
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o12 =
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o21 =
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11);
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o22 =
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12);
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21);
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22);
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22);
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserSelf) {
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
2663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // On the following graph:
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // p (self-referencing)
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //          <- o1     <-
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // q (self-referencing)   o
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //          <- o2     <-
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r (self-referencing)
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o =
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1);
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &p);
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1, &o2);
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &q);
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2);
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &r);
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1));
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p));
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace {
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass RetainerProfilePrinter : public RetainerHeapProfile::Printer {
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void PrintRetainers(const JSObjectsCluster& cluster,
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      const i::StringStream& retainers) {
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cluster.Print(&stream_);
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Add("%s", *(retainers.ToCString()));
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Put('\0');
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* GetRetainers(const char* constructor) {
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    FillLines();
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const size_t cons_len = strlen(constructor);
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for (int i = 0; i < lines_.length(); ++i) {
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (strncmp(constructor, lines_[i], cons_len) == 0 &&
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          lines_[i][cons_len] == ',') {
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return lines_[i] + cons_len + 1;
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void FillLines() {
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (lines_.length() > 0) return;
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Put('\0');
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_str_ = stream_.ToCString();
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const char* pos = *stream_str_;
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    while (pos != NULL && *pos != '\0') {
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      lines_.Add(pos);
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      pos = strchr(pos, '\0');
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (pos != NULL) ++pos;
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapStringAllocator allocator_;
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::StringStream stream_;
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::SmartPointer<const char> stream_str_;
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::List<const char*> lines_;
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(RetainerProfile) {
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
3603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileAndRunScript(
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function A() {}\n"
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function B(x) { this.x = x; }\n"
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function C(x) { this.x1 = x; this.x2 = x; }\n"
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var a = new A();\n"
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var b1 = new B(a), b2 = new B(a);\n"
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var c = new C(a);");
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerHeapProfile ret_profile;
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::AssertNoAllocation no_alloc;
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapIterator iterator;
373d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ret_profile.CollectStats(obj);
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerProfilePrinter printer;
376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ret_profile.DebugPrintStats(&printer);
377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* retainers_of_a = printer.GetRetainers("A");
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The order of retainers is unspecified, so we check string length, and
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // verify each retainer separately.
380d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"),
381d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block           i::StrLength(retainers_of_a));
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "(global property);1") != NULL);
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "B;2") != NULL);
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "C;2") != NULL);
385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ("(global property);2", printer.GetRetainers("B"));
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ("(global property);1", printer.GetRetainers("C"));
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
3909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsennamespace {
3919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
3929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenclass NamedEntriesDetector {
3939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen public:
3949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  NamedEntriesDetector()
3959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      : has_A1(false), has_B1(false), has_C1(false),
3969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        has_A2(false), has_B2(false), has_C2(false) {
3979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
3989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
3999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  void Apply(i::HeapEntry* entry) {
4009dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const char* node_name = entry->name();
4019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("A1", node_name) == 0
4029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && entry->GetRetainingPaths()->length() > 0) has_A1 = true;
4039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("B1", node_name) == 0
4049dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && entry->GetRetainingPaths()->length() > 0) has_B1 = true;
4059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("C1", node_name) == 0
4069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && entry->GetRetainingPaths()->length() > 0) has_C1 = true;
4079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("A2", node_name) == 0
4089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && entry->GetRetainingPaths()->length() > 0) has_A2 = true;
4099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("B2", node_name) == 0
4109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && entry->GetRetainingPaths()->length() > 0) has_B2 = true;
4119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("C2", node_name) == 0
4129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && entry->GetRetainingPaths()->length() > 0) has_C2 = true;
4139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
4149dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_A1;
4169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_B1;
4179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_C1;
4189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_A2;
4199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_B2;
4209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_C2;
4219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen};
4229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}  // namespace
4249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic const v8::HeapGraphNode* GetGlobalObject(
4279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapSnapshot* snapshot) {
4283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ(1, snapshot->GetRoot()->GetChildrenCount());
4293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  return snapshot->GetRoot()->GetChild(0)->GetToNode();
4309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4319dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4329dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4339dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
4349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                            v8::HeapGraphEdge::Type type,
4359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                            const char* name) {
4369dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
4379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = node->GetChild(i);
4389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    v8::String::AsciiValue prop_name(prop->GetName());
4399dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
4409dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      return prop->GetToNode();
4419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
4429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  return NULL;
4439dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdochstatic bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
4473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                             v8::HeapGraphEdge::Type type,
4483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                             const char* name) {
4493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
4503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphEdge* prop = node->GetRetainer(i);
4513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    v8::String::AsciiValue prop_name(prop->GetName());
4523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
4533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      return true;
4543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  }
4553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  return false;
4563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
4573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
4583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
4599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic bool HasString(const v8::HeapGraphNode* node, const char* contents) {
4609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
4619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = node->GetChild(i);
4629dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
4639dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (node->GetType() == v8::HeapGraphNode::STRING) {
4649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::String::AsciiValue node_name(node->GetName());
4659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (strcmp(contents, *node_name) == 0) return true;
4669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
4679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
4689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  return false;
4699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4719dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4729dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshot) {
4739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::HandleScope scope;
4749dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::Handle<v8::String> token1 = v8::String::New("token1");
4753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env1;
4769dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  env1->SetSecurityToken(token1);
4779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CompileAndRunScript(
4799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function A1() {}\n"
4809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function B1(x) { this.x = x; }\n"
4819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function C1(x) { this.x1 = x; this.x2 = x; }\n"
4829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var a1 = new A1();\n"
4839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var b1_1 = new B1(a1), b1_2 = new B1(a1);\n"
4849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var c1 = new C1(a1);");
4859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4869dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::Handle<v8::String> token2 = v8::String::New("token2");
4873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env2;
4889dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  env2->SetSecurityToken(token2);
4899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CompileAndRunScript(
4919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function A2() {}\n"
4929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function B2(x) { return function() { return typeof x; }; }\n"
4939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
4949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var a2 = new A2();\n"
4959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
4969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var c2 = new C2(a2);");
4979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapSnapshot* snapshot_env2 =
4989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
4999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
5009dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Verify, that JS global object of env2 doesn't have '..1'
5029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // properties, but has '..2' properties.
5039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a1"));
5049dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_1"));
5059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b1_2"));
5069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c1"));
5079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* a2_node =
5089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "a2");
5099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, a2_node);
5109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_1"));
5119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "b2_2"));
5129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::PROPERTY, "c2"));
5139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5149dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Verify that anything related to '[ABC]1' is not reachable.
5159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  NamedEntriesDetector det;
5169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  i::HeapSnapshot* i_snapshot_env2 =
5179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      const_cast<i::HeapSnapshot*>(
5189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen          reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
5199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  i_snapshot_env2->IterateEntries(&det);
5209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(!det.has_A1);
5219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(!det.has_B1);
5229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(!det.has_C1);
5239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_A2);
5249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_B2);
5259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_C2);
5269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Verify 'a2' object retainers. They are:
5289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  - (global object).a2
5299dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  - c2.x1, c2.x2, c2[1]
5309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  - b2_1 and b2_2 closures: via 'x' variable
5319dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(6, a2_node->GetRetainingPathsCount());
5329dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_global_obj_a2_ref = false;
5339dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false;
5349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_b2_1_x_ref = false, has_b2_2_x_ref = false;
5359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) {
5369dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i);
5379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const int edges_count = path->GetEdgesCount();
5389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    CHECK_GT(edges_count, 0);
5399dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* last_edge = path->GetEdge(edges_count - 1);
5409dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    v8::String::AsciiValue last_edge_name(last_edge->GetName());
5419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("a2", *last_edge_name) == 0
5429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY) {
5439dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      has_global_obj_a2_ref = true;
5449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      continue;
5459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
5469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    CHECK_GT(edges_count, 1);
5479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prev_edge = path->GetEdge(edges_count - 2);
5489dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    v8::String::AsciiValue prev_edge_name(prev_edge->GetName());
5499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x1", *last_edge_name) == 0
5509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY
5519dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("c2", *prev_edge_name) == 0) has_c2_x1_ref = true;
5529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x2", *last_edge_name) == 0
5539dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY
5549dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("c2", *prev_edge_name) == 0) has_c2_x2_ref = true;
5559dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("1", *last_edge_name) == 0
5569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && last_edge->GetType() == v8::HeapGraphEdge::ELEMENT
5579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("c2", *prev_edge_name) == 0) has_c2_1_ref = true;
5589dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x", *last_edge_name) == 0
5599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && last_edge->GetType() == v8::HeapGraphEdge::CONTEXT_VARIABLE
5609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("b2_1", *prev_edge_name) == 0) has_b2_1_x_ref = true;
5619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x", *last_edge_name) == 0
5629dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && last_edge->GetType() == v8::HeapGraphEdge::CONTEXT_VARIABLE
5639dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true;
5649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
5659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_global_obj_a2_ref);
5669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_c2_x1_ref);
5679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_c2_x2_ref);
5689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_c2_1_ref);
5699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_b2_1_x_ref);
5709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_b2_2_x_ref);
5719dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
5729dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5749dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshotCodeObjects) {
5759dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::HandleScope scope;
5763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
5779dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CompileAndRunScript(
5799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function lazy(x) { return x - 1; }\n"
5809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function compiled(x) { return x + 1; }\n"
5819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "compiled(1)");
5829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapSnapshot* snapshot =
5839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("code"));
5849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
5869dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* compiled =
5879dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      GetProperty(global, v8::HeapGraphEdge::PROPERTY, "compiled");
5889dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, compiled);
5899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(v8::HeapGraphNode::CLOSURE, compiled->GetType());
5909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* lazy =
5919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      GetProperty(global, v8::HeapGraphEdge::PROPERTY, "lazy");
5929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, lazy);
5939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(v8::HeapGraphNode::CLOSURE, lazy->GetType());
5949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Find references to code.
5969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* compiled_code =
5979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      GetProperty(compiled, v8::HeapGraphEdge::INTERNAL, "code");
5989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, compiled_code);
5999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* lazy_code =
6009dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      GetProperty(lazy, v8::HeapGraphEdge::INTERNAL, "code");
6019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, lazy_code);
6029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
6039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Verify that non-compiled code doesn't contain references to "x"
6043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // literal, while compiled code does. The scope info is stored in FixedArray
6053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // objects attached to the SharedFunctionInfo.
6069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool compiled_references_x = false, lazy_references_x = false;
6079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
6089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
6099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
6103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    if (node->GetType() == v8::HeapGraphNode::ARRAY) {
6119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (HasString(node, "x")) {
6129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        compiled_references_x = true;
6139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        break;
6149dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      }
6159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
6169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
6179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
6189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
6199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
6203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    if (node->GetType() == v8::HeapGraphNode::ARRAY) {
6219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (HasString(node, "x")) {
6229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        lazy_references_x = true;
6239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        break;
6249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      }
6259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
6269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
6279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(compiled_references_x);
6289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(!lazy_references_x);
6299dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
6309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
6313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Trying to introduce a check helper for uint64_t causes many
6333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// overloading ambiguities, so it seems easier just to cast
6343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// them to a signed type.
6353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch#define CHECK_EQ_UINT64_T(a, b) \
6363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b))
6373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch#define CHECK_NE_UINT64_T(a, b) do              \
6383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  {                                             \
6393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    bool ne = a != b;                           \
6403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    CHECK(ne);                                  \
6413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  } while (false)
6423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben MurdochTEST(HeapEntryIdsAndGC) {
6443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  v8::HandleScope scope;
6453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
6463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CompileAndRunScript(
6483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function A() {}\n"
6493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function B(x) { this.x = x; }\n"
6503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var a = new A();\n"
6513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var b = new B(a);");
6523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot1 =
6533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
6543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  i::Heap::CollectAllGarbage(true);  // Enforce compaction.
6563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot2 =
6583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
6593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
6613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
6623bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, global1->GetId());
6633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId());
6643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* A1 =
6653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "A");
6663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* A2 =
6673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "A");
6683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, A1->GetId());
6693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
6703bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* B1 =
6713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "B");
6723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* B2 =
6733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "B");
6743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, B1->GetId());
6753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
6763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* a1 =
6773bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "a");
6783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* a2 =
6793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "a");
6803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, a1->GetId());
6813bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
6823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* b1 =
6833bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global1, v8::HeapGraphEdge::PROPERTY, "b");
6843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* b2 =
6853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      GetProperty(global2, v8::HeapGraphEdge::PROPERTY, "b");
6863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, b1->GetId());
6873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
6883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
6893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben MurdochTEST(HeapSnapshotsDiff) {
6923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  v8::HandleScope scope;
6933bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
6943bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CompileAndRunScript(
6963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function A() {}\n"
6973bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function B(x) { this.x = x; }\n"
6983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var a = new A();\n"
6993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var b = new B(a);");
7003bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot1 =
7013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
7023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CompileAndRunScript(
7043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "delete a;\n"
7053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "b.x = null;\n"
7063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var a = new A();\n"
7073bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var b2 = new B(a);");
7083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot2 =
7093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
7103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshotsDiff* diff = snapshot1->CompareWith(snapshot2);
7123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Verify additions: ensure that addition of A and B was detected.
7143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot();
7153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  bool found_A = false, found_B = false;
7163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  uint64_t s1_A_id = 0;
7173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) {
7183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphEdge* prop = additions_root->GetChild(i);
7193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphNode* node = prop->GetToNode();
7203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    if (node->GetType() == v8::HeapGraphNode::OBJECT) {
7213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::String::AsciiValue node_name(node->GetName());
7223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      if (strcmp(*node_name, "A") == 0) {
7233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::PROPERTY, "a"));
7243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(!found_A);
7253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        found_A = true;
7263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        s1_A_id = node->GetId();
7273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      } else if (strcmp(*node_name, "B") == 0) {
7283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::PROPERTY, "b2"));
7293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(!found_B);
7303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        found_B = true;
7313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      }
7323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    }
7333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  }
7343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(found_A);
7353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(found_B);
7363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Verify deletions: ensure that deletion of A was detected.
7383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot();
7393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  bool found_A_del = false;
7403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  uint64_t s2_A_id = 0;
7413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) {
7423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphEdge* prop = deletions_root->GetChild(i);
7433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphNode* node = prop->GetToNode();
7443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    if (node->GetType() == v8::HeapGraphNode::OBJECT) {
7453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::String::AsciiValue node_name(node->GetName());
7463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      if (strcmp(*node_name, "A") == 0) {
7473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::PROPERTY, "a"));
7483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(!found_A_del);
7493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        found_A_del = true;
7503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        s2_A_id = node->GetId();
7513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      }
7523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    }
7533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  }
7543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(found_A_del);
7553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, s1_A_id);
7563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(s1_A_id != s2_A_id);
7573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
7583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // ENABLE_LOGGING_AND_PROFILING
760