v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-heap-profiler.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28 // Tests for heap profiler
29 
30 #include <ctype.h>
31 
32 #include "v8.h"
33 
34 #include "allocation-tracker.h"
35 #include "cctest.h"
36 #include "hashmap.h"
37 #include "heap-profiler.h"
38 #include "snapshot.h"
39 #include "debug.h"
40 #include "utils-inl.h"
41 #include "../include/v8-profiler.h"
42 
46 using i::HashMap;
47 using i::Vector;
48 
49 namespace {
50 
51 class NamedEntriesDetector {
52  public:
53  NamedEntriesDetector()
54  : has_A2(false), has_B2(false), has_C2(false) {
55  }
56 
57  void CheckEntry(i::HeapEntry* entry) {
58  if (strcmp(entry->name(), "A2") == 0) has_A2 = true;
59  if (strcmp(entry->name(), "B2") == 0) has_B2 = true;
60  if (strcmp(entry->name(), "C2") == 0) has_C2 = true;
61  }
62 
63  static bool AddressesMatch(void* key1, void* key2) {
64  return key1 == key2;
65  }
66 
67  void CheckAllReachables(i::HeapEntry* root) {
68  i::HashMap visited(AddressesMatch);
69  i::List<i::HeapEntry*> list(10);
70  list.Add(root);
71  CheckEntry(root);
72  while (!list.is_empty()) {
73  i::HeapEntry* entry = list.RemoveLast();
74  i::Vector<i::HeapGraphEdge*> children = entry->children();
75  for (int i = 0; i < children.length(); ++i) {
76  if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue;
77  i::HeapEntry* child = children[i]->to();
78  i::HashMap::Entry* entry = visited.Lookup(
79  reinterpret_cast<void*>(child),
80  static_cast<uint32_t>(reinterpret_cast<uintptr_t>(child)),
81  true);
82  if (entry->value)
83  continue;
84  entry->value = reinterpret_cast<void*>(1);
85  list.Add(child);
86  CheckEntry(child);
87  }
88  }
89  }
90 
91  bool has_A2;
92  bool has_B2;
93  bool has_C2;
94 };
95 
96 } // namespace
97 
98 
99 static const v8::HeapGraphNode* GetGlobalObject(
100  const v8::HeapSnapshot* snapshot) {
101  CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
102  // The 0th-child is (GC Roots), 1st is the user root.
103  const v8::HeapGraphNode* global_obj =
104  snapshot->GetRoot()->GetChild(1)->GetToNode();
105  CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
106  reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
107  return global_obj;
108 }
109 
110 
111 static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
113  const char* name) {
114  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
115  const v8::HeapGraphEdge* prop = node->GetChild(i);
116  v8::String::Utf8Value prop_name(prop->GetName());
117  if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
118  return prop->GetToNode();
119  }
120  return NULL;
121 }
122 
123 
124 static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
125  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
126  const v8::HeapGraphEdge* prop = node->GetChild(i);
127  const v8::HeapGraphNode* node = prop->GetToNode();
128  if (node->GetType() == v8::HeapGraphNode::kString) {
129  v8::String::Utf8Value node_name(node->GetName());
130  if (strcmp(contents, *node_name) == 0) return true;
131  }
132  }
133  return false;
134 }
135 
136 
137 static bool AddressesMatch(void* key1, void* key2) {
138  return key1 == key2;
139 }
140 
141 
142 // Check that snapshot has no unretained entries except root.
143 static bool ValidateSnapshot(const v8::HeapSnapshot* snapshot, int depth = 3) {
144  i::HeapSnapshot* heap_snapshot = const_cast<i::HeapSnapshot*>(
145  reinterpret_cast<const i::HeapSnapshot*>(snapshot));
146 
147  i::HashMap visited(AddressesMatch);
148  i::List<i::HeapGraphEdge>& edges = heap_snapshot->edges();
149  for (int i = 0; i < edges.length(); ++i) {
150  i::HashMap::Entry* entry = visited.Lookup(
151  reinterpret_cast<void*>(edges[i].to()),
152  static_cast<uint32_t>(reinterpret_cast<uintptr_t>(edges[i].to())),
153  true);
154  uint32_t ref_count = static_cast<uint32_t>(
155  reinterpret_cast<uintptr_t>(entry->value));
156  entry->value = reinterpret_cast<void*>(ref_count + 1);
157  }
158  uint32_t unretained_entries_count = 0;
159  i::List<i::HeapEntry>& entries = heap_snapshot->entries();
160  for (int i = 0; i < entries.length(); ++i) {
161  i::HashMap::Entry* entry = visited.Lookup(
162  reinterpret_cast<void*>(&entries[i]),
163  static_cast<uint32_t>(reinterpret_cast<uintptr_t>(&entries[i])),
164  false);
165  if (!entry && entries[i].id() != 1) {
166  entries[i].Print("entry with no retainer", "", depth, 0);
167  ++unretained_entries_count;
168  }
169  }
170  return unretained_entries_count == 0;
171 }
172 
173 
174 TEST(HeapSnapshot) {
175  LocalContext env2;
176  v8::HandleScope scope(env2->GetIsolate());
177  v8::HeapProfiler* heap_profiler = env2->GetIsolate()->GetHeapProfiler();
178 
179  CompileRun(
180  "function A2() {}\n"
181  "function B2(x) { return function() { return typeof x; }; }\n"
182  "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
183  "var a2 = new A2();\n"
184  "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
185  "var c2 = new C2(a2);");
186  const v8::HeapSnapshot* snapshot_env2 =
187  heap_profiler->TakeHeapSnapshot(v8_str("env2"));
188  CHECK(ValidateSnapshot(snapshot_env2));
189  const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
190 
191  // Verify, that JS global object of env2 has '..2' properties.
192  const v8::HeapGraphNode* a2_node =
193  GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
194  CHECK_NE(NULL, a2_node);
195  CHECK_NE(
196  NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1"));
197  CHECK_NE(
198  NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2"));
199  CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2"));
200 
201  NamedEntriesDetector det;
202  det.CheckAllReachables(const_cast<i::HeapEntry*>(
203  reinterpret_cast<const i::HeapEntry*>(global_env2)));
204  CHECK(det.has_A2);
205  CHECK(det.has_B2);
206  CHECK(det.has_C2);
207 }
208 
209 
210 TEST(HeapSnapshotObjectSizes) {
211  LocalContext env;
212  v8::HandleScope scope(env->GetIsolate());
213  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
214 
215  // -a-> X1 --a
216  // x -b-> X2 <-|
217  CompileRun(
218  "function X(a, b) { this.a = a; this.b = b; }\n"
219  "x = new X(new X(), new X());\n"
220  "dummy = new X();\n"
221  "(function() { x.a.a = x.b; })();");
222  const v8::HeapSnapshot* snapshot =
223  heap_profiler->TakeHeapSnapshot(v8_str("sizes"));
224  CHECK(ValidateSnapshot(snapshot));
225  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
226  const v8::HeapGraphNode* x =
227  GetProperty(global, v8::HeapGraphEdge::kProperty, "x");
228  CHECK_NE(NULL, x);
229  const v8::HeapGraphNode* x1 =
230  GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
231  CHECK_NE(NULL, x1);
232  const v8::HeapGraphNode* x2 =
233  GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
234  CHECK_NE(NULL, x2);
235 
236  // Test sizes.
237  CHECK_NE(0, static_cast<int>(x->GetShallowSize()));
238  CHECK_NE(0, static_cast<int>(x1->GetShallowSize()));
239  CHECK_NE(0, static_cast<int>(x2->GetShallowSize()));
240 }
241 
242 
243 TEST(BoundFunctionInSnapshot) {
244  LocalContext env;
245  v8::HandleScope scope(env->GetIsolate());
246  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
247  CompileRun(
248  "function myFunction(a, b) { this.a = a; this.b = b; }\n"
249  "function AAAAA() {}\n"
250  "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n");
251  const v8::HeapSnapshot* snapshot =
252  heap_profiler->TakeHeapSnapshot(v8_str("sizes"));
253  CHECK(ValidateSnapshot(snapshot));
254  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
255  const v8::HeapGraphNode* f =
256  GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction");
257  CHECK(f);
258  CHECK_EQ(v8::String::NewFromUtf8(env->GetIsolate(), "native_bind"),
259  f->GetName());
260  const v8::HeapGraphNode* bindings =
261  GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
262  CHECK_NE(NULL, bindings);
263  CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
264  CHECK_EQ(4, bindings->GetChildrenCount());
265 
266  const v8::HeapGraphNode* bound_this = GetProperty(
267  f, v8::HeapGraphEdge::kShortcut, "bound_this");
268  CHECK(bound_this);
269  CHECK_EQ(v8::HeapGraphNode::kObject, bound_this->GetType());
270 
271  const v8::HeapGraphNode* bound_function = GetProperty(
272  f, v8::HeapGraphEdge::kShortcut, "bound_function");
273  CHECK(bound_function);
274  CHECK_EQ(v8::HeapGraphNode::kClosure, bound_function->GetType());
275 
276  const v8::HeapGraphNode* bound_argument = GetProperty(
277  f, v8::HeapGraphEdge::kShortcut, "bound_argument_1");
278  CHECK(bound_argument);
279  CHECK_EQ(v8::HeapGraphNode::kObject, bound_argument->GetType());
280 }
281 
282 
283 TEST(HeapSnapshotEntryChildren) {
284  LocalContext env;
285  v8::HandleScope scope(env->GetIsolate());
286  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
287 
288  CompileRun(
289  "function A() { }\n"
290  "a = new A;");
291  const v8::HeapSnapshot* snapshot =
292  heap_profiler->TakeHeapSnapshot(v8_str("children"));
293  CHECK(ValidateSnapshot(snapshot));
294  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
295  for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
296  const v8::HeapGraphEdge* prop = global->GetChild(i);
297  CHECK_EQ(global, prop->GetFromNode());
298  }
299  const v8::HeapGraphNode* a =
300  GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
301  CHECK_NE(NULL, a);
302  for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
303  const v8::HeapGraphEdge* prop = a->GetChild(i);
304  CHECK_EQ(a, prop->GetFromNode());
305  }
306 }
307 
308 
309 TEST(HeapSnapshotCodeObjects) {
310  LocalContext env;
311  v8::HandleScope scope(env->GetIsolate());
312  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
313 
314  CompileRun(
315  "function lazy(x) { return x - 1; }\n"
316  "function compiled(x) { return x + 1; }\n"
317  "var anonymous = (function() { return function() { return 0; } })();\n"
318  "compiled(1)");
319  const v8::HeapSnapshot* snapshot =
320  heap_profiler->TakeHeapSnapshot(v8_str("code"));
321  CHECK(ValidateSnapshot(snapshot));
322 
323  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
324  const v8::HeapGraphNode* compiled =
325  GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled");
326  CHECK_NE(NULL, compiled);
328  const v8::HeapGraphNode* lazy =
329  GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy");
330  CHECK_NE(NULL, lazy);
331  CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
332  const v8::HeapGraphNode* anonymous =
333  GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous");
334  CHECK_NE(NULL, anonymous);
335  CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
336  v8::String::Utf8Value anonymous_name(anonymous->GetName());
337  CHECK_EQ("", *anonymous_name);
338 
339  // Find references to code.
340  const v8::HeapGraphNode* compiled_code =
341  GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
342  CHECK_NE(NULL, compiled_code);
343  const v8::HeapGraphNode* lazy_code =
344  GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
345  CHECK_NE(NULL, lazy_code);
346 
347  // Check that there's no strong next_code_link. There might be a weak one
348  // but might be not, so we can't check that fact.
349  const v8::HeapGraphNode* code =
350  GetProperty(compiled_code, v8::HeapGraphEdge::kInternal, "code");
351  CHECK_NE(NULL, code);
352  const v8::HeapGraphNode* next_code_link =
353  GetProperty(code, v8::HeapGraphEdge::kInternal, "code");
354  CHECK_EQ(NULL, next_code_link);
355 
356  // Verify that non-compiled code doesn't contain references to "x"
357  // literal, while compiled code does. The scope info is stored in FixedArray
358  // objects attached to the SharedFunctionInfo.
359  bool compiled_references_x = false, lazy_references_x = false;
360  for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
361  const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
362  const v8::HeapGraphNode* node = prop->GetToNode();
363  if (node->GetType() == v8::HeapGraphNode::kArray) {
364  if (HasString(node, "x")) {
365  compiled_references_x = true;
366  break;
367  }
368  }
369  }
370  for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
371  const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
372  const v8::HeapGraphNode* node = prop->GetToNode();
373  if (node->GetType() == v8::HeapGraphNode::kArray) {
374  if (HasString(node, "x")) {
375  lazy_references_x = true;
376  break;
377  }
378  }
379  }
380  CHECK(compiled_references_x);
381  CHECK(!lazy_references_x);
382 }
383 
384 
385 TEST(HeapSnapshotHeapNumbers) {
386  LocalContext env;
387  v8::HandleScope scope(env->GetIsolate());
388  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
389  CompileRun(
390  "a = 1; // a is Smi\n"
391  "b = 2.5; // b is HeapNumber");
392  const v8::HeapSnapshot* snapshot =
393  heap_profiler->TakeHeapSnapshot(v8_str("numbers"));
394  CHECK(ValidateSnapshot(snapshot));
395  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
396  CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
397  const v8::HeapGraphNode* b =
398  GetProperty(global, v8::HeapGraphEdge::kProperty, "b");
399  CHECK_NE(NULL, b);
401 }
402 
403 
404 TEST(HeapSnapshotSlicedString) {
405  LocalContext env;
406  v8::HandleScope scope(env->GetIsolate());
407  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
408  CompileRun(
409  "parent_string = \"123456789.123456789.123456789.123456789.123456789."
410  "123456789.123456789.123456789.123456789.123456789."
411  "123456789.123456789.123456789.123456789.123456789."
412  "123456789.123456789.123456789.123456789.123456789.\";"
413  "child_string = parent_string.slice(100);");
414  const v8::HeapSnapshot* snapshot =
415  heap_profiler->TakeHeapSnapshot(v8_str("strings"));
416  CHECK(ValidateSnapshot(snapshot));
417  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
418  const v8::HeapGraphNode* parent_string =
419  GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string");
420  CHECK_NE(NULL, parent_string);
421  const v8::HeapGraphNode* child_string =
422  GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
423  CHECK_NE(NULL, child_string);
425  const v8::HeapGraphNode* parent =
426  GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
427  CHECK_EQ(parent_string, parent);
428  heap_profiler->DeleteAllHeapSnapshots();
429 }
430 
431 
432 TEST(HeapSnapshotConsString) {
433  v8::Isolate* isolate = CcTest::isolate();
434  v8::HandleScope scope(isolate);
435  v8::Local<v8::ObjectTemplate> global_template =
436  v8::ObjectTemplate::New(isolate);
437  global_template->SetInternalFieldCount(1);
438  LocalContext env(NULL, global_template);
439  v8::Handle<v8::Object> global_proxy = env->Global();
440  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
441  CHECK_EQ(1, global->InternalFieldCount());
442 
443  i::Factory* factory = CcTest::i_isolate()->factory();
444  i::Handle<i::String> first =
445  factory->NewStringFromAscii(i::CStrVector("0123456789"));
446  i::Handle<i::String> second =
447  factory->NewStringFromAscii(i::CStrVector("0123456789"));
448  i::Handle<i::String> cons_string = factory->NewConsString(first, second);
449 
450  global->SetInternalField(0, v8::ToApiHandle<v8::String>(cons_string));
451 
452  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
453  const v8::HeapSnapshot* snapshot =
454  heap_profiler->TakeHeapSnapshot(v8_str("cons_strings"));
455  CHECK(ValidateSnapshot(snapshot));
456  const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
457 
458  const v8::HeapGraphNode* string_node =
459  GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0");
460  CHECK_NE(NULL, string_node);
462 
463  const v8::HeapGraphNode* first_node =
464  GetProperty(string_node, v8::HeapGraphEdge::kInternal, "first");
465  CHECK_EQ(v8::HeapGraphNode::kString, first_node->GetType());
466 
467  const v8::HeapGraphNode* second_node =
468  GetProperty(string_node, v8::HeapGraphEdge::kInternal, "second");
469  CHECK_EQ(v8::HeapGraphNode::kString, second_node->GetType());
470 
471  heap_profiler->DeleteAllHeapSnapshots();
472 }
473 
474 
475 
476 TEST(HeapSnapshotInternalReferences) {
477  v8::Isolate* isolate = CcTest::isolate();
478  v8::HandleScope scope(isolate);
479  v8::Local<v8::ObjectTemplate> global_template =
480  v8::ObjectTemplate::New(isolate);
481  global_template->SetInternalFieldCount(2);
482  LocalContext env(NULL, global_template);
483  v8::Handle<v8::Object> global_proxy = env->Global();
484  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
485  CHECK_EQ(2, global->InternalFieldCount());
487  global->SetInternalField(0, v8_num(17));
488  global->SetInternalField(1, obj);
489  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
490  const v8::HeapSnapshot* snapshot =
491  heap_profiler->TakeHeapSnapshot(v8_str("internals"));
492  CHECK(ValidateSnapshot(snapshot));
493  const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
494  // The first reference will not present, because it's a Smi.
495  CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
496  // The second reference is to an object.
497  CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
498 }
499 
500 
501 // Trying to introduce a check helper for uint32_t causes many
502 // overloading ambiguities, so it seems easier just to cast
503 // them to a signed type.
504 #define CHECK_EQ_SNAPSHOT_OBJECT_ID(a, b) \
505  CHECK_EQ(static_cast<int32_t>(a), static_cast<int32_t>(b))
506 #define CHECK_NE_SNAPSHOT_OBJECT_ID(a, b) \
507  CHECK((a) != (b)) // NOLINT
508 
509 TEST(HeapSnapshotAddressReuse) {
510  LocalContext env;
511  v8::HandleScope scope(env->GetIsolate());
512  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
513 
514  CompileRun(
515  "function A() {}\n"
516  "var a = [];\n"
517  "for (var i = 0; i < 10000; ++i)\n"
518  " a[i] = new A();\n");
519  const v8::HeapSnapshot* snapshot1 =
520  heap_profiler->TakeHeapSnapshot(v8_str("snapshot1"));
521  CHECK(ValidateSnapshot(snapshot1));
522  v8::SnapshotObjectId maxId1 = snapshot1->GetMaxSnapshotJSObjectId();
523 
524  CompileRun(
525  "for (var i = 0; i < 10000; ++i)\n"
526  " a[i] = new A();\n");
528 
529  const v8::HeapSnapshot* snapshot2 =
530  heap_profiler->TakeHeapSnapshot(v8_str("snapshot2"));
531  CHECK(ValidateSnapshot(snapshot2));
532  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
533 
534  const v8::HeapGraphNode* array_node =
535  GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
536  CHECK_NE(NULL, array_node);
537  int wrong_count = 0;
538  for (int i = 0, count = array_node->GetChildrenCount(); i < count; ++i) {
539  const v8::HeapGraphEdge* prop = array_node->GetChild(i);
540  if (prop->GetType() != v8::HeapGraphEdge::kElement)
541  continue;
542  v8::SnapshotObjectId id = prop->GetToNode()->GetId();
543  if (id < maxId1)
544  ++wrong_count;
545  }
546  CHECK_EQ(0, wrong_count);
547 }
548 
549 
550 TEST(HeapEntryIdsAndArrayShift) {
551  LocalContext env;
552  v8::HandleScope scope(env->GetIsolate());
553  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
554 
555  CompileRun(
556  "function AnObject() {\n"
557  " this.first = 'first';\n"
558  " this.second = 'second';\n"
559  "}\n"
560  "var a = new Array();\n"
561  "for (var i = 0; i < 10; ++i)\n"
562  " a.push(new AnObject());\n");
563  const v8::HeapSnapshot* snapshot1 =
564  heap_profiler->TakeHeapSnapshot(v8_str("s1"));
565  CHECK(ValidateSnapshot(snapshot1));
566 
567  CompileRun(
568  "for (var i = 0; i < 1; ++i)\n"
569  " a.shift();\n");
570 
572 
573  const v8::HeapSnapshot* snapshot2 =
574  heap_profiler->TakeHeapSnapshot(v8_str("s2"));
575  CHECK(ValidateSnapshot(snapshot2));
576 
577  const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
578  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
579  CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId());
580  CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId());
581 
582  const v8::HeapGraphNode* a1 =
583  GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
584  CHECK_NE(NULL, a1);
585  const v8::HeapGraphNode* k1 =
586  GetProperty(a1, v8::HeapGraphEdge::kInternal, "elements");
587  CHECK_NE(NULL, k1);
588  const v8::HeapGraphNode* a2 =
589  GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
590  CHECK_NE(NULL, a2);
591  const v8::HeapGraphNode* k2 =
592  GetProperty(a2, v8::HeapGraphEdge::kInternal, "elements");
593  CHECK_NE(NULL, k2);
594 
595  CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId());
597 }
598 
599 
600 TEST(HeapEntryIdsAndGC) {
601  LocalContext env;
602  v8::HandleScope scope(env->GetIsolate());
603  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
604 
605  CompileRun(
606  "function A() {}\n"
607  "function B(x) { this.x = x; }\n"
608  "var a = new A();\n"
609  "var b = new B(a);");
610  v8::Local<v8::String> s1_str = v8_str("s1");
611  v8::Local<v8::String> s2_str = v8_str("s2");
612  const v8::HeapSnapshot* snapshot1 =
613  heap_profiler->TakeHeapSnapshot(s1_str);
614  CHECK(ValidateSnapshot(snapshot1));
615 
617 
618  const v8::HeapSnapshot* snapshot2 =
619  heap_profiler->TakeHeapSnapshot(s2_str);
620  CHECK(ValidateSnapshot(snapshot2));
621 
622  CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000);
623  CHECK(snapshot1->GetMaxSnapshotJSObjectId() <=
624  snapshot2->GetMaxSnapshotJSObjectId());
625 
626  const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
627  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
628  CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId());
629  CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId());
630  const v8::HeapGraphNode* A1 =
631  GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
632  CHECK_NE(NULL, A1);
633  const v8::HeapGraphNode* A2 =
634  GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
635  CHECK_NE(NULL, A2);
636  CHECK_NE_SNAPSHOT_OBJECT_ID(0, A1->GetId());
637  CHECK_EQ_SNAPSHOT_OBJECT_ID(A1->GetId(), A2->GetId());
638  const v8::HeapGraphNode* B1 =
639  GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
640  CHECK_NE(NULL, B1);
641  const v8::HeapGraphNode* B2 =
642  GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
643  CHECK_NE(NULL, B2);
644  CHECK_NE_SNAPSHOT_OBJECT_ID(0, B1->GetId());
645  CHECK_EQ_SNAPSHOT_OBJECT_ID(B1->GetId(), B2->GetId());
646  const v8::HeapGraphNode* a1 =
647  GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
648  CHECK_NE(NULL, a1);
649  const v8::HeapGraphNode* a2 =
650  GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
651  CHECK_NE(NULL, a2);
652  CHECK_NE_SNAPSHOT_OBJECT_ID(0, a1->GetId());
653  CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId());
654  const v8::HeapGraphNode* b1 =
655  GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
656  CHECK_NE(NULL, b1);
657  const v8::HeapGraphNode* b2 =
658  GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
659  CHECK_NE(NULL, b2);
660  CHECK_NE_SNAPSHOT_OBJECT_ID(0, b1->GetId());
661  CHECK_EQ_SNAPSHOT_OBJECT_ID(b1->GetId(), b2->GetId());
662 }
663 
664 
665 TEST(HeapSnapshotRootPreservedAfterSorting) {
666  LocalContext env;
667  v8::HandleScope scope(env->GetIsolate());
668  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
669  const v8::HeapSnapshot* snapshot =
670  heap_profiler->TakeHeapSnapshot(v8_str("s"));
671  CHECK(ValidateSnapshot(snapshot));
672  const v8::HeapGraphNode* root1 = snapshot->GetRoot();
673  const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
674  snapshot))->GetSortedEntriesList();
675  const v8::HeapGraphNode* root2 = snapshot->GetRoot();
676  CHECK_EQ(root1, root2);
677 }
678 
679 
680 namespace {
681 
682 class TestJSONStream : public v8::OutputStream {
683  public:
684  TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
685  explicit TestJSONStream(int abort_countdown)
686  : eos_signaled_(0), abort_countdown_(abort_countdown) {}
687  virtual ~TestJSONStream() {}
688  virtual void EndOfStream() { ++eos_signaled_; }
689  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
690  if (abort_countdown_ > 0) --abort_countdown_;
691  if (abort_countdown_ == 0) return kAbort;
692  CHECK_GT(chars_written, 0);
693  i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
694  i::OS::MemCopy(chunk.start(), buffer, chars_written);
695  return kContinue;
696  }
697  virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) {
698  ASSERT(false);
699  return kAbort;
700  }
701  void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
702  int eos_signaled() { return eos_signaled_; }
703  int size() { return buffer_.size(); }
704 
705  private:
706  i::Collector<char> buffer_;
707  int eos_signaled_;
708  int abort_countdown_;
709 };
710 
711 class AsciiResource: public v8::String::ExternalAsciiStringResource {
712  public:
713  explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
714  length_ = string.length();
715  }
716  virtual const char* data() const { return data_; }
717  virtual size_t length() const { return length_; }
718  private:
719  const char* data_;
720  size_t length_;
721 };
722 
723 } // namespace
724 
725 TEST(HeapSnapshotJSONSerialization) {
726  LocalContext env;
727  v8::HandleScope scope(env->GetIsolate());
728  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
729 
730 #define STRING_LITERAL_FOR_TEST \
731  "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
732  CompileRun(
733  "function A(s) { this.s = s; }\n"
734  "function B(x) { this.x = x; }\n"
735  "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
736  "var b = new B(a);");
737  const v8::HeapSnapshot* snapshot =
738  heap_profiler->TakeHeapSnapshot(v8_str("json"));
739  CHECK(ValidateSnapshot(snapshot));
740 
741  TestJSONStream stream;
742  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
743  CHECK_GT(stream.size(), 0);
744  CHECK_EQ(1, stream.eos_signaled());
745  i::ScopedVector<char> json(stream.size());
746  stream.WriteTo(json);
747 
748  // Verify that snapshot string is valid JSON.
749  AsciiResource* json_res = new AsciiResource(json);
750  v8::Local<v8::String> json_string =
751  v8::String::NewExternal(env->GetIsolate(), json_res);
752  env->Global()->Set(v8_str("json_snapshot"), json_string);
753  v8::Local<v8::Value> snapshot_parse_result = CompileRun(
754  "var parsed = JSON.parse(json_snapshot); true;");
755  CHECK(!snapshot_parse_result.IsEmpty());
756 
757  // Verify that snapshot object has required fields.
758  v8::Local<v8::Object> parsed_snapshot =
759  env->Global()->Get(v8_str("parsed"))->ToObject();
760  CHECK(parsed_snapshot->Has(v8_str("snapshot")));
761  CHECK(parsed_snapshot->Has(v8_str("nodes")));
762  CHECK(parsed_snapshot->Has(v8_str("edges")));
763  CHECK(parsed_snapshot->Has(v8_str("strings")));
764 
765  // Get node and edge "member" offsets.
766  v8::Local<v8::Value> meta_analysis_result = CompileRun(
767  "var meta = parsed.snapshot.meta;\n"
768  "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n"
769  "var node_fields_count = meta.node_fields.length;\n"
770  "var edge_fields_count = meta.edge_fields.length;\n"
771  "var edge_type_offset = meta.edge_fields.indexOf('type');\n"
772  "var edge_name_offset = meta.edge_fields.indexOf('name_or_index');\n"
773  "var edge_to_node_offset = meta.edge_fields.indexOf('to_node');\n"
774  "var property_type ="
775  " meta.edge_types[edge_type_offset].indexOf('property');\n"
776  "var shortcut_type ="
777  " meta.edge_types[edge_type_offset].indexOf('shortcut');\n"
778  "var node_count = parsed.nodes.length / node_fields_count;\n"
779  "var first_edge_indexes = parsed.first_edge_indexes = [];\n"
780  "for (var i = 0, first_edge_index = 0; i < node_count; ++i) {\n"
781  " first_edge_indexes[i] = first_edge_index;\n"
782  " first_edge_index += edge_fields_count *\n"
783  " parsed.nodes[i * node_fields_count + edge_count_offset];\n"
784  "}\n"
785  "first_edge_indexes[node_count] = first_edge_index;\n");
786  CHECK(!meta_analysis_result.IsEmpty());
787 
788  // A helper function for processing encoded nodes.
789  CompileRun(
790  "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
791  " var nodes = parsed.nodes;\n"
792  " var edges = parsed.edges;\n"
793  " var strings = parsed.strings;\n"
794  " var node_ordinal = pos / node_fields_count;\n"
795  " for (var i = parsed.first_edge_indexes[node_ordinal],\n"
796  " count = parsed.first_edge_indexes[node_ordinal + 1];\n"
797  " i < count; i += edge_fields_count) {\n"
798  " if (edges[i + edge_type_offset] === prop_type\n"
799  " && strings[edges[i + edge_name_offset]] === prop_name)\n"
800  " return edges[i + edge_to_node_offset];\n"
801  " }\n"
802  " return null;\n"
803  "}\n");
804  // Get the string index using the path: <root> -> <global>.b.x.s
805  v8::Local<v8::Value> string_obj_pos_val = CompileRun(
806  "GetChildPosByProperty(\n"
807  " GetChildPosByProperty(\n"
808  " GetChildPosByProperty("
809  " parsed.edges[edge_fields_count + edge_to_node_offset],"
810  " \"b\", property_type),\n"
811  " \"x\", property_type),"
812  " \"s\", property_type)");
813  CHECK(!string_obj_pos_val.IsEmpty());
814  int string_obj_pos =
815  static_cast<int>(string_obj_pos_val->ToNumber()->Value());
816  v8::Local<v8::Object> nodes_array =
817  parsed_snapshot->Get(v8_str("nodes"))->ToObject();
818  int string_index = static_cast<int>(
819  nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
820  CHECK_GT(string_index, 0);
821  v8::Local<v8::Object> strings_array =
822  parsed_snapshot->Get(v8_str("strings"))->ToObject();
823  v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
824  v8::Local<v8::String> ref_string =
825  CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
826 #undef STRING_LITERAL_FOR_TEST
827  CHECK_EQ(*v8::String::Utf8Value(ref_string),
828  *v8::String::Utf8Value(string));
829 }
830 
831 
832 TEST(HeapSnapshotJSONSerializationAborting) {
833  LocalContext env;
834  v8::HandleScope scope(env->GetIsolate());
835  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
836  const v8::HeapSnapshot* snapshot =
837  heap_profiler->TakeHeapSnapshot(v8_str("abort"));
838  CHECK(ValidateSnapshot(snapshot));
839  TestJSONStream stream(5);
840  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
841  CHECK_GT(stream.size(), 0);
842  CHECK_EQ(0, stream.eos_signaled());
843 }
844 
845 namespace {
846 
847 class TestStatsStream : public v8::OutputStream {
848  public:
849  TestStatsStream()
850  : eos_signaled_(0),
851  updates_written_(0),
852  entries_count_(0),
853  entries_size_(0),
854  intervals_count_(0),
855  first_interval_index_(-1) { }
856  TestStatsStream(const TestStatsStream& stream)
857  : v8::OutputStream(stream),
858  eos_signaled_(stream.eos_signaled_),
859  updates_written_(stream.updates_written_),
860  entries_count_(stream.entries_count_),
861  entries_size_(stream.entries_size_),
862  intervals_count_(stream.intervals_count_),
863  first_interval_index_(stream.first_interval_index_) { }
864  virtual ~TestStatsStream() {}
865  virtual void EndOfStream() { ++eos_signaled_; }
866  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
867  ASSERT(false);
868  return kAbort;
869  }
870  virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer,
871  int updates_written) {
872  ++intervals_count_;
873  ASSERT(updates_written);
874  updates_written_ += updates_written;
875  entries_count_ = 0;
876  if (first_interval_index_ == -1 && updates_written != 0)
877  first_interval_index_ = buffer[0].index;
878  for (int i = 0; i < updates_written; ++i) {
879  entries_count_ += buffer[i].count;
880  entries_size_ += buffer[i].size;
881  }
882 
883  return kContinue;
884  }
885  int eos_signaled() { return eos_signaled_; }
886  int updates_written() { return updates_written_; }
887  uint32_t entries_count() const { return entries_count_; }
888  uint32_t entries_size() const { return entries_size_; }
889  int intervals_count() const { return intervals_count_; }
890  int first_interval_index() const { return first_interval_index_; }
891 
892  private:
893  int eos_signaled_;
894  int updates_written_;
895  uint32_t entries_count_;
896  uint32_t entries_size_;
897  int intervals_count_;
898  int first_interval_index_;
899 };
900 
901 } // namespace
902 
903 static TestStatsStream GetHeapStatsUpdate(
904  v8::HeapProfiler* heap_profiler,
905  v8::SnapshotObjectId* object_id = NULL) {
906  TestStatsStream stream;
907  v8::SnapshotObjectId last_seen_id = heap_profiler->GetHeapStats(&stream);
908  if (object_id)
909  *object_id = last_seen_id;
910  CHECK_EQ(1, stream.eos_signaled());
911  return stream;
912 }
913 
914 
915 TEST(HeapSnapshotObjectsStats) {
916  LocalContext env;
917  v8::HandleScope scope(env->GetIsolate());
918  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
919 
920  heap_profiler->StartTrackingHeapObjects();
921  // We have to call GC 6 times. In other case the garbage will be
922  // the reason of flakiness.
923  for (int i = 0; i < 6; ++i) {
925  }
926 
927  v8::SnapshotObjectId initial_id;
928  {
929  // Single chunk of data expected in update. Initial data.
930  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
931  &initial_id);
932  CHECK_EQ(1, stats_update.intervals_count());
933  CHECK_EQ(1, stats_update.updates_written());
934  CHECK_LT(0, stats_update.entries_size());
935  CHECK_EQ(0, stats_update.first_interval_index());
936  }
937 
938  // No data expected in update because nothing has happened.
939  v8::SnapshotObjectId same_id;
940  CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &same_id).updates_written());
941  CHECK_EQ_SNAPSHOT_OBJECT_ID(initial_id, same_id);
942 
943  {
944  v8::SnapshotObjectId additional_string_id;
945  v8::HandleScope inner_scope_1(env->GetIsolate());
946  v8_str("string1");
947  {
948  // Single chunk of data with one new entry expected in update.
949  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler,
950  &additional_string_id);
951  CHECK_LT(same_id, additional_string_id);
952  CHECK_EQ(1, stats_update.intervals_count());
953  CHECK_EQ(1, stats_update.updates_written());
954  CHECK_LT(0, stats_update.entries_size());
955  CHECK_EQ(1, stats_update.entries_count());
956  CHECK_EQ(2, stats_update.first_interval_index());
957  }
958 
959  // No data expected in update because nothing happened.
960  v8::SnapshotObjectId last_id;
961  CHECK_EQ(0, GetHeapStatsUpdate(heap_profiler, &last_id).updates_written());
962  CHECK_EQ_SNAPSHOT_OBJECT_ID(additional_string_id, last_id);
963 
964  {
965  v8::HandleScope inner_scope_2(env->GetIsolate());
966  v8_str("string2");
967 
968  uint32_t entries_size;
969  {
970  v8::HandleScope inner_scope_3(env->GetIsolate());
971  v8_str("string3");
972  v8_str("string4");
973 
974  {
975  // Single chunk of data with three new entries expected in update.
976  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
977  CHECK_EQ(1, stats_update.intervals_count());
978  CHECK_EQ(1, stats_update.updates_written());
979  CHECK_LT(0, entries_size = stats_update.entries_size());
980  CHECK_EQ(3, stats_update.entries_count());
981  CHECK_EQ(4, stats_update.first_interval_index());
982  }
983  }
984 
985  {
986  // Single chunk of data with two left entries expected in update.
987  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
988  CHECK_EQ(1, stats_update.intervals_count());
989  CHECK_EQ(1, stats_update.updates_written());
990  CHECK_GT(entries_size, stats_update.entries_size());
991  CHECK_EQ(1, stats_update.entries_count());
992  // Two strings from forth interval were released.
993  CHECK_EQ(4, stats_update.first_interval_index());
994  }
995  }
996 
997  {
998  // Single chunk of data with 0 left entries expected in update.
999  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1000  CHECK_EQ(1, stats_update.intervals_count());
1001  CHECK_EQ(1, stats_update.updates_written());
1002  CHECK_EQ(0, stats_update.entries_size());
1003  CHECK_EQ(0, stats_update.entries_count());
1004  // The last string from forth interval was released.
1005  CHECK_EQ(4, stats_update.first_interval_index());
1006  }
1007  }
1008  {
1009  // Single chunk of data with 0 left entries expected in update.
1010  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1011  CHECK_EQ(1, stats_update.intervals_count());
1012  CHECK_EQ(1, stats_update.updates_written());
1013  CHECK_EQ(0, stats_update.entries_size());
1014  CHECK_EQ(0, stats_update.entries_count());
1015  // The only string from the second interval was released.
1016  CHECK_EQ(2, stats_update.first_interval_index());
1017  }
1018 
1020  CHECK_EQ(0, array->Length());
1021  // Force array's buffer allocation.
1022  array->Set(2, v8_num(7));
1023 
1024  uint32_t entries_size;
1025  {
1026  // Single chunk of data with 2 entries expected in update.
1027  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1028  CHECK_EQ(1, stats_update.intervals_count());
1029  CHECK_EQ(1, stats_update.updates_written());
1030  CHECK_LT(0, entries_size = stats_update.entries_size());
1031  // They are the array and its buffer.
1032  CHECK_EQ(2, stats_update.entries_count());
1033  CHECK_EQ(8, stats_update.first_interval_index());
1034  }
1035 
1036  for (int i = 0; i < 100; ++i)
1037  array->Set(i, v8_num(i));
1038 
1039  {
1040  // Single chunk of data with 1 entry expected in update.
1041  TestStatsStream stats_update = GetHeapStatsUpdate(heap_profiler);
1042  CHECK_EQ(1, stats_update.intervals_count());
1043  // The first interval was changed because old buffer was collected.
1044  // The second interval was changed because new buffer was allocated.
1045  CHECK_EQ(2, stats_update.updates_written());
1046  CHECK_LT(entries_size, stats_update.entries_size());
1047  CHECK_EQ(2, stats_update.entries_count());
1048  CHECK_EQ(8, stats_update.first_interval_index());
1049  }
1050 
1051  heap_profiler->StopTrackingHeapObjects();
1052 }
1053 
1054 
1055 TEST(HeapObjectIds) {
1056  LocalContext env;
1057  v8::Isolate* isolate = env->GetIsolate();
1058  v8::HandleScope scope(isolate);
1059  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1060 
1061  const int kLength = 10;
1062  v8::Handle<v8::Object> objects[kLength];
1063  v8::SnapshotObjectId ids[kLength];
1064 
1065  heap_profiler->StartTrackingHeapObjects(false);
1066 
1067  for (int i = 0; i < kLength; i++) {
1068  objects[i] = v8::Object::New(isolate);
1069  }
1070  GetHeapStatsUpdate(heap_profiler);
1071 
1072  for (int i = 0; i < kLength; i++) {
1073  v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1074  CHECK_NE(v8::HeapProfiler::kUnknownObjectId, static_cast<int>(id));
1075  ids[i] = id;
1076  }
1077 
1078  heap_profiler->StopTrackingHeapObjects();
1080 
1081  for (int i = 0; i < kLength; i++) {
1082  v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1083  CHECK_EQ(static_cast<int>(ids[i]), static_cast<int>(id));
1084  v8::Handle<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
1085  CHECK_EQ(objects[i], obj);
1086  }
1087 
1088  heap_profiler->ClearObjectIds();
1089  for (int i = 0; i < kLength; i++) {
1090  v8::SnapshotObjectId id = heap_profiler->GetObjectId(objects[i]);
1091  CHECK_EQ(v8::HeapProfiler::kUnknownObjectId, static_cast<int>(id));
1092  v8::Handle<v8::Value> obj = heap_profiler->FindObjectById(ids[i]);
1093  CHECK(obj.IsEmpty());
1094  }
1095 }
1096 
1097 
1098 static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
1099  const v8::HeapGraphNode* node,
1100  int level, int max_level) {
1101  if (level > max_level) return;
1102  CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
1103  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
1104  const v8::HeapGraphEdge* prop = node->GetChild(i);
1105  const v8::HeapGraphNode* child =
1106  snapshot->GetNodeById(prop->GetToNode()->GetId());
1107  CHECK_EQ_SNAPSHOT_OBJECT_ID(prop->GetToNode()->GetId(), child->GetId());
1108  CHECK_EQ(prop->GetToNode(), child);
1109  CheckChildrenIds(snapshot, child, level + 1, max_level);
1110  }
1111 }
1112 
1113 
1114 TEST(HeapSnapshotGetNodeById) {
1115  LocalContext env;
1116  v8::HandleScope scope(env->GetIsolate());
1117  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1118 
1119  const v8::HeapSnapshot* snapshot =
1120  heap_profiler->TakeHeapSnapshot(v8_str("id"));
1121  CHECK(ValidateSnapshot(snapshot));
1122  const v8::HeapGraphNode* root = snapshot->GetRoot();
1123  CheckChildrenIds(snapshot, root, 0, 3);
1124  // Check a big id, which should not exist yet.
1125  CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
1126 }
1127 
1128 
1129 TEST(HeapSnapshotGetSnapshotObjectId) {
1130  LocalContext env;
1131  v8::HandleScope scope(env->GetIsolate());
1132  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1133  CompileRun("globalObject = {};\n");
1134  const v8::HeapSnapshot* snapshot =
1135  heap_profiler->TakeHeapSnapshot(v8_str("get_snapshot_object_id"));
1136  CHECK(ValidateSnapshot(snapshot));
1137  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1138  const v8::HeapGraphNode* global_object =
1139  GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject");
1140  CHECK(global_object);
1141 
1142  v8::Local<v8::Value> globalObjectHandle = env->Global()->Get(
1143  v8::String::NewFromUtf8(env->GetIsolate(), "globalObject"));
1144  CHECK(!globalObjectHandle.IsEmpty());
1145  CHECK(globalObjectHandle->IsObject());
1146 
1147  v8::SnapshotObjectId id = heap_profiler->GetObjectId(globalObjectHandle);
1148  CHECK_NE(static_cast<int>(v8::HeapProfiler::kUnknownObjectId),
1149  id);
1150  CHECK_EQ(static_cast<int>(id), global_object->GetId());
1151 }
1152 
1153 
1154 TEST(HeapSnapshotUnknownSnapshotObjectId) {
1155  LocalContext env;
1156  v8::HandleScope scope(env->GetIsolate());
1157  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1158  CompileRun("globalObject = {};\n");
1159  const v8::HeapSnapshot* snapshot =
1160  heap_profiler->TakeHeapSnapshot(v8_str("unknown_object_id"));
1161  CHECK(ValidateSnapshot(snapshot));
1162  const v8::HeapGraphNode* node =
1164  CHECK_EQ(NULL, node);
1165 }
1166 
1167 
1168 namespace {
1169 
1170 class TestActivityControl : public v8::ActivityControl {
1171  public:
1172  explicit TestActivityControl(int abort_count)
1173  : done_(0), total_(0), abort_count_(abort_count) {}
1174  ControlOption ReportProgressValue(int done, int total) {
1175  done_ = done;
1176  total_ = total;
1177  return --abort_count_ != 0 ? kContinue : kAbort;
1178  }
1179  int done() { return done_; }
1180  int total() { return total_; }
1181 
1182  private:
1183  int done_;
1184  int total_;
1185  int abort_count_;
1186 };
1187 }
1188 
1189 
1190 TEST(TakeHeapSnapshotAborting) {
1191  LocalContext env;
1192  v8::HandleScope scope(env->GetIsolate());
1193 
1194  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1195  const int snapshots_count = heap_profiler->GetSnapshotCount();
1196  TestActivityControl aborting_control(1);
1197  const v8::HeapSnapshot* no_snapshot =
1198  heap_profiler->TakeHeapSnapshot(v8_str("abort"),
1199  &aborting_control);
1200  CHECK_EQ(NULL, no_snapshot);
1201  CHECK_EQ(snapshots_count, heap_profiler->GetSnapshotCount());
1202  CHECK_GT(aborting_control.total(), aborting_control.done());
1203 
1204  TestActivityControl control(-1); // Don't abort.
1205  const v8::HeapSnapshot* snapshot =
1206  heap_profiler->TakeHeapSnapshot(v8_str("full"),
1207  &control);
1208  CHECK(ValidateSnapshot(snapshot));
1209 
1210  CHECK_NE(NULL, snapshot);
1211  CHECK_EQ(snapshots_count + 1, heap_profiler->GetSnapshotCount());
1212  CHECK_EQ(control.total(), control.done());
1213  CHECK_GT(control.total(), 0);
1214 }
1215 
1216 
1217 namespace {
1218 
1220  public:
1221  TestRetainedObjectInfo(int hash,
1222  const char* group_label,
1223  const char* label,
1224  intptr_t element_count = -1,
1225  intptr_t size = -1)
1226  : disposed_(false),
1227  hash_(hash),
1228  group_label_(group_label),
1229  label_(label),
1230  element_count_(element_count),
1231  size_(size) {
1232  instances.Add(this);
1233  }
1234  virtual ~TestRetainedObjectInfo() {}
1235  virtual void Dispose() {
1236  CHECK(!disposed_);
1237  disposed_ = true;
1238  }
1239  virtual bool IsEquivalent(RetainedObjectInfo* other) {
1240  return GetHash() == other->GetHash();
1241  }
1242  virtual intptr_t GetHash() { return hash_; }
1243  virtual const char* GetGroupLabel() { return group_label_; }
1244  virtual const char* GetLabel() { return label_; }
1245  virtual intptr_t GetElementCount() { return element_count_; }
1246  virtual intptr_t GetSizeInBytes() { return size_; }
1247  bool disposed() { return disposed_; }
1248 
1249  static v8::RetainedObjectInfo* WrapperInfoCallback(
1250  uint16_t class_id, v8::Handle<v8::Value> wrapper) {
1251  if (class_id == 1) {
1252  if (wrapper->IsString()) {
1253  v8::String::Utf8Value utf8(wrapper);
1254  if (strcmp(*utf8, "AAA") == 0)
1255  return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
1256  else if (strcmp(*utf8, "BBB") == 0)
1257  return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
1258  }
1259  } else if (class_id == 2) {
1260  if (wrapper->IsString()) {
1261  v8::String::Utf8Value utf8(wrapper);
1262  if (strcmp(*utf8, "CCC") == 0)
1263  return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
1264  }
1265  }
1266  CHECK(false);
1267  return NULL;
1268  }
1269 
1270  static i::List<TestRetainedObjectInfo*> instances;
1271 
1272  private:
1273  bool disposed_;
1274  int hash_;
1275  const char* group_label_;
1276  const char* label_;
1277  intptr_t element_count_;
1278  intptr_t size_;
1279 };
1280 
1281 
1282 i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
1283 }
1284 
1285 
1286 static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
1288  const char* name) {
1289  for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
1290  const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
1291  if (node->GetType() == type && strcmp(name,
1292  const_cast<i::HeapEntry*>(
1293  reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
1294  return node;
1295  }
1296  }
1297  return NULL;
1298 }
1299 
1300 
1301 TEST(HeapSnapshotRetainedObjectInfo) {
1302  LocalContext env;
1303  v8::Isolate* isolate = env->GetIsolate();
1304  v8::HandleScope scope(isolate);
1305  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
1306 
1307  heap_profiler->SetWrapperClassInfoProvider(
1308  1, TestRetainedObjectInfo::WrapperInfoCallback);
1309  heap_profiler->SetWrapperClassInfoProvider(
1310  2, TestRetainedObjectInfo::WrapperInfoCallback);
1311  v8::Persistent<v8::String> p_AAA(isolate, v8_str("AAA"));
1312  p_AAA.SetWrapperClassId(1);
1313  v8::Persistent<v8::String> p_BBB(isolate, v8_str("BBB"));
1314  p_BBB.SetWrapperClassId(1);
1315  v8::Persistent<v8::String> p_CCC(isolate, v8_str("CCC"));
1316  p_CCC.SetWrapperClassId(2);
1317  CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
1318  const v8::HeapSnapshot* snapshot =
1319  heap_profiler->TakeHeapSnapshot(v8_str("retained"));
1320  CHECK(ValidateSnapshot(snapshot));
1321 
1322  CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
1323  for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
1324  CHECK(TestRetainedObjectInfo::instances[i]->disposed());
1325  delete TestRetainedObjectInfo::instances[i];
1326  }
1327 
1328  const v8::HeapGraphNode* native_group_aaa = GetNode(
1329  snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "aaa-group");
1330  CHECK_NE(NULL, native_group_aaa);
1331  CHECK_EQ(1, native_group_aaa->GetChildrenCount());
1332  const v8::HeapGraphNode* aaa = GetNode(
1333  native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
1334  CHECK_NE(NULL, aaa);
1335  CHECK_EQ(2, aaa->GetChildrenCount());
1336 
1337  const v8::HeapGraphNode* native_group_ccc = GetNode(
1338  snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "ccc-group");
1339  const v8::HeapGraphNode* ccc = GetNode(
1340  native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
1341  CHECK_NE(NULL, ccc);
1342 
1343  const v8::HeapGraphNode* n_AAA = GetNode(
1344  aaa, v8::HeapGraphNode::kString, "AAA");
1345  CHECK_NE(NULL, n_AAA);
1346  const v8::HeapGraphNode* n_BBB = GetNode(
1347  aaa, v8::HeapGraphNode::kString, "BBB");
1348  CHECK_NE(NULL, n_BBB);
1349  CHECK_EQ(1, ccc->GetChildrenCount());
1350  const v8::HeapGraphNode* n_CCC = GetNode(
1351  ccc, v8::HeapGraphNode::kString, "CCC");
1352  CHECK_NE(NULL, n_CCC);
1353 
1354  CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
1355  CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
1356  CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
1357 }
1358 
1359 
1361  public:
1362  static const int kObjectsCount = 4;
1364  CHECK_EQ(NULL, instance_);
1365  instance_ = this;
1366  isolate_ = (*env)->GetIsolate();
1367  for (int i = 0; i < kObjectsCount; i++) {
1368  objects_[i].Reset(isolate_, v8::Object::New(isolate_));
1369  }
1370  (*env)->Global()->Set(v8_str("root_object"),
1371  v8::Local<v8::Value>::New(isolate_, objects_[0]));
1372  }
1374  instance_ = NULL;
1375  }
1376 
1378  instance_->AddImplicitReferences();
1379  }
1380 
1381  private:
1382  void AddImplicitReferences() {
1383  // 0 -> 1
1384  isolate_->SetObjectGroupId(objects_[0],
1385  v8::UniqueId(1));
1386  isolate_->SetReferenceFromGroup(
1387  v8::UniqueId(1), objects_[1]);
1388  // Adding two more references: 1 -> 2, 1 -> 3
1389  isolate_->SetReference(objects_[1].As<v8::Object>(),
1390  objects_[2]);
1391  isolate_->SetReference(objects_[1].As<v8::Object>(),
1392  objects_[3]);
1393  }
1394 
1396  static GraphWithImplicitRefs* instance_;
1397  v8::Isolate* isolate_;
1398 };
1399 
1400 GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
1401 
1402 
1403 TEST(HeapSnapshotImplicitReferences) {
1404  LocalContext env;
1405  v8::HandleScope scope(env->GetIsolate());
1406  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1407 
1408  GraphWithImplicitRefs graph(&env);
1410 
1411  const v8::HeapSnapshot* snapshot =
1412  heap_profiler->TakeHeapSnapshot(v8_str("implicit_refs"));
1413  CHECK(ValidateSnapshot(snapshot));
1414 
1415  const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
1416  const v8::HeapGraphNode* obj0 = GetProperty(
1417  global_object, v8::HeapGraphEdge::kProperty, "root_object");
1418  CHECK(obj0);
1420  const v8::HeapGraphNode* obj1 = GetProperty(
1421  obj0, v8::HeapGraphEdge::kInternal, "native");
1422  CHECK(obj1);
1423  int implicit_targets_count = 0;
1424  for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
1425  const v8::HeapGraphEdge* prop = obj1->GetChild(i);
1426  v8::String::Utf8Value prop_name(prop->GetName());
1427  if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
1428  strcmp("native", *prop_name) == 0) {
1429  ++implicit_targets_count;
1430  }
1431  }
1432  CHECK_EQ(2, implicit_targets_count);
1434 }
1435 
1436 
1437 TEST(DeleteAllHeapSnapshots) {
1438  LocalContext env;
1439  v8::HandleScope scope(env->GetIsolate());
1440  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1441 
1442  CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1443  heap_profiler->DeleteAllHeapSnapshots();
1444  CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1445  CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1")));
1446  CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1447  heap_profiler->DeleteAllHeapSnapshots();
1448  CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1449  CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("1")));
1450  CHECK_NE(NULL, heap_profiler->TakeHeapSnapshot(v8_str("2")));
1451  CHECK_EQ(2, heap_profiler->GetSnapshotCount());
1452  heap_profiler->DeleteAllHeapSnapshots();
1453  CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1454 }
1455 
1456 
1457 static const v8::HeapSnapshot* FindHeapSnapshot(v8::HeapProfiler* profiler,
1458  unsigned uid) {
1459  int length = profiler->GetSnapshotCount();
1460  for (int i = 0; i < length; i++) {
1461  const v8::HeapSnapshot* snapshot = profiler->GetHeapSnapshot(i);
1462  if (snapshot->GetUid() == uid) {
1463  return snapshot;
1464  }
1465  }
1466  return NULL;
1467 }
1468 
1469 
1470 TEST(DeleteHeapSnapshot) {
1471  LocalContext env;
1472  v8::HandleScope scope(env->GetIsolate());
1473  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1474 
1475  CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1476  const v8::HeapSnapshot* s1 =
1477  heap_profiler->TakeHeapSnapshot(v8_str("1"));
1478 
1479  CHECK_NE(NULL, s1);
1480  CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1481  unsigned uid1 = s1->GetUid();
1482  CHECK_EQ(s1, FindHeapSnapshot(heap_profiler, uid1));
1483  const_cast<v8::HeapSnapshot*>(s1)->Delete();
1484  CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1485  CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid1));
1486 
1487  const v8::HeapSnapshot* s2 =
1488  heap_profiler->TakeHeapSnapshot(v8_str("2"));
1489  CHECK_NE(NULL, s2);
1490  CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1491  unsigned uid2 = s2->GetUid();
1492  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
1493  CHECK_EQ(s2, FindHeapSnapshot(heap_profiler, uid2));
1494  const v8::HeapSnapshot* s3 =
1495  heap_profiler->TakeHeapSnapshot(v8_str("3"));
1496  CHECK_NE(NULL, s3);
1497  CHECK_EQ(2, heap_profiler->GetSnapshotCount());
1498  unsigned uid3 = s3->GetUid();
1499  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
1500  CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
1501  const_cast<v8::HeapSnapshot*>(s2)->Delete();
1502  CHECK_EQ(1, heap_profiler->GetSnapshotCount());
1503  CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid2));
1504  CHECK_EQ(s3, FindHeapSnapshot(heap_profiler, uid3));
1505  const_cast<v8::HeapSnapshot*>(s3)->Delete();
1506  CHECK_EQ(0, heap_profiler->GetSnapshotCount());
1507  CHECK_EQ(NULL, FindHeapSnapshot(heap_profiler, uid3));
1508 }
1509 
1510 
1512  public:
1513  virtual const char* GetName(v8::Handle<v8::Object> object) {
1514  return "Global object name";
1515  }
1516 };
1517 
1518 
1519 TEST(GlobalObjectName) {
1520  LocalContext env;
1521  v8::HandleScope scope(env->GetIsolate());
1522  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1523 
1524  CompileRun("document = { URL:\"abcdefgh\" };");
1525 
1526  NameResolver name_resolver;
1527  const v8::HeapSnapshot* snapshot =
1528  heap_profiler->TakeHeapSnapshot(v8_str("document"),
1529  NULL,
1530  &name_resolver);
1531  CHECK(ValidateSnapshot(snapshot));
1532  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1533  CHECK_NE(NULL, global);
1534  CHECK_EQ("Object / Global object name" ,
1535  const_cast<i::HeapEntry*>(
1536  reinterpret_cast<const i::HeapEntry*>(global))->name());
1537 }
1538 
1539 
1540 TEST(GlobalObjectFields) {
1541  LocalContext env;
1542  v8::HandleScope scope(env->GetIsolate());
1543  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1544  CompileRun("obj = {};");
1545  const v8::HeapSnapshot* snapshot =
1546  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1547  CHECK(ValidateSnapshot(snapshot));
1548  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1549  const v8::HeapGraphNode* builtins =
1550  GetProperty(global, v8::HeapGraphEdge::kInternal, "builtins");
1551  CHECK_NE(NULL, builtins);
1552  const v8::HeapGraphNode* native_context =
1553  GetProperty(global, v8::HeapGraphEdge::kInternal, "native_context");
1554  CHECK_NE(NULL, native_context);
1555  const v8::HeapGraphNode* global_context =
1556  GetProperty(global, v8::HeapGraphEdge::kInternal, "global_context");
1557  CHECK_NE(NULL, global_context);
1558  const v8::HeapGraphNode* global_receiver =
1559  GetProperty(global, v8::HeapGraphEdge::kInternal, "global_receiver");
1560  CHECK_NE(NULL, global_receiver);
1561 }
1562 
1563 
1564 TEST(NoHandleLeaks) {
1565  LocalContext env;
1566  v8::HandleScope scope(env->GetIsolate());
1567  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1568 
1569  CompileRun("document = { URL:\"abcdefgh\" };");
1570 
1571  v8::Handle<v8::String> name(v8_str("leakz"));
1572  i::Isolate* isolate = CcTest::i_isolate();
1573  int count_before = i::HandleScope::NumberOfHandles(isolate);
1574  heap_profiler->TakeHeapSnapshot(name);
1575  int count_after = i::HandleScope::NumberOfHandles(isolate);
1576  CHECK_EQ(count_before, count_after);
1577 }
1578 
1579 
1580 TEST(NodesIteration) {
1581  LocalContext env;
1582  v8::HandleScope scope(env->GetIsolate());
1583  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1584  const v8::HeapSnapshot* snapshot =
1585  heap_profiler->TakeHeapSnapshot(v8_str("iteration"));
1586  CHECK(ValidateSnapshot(snapshot));
1587  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1588  CHECK_NE(NULL, global);
1589  // Verify that we can find this object by iteration.
1590  const int nodes_count = snapshot->GetNodesCount();
1591  int count = 0;
1592  for (int i = 0; i < nodes_count; ++i) {
1593  if (snapshot->GetNode(i) == global)
1594  ++count;
1595  }
1596  CHECK_EQ(1, count);
1597 }
1598 
1599 
1600 TEST(GetHeapValueForNode) {
1601  LocalContext env;
1602  v8::HandleScope scope(env->GetIsolate());
1603  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1604 
1605  CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };");
1606  const v8::HeapSnapshot* snapshot =
1607  heap_profiler->TakeHeapSnapshot(v8_str("value"));
1608  CHECK(ValidateSnapshot(snapshot));
1609  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1610  CHECK(heap_profiler->FindObjectById(global->GetId())->IsObject());
1611  v8::Local<v8::Object> js_global =
1612  env->Global()->GetPrototype().As<v8::Object>();
1613  CHECK(js_global == heap_profiler->FindObjectById(global->GetId()));
1614  const v8::HeapGraphNode* obj = GetProperty(
1615  global, v8::HeapGraphEdge::kProperty, "a");
1616  CHECK(heap_profiler->FindObjectById(obj->GetId())->IsObject());
1617  v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>();
1618  CHECK(js_obj == heap_profiler->FindObjectById(obj->GetId()));
1619  const v8::HeapGraphNode* s_prop =
1620  GetProperty(obj, v8::HeapGraphEdge::kProperty, "s_prop");
1621  v8::Local<v8::String> js_s_prop =
1622  js_obj->Get(v8_str("s_prop")).As<v8::String>();
1623  CHECK(js_s_prop == heap_profiler->FindObjectById(s_prop->GetId()));
1624  const v8::HeapGraphNode* n_prop =
1625  GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
1626  v8::Local<v8::Number> js_n_prop =
1627  js_obj->Get(v8_str("n_prop")).As<v8::Number>();
1628  CHECK(js_n_prop->NumberValue() ==
1629  heap_profiler->FindObjectById(n_prop->GetId())->NumberValue());
1630 }
1631 
1632 
1633 TEST(GetHeapValueForDeletedObject) {
1634  LocalContext env;
1635  v8::HandleScope scope(env->GetIsolate());
1636  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1637 
1638  // It is impossible to delete a global property, so we are about to delete a
1639  // property of the "a" object. Also, the "p" object can't be an empty one
1640  // because the empty object is static and isn't actually deleted.
1641  CompileRun("a = { p: { r: {} } };");
1642  const v8::HeapSnapshot* snapshot =
1643  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1644  CHECK(ValidateSnapshot(snapshot));
1645  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1646  const v8::HeapGraphNode* obj = GetProperty(
1647  global, v8::HeapGraphEdge::kProperty, "a");
1648  const v8::HeapGraphNode* prop = GetProperty(
1649  obj, v8::HeapGraphEdge::kProperty, "p");
1650  {
1651  // Perform the check inside a nested local scope to avoid creating a
1652  // reference to the object we are deleting.
1653  v8::HandleScope scope(env->GetIsolate());
1654  CHECK(heap_profiler->FindObjectById(prop->GetId())->IsObject());
1655  }
1656  CompileRun("delete a.p;");
1657  CHECK(heap_profiler->FindObjectById(prop->GetId()).IsEmpty());
1658 }
1659 
1660 
1661 static int StringCmp(const char* ref, i::String* act) {
1662  i::SmartArrayPointer<char> s_act = act->ToCString();
1663  int result = strcmp(ref, s_act.get());
1664  if (result != 0)
1665  fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, s_act.get());
1666  return result;
1667 }
1668 
1669 
1670 TEST(GetConstructorName) {
1671  LocalContext env;
1672  v8::HandleScope scope(env->GetIsolate());
1673 
1674  CompileRun(
1675  "function Constructor1() {};\n"
1676  "var obj1 = new Constructor1();\n"
1677  "var Constructor2 = function() {};\n"
1678  "var obj2 = new Constructor2();\n"
1679  "var obj3 = {};\n"
1680  "obj3.constructor = function Constructor3() {};\n"
1681  "var obj4 = {};\n"
1682  "// Slow properties\n"
1683  "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
1684  "obj4.constructor = function Constructor4() {};\n"
1685  "var obj5 = {};\n"
1686  "var obj6 = {};\n"
1687  "obj6.constructor = 6;");
1688  v8::Local<v8::Object> js_global =
1689  env->Global()->GetPrototype().As<v8::Object>();
1690  v8::Local<v8::Object> obj1 = js_global->Get(v8_str("obj1")).As<v8::Object>();
1692  CHECK_EQ(0, StringCmp(
1693  "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
1694  v8::Local<v8::Object> obj2 = js_global->Get(v8_str("obj2")).As<v8::Object>();
1696  CHECK_EQ(0, StringCmp(
1697  "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
1698  v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
1700  CHECK_EQ(0, StringCmp(
1701  "Constructor3", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
1702  v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
1704  CHECK_EQ(0, StringCmp(
1705  "Constructor4", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
1706  v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
1708  CHECK_EQ(0, StringCmp(
1709  "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
1710  v8::Local<v8::Object> obj6 = js_global->Get(v8_str("obj6")).As<v8::Object>();
1712  CHECK_EQ(0, StringCmp(
1713  "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
1714 }
1715 
1716 
1717 TEST(FastCaseAccessors) {
1718  LocalContext env;
1719  v8::HandleScope scope(env->GetIsolate());
1720  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1721 
1722  CompileRun("var obj1 = {};\n"
1723  "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1724  " return 42;\n"
1725  "});\n"
1726  "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1727  " return this.value_ = value;\n"
1728  "});\n");
1729  const v8::HeapSnapshot* snapshot =
1730  heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
1731  CHECK(ValidateSnapshot(snapshot));
1732 
1733  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1734  CHECK_NE(NULL, global);
1735  const v8::HeapGraphNode* obj1 =
1736  GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
1737  CHECK_NE(NULL, obj1);
1738  const v8::HeapGraphNode* func;
1739  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
1740  CHECK_NE(NULL, func);
1741  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
1742  CHECK_EQ(NULL, func);
1743  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
1744  CHECK_NE(NULL, func);
1745  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
1746  CHECK_EQ(NULL, func);
1747 }
1748 
1749 
1750 TEST(SlowCaseAccessors) {
1751  LocalContext env;
1752  v8::HandleScope scope(env->GetIsolate());
1753  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1754 
1755  CompileRun("var obj1 = {};\n"
1756  "for (var i = 0; i < 100; ++i) obj1['z' + i] = {};"
1757  "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1758  " return 42;\n"
1759  "});\n"
1760  "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1761  " return this.value_ = value;\n"
1762  "});\n");
1763  const v8::HeapSnapshot* snapshot =
1764  heap_profiler->TakeHeapSnapshot(v8_str("slowCaseAccessors"));
1765  CHECK(ValidateSnapshot(snapshot));
1766 
1767  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1768  CHECK_NE(NULL, global);
1769  const v8::HeapGraphNode* obj1 =
1770  GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
1771  CHECK_NE(NULL, obj1);
1772  const v8::HeapGraphNode* func;
1773  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithGetter");
1774  CHECK_NE(NULL, func);
1775  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithGetter");
1776  CHECK_EQ(NULL, func);
1777  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set propWithSetter");
1778  CHECK_NE(NULL, func);
1779  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get propWithSetter");
1780  CHECK_EQ(NULL, func);
1781 }
1782 
1783 
1784 TEST(HiddenPropertiesFastCase) {
1785  LocalContext env;
1786  v8::HandleScope scope(env->GetIsolate());
1787  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1788 
1789  CompileRun(
1790  "function C(x) { this.a = this; this.b = x; }\n"
1791  "c = new C(2012);\n");
1792  const v8::HeapSnapshot* snapshot =
1793  heap_profiler->TakeHeapSnapshot(v8_str("HiddenPropertiesFastCase1"));
1794  CHECK(ValidateSnapshot(snapshot));
1795  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1796  const v8::HeapGraphNode* c =
1797  GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
1798  CHECK_NE(NULL, c);
1799  const v8::HeapGraphNode* hidden_props =
1800  GetProperty(c, v8::HeapGraphEdge::kInternal, "hidden_properties");
1801  CHECK_EQ(NULL, hidden_props);
1802 
1803  v8::Handle<v8::Value> cHandle =
1804  env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"));
1805  CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
1806  cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
1807 
1808  snapshot = heap_profiler->TakeHeapSnapshot(
1809  v8_str("HiddenPropertiesFastCase2"));
1810  CHECK(ValidateSnapshot(snapshot));
1811  global = GetGlobalObject(snapshot);
1812  c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
1813  CHECK_NE(NULL, c);
1814  hidden_props = GetProperty(c, v8::HeapGraphEdge::kInternal,
1815  "hidden_properties");
1816  CHECK_NE(NULL, hidden_props);
1817 }
1818 
1819 
1820 bool HasWeakEdge(const v8::HeapGraphNode* node) {
1821  for (int i = 0; i < node->GetChildrenCount(); ++i) {
1822  const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
1823  if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
1824  }
1825  return false;
1826 }
1827 
1828 
1830  v8::Isolate* isolate = CcTest::isolate();
1831  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
1832  const v8::HeapSnapshot* snapshot =
1833  heap_profiler->TakeHeapSnapshot(v8_str("weaks"));
1834  CHECK(ValidateSnapshot(snapshot));
1835  const v8::HeapGraphNode* gc_roots = GetNode(
1836  snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
1837  CHECK_NE(NULL, gc_roots);
1838  const v8::HeapGraphNode* global_handles = GetNode(
1839  gc_roots, v8::HeapGraphNode::kSynthetic, "(Global handles)");
1840  CHECK_NE(NULL, global_handles);
1841  return HasWeakEdge(global_handles);
1842 }
1843 
1844 
1845 static void PersistentHandleCallback(
1847  data.GetParameter()->Reset();
1848  delete data.GetParameter();
1849 }
1850 
1851 
1852 TEST(WeakGlobalHandle) {
1853  LocalContext env;
1854  v8::HandleScope scope(env->GetIsolate());
1855 
1857 
1859  v8::Object::New(env->GetIsolate()));
1860  handle.SetWeak(&handle, PersistentHandleCallback);
1861 
1863 }
1864 
1865 
1866 TEST(SfiAndJsFunctionWeakRefs) {
1867  LocalContext env;
1868  v8::HandleScope scope(env->GetIsolate());
1869  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1870 
1871  CompileRun(
1872  "fun = (function (x) { return function () { return x + 1; } })(1);");
1873  const v8::HeapSnapshot* snapshot =
1874  heap_profiler->TakeHeapSnapshot(v8_str("fun"));
1875  CHECK(ValidateSnapshot(snapshot));
1876  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1877  CHECK_NE(NULL, global);
1878  const v8::HeapGraphNode* fun =
1879  GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
1880  CHECK(!HasWeakEdge(fun));
1881  const v8::HeapGraphNode* shared =
1882  GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
1883  CHECK(!HasWeakEdge(shared));
1884 }
1885 
1886 
1887 #ifdef ENABLE_DEBUGGER_SUPPORT
1888 TEST(NoDebugObjectInSnapshot) {
1889  LocalContext env;
1890  v8::HandleScope scope(env->GetIsolate());
1891  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1892 
1893  CcTest::i_isolate()->debug()->Load();
1894  CompileRun("foo = {};");
1895  const v8::HeapSnapshot* snapshot =
1896  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1897  CHECK(ValidateSnapshot(snapshot));
1898  const v8::HeapGraphNode* root = snapshot->GetRoot();
1899  int globals_count = 0;
1900  for (int i = 0; i < root->GetChildrenCount(); ++i) {
1901  const v8::HeapGraphEdge* edge = root->GetChild(i);
1902  if (edge->GetType() == v8::HeapGraphEdge::kShortcut) {
1903  ++globals_count;
1904  const v8::HeapGraphNode* global = edge->GetToNode();
1905  const v8::HeapGraphNode* foo =
1906  GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
1907  CHECK_NE(NULL, foo);
1908  }
1909  }
1910  CHECK_EQ(1, globals_count);
1911 }
1912 #endif // ENABLE_DEBUGGER_SUPPORT
1913 
1914 
1915 TEST(AllStrongGcRootsHaveNames) {
1916  LocalContext env;
1917  v8::HandleScope scope(env->GetIsolate());
1918  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1919 
1920  CompileRun("foo = {};");
1921  const v8::HeapSnapshot* snapshot =
1922  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1923  CHECK(ValidateSnapshot(snapshot));
1924  const v8::HeapGraphNode* gc_roots = GetNode(
1925  snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "(GC roots)");
1926  CHECK_NE(NULL, gc_roots);
1927  const v8::HeapGraphNode* strong_roots = GetNode(
1928  gc_roots, v8::HeapGraphNode::kSynthetic, "(Strong roots)");
1929  CHECK_NE(NULL, strong_roots);
1930  for (int i = 0; i < strong_roots->GetChildrenCount(); ++i) {
1931  const v8::HeapGraphEdge* edge = strong_roots->GetChild(i);
1934  CHECK(isalpha(**name));
1935  }
1936 }
1937 
1938 
1939 TEST(NoRefsToNonEssentialEntries) {
1940  LocalContext env;
1941  v8::HandleScope scope(env->GetIsolate());
1942  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1943  CompileRun("global_object = {};\n");
1944  const v8::HeapSnapshot* snapshot =
1945  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1946  CHECK(ValidateSnapshot(snapshot));
1947  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1948  const v8::HeapGraphNode* global_object =
1949  GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object");
1950  CHECK_NE(NULL, global_object);
1951  const v8::HeapGraphNode* properties =
1952  GetProperty(global_object, v8::HeapGraphEdge::kInternal, "properties");
1953  CHECK_EQ(NULL, properties);
1954  const v8::HeapGraphNode* elements =
1955  GetProperty(global_object, v8::HeapGraphEdge::kInternal, "elements");
1956  CHECK_EQ(NULL, elements);
1957 }
1958 
1959 
1960 TEST(MapHasDescriptorsAndTransitions) {
1961  LocalContext env;
1962  v8::HandleScope scope(env->GetIsolate());
1963  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1964  CompileRun("obj = { a: 10 };\n");
1965  const v8::HeapSnapshot* snapshot =
1966  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
1967  CHECK(ValidateSnapshot(snapshot));
1968  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1969  const v8::HeapGraphNode* global_object =
1970  GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
1971  CHECK_NE(NULL, global_object);
1972 
1973  const v8::HeapGraphNode* map =
1974  GetProperty(global_object, v8::HeapGraphEdge::kInternal, "map");
1975  CHECK_NE(NULL, map);
1976  const v8::HeapGraphNode* own_descriptors = GetProperty(
1977  map, v8::HeapGraphEdge::kInternal, "descriptors");
1978  CHECK_NE(NULL, own_descriptors);
1979  const v8::HeapGraphNode* own_transitions = GetProperty(
1980  map, v8::HeapGraphEdge::kInternal, "transitions");
1981  CHECK_EQ(NULL, own_transitions);
1982 }
1983 
1984 
1985 TEST(ManyLocalsInSharedContext) {
1986  LocalContext env;
1987  v8::HandleScope scope(env->GetIsolate());
1988  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
1989  int num_objects = 6000;
1990  CompileRun(
1991  "var n = 6000;"
1992  "var result = [];"
1993  "result.push('(function outer() {');"
1994  "for (var i = 0; i < n; i++) {"
1995  " var f = 'function f_' + i + '() { ';"
1996  " if (i > 0)"
1997  " f += 'f_' + (i - 1) + '();';"
1998  " f += ' }';"
1999  " result.push(f);"
2000  "}"
2001  "result.push('return f_' + (n - 1) + ';');"
2002  "result.push('})()');"
2003  "var ok = eval(result.join('\\n'));");
2004  const v8::HeapSnapshot* snapshot =
2005  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2006  CHECK(ValidateSnapshot(snapshot));
2007 
2008  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2009  CHECK_NE(NULL, global);
2010  const v8::HeapGraphNode* ok_object =
2011  GetProperty(global, v8::HeapGraphEdge::kProperty, "ok");
2012  CHECK_NE(NULL, ok_object);
2013  const v8::HeapGraphNode* context_object =
2014  GetProperty(ok_object, v8::HeapGraphEdge::kInternal, "context");
2015  CHECK_NE(NULL, context_object);
2016  // Check the objects are not duplicated in the context.
2018  context_object->GetChildrenCount());
2019  // Check all the objects have got their names.
2020  // ... well check just every 15th because otherwise it's too slow in debug.
2021  for (int i = 0; i < num_objects - 1; i += 15) {
2023  i::OS::SNPrintF(var_name, "f_%d", i);
2024  const v8::HeapGraphNode* f_object = GetProperty(
2025  context_object, v8::HeapGraphEdge::kContextVariable, var_name.start());
2026  CHECK_NE(NULL, f_object);
2027  }
2028 }
2029 
2030 
2031 TEST(AllocationSitesAreVisible) {
2032  LocalContext env;
2033  v8::Isolate* isolate = env->GetIsolate();
2034  v8::HandleScope scope(isolate);
2035  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2036  CompileRun(
2037  "fun = function () { var a = [3, 2, 1]; return a; }\n"
2038  "fun();");
2039  const v8::HeapSnapshot* snapshot =
2040  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2041  CHECK(ValidateSnapshot(snapshot));
2042 
2043  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2044  CHECK_NE(NULL, global);
2045  const v8::HeapGraphNode* fun_code =
2046  GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
2047  CHECK_NE(NULL, fun_code);
2048  const v8::HeapGraphNode* literals =
2049  GetProperty(fun_code, v8::HeapGraphEdge::kInternal, "literals");
2050  CHECK_NE(NULL, literals);
2052  CHECK_EQ(2, literals->GetChildrenCount());
2053 
2054  // The second value in the literals array should be the boilerplate,
2055  // after an AllocationSite.
2056  const v8::HeapGraphEdge* prop = literals->GetChild(1);
2057  const v8::HeapGraphNode* allocation_site = prop->GetToNode();
2058  v8::String::Utf8Value name(allocation_site->GetName());
2059  CHECK_EQ("system / AllocationSite", *name);
2060  const v8::HeapGraphNode* transition_info =
2061  GetProperty(allocation_site, v8::HeapGraphEdge::kInternal,
2062  "transition_info");
2063  CHECK_NE(NULL, transition_info);
2064 
2065  const v8::HeapGraphNode* elements =
2066  GetProperty(transition_info, v8::HeapGraphEdge::kInternal,
2067  "elements");
2068  CHECK_NE(NULL, elements);
2071  static_cast<int>(elements->GetShallowSize()));
2072 
2073  v8::Handle<v8::Value> array_val =
2074  heap_profiler->FindObjectById(transition_info->GetId());
2075  CHECK(array_val->IsArray());
2077  // Verify the array is "a" in the code above.
2078  CHECK_EQ(3, array->Length());
2079  CHECK_EQ(v8::Integer::New(isolate, 3),
2080  array->Get(v8::Integer::New(isolate, 0)));
2081  CHECK_EQ(v8::Integer::New(isolate, 2),
2082  array->Get(v8::Integer::New(isolate, 1)));
2083  CHECK_EQ(v8::Integer::New(isolate, 1),
2084  array->Get(v8::Integer::New(isolate, 2)));
2085 }
2086 
2087 
2088 TEST(JSFunctionHasCodeLink) {
2089  LocalContext env;
2090  v8::HandleScope scope(env->GetIsolate());
2091  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2092  CompileRun("function foo(x, y) { return x + y; }\n");
2093  const v8::HeapSnapshot* snapshot =
2094  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2095  CHECK(ValidateSnapshot(snapshot));
2096  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2097  const v8::HeapGraphNode* foo_func =
2098  GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
2099  CHECK_NE(NULL, foo_func);
2100  const v8::HeapGraphNode* code =
2101  GetProperty(foo_func, v8::HeapGraphEdge::kInternal, "code");
2102  CHECK_NE(NULL, code);
2103 }
2104 
2105 
2106 static const v8::HeapGraphNode* GetNodeByPath(const v8::HeapSnapshot* snapshot,
2107  const char* path[],
2108  int depth) {
2109  const v8::HeapGraphNode* node = snapshot->GetRoot();
2110  for (int current_depth = 0; current_depth < depth; ++current_depth) {
2111  int i, count = node->GetChildrenCount();
2112  for (i = 0; i < count; ++i) {
2113  const v8::HeapGraphEdge* edge = node->GetChild(i);
2114  const v8::HeapGraphNode* to_node = edge->GetToNode();
2115  v8::String::Utf8Value edge_name(edge->GetName());
2116  v8::String::Utf8Value node_name(to_node->GetName());
2118  i::OS::SNPrintF(name, "%s::%s", *edge_name, *node_name);
2119  if (strstr(name.start(), path[current_depth])) {
2120  node = to_node;
2121  break;
2122  }
2123  }
2124  if (i == count) return NULL;
2125  }
2126  return node;
2127 }
2128 
2129 
2130 TEST(CheckCodeNames) {
2131  LocalContext env;
2132  v8::HandleScope scope(env->GetIsolate());
2133  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2134  CompileRun("var a = 1.1;");
2135  const v8::HeapSnapshot* snapshot =
2136  heap_profiler->TakeHeapSnapshot(v8_str("CheckCodeNames"));
2137  CHECK(ValidateSnapshot(snapshot));
2138 
2139  const char* stub_path[] = {
2140  "::(GC roots)",
2141  "::(Strong roots)",
2142  "code_stubs::",
2143  "::(ArraySingleArgumentConstructorStub code)"
2144  };
2145  const v8::HeapGraphNode* node = GetNodeByPath(snapshot,
2146  stub_path, ARRAY_SIZE(stub_path));
2147  CHECK_NE(NULL, node);
2148 
2149  const char* builtin_path1[] = {
2150  "::(GC roots)",
2151  "::(Builtins)",
2152  "::(KeyedLoadIC_Generic builtin)"
2153  };
2154  node = GetNodeByPath(snapshot, builtin_path1, ARRAY_SIZE(builtin_path1));
2155  CHECK_NE(NULL, node);
2156 
2157  const char* builtin_path2[] = {
2158  "::(GC roots)",
2159  "::(Builtins)",
2160  "::(CompileUnoptimized builtin)"
2161  };
2162  node = GetNodeByPath(snapshot, builtin_path2, ARRAY_SIZE(builtin_path2));
2163  CHECK_NE(NULL, node);
2164  v8::String::Utf8Value node_name(node->GetName());
2165  CHECK_EQ("(CompileUnoptimized builtin)", *node_name);
2166 }
2167 
2168 
2169 static const char* record_trace_tree_source =
2170 "var topFunctions = [];\n"
2171 "var global = this;\n"
2172 "function generateFunctions(width, depth) {\n"
2173 " var script = [];\n"
2174 " for (var i = 0; i < width; i++) {\n"
2175 " for (var j = 0; j < depth; j++) {\n"
2176 " script.push('function f_' + i + '_' + j + '(x) {\\n');\n"
2177 " script.push(' try {\\n');\n"
2178 " if (j < depth-2) {\n"
2179 " script.push(' return f_' + i + '_' + (j+1) + '(x+1);\\n');\n"
2180 " } else if (j == depth - 2) {\n"
2181 " script.push(' return new f_' + i + '_' + (depth - 1) + '();\\n');\n"
2182 " } else if (j == depth - 1) {\n"
2183 " script.push(' this.ts = Date.now();\\n');\n"
2184 " }\n"
2185 " script.push(' } catch (e) {}\\n');\n"
2186 " script.push('}\\n');\n"
2187 " \n"
2188 " }\n"
2189 " }\n"
2190 " var script = script.join('');\n"
2191 " // throw script;\n"
2192 " global.eval(script);\n"
2193 " for (var i = 0; i < width; i++) {\n"
2194 " topFunctions.push(this['f_' + i + '_0']);\n"
2195 " }\n"
2196 "}\n"
2197 "\n"
2198 "var width = 3;\n"
2199 "var depth = 3;\n"
2200 "generateFunctions(width, depth);\n"
2201 "var instances = [];\n"
2202 "function start() {\n"
2203 " for (var i = 0; i < width; i++) {\n"
2204 " instances.push(topFunctions[i](0));\n"
2205 " }\n"
2206 "}\n"
2207 "\n"
2208 "for (var i = 0; i < 100; i++) start();\n";
2209 
2210 
2211 static AllocationTraceNode* FindNode(
2212  AllocationTracker* tracker, const Vector<const char*>& names) {
2213  AllocationTraceNode* node = tracker->trace_tree()->root();
2214  for (int i = 0; node != NULL && i < names.length(); i++) {
2215  const char* name = names[i];
2216  Vector<AllocationTraceNode*> children = node->children();
2217  node = NULL;
2218  for (int j = 0; j < children.length(); j++) {
2219  unsigned index = children[j]->function_info_index();
2220  AllocationTracker::FunctionInfo* info =
2221  tracker->function_info_list()[index];
2222  if (info && strcmp(info->name, name) == 0) {
2223  node = children[j];
2224  break;
2225  }
2226  }
2227  }
2228  return node;
2229 }
2230 
2231 
2232 TEST(ArrayGrowLeftTrim) {
2233  LocalContext env;
2234  v8::HandleScope scope(env->GetIsolate());
2235  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2236  heap_profiler->StartTrackingHeapObjects(true);
2237 
2238  CompileRun(
2239  "var a = [];\n"
2240  "for (var i = 0; i < 5; ++i)\n"
2241  " a[i] = i;\n"
2242  "for (var i = 0; i < 3; ++i)\n"
2243  " a.shift();\n");
2244 
2245  const char* names[] = { "(anonymous function)" };
2246  AllocationTracker* tracker =
2247  reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2248  CHECK_NE(NULL, tracker);
2249  // Resolve all function locations.
2250  tracker->PrepareForSerialization();
2251  // Print for better diagnostics in case of failure.
2252  tracker->trace_tree()->Print(tracker);
2253 
2254  AllocationTraceNode* node =
2255  FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
2256  CHECK_NE(NULL, node);
2257  CHECK_GE(node->allocation_count(), 2);
2258  CHECK_GE(node->allocation_size(), 4 * 5);
2259  heap_profiler->StopTrackingHeapObjects();
2260 }
2261 
2262 
2263 TEST(TrackHeapAllocations) {
2265  LocalContext env;
2266 
2267  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2268  heap_profiler->StartTrackingHeapObjects(true);
2269 
2270  CompileRun(record_trace_tree_source);
2271 
2272  AllocationTracker* tracker =
2273  reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2274  CHECK_NE(NULL, tracker);
2275  // Resolve all function locations.
2276  tracker->PrepareForSerialization();
2277  // Print for better diagnostics in case of failure.
2278  tracker->trace_tree()->Print(tracker);
2279 
2280  const char* names[] =
2281  { "(anonymous function)", "start", "f_0_0", "f_0_1", "f_0_2" };
2282  AllocationTraceNode* node =
2283  FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
2284  CHECK_NE(NULL, node);
2285  CHECK_GE(node->allocation_count(), 100);
2286  CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2287  heap_profiler->StopTrackingHeapObjects();
2288 }
2289 
2290 
2291 static const char* inline_heap_allocation_source =
2292 "function f_0(x) {\n"
2293 " return f_1(x+1);\n"
2294 "}\n"
2295 "%NeverOptimizeFunction(f_0);\n"
2296 "function f_1(x) {\n"
2297 " return new f_2(x+1);\n"
2298 "}\n"
2299 "function f_2(x) {\n"
2300 " this.foo = x;\n"
2301 "}\n"
2302 "var instances = [];\n"
2303 "function start() {\n"
2304 " instances.push(f_0(0));\n"
2305 "}\n"
2306 "\n"
2307 "for (var i = 0; i < 100; i++) start();\n";
2308 
2309 
2310 TEST(TrackBumpPointerAllocations) {
2311  i::FLAG_allow_natives_syntax = true;
2313  LocalContext env;
2314 
2315  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2316  const char* names[] = { "(anonymous function)", "start", "f_0", "f_1" };
2317  // First check that normally all allocations are recorded.
2318  {
2319  heap_profiler->StartTrackingHeapObjects(true);
2320 
2321  CompileRun(inline_heap_allocation_source);
2322 
2323  AllocationTracker* tracker =
2324  reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2325  CHECK_NE(NULL, tracker);
2326  // Resolve all function locations.
2327  tracker->PrepareForSerialization();
2328  // Print for better diagnostics in case of failure.
2329  tracker->trace_tree()->Print(tracker);
2330 
2331  AllocationTraceNode* node =
2332  FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
2333  CHECK_NE(NULL, node);
2334  CHECK_GE(node->allocation_count(), 100);
2335  CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2336  heap_profiler->StopTrackingHeapObjects();
2337  }
2338 
2339  {
2340  heap_profiler->StartTrackingHeapObjects(true);
2341 
2342  // Now check that not all allocations are tracked if we manually reenable
2343  // inline allocations.
2344  CHECK(CcTest::heap()->inline_allocation_disabled());
2346 
2347  CompileRun(inline_heap_allocation_source);
2348 
2349  AllocationTracker* tracker =
2350  reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2351  CHECK_NE(NULL, tracker);
2352  // Resolve all function locations.
2353  tracker->PrepareForSerialization();
2354  // Print for better diagnostics in case of failure.
2355  tracker->trace_tree()->Print(tracker);
2356 
2357  AllocationTraceNode* node =
2358  FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
2359  CHECK_NE(NULL, node);
2360  CHECK_LT(node->allocation_count(), 100);
2361 
2363  heap_profiler->StopTrackingHeapObjects();
2364  }
2365 }
2366 
2367 
2368 TEST(TrackV8ApiAllocation) {
2370  LocalContext env;
2371 
2372  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2373  const char* names[] = { "(V8 API)" };
2374  heap_profiler->StartTrackingHeapObjects(true);
2375 
2377  o1->Clone();
2378 
2379  AllocationTracker* tracker =
2380  reinterpret_cast<i::HeapProfiler*>(heap_profiler)->allocation_tracker();
2381  CHECK_NE(NULL, tracker);
2382  // Resolve all function locations.
2383  tracker->PrepareForSerialization();
2384  // Print for better diagnostics in case of failure.
2385  tracker->trace_tree()->Print(tracker);
2386 
2387  AllocationTraceNode* node =
2388  FindNode(tracker, Vector<const char*>(names, ARRAY_SIZE(names)));
2389  CHECK_NE(NULL, node);
2390  CHECK_GE(node->allocation_count(), 2);
2391  CHECK_GE(node->allocation_size(), 4 * node->allocation_count());
2392  heap_profiler->StopTrackingHeapObjects();
2393 }
2394 
2395 
2396 TEST(ArrayBufferAndArrayBufferView) {
2397  LocalContext env;
2398  v8::HandleScope scope(env->GetIsolate());
2399  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
2400  CompileRun("arr1 = new Uint32Array(100);\n");
2401  const v8::HeapSnapshot* snapshot =
2402  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2403  CHECK(ValidateSnapshot(snapshot));
2404  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2405  const v8::HeapGraphNode* arr1_obj =
2406  GetProperty(global, v8::HeapGraphEdge::kProperty, "arr1");
2407  CHECK_NE(NULL, arr1_obj);
2408  const v8::HeapGraphNode* arr1_buffer =
2409  GetProperty(arr1_obj, v8::HeapGraphEdge::kInternal, "buffer");
2410  CHECK_NE(NULL, arr1_buffer);
2411  const v8::HeapGraphNode* first_view =
2412  GetProperty(arr1_buffer, v8::HeapGraphEdge::kWeak, "weak_first_view");
2413  CHECK_NE(NULL, first_view);
2414  const v8::HeapGraphNode* backing_store =
2415  GetProperty(arr1_buffer, v8::HeapGraphEdge::kInternal, "backing_store");
2416  CHECK_NE(NULL, backing_store);
2417  CHECK_EQ(400, static_cast<int>(backing_store->GetShallowSize()));
2418 }
2419 
2420 
2421 static int GetRetainersCount(const v8::HeapSnapshot* snapshot,
2422  const v8::HeapGraphNode* node) {
2423  int count = 0;
2424  for (int i = 0, l = snapshot->GetNodesCount(); i < l; ++i) {
2425  const v8::HeapGraphNode* parent = snapshot->GetNode(i);
2426  for (int j = 0, l2 = parent->GetChildrenCount(); j < l2; ++j) {
2427  if (parent->GetChild(j)->GetToNode() == node) {
2428  ++count;
2429  }
2430  }
2431  }
2432  return count;
2433 }
2434 
2435 
2436 TEST(ArrayBufferSharedBackingStore) {
2437  LocalContext env;
2438  v8::Isolate* isolate = env->GetIsolate();
2439  v8::HandleScope handle_scope(isolate);
2440  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2441 
2443  CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2444  CHECK(!ab->IsExternal());
2445  v8::ArrayBuffer::Contents ab_contents = ab->Externalize();
2446  CHECK(ab->IsExternal());
2447 
2448  CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2449  void* data = ab_contents.Data();
2450  ASSERT(data != NULL);
2452  v8::ArrayBuffer::New(isolate, data, ab_contents.ByteLength());
2453  CHECK(ab2->IsExternal());
2454  env->Global()->Set(v8_str("ab1"), ab);
2455  env->Global()->Set(v8_str("ab2"), ab2);
2456 
2457  v8::Handle<v8::Value> result = CompileRun("ab2.byteLength");
2458  CHECK_EQ(1024, result->Int32Value());
2459 
2460  const v8::HeapSnapshot* snapshot =
2461  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2462  CHECK(ValidateSnapshot(snapshot));
2463  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
2464  const v8::HeapGraphNode* ab1_node =
2465  GetProperty(global, v8::HeapGraphEdge::kProperty, "ab1");
2466  CHECK_NE(NULL, ab1_node);
2467  const v8::HeapGraphNode* ab1_data =
2468  GetProperty(ab1_node, v8::HeapGraphEdge::kInternal, "backing_store");
2469  CHECK_NE(NULL, ab1_data);
2470  const v8::HeapGraphNode* ab2_node =
2471  GetProperty(global, v8::HeapGraphEdge::kProperty, "ab2");
2472  CHECK_NE(NULL, ab2_node);
2473  const v8::HeapGraphNode* ab2_data =
2474  GetProperty(ab2_node, v8::HeapGraphEdge::kInternal, "backing_store");
2475  CHECK_NE(NULL, ab2_data);
2476  CHECK_EQ(ab1_data, ab2_data);
2477  CHECK_EQ(2, GetRetainersCount(snapshot, ab1_data));
2478  free(data);
2479 }
2480 
2481 
2482 TEST(BoxObject) {
2483  v8::Isolate* isolate = CcTest::isolate();
2484  v8::HandleScope scope(isolate);
2485  LocalContext env;
2486  v8::Handle<v8::Object> global_proxy = env->Global();
2487  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2488 
2489  i::Factory* factory = CcTest::i_isolate()->factory();
2490  i::Handle<i::String> string =
2491  factory->NewStringFromAscii(i::CStrVector("string"));
2492  i::Handle<i::Object> box = factory->NewBox(string);
2493  global->Set(0, v8::ToApiHandle<v8::Object>(box));
2494 
2495  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
2496  const v8::HeapSnapshot* snapshot =
2497  heap_profiler->TakeHeapSnapshot(v8_str("snapshot"));
2498  CHECK(ValidateSnapshot(snapshot));
2499  const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
2500  const v8::HeapGraphNode* box_node =
2501  GetProperty(global_node, v8::HeapGraphEdge::kElement, "0");
2502  CHECK_NE(NULL, box_node);
2503  v8::String::Utf8Value box_node_name(box_node->GetName());
2504  CHECK_EQ("system / Box", *box_node_name);
2505  const v8::HeapGraphNode* box_value =
2506  GetProperty(box_node, v8::HeapGraphEdge::kInternal, "value");
2507  CHECK_NE(NULL, box_value);
2508 }
2509 
2510 
2511 static inline i::Address ToAddress(int n) {
2512  return reinterpret_cast<i::Address>(n);
2513 }
2514 
2515 
2516 TEST(AddressToTraceMap) {
2518 
2519  CHECK_EQ(0, map.GetTraceNodeId(ToAddress(150)));
2520 
2521  // [0x100, 0x200) -> 1
2522  map.AddRange(ToAddress(0x100), 0x100, 1U);
2523  CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x50)));
2524  CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x100)));
2525  CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x150)));
2526  CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x100 + 0x100)));
2527  CHECK_EQ(1, static_cast<int>(map.size()));
2528 
2529  // [0x100, 0x200) -> 1, [0x200, 0x300) -> 2
2530  map.AddRange(ToAddress(0x200), 0x100, 2U);
2531  CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x2a0)));
2532  CHECK_EQ(2, static_cast<int>(map.size()));
2533 
2534  // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2
2535  map.AddRange(ToAddress(0x180), 0x100, 3U);
2536  CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
2537  CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
2538  CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
2539  CHECK_EQ(3, static_cast<int>(map.size()));
2540 
2541  // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2,
2542  // [0x400, 0x500) -> 4
2543  map.AddRange(ToAddress(0x400), 0x100, 4U);
2544  CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
2545  CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
2546  CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
2547  CHECK_EQ(4, map.GetTraceNodeId(ToAddress(0x450)));
2548  CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x500)));
2549  CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x350)));
2550  CHECK_EQ(4, static_cast<int>(map.size()));
2551 
2552  // [0x100, 0x180) -> 1, [0x180, 0x200) -> 3, [0x200, 0x600) -> 5
2553  map.AddRange(ToAddress(0x200), 0x400, 5U);
2554  CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
2555  CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x400)));
2556  CHECK_EQ(3, static_cast<int>(map.size()));
2557 
2558  // [0x100, 0x180) -> 1, [0x180, 0x200) -> 7, [0x200, 0x600) ->5
2559  map.AddRange(ToAddress(0x180), 0x80, 6U);
2560  map.AddRange(ToAddress(0x180), 0x80, 7U);
2561  CHECK_EQ(7, map.GetTraceNodeId(ToAddress(0x180)));
2562  CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
2563  CHECK_EQ(3, static_cast<int>(map.size()));
2564 
2565  map.Clear();
2566  CHECK_EQ(0, static_cast<int>(map.size()));
2567  CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x400)));
2568 }
byte * Address
Definition: globals.h:186
void DeleteAllHeapSnapshots()
Definition: api.cc:7391
static Isolate * GetCurrent()
Definition: api.cc:6580
const SwVfpRegister s2
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
double NumberValue() const
Definition: api.cc:2829
const HeapGraphEdge * GetChild(int index) const
Definition: api.cc:7260
V8_INLINE void SetWrapperClassId(uint16_t class_id)
Definition: v8.h:5896
#define CHECK_EQ(expected, value)
Definition: checks.h:252
void StopTrackingHeapObjects()
Definition: api.cc:7381
void SetWrapperClassInfoProvider(uint16_t class_id, WrapperInfoCallback callback)
Definition: api.cc:7396
const HeapGraphNode * GetFromNode() const
Definition: api.cc:7208
SnapshotObjectId GetObjectId(Handle< Value > value)
Definition: api.cc:7346
void CollectAllGarbage(int flags, const char *gc_reason=NULL, const GCCallbackFlags gc_callback_flags=kNoGCCallbackFlags)
Definition: heap.cc:731
Handle< Value > FindObjectById(SnapshotObjectId id)
Definition: api.cc:7352
void ClearObjectIds()
Definition: api.cc:7360
Local< Value > Get(Handle< Value > key)
Definition: api.cc:3139
virtual const char * GetName(v8::Handle< v8::Object > object)
void SetObjectGroupId(const Persistent< T > &object, UniqueId id)
Definition: v8.h:6596
#define CHECK_GT(a, b)
Definition: checks.h:260
Handle< Value > GetName() const
Definition: api.cc:7187
GraphWithImplicitRefs(LocalContext *env)
Handle< String > GetName() const
Definition: api.cc:7231
SnapshotObjectId GetId() const
Definition: api.cc:7238
Contents Externalize()
Definition: api.cc:5962
static void gcPrologue(v8::GCType type, v8::GCCallbackFlags flags)
const HeapGraphNode * GetNodeById(SnapshotObjectId id) const
Definition: api.cc:7300
const HeapGraphNode * GetNode(int index) const
Definition: api.cc:7311
#define CHECK_LT(a, b)
Definition: checks.h:262
#define ASSERT(condition)
Definition: checks.h:329
static i::Heap * heap()
Definition: cctest.h:106
unsigned short uint16_t
Definition: unicode.cc:46
size_t GetShallowSize() const
Definition: api.cc:7250
static Local< Integer > New(Isolate *isolate, int32_t value)
Definition: api.cc:6233
Type GetType() const
Definition: api.cc:7182
#define CHECK(condition)
Definition: checks.h:75
void AddRange(Address addr, int size, unsigned node_id)
Handle< Object > GetProperty(Handle< JSReceiver > obj, const char *name)
Definition: handles.cc:196
Factory * factory()
Definition: isolate.h:995
#define CHECK_GE(a, b)
Definition: checks.h:261
virtual ControlOption ReportProgressValue(int done, int total)=0
virtual bool IsEquivalent(v8::RetainedObjectInfo *other)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in name
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object size
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in only print modified registers Don t break for ASM_UNIMPLEMENTED_BREAK macros print stack trace when an illegal exception is thrown randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot testing_bool_flag testing_int_flag string flag tmp file in which to serialize heap Print the time it takes to lazily compile hydrogen code stubs concurrent_recompilation concurrent_sweeping Print usage including flags
static void AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type_filter=kGCTypeAll)
Definition: api.cc:6453
v8::Isolate * GetIsolate()
Definition: api.cc:5233
void SetInternalField(int index, Handle< Value > value)
Definition: api.cc:4911
int foo
SmartArrayPointer< char > ToCString(AllowNullsFlag allow_nulls, RobustnessFlag robustness_flag, int offset, int length, int *length_output=0)
Definition: objects.cc:8272
const SwVfpRegister s3
int InternalFieldCount()
Definition: api.cc:4887
int GetChildrenCount() const
Definition: api.cc:7255
T * start() const
Definition: utils.h:426
static Local< ObjectTemplate > New()
Definition: api.cc:1286
static int NumberOfHandles(Isolate *isolate)
Definition: handles.cc:48
static void MemCopy(void *dest, const void *src, size_t size)
Definition: platform.h:399
SnapshotObjectId GetMaxSnapshotJSObjectId() const
Definition: api.cc:7317
Local< Value > GetPrototype()
Definition: api.cc:3192
static String * GetConstructorName(JSObject *object)
void CollectAllAvailableGarbage(const char *gc_reason=NULL)
Definition: heap.cc:743
static const int kNoGCFlags
Definition: heap.h:1257
void SetInternalFieldCount(int value)
Definition: api.cc:1552
bool IsExternal() const
Definition: api.cc:5957
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf map
AsciiResource(const char *data, size_t length)
int32_t Int32Value() const
Definition: api.cc:2929
virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate *data, int count)
Definition: v8-profiler.h:305
static V8_INLINE Handle< T > Cast(Handle< S > that)
Definition: v8.h:297
Local< Object > Global()
Definition: api.cc:5239
static Local< ArrayBuffer > New(Isolate *isolate, size_t byte_length)
Definition: api.cc:5994
TEST(HeapSnapshot)
unsigned GetTraceNodeId(Address addr)
int length() const
Definition: utils.h:420
static i::Isolate * i_isolate()
Definition: cctest.h:102
List< HeapGraphEdge > & edges()
GCType
Definition: v8.h:4067
#define STRING_LITERAL_FOR_TEST
Definition: v8.h:123
static const int kObjectsCount
static Local< Array > New(Isolate *isolate, int length=0)
Definition: api.cc:5786
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long expose natives in global object expose freeBuffer extension expose gc extension under the specified name expose externalize string extension number of stack frames to capture disable builtin natives files print name of functions for which code is generated use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations always try to OSR functions trace optimize function deoptimization minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions trace debugging JSON request response trace out of bounds accesses to external arrays trace_js_array_abuse automatically set the debug break flag when debugger commands are in the queue abort by crashing maximum length of function source code printed in a stack trace max size of the new max size of the old max size of executable always perform global GCs print one trace line following each garbage collection do not print trace line after scavenger collection print statistics of the maximum memory committed for the heap in only print modified registers Don t break for ASM_UNIMPLEMENTED_BREAK macros print stack trace when an illegal exception is thrown randomize hashes to avoid predictable hash Fixed seed to use to hash property Print the time it takes to deserialize the snapshot testing_bool_flag testing_int_flag string flag tmp file in which to serialize heap Print the time it takes to lazily compile hydrogen code stubs concurrent_recompilation concurrent_sweeping Print usage including on console Map counters to a file Enable debugger compile events enable GDBJIT enable GDBJIT interface for all code objects dump only objects containing this substring stress the GC compactor to flush out pretty print source code print source AST function name where to insert a breakpoint print scopes for builtins trace contexts operations print stuff during garbage collection report code statistics after GC report handles after GC trace cache state transitions print interface inference details prints when objects are turned into dictionaries report heap spill statistics along with trace isolate state changes trace regexp bytecode execution Minimal Log all events to the log file Log API events to the log file Log heap samples on garbage collection for the hp2ps tool log positions Log suspect operations Used with turns on browser compatible mode for profiling v8 Specify the name of the log file Enable low level linux profiler Enable perf linux profiler(experimental annotate support).") DEFINE_string(gc_fake_mmap
static v8::internal::Handle< To > OpenHandle(v8::Local< From > handle)
Definition: api.h:308
#define CHECK_NE(unexpected, value)
Definition: checks.h:256
Vector< const char > CStrVector(const char *data)
Definition: utils.h:574
static Local< Object > New(Isolate *isolate)
Definition: api.cc:5589
static int SizeFor(int length)
Definition: objects.h:3067
SnapshotObjectId GetHeapStats(OutputStream *stream)
Definition: api.cc:7386
virtual intptr_t GetHash()
V8_INLINE bool IsString() const
Definition: v8.h:6265
const SwVfpRegister s1
bool IsObject() const
Definition: api.cc:2411
const HeapSnapshot * TakeHeapSnapshot(Handle< String > title, ActivityControl *control=NULL, ObjectNameResolver *global_object_name_resolver=NULL)
Definition: api.cc:7365
void SetReferenceFromGroup(UniqueId id, const Persistent< T > &child)
Definition: v8.h:6604
static int SNPrintF(Vector< char > str, const char *format,...)
virtual WriteResult WriteAsciiChunk(char *data, int size)=0
virtual size_t length() const =0
V8_INLINE Local< S > As()
Definition: v8.h:385
void SetReference(const Persistent< T > &parent, const Persistent< S > &child)
Definition: v8.h:6613
const HeapSnapshot * GetHeapSnapshot(int index)
Definition: api.cc:7340
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:103
V8_INLINE bool IsEmpty() const
Definition: v8.h:248
List< HeapEntry * > * GetSortedEntriesList()
uint32_t SnapshotObjectId
Definition: v8-profiler.h:39
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
void EnableInlineAllocation()
Definition: heap.cc:6529
int GetNodesCount() const
Definition: api.cc:7306
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function info
static Local< String > NewExternal(Isolate *isolate, ExternalStringResource *resource)
Definition: api.cc:5493
Local< Object > Clone()
Definition: api.cc:3611
virtual const char * data() const =0
V8_INLINE void Reset()
Definition: v8.h:5808
const HeapGraphNode * GetRoot() const
Definition: api.cc:7295
virtual const char * GetLabel()
TemplateHashMapImpl< FreeStoreAllocationPolicy > HashMap
Definition: hashmap.h:113
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric literals(0o77, 0b11)") DEFINE_bool(harmony_strings
virtual intptr_t GetElementCount()
Definition: v8-profiler.h:591
int GetSnapshotCount()
Definition: api.cc:7335
static void RemoveGCPrologueCallback(GCPrologueCallback callback)
Definition: api.cc:6462
void DisableInlineAllocation()
Definition: heap.cc:6538
void StartTrackingHeapObjects(bool track_allocations=false)
Definition: api.cc:7375
bool HasWeakEdge(const v8::HeapGraphNode *node)
GCCallbackFlags
Definition: v8.h:4073
Type GetType() const
Definition: api.cc:7226
Local< Object > ToObject() const
Definition: api.cc:2570
bool IsArray() const
Definition: api.cc:2374
HeapObject * obj
uint32_t Length() const
Definition: api.cc:5800
size_t ByteLength() const
Definition: api.cc:5988
virtual void EndOfStream()=0
#define CHECK_NE_SNAPSHOT_OBJECT_ID(a, b)
unsigned GetUid() const
Definition: api.cc:7283
#define CHECK_EQ_SNAPSHOT_OBJECT_ID(a, b)
V8_INLINE void SetWeak(P *parameter, typename WeakCallbackData< T, P >::Callback callback)
virtual intptr_t GetSizeInBytes()
Definition: v8-profiler.h:594
HeapProfiler * GetHeapProfiler()
Definition: api.cc:6339
const HeapGraphNode * GetToNode() const
Definition: api.cc:7214
bool HasWeakGlobalHandle()
#define ARRAY_SIZE(a)
Definition: globals.h:333
Definition: v8.h:124
void Serialize(OutputStream *stream, SerializationFormat format) const
Definition: api.cc:7322
virtual const char * GetGroupLabel()
Definition: v8-profiler.h:585
static const SnapshotObjectId kUnknownObjectId
Definition: v8-profiler.h:442
bool Set(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:3044
static v8::Isolate * isolate()
Definition: cctest.h:96
static Local< String > NewFromUtf8(Isolate *isolate, const char *data, NewStringType type=kNormalString, int length=-1)
Definition: api.cc:5417