heap-snapshot-generator.h 22.4 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 <deque>
9
#include <memory>
10
#include <unordered_map>
11
#include <unordered_set>
12
#include <vector>
13

14
#include "include/v8-profiler.h"
15
#include "src/base/platform/time.h"
16
#include "src/objects/fixed-array.h"
17
#include "src/objects/hash-table.h"
18
#include "src/objects/heap-object.h"
19
#include "src/objects/js-objects.h"
20
#include "src/objects/literal-objects.h"
21
#include "src/objects/objects.h"
22
#include "src/objects/visitors.h"
23
#include "src/profiler/strings-storage.h"
24
#include "src/strings/string-hasher.h"
25

26 27 28
namespace v8 {
namespace internal {

29
class AllocationTraceNode;
30
class HeapEntry;
31
class HeapProfiler;
32
class HeapSnapshot;
33
class HeapSnapshotGenerator;
34
class JSArrayBuffer;
35
class JSCollection;
36 37 38 39
class JSGeneratorObject;
class JSGlobalObject;
class JSGlobalProxy;
class JSPromise;
40
class JSWeakCollection;
41
class SafepointScope;
42

43 44 45 46 47 48 49 50 51 52
struct SourceLocation {
  SourceLocation(int entry_index, int scriptId, int line, int col)
      : entry_index(entry_index), scriptId(scriptId), line(line), col(col) {}

  const int entry_index;
  const int scriptId;
  const int line;
  const int col;
};

53
class HeapGraphEdge {
54 55 56 57 58 59 60 61 62 63 64
 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
  };

65 66
  HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to);
  HeapGraphEdge(Type type, int index, HeapEntry* from, HeapEntry* to);
67

68
  Type type() const { return TypeField::decode(bit_field_); }
69
  int index() const {
70
    DCHECK(type() == kElement || type() == kHidden);
71 72 73
    return index_;
  }
  const char* name() const {
74 75
    DCHECK(type() == kContextVariable || type() == kProperty ||
           type() == kInternal || type() == kShortcut || type() == kWeak);
76 77
    return name_;
  }
78
  V8_INLINE HeapEntry* from() const;
79 80
  HeapEntry* to() const { return to_entry_; }

81
  V8_INLINE Isolate* isolate() const;
82

83
 private:
84
  V8_INLINE HeapSnapshot* snapshot() const;
85
  int from_index() const { return FromIndexField::decode(bit_field_); }
86

87 88
  using TypeField = base::BitField<Type, 0, 3>;
  using FromIndexField = base::BitField<int, 3, 29>;
89
  uint32_t bit_field_;
90
  HeapEntry* to_entry_;
91 92 93 94 95 96 97 98 99
  union {
    int index_;
    const char* name_;
  };
};


// HeapEntry instances represent an entity from the heap (or a special
// virtual node, e.g. root).
100
class HeapEntry {
101 102 103 104 105 106 107 108 109 110 111
 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,
112 113
    kSynthetic = v8::HeapGraphNode::kSynthetic,
    kConsString = v8::HeapGraphNode::kConsString,
114
    kSlicedString = v8::HeapGraphNode::kSlicedString,
115 116
    kSymbol = v8::HeapGraphNode::kSymbol,
    kBigInt = v8::HeapGraphNode::kBigInt
117 118
  };

119 120
  HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name,
            SnapshotObjectId id, size_t self_size, unsigned trace_node_id);
121 122

  HeapSnapshot* snapshot() { return snapshot_; }
123
  Type type() const { return static_cast<Type>(type_); }
124
  void set_type(Type type) { type_ = type; }
125
  const char* name() const { return name_; }
126
  void set_name(const char* name) { name_ = name; }
127 128
  SnapshotObjectId id() const { return id_; }
  size_t self_size() const { return self_size_; }
129
  void add_self_size(size_t size) { self_size_ += size; }
130
  unsigned trace_node_id() const { return trace_node_id_; }
131 132
  int index() const { return index_; }
  V8_INLINE int children_count() const;
133
  V8_INLINE int set_children_index(int index);
