blob: bd08d4cec65b7e7d5fceb3b5cfd09c40a06414e7 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2//
3// Tests for heap profiler
4
5#ifdef ENABLE_LOGGING_AND_PROFILING
6
7#include "v8.h"
8#include "heap-profiler.h"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01009#include "snapshot.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000010#include "string-stream.h"
11#include "cctest.h"
Steve Block6ded16b2010-05-10 14:33:55 +010012#include "zone-inl.h"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010013#include "../include/v8-profiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000014
15namespace i = v8::internal;
16using i::ClustersCoarser;
17using i::JSObjectsCluster;
18using i::JSObjectsRetainerTree;
19using i::JSObjectsClusterTree;
20using i::RetainerHeapProfile;
21
22
Steve Blocka7e24c12009-10-30 11:49:00 +000023namespace {
24
25class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
26 public:
27 ConstructorHeapProfileTestHelper()
28 : i::ConstructorHeapProfile(),
Steve Block44f0eee2011-05-26 01:26:41 +010029 f_name_(FACTORY->NewStringFromAscii(i::CStrVector("F"))),
Steve Blocka7e24c12009-10-30 11:49:00 +000030 f_count_(0) {
31 }
32
33 void Call(const JSObjectsCluster& cluster,
34 const i::NumberAndSizeInfo& number_and_size) {
35 if (f_name_->Equals(cluster.constructor())) {
36 CHECK_EQ(f_count_, 0);
37 f_count_ = number_and_size.number();
38 CHECK_GT(f_count_, 0);
39 }
40 }
41
42 int f_count() { return f_count_; }
43
44 private:
45 i::Handle<i::String> f_name_;
46 int f_count_;
47};
48
49} // namespace
50
51
52TEST(ConstructorProfile) {
53 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010054 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +000055
Ben Murdochf87a2032010-10-22 12:50:53 +010056 CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +000057 "function F() {} // A constructor\n"
58 "var f1 = new F();\n"
59 "var f2 = new F();\n");
60
61 ConstructorHeapProfileTestHelper cons_profile;
62 i::AssertNoAllocation no_alloc;
63 i::HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +000064 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
Steve Blocka7e24c12009-10-30 11:49:00 +000065 cons_profile.CollectStats(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +000066 CHECK_EQ(0, cons_profile.f_count());
67 cons_profile.PrintStats();
68 CHECK_EQ(2, cons_profile.f_count());
69}
70
71
72static JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree,
73 i::String* constructor,
74 int instance,
75 JSObjectsCluster* ref1 = NULL,
76 JSObjectsCluster* ref2 = NULL,
77 JSObjectsCluster* ref3 = NULL) {
78 JSObjectsCluster o(constructor, reinterpret_cast<i::Object*>(instance));
79 JSObjectsClusterTree* o_tree = new JSObjectsClusterTree();
80 JSObjectsClusterTree::Locator o_loc;
81 if (ref1 != NULL) o_tree->Insert(*ref1, &o_loc);
82 if (ref2 != NULL) o_tree->Insert(*ref2, &o_loc);
83 if (ref3 != NULL) o_tree->Insert(*ref3, &o_loc);
84 JSObjectsRetainerTree::Locator loc;
85 tree->Insert(o, &loc);
86 loc.set_value(o_tree);
87 return o;
88}
89
90
91static void AddSelfReferenceToTree(JSObjectsRetainerTree* tree,
92 JSObjectsCluster* self_ref) {
93 JSObjectsRetainerTree::Locator loc;
94 CHECK(tree->Find(*self_ref, &loc));
95 JSObjectsClusterTree::Locator o_loc;
96 CHECK_NE(NULL, loc.value());
97 loc.value()->Insert(*self_ref, &o_loc);
98}
99
100
101static inline void CheckEqualsHelper(const char* file, int line,
102 const char* expected_source,
103 const JSObjectsCluster& expected,
104 const char* value_source,
105 const JSObjectsCluster& value) {
106 if (JSObjectsCluster::Compare(expected, value) != 0) {
107 i::HeapStringAllocator allocator;
108 i::StringStream stream(&allocator);
109 stream.Add("# Expected: ");
110 expected.DebugPrint(&stream);
111 stream.Add("\n# Found: ");
112 value.DebugPrint(&stream);
113 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n%s",
114 expected_source, value_source,
115 *stream.ToCString());
116 }
117}
118
119
120static inline void CheckNonEqualsHelper(const char* file, int line,
121 const char* expected_source,
122 const JSObjectsCluster& expected,
123 const char* value_source,
124 const JSObjectsCluster& value) {
125 if (JSObjectsCluster::Compare(expected, value) == 0) {
126 i::HeapStringAllocator allocator;
127 i::StringStream stream(&allocator);
128 stream.Add("# !Expected: ");
129 expected.DebugPrint(&stream);
130 stream.Add("\n# Found: ");
131 value.DebugPrint(&stream);
132 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n%s",
133 expected_source, value_source,
134 *stream.ToCString());
135 }
136}
137
138
139TEST(ClustersCoarserSimple) {
140 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100141 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000142
143 i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
144
145 JSObjectsRetainerTree tree;
Steve Block44f0eee2011-05-26 01:26:41 +0100146 JSObjectsCluster function(HEAP->function_class_symbol());
147 JSObjectsCluster a(*FACTORY->NewStringFromAscii(i::CStrVector("A")));
148 JSObjectsCluster b(*FACTORY->NewStringFromAscii(i::CStrVector("B")));
Steve Blocka7e24c12009-10-30 11:49:00 +0000149
150 // o1 <- Function
151 JSObjectsCluster o1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100152 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000153 // o2 <- Function
154 JSObjectsCluster o2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100155 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 // o3 <- A, B
157 JSObjectsCluster o3 =
Steve Block44f0eee2011-05-26 01:26:41 +0100158 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &a, &b);
Steve Blocka7e24c12009-10-30 11:49:00 +0000159 // o4 <- B, A
160 JSObjectsCluster o4 =
Steve Block44f0eee2011-05-26 01:26:41 +0100161 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x400, &b, &a);
Steve Blocka7e24c12009-10-30 11:49:00 +0000162 // o5 <- A, B, Function
163 JSObjectsCluster o5 =
Steve Block44f0eee2011-05-26 01:26:41 +0100164 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x500,
Steve Blocka7e24c12009-10-30 11:49:00 +0000165 &a, &b, &function);
166
167 ClustersCoarser coarser;
168 coarser.Process(&tree);
169
170 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
171 CHECK_EQ(coarser.GetCoarseEquivalent(o3), coarser.GetCoarseEquivalent(o4));
172 CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o3));
173 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o5));
174}
175
176
177TEST(ClustersCoarserMultipleConstructors) {
178 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100179 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000180
181 i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
182
183 JSObjectsRetainerTree tree;
Steve Block44f0eee2011-05-26 01:26:41 +0100184 JSObjectsCluster function(HEAP->function_class_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +0000185
186 // o1 <- Function
187 JSObjectsCluster o1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100188 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000189 // a1 <- Function
190 JSObjectsCluster a1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100191 AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x1000, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 // o2 <- Function
193 JSObjectsCluster o2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100194 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 // a2 <- Function
196 JSObjectsCluster a2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100197 AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x2000, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000198
199 ClustersCoarser coarser;
200 coarser.Process(&tree);
201
202 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
203 CHECK_EQ(coarser.GetCoarseEquivalent(a1), coarser.GetCoarseEquivalent(a2));
204}
205
206
207TEST(ClustersCoarserPathsTraversal) {
208 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100209 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000210
211 i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
212
213 JSObjectsRetainerTree tree;
214
215 // On the following graph:
216 //
217 // p
218 // <- o21 <- o11 <-
219 // q o
220 // <- o22 <- o12 <-
221 // r
222 //
223 // we expect that coarser will deduce equivalences: p ~ q ~ r,
224 // o21 ~ o22, and o11 ~ o12.
225
226 JSObjectsCluster o =
Steve Block44f0eee2011-05-26 01:26:41 +0100227 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
Steve Blocka7e24c12009-10-30 11:49:00 +0000228 JSObjectsCluster o11 =
Steve Block44f0eee2011-05-26 01:26:41 +0100229 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 JSObjectsCluster o12 =
Steve Block44f0eee2011-05-26 01:26:41 +0100231 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 JSObjectsCluster o21 =
Steve Block44f0eee2011-05-26 01:26:41 +0100233 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x210, &o11);
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 JSObjectsCluster o22 =
Steve Block44f0eee2011-05-26 01:26:41 +0100235 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x220, &o12);
Steve Blocka7e24c12009-10-30 11:49:00 +0000236 JSObjectsCluster p =
Steve Block44f0eee2011-05-26 01:26:41 +0100237 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o21);
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 JSObjectsCluster q =
Steve Block44f0eee2011-05-26 01:26:41 +0100239 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o21, &o22);
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 JSObjectsCluster r =
Steve Block44f0eee2011-05-26 01:26:41 +0100241 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o22);
Steve Blocka7e24c12009-10-30 11:49:00 +0000242
243 ClustersCoarser coarser;
244 coarser.Process(&tree);
245
246 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
247 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
248 CHECK_EQ(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o12));
249 CHECK_EQ(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(o22));
250 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(o21));
251 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
252 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
253 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
254 CHECK_NE(coarser.GetCoarseEquivalent(o11), coarser.GetCoarseEquivalent(p));
255 CHECK_NE(coarser.GetCoarseEquivalent(o21), coarser.GetCoarseEquivalent(p));
256}
257
258
259TEST(ClustersCoarserSelf) {
260 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100261 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000262
263 i::ZoneScope zn_scope(i::DELETE_ON_EXIT);
264
265 JSObjectsRetainerTree tree;
266
267 // On the following graph:
268 //
269 // p (self-referencing)
270 // <- o1 <-
271 // q (self-referencing) o
272 // <- o2 <-
273 // r (self-referencing)
274 //
275 // we expect that coarser will deduce equivalences: p ~ q ~ r, o1 ~ o2;
276
277 JSObjectsCluster o =
Steve Block44f0eee2011-05-26 01:26:41 +0100278 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
Steve Blocka7e24c12009-10-30 11:49:00 +0000279 JSObjectsCluster o1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100280 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000281 JSObjectsCluster o2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100282 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 JSObjectsCluster p =
Steve Block44f0eee2011-05-26 01:26:41 +0100284 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 AddSelfReferenceToTree(&tree, &p);
286 JSObjectsCluster q =
Steve Block44f0eee2011-05-26 01:26:41 +0100287 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o1, &o2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000288 AddSelfReferenceToTree(&tree, &q);
289 JSObjectsCluster r =
Steve Block44f0eee2011-05-26 01:26:41 +0100290 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 AddSelfReferenceToTree(&tree, &r);
292
293 ClustersCoarser coarser;
294 coarser.Process(&tree);
295
296 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
297 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o1));
298 CHECK_EQ(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(o2));
299 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
300 CHECK_EQ(coarser.GetCoarseEquivalent(p), coarser.GetCoarseEquivalent(q));
301 CHECK_EQ(coarser.GetCoarseEquivalent(q), coarser.GetCoarseEquivalent(r));
302 CHECK_NE(coarser.GetCoarseEquivalent(o1), coarser.GetCoarseEquivalent(p));
303}
304
305
306namespace {
307
308class RetainerProfilePrinter : public RetainerHeapProfile::Printer {
309 public:
310 RetainerProfilePrinter() : stream_(&allocator_), lines_(100) {}
311
312 void PrintRetainers(const JSObjectsCluster& cluster,
313 const i::StringStream& retainers) {
314 cluster.Print(&stream_);
315 stream_.Add("%s", *(retainers.ToCString()));
316 stream_.Put('\0');
317 }
318
319 const char* GetRetainers(const char* constructor) {
320 FillLines();
321 const size_t cons_len = strlen(constructor);
322 for (int i = 0; i < lines_.length(); ++i) {
323 if (strncmp(constructor, lines_[i], cons_len) == 0 &&
324 lines_[i][cons_len] == ',') {
325 return lines_[i] + cons_len + 1;
326 }
327 }
328 return NULL;
329 }
330
331 private:
332 void FillLines() {
333 if (lines_.length() > 0) return;
334 stream_.Put('\0');
335 stream_str_ = stream_.ToCString();
336 const char* pos = *stream_str_;
337 while (pos != NULL && *pos != '\0') {
338 lines_.Add(pos);
339 pos = strchr(pos, '\0');
340 if (pos != NULL) ++pos;
341 }
342 }
343
344 i::HeapStringAllocator allocator_;
345 i::StringStream stream_;
346 i::SmartPointer<const char> stream_str_;
347 i::List<const char*> lines_;
348};
349
350} // namespace
351
352
353TEST(RetainerProfile) {
354 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100355 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000356
Ben Murdochf87a2032010-10-22 12:50:53 +0100357 CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 "function A() {}\n"
359 "function B(x) { this.x = x; }\n"
360 "function C(x) { this.x1 = x; this.x2 = x; }\n"
361 "var a = new A();\n"
362 "var b1 = new B(a), b2 = new B(a);\n"
363 "var c = new C(a);");
364
365 RetainerHeapProfile ret_profile;
366 i::AssertNoAllocation no_alloc;
367 i::HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +0000368 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
Steve Blocka7e24c12009-10-30 11:49:00 +0000369 ret_profile.CollectStats(obj);
Steve Block791712a2010-08-27 10:21:07 +0100370 ret_profile.CoarseAndAggregate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000371 RetainerProfilePrinter printer;
372 ret_profile.DebugPrintStats(&printer);
373 const char* retainers_of_a = printer.GetRetainers("A");
374 // The order of retainers is unspecified, so we check string length, and
375 // verify each retainer separately.
Steve Blockd0582a62009-12-15 09:54:21 +0000376 CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"),
377 i::StrLength(retainers_of_a));
Steve Blocka7e24c12009-10-30 11:49:00 +0000378 CHECK(strstr(retainers_of_a, "(global property);1") != NULL);
379 CHECK(strstr(retainers_of_a, "B;2") != NULL);
380 CHECK(strstr(retainers_of_a, "C;2") != NULL);
381 CHECK_EQ("(global property);2", printer.GetRetainers("B"));
382 CHECK_EQ("(global property);1", printer.GetRetainers("C"));
383}
384
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100385
386namespace {
387
388class NamedEntriesDetector {
389 public:
390 NamedEntriesDetector()
Russell Brenner90bac252010-11-18 13:33:46 -0800391 : has_A2(false), has_B2(false), has_C2(false) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100392 }
393
Iain Merrick75681382010-08-19 15:07:18 +0100394 void Apply(i::HeapEntry** entry_ptr) {
Iain Merrick75681382010-08-19 15:07:18 +0100395 if (IsReachableNodeWithName(*entry_ptr, "A2")) has_A2 = true;
396 if (IsReachableNodeWithName(*entry_ptr, "B2")) has_B2 = true;
397 if (IsReachableNodeWithName(*entry_ptr, "C2")) has_C2 = true;
398 }
399
400 static bool IsReachableNodeWithName(i::HeapEntry* entry, const char* name) {
401 return strcmp(name, entry->name()) == 0 && entry->painted_reachable();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100402 }
403
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100404 bool has_A2;
405 bool has_B2;
406 bool has_C2;
407};
408
409} // namespace
410
411
412static const v8::HeapGraphNode* GetGlobalObject(
413 const v8::HeapSnapshot* snapshot) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800414 CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
415 const v8::HeapGraphNode* global_obj =
416 snapshot->GetRoot()->GetChild(0)->GetToNode();
417 CHECK_EQ("Object", const_cast<i::HeapEntry*>(
418 reinterpret_cast<const i::HeapEntry*>(global_obj))->name());
419 return global_obj;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100420}
421
422
423static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
424 v8::HeapGraphEdge::Type type,
425 const char* name) {
426 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
427 const v8::HeapGraphEdge* prop = node->GetChild(i);
428 v8::String::AsciiValue prop_name(prop->GetName());
429 if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
430 return prop->GetToNode();
431 }
432 return NULL;
433}
434
435
436static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
437 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
438 const v8::HeapGraphEdge* prop = node->GetChild(i);
439 const v8::HeapGraphNode* node = prop->GetToNode();
Iain Merrick75681382010-08-19 15:07:18 +0100440 if (node->GetType() == v8::HeapGraphNode::kString) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100441 v8::String::AsciiValue node_name(node->GetName());
442 if (strcmp(contents, *node_name) == 0) return true;
443 }
444 }
445 return false;
446}
447
448
449TEST(HeapSnapshot) {
450 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100451 LocalContext env2;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100452
Ben Murdochf87a2032010-10-22 12:50:53 +0100453 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100454 "function A2() {}\n"
455 "function B2(x) { return function() { return typeof x; }; }\n"
456 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
457 "var a2 = new A2();\n"
458 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
459 "var c2 = new C2(a2);");
460 const v8::HeapSnapshot* snapshot_env2 =
461 v8::HeapProfiler::TakeSnapshot(v8::String::New("env2"));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100462 i::HeapSnapshot* i_snapshot_env2 =
463 const_cast<i::HeapSnapshot*>(
464 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
Iain Merrick75681382010-08-19 15:07:18 +0100465 const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
466 // Paint all nodes reachable from global object.
467 i_snapshot_env2->ClearPaint();
468 const_cast<i::HeapEntry*>(
469 reinterpret_cast<const i::HeapEntry*>(global_env2))->PaintAllReachable();
470
Russell Brenner90bac252010-11-18 13:33:46 -0800471 // Verify, that JS global object of env2 has '..2' properties.
Iain Merrick75681382010-08-19 15:07:18 +0100472 const v8::HeapGraphNode* a2_node =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800473 GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
Iain Merrick75681382010-08-19 15:07:18 +0100474 CHECK_NE(NULL, a2_node);
475 CHECK_NE(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800476 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
Iain Merrick75681382010-08-19 15:07:18 +0100477 CHECK_NE(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800478 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
479 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
Iain Merrick75681382010-08-19 15:07:18 +0100480
Iain Merrick75681382010-08-19 15:07:18 +0100481 NamedEntriesDetector det;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100482 i_snapshot_env2->IterateEntries(&det);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100483 CHECK(det.has_A2);
484 CHECK(det.has_B2);
485 CHECK(det.has_C2);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100486}
487
488
Iain Merrick75681382010-08-19 15:07:18 +0100489TEST(HeapSnapshotObjectSizes) {
490 v8::HandleScope scope;
491 LocalContext env;
492
493 // -a-> X1 --a
494 // x -b-> X2 <-|
Ben Murdochf87a2032010-10-22 12:50:53 +0100495 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100496 "function X(a, b) { this.a = a; this.b = b; }\n"
497 "x = new X(new X(), new X());\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800498 "(function() { x.a.a = x.b; })();");
Iain Merrick75681382010-08-19 15:07:18 +0100499 const v8::HeapSnapshot* snapshot =
500 v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes"));
501 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
502 const v8::HeapGraphNode* x =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800503 GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
Iain Merrick75681382010-08-19 15:07:18 +0100504 CHECK_NE(NULL, x);
Iain Merrick75681382010-08-19 15:07:18 +0100505 const v8::HeapGraphNode* x1 =
506 GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
507 CHECK_NE(NULL, x1);
508 const v8::HeapGraphNode* x2 =
509 GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
510 CHECK_NE(NULL, x2);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800511
512 // Test approximate sizes.
513 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(false));
514 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(false));
515 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(false));
516 // Test exact sizes.
517 CHECK_EQ(x->GetSelfSize() * 3, x->GetRetainedSize(true));
518 CHECK_EQ(x1->GetSelfSize(), x1->GetRetainedSize(true));
519 CHECK_EQ(x2->GetSelfSize(), x2->GetRetainedSize(true));
Iain Merrick75681382010-08-19 15:07:18 +0100520}
521
522
523TEST(HeapSnapshotEntryChildren) {
524 v8::HandleScope scope;
525 LocalContext env;
526
Ben Murdochf87a2032010-10-22 12:50:53 +0100527 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100528 "function A() { }\n"
529 "a = new A;");
530 const v8::HeapSnapshot* snapshot =
531 v8::HeapProfiler::TakeSnapshot(v8::String::New("children"));
532 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
533 for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
534 const v8::HeapGraphEdge* prop = global->GetChild(i);
535 CHECK_EQ(global, prop->GetFromNode());
536 }
537 const v8::HeapGraphNode* a =
538 GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
539 CHECK_NE(NULL, a);
540 for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
541 const v8::HeapGraphEdge* prop = a->GetChild(i);
542 CHECK_EQ(a, prop->GetFromNode());
543 }
544}
545
546
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100547TEST(HeapSnapshotCodeObjects) {
548 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100549 LocalContext env;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100550
Ben Murdochf87a2032010-10-22 12:50:53 +0100551 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100552 "function lazy(x) { return x - 1; }\n"
553 "function compiled(x) { return x + 1; }\n"
Steve Block791712a2010-08-27 10:21:07 +0100554 "var anonymous = (function() { return function() { return 0; } })();\n"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100555 "compiled(1)");
556 const v8::HeapSnapshot* snapshot =
557 v8::HeapProfiler::TakeSnapshot(v8::String::New("code"));
558
559 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
560 const v8::HeapGraphNode* compiled =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800561 GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100562 CHECK_NE(NULL, compiled);
Iain Merrick75681382010-08-19 15:07:18 +0100563 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100564 const v8::HeapGraphNode* lazy =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800565 GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100566 CHECK_NE(NULL, lazy);
Iain Merrick75681382010-08-19 15:07:18 +0100567 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
Steve Block791712a2010-08-27 10:21:07 +0100568 const v8::HeapGraphNode* anonymous =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800569 GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
Steve Block791712a2010-08-27 10:21:07 +0100570 CHECK_NE(NULL, anonymous);
571 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
572 v8::String::AsciiValue anonymous_name(anonymous->GetName());
Ben Murdochf87a2032010-10-22 12:50:53 +0100573 CHECK_EQ("", *anonymous_name);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100574
575 // Find references to code.
576 const v8::HeapGraphNode* compiled_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100577 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100578 CHECK_NE(NULL, compiled_code);
579 const v8::HeapGraphNode* lazy_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100580 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100581 CHECK_NE(NULL, lazy_code);
582
583 // Verify that non-compiled code doesn't contain references to "x"
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100584 // literal, while compiled code does. The scope info is stored in FixedArray
585 // objects attached to the SharedFunctionInfo.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100586 bool compiled_references_x = false, lazy_references_x = false;
587 for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
588 const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
589 const v8::HeapGraphNode* node = prop->GetToNode();
Iain Merrick75681382010-08-19 15:07:18 +0100590 if (node->GetType() == v8::HeapGraphNode::kArray) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100591 if (HasString(node, "x")) {
592 compiled_references_x = true;
593 break;
594 }
595 }
596 }
597 for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
598 const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
599 const v8::HeapGraphNode* node = prop->GetToNode();
Iain Merrick75681382010-08-19 15:07:18 +0100600 if (node->GetType() == v8::HeapGraphNode::kArray) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100601 if (HasString(node, "x")) {
602 lazy_references_x = true;
603 break;
604 }
605 }
606 }
607 CHECK(compiled_references_x);
608 CHECK(!lazy_references_x);
609}
610
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100611
Ben Murdochf87a2032010-10-22 12:50:53 +0100612TEST(HeapSnapshotHeapNumbers) {
613 v8::HandleScope scope;
614 LocalContext env;
615 CompileRun(
616 "a = 1; // a is Smi\n"
617 "b = 2.5; // b is HeapNumber");
618 const v8::HeapSnapshot* snapshot =
619 v8::HeapProfiler::TakeSnapshot(v8::String::New("numbers"));
620 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800621 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100622 const v8::HeapGraphNode* b =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800623 GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
Ben Murdochf87a2032010-10-22 12:50:53 +0100624 CHECK_NE(NULL, b);
625 CHECK_EQ(v8::HeapGraphNode::kHeapNumber, b->GetType());
626}
627
628
629TEST(HeapSnapshotInternalReferences) {
630 v8::HandleScope scope;
631 v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
632 global_template->SetInternalFieldCount(2);
633 LocalContext env(NULL, global_template);
634 v8::Handle<v8::Object> global_proxy = env->Global();
635 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
636 CHECK_EQ(2, global->InternalFieldCount());
637 v8::Local<v8::Object> obj = v8::Object::New();
638 global->SetInternalField(0, v8_num(17));
639 global->SetInternalField(1, obj);
640 const v8::HeapSnapshot* snapshot =
641 v8::HeapProfiler::TakeSnapshot(v8::String::New("internals"));
642 const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
643 // The first reference will not present, because it's a Smi.
644 CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
645 // The second reference is to an object.
646 CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
647}
648
649
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100650// Trying to introduce a check helper for uint64_t causes many
651// overloading ambiguities, so it seems easier just to cast
652// them to a signed type.
653#define CHECK_EQ_UINT64_T(a, b) \
654 CHECK_EQ(static_cast<int64_t>(a), static_cast<int64_t>(b))
Iain Merrick75681382010-08-19 15:07:18 +0100655#define CHECK_NE_UINT64_T(a, b) \
656 CHECK((a) != (b)) // NOLINT
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100657
658TEST(HeapEntryIdsAndGC) {
659 v8::HandleScope scope;
660 LocalContext env;
661
Ben Murdochf87a2032010-10-22 12:50:53 +0100662 CompileRun(
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100663 "function A() {}\n"
664 "function B(x) { this.x = x; }\n"
665 "var a = new A();\n"
666 "var b = new B(a);");
667 const v8::HeapSnapshot* snapshot1 =
668 v8::HeapProfiler::TakeSnapshot(v8::String::New("s1"));
669
Steve Block44f0eee2011-05-26 01:26:41 +0100670 HEAP->CollectAllGarbage(true); // Enforce compaction.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100671
672 const v8::HeapSnapshot* snapshot2 =
673 v8::HeapProfiler::TakeSnapshot(v8::String::New("s2"));
674
675 const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
676 const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
677 CHECK_NE_UINT64_T(0, global1->GetId());
678 CHECK_EQ_UINT64_T(global1->GetId(), global2->GetId());
679 const v8::HeapGraphNode* A1 =
Iain Merrick75681382010-08-19 15:07:18 +0100680 GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
681 CHECK_NE(NULL, A1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100682 const v8::HeapGraphNode* A2 =
Iain Merrick75681382010-08-19 15:07:18 +0100683 GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
684 CHECK_NE(NULL, A2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100685 CHECK_NE_UINT64_T(0, A1->GetId());
686 CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
687 const v8::HeapGraphNode* B1 =
Iain Merrick75681382010-08-19 15:07:18 +0100688 GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
689 CHECK_NE(NULL, B1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100690 const v8::HeapGraphNode* B2 =
Iain Merrick75681382010-08-19 15:07:18 +0100691 GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
692 CHECK_NE(NULL, B2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100693 CHECK_NE_UINT64_T(0, B1->GetId());
694 CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
695 const v8::HeapGraphNode* a1 =
Iain Merrick75681382010-08-19 15:07:18 +0100696 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
697 CHECK_NE(NULL, a1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100698 const v8::HeapGraphNode* a2 =
Iain Merrick75681382010-08-19 15:07:18 +0100699 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
700 CHECK_NE(NULL, a2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100701 CHECK_NE_UINT64_T(0, a1->GetId());
702 CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
703 const v8::HeapGraphNode* b1 =
Iain Merrick75681382010-08-19 15:07:18 +0100704 GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
705 CHECK_NE(NULL, b1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100706 const v8::HeapGraphNode* b2 =
Iain Merrick75681382010-08-19 15:07:18 +0100707 GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
708 CHECK_NE(NULL, b2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100709 CHECK_NE_UINT64_T(0, b1->GetId());
710 CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
711}
712
713
Ben Murdochf87a2032010-10-22 12:50:53 +0100714TEST(HeapSnapshotRootPreservedAfterSorting) {
715 v8::HandleScope scope;
716 LocalContext env;
717 const v8::HeapSnapshot* snapshot =
718 v8::HeapProfiler::TakeSnapshot(v8::String::New("s"));
719 const v8::HeapGraphNode* root1 = snapshot->GetRoot();
720 const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
721 snapshot))->GetSortedEntriesList();
722 const v8::HeapGraphNode* root2 = snapshot->GetRoot();
723 CHECK_EQ(root1, root2);
724}
725
726
Steve Block791712a2010-08-27 10:21:07 +0100727static const v8::HeapGraphNode* GetChild(
728 const v8::HeapGraphNode* node,
729 v8::HeapGraphNode::Type type,
730 const char* name,
731 const v8::HeapGraphNode* after = NULL) {
732 bool ignore_child = after == NULL ? false : true;
733 for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
734 const v8::HeapGraphEdge* prop = node->GetChild(i);
735 const v8::HeapGraphNode* child = prop->GetToNode();
736 v8::String::AsciiValue child_name(child->GetName());
737 if (!ignore_child
738 && child->GetType() == type
739 && strcmp(name, *child_name) == 0)
740 return child;
741 if (after != NULL && child == after) ignore_child = false;
742 }
743 return NULL;
744}
745
746static bool IsNodeRetainedAs(const v8::HeapGraphNode* node,
747 int element) {
748 for (int i = 0, count = node->GetRetainersCount(); i < count; ++i) {
749 const v8::HeapGraphEdge* prop = node->GetRetainer(i);
750 if (prop->GetType() == v8::HeapGraphEdge::kElement
751 && element == prop->GetName()->Int32Value())
752 return true;
753 }
754 return false;
755}
756
757TEST(AggregatedHeapSnapshot) {
758 v8::HandleScope scope;
759 LocalContext env;
760
Ben Murdochf87a2032010-10-22 12:50:53 +0100761 CompileRun(
Steve Block791712a2010-08-27 10:21:07 +0100762 "function A() {}\n"
763 "function B(x) { this.x = x; }\n"
764 "var a = new A();\n"
765 "var b = new B(a);");
766 const v8::HeapSnapshot* snapshot =
767 v8::HeapProfiler::TakeSnapshot(
768 v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
769 const v8::HeapGraphNode* strings = GetChild(snapshot->GetRoot(),
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800770 v8::HeapGraphNode::kHidden,
Steve Block791712a2010-08-27 10:21:07 +0100771 "STRING_TYPE");
772 CHECK_NE(NULL, strings);
773 CHECK_NE(0, strings->GetSelfSize());
774 CHECK_NE(0, strings->GetInstancesCount());
775 const v8::HeapGraphNode* maps = GetChild(snapshot->GetRoot(),
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800776 v8::HeapGraphNode::kHidden,
Steve Block791712a2010-08-27 10:21:07 +0100777 "MAP_TYPE");
778 CHECK_NE(NULL, maps);
779 CHECK_NE(0, maps->GetSelfSize());
780 CHECK_NE(0, maps->GetInstancesCount());
781
782 const v8::HeapGraphNode* a = GetChild(snapshot->GetRoot(),
783 v8::HeapGraphNode::kObject,
784 "A");
785 CHECK_NE(NULL, a);
786 CHECK_NE(0, a->GetSelfSize());
787 CHECK_EQ(1, a->GetInstancesCount());
788
789 const v8::HeapGraphNode* b = GetChild(snapshot->GetRoot(),
790 v8::HeapGraphNode::kObject,
791 "B");
792 CHECK_NE(NULL, b);
793 CHECK_NE(0, b->GetSelfSize());
794 CHECK_EQ(1, b->GetInstancesCount());
795
796 const v8::HeapGraphNode* glob_prop = GetChild(snapshot->GetRoot(),
797 v8::HeapGraphNode::kObject,
798 "(global property)",
799 b);
800 CHECK_NE(NULL, glob_prop);
801 CHECK_EQ(0, glob_prop->GetSelfSize());
802 CHECK_EQ(0, glob_prop->GetInstancesCount());
803 CHECK_NE(0, glob_prop->GetChildrenCount());
804
805 const v8::HeapGraphNode* a_from_glob_prop = GetChild(
806 glob_prop,
807 v8::HeapGraphNode::kObject,
808 "A");
809 CHECK_NE(NULL, a_from_glob_prop);
810 CHECK_EQ(0, a_from_glob_prop->GetSelfSize());
811 CHECK_EQ(0, a_from_glob_prop->GetInstancesCount());
812 CHECK_EQ(0, a_from_glob_prop->GetChildrenCount()); // Retains nothing.
813 CHECK(IsNodeRetainedAs(a_from_glob_prop, 1)); // (global propery) has 1 ref.
814
815 const v8::HeapGraphNode* b_with_children = GetChild(
816 snapshot->GetRoot(),
817 v8::HeapGraphNode::kObject,
818 "B",
819 b);
820 CHECK_NE(NULL, b_with_children);
821 CHECK_EQ(0, b_with_children->GetSelfSize());
822 CHECK_EQ(0, b_with_children->GetInstancesCount());
823 CHECK_NE(0, b_with_children->GetChildrenCount());
824
825 const v8::HeapGraphNode* a_from_b = GetChild(
826 b_with_children,
827 v8::HeapGraphNode::kObject,
828 "A");
829 CHECK_NE(NULL, a_from_b);
830 CHECK_EQ(0, a_from_b->GetSelfSize());
831 CHECK_EQ(0, a_from_b->GetInstancesCount());
832 CHECK_EQ(0, a_from_b->GetChildrenCount()); // Retains nothing.
833 CHECK(IsNodeRetainedAs(a_from_b, 1)); // B has 1 ref to A.
834}
835
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800836
837TEST(HeapEntryDominator) {
838 // The graph looks like this:
839 //
840 // -> node1
841 // a |^
842 // -> node5 ba
843 // a v|
844 // node6 -> node2
845 // b a |^
846 // -> node4 ba
847 // b v|
848 // -> node3
849 //
850 // The dominator for all nodes is node6.
851
852 v8::HandleScope scope;
853 LocalContext env;
854
855 CompileRun(
856 "function X(a, b) { this.a = a; this.b = b; }\n"
857 "node6 = new X(new X(new X()), new X(new X(),new X()));\n"
858 "(function(){\n"
859 "node6.a.a.b = node6.b.a; // node1 -> node2\n"
860 "node6.b.a.a = node6.a.a; // node2 -> node1\n"
861 "node6.b.a.b = node6.b.b; // node2 -> node3\n"
862 "node6.b.b.a = node6.b.a; // node3 -> node2\n"
863 "})();");
864
865 const v8::HeapSnapshot* snapshot =
866 v8::HeapProfiler::TakeSnapshot(v8::String::New("dominators"));
867
868 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
869 CHECK_NE(NULL, global);
870 const v8::HeapGraphNode* node6 =
871 GetProperty(global, v8::HeapGraphEdge::kShortcut, "node6");
872 CHECK_NE(NULL, node6);
873 const v8::HeapGraphNode* node5 =
874 GetProperty(node6, v8::HeapGraphEdge::kProperty, "a");
875 CHECK_NE(NULL, node5);
876 const v8::HeapGraphNode* node4 =
877 GetProperty(node6, v8::HeapGraphEdge::kProperty, "b");
878 CHECK_NE(NULL, node4);
879 const v8::HeapGraphNode* node3 =
880 GetProperty(node4, v8::HeapGraphEdge::kProperty, "b");
881 CHECK_NE(NULL, node3);
882 const v8::HeapGraphNode* node2 =
883 GetProperty(node4, v8::HeapGraphEdge::kProperty, "a");
884 CHECK_NE(NULL, node2);
885 const v8::HeapGraphNode* node1 =
886 GetProperty(node5, v8::HeapGraphEdge::kProperty, "a");
887 CHECK_NE(NULL, node1);
888
889 CHECK_EQ(node6, node1->GetDominatorNode());
890 CHECK_EQ(node6, node2->GetDominatorNode());
891 CHECK_EQ(node6, node3->GetDominatorNode());
892 CHECK_EQ(node6, node4->GetDominatorNode());
893 CHECK_EQ(node6, node5->GetDominatorNode());
894}
895
896
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100897namespace {
898
899class TestJSONStream : public v8::OutputStream {
900 public:
901 TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
902 explicit TestJSONStream(int abort_countdown)
903 : eos_signaled_(0), abort_countdown_(abort_countdown) {}
904 virtual ~TestJSONStream() {}
905 virtual void EndOfStream() { ++eos_signaled_; }
906 virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
907 if (abort_countdown_ > 0) --abort_countdown_;
908 if (abort_countdown_ == 0) return kAbort;
909 CHECK_GT(chars_written, 0);
910 i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
911 memcpy(chunk.start(), buffer, chars_written);
912 return kContinue;
913 }
914 void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
915 int eos_signaled() { return eos_signaled_; }
916 int size() { return buffer_.size(); }
917 private:
918 i::Collector<char> buffer_;
919 int eos_signaled_;
920 int abort_countdown_;
921};
922
923class AsciiResource: public v8::String::ExternalAsciiStringResource {
924 public:
925 explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
926 length_ = string.length();
927 }
928 virtual const char* data() const { return data_; }
929 virtual size_t length() const { return length_; }
930 private:
931 const char* data_;
932 size_t length_;
933};
934
935} // namespace
936
937TEST(HeapSnapshotJSONSerialization) {
938 v8::HandleScope scope;
939 LocalContext env;
940
941#define STRING_LITERAL_FOR_TEST \
942 "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
Ben Murdochf87a2032010-10-22 12:50:53 +0100943 CompileRun(
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100944 "function A(s) { this.s = s; }\n"
945 "function B(x) { this.x = x; }\n"
946 "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
947 "var b = new B(a);");
948 const v8::HeapSnapshot* snapshot =
949 v8::HeapProfiler::TakeSnapshot(v8::String::New("json"));
950 TestJSONStream stream;
951 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
952 CHECK_GT(stream.size(), 0);
953 CHECK_EQ(1, stream.eos_signaled());
954 i::ScopedVector<char> json(stream.size());
955 stream.WriteTo(json);
956
957 // Verify that snapshot string is valid JSON.
958 AsciiResource json_res(json);
959 v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res);
960 env->Global()->Set(v8::String::New("json_snapshot"), json_string);
961 v8::Local<v8::Value> snapshot_parse_result = CompileRun(
962 "var parsed = JSON.parse(json_snapshot); true;");
963 CHECK(!snapshot_parse_result.IsEmpty());
964
965 // Verify that snapshot object has required fields.
966 v8::Local<v8::Object> parsed_snapshot =
967 env->Global()->Get(v8::String::New("parsed"))->ToObject();
968 CHECK(parsed_snapshot->Has(v8::String::New("snapshot")));
969 CHECK(parsed_snapshot->Has(v8::String::New("nodes")));
970 CHECK(parsed_snapshot->Has(v8::String::New("strings")));
971
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100972 // Get node and edge "member" offsets.
973 v8::Local<v8::Value> meta_analysis_result = CompileRun(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800974 "var parsed_meta = parsed.nodes[0];\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100975 "var children_count_offset ="
976 " parsed_meta.fields.indexOf('children_count');\n"
977 "var children_offset ="
978 " parsed_meta.fields.indexOf('children');\n"
979 "var children_meta ="
980 " parsed_meta.types[children_offset];\n"
981 "var child_fields_count = children_meta.fields.length;\n"
982 "var child_type_offset ="
983 " children_meta.fields.indexOf('type');\n"
984 "var child_name_offset ="
985 " children_meta.fields.indexOf('name_or_index');\n"
986 "var child_to_node_offset ="
987 " children_meta.fields.indexOf('to_node');\n"
988 "var property_type ="
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800989 " children_meta.types[child_type_offset].indexOf('property');\n"
990 "var shortcut_type ="
991 " children_meta.types[child_type_offset].indexOf('shortcut');");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100992 CHECK(!meta_analysis_result.IsEmpty());
993
994 // A helper function for processing encoded nodes.
995 CompileRun(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800996 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100997 " var nodes = parsed.nodes;\n"
998 " var strings = parsed.strings;\n"
999 " for (var i = 0,\n"
1000 " count = nodes[pos + children_count_offset] * child_fields_count;\n"
1001 " i < count; i += child_fields_count) {\n"
1002 " var child_pos = pos + children_offset + i;\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001003 " if (nodes[child_pos + child_type_offset] === prop_type\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001004 " && strings[nodes[child_pos + child_name_offset]] === prop_name)\n"
1005 " return nodes[child_pos + child_to_node_offset];\n"
1006 " }\n"
1007 " return null;\n"
1008 "}\n");
1009 // Get the string index using the path: <root> -> <global>.b.x.s
1010 v8::Local<v8::Value> string_obj_pos_val = CompileRun(
1011 "GetChildPosByProperty(\n"
1012 " GetChildPosByProperty(\n"
1013 " GetChildPosByProperty("
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001014 " parsed.nodes[1 + children_offset + child_to_node_offset],"
1015 " \"b\",shortcut_type),\n"
1016 " \"x\", property_type),"
1017 " \"s\", property_type)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001018 CHECK(!string_obj_pos_val.IsEmpty());
1019 int string_obj_pos =
1020 static_cast<int>(string_obj_pos_val->ToNumber()->Value());
1021 v8::Local<v8::Object> nodes_array =
1022 parsed_snapshot->Get(v8::String::New("nodes"))->ToObject();
1023 int string_index = static_cast<int>(
1024 nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
1025 CHECK_GT(string_index, 0);
1026 v8::Local<v8::Object> strings_array =
1027 parsed_snapshot->Get(v8::String::New("strings"))->ToObject();
1028 v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
1029 v8::Local<v8::String> ref_string =
1030 CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
1031#undef STRING_LITERAL_FOR_TEST
1032 CHECK_EQ(*v8::String::Utf8Value(ref_string),
1033 *v8::String::Utf8Value(string));
1034}
1035
1036
1037TEST(HeapSnapshotJSONSerializationAborting) {
1038 v8::HandleScope scope;
1039 LocalContext env;
1040 const v8::HeapSnapshot* snapshot =
1041 v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"));
1042 TestJSONStream stream(5);
1043 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
1044 CHECK_GT(stream.size(), 0);
1045 CHECK_EQ(0, stream.eos_signaled());
1046}
1047
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001048
1049// Must not crash in debug mode.
1050TEST(AggregatedHeapSnapshotJSONSerialization) {
1051 v8::HandleScope scope;
1052 LocalContext env;
1053
1054 const v8::HeapSnapshot* snapshot =
1055 v8::HeapProfiler::TakeSnapshot(
1056 v8::String::New("agg"), v8::HeapSnapshot::kAggregated);
1057 TestJSONStream stream;
1058 snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
1059 CHECK_GT(stream.size(), 0);
1060 CHECK_EQ(1, stream.eos_signaled());
1061}
1062
Ben Murdochb0fe1622011-05-05 13:52:32 +01001063
1064TEST(HeapSnapshotGetNodeById) {
1065 v8::HandleScope scope;
1066 LocalContext env;
1067
1068 const v8::HeapSnapshot* snapshot =
1069 v8::HeapProfiler::TakeSnapshot(v8::String::New("id"));
1070 const v8::HeapGraphNode* root = snapshot->GetRoot();
1071 CHECK_EQ(root, snapshot->GetNodeById(root->GetId()));
1072 for (int i = 0, count = root->GetChildrenCount(); i < count; ++i) {
1073 const v8::HeapGraphEdge* prop = root->GetChild(i);
1074 CHECK_EQ(
1075 prop->GetToNode(), snapshot->GetNodeById(prop->GetToNode()->GetId()));
1076 }
1077 // Check a big id, which should not exist yet.
1078 CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
1079}
1080
1081
1082namespace {
1083
1084class TestActivityControl : public v8::ActivityControl {
1085 public:
1086 explicit TestActivityControl(int abort_count)
1087 : done_(0), total_(0), abort_count_(abort_count) {}
1088 ControlOption ReportProgressValue(int done, int total) {
1089 done_ = done;
1090 total_ = total;
1091 return --abort_count_ != 0 ? kContinue : kAbort;
1092 }
1093 int done() { return done_; }
1094 int total() { return total_; }
1095
1096 private:
1097 int done_;
1098 int total_;
1099 int abort_count_;
1100};
1101}
1102
1103TEST(TakeHeapSnapshotAborting) {
1104 v8::HandleScope scope;
1105 LocalContext env;
1106
1107 const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
1108 TestActivityControl aborting_control(3);
1109 const v8::HeapSnapshot* no_snapshot =
1110 v8::HeapProfiler::TakeSnapshot(v8::String::New("abort"),
1111 v8::HeapSnapshot::kFull,
1112 &aborting_control);
1113 CHECK_EQ(NULL, no_snapshot);
1114 CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
1115 CHECK_GT(aborting_control.total(), aborting_control.done());
1116
1117 TestActivityControl control(-1); // Don't abort.
1118 const v8::HeapSnapshot* snapshot =
1119 v8::HeapProfiler::TakeSnapshot(v8::String::New("full"),
1120 v8::HeapSnapshot::kFull,
1121 &control);
1122 CHECK_NE(NULL, snapshot);
1123 CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
1124 CHECK_EQ(control.total(), control.done());
1125 CHECK_GT(control.total(), 0);
1126}
1127
Steve Block44f0eee2011-05-26 01:26:41 +01001128
1129namespace {
1130
1131class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
1132 public:
1133 TestRetainedObjectInfo(int hash,
1134 const char* label,
1135 intptr_t element_count = -1,
1136 intptr_t size = -1)
1137 : disposed_(false),
1138 hash_(hash),
1139 label_(label),
1140 element_count_(element_count),
1141 size_(size) {
1142 instances.Add(this);
1143 }
1144 virtual ~TestRetainedObjectInfo() {}
1145 virtual void Dispose() {
1146 CHECK(!disposed_);
1147 disposed_ = true;
1148 }
1149 virtual bool IsEquivalent(RetainedObjectInfo* other) {
1150 return GetHash() == other->GetHash();
1151 }
1152 virtual intptr_t GetHash() { return hash_; }
1153 virtual const char* GetLabel() { return label_; }
1154 virtual intptr_t GetElementCount() { return element_count_; }
1155 virtual intptr_t GetSizeInBytes() { return size_; }
1156 bool disposed() { return disposed_; }
1157
1158 static v8::RetainedObjectInfo* WrapperInfoCallback(
1159 uint16_t class_id, v8::Handle<v8::Value> wrapper) {
1160 if (class_id == 1) {
1161 if (wrapper->IsString()) {
1162 v8::String::AsciiValue ascii(wrapper);
1163 if (strcmp(*ascii, "AAA") == 0)
1164 return new TestRetainedObjectInfo(1, "aaa", 100);
1165 else if (strcmp(*ascii, "BBB") == 0)
1166 return new TestRetainedObjectInfo(1, "aaa", 100);
1167 }
1168 } else if (class_id == 2) {
1169 if (wrapper->IsString()) {
1170 v8::String::AsciiValue ascii(wrapper);
1171 if (strcmp(*ascii, "CCC") == 0)
1172 return new TestRetainedObjectInfo(2, "ccc");
1173 }
1174 }
1175 CHECK(false);
1176 return NULL;
1177 }
1178
1179 static i::List<TestRetainedObjectInfo*> instances;
1180
1181 private:
1182 bool disposed_;
1183 int category_;
1184 int hash_;
1185 const char* label_;
1186 intptr_t element_count_;
1187 intptr_t size_;
1188};
1189
1190
1191i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
1192}
1193
1194
1195static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
1196 v8::HeapGraphNode::Type type,
1197 const char* name) {
1198 for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
1199 const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
1200 if (node->GetType() == type && strcmp(name,
1201 const_cast<i::HeapEntry*>(
1202 reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
1203 return node;
1204 }
1205 }
1206 return NULL;
1207}
1208
1209
1210TEST(HeapSnapshotRetainedObjectInfo) {
1211 v8::HandleScope scope;
1212 LocalContext env;
1213
1214 v8::HeapProfiler::DefineWrapperClass(
1215 1, TestRetainedObjectInfo::WrapperInfoCallback);
1216 v8::HeapProfiler::DefineWrapperClass(
1217 2, TestRetainedObjectInfo::WrapperInfoCallback);
1218 v8::Persistent<v8::String> p_AAA =
1219 v8::Persistent<v8::String>::New(v8_str("AAA"));
1220 p_AAA.SetWrapperClassId(1);
1221 v8::Persistent<v8::String> p_BBB =
1222 v8::Persistent<v8::String>::New(v8_str("BBB"));
1223 p_BBB.SetWrapperClassId(1);
1224 v8::Persistent<v8::String> p_CCC =
1225 v8::Persistent<v8::String>::New(v8_str("CCC"));
1226 p_CCC.SetWrapperClassId(2);
1227 CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
1228 const v8::HeapSnapshot* snapshot =
1229 v8::HeapProfiler::TakeSnapshot(v8::String::New("retained"));
1230
1231 CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
1232 for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
1233 CHECK(TestRetainedObjectInfo::instances[i]->disposed());
1234 delete TestRetainedObjectInfo::instances[i];
1235 }
1236
1237 const v8::HeapGraphNode* natives = GetNode(
1238 snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(Native objects)");
1239 CHECK_NE(NULL, natives);
1240 CHECK_EQ(2, natives->GetChildrenCount());
1241 const v8::HeapGraphNode* aaa = GetNode(
1242 natives, v8::HeapGraphNode::kNative, "aaa / 100 entries");
1243 CHECK_NE(NULL, aaa);
1244 const v8::HeapGraphNode* ccc = GetNode(
1245 natives, v8::HeapGraphNode::kNative, "ccc");
1246 CHECK_NE(NULL, ccc);
1247
1248 CHECK_EQ(2, aaa->GetChildrenCount());
1249 const v8::HeapGraphNode* n_AAA = GetNode(
1250 aaa, v8::HeapGraphNode::kString, "AAA");
1251 CHECK_NE(NULL, n_AAA);
1252 const v8::HeapGraphNode* n_BBB = GetNode(
1253 aaa, v8::HeapGraphNode::kString, "BBB");
1254 CHECK_NE(NULL, n_BBB);
1255 CHECK_EQ(1, ccc->GetChildrenCount());
1256 const v8::HeapGraphNode* n_CCC = GetNode(
1257 ccc, v8::HeapGraphNode::kString, "CCC");
1258 CHECK_NE(NULL, n_CCC);
1259
Ben Murdoch8b112d22011-06-08 16:22:53 +01001260 CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
1261 CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
1262 CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
Steve Block44f0eee2011-05-26 01:26:41 +01001263}
1264
1265
1266TEST(DeleteAllHeapSnapshots) {
1267 v8::HandleScope scope;
1268 LocalContext env;
1269
1270 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1271 v8::HeapProfiler::DeleteAllSnapshots();
1272 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1273 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
1274 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1275 v8::HeapProfiler::DeleteAllSnapshots();
1276 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1277 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("1")));
1278 CHECK_NE(NULL, v8::HeapProfiler::TakeSnapshot(v8::String::New("2")));
1279 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
1280 v8::HeapProfiler::DeleteAllSnapshots();
1281 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1282}
1283
1284
1285TEST(DeleteHeapSnapshot) {
1286 v8::HandleScope scope;
1287 LocalContext env;
1288
1289 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1290 const v8::HeapSnapshot* s1 =
1291 v8::HeapProfiler::TakeSnapshot(v8::String::New("1"));
1292 CHECK_NE(NULL, s1);
1293 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1294 unsigned uid1 = s1->GetUid();
1295 CHECK_EQ(s1, v8::HeapProfiler::FindSnapshot(uid1));
1296 const_cast<v8::HeapSnapshot*>(s1)->Delete();
1297 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1298 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid1));
1299
1300 const v8::HeapSnapshot* s2 =
1301 v8::HeapProfiler::TakeSnapshot(v8::String::New("2"));
1302 CHECK_NE(NULL, s2);
1303 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1304 unsigned uid2 = s2->GetUid();
1305 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
1306 CHECK_EQ(s2, v8::HeapProfiler::FindSnapshot(uid2));
1307 const v8::HeapSnapshot* s3 =
1308 v8::HeapProfiler::TakeSnapshot(v8::String::New("3"));
1309 CHECK_NE(NULL, s3);
1310 CHECK_EQ(2, v8::HeapProfiler::GetSnapshotsCount());
1311 unsigned uid3 = s3->GetUid();
1312 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
1313 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
1314 const_cast<v8::HeapSnapshot*>(s2)->Delete();
1315 CHECK_EQ(1, v8::HeapProfiler::GetSnapshotsCount());
1316 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid2));
1317 CHECK_EQ(s3, v8::HeapProfiler::FindSnapshot(uid3));
1318 const_cast<v8::HeapSnapshot*>(s3)->Delete();
1319 CHECK_EQ(0, v8::HeapProfiler::GetSnapshotsCount());
1320 CHECK_EQ(NULL, v8::HeapProfiler::FindSnapshot(uid3));
1321}
1322
Steve Blocka7e24c12009-10-30 11:49:00 +00001323#endif // ENABLE_LOGGING_AND_PROFILING