test-heap-profiler.cc revision 44f0eee88ff00398ff7f715fab053374d808c90d
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(),
2944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      f_name_(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;
14644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  JSObjectsCluster function(HEAP->function_class_symbol());
14744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  JSObjectsCluster a(*FACTORY->NewStringFromAscii(i::CStrVector("A")));
14844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  JSObjectsCluster b(*FACTORY->NewStringFromAscii(i::CStrVector("B")));
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
15244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
15544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o3 <- A, B
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o3 =
15844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &a, &b);
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o4 <- B, A
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o4 =
16144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x400, &b, &a);
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o5 <- A, B, Function
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o5 =
16444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, 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;
18444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  JSObjectsCluster function(HEAP->function_class_symbol());
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o1 <- Function
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
18844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a1 <- Function
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a1 =
19144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x1000, &function);
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // o2 <- Function
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
19444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // a2 <- Function
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster a2 =
19744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, 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 =
22744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o11 =
22944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o12 =
23144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o21 =
23344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x210, &o11);
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o22 =
23544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x220, &o12);
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
23744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o21);
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
23944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o21, &o22);
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
24144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, 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 =
27844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o1 =
28044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster o2 =
28244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster p =
28444f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o1);
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &p);
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster q =
28744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o1, &o2);
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  AddSelfReferenceToTree(&tree, &q);
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  JSObjectsCluster r =
29044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      AddHeapObjectToTree(&tree, 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
4369dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsenstatic bool HasString(const v8::HeapGraphNode* node, const char* contents) {
4379dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
4389dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = node->GetChild(i);
4399dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
440756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kString) {
4419dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::String::AsciiValue node_name(node->GetName());
4429dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (strcmp(contents, *node_name) == 0) return true;
4439dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
4449dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
4459dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  return false;
4469dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4479dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4489dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4499dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshot) {
4509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::HandleScope scope;
4513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env2;
4529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
453f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
4549dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function A2() {}\n"
4559dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function B2(x) { return function() { return typeof x; }; }\n"
4569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
4579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var a2 = new A2();\n"
4589dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
4599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "var c2 = new C2(a2);");
4609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapSnapshot* snapshot_env2 =
4619dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
462756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  i::HeapSnapshot* i_snapshot_env2 =
463756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      const_cast<i::HeapSnapshot*>(
464756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick          reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
4659dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
466756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // Paint all nodes reachable from global object.
467756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  i_snapshot_env2->ClearPaint();
468756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const_cast<i::HeapEntry*>(
469756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
4709dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
47190bac256d9f48d4ee52d0e08bf0e5cad57b3c51cRussell Brenner  // Verify, that JS global object of env2 has '..2' properties.
4729dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* a2_node =
4738a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
4749dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, a2_node);
475756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(
4768a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
477756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(
4788a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
4798a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
4809dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  NamedEntriesDetector det;
4829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  i_snapshot_env2->IterateEntries(&det);
4839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_A2);
4849dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_B2);
4859dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(det.has_C2);
4869dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
4879dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
4889dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
489756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain MerrickTEST(HeapSnapshotObjectSizes) {
490756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  v8::HandleScope scope;
491756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  LocalContext env;
492756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
493756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  //   -a-> X1 --a
494756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  // x -b-> X2 <-|
495f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
496756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "function X(a, b) { this.a = a; this.b = b; }\n"
497756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "x = new X(new X(), new X());\n"
4988a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "(function() { x.a.a = x.b; })();");
499756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapSnapshot* snapshot =
500756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes"));
501756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
502756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* x =
5038a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
504756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, x);
505756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* x1 =
506756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
507756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, x1);
508756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* x2 =
509756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
510756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, x2);
5118a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
5128a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Test approximate sizes.
5138a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(false));
5148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(false));
5158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(false));
5168a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // Test exact sizes.
5178a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(true));
5188a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(true));
5198a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(true));
520756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick}
521756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
522756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
523756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain MerrickTEST(HeapSnapshotEntryChildren) {
524756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  v8::HandleScope scope;
525756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  LocalContext env;
526756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
527f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
528756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "function A() { }\n"
529756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      "a = new A;");
530756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapSnapshot* snapshot =
531756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      v8::HeapProfiler::TakeSnapshot(v8::String::New("children"));
532756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
533756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
534756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    const v8::HeapGraphEdge* prop = global->GetChild(i);
535756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    CHECK_EQ(global, prop->GetFromNode());
536756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
537756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  const v8::HeapGraphNode* a =
538756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
539756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, a);
540756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
541756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    const v8::HeapGraphEdge* prop = a->GetChild(i);
542756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    CHECK_EQ(a, prop->GetFromNode());
543756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  }
544756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick}
545756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
546756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick
5479dcf7e2f83591d471e88bf7d230651900b8e424bKristian MonsenTEST(HeapSnapshotCodeObjects) {
5489dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  v8::HandleScope scope;
5493bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
5509dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
551f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
5529dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function lazy(x) { return x - 1; }\n"
5539dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "function compiled(x) { return x + 1; }\n"
554791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "var anonymous = (function() { return function() { return 0; } })();\n"
5559dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      "compiled(1)");
5569dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapSnapshot* snapshot =
5579dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("code"));
5589dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5599dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
5609dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* compiled =
5618a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
5629dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, compiled);
563756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
5649dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* lazy =
5658a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
5669dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, lazy);
567756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
568791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* anonymous =
5698a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
570791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, anonymous);
571791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
572791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  v8::String::AsciiValue anonymous_name(anonymous->GetName());
573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ("", *anonymous_name);
5749dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5759dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Find references to code.
5769dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* compiled_code =
577756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(compiled, v8::HeapGraphEdge::kInternal, "code");
5789dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, compiled_code);
5799dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  const v8::HeapGraphNode* lazy_code =
580756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(lazy, v8::HeapGraphEdge::kInternal, "code");
5819dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK_NE(NULL, lazy_code);
5829dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
5839dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  // Verify that non-compiled code doesn't contain references to "x"
5843bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // literal, while compiled code does. The scope info is stored in FixedArray
5853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  // objects attached to the SharedFunctionInfo.
5869dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  bool compiled_references_x = false, lazy_references_x = false;
5879dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
5889dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
5899dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
590756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kArray) {
5919dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (HasString(node, "x")) {
5929dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        compiled_references_x = true;
5939dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        break;
5949dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      }
5959dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
5969dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
5979dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
5989dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
5999dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    const v8::HeapGraphNode* node = prop->GetToNode();
600756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick    if (node->GetType() == v8::HeapGraphNode::kArray) {
6019dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      if (HasString(node, "x")) {
6029dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        lazy_references_x = true;
6039dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen        break;
6049dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen      }
6059dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen    }
6069dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  }
6079dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(compiled_references_x);
6089dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen  CHECK(!lazy_references_x);
6099dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen}
6109dcf7e2f83591d471e88bf7d230651900b8e424bKristian Monsen
6113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
612f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTEST(HeapSnapshotHeapNumbers) {
613f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::HandleScope scope;
614f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  LocalContext env;
615f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      "a = 1;    // a is Smi\n"
617f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      "b = 2.5;  // b is HeapNumber");
618f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapSnapshot* snapshot =
619f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers"));
620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
6218a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
622f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* b =
6238a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
624f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_NE(NULL, b);
625f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
626f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
628f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
629f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTEST(HeapSnapshotInternalReferences) {
630f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::HandleScope scope;
631f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
632f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  global_template->SetInternalFieldCount(2);
633f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  LocalContext env(NULL, global_template);
634f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Handle<v8::Object> global_proxy = env->Global();
635f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
636f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(2, global->InternalFieldCount());
637f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::Local<v8::Object> obj = v8::Object::New();
638f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  global->SetInternalField(0, v8_num(17));
639f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  global->SetInternalField(1, obj);
640f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapSnapshot* snapshot =
641f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("internals"));
642f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
643f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // The first reference will not present, because it's a Smi.
644f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
645f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  // The second reference is to an object.
646f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
647f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
648f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
649f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
6503bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// Trying to introduce a check helper for uint64_t causes many
6513bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// overloading ambiguities, so it seems easier just to cast
6523bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch// them to a signed type.
6533bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch#define CHECK_EQ_UINT64_T(a, b) \
6543bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b))
655756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick#define CHECK_NE_UINT64_T(a, b) \
656756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK((a) != (b))  // NOLINT
6573bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6583bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben MurdochTEST(HeapEntryIdsAndGC) {
6593bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  v8::HandleScope scope;
6603bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  LocalContext env;
6613bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
662f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
6633bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function A() {}\n"
6643bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "function B(x) { this.x = x; }\n"
6653bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var a = new A();\n"
6663bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      "var b = new B(a);");
6673bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot1 =
6683bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
6693bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
67044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  HEAP->CollectAllGarbage(true);  // Enforce compaction.
6713bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6723bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapSnapshot* snapshot2 =
6733bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
6743bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
6753bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
6763bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
6773bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, global1->GetId());
6783bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId());
6793bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* A1 =
680756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
681756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, A1);
6823bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* A2 =
683756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
684756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, A2);
6853bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, A1->GetId());
6863bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
6873bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* B1 =
688756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
689756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, B1);
6903bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* B2 =
691756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
692756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, B2);
6933bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, B1->GetId());
6943bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
6953bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* a1 =
696756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
697756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, a1);
6983bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* a2 =
699756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
700756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, a2);
7013bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, a1->GetId());
7023bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
7033bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* b1 =
704756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
705756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, b1);
7063bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  const v8::HeapGraphNode* b2 =
707756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick      GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
708756813857a4c2a4d8ad2e805969d5768d3cf43a0Iain Merrick  CHECK_NE(NULL, b2);
7093bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_NE_UINT64_T(0, b1->GetId());
7103bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch  CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
7113bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch}
7123bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
7133bec4d28b1f388dbc06a9c4276e1a03e86c52b04Ben Murdoch
714f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTEST(HeapSnapshotRootPreservedAfterSorting) {
715f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  v8::HandleScope scope;
716f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  LocalContext env;
717f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapSnapshot* snapshot =
718f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("s"));
719f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* root1 = snapshot->GetRoot();
720f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
721f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      snapshot))->GetSortedEntriesList();
722f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  const v8::HeapGraphNode* root2 = snapshot->GetRoot();
723f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CHECK_EQ(root1, root2);
724f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch}
725f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
726f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
727791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Blockstatic const v8::HeapGraphNode* GetChild(
728791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphNode* node,
729791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    v8::HeapGraphNode::Type type,
730791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const char* name,
731791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphNode* after = NULL) {
732791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  bool ignore_child = after == NULL ? false : true;
733791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
734791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphEdge* prop = node->GetChild(i);
735791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphNode* child = prop->GetToNode();
736791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    v8::String::AsciiValue child_name(child->GetName());
737791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    if (!ignore_child
738791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block        && child->GetType() == type
739791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block        && strcmp(name, *child_name) == 0)
740791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      return child;
741791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    if (after != NULL && child == after) ignore_child = false;
742791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  }
743791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  return NULL;
744791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block}
745791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
746791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Blockstatic bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
747791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                             int element) {
748791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
749791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    const v8::HeapGraphEdge* prop = node->GetRetainer(i);
750791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block    if (prop->GetType() == v8::HeapGraphEdge::kElement
751791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block        && element == prop->GetName()->Int32Value())
752791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      return true;
753791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  }
754791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  return false;
755791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block}
756791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
757791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve BlockTEST(AggregatedHeapSnapshot) {
758791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  v8::HandleScope scope;
759791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  LocalContext env;
760791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
761f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
762791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "function A() {}\n"
763791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "function B(x) { this.x = x; }\n"
764791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "var a = new A();\n"
765791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "var b = new B(a);");
766791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapSnapshot* snapshot =
767791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapProfiler::TakeSnapshot(
768791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block          v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
769791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(),
7708a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                                              v8::HeapGraphNode::kHidden,
771791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                              "STRING_TYPE");
772791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, strings);
773791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, strings->GetSelfSize());
774791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, strings->GetInstancesCount());
775791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(),
7768a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang                                           v8::HeapGraphNode::kHidden,
777791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                           "MAP_TYPE");
778791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, maps);
779791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, maps->GetSelfSize());
780791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, maps->GetInstancesCount());
781791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
782791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* a = GetChild(snapshot->GetRoot(),
783791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        v8::HeapGraphNode::kObject,
784791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        "A");
785791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, a);
786791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, a->GetSelfSize());
787791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(1, a->GetInstancesCount());
788791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
789791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* b = GetChild(snapshot->GetRoot(),
790791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        v8::HeapGraphNode::kObject,
791791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                        "B");
792791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, b);
793791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, b->GetSelfSize());
794791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(1, b->GetInstancesCount());
795791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
796791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* glob_prop = GetChild(snapshot->GetRoot(),
797791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                                v8::HeapGraphNode::kObject,
798791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                                "(global property)",
799791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block                                                b);
800791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, glob_prop);
801791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, glob_prop->GetSelfSize());
802791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, glob_prop->GetInstancesCount());
803791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, glob_prop->GetChildrenCount());
804791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
805791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* a_from_glob_prop = GetChild(
806791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      glob_prop,
807791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapGraphNode::kObject,
808791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "A");
809791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, a_from_glob_prop);
810791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_glob_prop->GetSelfSize());
811791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_glob_prop->GetInstancesCount());
812791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_glob_prop->GetChildrenCount());  // Retains nothing.
813791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK(IsNodeRetainedAs(a_from_glob_prop, 1));  // (global propery) has 1 ref.
814791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
815791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* b_with_children = GetChild(
816791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      snapshot->GetRoot(),
817791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapGraphNode::kObject,
818791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "B",
819791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      b);
820791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, b_with_children);
821791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, b_with_children->GetSelfSize());
822791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, b_with_children->GetInstancesCount());
823791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(0, b_with_children->GetChildrenCount());
824791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
825791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  const v8::HeapGraphNode* a_from_b = GetChild(
826791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      b_with_children,
827791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      v8::HeapGraphNode::kObject,
828791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block      "A");
829791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_NE(NULL, a_from_b);
830791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_b->GetSelfSize());
831791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_b->GetInstancesCount());
832791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK_EQ(0, a_from_b->GetChildrenCount());  // Retains nothing.
833791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block  CHECK(IsNodeRetainedAs(a_from_b, 1));  // B has 1 ref to A.
834791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block}
835791712a13f1814dd3ab5d1a5ab8ff5dbc476f6d6Steve Block
8368a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8378a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) WangTEST(HeapEntryDominator) {
8388a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // The graph looks like this:
8398a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //
8408a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                   -> node1
8418a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                  a    |^
8428a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //          -> node5     ba
8438a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //         a             v|
8448a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //   node6           -> node2
8458a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //         b        a    |^
8468a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //          -> node4     ba
8478a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                  b    v|
8488a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //                   -> node3
8498a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  //
8508a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  // The dominator for all nodes is node6.
8518a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8528a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  v8::HandleScope scope;
8538a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  LocalContext env;
8548a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8558a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CompileRun(
8568a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "function X(a, b) { this.a = a; this.b = b; }\n"
8578a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6 = new X(new X(new X()), new X(new X(),new X()));\n"
8588a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "(function(){\n"
8598a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.a.a.b = node6.b.a;  // node1 -> node2\n"
8608a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.b.a.a = node6.a.a;  // node2 -> node1\n"
8618a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.b.a.b = node6.b.b;  // node2 -> node3\n"
8628a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "node6.b.b.a = node6.b.a;  // node3 -> node2\n"
8638a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "})();");
8648a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8658a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapSnapshot* snapshot =
8668a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      v8::HeapProfiler::TakeSnapshot(v8::String::New("dominators"));
8678a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8688a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
8698a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, global);
8708a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node6 =
8718a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
8728a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node6);
8738a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node5 =
8748a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
8758a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node5);
8768a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node4 =
8778a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node6, v8::HeapGraphEdge::kProperty, "b");
8788a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node4);
8798a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node3 =
8808a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node4, v8::HeapGraphEdge::kProperty, "b");
8818a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node3);
8828a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node2 =
8838a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node4, v8::HeapGraphEdge::kProperty, "a");
8848a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node2);
8858a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapGraphNode* node1 =
8868a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      GetProperty(node5, v8::HeapGraphEdge::kProperty, "a");
8878a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_NE(NULL, node1);
8888a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node1->GetDominatorNode());
8908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node2->GetDominatorNode());
8918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node3->GetDominatorNode());
8928a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node4->GetDominatorNode());
8938a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(node6, node5->GetDominatorNode());
8948a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang}
8958a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8968a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
8970d5e116f6aee03185f237311a943491bb079a768Kristian Monsennamespace {
8980d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
8990d5e116f6aee03185f237311a943491bb079a768Kristian Monsenclass TestJSONStream : public v8::OutputStream {
9000d5e116f6aee03185f237311a943491bb079a768Kristian Monsen public:
9010d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
9020d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  explicit TestJSONStream(int abort_countdown)
9030d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      : eos_signaled_(0), abort_countdown_(abort_countdown) {}
9040d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual ~TestJSONStream() {}
9050d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual void EndOfStream() { ++eos_signaled_; }
9060d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
9070d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    if (abort_countdown_ > 0) --abort_countdown_;
9080d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    if (abort_countdown_ == 0) return kAbort;
9090d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    CHECK_GT(chars_written, 0);
9100d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
9110d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    memcpy(chunk.start(), buffer, chars_written);
9120d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    return kContinue;
9130d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
9140d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
9150d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int eos_signaled() { return eos_signaled_; }
9160d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int size() { return buffer_.size(); }
9170d5e116f6aee03185f237311a943491bb079a768Kristian Monsen private:
9180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  i::Collector<char> buffer_;
9190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int eos_signaled_;
9200d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int abort_countdown_;
9210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen};
9220d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9230d5e116f6aee03185f237311a943491bb079a768Kristian Monsenclass AsciiResource: public v8::String::ExternalAsciiStringResource {
9240d5e116f6aee03185f237311a943491bb079a768Kristian Monsen public:
9250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
9260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen    length_ = string.length();
9270d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  }
9280d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual const char* data() const { return data_; }
9290d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  virtual size_t length() const { return length_; }
9300d5e116f6aee03185f237311a943491bb079a768Kristian Monsen private:
9310d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const char* data_;
9320d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  size_t length_;
9330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen};
9340d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9350d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}  // namespace
9360d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9370d5e116f6aee03185f237311a943491bb079a768Kristian MonsenTEST(HeapSnapshotJSONSerialization) {
9380d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::HandleScope scope;
9390d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  LocalContext env;
9400d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen#define STRING_LITERAL_FOR_TEST \
9420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
943f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CompileRun(
9440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "function A(s) { this.s = s; }\n"
9450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "function B(x) { this.x = x; }\n"
9460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
9470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var b = new B(a);");
9480d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const v8::HeapSnapshot* snapshot =
9490d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("json"));
9500d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  TestJSONStream stream;
9510d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
9520d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_GT(stream.size(), 0);
9530d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_EQ(1, stream.eos_signaled());
9540d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  i::ScopedVector<char> json(stream.size());
9550d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  stream.WriteTo(json);
9560d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9570d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Verify that snapshot string is valid JSON.
9580d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  AsciiResource json_res(json);
9590d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res);
9600d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  env->Global()->Set(v8::String::New("json_snapshot"), json_string);
9610d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Value> snapshot_parse_result = CompileRun(
9620d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var parsed = JSON.parse(json_snapshot); true;");
9630d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(!snapshot_parse_result.IsEmpty());
9640d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9650d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Verify that snapshot object has required fields.
9660d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Object> parsed_snapshot =
9670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      env->Global()->Get(v8::String::New("parsed"))->ToObject();
9680d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(parsed_snapshot->Has(v8::String::New("snapshot")));
9690d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(parsed_snapshot->Has(v8::String::New("nodes")));
9700d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(parsed_snapshot->Has(v8::String::New("strings")));
9710d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9720d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Get node and edge "member" offsets.
9730d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Value> meta_analysis_result = CompileRun(
9748a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "var parsed_meta = parsed.nodes[0];\n"
9750d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var children_count_offset ="
9760d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    parsed_meta.fields.indexOf('children_count');\n"
9770d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var children_offset ="
9780d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    parsed_meta.fields.indexOf('children');\n"
9790d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var children_meta ="
9800d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    parsed_meta.types[children_offset];\n"
9810d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_fields_count = children_meta.fields.length;\n"
9820d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_type_offset ="
9830d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    children_meta.fields.indexOf('type');\n"
9840d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_name_offset ="
9850d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    children_meta.fields.indexOf('name_or_index');\n"
9860d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var child_to_node_offset ="
9870d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    children_meta.fields.indexOf('to_node');\n"
9880d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "var property_type ="
9898a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    children_meta.types[child_type_offset].indexOf('property');\n"
9908a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "var shortcut_type ="
9918a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    children_meta.types[child_type_offset].indexOf('shortcut');");
9920d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(!meta_analysis_result.IsEmpty());
9930d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
9940d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // A helper function for processing encoded nodes.
9950d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CompileRun(
9968a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
9970d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  var nodes = parsed.nodes;\n"
9980d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  var strings = parsed.strings;\n"
9990d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  for (var i = 0,\n"
10000d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "      count = nodes[pos + children_count_offset] * child_fields_count;\n"
10010d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "      i < count; i += child_fields_count) {\n"
10020d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    var child_pos = pos + children_offset + i;\n"
10038a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    if (nodes[child_pos + child_type_offset] === prop_type\n"
10040d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "       && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
10050d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "        return nodes[child_pos + child_to_node_offset];\n"
10060d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  }\n"
10070d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  return null;\n"
10080d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "}\n");
10090d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  // Get the string index using the path: <root> -> <global>.b.x.s
10100d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Value> string_obj_pos_val = CompileRun(
10110d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "GetChildPosByProperty(\n"
10120d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "  GetChildPosByProperty(\n"
10130d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      "    GetChildPosByProperty("
10148a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "      parsed.nodes[1 + children_offset + child_to_node_offset],"
10158a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "      \"b\",shortcut_type),\n"
10168a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "    \"x\", property_type),"
10178a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      "  \"s\", property_type)");
10180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK(!string_obj_pos_val.IsEmpty());
10190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int string_obj_pos =
10200d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      static_cast<int>(string_obj_pos_val->ToNumber()->Value());
10210d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Object> nodes_array =
10220d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      parsed_snapshot->Get(v8::String::New("nodes"))->ToObject();
10230d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  int string_index = static_cast<int>(
10240d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
10250d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_GT(string_index, 0);
10260d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::Object> strings_array =
10270d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      parsed_snapshot->Get(v8::String::New("strings"))->ToObject();
10280d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
10290d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::Local<v8::String> ref_string =
10300d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
10310d5e116f6aee03185f237311a943491bb079a768Kristian Monsen#undef STRING_LITERAL_FOR_TEST
10320d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_EQ(*v8::String::Utf8Value(ref_string),
10330d5e116f6aee03185f237311a943491bb079a768Kristian Monsen           *v8::String::Utf8Value(string));
10340d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}
10350d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10360d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10370d5e116f6aee03185f237311a943491bb079a768Kristian MonsenTEST(HeapSnapshotJSONSerializationAborting) {
10380d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  v8::HandleScope scope;
10390d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  LocalContext env;
10400d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  const v8::HeapSnapshot* snapshot =
10410d5e116f6aee03185f237311a943491bb079a768Kristian Monsen      v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"));
10420d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  TestJSONStream stream(5);
10430d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
10440d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_GT(stream.size(), 0);
10450d5e116f6aee03185f237311a943491bb079a768Kristian Monsen  CHECK_EQ(0, stream.eos_signaled());
10460d5e116f6aee03185f237311a943491bb079a768Kristian Monsen}
10470d5e116f6aee03185f237311a943491bb079a768Kristian Monsen
10488a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
10498a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang// Must not crash in debug mode.
10508a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) WangTEST(AggregatedHeapSnapshotJSONSerialization) {
10518a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  v8::HandleScope scope;
10528a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  LocalContext env;
10538a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
10548a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  const v8::HeapSnapshot* snapshot =
10558a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang      v8::HeapProfiler::TakeSnapshot(
10568a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang          v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
10578a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  TestJSONStream stream;
10588a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
10598a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_GT(stream.size(), 0);
10608a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang  CHECK_EQ(1, stream.eos_signaled());
10618a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang}
10628a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang
1063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben MurdochTEST(HeapSnapshotGetNodeById) {
1065b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  v8::HandleScope scope;
1066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  LocalContext env;
1067b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1068b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const v8::HeapSnapshot* snapshot =
1069b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("id"));
1070b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const v8::HeapGraphNode* root = snapshot->GetRoot();
1071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_EQ(root, snapshot->GetNodeById(root->GetId()));
1072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  for (int i = 0, count = root->GetChildrenCount(); i < count; ++i) {
1073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    const v8::HeapGraphEdge* prop = root->GetChild(i);
1074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CHECK_EQ(
1075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        prop->GetToNode(), snapshot->GetNodeById(prop->GetToNode()->GetId()));
1076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1077b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  // Check a big id, which should not exist yet.
1078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
1079b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1080b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1081b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochnamespace {
1083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochclass TestActivityControl : public v8::ActivityControl {
1085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch public:
1086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  explicit TestActivityControl(int abort_count)
1087b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      : done_(0), total_(0), abort_count_(abort_count) {}
1088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  ControlOption ReportProgressValue(int done, int total) {
1089b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    done_ = done;
1090b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    total_ = total;
1091b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    return --abort_count_ != 0 ? kContinue : kAbort;
1092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  }
1093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int done() { return done_; }
1094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int total() { return total_; }
1095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch private:
1097b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int done_;
1098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int total_;
1099b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  int abort_count_;
1100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch};
1101b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1102b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben MurdochTEST(TakeHeapSnapshotAborting) {
1104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  v8::HandleScope scope;
1105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  LocalContext env;
1106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
1108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  TestActivityControl aborting_control(3);
1109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const v8::HeapSnapshot* no_snapshot =
1110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"),
1111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                     v8::HeapSnapshot::kFull,
1112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                     &aborting_control);
1113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_EQ(NULL, no_snapshot);
1114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
1115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_GT(aborting_control.total(), aborting_control.done());
1116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  TestActivityControl control(-1);  // Don't abort.
1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  const v8::HeapSnapshot* snapshot =
1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      v8::HeapProfiler::TakeSnapshot(v8::String::New("full"),
1120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                     v8::HeapSnapshot::kFull,
1121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                     &control);
1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_NE(NULL, snapshot);
1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
1124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_EQ(control.total(), control.done());
1125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  CHECK_GT(control.total(), 0);
1126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch}
1127b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
112844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
112944f0eee88ff00398ff7f715fab053374d808c90dSteve Blocknamespace {
113044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
113144f0eee88ff00398ff7f715fab053374d808c90dSteve Blockclass TestRetainedObjectInfo : public v8::RetainedObjectInfo {
113244f0eee88ff00398ff7f715fab053374d808c90dSteve Block public:
113344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  TestRetainedObjectInfo(int hash,
113444f0eee88ff00398ff7f715fab053374d808c90dSteve Block                         const char* label,
113544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                         intptr_t element_count = -1,
113644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                         intptr_t size = -1)
113744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      : disposed_(false),
113844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        hash_(hash),
113944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        label_(label),
114044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        element_count_(element_count),
114144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        size_(size) {
114244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    instances.Add(this);
114344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
114444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual ~TestRetainedObjectInfo() {}
114544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual void Dispose() {
114644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    CHECK(!disposed_);
114744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    disposed_ = true;
114844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
114944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual bool IsEquivalent(RetainedObjectInfo* other) {
115044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return GetHash() == other->GetHash();
115144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
115244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual intptr_t GetHash() { return hash_; }
115344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual const char* GetLabel() { return label_; }
115444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual intptr_t GetElementCount() { return element_count_; }
115544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  virtual intptr_t GetSizeInBytes() { return size_; }
115644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  bool disposed() { return disposed_; }
115744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
115844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static v8::RetainedObjectInfo* WrapperInfoCallback(
115944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      uint16_t class_id, v8::Handle<v8::Value> wrapper) {
116044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (class_id == 1) {
116144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (wrapper->IsString()) {
116244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        v8::String::AsciiValue ascii(wrapper);
116344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (strcmp(*ascii, "AAA") == 0)
116444f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return new TestRetainedObjectInfo(1, "aaa", 100);
116544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        else if (strcmp(*ascii, "BBB") == 0)
116644f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return new TestRetainedObjectInfo(1, "aaa", 100);
116744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
116844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    } else if (class_id == 2) {
116944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      if (wrapper->IsString()) {
117044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        v8::String::AsciiValue ascii(wrapper);
117144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if (strcmp(*ascii, "CCC") == 0)
117244f0eee88ff00398ff7f715fab053374d808c90dSteve Block          return new TestRetainedObjectInfo(2, "ccc");
117344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      }
117444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
117544f0eee88ff00398ff7f715fab053374d808c90dSteve Block    CHECK(false);
117644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return NULL;
117744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
117844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
117944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  static i::List<TestRetainedObjectInfo*> instances;
118044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
118144f0eee88ff00398ff7f715fab053374d808c90dSteve Block private:
118244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  bool disposed_;
118344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int category_;
118444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  int hash_;
118544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const char* label_;
118644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  intptr_t element_count_;
118744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  intptr_t size_;
118844f0eee88ff00398ff7f715fab053374d808c90dSteve Block};
118944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
119044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
119144f0eee88ff00398ff7f715fab053374d808c90dSteve Blocki::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
119244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
119344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
119444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
119544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockstatic const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
119644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                        v8::HeapGraphNode::Type type,
119744f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                        const char* name) {
119844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
119944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
120044f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if (node->GetType() == type && strcmp(name,
120144f0eee88ff00398ff7f715fab053374d808c90dSteve Block               const_cast<i::HeapEntry*>(
120244f0eee88ff00398ff7f715fab053374d808c90dSteve Block                   reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
120344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      return node;
120444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    }
120544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
120644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  return NULL;
120744f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
120844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
120944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
121044f0eee88ff00398ff7f715fab053374d808c90dSteve BlockTEST(HeapSnapshotRetainedObjectInfo) {
121144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HandleScope scope;
121244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  LocalContext env;
121344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
121444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HeapProfiler::DefineWrapperClass(
121544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      1, TestRetainedObjectInfo::WrapperInfoCallback);
121644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HeapProfiler::DefineWrapperClass(
121744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      2, TestRetainedObjectInfo::WrapperInfoCallback);
121844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::Persistent<v8::String> p_AAA =
121944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      v8::Persistent<v8::String>::New(v8_str("AAA"));
122044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  p_AAA.SetWrapperClassId(1);
122144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::Persistent<v8::String> p_BBB =
122244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      v8::Persistent<v8::String>::New(v8_str("BBB"));
122344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  p_BBB.SetWrapperClassId(1);
122444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::Persistent<v8::String> p_CCC =
122544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      v8::Persistent<v8::String>::New(v8_str("CCC"));
122644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  p_CCC.SetWrapperClassId(2);
122744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
122844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapSnapshot* snapshot =
122944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      v8::HeapProfiler::TakeSnapshot(v8::String::New("retained"));
123044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
123144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
123244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
123344f0eee88ff00398ff7f715fab053374d808c90dSteve Block    CHECK(TestRetainedObjectInfo::instances[i]->disposed());
123444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    delete TestRetainedObjectInfo::instances[i];
123544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  }
123644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
123744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapGraphNode* natives = GetNode(
123844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(Native objects)");
123944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, natives);
124044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(2, natives->GetChildrenCount());
124144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapGraphNode* aaa = GetNode(
124244f0eee88ff00398ff7f715fab053374d808c90dSteve Block      natives, v8::HeapGraphNode::kNative, "aaa / 100 entries");
124344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, aaa);
124444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapGraphNode* ccc = GetNode(
124544f0eee88ff00398ff7f715fab053374d808c90dSteve Block      natives, v8::HeapGraphNode::kNative, "ccc");
124644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, ccc);
124744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
124844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(2, aaa->GetChildrenCount());
124944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapGraphNode* n_AAA = GetNode(
125044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      aaa, v8::HeapGraphNode::kString, "AAA");
125144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, n_AAA);
125244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapGraphNode* n_BBB = GetNode(
125344f0eee88ff00398ff7f715fab053374d808c90dSteve Block      aaa, v8::HeapGraphNode::kString, "BBB");
125444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, n_BBB);
125544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(1, ccc->GetChildrenCount());
125644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapGraphNode* n_CCC = GetNode(
125744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      ccc, v8::HeapGraphNode::kString, "CCC");
125844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, n_CCC);
125944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
126044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "Native"));
126144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "Native"));
126244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "Native"));
126344f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
126444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
126544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
126644f0eee88ff00398ff7f715fab053374d808c90dSteve BlockTEST(DeleteAllHeapSnapshots) {
126744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HandleScope scope;
126844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  LocalContext env;
126944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
127044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
127144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HeapProfiler::DeleteAllSnapshots();
127244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
127344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
127444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
127544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HeapProfiler::DeleteAllSnapshots();
127644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
127744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
127844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("2")));
127944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
128044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HeapProfiler::DeleteAllSnapshots();
128144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
128244f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
128344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
128444f0eee88ff00398ff7f715fab053374d808c90dSteve Block
128544f0eee88ff00398ff7f715fab053374d808c90dSteve BlockTEST(DeleteHeapSnapshot) {
128644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  v8::HandleScope scope;
128744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  LocalContext env;
128844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
128944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
129044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapSnapshot* s1 =
129144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      v8::HeapProfiler::TakeSnapshot(v8::String::New("1"));
129244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, s1);
129344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
129444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  unsigned uid1 = s1->GetUid();
129544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(s1, v8::HeapProfiler::FindSnapshot(uid1));
129644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const_cast<v8::HeapSnapshot*>(s1)->Delete();
129744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
129844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid1));
129944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
130044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapSnapshot* s2 =
130144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      v8::HeapProfiler::TakeSnapshot(v8::String::New("2"));
130244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, s2);
130344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
130444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  unsigned uid2 = s2->GetUid();
130544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
130644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(s2, v8::HeapProfiler::FindSnapshot(uid2));
130744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const v8::HeapSnapshot* s3 =
130844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      v8::HeapProfiler::TakeSnapshot(v8::String::New("3"));
130944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(NULL, s3);
131044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
131144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  unsigned uid3 = s3->GetUid();
131244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
131344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
131444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const_cast<v8::HeapSnapshot*>(s2)->Delete();
131544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
131644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2));
131744f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
131844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  const_cast<v8::HeapSnapshot*>(s3)->Delete();
131944f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
132044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3));
132144f0eee88ff00398ff7f715fab053374d808c90dSteve Block}
132244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // ENABLE_LOGGING_AND_PROFILING
1324