134 135
  V8_INLINE void add_child(HeapGraphEdge* edge);
  V8_INLINE HeapGraphEdge* child(int i);
136
  V8_INLINE Isolate* isolate() const;
137

138 139 140 141 142
  void set_detachedness(v8::EmbedderGraph::Node::Detachedness value) {
    detachedness_ = static_cast<uint8_t>(value);
  }
  uint8_t detachedness() const { return detachedness_; }

143 144 145 146
  void SetIndexedReference(
      HeapGraphEdge::Type type, int index, HeapEntry* entry);
  void SetNamedReference(
      HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
147 148 149 150 151 152 153
  void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
                                    HeapEntry* child) {
    SetIndexedReference(type, children_count_ + 1, child);
  }
  void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
                                  const char* description, HeapEntry* child,
                                  StringsStorage* strings);
154

155
  V8_EXPORT_PRIVATE void Print(const char* prefix, const char* edge_name,
156
                               int max_depth, int indent) const;
157 158

 private:
159 160
  V8_INLINE std::vector<HeapGraphEdge*>::iterator children_begin() const;
  V8_INLINE std::vector<HeapGraphEdge*>::iterator children_end() const;
161
  const char* TypeAsString() const;
162 163

  unsigned type_: 4;
164 165 166 167 168 169 170
  unsigned index_ : 28;  // Supports up to ~250M objects.
  union {
    // The count is used during the snapshot build phase,
    // then it gets converted into the index by the |FillChildren| function.
    unsigned children_count_;
    unsigned children_end_index_;
  };
171 172 173
#ifdef V8_TARGET_ARCH_64_BIT
  size_t self_size_ : 48;
#else   // !V8_TARGET_ARCH_64_BIT
174
  size_t self_size_;
175 176
#endif  // !V8_TARGET_ARCH_64_BIT
  uint8_t detachedness_ = 0;
177 178
  HeapSnapshot* snapshot_;
  const char* name_;
179 180 181
  SnapshotObjectId id_;
  // id of allocation stack trace top node
  unsigned trace_node_id_;
182 183 184
};

// HeapSnapshot represents a single heap snapshot. It is stored in
185
// HeapProfiler, which is also a factory for
186 187 188 189 190
// 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:
191
  explicit HeapSnapshot(HeapProfiler* profiler, bool global_objects_as_roots);
192 193
  HeapSnapshot(const HeapSnapshot&) = delete;
  HeapSnapshot& operator=(const HeapSnapshot&) = delete;
194 195
  void Delete();

196 197 198 199 200
  HeapProfiler* profiler() const { return profiler_; }
  HeapEntry* root() const { return root_entry_; }
  HeapEntry* gc_roots() const { return gc_roots_entry_; }
  HeapEntry* gc_subroot(Root root) const {
    return gc_subroot_entries_[static_cast<int>(root)];
201
  }
202
  std::deque<HeapEntry>& entries() { return entries_; }
203
  const std::deque<HeapEntry>& entries() const { return entries_; }
204
  std::deque<HeapGraphEdge>& edges() { return edges_; }
205
  const std::deque<HeapGraphEdge>& edges() const { return edges_; }
206
  std::vector<HeapGraphEdge*>& children() { return children_; }
207
  const std::vector<SourceLocation>& locations() const { return locations_; }
208 209 210 211
  void RememberLastJSObjectId();
  SnapshotObjectId max_snapshot_js_object_id() const {
    return max_snapshot_js_object_id_;
  }
212
  bool is_complete() const { return !children_.empty(); }
213 214 215
  bool treat_global_objects_as_roots() const {
    return treat_global_objects_as_roots_;
  }
216

217
  void AddLocation(HeapEntry* entry, int scriptId, int line, int col);
218 219 220
  HeapEntry* AddEntry(HeapEntry::Type type,
                      const char* name,
                      SnapshotObjectId id,
221 222
                      size_t size,
                      unsigned trace_node_id);
223
  void AddSyntheticRootEntries();
224 225 226 227 228 229
  HeapEntry* GetEntryById(SnapshotObjectId id);
  void FillChildren();

  void Print(int max_depth);

 private:
