heap-snapshot-generator.h 20.6 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
#define V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
7

8
#include "include/v8-profiler.h"
9
#include "src/base/platform/time.h"
10
#include "src/objects.h"
11
#include "src/profiler/strings-storage.h"
12

13 14 15
namespace v8 {
namespace internal {

16 17
class AllocationTracker;
class AllocationTraceNode;
18
class HeapEntry;
19 20
class HeapIterator;
class HeapProfiler;
21
class HeapSnapshot;
22
class SnapshotFiller;
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

class HeapGraphEdge BASE_EMBEDDED {
 public:
  enum Type {
    kContextVariable = v8::HeapGraphEdge::kContextVariable,
    kElement = v8::HeapGraphEdge::kElement,
    kProperty = v8::HeapGraphEdge::kProperty,
    kInternal = v8::HeapGraphEdge::kInternal,
    kHidden = v8::HeapGraphEdge::kHidden,
    kShortcut = v8::HeapGraphEdge::kShortcut,
    kWeak = v8::HeapGraphEdge::kWeak
  };

  HeapGraphEdge(Type type, const char* name, int from, int to);
  HeapGraphEdge(Type type, int index, int from, int to);
  void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);

40
  Type type() const { return TypeField::decode(bit_field_); }
41
  int index() const {
42
    DCHECK(type() == kElement || type() == kHidden);
43 44 45
    return index_;
  }
  const char* name() const {
46 47
    DCHECK(type() == kContextVariable || type() == kProperty ||
           type() == kInternal || type() == kShortcut || type() == kWeak);
48 49 50 51 52
    return name_;
  }
  INLINE(HeapEntry* from() const);
  HeapEntry* to() const { return to_entry_; }

53 54
  INLINE(Isolate* isolate() const);

55 56
 private:
  INLINE(HeapSnapshot* snapshot() const);
57
  int from_index() const { return FromIndexField::decode(bit_field_); }
58

59 60 61
  class TypeField : public BitField<Type, 0, 3> {};
  class FromIndexField : public BitField<int, 3, 29> {};
  uint32_t bit_field_;
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
  union {
    // During entries population |to_index_| is used for storing the index,
    // afterwards it is replaced with a pointer to the entry.
    int to_index_;
    HeapEntry* to_entry_;
  };
  union {
    int index_;
    const char* name_;
  };
};


// HeapEntry instances represent an entity from the heap (or a special
// virtual node, e.g. root).
class HeapEntry BASE_EMBEDDED {
 public:
  enum Type {
    kHidden = v8::HeapGraphNode::kHidden,
    kArray = v8::HeapGraphNode::kArray,
    kString = v8::HeapGraphNode::kString,
    kObject = v8::HeapGraphNode::kObject,
    kCode = v8::HeapGraphNode::kCode,
    kClosure = v8::HeapGraphNode::kClosure,
    kRegExp = v8::HeapGraphNode::kRegExp,
    kHeapNumber = v8::HeapGraphNode::kHeapNumber,
    kNative = v8::HeapGraphNode::kNative,
89 90
    kSynthetic = v8::HeapGraphNode::kSynthetic,
    kConsString = v8::HeapGraphNode::kConsString,
91
    kSlicedString = v8::HeapGraphNode::kSlicedString,
92 93
    kSymbol = v8::HeapGraphNode::kSymbol,
    kSimdValue = v8::HeapGraphNode::kSimdValue
94 95 96 97 98 99 100 101
  };
  static const int kNoEntry;

  HeapEntry() { }
  HeapEntry(HeapSnapshot* snapshot,
            Type type,
            const char* name,
            SnapshotObjectId id,
102 103
            size_t self_size,
            unsigned trace_node_id);
104 105 106 107 108

