test-heap-profiler.cc revision 8a31eba00023874d4a1dcdc5f411cc4336776874
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 Blocknamespace {
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ConstructorHeapProfileTestHelper()
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    : i::ConstructorHeapProfile(),
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_name_(i::Factory::NewStringFromAscii(i::CStrVector("F"))),
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_count_(0) {
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void Call(const JSObjectsCluster& cluster,
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block            const i::NumberAndSizeInfo& number_and_size) {
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (f_name_->Equals(cluster.constructor())) {
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CHECK_EQ(f_count_, 0);
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      f_count_ = number_and_size.number();
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      CHECK_GT(f_count_, 0);
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int f_count() { return f_count_; }
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::Handle<i::String> f_name_;
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  int f_count_;
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ConstructorProfile) {
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
56f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function F() {}  // A constructor\n"
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var f1 = new F();\n"
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var f2 = new F();\n");
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ConstructorHeapProfileTestHelper cons_profile;
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::AssertNoAllocation no_alloc;
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapIterator iterator;
64d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cons_profile.CollectStats(obj);
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, cons_profile.f_count());
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  cons_profile.PrintStats();
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(2, cons_profile.f_count());
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree,
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            i::String* constructor,
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            int instance,
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSObjectsCluster* ref1 = NULL,
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSObjectsCluster* ref2 = NULL,
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                            JSObjectsCluster* ref3 = NULL) {
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsClusterTree::Locator o_loc;
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc);
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc);
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc);
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree::Locator loc;
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  tree->Insert(o, &loc);
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  loc.set_value(o_tree);
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return o;
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void AddSelfReferenceToTree(JSObjectsRetainerTree* tree,
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                   JSObjectsCluster* self_ref) {
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree::Locator loc;
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(tree->Find(*self_ref, &loc));
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsClusterTree::Locator o_loc;
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(NULL, loc.value());
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  loc.value()->Insert(*self_ref, &o_loc);
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic inline void CheckEqualsHelper(const char* file, int line,
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* expected_source,
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& expected,
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* value_source,
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& value) {
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (JSObjectsCluster::Compare(expected, value) != 0) {
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::HeapStringAllocator allocator;
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::StringStream stream(&allocator);
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("#  Expected: ");
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    expected.DebugPrint(&stream);
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("\n#  Found: ");
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    value.DebugPrint(&stream);
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s",
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             expected_source, value_source,
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             *stream.ToCString());
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic inline void CheckNonEqualsHelper(const char* file, int line,
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* expected_source,
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& expected,
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const char* value_source,
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                     const JSObjectsCluster& value) {
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (JSObjectsCluster::Compare(expected, value) == 0) {
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::HeapStringAllocator allocator;
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    i::StringStream stream(&allocator);
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("# !Expected: ");
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    expected.DebugPrint(&stream);
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream.Add("\n#  Found: ");
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    value.DebugPrint(&stream);
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s",
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             expected_source, value_source,
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             *stream.ToCString());
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserSimple) {
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
1413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster function(i::Heap::function_class_symbol());
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a(*i::Factory::NewStringFromAscii(i::CStrVector("A")));
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster b(*i::Factory::NewStringFromAscii(i::CStrVector("B")));
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o3 <- A, B
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o3 =
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &a, &b);
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o4 <- B, A
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o4 =
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x400, &b, &a);
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o5 <- A, B, Function
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o5 =
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x500,
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                          &a, &b, &function);
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserMultipleConstructors) {
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
1793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster function(i::Heap::function_class_symbol());
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100, &function);
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a1 <- Function
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a1 =
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x1000, &function);
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x200, &function);
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a2 <- Function
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a2 =
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Array_symbol(), 0x2000, &function);
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserPathsTraversal) {
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
2093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // On the following graph:
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // p
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   <- o21 <- o11 <-
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // q                  o
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //   <- o22 <- o12 <-
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we expect that coarser will deduce equivalences: p ~ q ~ r,
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o21 ~ o22, and o11 ~ o12.
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o =
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o11 =
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o12 =
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o21 =
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x210, &o11);
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o22 =
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x220, &o12);
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o21);
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o21, &o22);
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o22);
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(ClustersCoarserSelf) {
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
2613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsRetainerTree tree;
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // On the following graph:
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // p (self-referencing)
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //          <- o1     <-
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // q (self-referencing)   o
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //          <- o2     <-
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // r (self-referencing)
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  //
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o =
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x100);
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x110, &o);
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x120, &o);
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x300, &o1);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &p);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x310, &o1, &o2);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &q);
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      AddHeapObjectToTree(&tree, i::Heap::Object_symbol(), 0x320, &o2);
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &r);
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ClustersCoarser coarser;
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  coarser.Process(&tree);
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1));
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p));
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace {
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass RetainerProfilePrinter : public RetainerHeapProfile::Printer {
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void PrintRetainers(const JSObjectsCluster& cluster,
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                      const i::StringStream& retainers) {
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    cluster.Print(&stream_);
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Add("%s", *(retainers.ToCString()));
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Put('\0');
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* GetRetainers(const char* constructor) {
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    FillLines();
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const size_t cons_len = strlen(constructor);
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for (int i = 0; i < lines_.length(); ++i) {
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (strncmp(constructor, lines_[i], cons_len) == 0 &&
324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          lines_[i][cons_len] == ',') {
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return lines_[i] + cons_len + 1;
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return NULL;
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  void FillLines() {
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (lines_.length() > 0) return;
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_.Put('\0');
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stream_str_ = stream_.ToCString();
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const char* pos = *stream_str_;
337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    while (pos != NULL && *pos != '\0') {
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      lines_.Add(pos);
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      pos = strchr(pos, '\0');
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if (pos != NULL) ++pos;
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapStringAllocator allocator_;
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::StringStream stream_;
346a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::SmartPointer<const char> stream_str_;
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::List<const char*> lines_;
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}  // namespace
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(RetainerProfile) {
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
3553bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
357f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function A() {}\n"
359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function B(x) { this.x = x; }\n"
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function C(x) { this.x1 = x; this.x2 = x; }\n"
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var a = new A();\n"
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var b1 = new B(a), b2 = new B(a);\n"
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "var c = new C(a);");
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerHeapProfile ret_profile;
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::AssertNoAllocation no_alloc;
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::HeapIterator iterator;
368d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    ret_profile.CollectStats(obj);
370791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  ret_profile.CoarseAndAggregate();
371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  RetainerProfilePrinter printer;
372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ret_profile.DebugPrintStats(&printer);
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const char* retainers_of_a = printer.GetRetainers("A");
374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // The order of retainers is unspecified, so we check string length, and
375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // verify each retainer separately.
376d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"),
377d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block           i::StrLength(retainers_of_a));
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "(global property);1") != NULL);
379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "B;2") != NULL);
380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(strstr(retainers_of_a, "C;2") != NULL);
381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ("(global property);2", printer.GetRetainers("B"));
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ("(global property);1", printer.GetRetainers("C"));
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
3869dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsennamespace {
3879dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
3889dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenclass NamedEntriesDetector {
3899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen public:
3909dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  NamedEntriesDetector()
39190bac256d9f48d4ee52d0e08bf0e5cad57b3c51cRussell Brenner      : has_A2(false), has_B2(false), has_C2(false) {
3929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
3939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
394756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  void Apply(i::HeapEntry** entry_ptr) {
395756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
396756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
397756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
398756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
399756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
400756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  static bool IsReachableNodeWithName(i::HeapEntry* entry, const char* name) {
401756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
4029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
4039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4049dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_A2;
4059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_B2;
4069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_C2;
4079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen};
4089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}  // namespace
4109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic const v8::HeapGraphNode* GetGlobalObject(
4139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapSnapshot* snapshot) {
4148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
4158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* global_obj =
4168a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      snapshot->GetRoot()->GetChild(0)->GetToNode();
4178a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ("Object", const_cast<i::HeapEntry*>(
4188a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      reinterpret_cast<const i::HeapEntry*>(global_obj))->name());
4198a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  return global_obj;
4209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
4249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                            v8::HeapGraphEdge::Type type,
4259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen                                            const char* name) {
4269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
4279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = node->GetChild(i);
4289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    v8::String::AsciiValue prop_name(prop->GetName());
4299dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
4309dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      return prop->GetToNode();
4319dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
4329dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  return NULL;
4339dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdochstatic bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
4373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                             v8::HeapGraphEdge::Type type,
4383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch                             const char* name) {
4393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
4403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphEdge* prop = node->GetRetainer(i);
4413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    v8::String::AsciiValue prop_name(prop->GetName());
4423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
4433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      return true;
4443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  }
4453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  return false;
4463bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
4473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
4483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
4499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic bool HasString(const v8::HeapGraphNode* node, const char* contents) {
4509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
4519dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = node->GetChild(i);
4529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
453756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kString) {
4549dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::String::AsciiValue node_name(node->GetName());
4559dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (strcmp(contents, *node_name) == 0) return true;
4569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
4579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
4589dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  return false;
4599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4629dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshot) {
4639dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::HandleScope scope;
4643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env2;
4659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
466f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
4679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function A2() {}\n"
4689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function B2(x) { return function() { return typeof x; }; }\n"
4699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
4709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var a2 = new A2();\n"
4719dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
4729dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var c2 = new C2(a2);");
4739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapSnapshot* snapshot_env2 =
4749dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
475756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  i::HeapSnapshot* i_snapshot_env2 =
476756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      const_cast<i::HeapSnapshot*>(
477756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick          reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
4789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
479756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Paint all nodes reachable from global object.
480756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  i_snapshot_env2->ClearPaint();
481756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const_cast<i::HeapEntry*>(
482756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
4839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
48490bac256d9f48d4ee52d0e08bf0e5cad57b3c51cRussell Brenner  // Verify, that JS global object of env2 has '..2' properties.
4859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* a2_node =
4868a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
4879dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, a2_node);
488756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(
4898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
490756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(
4918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
4928a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
4939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  NamedEntriesDetector det;
4959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  i_snapshot_env2->IterateEntries(&det);
4969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_A2);
4979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_B2);
4989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_C2);
4999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5008a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  /*
5018a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    // Currently disabled. Too many retaining paths emerge, need to
5028a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang    // reduce the amount.
5038a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
5049dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Verify 'a2' object retainers. They are:
5059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  - (global object).a2
5069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  - c2.x1, c2.x2, c2[1]
5079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  //  - b2_1 and b2_2 closures: via 'x' variable
5089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_EQ(6, a2_node->GetRetainingPathsCount());
5099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_global_obj_a2_ref = false;
5109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false;
5119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool has_b2_1_x_ref = false, has_b2_2_x_ref = false;
5129dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) {
5139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i);
5149dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const int edges_count = path->GetEdgesCount();
5159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    CHECK_GT(edges_count, 0);
5169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* last_edge = path->GetEdge(edges_count - 1);
5179dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    v8::String::AsciiValue last_edge_name(last_edge->GetName());
5189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("a2", *last_edge_name) == 0
519756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick        && last_edge->GetType() == v8::HeapGraphEdge::kProperty) {
5209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      has_global_obj_a2_ref = true;
5219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      continue;
5229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
5239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    CHECK_GT(edges_count, 1);
5249dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prev_edge = path->GetEdge(edges_count - 2);
5259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    v8::String::AsciiValue prev_edge_name(prev_edge->GetName());
5269dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x1", *last_edge_name) == 0
527756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick        && last_edge->GetType() == v8::HeapGraphEdge::kProperty
5289dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("c2", *prev_edge_name) == 0) has_c2_x1_ref = true;
5299dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x2", *last_edge_name) == 0
530756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick        && last_edge->GetType() == v8::HeapGraphEdge::kProperty
5319dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("c2", *prev_edge_name) == 0) has_c2_x2_ref = true;
5329dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("1", *last_edge_name) == 0
533756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick        && last_edge->GetType() == v8::HeapGraphEdge::kElement
5349dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("c2", *prev_edge_name) == 0) has_c2_1_ref = true;
5359dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x", *last_edge_name) == 0
536756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick        && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable
5379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("b2_1", *prev_edge_name) == 0) has_b2_1_x_ref = true;
5389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    if (strcmp("x", *last_edge_name) == 0
539756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick        && last_edge->GetType() == v8::HeapGraphEdge::kContextVariable
5409dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true;
5419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
5429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_global_obj_a2_ref);
5439dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_c2_x1_ref);
5449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_c2_x2_ref);
5459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_c2_1_ref);
5469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_b2_1_x_ref);
5479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(has_b2_2_x_ref);
5488a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  */
5499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
5509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5519dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
552756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain MerrickTEST(HeapSnapshotObjectSizes) {
553756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  v8::HandleScope scope;
554756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  LocalContext env;
555756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
556756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  //   -a-> X1 --a
557756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // x -b-> X2 <-|
558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
559756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "function X(a, b) { this.a = a; this.b = b; }\n"
560756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "x = new X(new X(), new X());\n"
5618a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "(function() { x.a.a = x.b; })();");
562756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapSnapshot* snapshot =
563756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes"));
564756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
565756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* x =
5668a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
567756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, x);
568756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* x1 =
569756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
570756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, x1);
571756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* x2 =
572756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
573756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, x2);
5748a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
5758a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Test approximate sizes.
5768a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(false));
5778a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(false));
5788a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(false));
5798a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Test exact sizes.
5808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(true));
5818a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(true));
5828a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(true));
583756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick}
584756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
585756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
586756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain MerrickTEST(HeapSnapshotEntryChildren) {
587756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  v8::HandleScope scope;
588756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  LocalContext env;
589756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
590f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
591756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "function A() { }\n"
592756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "a = new A;");
593756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapSnapshot* snapshot =
594756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      v8::HeapProfiler::TakeSnapshot(v8::String::New("children"));
595756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
596756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
597756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    const v8::HeapGraphEdge* prop = global->GetChild(i);
598756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    CHECK_EQ(global, prop->GetFromNode());
599756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
600756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* a =
601756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
602756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, a);
603756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
604756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    const v8::HeapGraphEdge* prop = a->GetChild(i);
605756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    CHECK_EQ(a, prop->GetFromNode());
606756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
607756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick}
608756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
609756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
6109dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshotCodeObjects) {
6119dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::HandleScope scope;
6123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
6139dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
614f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
6159dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function lazy(x) { return x - 1; }\n"
6169dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function compiled(x) { return x + 1; }\n"
617791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "var anonymous = (function() { return function() { return 0; } })();\n"
6189dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "compiled(1)");
6199dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapSnapshot* snapshot =
6209dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("code"));
6219dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
6229dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
6239dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* compiled =
6248a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
6259dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, compiled);
626756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
6279dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* lazy =
6288a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
6299dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, lazy);
630756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
631791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* anonymous =
6328a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
633791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, anonymous);
634791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
635791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  v8::String::AsciiValue anonymous_name(anonymous->GetName());
636f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ("", *anonymous_name);
6379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
6389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Find references to code.
6399dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* compiled_code =
640756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(compiled, v8::HeapGraphEdge::kInternal, "code");
6419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, compiled_code);
6429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* lazy_code =
643756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(lazy, v8::HeapGraphEdge::kInternal, "code");
6449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, lazy_code);
6459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
6469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Verify that non-compiled code doesn't contain references to "x"
6473bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // literal, while compiled code does. The scope info is stored in FixedArray
6483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // objects attached to the SharedFunctionInfo.
6499dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool compiled_references_x = false, lazy_references_x = false;
6509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
6519dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
6529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
653756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kArray) {
6549dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (HasString(node, "x")) {
6559dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        compiled_references_x = true;
6569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        break;
6579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      }
6589dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
6599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
6609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
6619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
6629dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
663756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kArray) {
6649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (HasString(node, "x")) {
6659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        lazy_references_x = true;
6669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        break;
6679dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      }
6689dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
6699dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
6709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(compiled_references_x);
6719dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(!lazy_references_x);
6729dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
6739dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
6743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
675f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTEST(HeapSnapshotHeapNumbers) {
676f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::HandleScope scope;
677f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  LocalContext env;
678f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
679f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      "a = 1;    // a is Smi\n"
680f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      "b = 2.5;  // b is HeapNumber");
681f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapSnapshot* snapshot =
682f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers"));
683f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
6848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
685f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* b =
6868a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
687f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_NE(NULL, b);
688f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
689f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
690f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
691f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
692f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTEST(HeapSnapshotInternalReferences) {
693f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::HandleScope scope;
694f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
695f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  global_template->SetInternalFieldCount(2);
696f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  LocalContext env(NULL, global_template);
697f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Handle<v8::Object> global_proxy = env->Global();
698f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
699f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(2, global->InternalFieldCount());
700f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Local<v8::Object> obj = v8::Object::New();
701f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  global->SetInternalField(0, v8_num(17));
702f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  global->SetInternalField(1, obj);
703f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapSnapshot* snapshot =
704f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("internals"));
705f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
706f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // The first reference will not present, because it's a Smi.
707f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
708f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // The second reference is to an object.
709f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
710f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
711f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
712f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
7133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Trying to introduce a check helper for uint64_t causes many
7143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// overloading ambiguities, so it seems easier just to cast
7153bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// them to a signed type.
7163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch#define CHECK_EQ_UINT64_T(a, b) \
7173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b))
718756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick#define CHECK_NE_UINT64_T(a, b) \
719756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK((a) != (b))  // NOLINT
7203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben MurdochTEST(HeapEntryIdsAndGC) {
7223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  v8::HandleScope scope;
7233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
7243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
725f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
7263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function A() {}\n"
7273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function B(x) { this.x = x; }\n"
7283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var a = new A();\n"
7293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var b = new B(a);");
7303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot1 =
7313bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
7323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  i::Heap::CollectAllGarbage(true);  // Enforce compaction.
7343bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot2 =
7363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
7373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
7393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
7403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, global1->GetId());
7413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId());
7423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* A1 =
743756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
744756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, A1);
7453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* A2 =
746756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
747756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, A2);
7483bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, A1->GetId());
7493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
7503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* B1 =
751756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
752756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, B1);
7533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* B2 =
754756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
755756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, B2);
7563bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, B1->GetId());
7573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
7583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* a1 =
759756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
760756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, a1);
7613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* a2 =
762756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
763756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, a2);
7643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, a1->GetId());
7653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
7663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* b1 =
767756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
768756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, b1);
7693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* b2 =
770756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
771756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, b2);
7723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, b1->GetId());
7733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
7743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
7753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7773bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben MurdochTEST(HeapSnapshotsDiff) {
7783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  v8::HandleScope scope;
7793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
7803bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
781f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
7823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function A() {}\n"
7833bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function B(x) { this.x = x; }\n"
784f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      "function A2(a) { for (var i = 0; i < a; ++i) this[i] = i; }\n"
7853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var a = new A();\n"
7863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var b = new B(a);");
7873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot1 =
7883bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
7893bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
790f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
7913bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "delete a;\n"
7923bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "b.x = null;\n"
793f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      "var a = new A2(20);\n"
7943bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var b2 = new B(a);");
7953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot2 =
7963bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
7973bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshotsDiff* diff = snapshot1->CompareWith(snapshot2);
7993bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
8003bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Verify additions: ensure that addition of A and B was detected.
8013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* additions_root = diff->GetAdditionsRoot();
8023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  bool found_A = false, found_B = false;
8033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  uint64_t s1_A_id = 0;
8043bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  for (int i = 0, count = additions_root->GetChildrenCount(); i < count; ++i) {
8053bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphEdge* prop = additions_root->GetChild(i);
8063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphNode* node = prop->GetToNode();
807756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kObject) {
8083bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::String::AsciiValue node_name(node->GetName());
809f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if (strcmp(*node_name, "A2") == 0) {
8108a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang        CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
8113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(!found_A);
8123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        found_A = true;
8133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        s1_A_id = node->GetId();
8143bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      } else if (strcmp(*node_name, "B") == 0) {
8158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang        CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "b2"));
8163bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(!found_B);
8173bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        found_B = true;
8183bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      }
8193bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    }
8203bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  }
8213bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(found_A);
8223bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(found_B);
8233bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
8243bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // Verify deletions: ensure that deletion of A was detected.
8253bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* deletions_root = diff->GetDeletionsRoot();
8263bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  bool found_A_del = false;
8273bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  uint64_t s2_A_id = 0;
8283bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  for (int i = 0, count = deletions_root->GetChildrenCount(); i < count; ++i) {
8293bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphEdge* prop = deletions_root->GetChild(i);
8303bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    const v8::HeapGraphNode* node = prop->GetToNode();
831756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kObject) {
8323bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::String::AsciiValue node_name(node->GetName());
8333bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      if (strcmp(*node_name, "A") == 0) {
8348a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang        CHECK(IsNodeRetainedAs(node, v8::HeapGraphEdge::kShortcut, "a"));
8353bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        CHECK(!found_A_del);
8363bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        found_A_del = true;
8373bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch        s2_A_id = node->GetId();
8383bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      }
8393bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch    }
8403bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  }
8413bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(found_A_del);
8423bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, s1_A_id);
8433bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK(s1_A_id != s2_A_id);
8443bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
8453bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
846756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
847f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTEST(HeapSnapshotRootPreservedAfterSorting) {
848f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::HandleScope scope;
849f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  LocalContext env;
850f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapSnapshot* snapshot =
851f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s"));
852f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* root1 = snapshot->GetRoot();
853f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
854f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      snapshot))->GetSortedEntriesList();
855f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* root2 = snapshot->GetRoot();
856f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(root1, root2);
857f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
858f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
859f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
860791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Blockstatic const v8::HeapGraphNode* GetChild(
861791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphNode* node,
862791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    v8::HeapGraphNode::Type type,
863791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const char* name,
864791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphNode* after = NULL) {
865791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  bool ignore_child = after == NULL ? false : true;
866791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
867791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphEdge* prop = node->GetChild(i);
868791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphNode* child = prop->GetToNode();
869791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    v8::String::AsciiValue child_name(child->GetName());
870791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    if (!ignore_child
871791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block        && child->GetType() == type
872791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block        && strcmp(name, *child_name) == 0)
873791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      return child;
874791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    if (after != NULL && child == after) ignore_child = false;
875791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  }
876791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  return NULL;
877791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block}
878791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
879791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Blockstatic bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
880791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                             int element) {
881791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
882791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphEdge* prop = node->GetRetainer(i);
883791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    if (prop->GetType() == v8::HeapGraphEdge::kElement
884791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block        && element == prop->GetName()->Int32Value())
885791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      return true;
886791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  }
887791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  return false;
888791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block}
889791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
890791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve BlockTEST(AggregatedHeapSnapshot) {
891791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  v8::HandleScope scope;
892791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  LocalContext env;
893791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
894f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
895791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "function A() {}\n"
896791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "function B(x) { this.x = x; }\n"
897791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "var a = new A();\n"
898791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "var b = new B(a);");
899791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapSnapshot* snapshot =
900791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapProfiler::TakeSnapshot(
901791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block          v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
902791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(),
9038a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                                              v8::HeapGraphNode::kHidden,
904791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                              "STRING_TYPE");
905791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, strings);
906791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, strings->GetSelfSize());
907791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, strings->GetInstancesCount());
908791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(),
9098a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                                           v8::HeapGraphNode::kHidden,
910791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                           "MAP_TYPE");
911791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, maps);
912791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, maps->GetSelfSize());
913791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, maps->GetInstancesCount());
914791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
915791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* a = GetChild(snapshot->GetRoot(),
916791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        v8::HeapGraphNode::kObject,
917791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        "A");
918791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, a);
919791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, a->GetSelfSize());
920791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(1, a->GetInstancesCount());
921791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
922791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* b = GetChild(snapshot->GetRoot(),
923791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        v8::HeapGraphNode::kObject,
924791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        "B");
925791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, b);
926791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, b->GetSelfSize());
927791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(1, b->GetInstancesCount());
928791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
929791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* glob_prop = GetChild(snapshot->GetRoot(),
930791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                                v8::HeapGraphNode::kObject,
931791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                                "(global property)",
932791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                                b);
933791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, glob_prop);
934791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, glob_prop->GetSelfSize());
935791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, glob_prop->GetInstancesCount());
936791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, glob_prop->GetChildrenCount());
937791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
938791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* a_from_glob_prop = GetChild(
939791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      glob_prop,
940791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapGraphNode::kObject,
941791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "A");
942791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, a_from_glob_prop);
943791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_glob_prop->GetSelfSize());
944791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_glob_prop->GetInstancesCount());
945791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_glob_prop->GetChildrenCount());  // Retains nothing.
946791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK(IsNodeRetainedAs(a_from_glob_prop, 1));  // (global propery) has 1 ref.
947791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
948791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* b_with_children = GetChild(
949791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      snapshot->GetRoot(),
950791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapGraphNode::kObject,
951791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "B",
952791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      b);
953791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, b_with_children);
954791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, b_with_children->GetSelfSize());
955791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, b_with_children->GetInstancesCount());
956791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, b_with_children->GetChildrenCount());
957791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
958791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* a_from_b = GetChild(
959791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      b_with_children,
960791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapGraphNode::kObject,
961791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "A");
962791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, a_from_b);
963791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_b->GetSelfSize());
964791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_b->GetInstancesCount());
965791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_b->GetChildrenCount());  // Retains nothing.
966791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK(IsNodeRetainedAs(a_from_b, 1));  // B has 1 ref to A.
967791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block}
968791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
9698a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
9708a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) WangTEST(HeapEntryDominator) {
9718a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // The graph looks like this:
9728a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //
9738a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                   -> node1
9748a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                  a    |^
9758a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //          -> node5     ba
9768a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //         a             v|
9778a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //   node6           -> node2
9788a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //         b        a    |^
9798a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //          -> node4     ba
9808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                  b    v|
9818a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                   -> node3
9828a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //
9838a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // The dominator for all nodes is node6.
9848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
9858a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  v8::HandleScope scope;
9868a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  LocalContext env;
9878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
9888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CompileRun(
9898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "function X(a, b) { this.a = a; this.b = b; }\n"
9908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6 = new X(new X(new X()), new X(new X(),new X()));\n"
9918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "(function(){\n"
9928a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.a.a.b = node6.b.a;  // node1 -> node2\n"
9938a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.b.a.a = node6.a.a;  // node2 -> node1\n"
9948a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.b.a.b = node6.b.b;  // node2 -> node3\n"
9958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.b.b.a = node6.b.a;  // node3 -> node2\n"
9968a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "})();");
9978a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
9988a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapSnapshot* snapshot =
9998a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      v8::HeapProfiler::TakeSnapshot(v8::String::New("dominators"));
10008a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
10018a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
10028a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, global);
10038a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node6 =
10048a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
10058a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node6);
10068a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node5 =
10078a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
10088a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node5);
10098a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node4 =
10108a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node6, v8::HeapGraphEdge::kProperty, "b");
10118a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node4);
10128a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node3 =
10138a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node4, v8::HeapGraphEdge::kProperty, "b");
10148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node3);
10158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node2 =
10168a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node4, v8::HeapGraphEdge::kProperty, "a");
10178a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node2);
10188a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node1 =
10198a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node5, v8::HeapGraphEdge::kProperty, "a");
10208a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node1);
10218a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
10228a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node1->GetDominatorNode());
10238a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node2->GetDominatorNode());
10248a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node3->GetDominatorNode());
10258a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node4->GetDominatorNode());
10268a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node5->GetDominatorNode());
10278a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang}
10288a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
10298a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
10300d5e116f6aee03185f237311a943491bb079a768Kristian Monsennamespace {
10310d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10320d5e116f6aee03185f237311a943491bb079a768Kristian Monsenclass TestJSONStream : public v8::OutputStream {
10330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen public:
10340d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
10350d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  explicit TestJSONStream(int abort_countdown)
10360d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      : eos_signaled_(0), abort_countdown_(abort_countdown) {}
10370d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual ~TestJSONStream() {}
10380d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual void EndOfStream() { ++eos_signaled_; }
10390d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
10400d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    if (abort_countdown_ > 0) --abort_countdown_;
10410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    if (abort_countdown_ == 0) return kAbort;
10420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    CHECK_GT(chars_written, 0);
10430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
10440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    memcpy(chunk.start(), buffer, chars_written);
10450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    return kContinue;
10460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
10470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
10480d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int eos_signaled() { return eos_signaled_; }
10490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int size() { return buffer_.size(); }
10500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen private:
10510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  i::Collector<char> buffer_;
10520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int eos_signaled_;
10530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int abort_countdown_;
10540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen};
10550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10560d5e116f6aee03185f237311a943491bb079a768Kristian Monsenclass AsciiResource: public v8::String::ExternalAsciiStringResource {
10570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen public:
10580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
10590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    length_ = string.length();
10600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
10610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual const char* data() const { return data_; }
10620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual size_t length() const { return length_; }
10630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen private:
10640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const char* data_;
10650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  size_t length_;
10660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen};
10670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}  // namespace
10690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10700d5e116f6aee03185f237311a943491bb079a768Kristian MonsenTEST(HeapSnapshotJSONSerialization) {
10710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::HandleScope scope;
10720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  LocalContext env;
10730d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10740d5e116f6aee03185f237311a943491bb079a768Kristian Monsen#define STRING_LITERAL_FOR_TEST \
10750d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
1076f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
10770d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "function A(s) { this.s = s; }\n"
10780d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "function B(x) { this.x = x; }\n"
10790d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
10800d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var b = new B(a);");
10810d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const v8::HeapSnapshot* snapshot =
10820d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("json"));
10830d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  TestJSONStream stream;
10840d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
10850d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_GT(stream.size(), 0);
10860d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_EQ(1, stream.eos_signaled());
10870d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  i::ScopedVector<char> json(stream.size());
10880d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  stream.WriteTo(json);
10890d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10900d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Verify that snapshot string is valid JSON.
10910d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  AsciiResource json_res(json);
10920d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res);
10930d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  env->Global()->Set(v8::String::New("json_snapshot"), json_string);
10940d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Value> snapshot_parse_result = CompileRun(
10950d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var parsed = JSON.parse(json_snapshot); true;");
10960d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(!snapshot_parse_result.IsEmpty());
10970d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10980d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Verify that snapshot object has required fields.
10990d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Object> parsed_snapshot =
11000d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      env->Global()->Get(v8::String::New("parsed"))->ToObject();
11010d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(parsed_snapshot->Has(v8::String::New("snapshot")));
11020d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(parsed_snapshot->Has(v8::String::New("nodes")));
11030d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(parsed_snapshot->Has(v8::String::New("strings")));
11040d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
11050d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Get node and edge "member" offsets.
11060d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Value> meta_analysis_result = CompileRun(
11078a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "var parsed_meta = parsed.nodes[0];\n"
11080d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var children_count_offset ="
11090d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    parsed_meta.fields.indexOf('children_count');\n"
11100d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var children_offset ="
11110d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    parsed_meta.fields.indexOf('children');\n"
11120d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var children_meta ="
11130d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    parsed_meta.types[children_offset];\n"
11140d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_fields_count = children_meta.fields.length;\n"
11150d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_type_offset ="
11160d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    children_meta.fields.indexOf('type');\n"
11170d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_name_offset ="
11180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    children_meta.fields.indexOf('name_or_index');\n"
11190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_to_node_offset ="
11200d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    children_meta.fields.indexOf('to_node');\n"
11210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var property_type ="
11228a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    children_meta.types[child_type_offset].indexOf('property');\n"
11238a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "var shortcut_type ="
11248a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    children_meta.types[child_type_offset].indexOf('shortcut');");
11250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(!meta_analysis_result.IsEmpty());
11260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
11270d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // A helper function for processing encoded nodes.
11280d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CompileRun(
11298a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
11300d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  var nodes = parsed.nodes;\n"
11310d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  var strings = parsed.strings;\n"
11320d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  for (var i = 0,\n"
11330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "      count = nodes[pos + children_count_offset] * child_fields_count;\n"
11340d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "      i < count; i += child_fields_count) {\n"
11350d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    var child_pos = pos + children_offset + i;\n"
11368a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    if (nodes[child_pos + child_type_offset] === prop_type\n"
11370d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "       && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
11380d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "        return nodes[child_pos + child_to_node_offset];\n"
11390d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  }\n"
11400d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  return null;\n"
11410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "}\n");
11420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Get the string index using the path: <root> -> <global>.b.x.s
11430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Value> string_obj_pos_val = CompileRun(
11440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "GetChildPosByProperty(\n"
11450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  GetChildPosByProperty(\n"
11460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    GetChildPosByProperty("
11478a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "      parsed.nodes[1 + children_offset + child_to_node_offset],"
11488a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "      \"b\",shortcut_type),\n"
11498a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    \"x\", property_type),"
11508a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "  \"s\", property_type)");
11510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(!string_obj_pos_val.IsEmpty());
11520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int string_obj_pos =
11530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      static_cast<int>(string_obj_pos_val->ToNumber()->Value());
11540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Object> nodes_array =
11550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      parsed_snapshot->Get(v8::String::New("nodes"))->ToObject();
11560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int string_index = static_cast<int>(
11570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
11580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_GT(string_index, 0);
11590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Object> strings_array =
11600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      parsed_snapshot->Get(v8::String::New("strings"))->ToObject();
11610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
11620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::String> ref_string =
11630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
11640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen#undef STRING_LITERAL_FOR_TEST
11650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_EQ(*v8::String::Utf8Value(ref_string),
11660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen           *v8::String::Utf8Value(string));
11670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}
11680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
11690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
11700d5e116f6aee03185f237311a943491bb079a768Kristian MonsenTEST(HeapSnapshotJSONSerializationAborting) {
11710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::HandleScope scope;
11720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  LocalContext env;
11730d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const v8::HeapSnapshot* snapshot =
11740d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"));
11750d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  TestJSONStream stream(5);
11760d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
11770d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_GT(stream.size(), 0);
11780d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_EQ(0, stream.eos_signaled());
11790d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}
11800d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
11818a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
11828a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Must not crash in debug mode.
11838a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) WangTEST(AggregatedHeapSnapshotJSONSerialization) {
11848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  v8::HandleScope scope;
11858a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  LocalContext env;
11868a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
11878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapSnapshot* snapshot =
11888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      v8::HeapProfiler::TakeSnapshot(
11898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang          v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
11908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  TestJSONStream stream;
11918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
11928a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_GT(stream.size(), 0);
11938a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(1, stream.eos_signaled());
11948a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang}
11958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
1196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // ENABLE_LOGGING_AND_PROFILING
1197