230 231 232
  void AddRootEntry();
  void AddGcRootsEntry();
  void AddGcSubrootEntry(Root root, SnapshotObjectId id);
233

234
  HeapProfiler* profiler_;
235 236 237 238 239 240 241
  HeapEntry* root_entry_ = nullptr;
  HeapEntry* gc_roots_entry_ = nullptr;
  HeapEntry* gc_subroot_entries_[static_cast<int>(Root::kNumberOfRoots)];
  // For |entries_| we rely on the deque property, that it never reallocates
  // backing storage, thus all entry pointers remain valid for the duration
  // of snapshotting.
  std::deque<HeapEntry> entries_;
242
  std::deque<HeapGraphEdge> edges_;
243 244
  std::vector<HeapGraphEdge*> children_;
  std::unordered_map<SnapshotObjectId, HeapEntry*> entries_by_id_cache_;
245
  std::vector<SourceLocation> locations_;
246
  SnapshotObjectId max_snapshot_js_object_id_ = -1;
247
  bool treat_global_objects_as_roots_;
248 249 250 251 252
};


class HeapObjectsMap {
 public:
253 254 255 256 257 258 259 260 261 262
  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;
  };

263
  explicit HeapObjectsMap(Heap* heap);
264 265
  HeapObjectsMap(const HeapObjectsMap&) = delete;
  HeapObjectsMap& operator=(const HeapObjectsMap&) = delete;
266 267 268 269

  Heap* heap() const { return heap_; }

  SnapshotObjectId FindEntry(Address addr);
270 271 272
  SnapshotObjectId FindOrAddEntry(Address addr,
                                  unsigned int size,
                                  bool accessed = true);
273 274
  SnapshotObjectId FindMergedNativeEntry(NativeObject addr);
  void AddMergedNativeEntry(NativeObject addr, Address canonical_addr);
275
  bool MoveObject(Address from, Address to, int size);
276
  void UpdateObjectSize(Address addr, int size);
277 278 279 280 281
  SnapshotObjectId last_assigned_id() const {
    return next_id_ - kObjectIdStep;
  }

  void StopHeapObjectsTracking();
282 283
  SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
                                        int64_t* timestamp_us);
284
  const std::vector<TimeInterval>& samples() const { return time_intervals_; }
285 286 287 288 289 290 291

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

292
  void UpdateHeapObjectsMap();
293
  void RemoveDeadEntries();
294

295 296
 private:
  struct EntryInfo {
297 298 299
    EntryInfo(SnapshotObjectId id, Address addr, unsigned int size,
              bool accessed)
        : id(id), addr(addr), size(size), accessed(accessed) {}
300 301 302 303 304 305 306
    SnapshotObjectId id;
    Address addr;
    unsigned int size;
    bool accessed;
  };

  SnapshotObjectId next_id_;
307
  // TODO(jkummerow): Use a map that uses {Address} as the key type.
lpy's avatar
lpy committed
308
  base::HashMap entries_map_;
309
  std::vector<EntryInfo> entries_;
310
  std::vector<TimeInterval> time_intervals_;
311 312
  // Map from NativeObject to EntryInfo index in entries_.
  std::unordered_map<NativeObject, size_t> merged_native_entries_map_;
313 314 315 316 317
  Heap* heap_;
};

// A typedef for referencing anything that can be snapshotted living
// in any kind of heap memory.
318
using HeapThing = void*;
319 320 321 322

// An interface that creates HeapEntries by HeapThings.
class HeapEntriesAllocator {
 public:
323
  virtual ~HeapEntriesAllocator() = default;
324 325 326 327 328
  virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
};

class SnapshottingProgressReportingInterface {
 public:
329
  virtual ~SnapshottingProgressReportingInterface() = default;
330 331 332 333 334
  virtual void ProgressStep() = 0;
  virtual bool ProgressReport(bool force) = 0;
};