  HeapSnapshot* snapshot() { return snapshot_; }
  Type type() { return static_cast<Type>(type_); }
  const char* name() { return name_; }
  void set_name(const char* name) { name_ = name; }
109
  SnapshotObjectId id() { return id_; }
110
  size_t self_size() { return self_size_; }
111
  unsigned trace_node_id() const { return trace_node_id_; }
112 113 114 115 116 117 118 119
  INLINE(int index() const);
  int children_count() const { return children_count_; }
  INLINE(int set_children_index(int index));
  void add_child(HeapGraphEdge* edge) {
    children_arr()[children_count_++] = edge;
  }
  Vector<HeapGraphEdge*> children() {
    return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
120
  INLINE(Isolate* isolate() const);
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

  void SetIndexedReference(
      HeapGraphEdge::Type type, int index, HeapEntry* entry);
  void SetNamedReference(
      HeapGraphEdge::Type type, const char* name, HeapEntry* entry);

  void Print(
      const char* prefix, const char* edge_name, int max_depth, int indent);

 private:
  INLINE(HeapGraphEdge** children_arr());
  const char* TypeAsString();

  unsigned type_: 4;
  int children_count_: 28;
  int children_index_;
137
  size_t self_size_;
138 139
  HeapSnapshot* snapshot_;
  const char* name_;
140 141 142
  SnapshotObjectId id_;
  // id of allocation stack trace top node
  unsigned trace_node_id_;
143 144 145 146
};


// HeapSnapshot represents a single heap snapshot. It is stored in
147
// HeapProfiler, which is also a factory for
148 149 150 151 152
// HeapSnapshots. All HeapSnapshots share strings copied from JS heap
// to be able to return them even if they were collected.
// HeapSnapshotGenerator fills in a HeapSnapshot.
class HeapSnapshot {
 public:
153
  explicit HeapSnapshot(HeapProfiler* profiler);
154 155
  void Delete();

156
  HeapProfiler* profiler() { return profiler_; }
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
  size_t RawSnapshotSize() const;
  HeapEntry* root() { return &entries_[root_index_]; }
  HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
  HeapEntry* gc_subroot(int index) {
    return &entries_[gc_subroot_indexes_[index]];
  }
  List<HeapEntry>& entries() { return entries_; }
  List<HeapGraphEdge>& edges() { return edges_; }
  List<HeapGraphEdge*>& children() { return children_; }
  void RememberLastJSObjectId();
  SnapshotObjectId max_snapshot_js_object_id() const {
    return max_snapshot_js_object_id_;
  }

  HeapEntry* AddEntry(HeapEntry::Type type,
                      const char* name,
                      SnapshotObjectId id,
174 175
                      size_t size,
                      unsigned trace_node_id);
176
  void AddSyntheticRootEntries();
177 178 179 180 181 182 183
  HeapEntry* GetEntryById(SnapshotObjectId id);
  List<HeapEntry*>* GetSortedEntriesList();
  void FillChildren();

  void Print(int max_depth);

 private:
184 185 186 187
  HeapEntry* AddRootEntry();
  HeapEntry* AddGcRootsEntry();
  HeapEntry* AddGcSubrootEntry(int tag, SnapshotObjectId id);

188
  HeapProfiler* profiler_;
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
  int root_index_;
  int gc_roots_index_;
  int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
  List<HeapEntry> entries_;
  List<HeapGraphEdge> edges_;
  List<HeapGraphEdge*> children_;
  List<HeapEntry*> sorted_entries_;
  SnapshotObjectId max_snapshot_js_object_id_;

  friend class HeapSnapshotTester;

  DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
};


class HeapObjectsMap {
 public:
206 207 208 209 210 211 212 213 214 215
  struct TimeInterval {
    explicit TimeInterval(SnapshotObjectId id)
        : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
    SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; }
    SnapshotObjectId id;
    uint32_t size;
    uint32_t count;
    base::TimeTicks timestamp;
  };

216 217 218 219 220
  explicit HeapObjectsMap(Heap* heap);

  Heap* heap() const { return heap_; }

  SnapshotObjectId FindEntry(Address addr);
221 222 223
  SnapshotObjectId FindOrAddEntry(Address addr,
                                  unsigned int size,
                                  bool accessed = true);
224
  bool MoveObject(Address from, Address to, int size);
225
  void UpdateObjectSize(Address addr, int size);
226 227 228 229 230
  SnapshotObjectId last_assigned_id() const {
    return next_id_ - kObjectIdStep;
  }

  void StopHeapObjectsTracking();
231 232
  SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
                                        int64_t* timestamp_us);
233
  const List<TimeInterval>& samples() const { return time_intervals_; }
234 235
  size_t GetUsedMemorySize() const;

236
  SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
237 238 239 240 241 242 243

