blob: d68692116bff9590396b41095ce5c0544c31f01e [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002//
3// Tests for heap profiler
4
5#ifdef ENABLE_LOGGING_AND_PROFILING
6
7#include "v8.h"
Ben Murdoch257744e2011-11-30 15:57:28 +00008
9#include "cctest.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000010#include "heap-profiler.h"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010011#include "snapshot.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000012#include "string-stream.h"
Ben Murdoch257744e2011-11-30 15:57:28 +000013#include "utils-inl.h"
Steve Block6ded16b2010-05-10 14:33:55 +010014#include "zone-inl.h"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010015#include "../include/v8-profiler.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000016
17namespace i = v8::internal;
18using i::ClustersCoarser;
19using i::JSObjectsCluster;
20using i::JSObjectsRetainerTree;
21using i::JSObjectsClusterTree;
22using i::RetainerHeapProfile;
23
24
Steve Blocka7e24c12009-10-30 11:49:00 +000025namespace {
26
27class ConstructorHeapProfileTestHelper : public i::ConstructorHeapProfile {
28 public:
29 ConstructorHeapProfileTestHelper()
30 : i::ConstructorHeapProfile(),
Steve Block44f0eee2011-05-26 01:26:41 +010031 f_name_(FACTORY->NewStringFromAscii(i::CStrVector("F"))),
Steve Blocka7e24c12009-10-30 11:49:00 +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;
Ben Murdoch3bec4d22010-07-22 14:51:16 +010056 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +000057
Ben Murdochf87a2032010-10-22 12:50:53 +010058 CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +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;
Leon Clarked91b9f72010-01-27 17:25:45 +000066 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
Steve Blocka7e24c12009-10-30 11:49:00 +000067 cons_profile.CollectStats(obj);
Steve Blocka7e24c12009-10-30 11:49:00 +000068 CHECK_EQ(0, cons_profile.f_count());
69 cons_profile.PrintStats();
70 CHECK_EQ(2, cons_profile.f_count());
71}
72
73
74static JSObjectsCluster AddHeapObjectToTree(JSObjectsRetainerTree* tree,
75 i::String* constructor,
76 int instance,
77 JSObjectsCluster* ref1 = NULL,
78 JSObjectsCluster* ref2 = NULL,
79 JSObjectsCluster* ref3 = NULL) {
80 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
93static 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
103static 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);
130 stream.Add("# !Expected: ");
131 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;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100143 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000144
Ben Murdoch257744e2011-11-30 15:57:28 +0000145 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +0000146
147 JSObjectsRetainerTree tree;
Steve Block44f0eee2011-05-26 01:26:41 +0100148 JSObjectsCluster function(HEAP->function_class_symbol());
149 JSObjectsCluster a(*FACTORY->NewStringFromAscii(i::CStrVector("A")));
150 JSObjectsCluster b(*FACTORY->NewStringFromAscii(i::CStrVector("B")));
Steve Blocka7e24c12009-10-30 11:49:00 +0000151
152 // o1 <- Function
153 JSObjectsCluster o1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100154 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000155 // o2 <- Function
156 JSObjectsCluster o2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100157 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 // o3 <- A, B
159 JSObjectsCluster o3 =
Steve Block44f0eee2011-05-26 01:26:41 +0100160 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &a, &b);
Steve Blocka7e24c12009-10-30 11:49:00 +0000161 // o4 <- B, A
162 JSObjectsCluster o4 =
Steve Block44f0eee2011-05-26 01:26:41 +0100163 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x400, &b, &a);
Steve Blocka7e24c12009-10-30 11:49:00 +0000164 // o5 <- A, B, Function
165 JSObjectsCluster o5 =
Steve Block44f0eee2011-05-26 01:26:41 +0100166 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x500,
Steve Blocka7e24c12009-10-30 11:49:00 +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;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100181 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000182
Ben Murdoch257744e2011-11-30 15:57:28 +0000183 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +0000184
185 JSObjectsRetainerTree tree;
Steve Block44f0eee2011-05-26 01:26:41 +0100186 JSObjectsCluster function(HEAP->function_class_symbol());
Steve Blocka7e24c12009-10-30 11:49:00 +0000187
188 // o1 <- Function
189 JSObjectsCluster o1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100190 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000191 // a1 <- Function
192 JSObjectsCluster a1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100193 AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x1000, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 // o2 <- Function
195 JSObjectsCluster o2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100196 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x200, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +0000197 // a2 <- Function
198 JSObjectsCluster a2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100199 AddHeapObjectToTree(&tree, HEAP->Array_symbol(), 0x2000, &function);
Steve Blocka7e24c12009-10-30 11:49:00 +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;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100211 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000212
Ben Murdoch257744e2011-11-30 15:57:28 +0000213 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +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 =
Steve Block44f0eee2011-05-26 01:26:41 +0100229 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
Steve Blocka7e24c12009-10-30 11:49:00 +0000230 JSObjectsCluster o11 =
Steve Block44f0eee2011-05-26 01:26:41 +0100231 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 JSObjectsCluster o12 =
Steve Block44f0eee2011-05-26 01:26:41 +0100233 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 JSObjectsCluster o21 =
Steve Block44f0eee2011-05-26 01:26:41 +0100235 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x210, &o11);
Steve Blocka7e24c12009-10-30 11:49:00 +0000236 JSObjectsCluster o22 =
Steve Block44f0eee2011-05-26 01:26:41 +0100237 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x220, &o12);
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 JSObjectsCluster p =
Steve Block44f0eee2011-05-26 01:26:41 +0100239 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o21);
Steve Blocka7e24c12009-10-30 11:49:00 +0000240 JSObjectsCluster q =
Steve Block44f0eee2011-05-26 01:26:41 +0100241 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o21, &o22);
Steve Blocka7e24c12009-10-30 11:49:00 +0000242 JSObjectsCluster r =
Steve Block44f0eee2011-05-26 01:26:41 +0100243 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o22);
Steve Blocka7e24c12009-10-30 11:49:00 +0000244
245 ClustersCoarser coarser;
246 coarser.Process(&tree);
247
248 CHECK_EQ(JSObjectsCluster(), coarser.GetCoarseEquivalent(o));
249 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(o11));
250 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));
253 CHECK_NE(JSObjectsCluster(), coarser.GetCoarseEquivalent(p));
254 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
261TEST(ClustersCoarserSelf) {
262 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100263 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000264
Ben Murdoch257744e2011-11-30 15:57:28 +0000265 i::ZoneScope zn_scope(i::Isolate::Current(), i::DELETE_ON_EXIT);
Steve Blocka7e24c12009-10-30 11:49:00 +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 =
Steve Block44f0eee2011-05-26 01:26:41 +0100280 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x100);
Steve Blocka7e24c12009-10-30 11:49:00 +0000281 JSObjectsCluster o1 =
Steve Block44f0eee2011-05-26 01:26:41 +0100282 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x110, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000283 JSObjectsCluster o2 =
Steve Block44f0eee2011-05-26 01:26:41 +0100284 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x120, &o);
Steve Blocka7e24c12009-10-30 11:49:00 +0000285 JSObjectsCluster p =
Steve Block44f0eee2011-05-26 01:26:41 +0100286 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x300, &o1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000287 AddSelfReferenceToTree(&tree, &p);
288 JSObjectsCluster q =
Steve Block44f0eee2011-05-26 01:26:41 +0100289 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x310, &o1, &o2);
Steve Blocka7e24c12009-10-30 11:49:00 +0000290 AddSelfReferenceToTree(&tree, &q);
291 JSObjectsCluster r =
Steve Block44f0eee2011-05-26 01:26:41 +0100292 AddHeapObjectToTree(&tree, HEAP->Object_symbol(), 0x320, &o2);
Steve Blocka7e24c12009-10-30 11:49:00 +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
308namespace {
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;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100357 LocalContext env;
Steve Blocka7e24c12009-10-30 11:49:00 +0000358
Ben Murdochf87a2032010-10-22 12:50:53 +0100359 CompileRun(
Steve Blocka7e24c12009-10-30 11:49:00 +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;
Leon Clarked91b9f72010-01-27 17:25:45 +0000370 for (i::HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next())
Steve Blocka7e24c12009-10-30 11:49:00 +0000371 ret_profile.CollectStats(obj);
Steve Block791712a2010-08-27 10:21:07 +0100372 ret_profile.CoarseAndAggregate();
Steve Blocka7e24c12009-10-30 11:49:00 +0000373 RetainerProfilePrinter printer;
374 ret_profile.DebugPrintStats(&printer);
375 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.
Steve Blockd0582a62009-12-15 09:54:21 +0000378 CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"),
379 i::StrLength(retainers_of_a));
Steve Blocka7e24c12009-10-30 11:49:00 +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);
383 CHECK_EQ("(global property);2", printer.GetRetainers("B"));
384 CHECK_EQ("(global property);1", printer.GetRetainers("C"));
385}
386
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100387
388namespace {
389
390class NamedEntriesDetector {
391 public:
392 NamedEntriesDetector()
Russell Brenner90bac252010-11-18 13:33:46 -0800393 : has_A2(false), has_B2(false), has_C2(false) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100394 }
395
Iain Merrick75681382010-08-19 15:07:18 +0100396 void Apply(i::HeapEntry** entry_ptr) {
Iain Merrick75681382010-08-19 15:07:18 +0100397 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();
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100404 }
405
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100406 bool has_A2;
407 bool has_B2;
408 bool has_C2;
409};
410
411} // namespace
412
413
414static const v8::HeapGraphNode* GetGlobalObject(
415 const v8::HeapSnapshot* snapshot) {
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800416 CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
417 const v8::HeapGraphNode* global_obj =
418 snapshot->GetRoot()->GetChild(0)->GetToNode();
419 CHECK_EQ("Object", const_cast<i::HeapEntry*>(
420 reinterpret_cast<const i::HeapEntry*>(global_obj))->name());
421 return global_obj;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100422}
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();
Iain Merrick75681382010-08-19 15:07:18 +0100442 if (node->GetType() == v8::HeapGraphNode::kString) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100443 v8::String::AsciiValue node_name(node->GetName());
444 if (strcmp(contents, *node_name) == 0) return true;
445 }
446 }
447 return false;
448}
449
450
451TEST(HeapSnapshot) {
452 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100453 LocalContext env2;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100454
Ben Murdochf87a2032010-10-22 12:50:53 +0100455 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100456 "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"));
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100464 i::HeapSnapshot* i_snapshot_env2 =
465 const_cast<i::HeapSnapshot*>(
466 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2));
Iain Merrick75681382010-08-19 15:07:18 +0100467 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
Russell Brenner90bac252010-11-18 13:33:46 -0800473 // Verify, that JS global object of env2 has '..2' properties.
Iain Merrick75681382010-08-19 15:07:18 +0100474 const v8::HeapGraphNode* a2_node =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800475 GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "a2");
Iain Merrick75681382010-08-19 15:07:18 +0100476 CHECK_NE(NULL, a2_node);
477 CHECK_NE(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800478 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_1"));
Iain Merrick75681382010-08-19 15:07:18 +0100479 CHECK_NE(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800480 NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "b2_2"));
481 CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kShortcut, "c2"));
Iain Merrick75681382010-08-19 15:07:18 +0100482
Iain Merrick75681382010-08-19 15:07:18 +0100483 NamedEntriesDetector det;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100484 i_snapshot_env2->IterateEntries(&det);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100485 CHECK(det.has_A2);
486 CHECK(det.has_B2);
487 CHECK(det.has_C2);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100488}
489
490
Iain Merrick75681382010-08-19 15:07:18 +0100491TEST(HeapSnapshotObjectSizes) {
492 v8::HandleScope scope;
493 LocalContext env;
494
495 // -a-> X1 --a
496 // x -b-> X2 <-|
Ben Murdochf87a2032010-10-22 12:50:53 +0100497 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100498 "function X(a, b) { this.a = a; this.b = b; }\n"
499 "x = new X(new X(), new X());\n"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800500 "(function() { x.a.a = x.b; })();");
Iain Merrick75681382010-08-19 15:07:18 +0100501 const v8::HeapSnapshot* snapshot =
502 v8::HeapProfiler::TakeSnapshot(v8::String::New("sizes"));
503 const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
504 const v8::HeapGraphNode* x =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800505 GetProperty(global, v8::HeapGraphEdge::kShortcut, "x");
Iain Merrick75681382010-08-19 15:07:18 +0100506 CHECK_NE(NULL, x);
Iain Merrick75681382010-08-19 15:07:18 +0100507 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);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800513
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));
Iain Merrick75681382010-08-19 15:07:18 +0100522}
523
524
525TEST(HeapSnapshotEntryChildren) {
526 v8::HandleScope scope;
527 LocalContext env;
528
Ben Murdochf87a2032010-10-22 12:50:53 +0100529 CompileRun(
Iain Merrick75681382010-08-19 15:07:18 +0100530 "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
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100549TEST(HeapSnapshotCodeObjects) {
550 v8::HandleScope scope;
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100551 LocalContext env;
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100552
Ben Murdochf87a2032010-10-22 12:50:53 +0100553 CompileRun(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100554 "function lazy(x) { return x - 1; }\n"
555 "function compiled(x) { return x + 1; }\n"
Steve Block791712a2010-08-27 10:21:07 +0100556 "var anonymous = (function() { return function() { return 0; } })();\n"
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100557 "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 =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800563 GetProperty(global, v8::HeapGraphEdge::kShortcut, "compiled");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100564 CHECK_NE(NULL, compiled);
Iain Merrick75681382010-08-19 15:07:18 +0100565 CHECK_EQ(v8::HeapGraphNode::kClosure, compiled->GetType());
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100566 const v8::HeapGraphNode* lazy =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800567 GetProperty(global, v8::HeapGraphEdge::kShortcut, "lazy");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100568 CHECK_NE(NULL, lazy);
Iain Merrick75681382010-08-19 15:07:18 +0100569 CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
Steve Block791712a2010-08-27 10:21:07 +0100570 const v8::HeapGraphNode* anonymous =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800571 GetProperty(global, v8::HeapGraphEdge::kShortcut, "anonymous");
Steve Block791712a2010-08-27 10:21:07 +0100572 CHECK_NE(NULL, anonymous);
573 CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
574 v8::String::AsciiValue anonymous_name(anonymous->GetName());
Ben Murdochf87a2032010-10-22 12:50:53 +0100575 CHECK_EQ("", *anonymous_name);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100576
577 // Find references to code.
578 const v8::HeapGraphNode* compiled_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100579 GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100580 CHECK_NE(NULL, compiled_code);
581 const v8::HeapGraphNode* lazy_code =
Ben Murdoch8b112d22011-06-08 16:22:53 +0100582 GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100583 CHECK_NE(NULL, lazy_code);
584
585 // Verify that non-compiled code doesn't contain references to "x"
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100586 // literal, while compiled code does. The scope info is stored in FixedArray
587 // objects attached to the SharedFunctionInfo.
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100588 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();
Iain Merrick75681382010-08-19 15:07:18 +0100592 if (node->GetType() == v8::HeapGraphNode::kArray) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100593 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();
Iain Merrick75681382010-08-19 15:07:18 +0100602 if (node->GetType() == v8::HeapGraphNode::kArray) {
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100603 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
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100613
Ben Murdochf87a2032010-10-22 12:50:53 +0100614TEST(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);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800623 CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kShortcut, "a"));
Ben Murdochf87a2032010-10-22 12:50:53 +0100624 const v8::HeapGraphNode* b =
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800625 GetProperty(global, v8::HeapGraphEdge::kShortcut, "b");
Ben Murdochf87a2032010-10-22 12:50:53 +0100626 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
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100652// 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))
Iain Merrick75681382010-08-19 15:07:18 +0100657#define CHECK_NE_UINT64_T(a, b) \
658 CHECK((a) != (b)) // NOLINT
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100659
660TEST(HeapEntryIdsAndGC) {
661 v8::HandleScope scope;
662 LocalContext env;
663
Ben Murdochf87a2032010-10-22 12:50:53 +0100664 CompileRun(
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100665 "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
Steve Block44f0eee2011-05-26 01:26:41 +0100672 HEAP->CollectAllGarbage(true); // Enforce compaction.
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100673
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 =
Iain Merrick75681382010-08-19 15:07:18 +0100682 GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
683 CHECK_NE(NULL, A1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100684 const v8::HeapGraphNode* A2 =
Iain Merrick75681382010-08-19 15:07:18 +0100685 GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
686 CHECK_NE(NULL, A2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100687 CHECK_NE_UINT64_T(0, A1->GetId());
688 CHECK_EQ_UINT64_T(A1->GetId(), A2->GetId());
689 const v8::HeapGraphNode* B1 =
Iain Merrick75681382010-08-19 15:07:18 +0100690 GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
691 CHECK_NE(NULL, B1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100692 const v8::HeapGraphNode* B2 =
Iain Merrick75681382010-08-19 15:07:18 +0100693 GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
694 CHECK_NE(NULL, B2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100695 CHECK_NE_UINT64_T(0, B1->GetId());
696 CHECK_EQ_UINT64_T(B1->GetId(), B2->GetId());
697 const v8::HeapGraphNode* a1 =
Iain Merrick75681382010-08-19 15:07:18 +0100698 GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
699 CHECK_NE(NULL, a1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100700 const v8::HeapGraphNode* a2 =
Iain Merrick75681382010-08-19 15:07:18 +0100701 GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
702 CHECK_NE(NULL, a2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100703 CHECK_NE_UINT64_T(0, a1->GetId());
704 CHECK_EQ_UINT64_T(a1->GetId(), a2->GetId());
705 const v8::HeapGraphNode* b1 =
Iain Merrick75681382010-08-19 15:07:18 +0100706 GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
707 CHECK_NE(NULL, b1);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100708 const v8::HeapGraphNode* b2 =
Iain Merrick75681382010-08-19 15:07:18 +0100709 GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
710 CHECK_NE(NULL, b2);
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100711 CHECK_NE_UINT64_T(0, b1->GetId());
712 CHECK_EQ_UINT64_T(b1->GetId(), b2->GetId());
713}
714
715
Ben Murdochf87a2032010-10-22 12:50:53 +0100716TEST(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
Steve Block791712a2010-08-27 10:21:07 +0100729static 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
Ben Murdochf87a2032010-10-22 12:50:53 +0100763 CompileRun(
Steve Block791712a2010-08-27 10:21:07 +0100764 "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(),
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800772 v8::HeapGraphNode::kHidden,
Steve Block791712a2010-08-27 10:21:07 +0100773 "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(),
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800778 v8::HeapGraphNode::kHidden,
Steve Block791712a2010-08-27 10:21:07 +0100779 "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
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800838
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
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100899namespace {
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\""
Ben Murdochf87a2032010-10-22 12:50:53 +0100945 CompileRun(
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100946 "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
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100974 // Get node and edge "member" offsets.
975 v8::Local<v8::Value> meta_analysis_result = CompileRun(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800976 "var parsed_meta = parsed.nodes[0];\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100977 "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 ="
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800991 " children_meta.types[child_type_offset].indexOf('property');\n"
992 "var shortcut_type ="
993 " children_meta.types[child_type_offset].indexOf('shortcut');");
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100994 CHECK(!meta_analysis_result.IsEmpty());
995
996 // A helper function for processing encoded nodes.
997 CompileRun(
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -0800998 "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100999 " 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"
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001005 " if (nodes[child_pos + child_type_offset] === prop_type\n"
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001006 " && 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("
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001016 " parsed.nodes[1 + children_offset + child_to_node_offset],"
1017 " \"b\",shortcut_type),\n"
1018 " \"x\", property_type),"
1019 " \"s\", property_type)");
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001020 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
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08001050
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
Ben Murdochb0fe1622011-05-05 13:52:32 +01001065
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
1083
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
Steve Block44f0eee2011-05-26 01:26:41 +01001130
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
Ben Murdoch8b112d22011-06-08 16:22:53 +01001262 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"));
Steve Block44f0eee2011-05-26 01:26:41 +01001265}
1266
1267
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
Steve Blocka7e24c12009-10-30 11:49:00 +00001325#endif // ENABLE_LOGGING_AND_PROFILING