v8  3.14.5(node0.10.28)
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 //
3 // Tests for heap profiler
4 
5 #include <ctype.h>
6 
7 #include "v8.h"
8 
9 #include "cctest.h"
10 #include "hashmap.h"
11 #include "heap-profiler.h"
12 #include "snapshot.h"
13 #include "debug.h"
14 #include "utils-inl.h"
15 #include "../include/v8-profiler.h"
16 
17 namespace {
18 
19 class NamedEntriesDetector {
20  public:
21  NamedEntriesDetector()
22  : has_A2(false), has_B2(false), has_C2(false) {
23  }
24 
25  void CheckEntry(i::HeapEntry* entry) {
26  if (strcmp(entry->name(), "A2") == 0) has_A2 = true;
27  if (strcmp(entry->name(), "B2") == 0) has_B2 = true;
28  if (strcmp(entry->name(), "C2") == 0) has_C2 = true;
29  }
30 
31  static bool AddressesMatch(void* key1, void* key2) {
32  return key1 == key2;
33  }
34 
35  void CheckAllReachables(i::HeapEntry* root) {
36  i::HashMap visited(AddressesMatch);
37  i::List<i::HeapEntry*> list(10);
38  list.Add(root);
39  CheckEntry(root);
40  while (!list.is_empty()) {
41  i::HeapEntry* entry = list.RemoveLast();
42  i::Vector<i::HeapGraphEdge*> children = entry->children();
43  for (int i = 0; i < children.length(); ++i) {
44  if (children[i]->type() == i::HeapGraphEdge::kShortcut) continue;
45  i::HeapEntry* child = children[i]->to();
46  i::HashMap::Entry* entry = visited.Lookup(
47  reinterpret_cast<void*>(child),
48  static_cast<uint32_t>(reinterpret_cast<uintptr_t>(child)),
49  true);
50  if (entry->value)
51  continue;
52  entry->value = reinterpret_cast<void*>(1);
53  list.Add(child);
54  CheckEntry(child);
55  }
56  }
57  }
58 
59  bool has_A2;
60  bool has_B2;
61  bool has_C2;
62 };
63 
64 } // namespace
65 
66 
67 static const v8::HeapGraphNode* GetGlobalObject(
68  const v8::HeapSnapshot* snapshot) {
69  CHECK_EQ(2, snapshot->GetRoot()->GetChildrenCount());
70  const v8::HeapGraphNode* global_obj =
71  snapshot->GetRoot()->GetChild(0)->GetToNode();
72  CHECK_EQ(0, strncmp("Object", const_cast<i::HeapEntry*>(
73  reinterpret_cast<const i::HeapEntry*>(global_obj))->name(), 6));
74  return global_obj;
75 }
76 
77 
78 static const v8::HeapGraphNode* GetProperty(const v8::HeapGraphNode* node,
80  const char* name) {
81  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
82  const v8::HeapGraphEdge* prop = node->GetChild(i);
83  v8::String::AsciiValue prop_name(prop->GetName());
84  if (prop->GetType() == type && strcmp(name, *prop_name) == 0)
85  return prop->GetToNode();
86  }
87  return NULL;
88 }
89 
90 
91 static bool HasString(const v8::HeapGraphNode* node, const char* contents) {
92  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
93  const v8::HeapGraphEdge* prop = node->GetChild(i);
94  const v8::HeapGraphNode* node = prop->GetToNode();
95  if (node->GetType() == v8::HeapGraphNode::kString) {
96  v8::String::AsciiValue node_name(node->GetName());
97  if (strcmp(contents, *node_name) == 0) return true;
98  }
99  }
100  return false;
101 }
102 
103 
104 TEST(HeapSnapshot) {
105  v8::HandleScope scope;
106  LocalContext env2;
107 
108  CompileRun(
109  "function A2() {}\n"
110  "function B2(x) { return function() { return typeof x; }; }\n"
111  "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n"
112  "var a2 = new A2();\n"
113  "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n"
114  "var c2 = new C2(a2);");
115  const v8::HeapSnapshot* snapshot_env2 =
116  v8::HeapProfiler::TakeSnapshot(v8_str("env2"));
117  const v8::HeapGraphNode* global_env2 = GetGlobalObject(snapshot_env2);
118 
119  // Verify, that JS global object of env2 has '..2' properties.
120  const v8::HeapGraphNode* a2_node =
121  GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "a2");
122  CHECK_NE(NULL, a2_node);
123  CHECK_NE(
124  NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_1"));
125  CHECK_NE(
126  NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "b2_2"));
127  CHECK_NE(NULL, GetProperty(global_env2, v8::HeapGraphEdge::kProperty, "c2"));
128 
129  NamedEntriesDetector det;
130  det.CheckAllReachables(const_cast<i::HeapEntry*>(
131  reinterpret_cast<const i::HeapEntry*>(global_env2)));
132  CHECK(det.has_A2);
133  CHECK(det.has_B2);
134  CHECK(det.has_C2);
135 }
136 
137 
138 TEST(HeapSnapshotObjectSizes) {
139  v8::HandleScope scope;
140  LocalContext env;
141 
142  // -a-> X1 --a
143  // x -b-> X2 <-|
144  CompileRun(
145  "function X(a, b) { this.a = a; this.b = b; }\n"
146  "x = new X(new X(), new X());\n"
147  "dummy = new X();\n"
148  "(function() { x.a.a = x.b; })();");
149  const v8::HeapSnapshot* snapshot =
150  v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
151  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
152  const v8::HeapGraphNode* x =
153  GetProperty(global, v8::HeapGraphEdge::kProperty, "x");
154  CHECK_NE(NULL, x);
155  const v8::HeapGraphNode* x1 =
156  GetProperty(x, v8::HeapGraphEdge::kProperty, "a");
157  CHECK_NE(NULL, x1);
158  const v8::HeapGraphNode* x2 =
159  GetProperty(x, v8::HeapGraphEdge::kProperty, "b");
160  CHECK_NE(NULL, x2);
161 
162  // Test sizes.
163  CHECK_NE(0, x->GetSelfSize());
164  CHECK_NE(0, x1->GetSelfSize());
165  CHECK_NE(0, x2->GetSelfSize());
166 }
167 
168 
169 TEST(BoundFunctionInSnapshot) {
170  v8::HandleScope scope;
171  LocalContext env;
172  CompileRun(
173  "function myFunction(a, b) { this.a = a; this.b = b; }\n"
174  "function AAAAA() {}\n"
175  "boundFunction = myFunction.bind(new AAAAA(), 20, new Number(12)); \n");
176  const v8::HeapSnapshot* snapshot =
177  v8::HeapProfiler::TakeSnapshot(v8_str("sizes"));
178  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
179  const v8::HeapGraphNode* f =
180  GetProperty(global, v8::HeapGraphEdge::kProperty, "boundFunction");
181  CHECK(f);
182  CHECK_EQ(v8::String::New("native_bind"), f->GetName());
183  const v8::HeapGraphNode* bindings =
184  GetProperty(f, v8::HeapGraphEdge::kInternal, "bindings");
185  CHECK_NE(NULL, bindings);
186  CHECK_EQ(v8::HeapGraphNode::kArray, bindings->GetType());
187  CHECK_EQ(4, bindings->GetChildrenCount());
188 
189  const v8::HeapGraphNode* bound_this = GetProperty(
190  f, v8::HeapGraphEdge::kShortcut, "bound_this");
191  CHECK(bound_this);
192  CHECK_EQ(v8::HeapGraphNode::kObject, bound_this->GetType());
193 
194  const v8::HeapGraphNode* bound_function = GetProperty(
195  f, v8::HeapGraphEdge::kShortcut, "bound_function");
196  CHECK(bound_function);
197  CHECK_EQ(v8::HeapGraphNode::kClosure, bound_function->GetType());
198 
199  const v8::HeapGraphNode* bound_argument = GetProperty(
200  f, v8::HeapGraphEdge::kShortcut, "bound_argument_1");
201  CHECK(bound_argument);
202  CHECK_EQ(v8::HeapGraphNode::kObject, bound_argument->GetType());
203 }
204 
205 
206 TEST(HeapSnapshotEntryChildren) {
207  v8::HandleScope scope;
208  LocalContext env;
209 
210  CompileRun(
211  "function A() { }\n"
212  "a = new A;");
213  const v8::HeapSnapshot* snapshot =
214  v8::HeapProfiler::TakeSnapshot(v8_str("children"));
215  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
216  for (int i = 0, count = global->GetChildrenCount(); i < count; ++i) {
217  const v8::HeapGraphEdge* prop = global->GetChild(i);
218  CHECK_EQ(global, prop->GetFromNode());
219  }
220  const v8::HeapGraphNode* a =
221  GetProperty(global, v8::HeapGraphEdge::kProperty, "a");
222  CHECK_NE(NULL, a);
223  for (int i = 0, count = a->GetChildrenCount(); i < count; ++i) {
224  const v8::HeapGraphEdge* prop = a->GetChild(i);
225  CHECK_EQ(a, prop->GetFromNode());
226  }
227 }
228 
229 
230 TEST(HeapSnapshotCodeObjects) {
231  v8::HandleScope scope;
232  LocalContext env;
233 
234  CompileRun(
235  "function lazy(x) { return x - 1; }\n"
236  "function compiled(x) { return x + 1; }\n"
237  "var anonymous = (function() { return function() { return 0; } })();\n"
238  "compiled(1)");
239  const v8::HeapSnapshot* snapshot =
240  v8::HeapProfiler::TakeSnapshot(v8_str("code"));
241 
242  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
243  const v8::HeapGraphNode* compiled =
244  GetProperty(global, v8::HeapGraphEdge::kProperty, "compiled");
245  CHECK_NE(NULL, compiled);
247  const v8::HeapGraphNode* lazy =
248  GetProperty(global, v8::HeapGraphEdge::kProperty, "lazy");
249  CHECK_NE(NULL, lazy);
250  CHECK_EQ(v8::HeapGraphNode::kClosure, lazy->GetType());
251  const v8::HeapGraphNode* anonymous =
252  GetProperty(global, v8::HeapGraphEdge::kProperty, "anonymous");
253  CHECK_NE(NULL, anonymous);
254  CHECK_EQ(v8::HeapGraphNode::kClosure, anonymous->GetType());
255  v8::String::AsciiValue anonymous_name(anonymous->GetName());
256  CHECK_EQ("", *anonymous_name);
257 
258  // Find references to code.
259  const v8::HeapGraphNode* compiled_code =
260  GetProperty(compiled, v8::HeapGraphEdge::kInternal, "shared");
261  CHECK_NE(NULL, compiled_code);
262  const v8::HeapGraphNode* lazy_code =
263  GetProperty(lazy, v8::HeapGraphEdge::kInternal, "shared");
264  CHECK_NE(NULL, lazy_code);
265 
266  // Verify that non-compiled code doesn't contain references to "x"
267  // literal, while compiled code does. The scope info is stored in FixedArray
268  // objects attached to the SharedFunctionInfo.
269  bool compiled_references_x = false, lazy_references_x = false;
270  for (int i = 0, count = compiled_code->GetChildrenCount(); i < count; ++i) {
271  const v8::HeapGraphEdge* prop = compiled_code->GetChild(i);
272  const v8::HeapGraphNode* node = prop->GetToNode();
273  if (node->GetType() == v8::HeapGraphNode::kArray) {
274  if (HasString(node, "x")) {
275  compiled_references_x = true;
276  break;
277  }
278  }
279  }
280  for (int i = 0, count = lazy_code->GetChildrenCount(); i < count; ++i) {
281  const v8::HeapGraphEdge* prop = lazy_code->GetChild(i);
282  const v8::HeapGraphNode* node = prop->GetToNode();
283  if (node->GetType() == v8::HeapGraphNode::kArray) {
284  if (HasString(node, "x")) {
285  lazy_references_x = true;
286  break;
287  }
288  }
289  }
290  CHECK(compiled_references_x);
291  CHECK(!lazy_references_x);
292 }
293 
294 
295 TEST(HeapSnapshotHeapNumbers) {
296  v8::HandleScope scope;
297  LocalContext env;
298  CompileRun(
299  "a = 1; // a is Smi\n"
300  "b = 2.5; // b is HeapNumber");
301  const v8::HeapSnapshot* snapshot =
302  v8::HeapProfiler::TakeSnapshot(v8_str("numbers"));
303  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
304  CHECK_EQ(NULL, GetProperty(global, v8::HeapGraphEdge::kProperty, "a"));
305  const v8::HeapGraphNode* b =
306  GetProperty(global, v8::HeapGraphEdge::kProperty, "b");
307  CHECK_NE(NULL, b);
309 }
310 
311 TEST(HeapSnapshotSlicedString) {
312  v8::HandleScope scope;
313  LocalContext env;
314  CompileRun(
315  "parent_string = \"123456789.123456789.123456789.123456789.123456789."
316  "123456789.123456789.123456789.123456789.123456789."
317  "123456789.123456789.123456789.123456789.123456789."
318  "123456789.123456789.123456789.123456789.123456789.\";"
319  "child_string = parent_string.slice(100);");
320  const v8::HeapSnapshot* snapshot =
321  v8::HeapProfiler::TakeSnapshot(v8_str("strings"));
322  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
323  const v8::HeapGraphNode* parent_string =
324  GetProperty(global, v8::HeapGraphEdge::kProperty, "parent_string");
325  CHECK_NE(NULL, parent_string);
326  const v8::HeapGraphNode* child_string =
327  GetProperty(global, v8::HeapGraphEdge::kProperty, "child_string");
328  CHECK_NE(NULL, child_string);
329  const v8::HeapGraphNode* parent =
330  GetProperty(child_string, v8::HeapGraphEdge::kInternal, "parent");
331  CHECK_EQ(parent_string, parent);
332 }
333 
334 TEST(HeapSnapshotInternalReferences) {
335  v8::HandleScope scope;
337  global_template->SetInternalFieldCount(2);
338  LocalContext env(NULL, global_template);
339  v8::Handle<v8::Object> global_proxy = env->Global();
340  v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
341  CHECK_EQ(2, global->InternalFieldCount());
343  global->SetInternalField(0, v8_num(17));
344  global->SetInternalField(1, obj);
345  const v8::HeapSnapshot* snapshot =
346  v8::HeapProfiler::TakeSnapshot(v8_str("internals"));
347  const v8::HeapGraphNode* global_node = GetGlobalObject(snapshot);
348  // The first reference will not present, because it's a Smi.
349  CHECK_EQ(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "0"));
350  // The second reference is to an object.
351  CHECK_NE(NULL, GetProperty(global_node, v8::HeapGraphEdge::kInternal, "1"));
352 }
353 
354 
355 // Trying to introduce a check helper for uint32_t causes many
356 // overloading ambiguities, so it seems easier just to cast
357 // them to a signed type.
358 #define CHECK_EQ_SNAPSHOT_OBJECT_ID(a, b) \
359  CHECK_EQ(static_cast<int32_t>(a), static_cast<int32_t>(b))
360 #define CHECK_NE_SNAPSHOT_OBJECT_ID(a, b) \
361  CHECK((a) != (b)) // NOLINT
362 
363 TEST(HeapEntryIdsAndArrayShift) {
364  v8::HandleScope scope;
365  LocalContext env;
366 
367  CompileRun(
368  "function AnObject() {\n"
369  " this.first = 'first';\n"
370  " this.second = 'second';\n"
371  "}\n"
372  "var a = new Array();\n"
373  "for (var i = 0; i < 10; ++i)\n"
374  " a.push(new AnObject());\n");
375  const v8::HeapSnapshot* snapshot1 =
376  v8::HeapProfiler::TakeSnapshot(v8_str("s1"));
377 
378  CompileRun(
379  "for (var i = 0; i < 1; ++i)\n"
380  " a.shift();\n");
381 
382  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
383 
384  const v8::HeapSnapshot* snapshot2 =
385  v8::HeapProfiler::TakeSnapshot(v8_str("s2"));
386 
387  const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
388  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
389  CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId());
390  CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId());
391 
392  const v8::HeapGraphNode* a1 =
393  GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
394  CHECK_NE(NULL, a1);
395  const v8::HeapGraphNode* k1 =
396  GetProperty(a1, v8::HeapGraphEdge::kInternal, "elements");
397  CHECK_NE(NULL, k1);
398  const v8::HeapGraphNode* a2 =
399  GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
400  CHECK_NE(NULL, a2);
401  const v8::HeapGraphNode* k2 =
402  GetProperty(a2, v8::HeapGraphEdge::kInternal, "elements");
403  CHECK_NE(NULL, k2);
404 
405  CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId());
407 }
408 
409 TEST(HeapEntryIdsAndGC) {
410  v8::HandleScope scope;
411  LocalContext env;
412 
413  CompileRun(
414  "function A() {}\n"
415  "function B(x) { this.x = x; }\n"
416  "var a = new A();\n"
417  "var b = new B(a);");
418  v8::Local<v8::String> s1_str = v8_str("s1");
419  v8::Local<v8::String> s2_str = v8_str("s2");
420  const v8::HeapSnapshot* snapshot1 =
422 
423  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
424 
425  const v8::HeapSnapshot* snapshot2 =
427 
428  CHECK_GT(snapshot1->GetMaxSnapshotJSObjectId(), 7000);
429  CHECK(snapshot1->GetMaxSnapshotJSObjectId() <=
430  snapshot2->GetMaxSnapshotJSObjectId());
431 
432  const v8::HeapGraphNode* global1 = GetGlobalObject(snapshot1);
433  const v8::HeapGraphNode* global2 = GetGlobalObject(snapshot2);
434  CHECK_NE_SNAPSHOT_OBJECT_ID(0, global1->GetId());
435  CHECK_EQ_SNAPSHOT_OBJECT_ID(global1->GetId(), global2->GetId());
436  const v8::HeapGraphNode* A1 =
437  GetProperty(global1, v8::HeapGraphEdge::kProperty, "A");
438  CHECK_NE(NULL, A1);
439  const v8::HeapGraphNode* A2 =
440  GetProperty(global2, v8::HeapGraphEdge::kProperty, "A");
441  CHECK_NE(NULL, A2);
442  CHECK_NE_SNAPSHOT_OBJECT_ID(0, A1->GetId());
443  CHECK_EQ_SNAPSHOT_OBJECT_ID(A1->GetId(), A2->GetId());
444  const v8::HeapGraphNode* B1 =
445  GetProperty(global1, v8::HeapGraphEdge::kProperty, "B");
446  CHECK_NE(NULL, B1);
447  const v8::HeapGraphNode* B2 =
448  GetProperty(global2, v8::HeapGraphEdge::kProperty, "B");
449  CHECK_NE(NULL, B2);
450  CHECK_NE_SNAPSHOT_OBJECT_ID(0, B1->GetId());
451  CHECK_EQ_SNAPSHOT_OBJECT_ID(B1->GetId(), B2->GetId());
452  const v8::HeapGraphNode* a1 =
453  GetProperty(global1, v8::HeapGraphEdge::kProperty, "a");
454  CHECK_NE(NULL, a1);
455  const v8::HeapGraphNode* a2 =
456  GetProperty(global2, v8::HeapGraphEdge::kProperty, "a");
457  CHECK_NE(NULL, a2);
458  CHECK_NE_SNAPSHOT_OBJECT_ID(0, a1->GetId());
459  CHECK_EQ_SNAPSHOT_OBJECT_ID(a1->GetId(), a2->GetId());
460  const v8::HeapGraphNode* b1 =
461  GetProperty(global1, v8::HeapGraphEdge::kProperty, "b");
462  CHECK_NE(NULL, b1);
463  const v8::HeapGraphNode* b2 =
464  GetProperty(global2, v8::HeapGraphEdge::kProperty, "b");
465  CHECK_NE(NULL, b2);
466  CHECK_NE_SNAPSHOT_OBJECT_ID(0, b1->GetId());
467  CHECK_EQ_SNAPSHOT_OBJECT_ID(b1->GetId(), b2->GetId());
468 }
469 
470 
471 TEST(HeapSnapshotRootPreservedAfterSorting) {
472  v8::HandleScope scope;
473  LocalContext env;
474  const v8::HeapSnapshot* snapshot =
475  v8::HeapProfiler::TakeSnapshot(v8_str("s"));
476  const v8::HeapGraphNode* root1 = snapshot->GetRoot();
477  const_cast<i::HeapSnapshot*>(reinterpret_cast<const i::HeapSnapshot*>(
479  const v8::HeapGraphNode* root2 = snapshot->GetRoot();
480  CHECK_EQ(root1, root2);
481 }
482 
483 
484 namespace {
485 
486 class TestJSONStream : public v8::OutputStream {
487  public:
488  TestJSONStream() : eos_signaled_(0), abort_countdown_(-1) {}
489  explicit TestJSONStream(int abort_countdown)
490  : eos_signaled_(0), abort_countdown_(abort_countdown) {}
491  virtual ~TestJSONStream() {}
492  virtual void EndOfStream() { ++eos_signaled_; }
493  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
494  if (abort_countdown_ > 0) --abort_countdown_;
495  if (abort_countdown_ == 0) return kAbort;
496  CHECK_GT(chars_written, 0);
497  i::Vector<char> chunk = buffer_.AddBlock(chars_written, '\0');
498  memcpy(chunk.start(), buffer, chars_written);
499  return kContinue;
500  }
501  virtual WriteResult WriteUint32Chunk(uint32_t* buffer, int chars_written) {
502  ASSERT(false);
503  return kAbort;
504  }
505  void WriteTo(i::Vector<char> dest) { buffer_.WriteTo(dest); }
506  int eos_signaled() { return eos_signaled_; }
507  int size() { return buffer_.size(); }
508 
509  private:
511  int eos_signaled_;
512  int abort_countdown_;
513 };
514 
515 class AsciiResource: public v8::String::ExternalAsciiStringResource {
516  public:
517  explicit AsciiResource(i::Vector<char> string): data_(string.start()) {
518  length_ = string.length();
519  }
520  virtual const char* data() const { return data_; }
521  virtual size_t length() const { return length_; }
522  private:
523  const char* data_;
524  size_t length_;
525 };
526 
527 } // namespace
528 
529 TEST(HeapSnapshotJSONSerialization) {
530  v8::HandleScope scope;
531  LocalContext env;
532 
533 #define STRING_LITERAL_FOR_TEST \
534  "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
535  CompileRun(
536  "function A(s) { this.s = s; }\n"
537  "function B(x) { this.x = x; }\n"
538  "var a = new A(" STRING_LITERAL_FOR_TEST ");\n"
539  "var b = new B(a);");
540  const v8::HeapSnapshot* snapshot =
541  v8::HeapProfiler::TakeSnapshot(v8_str("json"));
542  TestJSONStream stream;
543  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
544  CHECK_GT(stream.size(), 0);
545  CHECK_EQ(1, stream.eos_signaled());
546  i::ScopedVector<char> json(stream.size());
547  stream.WriteTo(json);
548 
549  // Verify that snapshot string is valid JSON.
550  AsciiResource json_res(json);
551  v8::Local<v8::String> json_string = v8::String::NewExternal(&json_res);
552  env->Global()->Set(v8_str("json_snapshot"), json_string);
553  v8::Local<v8::Value> snapshot_parse_result = CompileRun(
554  "var parsed = JSON.parse(json_snapshot); true;");
555  CHECK(!snapshot_parse_result.IsEmpty());
556 
557  // Verify that snapshot object has required fields.
558  v8::Local<v8::Object> parsed_snapshot =
559  env->Global()->Get(v8_str("parsed"))->ToObject();
560  CHECK(parsed_snapshot->Has(v8_str("snapshot")));
561  CHECK(parsed_snapshot->Has(v8_str("nodes")));
562  CHECK(parsed_snapshot->Has(v8_str("edges")));
563  CHECK(parsed_snapshot->Has(v8_str("strings")));
564 
565  // Get node and edge "member" offsets.
566  v8::Local<v8::Value> meta_analysis_result = CompileRun(
567  "var meta = parsed.snapshot.meta;\n"
568  "var edge_count_offset = meta.node_fields.indexOf('edge_count');\n"
569  "var node_fields_count = meta.node_fields.length;\n"
570  "var edge_fields_count = meta.edge_fields.length;\n"
571  "var edge_type_offset = meta.edge_fields.indexOf('type');\n"
572  "var edge_name_offset = meta.edge_fields.indexOf('name_or_index');\n"
573  "var edge_to_node_offset = meta.edge_fields.indexOf('to_node');\n"
574  "var property_type ="
575  " meta.edge_types[edge_type_offset].indexOf('property');\n"
576  "var shortcut_type ="
577  " meta.edge_types[edge_type_offset].indexOf('shortcut');\n"
578  "var node_count = parsed.nodes.length / node_fields_count;\n"
579  "var first_edge_indexes = parsed.first_edge_indexes = [];\n"
580  "for (var i = 0, first_edge_index = 0; i < node_count; ++i) {\n"
581  " first_edge_indexes[i] = first_edge_index;\n"
582  " first_edge_index += edge_fields_count *\n"
583  " parsed.nodes[i * node_fields_count + edge_count_offset];\n"
584  "}\n");
585  CHECK(!meta_analysis_result.IsEmpty());
586 
587  // A helper function for processing encoded nodes.
588  CompileRun(
589  "function GetChildPosByProperty(pos, prop_name, prop_type) {\n"
590  " var nodes = parsed.nodes;\n"
591  " var edges = parsed.edges;\n"
592  " var strings = parsed.strings;\n"
593  " var node_ordinal = pos / node_fields_count;\n"
594  " for (var i = parsed.first_edge_indexes[node_ordinal],\n"
595  " count = parsed.first_edge_indexes[node_ordinal + 1];\n"
596  " i < count; i += edge_fields_count) {\n"
597  " if (edges[i + edge_type_offset] === prop_type\n"
598  " && strings[edges[i + edge_name_offset]] === prop_name)\n"
599  " return edges[i + edge_to_node_offset];\n"
600  " }\n"
601  " return null;\n"
602  "}\n");
603  // Get the string index using the path: <root> -> <global>.b.x.s
604  v8::Local<v8::Value> string_obj_pos_val = CompileRun(
605  "GetChildPosByProperty(\n"
606  " GetChildPosByProperty(\n"
607  " GetChildPosByProperty("
608  " parsed.edges[edge_to_node_offset],"
609  " \"b\", property_type),\n"
610  " \"x\", property_type),"
611  " \"s\", property_type)");
612  CHECK(!string_obj_pos_val.IsEmpty());
613  int string_obj_pos =
614  static_cast<int>(string_obj_pos_val->ToNumber()->Value());
615  v8::Local<v8::Object> nodes_array =
616  parsed_snapshot->Get(v8_str("nodes"))->ToObject();
617  int string_index = static_cast<int>(
618  nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
619  CHECK_GT(string_index, 0);
620  v8::Local<v8::Object> strings_array =
621  parsed_snapshot->Get(v8_str("strings"))->ToObject();
622  v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
623  v8::Local<v8::String> ref_string =
624  CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
625 #undef STRING_LITERAL_FOR_TEST
626  CHECK_EQ(*v8::String::Utf8Value(ref_string),
627  *v8::String::Utf8Value(string));
628 }
629 
630 
631 TEST(HeapSnapshotJSONSerializationAborting) {
632  v8::HandleScope scope;
633  LocalContext env;
634  const v8::HeapSnapshot* snapshot =
635  v8::HeapProfiler::TakeSnapshot(v8_str("abort"));
636  TestJSONStream stream(5);
637  snapshot->Serialize(&stream, v8::HeapSnapshot::kJSON);
638  CHECK_GT(stream.size(), 0);
639  CHECK_EQ(0, stream.eos_signaled());
640 }
641 
642 namespace {
643 
644 class TestStatsStream : public v8::OutputStream {
645  public:
646  TestStatsStream()
647  : eos_signaled_(0),
648  updates_written_(0),
649  entries_count_(0),
650  entries_size_(0),
651  intervals_count_(0),
652  first_interval_index_(-1) { }
653  TestStatsStream(const TestStatsStream& stream)
654  : v8::OutputStream(stream),
655  eos_signaled_(stream.eos_signaled_),
656  updates_written_(stream.updates_written_),
657  entries_count_(stream.entries_count_),
658  entries_size_(stream.entries_size_),
659  intervals_count_(stream.intervals_count_),
660  first_interval_index_(stream.first_interval_index_) { }
661  virtual ~TestStatsStream() {}
662  virtual void EndOfStream() { ++eos_signaled_; }
663  virtual WriteResult WriteAsciiChunk(char* buffer, int chars_written) {
664  ASSERT(false);
665  return kAbort;
666  }
667  virtual WriteResult WriteHeapStatsChunk(v8::HeapStatsUpdate* buffer,
668  int updates_written) {
669  ++intervals_count_;
670  ASSERT(updates_written);
671  updates_written_ += updates_written;
672  entries_count_ = 0;
673  if (first_interval_index_ == -1 && updates_written != 0)
674  first_interval_index_ = buffer[0].index;
675  for (int i = 0; i < updates_written; ++i) {
676  entries_count_ += buffer[i].count;
677  entries_size_ += buffer[i].size;
678  }
679 
680  return kContinue;
681  }
682  int eos_signaled() { return eos_signaled_; }
683  int updates_written() { return updates_written_; }
684  uint32_t entries_count() const { return entries_count_; }
685  uint32_t entries_size() const { return entries_size_; }
686  int intervals_count() const { return intervals_count_; }
687  int first_interval_index() const { return first_interval_index_; }
688 
689  private:
690  int eos_signaled_;
691  int updates_written_;
692  uint32_t entries_count_;
693  uint32_t entries_size_;
694  int intervals_count_;
695  int first_interval_index_;
696 };
697 
698 } // namespace
699 
700 static TestStatsStream GetHeapStatsUpdate(
701  v8::SnapshotObjectId* object_id = NULL) {
702  TestStatsStream stream;
703  v8::SnapshotObjectId last_seen_id =
705  if (object_id)
706  *object_id = last_seen_id;
707  CHECK_EQ(1, stream.eos_signaled());
708  return stream;
709 }
710 
711 
712 TEST(HeapSnapshotObjectsStats) {
713  v8::HandleScope scope;
714  LocalContext env;
715 
717  // We have to call GC 6 times. In other case the garbage will be
718  // the reason of flakiness.
719  for (int i = 0; i < 6; ++i) {
720  HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
721  }
722 
723  v8::SnapshotObjectId initial_id;
724  {
725  // Single chunk of data expected in update. Initial data.
726  TestStatsStream stats_update = GetHeapStatsUpdate(&initial_id);
727  CHECK_EQ(1, stats_update.intervals_count());
728  CHECK_EQ(1, stats_update.updates_written());
729  CHECK_LT(0, stats_update.entries_size());
730  CHECK_EQ(0, stats_update.first_interval_index());
731  }
732 
733  // No data expected in update because nothing has happened.
734  v8::SnapshotObjectId same_id;
735  CHECK_EQ(0, GetHeapStatsUpdate(&same_id).updates_written());
736  CHECK_EQ_SNAPSHOT_OBJECT_ID(initial_id, same_id);
737 
738  {
739  v8::SnapshotObjectId additional_string_id;
740  v8::HandleScope inner_scope_1;
741  v8_str("string1");
742  {
743  // Single chunk of data with one new entry expected in update.
744  TestStatsStream stats_update = GetHeapStatsUpdate(&additional_string_id);
745  CHECK_LT(same_id, additional_string_id);
746  CHECK_EQ(1, stats_update.intervals_count());
747  CHECK_EQ(1, stats_update.updates_written());
748  CHECK_LT(0, stats_update.entries_size());
749  CHECK_EQ(1, stats_update.entries_count());
750  CHECK_EQ(2, stats_update.first_interval_index());
751  }
752 
753  // No data expected in update because nothing happened.
754  v8::SnapshotObjectId last_id;
755  CHECK_EQ(0, GetHeapStatsUpdate(&last_id).updates_written());
756  CHECK_EQ_SNAPSHOT_OBJECT_ID(additional_string_id, last_id);
757 
758  {
759  v8::HandleScope inner_scope_2;
760  v8_str("string2");
761 
762  uint32_t entries_size;
763  {
764  v8::HandleScope inner_scope_3;
765  v8_str("string3");
766  v8_str("string4");
767 
768  {
769  // Single chunk of data with three new entries expected in update.
770  TestStatsStream stats_update = GetHeapStatsUpdate();
771  CHECK_EQ(1, stats_update.intervals_count());
772  CHECK_EQ(1, stats_update.updates_written());
773  CHECK_LT(0, entries_size = stats_update.entries_size());
774  CHECK_EQ(3, stats_update.entries_count());
775  CHECK_EQ(4, stats_update.first_interval_index());
776  }
777  }
778 
779  {
780  // Single chunk of data with two left entries expected in update.
781  TestStatsStream stats_update = GetHeapStatsUpdate();
782  CHECK_EQ(1, stats_update.intervals_count());
783  CHECK_EQ(1, stats_update.updates_written());
784  CHECK_GT(entries_size, stats_update.entries_size());
785  CHECK_EQ(1, stats_update.entries_count());
786  // Two strings from forth interval were released.
787  CHECK_EQ(4, stats_update.first_interval_index());
788  }
789  }
790 
791  {
792  // Single chunk of data with 0 left entries expected in update.
793  TestStatsStream stats_update = GetHeapStatsUpdate();
794  CHECK_EQ(1, stats_update.intervals_count());
795  CHECK_EQ(1, stats_update.updates_written());
796  CHECK_EQ(0, stats_update.entries_size());
797  CHECK_EQ(0, stats_update.entries_count());
798  // The last string from forth interval was released.
799  CHECK_EQ(4, stats_update.first_interval_index());
800  }
801  }
802  {
803  // Single chunk of data with 0 left entries expected in update.
804  TestStatsStream stats_update = GetHeapStatsUpdate();
805  CHECK_EQ(1, stats_update.intervals_count());
806  CHECK_EQ(1, stats_update.updates_written());
807  CHECK_EQ(0, stats_update.entries_size());
808  CHECK_EQ(0, stats_update.entries_count());
809  // The only string from the second interval was released.
810  CHECK_EQ(2, stats_update.first_interval_index());
811  }
812 
814  CHECK_EQ(0, array->Length());
815  // Force array's buffer allocation.
816  array->Set(2, v8_num(7));
817 
818  uint32_t entries_size;
819  {
820  // Single chunk of data with 2 entries expected in update.
821  TestStatsStream stats_update = GetHeapStatsUpdate();
822  CHECK_EQ(1, stats_update.intervals_count());
823  CHECK_EQ(1, stats_update.updates_written());
824  CHECK_LT(0, entries_size = stats_update.entries_size());
825  // They are the array and its buffer.
826  CHECK_EQ(2, stats_update.entries_count());
827  CHECK_EQ(8, stats_update.first_interval_index());
828  }
829 
830  for (int i = 0; i < 100; ++i)
831  array->Set(i, v8_num(i));
832 
833  {
834  // Single chunk of data with 1 entry expected in update.
835  TestStatsStream stats_update = GetHeapStatsUpdate();
836  CHECK_EQ(1, stats_update.intervals_count());
837  // The first interval was changed because old buffer was collected.
838  // The second interval was changed because new buffer was allocated.
839  CHECK_EQ(2, stats_update.updates_written());
840  CHECK_LT(entries_size, stats_update.entries_size());
841  CHECK_EQ(2, stats_update.entries_count());
842  CHECK_EQ(8, stats_update.first_interval_index());
843  }
844 
846 }
847 
848 
849 static void CheckChildrenIds(const v8::HeapSnapshot* snapshot,
850  const v8::HeapGraphNode* node,
851  int level, int max_level) {
852  if (level > max_level) return;
853  CHECK_EQ(node, snapshot->GetNodeById(node->GetId()));
854  for (int i = 0, count = node->GetChildrenCount(); i < count; ++i) {
855  const v8::HeapGraphEdge* prop = node->GetChild(i);
856  const v8::HeapGraphNode* child =
857  snapshot->GetNodeById(prop->GetToNode()->GetId());
858  CHECK_EQ_SNAPSHOT_OBJECT_ID(prop->GetToNode()->GetId(), child->GetId());
859  CHECK_EQ(prop->GetToNode(), child);
860  CheckChildrenIds(snapshot, child, level + 1, max_level);
861  }
862 }
863 
864 
865 TEST(HeapSnapshotGetNodeById) {
866  v8::HandleScope scope;
867  LocalContext env;
868 
869  const v8::HeapSnapshot* snapshot =
870  v8::HeapProfiler::TakeSnapshot(v8_str("id"));
871  const v8::HeapGraphNode* root = snapshot->GetRoot();
872  CheckChildrenIds(snapshot, root, 0, 3);
873  // Check a big id, which should not exist yet.
874  CHECK_EQ(NULL, snapshot->GetNodeById(0x1000000UL));
875 }
876 
877 
878 TEST(HeapSnapshotGetSnapshotObjectId) {
879  v8::HandleScope scope;
880  LocalContext env;
881  CompileRun("globalObject = {};\n");
882  const v8::HeapSnapshot* snapshot =
883  v8::HeapProfiler::TakeSnapshot(v8_str("get_snapshot_object_id"));
884  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
885  const v8::HeapGraphNode* global_object =
886  GetProperty(global, v8::HeapGraphEdge::kProperty, "globalObject");
887  CHECK(global_object);
888 
889  v8::Local<v8::Value> globalObjectHandle =
890  env->Global()->Get(v8::String::New("globalObject"));
891  CHECK(!globalObjectHandle.IsEmpty());
892  CHECK(globalObjectHandle->IsObject());
893 
895  v8::HeapProfiler::GetSnapshotObjectId(globalObjectHandle);
897  id);
898  CHECK_EQ(static_cast<int>(id), global_object->GetId());
899 }
900 
901 
902 TEST(HeapSnapshotUnknownSnapshotObjectId) {
903  v8::HandleScope scope;
904  LocalContext env;
905  CompileRun("globalObject = {};\n");
906  const v8::HeapSnapshot* snapshot =
907  v8::HeapProfiler::TakeSnapshot(v8_str("unknown_object_id"));
908  const v8::HeapGraphNode* node =
910  CHECK_EQ(NULL, node);
911 }
912 
913 
914 namespace {
915 
916 class TestActivityControl : public v8::ActivityControl {
917  public:
918  explicit TestActivityControl(int abort_count)
919  : done_(0), total_(0), abort_count_(abort_count) {}
920  ControlOption ReportProgressValue(int done, int total) {
921  done_ = done;
922  total_ = total;
923  return --abort_count_ != 0 ? kContinue : kAbort;
924  }
925  int done() { return done_; }
926  int total() { return total_; }
927 
928  private:
929  int done_;
930  int total_;
931  int abort_count_;
932 };
933 }
934 
935 TEST(TakeHeapSnapshotAborting) {
936  v8::HandleScope scope;
937  LocalContext env;
938 
939  const int snapshots_count = v8::HeapProfiler::GetSnapshotsCount();
940  TestActivityControl aborting_control(1);
941  const v8::HeapSnapshot* no_snapshot =
942  v8::HeapProfiler::TakeSnapshot(v8_str("abort"),
944  &aborting_control);
945  CHECK_EQ(NULL, no_snapshot);
946  CHECK_EQ(snapshots_count, v8::HeapProfiler::GetSnapshotsCount());
947  CHECK_GT(aborting_control.total(), aborting_control.done());
948 
949  TestActivityControl control(-1); // Don't abort.
950  const v8::HeapSnapshot* snapshot =
951  v8::HeapProfiler::TakeSnapshot(v8_str("full"),
953  &control);
954  CHECK_NE(NULL, snapshot);
955  CHECK_EQ(snapshots_count + 1, v8::HeapProfiler::GetSnapshotsCount());
956  CHECK_EQ(control.total(), control.done());
957  CHECK_GT(control.total(), 0);
958 }
959 
960 
961 namespace {
962 
963 class TestRetainedObjectInfo : public v8::RetainedObjectInfo {
964  public:
965  TestRetainedObjectInfo(int hash,
966  const char* group_label,
967  const char* label,
968  intptr_t element_count = -1,
969  intptr_t size = -1)
970  : disposed_(false),
971  hash_(hash),
972  group_label_(group_label),
973  label_(label),
974  element_count_(element_count),
975  size_(size) {
976  instances.Add(this);
977  }
978  virtual ~TestRetainedObjectInfo() {}
979  virtual void Dispose() {
980  CHECK(!disposed_);
981  disposed_ = true;
982  }
983  virtual bool IsEquivalent(RetainedObjectInfo* other) {
984  return GetHash() == other->GetHash();
985  }
986  virtual intptr_t GetHash() { return hash_; }
987  virtual const char* GetGroupLabel() { return group_label_; }
988  virtual const char* GetLabel() { return label_; }
989  virtual intptr_t GetElementCount() { return element_count_; }
990  virtual intptr_t GetSizeInBytes() { return size_; }
991  bool disposed() { return disposed_; }
992 
993  static v8::RetainedObjectInfo* WrapperInfoCallback(
994  uint16_t class_id, v8::Handle<v8::Value> wrapper) {
995  if (class_id == 1) {
996  if (wrapper->IsString()) {
997  v8::String::AsciiValue ascii(wrapper);
998  if (strcmp(*ascii, "AAA") == 0)
999  return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
1000  else if (strcmp(*ascii, "BBB") == 0)
1001  return new TestRetainedObjectInfo(1, "aaa-group", "aaa", 100);
1002  }
1003  } else if (class_id == 2) {
1004  if (wrapper->IsString()) {
1005  v8::String::AsciiValue ascii(wrapper);
1006  if (strcmp(*ascii, "CCC") == 0)
1007  return new TestRetainedObjectInfo(2, "ccc-group", "ccc");
1008  }
1009  }
1010  CHECK(false);
1011  return NULL;
1012  }
1013 
1014  static i::List<TestRetainedObjectInfo*> instances;
1015 
1016  private:
1017  bool disposed_;
1018  int category_;
1019  int hash_;
1020  const char* group_label_;
1021  const char* label_;
1022  intptr_t element_count_;
1023  intptr_t size_;
1024 };
1025 
1026 
1027 i::List<TestRetainedObjectInfo*> TestRetainedObjectInfo::instances;
1028 }
1029 
1030 
1031 static const v8::HeapGraphNode* GetNode(const v8::HeapGraphNode* parent,
1033  const char* name) {
1034  for (int i = 0, count = parent->GetChildrenCount(); i < count; ++i) {
1035  const v8::HeapGraphNode* node = parent->GetChild(i)->GetToNode();
1036  if (node->GetType() == type && strcmp(name,
1037  const_cast<i::HeapEntry*>(
1038  reinterpret_cast<const i::HeapEntry*>(node))->name()) == 0) {
1039  return node;
1040  }
1041  }
1042  return NULL;
1043 }
1044 
1045 
1046 TEST(HeapSnapshotRetainedObjectInfo) {
1047  v8::HandleScope scope;
1048  LocalContext env;
1049 
1051  1, TestRetainedObjectInfo::WrapperInfoCallback);
1053  2, TestRetainedObjectInfo::WrapperInfoCallback);
1055  v8::Persistent<v8::String>::New(v8_str("AAA"));
1056  p_AAA.SetWrapperClassId(1);
1058  v8::Persistent<v8::String>::New(v8_str("BBB"));
1059  p_BBB.SetWrapperClassId(1);
1061  v8::Persistent<v8::String>::New(v8_str("CCC"));
1062  p_CCC.SetWrapperClassId(2);
1063  CHECK_EQ(0, TestRetainedObjectInfo::instances.length());
1064  const v8::HeapSnapshot* snapshot =
1065  v8::HeapProfiler::TakeSnapshot(v8_str("retained"));
1066 
1067  CHECK_EQ(3, TestRetainedObjectInfo::instances.length());
1068  for (int i = 0; i < TestRetainedObjectInfo::instances.length(); ++i) {
1069  CHECK(TestRetainedObjectInfo::instances[i]->disposed());
1070  delete TestRetainedObjectInfo::instances[i];
1071  }
1072 
1073  const v8::HeapGraphNode* native_group_aaa = GetNode(
1074  snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "aaa-group");
1075  CHECK_NE(NULL, native_group_aaa);
1076  CHECK_EQ(1, native_group_aaa->GetChildrenCount());
1077  const v8::HeapGraphNode* aaa = GetNode(
1078  native_group_aaa, v8::HeapGraphNode::kNative, "aaa / 100 entries");
1079  CHECK_NE(NULL, aaa);
1080  CHECK_EQ(2, aaa->GetChildrenCount());
1081 
1082  const v8::HeapGraphNode* native_group_ccc = GetNode(
1083  snapshot->GetRoot(), v8::HeapGraphNode::kSynthetic, "ccc-group");
1084  const v8::HeapGraphNode* ccc = GetNode(
1085  native_group_ccc, v8::HeapGraphNode::kNative, "ccc");
1086  CHECK_NE(NULL, ccc);
1087 
1088  const v8::HeapGraphNode* n_AAA = GetNode(
1089  aaa, v8::HeapGraphNode::kString, "AAA");
1090  CHECK_NE(NULL, n_AAA);
1091  const v8::HeapGraphNode* n_BBB = GetNode(
1092  aaa, v8::HeapGraphNode::kString, "BBB");
1093  CHECK_NE(NULL, n_BBB);
1094  CHECK_EQ(1, ccc->GetChildrenCount());
1095  const v8::HeapGraphNode* n_CCC = GetNode(
1096  ccc, v8::HeapGraphNode::kString, "CCC");
1097  CHECK_NE(NULL, n_CCC);
1098 
1099  CHECK_EQ(aaa, GetProperty(n_AAA, v8::HeapGraphEdge::kInternal, "native"));
1100  CHECK_EQ(aaa, GetProperty(n_BBB, v8::HeapGraphEdge::kInternal, "native"));
1101  CHECK_EQ(ccc, GetProperty(n_CCC, v8::HeapGraphEdge::kInternal, "native"));
1102 }
1103 
1104 
1106  public:
1107  static const int kObjectsCount = 4;
1109  CHECK_EQ(NULL, instance_);
1110  instance_ = this;
1111  for (int i = 0; i < kObjectsCount; i++) {
1113  }
1114  (*env)->Global()->Set(v8_str("root_object"), objects_[0]);
1115  }
1117  instance_ = NULL;
1118  }
1119 
1120  static void gcPrologue() {
1121  instance_->AddImplicitReferences();
1122  }
1123 
1124  private:
1125  void AddImplicitReferences() {
1126  // 0 -> 1
1128  v8::Persistent<v8::Object>::Cast(objects_[0]), &objects_[1], 1);
1129  // Adding two more references(note length=2 in params): 1 -> 2, 1 -> 3
1131  v8::Persistent<v8::Object>::Cast(objects_[1]), &objects_[2], 2);
1132  }
1133 
1135  static GraphWithImplicitRefs* instance_;
1136 };
1137 
1138 GraphWithImplicitRefs* GraphWithImplicitRefs::instance_ = NULL;
1139 
1140 
1141 TEST(HeapSnapshotImplicitReferences) {
1142  v8::HandleScope scope;
1143  LocalContext env;
1144 
1145  GraphWithImplicitRefs graph(&env);
1147 
1148  const v8::HeapSnapshot* snapshot =
1149  v8::HeapProfiler::TakeSnapshot(v8_str("implicit_refs"));
1150 
1151  const v8::HeapGraphNode* global_object = GetGlobalObject(snapshot);
1152  const v8::HeapGraphNode* obj0 = GetProperty(
1153  global_object, v8::HeapGraphEdge::kProperty, "root_object");
1154  CHECK(obj0);
1156  const v8::HeapGraphNode* obj1 = GetProperty(
1157  obj0, v8::HeapGraphEdge::kInternal, "native");
1158  CHECK(obj1);
1159  int implicit_targets_count = 0;
1160  for (int i = 0, count = obj1->GetChildrenCount(); i < count; ++i) {
1161  const v8::HeapGraphEdge* prop = obj1->GetChild(i);
1162  v8::String::AsciiValue prop_name(prop->GetName());
1163  if (prop->GetType() == v8::HeapGraphEdge::kInternal &&
1164  strcmp("native", *prop_name) == 0) {
1165  ++implicit_targets_count;
1166  }
1167  }
1168  CHECK_EQ(2, implicit_targets_count);
1170 }
1171 
1172 
1173 TEST(DeleteAllHeapSnapshots) {
1174  v8::HandleScope scope;
1175  LocalContext env;
1176 
1189 }
1190 
1191 
1192 TEST(DeleteHeapSnapshot) {
1193  v8::HandleScope scope;
1194  LocalContext env;
1195 
1197  const v8::HeapSnapshot* s1 =
1198  v8::HeapProfiler::TakeSnapshot(v8_str("1"));
1199  CHECK_NE(NULL, s1);
1201  unsigned uid1 = s1->GetUid();
1203  const_cast<v8::HeapSnapshot*>(s1)->Delete();
1206 
1207  const v8::HeapSnapshot* s2 =
1208  v8::HeapProfiler::TakeSnapshot(v8_str("2"));
1209  CHECK_NE(NULL, s2);
1211  unsigned uid2 = s2->GetUid();
1212  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2));
1214  const v8::HeapSnapshot* s3 =
1215  v8::HeapProfiler::TakeSnapshot(v8_str("3"));
1216  CHECK_NE(NULL, s3);
1218  unsigned uid3 = s3->GetUid();
1219  CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3));
1221  const_cast<v8::HeapSnapshot*>(s2)->Delete();
1225  const_cast<v8::HeapSnapshot*>(s3)->Delete();
1228 }
1229 
1230 
1231 TEST(DocumentURL) {
1232  v8::HandleScope scope;
1233  LocalContext env;
1234 
1235  CompileRun("document = { URL:\"abcdefgh\" };");
1236 
1237  const v8::HeapSnapshot* snapshot =
1238  v8::HeapProfiler::TakeSnapshot(v8_str("document"));
1239  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1240  CHECK_NE(NULL, global);
1241  CHECK_EQ("Object / abcdefgh",
1242  const_cast<i::HeapEntry*>(
1243  reinterpret_cast<const i::HeapEntry*>(global))->name());
1244 }
1245 
1246 
1247 TEST(DocumentWithException) {
1248  v8::HandleScope scope;
1249  LocalContext env;
1250 
1251  CompileRun(
1252  "this.__defineGetter__(\"document\", function() { throw new Error(); })");
1253  const v8::HeapSnapshot* snapshot =
1254  v8::HeapProfiler::TakeSnapshot(v8_str("document"));
1255  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1256  CHECK_NE(NULL, global);
1257  CHECK_EQ("Object",
1258  const_cast<i::HeapEntry*>(
1259  reinterpret_cast<const i::HeapEntry*>(global))->name());
1260 }
1261 
1262 
1263 TEST(DocumentURLWithException) {
1264  v8::HandleScope scope;
1265  LocalContext env;
1266 
1267  CompileRun(
1268  "function URLWithException() {}\n"
1269  "URLWithException.prototype = { get URL() { throw new Error(); } };\n"
1270  "document = { URL: new URLWithException() };");
1271  const v8::HeapSnapshot* snapshot =
1272  v8::HeapProfiler::TakeSnapshot(v8_str("document"));
1273  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1274  CHECK_NE(NULL, global);
1275  CHECK_EQ("Object",
1276  const_cast<i::HeapEntry*>(
1277  reinterpret_cast<const i::HeapEntry*>(global))->name());
1278 }
1279 
1280 
1281 TEST(NoHandleLeaks) {
1282  v8::HandleScope scope;
1283  LocalContext env;
1284 
1285  CompileRun("document = { URL:\"abcdefgh\" };");
1286 
1287  v8::Handle<v8::String> name(v8_str("leakz"));
1288  int count_before = i::HandleScope::NumberOfHandles();
1290  int count_after = i::HandleScope::NumberOfHandles();
1291  CHECK_EQ(count_before, count_after);
1292 }
1293 
1294 
1295 TEST(NodesIteration) {
1296  v8::HandleScope scope;
1297  LocalContext env;
1298  const v8::HeapSnapshot* snapshot =
1299  v8::HeapProfiler::TakeSnapshot(v8_str("iteration"));
1300  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1301  CHECK_NE(NULL, global);
1302  // Verify that we can find this object by iteration.
1303  const int nodes_count = snapshot->GetNodesCount();
1304  int count = 0;
1305  for (int i = 0; i < nodes_count; ++i) {
1306  if (snapshot->GetNode(i) == global)
1307  ++count;
1308  }
1309  CHECK_EQ(1, count);
1310 }
1311 
1312 
1313 TEST(GetHeapValue) {
1314  v8::HandleScope scope;
1315  LocalContext env;
1316 
1317  CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };");
1318  const v8::HeapSnapshot* snapshot =
1319  v8::HeapProfiler::TakeSnapshot(v8_str("value"));
1320  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1321  CHECK(global->GetHeapValue()->IsObject());
1322  v8::Local<v8::Object> js_global =
1323  env->Global()->GetPrototype().As<v8::Object>();
1324  CHECK(js_global == global->GetHeapValue());
1325  const v8::HeapGraphNode* obj = GetProperty(
1326  global, v8::HeapGraphEdge::kProperty, "a");
1327  CHECK(obj->GetHeapValue()->IsObject());
1328  v8::Local<v8::Object> js_obj = js_global->Get(v8_str("a")).As<v8::Object>();
1329  CHECK(js_obj == obj->GetHeapValue());
1330  const v8::HeapGraphNode* s_prop =
1331  GetProperty(obj, v8::HeapGraphEdge::kProperty, "s_prop");
1332  v8::Local<v8::String> js_s_prop =
1333  js_obj->Get(v8_str("s_prop")).As<v8::String>();
1334  CHECK(js_s_prop == s_prop->GetHeapValue());
1335  const v8::HeapGraphNode* n_prop =
1336  GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
1337  v8::Local<v8::Number> js_n_prop =
1338  js_obj->Get(v8_str("n_prop")).As<v8::Number>();
1339  CHECK(js_n_prop == n_prop->GetHeapValue());
1340 }
1341 
1342 
1343 TEST(GetHeapValueForDeletedObject) {
1344  v8::HandleScope scope;
1345  LocalContext env;
1346 
1347  // It is impossible to delete a global property, so we are about to delete a
1348  // property of the "a" object. Also, the "p" object can't be an empty one
1349  // because the empty object is static and isn't actually deleted.
1350  CompileRun("a = { p: { r: {} } };");
1351  const v8::HeapSnapshot* snapshot =
1352  v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
1353  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1354  const v8::HeapGraphNode* obj = GetProperty(
1355  global, v8::HeapGraphEdge::kProperty, "a");
1356  const v8::HeapGraphNode* prop = GetProperty(
1357  obj, v8::HeapGraphEdge::kProperty, "p");
1358  {
1359  // Perform the check inside a nested local scope to avoid creating a
1360  // reference to the object we are deleting.
1361  v8::HandleScope scope;
1362  CHECK(prop->GetHeapValue()->IsObject());
1363  }
1364  CompileRun("delete a.p;");
1365  CHECK(prop->GetHeapValue()->IsUndefined());
1366 }
1367 
1368 
1369 static int StringCmp(const char* ref, i::String* act) {
1370  i::SmartArrayPointer<char> s_act = act->ToCString();
1371  int result = strcmp(ref, *s_act);
1372  if (result != 0)
1373  fprintf(stderr, "Expected: \"%s\", Actual: \"%s\"\n", ref, *s_act);
1374  return result;
1375 }
1376 
1377 
1378 TEST(GetConstructorName) {
1379  v8::HandleScope scope;
1380  LocalContext env;
1381 
1382  CompileRun(
1383  "function Constructor1() {};\n"
1384  "var obj1 = new Constructor1();\n"
1385  "var Constructor2 = function() {};\n"
1386  "var obj2 = new Constructor2();\n"
1387  "var obj3 = {};\n"
1388  "obj3.constructor = function Constructor3() {};\n"
1389  "var obj4 = {};\n"
1390  "// Slow properties\n"
1391  "for (var i=0; i<2000; ++i) obj4[\"p\" + i] = i;\n"
1392  "obj4.constructor = function Constructor4() {};\n"
1393  "var obj5 = {};\n"
1394  "var obj6 = {};\n"
1395  "obj6.constructor = 6;");
1396  v8::Local<v8::Object> js_global =
1397  env->Global()->GetPrototype().As<v8::Object>();
1398  v8::Local<v8::Object> obj1 = js_global->Get(v8_str("obj1")).As<v8::Object>();
1399  i::Handle<i::JSObject> js_obj1 = v8::Utils::OpenHandle(*obj1);
1400  CHECK_EQ(0, StringCmp(
1401  "Constructor1", i::V8HeapExplorer::GetConstructorName(*js_obj1)));
1402  v8::Local<v8::Object> obj2 = js_global->Get(v8_str("obj2")).As<v8::Object>();
1403  i::Handle<i::JSObject> js_obj2 = v8::Utils::OpenHandle(*obj2);
1404  CHECK_EQ(0, StringCmp(
1405  "Constructor2", i::V8HeapExplorer::GetConstructorName(*js_obj2)));
1406  v8::Local<v8::Object> obj3 = js_global->Get(v8_str("obj3")).As<v8::Object>();
1407  i::Handle<i::JSObject> js_obj3 = v8::Utils::OpenHandle(*obj3);
1408  CHECK_EQ(0, StringCmp(
1409  "Constructor3", i::V8HeapExplorer::GetConstructorName(*js_obj3)));
1410  v8::Local<v8::Object> obj4 = js_global->Get(v8_str("obj4")).As<v8::Object>();
1411  i::Handle<i::JSObject> js_obj4 = v8::Utils::OpenHandle(*obj4);
1412  CHECK_EQ(0, StringCmp(
1413  "Constructor4", i::V8HeapExplorer::GetConstructorName(*js_obj4)));
1414  v8::Local<v8::Object> obj5 = js_global->Get(v8_str("obj5")).As<v8::Object>();
1415  i::Handle<i::JSObject> js_obj5 = v8::Utils::OpenHandle(*obj5);
1416  CHECK_EQ(0, StringCmp(
1417  "Object", i::V8HeapExplorer::GetConstructorName(*js_obj5)));
1418  v8::Local<v8::Object> obj6 = js_global->Get(v8_str("obj6")).As<v8::Object>();
1419  i::Handle<i::JSObject> js_obj6 = v8::Utils::OpenHandle(*obj6);
1420  CHECK_EQ(0, StringCmp(
1421  "Object", i::V8HeapExplorer::GetConstructorName(*js_obj6)));
1422 }
1423 
1424 
1425 TEST(FastCaseGetter) {
1426  v8::HandleScope scope;
1427  LocalContext env;
1428 
1429  CompileRun("var obj1 = {};\n"
1430  "obj1.__defineGetter__('propWithGetter', function Y() {\n"
1431  " return 42;\n"
1432  "});\n"
1433  "obj1.__defineSetter__('propWithSetter', function Z(value) {\n"
1434  " return this.value_ = value;\n"
1435  "});\n");
1436  const v8::HeapSnapshot* snapshot =
1437  v8::HeapProfiler::TakeSnapshot(v8_str("fastCaseGetter"));
1438 
1439  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1440  CHECK_NE(NULL, global);
1441  const v8::HeapGraphNode* obj1 =
1442  GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
1443  CHECK_NE(NULL, obj1);
1444  const v8::HeapGraphNode* getterFunction =
1445  GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get-propWithGetter");
1446  CHECK_NE(NULL, getterFunction);
1447  const v8::HeapGraphNode* setterFunction =
1448  GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set-propWithSetter");
1449  CHECK_NE(NULL, setterFunction);
1450 }
1451 
1452 TEST(HiddenPropertiesFastCase) {
1453  v8::HandleScope scope;
1454  LocalContext env;
1455 
1456  CompileRun(
1457  "function C(x) { this.a = this; this.b = x; }\n"
1458  "c = new C(2012);\n");
1459  const v8::HeapSnapshot* snapshot =
1460  v8::HeapProfiler::TakeSnapshot(v8_str("HiddenPropertiesFastCase1"));
1461  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1462  const v8::HeapGraphNode* c =
1463  GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
1464  CHECK_NE(NULL, c);
1465  const v8::HeapGraphNode* hidden_props =
1466  GetProperty(c, v8::HeapGraphEdge::kInternal, "hidden_properties");
1467  CHECK_EQ(NULL, hidden_props);
1468 
1469  v8::Handle<v8::Value> cHandle = env->Global()->Get(v8::String::New("c"));
1470  CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
1471  cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
1472 
1473  snapshot = v8::HeapProfiler::TakeSnapshot(
1474  v8_str("HiddenPropertiesFastCase2"));
1475  global = GetGlobalObject(snapshot);
1476  c = GetProperty(global, v8::HeapGraphEdge::kProperty, "c");
1477  CHECK_NE(NULL, c);
1478  hidden_props = GetProperty(c, v8::HeapGraphEdge::kInternal,
1479  "hidden_properties");
1480  CHECK_NE(NULL, hidden_props);
1481 }
1482 
1483 bool HasWeakEdge(const v8::HeapGraphNode* node) {
1484  for (int i = 0; i < node->GetChildrenCount(); ++i) {
1485  const v8::HeapGraphEdge* handle_edge = node->GetChild(i);
1486  if (handle_edge->GetType() == v8::HeapGraphEdge::kWeak) return true;
1487  }
1488  return false;
1489 }
1490 
1491 
1493  const v8::HeapSnapshot* snapshot =
1494  v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
1495  const v8::HeapGraphNode* gc_roots = GetNode(
1496  snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
1497  CHECK_NE(NULL, gc_roots);
1498  const v8::HeapGraphNode* global_handles = GetNode(
1499  gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
1500  CHECK_NE(NULL, global_handles);
1501  return HasWeakEdge(global_handles);
1502 }
1503 
1504 
1505 static void PersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) {
1506  handle.Dispose();
1507 }
1508 
1509 
1510 TEST(WeakGlobalHandle) {
1511  v8::HandleScope scope;
1512  LocalContext env;
1513 
1515 
1518  handle.MakeWeak(NULL, PersistentHandleCallback);
1519 
1521 }
1522 
1523 
1524 TEST(WeakNativeContextRefs) {
1525  v8::HandleScope scope;
1526  LocalContext env;
1527 
1528  const v8::HeapSnapshot* snapshot =
1529  v8::HeapProfiler::TakeSnapshot(v8_str("weaks"));
1530  const v8::HeapGraphNode* gc_roots = GetNode(
1531  snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
1532  CHECK_NE(NULL, gc_roots);
1533  const v8::HeapGraphNode* global_handles = GetNode(
1534  gc_roots, v8::HeapGraphNode::kObject, "(Global handles)");
1535  CHECK_NE(NULL, global_handles);
1536  const v8::HeapGraphNode* native_context = GetNode(
1537  global_handles, v8::HeapGraphNode::kHidden, "system / NativeContext");
1538  CHECK_NE(NULL, native_context);
1539  CHECK(HasWeakEdge(native_context));
1540 }
1541 
1542 
1543 TEST(SfiAndJsFunctionWeakRefs) {
1544  v8::HandleScope scope;
1545  LocalContext env;
1546 
1547  CompileRun(
1548  "fun = (function (x) { return function () { return x + 1; } })(1);");
1549  const v8::HeapSnapshot* snapshot =
1550  v8::HeapProfiler::TakeSnapshot(v8_str("fun"));
1551  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1552  CHECK_NE(NULL, global);
1553  const v8::HeapGraphNode* fun =
1554  GetProperty(global, v8::HeapGraphEdge::kProperty, "fun");
1555  CHECK(HasWeakEdge(fun));
1556  const v8::HeapGraphNode* shared =
1557  GetProperty(fun, v8::HeapGraphEdge::kInternal, "shared");
1558  CHECK(HasWeakEdge(shared));
1559 }
1560 
1561 
1562 #ifdef ENABLE_DEBUGGER_SUPPORT
1563 TEST(NoDebugObjectInSnapshot) {
1564  v8::HandleScope scope;
1565  LocalContext env;
1566 
1567  v8::internal::Isolate::Current()->debug()->Load();
1568  CompileRun("foo = {};");
1569  const v8::HeapSnapshot* snapshot =
1570  v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
1571  const v8::HeapGraphNode* root = snapshot->GetRoot();
1572  int globals_count = 0;
1573  for (int i = 0; i < root->GetChildrenCount(); ++i) {
1574  const v8::HeapGraphEdge* edge = root->GetChild(i);
1575  if (edge->GetType() == v8::HeapGraphEdge::kShortcut) {
1576  ++globals_count;
1577  const v8::HeapGraphNode* global = edge->GetToNode();
1578  const v8::HeapGraphNode* foo =
1579  GetProperty(global, v8::HeapGraphEdge::kProperty, "foo");
1580  CHECK_NE(NULL, foo);
1581  }
1582  }
1583  CHECK_EQ(1, globals_count);
1584 }
1585 #endif // ENABLE_DEBUGGER_SUPPORT
1586 
1587 
1588 TEST(PersistentHandleCount) {
1589  v8::HandleScope scope;
1590  LocalContext env;
1591 
1592  // V8 also uses global handles internally, so we can't test for an absolute
1593  // number.
1594  int global_handle_count = v8::HeapProfiler::GetPersistentHandleCount();
1595 
1596  // Create some persistent handles.
1598  v8::Persistent<v8::String>::New(v8_str("AAA"));
1599  CHECK_EQ(global_handle_count + 1,
1602  v8::Persistent<v8::String>::New(v8_str("BBB"));
1603  CHECK_EQ(global_handle_count + 2,
1606  v8::Persistent<v8::String>::New(v8_str("CCC"));
1607  CHECK_EQ(global_handle_count + 3,
1609 
1610  // Dipose the persistent handles in a different order.
1611  p_AAA.Dispose();
1612  CHECK_EQ(global_handle_count + 2,
1614  p_CCC.Dispose();
1615  CHECK_EQ(global_handle_count + 1,
1617  p_BBB.Dispose();
1618  CHECK_EQ(global_handle_count, v8::HeapProfiler::GetPersistentHandleCount());
1619 }
1620 
1621 
1622 TEST(AllStrongGcRootsHaveNames) {
1623  v8::HandleScope scope;
1624  LocalContext env;
1625 
1626  CompileRun("foo = {};");
1627  const v8::HeapSnapshot* snapshot =
1628  v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
1629  const v8::HeapGraphNode* gc_roots = GetNode(
1630  snapshot->GetRoot(), v8::HeapGraphNode::kObject, "(GC roots)");
1631  CHECK_NE(NULL, gc_roots);
1632  const v8::HeapGraphNode* strong_roots = GetNode(
1633  gc_roots, v8::HeapGraphNode::kObject, "(Strong roots)");
1634  CHECK_NE(NULL, strong_roots);
1635  for (int i = 0; i < strong_roots->GetChildrenCount(); ++i) {
1636  const v8::HeapGraphEdge* edge = strong_roots->GetChild(i);
1638  v8::String::AsciiValue name(edge->GetName());
1639  CHECK(isalpha(**name));
1640  }
1641 }
1642 
1643 
1644 TEST(NoRefsToNonEssentialEntries) {
1645  v8::HandleScope scope;
1646  LocalContext env;
1647  CompileRun("global_object = {};\n");
1648  const v8::HeapSnapshot* snapshot =
1649  v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
1650  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1651  const v8::HeapGraphNode* global_object =
1652  GetProperty(global, v8::HeapGraphEdge::kProperty, "global_object");
1653  CHECK_NE(NULL, global_object);
1654  const v8::HeapGraphNode* properties =
1655  GetProperty(global_object, v8::HeapGraphEdge::kInternal, "properties");
1656  CHECK_EQ(NULL, properties);
1657  const v8::HeapGraphNode* elements =
1658  GetProperty(global_object, v8::HeapGraphEdge::kInternal, "elements");
1659  CHECK_EQ(NULL, elements);
1660 }
1661 
1662 
1663 TEST(MapHasDescriptorsAndTransitions) {
1664  v8::HandleScope scope;
1665  LocalContext env;
1666  CompileRun("obj = { a: 10 };\n");
1667  const v8::HeapSnapshot* snapshot =
1668  v8::HeapProfiler::TakeSnapshot(v8_str("snapshot"));
1669  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
1670  const v8::HeapGraphNode* global_object =
1671  GetProperty(global, v8::HeapGraphEdge::kProperty, "obj");
1672  CHECK_NE(NULL, global_object);
1673 
1674  const v8::HeapGraphNode* map =
1675  GetProperty(global_object, v8::HeapGraphEdge::kInternal, "map");
1676  CHECK_NE(NULL, map);
1677  const v8::HeapGraphNode* own_descriptors = GetProperty(
1678  map, v8::HeapGraphEdge::kInternal, "descriptors");
1679  CHECK_NE(NULL, own_descriptors);
1680  const v8::HeapGraphNode* own_transitions = GetProperty(
1681  map, v8::HeapGraphEdge::kInternal, "transitions");
1682  CHECK_EQ(NULL, own_transitions);
1683 }
void MakeWeak(void *parameters, WeakReferenceCallback callback)
Definition: v8.h:4245
const SwVfpRegister s2
static void DeleteAllSnapshots()
Definition: api.cc:6410
Local< S > As()
Definition: v8.h:291
const HeapGraphEdge * GetChild(int index) const
Definition: api.cc:6226
static int NumberOfHandles()
Definition: handles.cc:48
#define CHECK_EQ(expected, value)
Definition: checks.h:219
static const HeapSnapshot * TakeSnapshot(Handle< String > title, HeapSnapshot::Type type=HeapSnapshot::kFull, ActivityControl *control=NULL)
Definition: api.cc:6370
void Dispose()
Definition: v8.h:4235
const HeapGraphNode * GetFromNode() const
Definition: api.cc:6168
virtual intptr_t GetHash()=0
V8EXPORT Local< Value > Get(Handle< Value > key)
Definition: api.cc:2853
#define CHECK_GT(a, b)
Definition: checks.h:227
Handle< Value > GetName() const
Definition: api.cc:6147
GraphWithImplicitRefs(LocalContext *env)
Handle< String > GetName() const
Definition: api.cc:6197
SnapshotObjectId GetId() const
Definition: api.cc:6205
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4779
const HeapGraphNode * GetNodeById(SnapshotObjectId id) const
Definition: api.cc:6291
const HeapGraphNode * GetNode(int index) const
Definition: api.cc:6306
#define CHECK_LT(a, b)
Definition: checks.h:229
#define ASSERT(condition)
Definition: checks.h:270
V8EXPORT Local< Number > ToNumber() const
Definition: api.cc:2390
static int GetSnapshotsCount()
Definition: api.cc:6339
unsigned short uint16_t
Definition: unicode.cc:46
int GetSelfSize() const
Definition: api.cc:6212
static void DefineWrapperClass(uint16_t class_id, WrapperInfoCallback callback)
Definition: api.cc:6417
Type GetType() const
Definition: api.cc:6140
#define CHECK(condition)
Definition: checks.h:56
AsciiResource(Vector< const char > string)
Definition: test-strings.cc:70
StringInputBuffer *const buffer_
Handle< Object > GetProperty(Handle< JSReceiver > obj, const char *name)
Definition: handles.cc:282
virtual ControlOption ReportProgressValue(int done, int total)=0
V8EXPORT void SetInternalField(int index, Handle< Value > value)
Definition: api.cc:4214
int foo
SmartArrayPointer< char > ToCString(AllowNullsFlag allow_nulls, RobustnessFlag robustness_flag, int offset, int length, int *length_output=0)
Definition: objects.cc:6233
const SwVfpRegister s3
V8EXPORT int InternalFieldCount()
Definition: api.cc:4185
int GetChildrenCount() const
Definition: api.cc:6219
virtual bool IsEquivalent(RetainedObjectInfo *other)=0
T * start() const
Definition: utils.h:390
static const HeapSnapshot * FindSnapshot(unsigned uid)
Definition: api.cc:6354
static Local< ObjectTemplate > New()
Definition: api.cc:1253
static void StopHeapObjectsTracking()
Definition: api.cc:6396
SnapshotObjectId GetMaxSnapshotJSObjectId() const
Definition: api.cc:6314
V8EXPORT Local< Value > GetPrototype()
Definition: api.cc:2900
static String * GetConstructorName(JSObject *object)
virtual const char * GetLabel()=0
static const int kNoGCFlags
Definition: heap.h:1081
void SetInternalFieldCount(int value)
Definition: api.cc:1438
static SnapshotObjectId PushHeapObjectsStats(OutputStream *stream)
Definition: api.cc:6403
virtual WriteResult WriteHeapStatsChunk(HeapStatsUpdate *data, int count)
Definition: v8.h:3975
Local< Object > Global()
Definition: api.cc:4570
TEST(HeapSnapshot)
int length() const
Definition: utils.h:384
#define STRING_LITERAL_FOR_TEST
void SetWrapperClassId(uint16_t class_id)
Definition: v8.h:4262
static Persistent< T > New(Handle< T > that)
Definition: v8.h:4206
activate correct semantics for inheriting readonliness false
static const int kObjectsCount
bool IsUndefined() const
Definition: v8.h:4472
#define CHECK_NE(unexpected, value)
Definition: checks.h:223
bool IsString() const
Definition: v8.h:4508
const SwVfpRegister s1
V8EXPORT bool IsObject() const
Definition: api.cc:2177
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit 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 SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available 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 MIPS FPU instructions if expose natives in global object expose gc extension number of stack frames to capture disable builtin natives files print a stack trace if an assertion failure occurs use random jit cookie to mask large constants trace lazy optimization use adaptive optimizations prepare for turning on always opt minimum length for automatic enable preparsing maximum number of optimization attempts before giving up cache prototype transitions automatically set the debug break flag when debugger commands are in the queue always cause a debug break before aborting 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 more details following each garbage collection print amount of external allocated memory after each time it is adjusted flush code that we expect not to use again before full gc do incremental marking steps track object counts and memory usage use caching Perform compaction on every full GC Never perform compaction on full GC testing only Compact code space on full incremental collections Default seed for initializing random allows verbose printing trace parsing and preparsing Check icache flushes in ARM and MIPS simulator Stack alingment in bytes in print stack trace when throwing exceptions randomize hashes to avoid predictable hash Fixed seed to use to hash property activate a timer that switches between V8 threads testing_bool_flag float flag Seed used for threading test randomness A filename with extra code to be included in the snapshot(mksnapshot only)") DEFINE_bool(help
virtual WriteResult WriteAsciiChunk(char *data, int size)=0
virtual size_t length() const =0
virtual void Dispose()=0
List< HeapEntry * > * GetSortedEntriesList()
uint32_t SnapshotObjectId
Definition: v8-profiler.h:68
int GetNodesCount() const
Definition: api.cc:6299
virtual const char * data() const =0
const HeapGraphNode * GetRoot() const
Definition: api.cc:6284
#define HEAP
Definition: isolate.h:1433
virtual intptr_t GetElementCount()
Definition: v8-profiler.h:531
static void SetGlobalGCPrologueCallback(GCCallback)
Definition: api.cc:5385
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination use dead code elimination trace on stack replacement optimize closures cache optimized code for closures functions with arguments object loop weight for representation inference allow uint32 values on optimize frames if they are used only in safe operations track parallel recompilation enable all profiler experiments number of stack frames inspected by the profiler call recompile stub directly when self optimizing trigger profiler ticks based on counting instead of timing weight back edges by jump distance for interrupt triggering percentage of ICs that must have type info to allow optimization watch_ic_patching retry_self_opt interrupt_at_exit 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 SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 and VFP2 enable use of VFP2 instructions if available 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 MIPS FPU instructions if NULL
bool IsEmpty() const
Definition: v8.h:209
static int GetPersistentHandleCount()
Definition: api.cc:6424
Handle< Value > GetHeapValue() const
Definition: api.cc:6234
bool HasWeakEdge(const v8::HeapGraphNode *node)
Type GetType() const
Definition: api.cc:6190
V8EXPORT Local< Object > ToObject() const
Definition: api.cc:2353
V8EXPORT uint32_t Length() const
Definition: api.cc:5168
virtual void EndOfStream()=0
static void StartHeapObjectsTracking()
Definition: api.cc:6389
#define CHECK_NE_SNAPSHOT_OBJECT_ID(a, b)
unsigned GetUid() const
Definition: api.cc:6269
static V8EXPORT Local< String > NewExternal(ExternalStringResource *resource)
Definition: api.cc:4871
#define CHECK_EQ_SNAPSHOT_OBJECT_ID(a, b)
virtual intptr_t GetSizeInBytes()
Definition: v8-profiler.h:534
static SnapshotObjectId GetSnapshotObjectId(Handle< Value > value)
Definition: api.cc:6362
const HeapGraphNode * GetToNode() const
Definition: api.cc:6176
bool HasWeakGlobalHandle()
Definition: v8.h:106
void Serialize(OutputStream *stream, SerializationFormat format) const
Definition: api.cc:6321
static void AddImplicitReferences(Persistent< Object > parent, Persistent< Value > *children, size_t length)
Definition: api.cc:5362
virtual const char * GetGroupLabel()
Definition: v8-profiler.h:525
static V8EXPORT Local< Object > New()
Definition: api.cc:4957
static const SnapshotObjectId kUnknownObjectId
Definition: v8-profiler.h:407
V8EXPORT bool Set(Handle< Value > key, Handle< Value > value, PropertyAttribute attribs=None)
Definition: api.cc:2765