  static const int kObjectIdStep = 2;
  static const SnapshotObjectId kInternalRootObjectId;
  static const SnapshotObjectId kGcRootsObjectId;
  static const SnapshotObjectId kGcRootsFirstSubrootId;
  static const SnapshotObjectId kFirstAvailableObjectId;

244 245 246
  int FindUntrackedObjects();

  void UpdateHeapObjectsMap();
247
  void RemoveDeadEntries();
248

249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341
 private:
  struct EntryInfo {
  EntryInfo(SnapshotObjectId id, Address addr, unsigned int size)
      : id(id), addr(addr), size(size), accessed(true) { }
  EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed)
      : id(id), addr(addr), size(size), accessed(accessed) { }
    SnapshotObjectId id;
    Address addr;
    unsigned int size;
    bool accessed;
  };

  SnapshotObjectId next_id_;
  HashMap entries_map_;
  List<EntryInfo> entries_;
  List<TimeInterval> time_intervals_;
  Heap* heap_;

  DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
};


// A typedef for referencing anything that can be snapshotted living
// in any kind of heap memory.
typedef void* HeapThing;


// An interface that creates HeapEntries by HeapThings.
class HeapEntriesAllocator {
 public:
  virtual ~HeapEntriesAllocator() { }
  virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
};


// The HeapEntriesMap instance is used to track a mapping between
// real heap objects and their representations in heap snapshots.
class HeapEntriesMap {
 public:
  HeapEntriesMap();

  int Map(HeapThing thing);
  void Pair(HeapThing thing, int entry);

 private:
  static uint32_t Hash(HeapThing thing) {
    return ComputeIntegerHash(
        static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
        v8::internal::kZeroHashSeed);
  }

  HashMap entries_;

  friend class HeapObjectsSet;

  DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
};


class HeapObjectsSet {
 public:
  HeapObjectsSet();
  void Clear();
  bool Contains(Object* object);
  void Insert(Object* obj);
  const char* GetTag(Object* obj);
  void SetTag(Object* obj, const char* tag);
  bool is_empty() const { return entries_.occupancy() == 0; }

 private:
  HashMap entries_;

  DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
};


class SnapshottingProgressReportingInterface {
 public:
  virtual ~SnapshottingProgressReportingInterface() { }
  virtual void ProgressStep() = 0;
  virtual bool ProgressReport(bool force) = 0;
};


// An implementation of V8 heap graph extractor.
class V8HeapExplorer : public HeapEntriesAllocator {
 public:
  V8HeapExplorer(HeapSnapshot* snapshot,
                 SnapshottingProgressReportingInterface* progress,
                 v8::HeapProfiler::ObjectNameResolver* resolver);
  virtual ~V8HeapExplorer();
  virtual HeapEntry* AllocateEntry(HeapThing ptr);
  int EstimateObjectsCount(HeapIterator* iterator);
342
  bool IterateAndExtractReferences(SnapshotFiller* filler);
343
  void TagGlobalObjects();
344
  void TagCodeObject(Code* code);
345
  void TagBuiltinCodeObject(Code* code, const char* name);
346 347 348
  HeapEntry* AddEntry(Address address,
                      HeapEntry::Type type,
                      const char* name,
349
                      size_t size);
350 351 352 353

  static String* GetConstructorName(JSObject* object);

 private:
354 355 356
  typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
                                                          HeapObject* object);

357 358
  void MarkVisitedField(HeapObject* obj, int offset);

359 360 361 362
  HeapEntry* AddEntry(HeapObject* object);
  HeapEntry* AddEntry(HeapObject* object,
                      HeapEntry::Type type,
                      const char* name);
363

364 365
  const char* GetSystemEntryName(HeapObject* object);

366 367 368 369 370
  template<V8HeapExplorer::ExtractReferencesMethod extractor>
  bool IterateAndExtractSinglePass();

  bool ExtractReferencesPass1(int entry, HeapObject* obj);
  bool ExtractReferencesPass2(int entry, HeapObject* obj);
371
  void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
372 373
  void ExtractJSObjectReferences(int entry, JSObject* js_obj);
  void ExtractStringReferences(int entry, String* obj);
374
  void ExtractSymbolReferences(int entry, Symbol* symbol);
375
  void ExtractJSCollectionReferences(int entry, JSCollection* collection);
376 377
  void ExtractJSWeakCollectionReferences(int entry,
                                         JSWeakCollection* collection);