// An implementation of V8 heap graph extractor.
335
class V8_EXPORT_PRIVATE V8HeapExplorer : public HeapEntriesAllocator {
336 337 338 339
 public:
  V8HeapExplorer(HeapSnapshot* snapshot,
                 SnapshottingProgressReportingInterface* progress,
                 v8::HeapProfiler::ObjectNameResolver* resolver);
340
  ~V8HeapExplorer() override = default;
341 342
  V8HeapExplorer(const V8HeapExplorer&) = delete;
  V8HeapExplorer& operator=(const V8HeapExplorer&) = delete;
343

344
  HeapEntry* AllocateEntry(HeapThing ptr) override;
345
  int EstimateObjectsCount();
346
  bool IterateAndExtractReferences(HeapSnapshotGenerator* generator);
347 348
  void CollectGlobalObjectsTags();
  void MakeGlobalObjectTagMap(const SafepointScope& safepoint_scope);
349
  void TagBuiltinCodeObject(Code code, const char* name);
350 351 352
  HeapEntry* AddEntry(Address address,
                      HeapEntry::Type type,
                      const char* name,
353
                      size_t size);
354

355 356
  static JSFunction GetConstructor(JSReceiver receiver);
  static String GetConstructorName(JSObject object);
357 358

 private:
359
  void MarkVisitedField(int offset);
360

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

365
  const char* GetSystemEntryName(HeapObject object);
366

367
  void ExtractLocation(HeapEntry* entry, HeapObject object);
368
  void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction func);
369
  void ExtractReferences(HeapEntry* entry, HeapObject obj);
370 371
  void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy proxy);
  void ExtractJSObjectReferences(HeapEntry* entry, JSObject js_obj);
372 373
  void ExtractStringReferences(HeapEntry* entry, String obj);
  void ExtractSymbolReferences(HeapEntry* entry, Symbol symbol);
374
  void ExtractJSCollectionReferences(HeapEntry* entry, JSCollection collection);
375
  void ExtractJSWeakCollectionReferences(HeapEntry* entry,
376
                                         JSWeakCollection collection);
377
  void ExtractEphemeronHashTableReferences(HeapEntry* entry,
378
                                           EphemeronHashTable table);
379
  void ExtractContextReferences(HeapEntry* entry, Context context);
380
  void ExtractMapReferences(HeapEntry* entry, Map map);
381
  void ExtractSharedFunctionInfoReferences(HeapEntry* entry,
382
                                           SharedFunctionInfo shared);
383
  void ExtractScriptReferences(HeapEntry* entry, Script script);
384
  void ExtractAccessorInfoReferences(HeapEntry* entry,
385 386
                                     AccessorInfo accessor_info);
  void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair accessors);
387
  void ExtractCodeReferences(HeapEntry* entry, Code code);
388
  void ExtractCellReferences(HeapEntry* entry, Cell cell);
389
  void ExtractFeedbackCellReferences(HeapEntry* entry,
390
                                     FeedbackCell feedback_cell);
391
  void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell cell);
392
  void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite site);
393
  void ExtractArrayBoilerplateDescriptionReferences(
394
      HeapEntry* entry, ArrayBoilerplateDescription value);
395 396
  void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer buffer);
  void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise promise);
397
  void ExtractJSGeneratorObjectReferences(HeapEntry* entry,
398
                                          JSGeneratorObject generator);
399
  void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray array);
400
  void ExtractFeedbackVectorReferences(HeapEntry* entry,
401
                                       FeedbackVector feedback_vector);
402
  void ExtractDescriptorArrayReferences(HeapEntry* entry,
403
                                        DescriptorArray array);
404
  template <typename T>
405
  void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T array);
406
  void ExtractPropertyReferences(JSObject js_obj, HeapEntry* entry);
407
  void ExtractAccessorPairProperty(HeapEntry* entry, Name key,
408
                                   Object callback_obj, int field_offset = -1);
409 410
  void ExtractElementReferences(JSObject js_obj, HeapEntry* entry);
  void ExtractInternalReferences(JSObject js_obj, HeapEntry* entry);
411

412 413
  bool IsEssentialObject(Object object);
  bool IsEssentialHiddenReference(Object parent, int field_offset);
414

