blob: a3e14cb74fbf6bdc6924ae7eafed12087e0c9be9 [file] [log] [blame]
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002//
3// Tests for heap profiler
4
5#ifdef ENABLE_LOGGING_AND_PROFILING
6
7#include "v8.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008
9#include "cctest.h"
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010#include "heap-profiler.h"
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000011#include "snapshot.h"
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000012#include "string-stream.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000013#include "utils-inl.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000014#include "zone-inl.h"
whesse@chromium.org2c186ca2010-06-16 11:32:39 +000015#include "../include/v8-profiler.h"
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000016
17namespace i = v8::internal;
18using i::ClustersCoarser;
19using i::JSObjectsCluster;
20using i::JSObjectsRetainerTree;
21using i::JSObjectsClusterTree;
22using i::RetainerHeapProfile;
23
24
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000025namespace {
26
27class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
28 public:
29 ConstructorHeapProfileTestHelper()
30 : i::ConstructorHeapProfile(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000031 f_name_(FACTORY->NewStringFromAscii(i::CStrVector("F"))),
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000032 f_count_(0) {
33 }
34
35 void Call(const JSObjectsCluster& cluster,
36 const i::NumberAndSizeInfo& number_and_size) {
37 if (f_name_->Equals(cluster.constructor())) {
38 CHECK_EQ(f_count_, 0);
39 f_count_ = number_and_size.number();
40 CHECK_GT(f_count_, 0);
41 }
42 }
43
44 int f_count() { return f_count_; }
45
46 private:
47 i::Handle<i::String> f_name_;
48 int f_count_;
49};
50
51} // namespace
52
53
54TEST(ConstructorProfile) {
55 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +000056 LocalContext env;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000057
vegorov@chromium.org42841962010-10-18 11:18:59 +000058 CompileRun(
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000059 "function F() {} // A constructor\n"
60 "var f1 = new F();\n"
61 "var f2 = new F();\n");
62
63 ConstructorHeapProfileTestHelper cons_profile;
64 i::AssertNoAllocation no_alloc;
65 i::HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000066 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000067 cons_profile.CollectStats(obj);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000068 CHECK_EQ(0, cons_profile.f_count());
69 cons_profile.PrintStats();
70 CHECK_EQ(2, cons_profile.f_count());
71}
72
73
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +000074static JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree,
75 i::String* constructor,
76 int instance,
77 JSObjectsCluster* ref1 = NULL,
78 JSObjectsCluster* ref2 = NULL,
79 JSObjectsCluster* ref3 = NULL) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000080 JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
81 JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
82 JSObjectsClusterTree::Locator o_loc;
83 if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc);
84 if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc);
85 if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc);
86 JSObjectsRetainerTree::Locator loc;
87 tree->Insert(o, &loc);
88 loc.set_value(o_tree);
89 return o;
90}
91
92
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +000093static void AddSelfReferenceToTree(JSObjectsRetainerTree* tree,
94 JSObjectsCluster* self_ref) {
95 JSObjectsRetainerTree::Locator loc;
96 CHECK(tree->Find(*self_ref, &loc));
97 JSObjectsClusterTree::Locator o_loc;
98 CHECK_NE(NULL, loc.value());
99 loc.value()->Insert(*self_ref, &o_loc);
100}
101
102
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000103static inline void CheckEqualsHelper(const char* file, int line,
104 const char* expected_source,
105 const JSObjectsCluster& expected,
106 const char* value_source,
107 const JSObjectsCluster& value) {
108 if (JSObjectsCluster::Compare(expected, value) != 0) {
109 i::HeapStringAllocator allocator;
110 i::StringStream stream(&allocator);
111 stream.Add("# Expected: ");
112 expected.DebugPrint(&stream);
113 stream.Add("\n# Found: ");
114 value.DebugPrint(&stream);
115 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s",
116 expected_source, value_source,
117 *stream.ToCString());
118 }
119}
120
121
122static inline void CheckNonEqualsHelper(const char* file, int line,
123 const char* expected_source,
124 const JSObjectsCluster& expected,
125 const char* value_source,
126 const JSObjectsCluster& value) {
127 if (JSObjectsCluster::Compare(expected, value) == 0) {
128 i::HeapStringAllocator allocator;
129 i::StringStream stream(&allocator);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000130 stream.Add("# !Expected: ");
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000131 expected.DebugPrint(&stream);
132 stream.Add("\n# Found: ");
133 value.DebugPrint(&stream);
134 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s",
135 expected_source, value_source,
136 *stream.ToCString());
137 }
138}
139
140
141TEST(ClustersCoarserSimple) {
142 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000143 LocalContext env;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000144
danno@chromium.org40cb8782011-05-25 07:58:50 +0000145 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000146
147 JSObjectsRetainerTree tree;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000148 JSObjectsCluster function(HEAP->function_class_symbol());
149 JSObjectsCluster a(*FACTORY->NewStringFromAscii(i::CStrVector("A")));
150 JSObjectsCluster b(*FACTORY->NewStringFromAscii(i::CStrVector("B")));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000151
152 // o1 <- Function
153 JSObjectsCluster o1 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000154 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000155 // o2 <- Function
156 JSObjectsCluster o2 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000158 // o3 <- A, B
159 JSObjectsCluster o3 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &a, &b);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000161 // o4 <- B, A
162 JSObjectsCluster o4 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x400, &b, &a);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000164 // o5 <- A, B, Function
165 JSObjectsCluster o5 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000166 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x500,
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000167 &a, &b, &function);
168
169 ClustersCoarser coarser;
170 coarser.Process(&tree);
171
172 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
173 CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
174 CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
175 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
176}
177
178
179TEST(ClustersCoarserMultipleConstructors) {
180 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000181 LocalContext env;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000182
danno@chromium.org40cb8782011-05-25 07:58:50 +0000183 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000184
185 JSObjectsRetainerTree tree;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 JSObjectsCluster function(HEAP->function_class_symbol());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000187
188 // o1 <- Function
189 JSObjectsCluster o1 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000190 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000191 // a1 <- Function
192 JSObjectsCluster a1 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x1000, &function);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000194 // o2 <- Function
195 JSObjectsCluster o2 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000196 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000197 // a2 <- Function
198 JSObjectsCluster a2 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000199 AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x2000, &function);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000200
201 ClustersCoarser coarser;
202 coarser.Process(&tree);
203
204 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
205 CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
206}
207
208
209TEST(ClustersCoarserPathsTraversal) {
210 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000211 LocalContext env;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000212
danno@chromium.org40cb8782011-05-25 07:58:50 +0000213 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000214
215 JSObjectsRetainerTree tree;
216
217 // On the following graph:
218 //
219 // p
220 // <- o21 <- o11 <-
221 // q o
222 // <- o22 <- o12 <-
223 // r
224 //
225 // we expect that coarser will deduce equivalences: p ~ q ~ r,
226 // o21 ~ o22, and o11 ~ o12.
227
228 JSObjectsCluster o =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000230 JSObjectsCluster o11 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000231 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000232 JSObjectsCluster o12 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000233 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000234 JSObjectsCluster o21 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x210, &o11);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000236 JSObjectsCluster o22 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x220, &o12);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000238 JSObjectsCluster p =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o21);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000240 JSObjectsCluster q =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000241 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o21, &o22);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000242 JSObjectsCluster r =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000243 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o22);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000244
245 ClustersCoarser coarser;
246 coarser.Process(&tree);
247
248 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000249 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000250 CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
251 CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
252 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000253 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000254 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
255 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
256 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
257 CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
258}
259
260
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000261TEST(ClustersCoarserSelf) {
262 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000263 LocalContext env;
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000264
danno@chromium.org40cb8782011-05-25 07:58:50 +0000265 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000266
267 JSObjectsRetainerTree tree;
268
269 // On the following graph:
270 //
271 // p (self-referencing)
272 // <- o1 <-
273 // q (self-referencing) o
274 // <- o2 <-
275 // r (self-referencing)
276 //
277 // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
278
279 JSObjectsCluster o =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000280 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000281 JSObjectsCluster o1 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000283 JSObjectsCluster o2 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000285 JSObjectsCluster p =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o1);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000287 AddSelfReferenceToTree(&tree, &p);
288 JSObjectsCluster q =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000289 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o1, &o2);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000290 AddSelfReferenceToTree(&tree, &q);
291 JSObjectsCluster r =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000292 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o2);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000293 AddSelfReferenceToTree(&tree, &r);
294
295 ClustersCoarser coarser;
296 coarser.Process(&tree);
297
298 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
299 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1));
300 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
301 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
302 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
303 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
304 CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p));
305}
306
307
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000308namespace {
309
310class RetainerProfilePrinter : public RetainerHeapProfile::Printer {
311 public:
312 RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
313
314 void PrintRetainers(const JSObjectsCluster& cluster,
315 const i::StringStream& retainers) {
316 cluster.Print(&stream_);
317 stream_.Add("%s", *(retainers.ToCString()));
318 stream_.Put('\0');
319 }
320
321 const char* GetRetainers(const char* constructor) {
322 FillLines();
323 const size_t cons_len = strlen(constructor);
324 for (int i = 0; i < lines_.length(); ++i) {
325 if (strncmp(constructor, lines_[i], cons_len) == 0 &&
326 lines_[i][cons_len] == ',') {
327 return lines_[i] + cons_len + 1;
328 }
329 }
330 return NULL;
331 }
332
333 private:
334 void FillLines() {
335 if (lines_.length() > 0) return;
336 stream_.Put('\0');
337 stream_str_ = stream_.ToCString();
338 const char* pos = *stream_str_;
339 while (pos != NULL && *pos != '\0') {
340 lines_.Add(pos);
341 pos = strchr(pos, '\0');
342 if (pos != NULL) ++pos;
343 }
344 }
345
346 i::HeapStringAllocator allocator_;
347 i::StringStream stream_;
348 i::SmartPointer<const char> stream_str_;
349 i::List<const char*> lines_;
350};
351
352} // namespace
353
354
355TEST(RetainerProfile) {
356 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000357 LocalContext env;
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000358
vegorov@chromium.org42841962010-10-18 11:18:59 +0000359 CompileRun(
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000360 "function A() {}\n"
361 "function B(x) { this.x = x; }\n"
362 "function C(x) { this.x1 = x; this.x2 = x; }\n"
363 "var a = new A();\n"
364 "var b1 = new B(a), b2 = new B(a);\n"
365 "var c = new C(a);");
366
367 RetainerHeapProfile ret_profile;
368 i::AssertNoAllocation no_alloc;
369 i::HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000370 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000371 ret_profile.CollectStats(obj);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000372 ret_profile.CoarseAndAggregate();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000373 RetainerProfilePrinter printer;
374 ret_profile.DebugPrintStats(&printer);
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000375 const char* retainers_of_a = printer.GetRetainers("A");
376 // The order of retainers is unspecified, so we check string length, and
377 // verify each retainer separately.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000378 CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"),
379 i::StrLength(retainers_of_a));
mikhail.naganov@gmail.com8578ca62009-09-30 14:20:18 +0000380 CHECK(strstr(retainers_of_a, "(global property);1") != NULL);
381 CHECK(strstr(retainers_of_a, "B;2") != NULL);
382 CHECK(strstr(retainers_of_a, "C;2") != NULL);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +0000383 CHECK_EQ("(global property);2", printer.GetRetainers("B"));
384 CHECK_EQ("(global property);1", printer.GetRetainers("C"));
385}
386
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000387
388namespace {
389
390class NamedEntriesDetector {
391 public:
392 NamedEntriesDetector()
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000393 : has_A2(false), has_B2(false), has_C2(false) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000394 }
395
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000396 void Apply(i::HeapEntry** entry_ptr) {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000397 if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
398 if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
399 if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
400 }
401
402 static bool IsReachableNodeWithName(i::HeapEntry* entry, const char* name) {
403 return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000404 }
405
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000406 bool has_A2;
407 bool has_B2;
408 bool has_C2;
409};
410
411} // namespace
412
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000413
414static const v8::HeapGraphNode* GetGlobalObject(
415 const v8::HeapSnapshot* snapshot) {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000416 CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
417 const v8::HeapGraphNode* global_obj =
418 snapshot->GetRoot()->GetChild(0)->GetToNode();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000419 CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
420 reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000421 return global_obj;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000422}
423
424
425static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
426 v8::HeapGraphEdge::Type type,
427 const char* name) {
428 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
429 const v8::HeapGraphEdge* prop = node->GetChild(i);
430 v8::String::AsciiValue prop_name(prop->GetName());
431 if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
432 return prop->GetToNode();
433 }
434 return NULL;
435}
436
437
438static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
439 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
440 const v8::HeapGraphEdge* prop = node->GetChild(i);
441 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000442 if (node->GetType() == v8::HeapGraphNode::kString) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000443 v8::String::AsciiValue node_name(node->GetName());
444 if (strcmp(contents, *node_name) == 0) return true;
445 }
446 }
447 return false;
448}
449
450
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000451TEST(HeapSnapshot) {
452 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000453 LocalContext env2;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000454
vegorov@chromium.org42841962010-10-18 11:18:59 +0000455 CompileRun(
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000456 "function A2() {}\n"
457 "function B2(x) { return function() { return typeof x; }; }\n"
458 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
459 "var a2 = new A2();\n"
460 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
461 "var c2 = new C2(a2);");
462 const v8::HeapSnapshot* snapshot_env2 =
463 v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000464 i::HeapSnapshot* i_snapshot_env2 =
465 const_cast<i::HeapSnapshot*>(
466 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000467 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
468 // Paint all nodes reachable from global object.
469 i_snapshot_env2->ClearPaint();
470 const_cast<i::HeapEntry*>(
471 reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
472
ager@chromium.org01fe7df2010-11-10 11:59:11 +0000473 // Verify, that JS global object of env2 has '..2' properties.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000474 const v8::HeapGraphNode* a2_node =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000475 GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000476 CHECK_NE(NULL, a2_node);
477 CHECK_NE(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000478 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000479 CHECK_NE(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000480 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
481 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000482
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000483 NamedEntriesDetector det;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000484 i_snapshot_env2->IterateEntries(&det);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000485 CHECK(det.has_A2);
486 CHECK(det.has_B2);
487 CHECK(det.has_C2);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +0000488}
489
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000490
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000491TEST(HeapSnapshotObjectSizes) {
492 v8::HandleScope scope;
493 LocalContext env;
494
495 // -a-> X1 --a
496 // x -b-> X2 <-|
vegorov@chromium.org42841962010-10-18 11:18:59 +0000497 CompileRun(
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000498 "function X(a, b) { this.a = a; this.b = b; }\n"
499 "x = new X(new X(), new X());\n"
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000500 "(function() { x.a.a = x.b; })();");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000501 const v8::HeapSnapshot* snapshot =
502 v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes"));
503 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
504 const v8::HeapGraphNode* x =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000505 GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000506 CHECK_NE(NULL, x);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000507 const v8::HeapGraphNode* x1 =
508 GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
509 CHECK_NE(NULL, x1);
510 const v8::HeapGraphNode* x2 =
511 GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
512 CHECK_NE(NULL, x2);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000513
514 // Test approximate sizes.
515 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(false));
516 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(false));
517 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(false));
518 // Test exact sizes.
519 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(true));
520 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(true));
521 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(true));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000522}
523
524
525TEST(HeapSnapshotEntryChildren) {
526 v8::HandleScope scope;
527 LocalContext env;
528
vegorov@chromium.org42841962010-10-18 11:18:59 +0000529 CompileRun(
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000530 "function A() { }\n"
531 "a = new A;");
532 const v8::HeapSnapshot* snapshot =
533 v8::HeapProfiler::TakeSnapshot(v8::String::New("children"));
534 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
535 for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
536 const v8::HeapGraphEdge* prop = global->GetChild(i);
537 CHECK_EQ(global, prop->GetFromNode());
538 }
539 const v8::HeapGraphNode* a =
540 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
541 CHECK_NE(NULL, a);
542 for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
543 const v8::HeapGraphEdge* prop = a->GetChild(i);
544 CHECK_EQ(a, prop->GetFromNode());
545 }
546}
547
548
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000549TEST(HeapSnapshotCodeObjects) {
550 v8::HandleScope scope;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000551 LocalContext env;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000552
vegorov@chromium.org42841962010-10-18 11:18:59 +0000553 CompileRun(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000554 "function lazy(x) { return x - 1; }\n"
555 "function compiled(x) { return x + 1; }\n"
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000556 "var anonymous = (function() { return function() { return 0; } })();\n"
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000557 "compiled(1)");
558 const v8::HeapSnapshot* snapshot =
559 v8::HeapProfiler::TakeSnapshot(v8::String::New("code"));
560
561 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
562 const v8::HeapGraphNode* compiled =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000563 GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000564 CHECK_NE(NULL, compiled);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000565 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000566 const v8::HeapGraphNode* lazy =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000567 GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000568 CHECK_NE(NULL, lazy);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000569 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000570 const v8::HeapGraphNode* anonymous =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000571 GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000572 CHECK_NE(NULL, anonymous);
573 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
574 v8::String::AsciiValue anonymous_name(anonymous->GetName());
vegorov@chromium.org42841962010-10-18 11:18:59 +0000575 CHECK_EQ("", *anonymous_name);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000576
577 // Find references to code.
578 const v8::HeapGraphNode* compiled_code =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000579 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000580 CHECK_NE(NULL, compiled_code);
581 const v8::HeapGraphNode* lazy_code =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000582 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000583 CHECK_NE(NULL, lazy_code);
584
585 // Verify that non-compiled code doesn't contain references to "x"
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000586 // literal, while compiled code does. The scope info is stored in FixedArray
587 // objects attached to the SharedFunctionInfo.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000588 bool compiled_references_x = false, lazy_references_x = false;
589 for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
590 const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
591 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000592 if (node->GetType() == v8::HeapGraphNode::kArray) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000593 if (HasString(node, "x")) {
594 compiled_references_x = true;
595 break;
596 }
597 }
598 }
599 for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
600 const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
601 const v8::HeapGraphNode* node = prop->GetToNode();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000602 if (node->GetType() == v8::HeapGraphNode::kArray) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000603 if (HasString(node, "x")) {
604 lazy_references_x = true;
605 break;
606 }
607 }
608 }
609 CHECK(compiled_references_x);
610 CHECK(!lazy_references_x);
611}
612
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000613
vegorov@chromium.org42841962010-10-18 11:18:59 +0000614TEST(HeapSnapshotHeapNumbers) {
615 v8::HandleScope scope;
616 LocalContext env;
617 CompileRun(
618 "a = 1; // a is Smi\n"
619 "b = 2.5; // b is HeapNumber");
620 const v8::HeapSnapshot* snapshot =
621 v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers"));
622 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000623 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
vegorov@chromium.org42841962010-10-18 11:18:59 +0000624 const v8::HeapGraphNode* b =
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000625 GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
vegorov@chromium.org42841962010-10-18 11:18:59 +0000626 CHECK_NE(NULL, b);
627 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
628}
629
630
631TEST(HeapSnapshotInternalReferences) {
632 v8::HandleScope scope;
633 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
634 global_template->SetInternalFieldCount(2);
635 LocalContext env(NULL, global_template);
636 v8::Handle<v8::Object> global_proxy = env->Global();
637 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
638 CHECK_EQ(2, global->InternalFieldCount());
639 v8::Local<v8::Object> obj = v8::Object::New();
640 global->SetInternalField(0, v8_num(17));
641 global->SetInternalField(1, obj);
642 const v8::HeapSnapshot* snapshot =
643 v8::HeapProfiler::TakeSnapshot(v8::String::New("internals"));
644 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
645 // The first reference will not present, because it's a Smi.
646 CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
647 // The second reference is to an object.
648 CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
649}
650
651
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000652// Trying to introduce a check helper for uint64_t causes many
653// overloading ambiguities, so it seems easier just to cast
654// them to a signed type.
655#define CHECK_EQ_UINT64_T(a, b) \
656 CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b))
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000657#define CHECK_NE_UINT64_T(a, b) \
658 CHECK((a) != (b)) // NOLINT
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000659
660TEST(HeapEntryIdsAndGC) {
661 v8::HandleScope scope;
662 LocalContext env;
663
vegorov@chromium.org42841962010-10-18 11:18:59 +0000664 CompileRun(
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000665 "function A() {}\n"
666 "function B(x) { this.x = x; }\n"
667 "var a = new A();\n"
668 "var b = new B(a);");
669 const v8::HeapSnapshot* snapshot1 =
670 v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
671
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000672 HEAP->CollectAllGarbage(true); // Enforce compaction.
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000673
674 const v8::HeapSnapshot* snapshot2 =
675 v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
676
677 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
678 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
679 CHECK_NE_UINT64_T(0, global1->GetId());
680 CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId());
681 const v8::HeapGraphNode* A1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000682 GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
683 CHECK_NE(NULL, A1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000684 const v8::HeapGraphNode* A2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000685 GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
686 CHECK_NE(NULL, A2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000687 CHECK_NE_UINT64_T(0, A1->GetId());
688 CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
689 const v8::HeapGraphNode* B1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000690 GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
691 CHECK_NE(NULL, B1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000692 const v8::HeapGraphNode* B2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000693 GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
694 CHECK_NE(NULL, B2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000695 CHECK_NE_UINT64_T(0, B1->GetId());
696 CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
697 const v8::HeapGraphNode* a1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000698 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
699 CHECK_NE(NULL, a1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000700 const v8::HeapGraphNode* a2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000701 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
702 CHECK_NE(NULL, a2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000703 CHECK_NE_UINT64_T(0, a1->GetId());
704 CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
705 const v8::HeapGraphNode* b1 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000706 GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
707 CHECK_NE(NULL, b1);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000708 const v8::HeapGraphNode* b2 =
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000709 GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
710 CHECK_NE(NULL, b2);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000711 CHECK_NE_UINT64_T(0, b1->GetId());
712 CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
713}
714
715
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000716TEST(HeapSnapshotRootPreservedAfterSorting) {
717 v8::HandleScope scope;
718 LocalContext env;
719 const v8::HeapSnapshot* snapshot =
720 v8::HeapProfiler::TakeSnapshot(v8::String::New("s"));
721 const v8::HeapGraphNode* root1 = snapshot->GetRoot();
722 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
723 snapshot))->GetSortedEntriesList();
724 const v8::HeapGraphNode* root2 = snapshot->GetRoot();
725 CHECK_EQ(root1, root2);
726}
727
728
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000729static const v8::HeapGraphNode* GetChild(
730 const v8::HeapGraphNode* node,
731 v8::HeapGraphNode::Type type,
732 const char* name,
733 const v8::HeapGraphNode* after = NULL) {
734 bool ignore_child = after == NULL ? false : true;
735 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
736 const v8::HeapGraphEdge* prop = node->GetChild(i);
737 const v8::HeapGraphNode* child = prop->GetToNode();
738 v8::String::AsciiValue child_name(child->GetName());
739 if (!ignore_child
740 && child->GetType() == type
741 && strcmp(name, *child_name) == 0)
742 return child;
743 if (after != NULL && child == after) ignore_child = false;
744 }
745 return NULL;
746}
747
748static bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
749 int element) {
750 for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
751 const v8::HeapGraphEdge* prop = node->GetRetainer(i);
752 if (prop->GetType() == v8::HeapGraphEdge::kElement
753 && element == prop->GetName()->Int32Value())
754 return true;
755 }
756 return false;
757}
758
759TEST(AggregatedHeapSnapshot) {
760 v8::HandleScope scope;
761 LocalContext env;
762
vegorov@chromium.org42841962010-10-18 11:18:59 +0000763 CompileRun(
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000764 "function A() {}\n"
765 "function B(x) { this.x = x; }\n"
766 "var a = new A();\n"
767 "var b = new B(a);");
768 const v8::HeapSnapshot* snapshot =
769 v8::HeapProfiler::TakeSnapshot(
770 v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
771 const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(),
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000772 v8::HeapGraphNode::kHidden,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000773 "STRING_TYPE");
774 CHECK_NE(NULL, strings);
775 CHECK_NE(0, strings->GetSelfSize());
776 CHECK_NE(0, strings->GetInstancesCount());
777 const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(),
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000778 v8::HeapGraphNode::kHidden,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000779 "MAP_TYPE");
780 CHECK_NE(NULL, maps);
781 CHECK_NE(0, maps->GetSelfSize());
782 CHECK_NE(0, maps->GetInstancesCount());
783
784 const v8::HeapGraphNode* a = GetChild(snapshot->GetRoot(),
785 v8::HeapGraphNode::kObject,
786 "A");
787 CHECK_NE(NULL, a);
788 CHECK_NE(0, a->GetSelfSize());
789 CHECK_EQ(1, a->GetInstancesCount());
790
791 const v8::HeapGraphNode* b = GetChild(snapshot->GetRoot(),
792 v8::HeapGraphNode::kObject,
793 "B");
794 CHECK_NE(NULL, b);
795 CHECK_NE(0, b->GetSelfSize());
796 CHECK_EQ(1, b->GetInstancesCount());
797
798 const v8::HeapGraphNode* glob_prop = GetChild(snapshot->GetRoot(),
799 v8::HeapGraphNode::kObject,
800 "(global property)",
801 b);
802 CHECK_NE(NULL, glob_prop);
803 CHECK_EQ(0, glob_prop->GetSelfSize());
804 CHECK_EQ(0, glob_prop->GetInstancesCount());
805 CHECK_NE(0, glob_prop->GetChildrenCount());
806
807 const v8::HeapGraphNode* a_from_glob_prop = GetChild(
808 glob_prop,
809 v8::HeapGraphNode::kObject,
810 "A");
811 CHECK_NE(NULL, a_from_glob_prop);
812 CHECK_EQ(0, a_from_glob_prop->GetSelfSize());
813 CHECK_EQ(0, a_from_glob_prop->GetInstancesCount());
814 CHECK_EQ(0, a_from_glob_prop->GetChildrenCount()); // Retains nothing.
815 CHECK(IsNodeRetainedAs(a_from_glob_prop, 1)); // (global propery) has 1 ref.
816
817 const v8::HeapGraphNode* b_with_children = GetChild(
818 snapshot->GetRoot(),
819 v8::HeapGraphNode::kObject,
820 "B",
821 b);
822 CHECK_NE(NULL, b_with_children);
823 CHECK_EQ(0, b_with_children->GetSelfSize());
824 CHECK_EQ(0, b_with_children->GetInstancesCount());
825 CHECK_NE(0, b_with_children->GetChildrenCount());
826
827 const v8::HeapGraphNode* a_from_b = GetChild(
828 b_with_children,
829 v8::HeapGraphNode::kObject,
830 "A");
831 CHECK_NE(NULL, a_from_b);
832 CHECK_EQ(0, a_from_b->GetSelfSize());
833 CHECK_EQ(0, a_from_b->GetInstancesCount());
834 CHECK_EQ(0, a_from_b->GetChildrenCount()); // Retains nothing.
835 CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A.
836}
837
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000838
839TEST(HeapEntryDominator) {
840 // The graph looks like this:
841 //
842 // -> node1
843 // a |^
844 // -> node5 ba
845 // a v|
846 // node6 -> node2
847 // b a |^
848 // -> node4 ba
849 // b v|
850 // -> node3
851 //
852 // The dominator for all nodes is node6.
853
854 v8::HandleScope scope;
855 LocalContext env;
856
857 CompileRun(
858 "function X(a, b) { this.a = a; this.b = b; }\n"
859 "node6 = new X(new X(new X()), new X(new X(),new X()));\n"
860 "(function(){\n"
861 "node6.a.a.b = node6.b.a; // node1 -> node2\n"
862 "node6.b.a.a = node6.a.a; // node2 -> node1\n"
863 "node6.b.a.b = node6.b.b; // node2 -> node3\n"
864 "node6.b.b.a = node6.b.a; // node3 -> node2\n"
865 "})();");
866
867 const v8::HeapSnapshot* snapshot =
868 v8::HeapProfiler::TakeSnapshot(v8::String::New("dominators"));
869
870 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
871 CHECK_NE(NULL, global);
872 const v8::HeapGraphNode* node6 =
873 GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
874 CHECK_NE(NULL, node6);
875 const v8::HeapGraphNode* node5 =
876 GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
877 CHECK_NE(NULL, node5);
878 const v8::HeapGraphNode* node4 =
879 GetProperty(node6, v8::HeapGraphEdge::kProperty, "b");
880 CHECK_NE(NULL, node4);
881 const v8::HeapGraphNode* node3 =
882 GetProperty(node4, v8::HeapGraphEdge::kProperty, "b");
883 CHECK_NE(NULL, node3);
884 const v8::HeapGraphNode* node2 =
885 GetProperty(node4, v8::HeapGraphEdge::kProperty, "a");
886 CHECK_NE(NULL, node2);
887 const v8::HeapGraphNode* node1 =
888 GetProperty(node5, v8::HeapGraphEdge::kProperty, "a");
889 CHECK_NE(NULL, node1);
890
891 CHECK_EQ(node6, node1->GetDominatorNode());
892 CHECK_EQ(node6, node2->GetDominatorNode());
893 CHECK_EQ(node6, node3->GetDominatorNode());
894 CHECK_EQ(node6, node4->GetDominatorNode());
895 CHECK_EQ(node6, node5->GetDominatorNode());
896}
897
898
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000899namespace {
900
901class TestJSONStream : public v8::OutputStream {
902 public:
903 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
904 explicit TestJSONStream(int abort_countdown)
905 : eos_signaled_(0), abort_countdown_(abort_countdown) {}
906 virtual ~TestJSONStream() {}
907 virtual void EndOfStream() { ++eos_signaled_; }
908 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
909 if (abort_countdown_ > 0) --abort_countdown_;
910 if (abort_countdown_ == 0) return kAbort;
911 CHECK_GT(chars_written, 0);
912 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
913 memcpy(chunk.start(), buffer, chars_written);
914 return kContinue;
915 }
916 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
917 int eos_signaled() { return eos_signaled_; }
918 int size() { return buffer_.size(); }
919 private:
920 i::Collector<char> buffer_;
921 int eos_signaled_;
922 int abort_countdown_;
923};
924
925class AsciiResource: public v8::String::ExternalAsciiStringResource {
926 public:
927 explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
928 length_ = string.length();
929 }
930 virtual const char* data() const { return data_; }
931 virtual size_t length() const { return length_; }
932 private:
933 const char* data_;
934 size_t length_;
935};
936
937} // namespace
938
939TEST(HeapSnapshotJSONSerialization) {
940 v8::HandleScope scope;
941 LocalContext env;
942
943#define STRING_LITERAL_FOR_TEST \
944 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
vegorov@chromium.org42841962010-10-18 11:18:59 +0000945 CompileRun(
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000946 "function A(s) { this.s = s; }\n"
947 "function B(x) { this.x = x; }\n"
948 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
949 "var b = new B(a);");
950 const v8::HeapSnapshot* snapshot =
951 v8::HeapProfiler::TakeSnapshot(v8::String::New("json"));
952 TestJSONStream stream;
953 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
954 CHECK_GT(stream.size(), 0);
955 CHECK_EQ(1, stream.eos_signaled());
956 i::ScopedVector<char> json(stream.size());
957 stream.WriteTo(json);
958
959 // Verify that snapshot string is valid JSON.
960 AsciiResource json_res(json);
961 v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res);
962 env->Global()->Set(v8::String::New("json_snapshot"), json_string);
963 v8::Local<v8::Value> snapshot_parse_result = CompileRun(
964 "var parsed = JSON.parse(json_snapshot); true;");
965 CHECK(!snapshot_parse_result.IsEmpty());
966
967 // Verify that snapshot object has required fields.
968 v8::Local<v8::Object> parsed_snapshot =
969 env->Global()->Get(v8::String::New("parsed"))->ToObject();
970 CHECK(parsed_snapshot->Has(v8::String::New("snapshot")));
971 CHECK(parsed_snapshot->Has(v8::String::New("nodes")));
972 CHECK(parsed_snapshot->Has(v8::String::New("strings")));
973
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000974 // Get node and edge "member" offsets.
975 v8::Local<v8::Value> meta_analysis_result = CompileRun(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000976 "var parsed_meta = parsed.nodes[0];\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000977 "var children_count_offset ="
978 " parsed_meta.fields.indexOf('children_count');\n"
979 "var children_offset ="
980 " parsed_meta.fields.indexOf('children');\n"
981 "var children_meta ="
982 " parsed_meta.types[children_offset];\n"
983 "var child_fields_count = children_meta.fields.length;\n"
984 "var child_type_offset ="
985 " children_meta.fields.indexOf('type');\n"
986 "var child_name_offset ="
987 " children_meta.fields.indexOf('name_or_index');\n"
988 "var child_to_node_offset ="
989 " children_meta.fields.indexOf('to_node');\n"
990 "var property_type ="
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000991 " children_meta.types[child_type_offset].indexOf('property');\n"
992 "var shortcut_type ="
993 " children_meta.types[child_type_offset].indexOf('shortcut');");
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000994 CHECK(!meta_analysis_result.IsEmpty());
995
996 // A helper function for processing encoded nodes.
997 CompileRun(
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000998 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000999 " var nodes = parsed.nodes;\n"
1000 " var strings = parsed.strings;\n"
1001 " for (var i = 0,\n"
1002 " count = nodes[pos + children_count_offset] * child_fields_count;\n"
1003 " i < count; i += child_fields_count) {\n"
1004 " var child_pos = pos + children_offset + i;\n"
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001005 " if (nodes[child_pos + child_type_offset] === prop_type\n"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001006 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
1007 " return nodes[child_pos + child_to_node_offset];\n"
1008 " }\n"
1009 " return null;\n"
1010 "}\n");
1011 // Get the string index using the path: <root> -> <global>.b.x.s
1012 v8::Local<v8::Value> string_obj_pos_val = CompileRun(
1013 "GetChildPosByProperty(\n"
1014 " GetChildPosByProperty(\n"
1015 " GetChildPosByProperty("
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001016 " parsed.nodes[1 + children_offset + child_to_node_offset],"
1017 " \"b\",shortcut_type),\n"
1018 " \"x\", property_type),"
1019 " \"s\", property_type)");
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001020 CHECK(!string_obj_pos_val.IsEmpty());
1021 int string_obj_pos =
1022 static_cast<int>(string_obj_pos_val->ToNumber()->Value());
1023 v8::Local<v8::Object> nodes_array =
1024 parsed_snapshot->Get(v8::String::New("nodes"))->ToObject();
1025 int string_index = static_cast<int>(
1026 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
1027 CHECK_GT(string_index, 0);
1028 v8::Local<v8::Object> strings_array =
1029 parsed_snapshot->Get(v8::String::New("strings"))->ToObject();
1030 v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
1031 v8::Local<v8::String> ref_string =
1032 CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
1033#undef STRING_LITERAL_FOR_TEST
1034 CHECK_EQ(*v8::String::Utf8Value(ref_string),
1035 *v8::String::Utf8Value(string));
1036}
1037
1038
1039TEST(HeapSnapshotJSONSerializationAborting) {
1040 v8::HandleScope scope;
1041 LocalContext env;
1042 const v8::HeapSnapshot* snapshot =
1043 v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"));
1044 TestJSONStream stream(5);
1045 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
1046 CHECK_GT(stream.size(), 0);
1047 CHECK_EQ(0, stream.eos_signaled());
1048}
1049
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001050
1051// Must not crash in debug mode.
1052TEST(AggregatedHeapSnapshotJSONSerialization) {
1053 v8::HandleScope scope;
1054 LocalContext env;
1055
1056 const v8::HeapSnapshot* snapshot =
1057 v8::HeapProfiler::TakeSnapshot(
1058 v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
1059 TestJSONStream stream;
1060 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
1061 CHECK_GT(stream.size(), 0);
1062 CHECK_EQ(1, stream.eos_signaled());
1063}
1064
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001065
1066TEST(HeapSnapshotGetNodeById) {
1067 v8::HandleScope scope;
1068 LocalContext env;
1069
1070 const v8::HeapSnapshot* snapshot =
1071 v8::HeapProfiler::TakeSnapshot(v8::String::New("id"));
1072 const v8::HeapGraphNode* root = snapshot->GetRoot();
1073 CHECK_EQ(root, snapshot->GetNodeById(root->GetId()));
1074 for (int i = 0, count = root->GetChildrenCount(); i < count; ++i) {
1075 const v8::HeapGraphEdge* prop = root->GetChild(i);
1076 CHECK_EQ(
1077 prop->GetToNode(), snapshot->GetNodeById(prop->GetToNode()->GetId()));
1078 }
1079 // Check a big id, which should not exist yet.
1080 CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
1081}
1082
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001083
1084namespace {
1085
1086class TestActivityControl : public v8::ActivityControl {
1087 public:
1088 explicit TestActivityControl(int abort_count)
1089 : done_(0), total_(0), abort_count_(abort_count) {}
1090 ControlOption ReportProgressValue(int done, int total) {
1091 done_ = done;
1092 total_ = total;
1093 return --abort_count_ != 0 ? kContinue : kAbort;
1094 }
1095 int done() { return done_; }
1096 int total() { return total_; }
1097
1098 private:
1099 int done_;
1100 int total_;
1101 int abort_count_;
1102};
1103}
1104
1105TEST(TakeHeapSnapshotAborting) {
1106 v8::HandleScope scope;
1107 LocalContext env;
1108
1109 const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
1110 TestActivityControl aborting_control(3);
1111 const v8::HeapSnapshot* no_snapshot =
1112 v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"),
1113 v8::HeapSnapshot::kFull,
1114 &aborting_control);
1115 CHECK_EQ(NULL, no_snapshot);
1116 CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
1117 CHECK_GT(aborting_control.total(), aborting_control.done());
1118
1119 TestActivityControl control(-1); // Don't abort.
1120 const v8::HeapSnapshot* snapshot =
1121 v8::HeapProfiler::TakeSnapshot(v8::String::New("full"),
1122 v8::HeapSnapshot::kFull,
1123 &control);
1124 CHECK_NE(NULL, snapshot);
1125 CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
1126 CHECK_EQ(control.total(), control.done());
1127 CHECK_GT(control.total(), 0);
1128}
1129
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001130
1131namespace {
1132
1133class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
1134 public:
1135 TestRetainedObjectInfo(int hash,
1136 const char* label,
1137 intptr_t element_count = -1,
1138 intptr_t size = -1)
1139 : disposed_(false),
1140 hash_(hash),
1141 label_(label),
1142 element_count_(element_count),
1143 size_(size) {
1144 instances.Add(this);
1145 }
1146 virtual ~TestRetainedObjectInfo() {}
1147 virtual void Dispose() {
1148 CHECK(!disposed_);
1149 disposed_ = true;
1150 }
1151 virtual bool IsEquivalent(RetainedObjectInfo* other) {
1152 return GetHash() == other->GetHash();
1153 }
1154 virtual intptr_t GetHash() { return hash_; }
1155 virtual const char* GetLabel() { return label_; }
1156 virtual intptr_t GetElementCount() { return element_count_; }
1157 virtual intptr_t GetSizeInBytes() { return size_; }
1158 bool disposed() { return disposed_; }
1159
1160 static v8::RetainedObjectInfo* WrapperInfoCallback(
1161 uint16_t class_id, v8::Handle<v8::Value> wrapper) {
1162 if (class_id == 1) {
1163 if (wrapper->IsString()) {
1164 v8::String::AsciiValue ascii(wrapper);
1165 if (strcmp(*ascii, "AAA") == 0)
1166 return new TestRetainedObjectInfo(1, "aaa", 100);
1167 else if (strcmp(*ascii, "BBB") == 0)
1168 return new TestRetainedObjectInfo(1, "aaa", 100);
1169 }
1170 } else if (class_id == 2) {
1171 if (wrapper->IsString()) {
1172 v8::String::AsciiValue ascii(wrapper);
1173 if (strcmp(*ascii, "CCC") == 0)
1174 return new TestRetainedObjectInfo(2, "ccc");
1175 }
1176 }
1177 CHECK(false);
1178 return NULL;
1179 }
1180
1181 static i::List<TestRetainedObjectInfo*> instances;
1182
1183 private:
1184 bool disposed_;
1185 int category_;
1186 int hash_;
1187 const char* label_;
1188 intptr_t element_count_;
1189 intptr_t size_;
1190};
1191
1192
1193i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
1194}
1195
1196
1197static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
1198 v8::HeapGraphNode::Type type,
1199 const char* name) {
1200 for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
1201 const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
1202 if (node->GetType() == type && strcmp(name,
1203 const_cast<i::HeapEntry*>(
1204 reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
1205 return node;
1206 }
1207 }
1208 return NULL;
1209}
1210
1211
1212TEST(HeapSnapshotRetainedObjectInfo) {
1213 v8::HandleScope scope;
1214 LocalContext env;
1215
1216 v8::HeapProfiler::DefineWrapperClass(
1217 1, TestRetainedObjectInfo::WrapperInfoCallback);
1218 v8::HeapProfiler::DefineWrapperClass(
1219 2, TestRetainedObjectInfo::WrapperInfoCallback);
1220 v8::Persistent<v8::String> p_AAA =
1221 v8::Persistent<v8::String>::New(v8_str("AAA"));
1222 p_AAA.SetWrapperClassId(1);
1223 v8::Persistent<v8::String> p_BBB =
1224 v8::Persistent<v8::String>::New(v8_str("BBB"));
1225 p_BBB.SetWrapperClassId(1);
1226 v8::Persistent<v8::String> p_CCC =
1227 v8::Persistent<v8::String>::New(v8_str("CCC"));
1228 p_CCC.SetWrapperClassId(2);
1229 CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
1230 const v8::HeapSnapshot* snapshot =
1231 v8::HeapProfiler::TakeSnapshot(v8::String::New("retained"));
1232
1233 CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
1234 for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
1235 CHECK(TestRetainedObjectInfo::instances[i]->disposed());
1236 delete TestRetainedObjectInfo::instances[i];
1237 }
1238
1239 const v8::HeapGraphNode* natives = GetNode(
1240 snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(Native objects)");
1241 CHECK_NE(NULL, natives);
1242 CHECK_EQ(2, natives->GetChildrenCount());
1243 const v8::HeapGraphNode* aaa = GetNode(
1244 natives, v8::HeapGraphNode::kNative, "aaa / 100 entries");
1245 CHECK_NE(NULL, aaa);
1246 const v8::HeapGraphNode* ccc = GetNode(
1247 natives, v8::HeapGraphNode::kNative, "ccc");
1248 CHECK_NE(NULL, ccc);
1249
1250 CHECK_EQ(2, aaa->GetChildrenCount());
1251 const v8::HeapGraphNode* n_AAA = GetNode(
1252 aaa, v8::HeapGraphNode::kString, "AAA");
1253 CHECK_NE(NULL, n_AAA);
1254 const v8::HeapGraphNode* n_BBB = GetNode(
1255 aaa, v8::HeapGraphNode::kString, "BBB");
1256 CHECK_NE(NULL, n_BBB);
1257 CHECK_EQ(1, ccc->GetChildrenCount());
1258 const v8::HeapGraphNode* n_CCC = GetNode(
1259 ccc, v8::HeapGraphNode::kString, "CCC");
1260 CHECK_NE(NULL, n_CCC);
1261
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001262 CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
1263 CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
1264 CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001265}
1266
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267
1268TEST(DeleteAllHeapSnapshots) {
1269 v8::HandleScope scope;
1270 LocalContext env;
1271
1272 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1273 v8::HeapProfiler::DeleteAllSnapshots();
1274 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1275 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
1276 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1277 v8::HeapProfiler::DeleteAllSnapshots();
1278 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1279 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
1280 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("2")));
1281 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
1282 v8::HeapProfiler::DeleteAllSnapshots();
1283 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1284}
1285
1286
1287TEST(DeleteHeapSnapshot) {
1288 v8::HandleScope scope;
1289 LocalContext env;
1290
1291 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1292 const v8::HeapSnapshot* s1 =
1293 v8::HeapProfiler::TakeSnapshot(v8::String::New("1"));
1294 CHECK_NE(NULL, s1);
1295 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1296 unsigned uid1 = s1->GetUid();
1297 CHECK_EQ(s1, v8::HeapProfiler::FindSnapshot(uid1));
1298 const_cast<v8::HeapSnapshot*>(s1)->Delete();
1299 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1300 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid1));
1301
1302 const v8::HeapSnapshot* s2 =
1303 v8::HeapProfiler::TakeSnapshot(v8::String::New("2"));
1304 CHECK_NE(NULL, s2);
1305 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1306 unsigned uid2 = s2->GetUid();
1307 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
1308 CHECK_EQ(s2, v8::HeapProfiler::FindSnapshot(uid2));
1309 const v8::HeapSnapshot* s3 =
1310 v8::HeapProfiler::TakeSnapshot(v8::String::New("3"));
1311 CHECK_NE(NULL, s3);
1312 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
1313 unsigned uid3 = s3->GetUid();
1314 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
1315 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
1316 const_cast<v8::HeapSnapshot*>(s2)->Delete();
1317 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1318 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2));
1319 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
1320 const_cast<v8::HeapSnapshot*>(s3)->Delete();
1321 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1322 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3));
1323}
1324
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001325
1326TEST(DocumentURL) {
1327 v8::HandleScope scope;
1328 LocalContext env;
1329
1330 CompileRun("document = { URL:\"abcdefgh\" };");
1331
1332 const v8::HeapSnapshot* snapshot =
1333 v8::HeapProfiler::TakeSnapshot(v8::String::New("document"));
1334 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1335 CHECK_NE(NULL, global);
1336 CHECK_EQ("Object / abcdefgh",
1337 const_cast<i::HeapEntry*>(
1338 reinterpret_cast<const i::HeapEntry*>(global))->name());
1339}
1340
1341
1342TEST(DocumentWithException) {
1343 v8::HandleScope scope;
1344 LocalContext env;
1345
1346 CompileRun(
1347 "this.__defineGetter__(\"document\", function() { throw new Error(); })");
1348 const v8::HeapSnapshot* snapshot =
1349 v8::HeapProfiler::TakeSnapshot(v8::String::New("document"));
1350 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1351 CHECK_NE(NULL, global);
1352 CHECK_EQ("Object",
1353 const_cast<i::HeapEntry*>(
1354 reinterpret_cast<const i::HeapEntry*>(global))->name());
1355}
1356
1357
1358TEST(DocumentURLWithException) {
1359 v8::HandleScope scope;
1360 LocalContext env;
1361
1362 CompileRun(
1363 "function URLWithException() {}\n"
1364 "URLWithException.prototype = { get URL() { throw new Error(); } };\n"
1365 "document = { URL: new URLWithException() };");
1366 const v8::HeapSnapshot* snapshot =
1367 v8::HeapProfiler::TakeSnapshot(v8::String::New("document"));
1368 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1369 CHECK_NE(NULL, global);
1370 CHECK_EQ("Object",
1371 const_cast<i::HeapEntry*>(
1372 reinterpret_cast<const i::HeapEntry*>(global))->name());
1373}
1374
lrn@chromium.orgac2828d2011-06-23 06:29:21 +00001375
1376TEST(NodesIteration) {
1377 v8::HandleScope scope;
1378 LocalContext env;
1379 const v8::HeapSnapshot* snapshot =
1380 v8::HeapProfiler::TakeSnapshot(v8::String::New("iteration"));
1381 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1382 CHECK_NE(NULL, global);
1383 // Verify that we can find this object by iteration.
1384 const int nodes_count = snapshot->GetNodesCount();
1385 int count = 0;
1386 for (int i = 0; i < nodes_count; ++i) {
1387 if (snapshot->GetNode(i) == global)
1388 ++count;
1389 }
1390 CHECK_EQ(1, count);
1391}
1392
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001393#endif // ENABLE_LOGGING_AND_PROFILING