378 379 380 381 382
  void ExtractContextReferences(int entry, Context* context);
  void ExtractMapReferences(int entry, Map* map);
  void ExtractSharedFunctionInfoReferences(int entry,
                                           SharedFunctionInfo* shared);
  void ExtractScriptReferences(int entry, Script* script);
383
  void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info);
384
  void ExtractAccessorPairReferences(int entry, AccessorPair* accessors);
385 386
  void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
  void ExtractCodeReferences(int entry, Code* code);
387
  void ExtractBoxReferences(int entry, Box* box);
388
  void ExtractCellReferences(int entry, Cell* cell);
389
  void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
390
  void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
391
  void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
392
  void ExtractFixedArrayReferences(int entry, FixedArray* array);
393 394
  void ExtractClosureReferences(JSObject* js_obj, int entry);
  void ExtractPropertyReferences(JSObject* js_obj, int entry);
395 396
  void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
                                   Object* callback_obj, int field_offset = -1);
397 398
  void ExtractElementReferences(JSObject* js_obj, int entry);
  void ExtractInternalReferences(JSObject* js_obj, int entry);
399

400
  bool IsEssentialObject(Object* object);
401
  void SetContextReference(HeapObject* parent_obj,
402 403
                           int parent,
                           String* reference_name,
404 405
                           Object* child,
                           int field_offset);
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
  void SetNativeBindReference(HeapObject* parent_obj,
                              int parent,
                              const char* reference_name,
                              Object* child);
  void SetElementReference(HeapObject* parent_obj,
                           int parent,
                           int index,
                           Object* child);
  void SetInternalReference(HeapObject* parent_obj,
                            int parent,
                            const char* reference_name,
                            Object* child,
                            int field_offset = -1);
  void SetInternalReference(HeapObject* parent_obj,
                            int parent,
                            int index,
                            Object* child,
                            int field_offset = -1);
  void SetHiddenReference(HeapObject* parent_obj,
                          int parent,
                          int index,
                          Object* child);
  void SetWeakReference(HeapObject* parent_obj,
                        int parent,
430
                        const char* reference_name,
431 432
                        Object* child_obj,
                        int field_offset);
433 434 435 436 437
  void SetWeakReference(HeapObject* parent_obj,
                        int parent,
                        int index,
                        Object* child_obj,
                        int field_offset);
438 439
  void SetPropertyReference(HeapObject* parent_obj,
                            int parent,
440
                            Name* reference_name,
441 442 443
                            Object* child,
                            const char* name_format_string = NULL,
                            int field_offset = -1);
444 445 446 447 448 449
  void SetDataOrAccessorPropertyReference(PropertyKind kind,
                                          JSObject* parent_obj, int parent,
                                          Name* reference_name, Object* child,
                                          const char* name_format_string = NULL,
                                          int field_offset = -1);

450 451 452 453 454 455 456
  void SetUserGlobalReference(Object* user_global);
  void SetRootGcRootsReference();
  void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
  void SetGcSubrootReference(
      VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
  const char* GetStrongGcSubrootName(Object* object);
  void TagObject(Object* obj, const char* tag);
457
  void MarkAsWeakContainer(Object* object);
458 459 460 461 462

  HeapEntry* GetEntry(Object* obj);

  Heap* heap_;
  HeapSnapshot* snapshot_;
463 464
  StringsStorage* names_;
  HeapObjectsMap* heap_object_map_;
465
  SnapshottingProgressReportingInterface* progress_;
466
  SnapshotFiller* filler_;
467 468
  HeapObjectsSet objects_tags_;
  HeapObjectsSet strong_gc_subroot_names_;
469
  HeapObjectsSet user_roots_;
470
  HeapObjectsSet weak_containers_;
471 472
  v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;

473 474
  std::vector<bool> marks_;

475 476 477 478 479 480 481 482 483 484 485 486 487 488
  friend class IndexedReferencesExtractor;
  friend class RootsReferencesExtractor;

  DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
};


class NativeGroupRetainedObjectInfo;


// An implementation of retained native objects extractor.
class NativeObjectsExplorer {
 public:
  NativeObjectsExplorer(HeapSnapshot* snapshot,
489
                        SnapshottingProgressReportingInterface* progress);
490 491
  virtual ~NativeObjectsExplorer();
  int EstimateObjectsCount();
492
  bool IterateAndExtractReferences(SnapshotFiller* filler);
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519