415
  void SetContextReference(HeapEntry* parent_entry, String reference_name,
416
                           Object child, int field_offset);
417
  void SetNativeBindReference(HeapEntry* parent_entry,
418 419
                              const char* reference_name, Object child);
  void SetElementReference(HeapEntry* parent_entry, int index, Object child);
420
  void SetInternalReference(HeapEntry* parent_entry, const char* reference_name,
421 422
                            Object child, int field_offset = -1);
  void SetInternalReference(HeapEntry* parent_entry, int index, Object child,
423
                            int field_offset = -1);
424
  void SetHiddenReference(HeapObject parent_obj, HeapEntry* parent_entry,
425
                          int index, Object child, int field_offset);
426
  void SetWeakReference(HeapEntry* parent_entry, const char* reference_name,
427 428
                        Object child_obj, int field_offset);
  void SetWeakReference(HeapEntry* parent_entry, int index, Object child_obj,
429
                        int field_offset);
430
  void SetPropertyReference(HeapEntry* parent_entry, Name reference_name,
431
                            Object child,
432
                            const char* name_format_string = nullptr,
433
                            int field_offset = -1);
434
  void SetDataOrAccessorPropertyReference(
435
      PropertyKind kind, HeapEntry* parent_entry, Name reference_name,
436
      Object child, const char* name_format_string = nullptr,
437
      int field_offset = -1);
438

439
  void SetUserGlobalReference(Object user_global);
440
  void SetRootGcRootsReference();
441 442
  void SetGcRootsReference(Root root);
  void SetGcSubrootReference(Root root, const char* description, bool is_weak,
443 444 445
                             Object child);
  const char* GetStrongGcSubrootName(Object object);
  void TagObject(Object obj, const char* tag);
446

447
  HeapEntry* GetEntry(Object obj);
448 449 450

  Heap* heap_;
  HeapSnapshot* snapshot_;
451 452
  StringsStorage* names_;
  HeapObjectsMap* heap_object_map_;
453
  SnapshottingProgressReportingInterface* progress_;
454
  HeapSnapshotGenerator* generator_ = nullptr;
455 456 457 458
  std::vector<std::pair<Handle<JSGlobalObject>, const char*>>
      global_object_tag_pairs_;
  std::unordered_map<JSGlobalObject, const char*, Object::Hasher>
      global_object_tag_map_;
459 460
  std::unordered_map<Object, const char*, Object::Hasher>
      strong_gc_subroot_names_;
461
  std::unordered_set<JSGlobalObject, Object::Hasher> user_roots_;
462 463
  v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;

464
  std::vector<bool> visited_fields_;
465

466 467 468 469 470 471 472 473
  friend class IndexedReferencesExtractor;
  friend class RootsReferencesExtractor;
};

// An implementation of retained native objects extractor.
class NativeObjectsExplorer {
 public:
  NativeObjectsExplorer(HeapSnapshot* snapshot,
474
                        SnapshottingProgressReportingInterface* progress);
475 476
  NativeObjectsExplorer(const NativeObjectsExplorer&) = delete;
  NativeObjectsExplorer& operator=(const NativeObjectsExplorer&) = delete;
477
  bool IterateAndExtractReferences(HeapSnapshotGenerator* generator);
478 479

 private:
480 481
  // Returns an entry for a given node, where node may be a V8 node or an
  // embedder node. Returns the coresponding wrapper node if present.
482
  HeapEntry* EntryForEmbedderGraphNode(EmbedderGraph::Node* node);
483 484
  void MergeNodeIntoEntry(HeapEntry* entry, EmbedderGraph::Node* original_node,
                          EmbedderGraph::Node* wrapper_node);
485

486
  Isolate* isolate_;
487
  HeapSnapshot* snapshot_;
488
  StringsStorage* names_;
489
  HeapObjectsMap* heap_object_map_;
490
  std::unique_ptr<HeapEntriesAllocator> embedder_graph_entries_allocator_;
491
  // Used during references extraction.
492
  HeapSnapshotGenerator* generator_ = nullptr;
493 494 495 496 497 498 499 500

  static HeapThing const kNativesRootObject;