 private:
  void FillRetainedObjects();
  void FillImplicitReferences();
  List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
  void SetNativeRootReference(v8::RetainedObjectInfo* info);
  void SetRootNativeRootsReference();
  void SetWrapperNativeReferences(HeapObject* wrapper,
                                      v8::RetainedObjectInfo* info);
  void VisitSubtreeWrapper(Object** p, uint16_t class_id);

  static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
    return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
                              v8::internal::kZeroHashSeed);
  }
  static bool RetainedInfosMatch(void* key1, void* key2) {
    return key1 == key2 ||
        (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
            reinterpret_cast<v8::RetainedObjectInfo*>(key2));
  }
  INLINE(static bool StringsMatch(void* key1, void* key2)) {
    return strcmp(reinterpret_cast<char*>(key1),
                  reinterpret_cast<char*>(key2)) == 0;
  }

  NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);

520
  Isolate* isolate_;
521
  HeapSnapshot* snapshot_;
522
  StringsStorage* names_;
523 524 525 526 527 528 529 530
  bool embedder_queried_;
  HeapObjectsSet in_groups_;
  // RetainedObjectInfo* -> List<HeapObject*>*
  HashMap objects_by_info_;
  HashMap native_groups_;
  HeapEntriesAllocator* synthetic_entries_allocator_;
  HeapEntriesAllocator* native_entries_allocator_;
  // Used during references extraction.
531
  SnapshotFiller* filler_;
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574

  static HeapThing const kNativesRootObject;

  friend class GlobalHandlesExtractor;

  DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
};


class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
 public:
  HeapSnapshotGenerator(HeapSnapshot* snapshot,
                        v8::ActivityControl* control,
                        v8::HeapProfiler::ObjectNameResolver* resolver,
                        Heap* heap);
  bool GenerateSnapshot();

 private:
  bool FillReferences();
  void ProgressStep();
  bool ProgressReport(bool force = false);
  void SetProgressTotal(int iterations_count);

  HeapSnapshot* snapshot_;
  v8::ActivityControl* control_;
  V8HeapExplorer v8_heap_explorer_;
  NativeObjectsExplorer dom_explorer_;
  // Mapping from HeapThing pointers to HeapEntry* pointers.
  HeapEntriesMap entries_;
  // Used during snapshot generation.
  int progress_counter_;
  int progress_total_;
  Heap* heap_;

  DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
};

class OutputStreamWriter;

class HeapSnapshotJSONSerializer {
 public:
  explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
      : snapshot_(snapshot),
575
        strings_(StringsMatch),
576 577 578 579 580 581 582
        next_node_id_(1),
        next_string_id_(1),
        writer_(NULL) {
  }
  void Serialize(v8::OutputStream* stream);

 private:
583 584 585
  INLINE(static bool StringsMatch(void* key1, void* key2)) {
    return strcmp(reinterpret_cast<char*>(key1),
                  reinterpret_cast<char*>(key2)) == 0;
586 587
  }

588 589 590 591 592
  INLINE(static uint32_t StringHash(const void* string)) {
    const char* s = reinterpret_cast<const char*>(string);
    int len = static_cast<int>(strlen(s));
    return StringHasher::HashSequentialString(
        s, len, v8::internal::kZeroHashSeed);
593 594 595 596 597 598 599 600 601 602
  }

  int GetStringId(const char* s);
  int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
  void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
  void SerializeEdges();
  void SerializeImpl();
  void SerializeNode(HeapEntry* entry);
  void SerializeNodes();
  void SerializeSnapshot();
603 604 605
  void SerializeTraceTree();
  void SerializeTraceNode(AllocationTraceNode* node);
  void SerializeTraceNodeInfos();
606
  void SerializeSamples();
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
  void SerializeString(const unsigned char* s);
  void SerializeStrings();

  static const int kEdgeFieldsCount;
  static const int kNodeFieldsCount;

  HeapSnapshot* snapshot_;
  HashMap strings_;
  int next_node_id_;
  int next_string_id_;
  OutputStreamWriter* writer_;

  friend class HeapSnapshotJSONSerializerEnumerator;
  friend class HeapSnapshotJSONSerializerIterator;

  DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
};


626 627
}  // namespace internal
}  // namespace v8
628

629
#endif  // V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_