  friend class GlobalHandlesExtractor;
};

class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
 public:
501 502
  // The HeapEntriesMap instance is used to track a mapping between
  // real heap objects and their representations in heap snapshots.
503
  using HeapEntriesMap = std::unordered_map<HeapThing, HeapEntry*>;
504

505 506 507 508
  HeapSnapshotGenerator(HeapSnapshot* snapshot,
                        v8::ActivityControl* control,
                        v8::HeapProfiler::ObjectNameResolver* resolver,
                        Heap* heap);
509 510
  HeapSnapshotGenerator(const HeapSnapshotGenerator&) = delete;
  HeapSnapshotGenerator& operator=(const HeapSnapshotGenerator&) = delete;
511 512
  bool GenerateSnapshot();

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
  HeapEntry* FindEntry(HeapThing ptr) {
    auto it = entries_map_.find(ptr);
    return it != entries_map_.end() ? it->second : nullptr;
  }

  HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
    return entries_map_.emplace(ptr, allocator->AllocateEntry(ptr))
        .first->second;
  }

  HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
    HeapEntry* entry = FindEntry(ptr);
    return entry != nullptr ? entry : AddEntry(ptr, allocator);
  }

528 529
 private:
  bool FillReferences();
530 531
  void ProgressStep() override;
  bool ProgressReport(bool force = false) override;
532
  void InitProgressCounter();
533 534 535 536 537

  HeapSnapshot* snapshot_;
  v8::ActivityControl* control_;
  V8HeapExplorer v8_heap_explorer_;
  NativeObjectsExplorer dom_explorer_;
538 539
  // Mapping from HeapThing pointers to HeapEntry indices.
  HeapEntriesMap entries_map_;
540 541 542 543 544 545 546 547 548 549 550 551
  // Used during snapshot generation.
  int progress_counter_;
  int progress_total_;
  Heap* heap_;
};

class OutputStreamWriter;

class HeapSnapshotJSONSerializer {
 public:
  explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
      : snapshot_(snapshot),
552
        strings_(StringsMatch),
553 554
        next_node_id_(1),
        next_string_id_(1),
555
        writer_(nullptr) {}
556 557 558
  HeapSnapshotJSONSerializer(const HeapSnapshotJSONSerializer&) = delete;
  HeapSnapshotJSONSerializer& operator=(const HeapSnapshotJSONSerializer&) =
      delete;
559 560 561
  void Serialize(v8::OutputStream* stream);

 private:
562
  V8_INLINE static bool StringsMatch(void* key1, void* key2) {
563 564
    return strcmp(reinterpret_cast<char*>(key1),
                  reinterpret_cast<char*>(key2)) == 0;
565 566
  }

567
  V8_INLINE static uint32_t StringHash(const void* string);
568 569

  int GetStringId(const char* s);
570 571
  V8_INLINE int to_node_index(const HeapEntry* e);
  V8_INLINE int to_node_index(int entry_index);
572 573 574
  void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
  void SerializeEdges();
  void SerializeImpl();
575
  void SerializeNode(const HeapEntry* entry);
576 577
  void SerializeNodes();
  void SerializeSnapshot();
578 579 580
  void SerializeTraceTree();
  void SerializeTraceNode(AllocationTraceNode* node);
  void SerializeTraceNodeInfos();
581
  void SerializeSamples();
582 583
  void SerializeString(const unsigned char* s);
  void SerializeStrings();
584 585
  void SerializeLocation(const SourceLocation& location);
  void SerializeLocations();
586 587 588 589 590

  static const int kEdgeFieldsCount;
  static const int kNodeFieldsCount;

  HeapSnapshot* snapshot_;
591
  base::CustomMatcherHashMap strings_;
592 593 594 595 596 597 598 599 600
  int next_node_id_;
  int next_string_id_;
  OutputStreamWriter* writer_;

  friend class HeapSnapshotJSONSerializerEnumerator;
  friend class HeapSnapshotJSONSerializerIterator;
};


601 602
}  // namespace internal
}  // namespace v8
603

604
#endif  // V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_