V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
heap-snapshot-generator.h
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
6 #define V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
7 
8 #include <deque>
9 #include <unordered_map>
10 #include <unordered_set>
11 #include <vector>
12 
13 #include "include/v8-profiler.h"
14 #include "src/base/platform/time.h"
15 #include "src/objects.h"
16 #include "src/objects/fixed-array.h"
17 #include "src/objects/hash-table.h"
18 #include "src/objects/literal-objects.h"
19 #include "src/profiler/strings-storage.h"
20 #include "src/string-hasher.h"
21 #include "src/visitors.h"
22 
23 namespace v8 {
24 namespace internal {
25 
26 class AllocationTracker;
27 class AllocationTraceNode;
28 class HeapEntry;
29 class HeapIterator;
30 class HeapProfiler;
31 class HeapSnapshot;
32 class HeapSnapshotGenerator;
33 class JSArrayBuffer;
34 class JSCollection;
35 class JSGeneratorObject;
36 class JSGlobalObject;
37 class JSGlobalProxy;
38 class JSPromise;
39 class JSWeakCollection;
40 
42  SourceLocation(int entry_index, int scriptId, int line, int col)
43  : entry_index(entry_index), scriptId(scriptId), line(line), col(col) {}
44 
45  const int entry_index;
46  const int scriptId;
47  const int line;
48  const int col;
49 };
50 
52  public:
53  enum Type {
54  kContextVariable = v8::HeapGraphEdge::kContextVariable,
55  kElement = v8::HeapGraphEdge::kElement,
56  kProperty = v8::HeapGraphEdge::kProperty,
57  kInternal = v8::HeapGraphEdge::kInternal,
58  kHidden = v8::HeapGraphEdge::kHidden,
59  kShortcut = v8::HeapGraphEdge::kShortcut,
60  kWeak = v8::HeapGraphEdge::kWeak
61  };
62 
63  HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to);
64  HeapGraphEdge(Type type, int index, HeapEntry* from, HeapEntry* to);
65 
66  Type type() const { return TypeField::decode(bit_field_); }
67  int index() const {
68  DCHECK(type() == kElement || type() == kHidden);
69  return index_;
70  }
71  const char* name() const {
72  DCHECK(type() == kContextVariable || type() == kProperty ||
73  type() == kInternal || type() == kShortcut || type() == kWeak);
74  return name_;
75  }
76  V8_INLINE HeapEntry* from() const;
77  HeapEntry* to() const { return to_entry_; }
78 
79  V8_INLINE Isolate* isolate() const;
80 
81  private:
82  V8_INLINE HeapSnapshot* snapshot() const;
83  int from_index() const { return FromIndexField::decode(bit_field_); }
84 
85  class TypeField : public BitField<Type, 0, 3> {};
86  class FromIndexField : public BitField<int, 3, 29> {};
87  uint32_t bit_field_;
88  HeapEntry* to_entry_;
89  union {
90  int index_;
91  const char* name_;
92  };
93 };
94 
95 
96 // HeapEntry instances represent an entity from the heap (or a special
97 // virtual node, e.g. root).
98 class HeapEntry {
99  public:
100  enum Type {
101  kHidden = v8::HeapGraphNode::kHidden,
102  kArray = v8::HeapGraphNode::kArray,
103  kString = v8::HeapGraphNode::kString,
104  kObject = v8::HeapGraphNode::kObject,
105  kCode = v8::HeapGraphNode::kCode,
106  kClosure = v8::HeapGraphNode::kClosure,
107  kRegExp = v8::HeapGraphNode::kRegExp,
108  kHeapNumber = v8::HeapGraphNode::kHeapNumber,
109  kNative = v8::HeapGraphNode::kNative,
110  kSynthetic = v8::HeapGraphNode::kSynthetic,
111  kConsString = v8::HeapGraphNode::kConsString,
112  kSlicedString = v8::HeapGraphNode::kSlicedString,
113  kSymbol = v8::HeapGraphNode::kSymbol,
114  kBigInt = v8::HeapGraphNode::kBigInt
115  };
116 
117  HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name,
118  SnapshotObjectId id, size_t self_size, unsigned trace_node_id);
119 
120  HeapSnapshot* snapshot() { return snapshot_; }
121  Type type() const { return static_cast<Type>(type_); }
122  void set_type(Type type) { type_ = type; }
123  const char* name() const { return name_; }
124  void set_name(const char* name) { name_ = name; }
125  SnapshotObjectId id() const { return id_; }
126  size_t self_size() const { return self_size_; }
127  unsigned trace_node_id() const { return trace_node_id_; }
128  int index() const { return index_; }
129  V8_INLINE int children_count() const;
130  V8_INLINE int set_children_index(int index);
131  V8_INLINE void add_child(HeapGraphEdge* edge);
132  V8_INLINE HeapGraphEdge* child(int i);
133  V8_INLINE Isolate* isolate() const;
134 
135  void SetIndexedReference(
136  HeapGraphEdge::Type type, int index, HeapEntry* entry);
137  void SetNamedReference(
138  HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
139  void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
140  HeapEntry* child) {
141  SetIndexedReference(type, children_count_ + 1, child);
142  }
143  void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
144  const char* description, HeapEntry* child,
145  StringsStorage* strings);
146 
147  void Print(
148  const char* prefix, const char* edge_name, int max_depth, int indent);
149 
150  private:
151  V8_INLINE std::vector<HeapGraphEdge*>::iterator children_begin() const;
152  V8_INLINE std::vector<HeapGraphEdge*>::iterator children_end() const;
153  const char* TypeAsString();
154 
155  unsigned type_: 4;
156  unsigned index_ : 28; // Supports up to ~250M objects.
157  union {
158  // The count is used during the snapshot build phase,
159  // then it gets converted into the index by the |FillChildren| function.
160  unsigned children_count_;
161  unsigned children_end_index_;
162  };
163  size_t self_size_;
164  HeapSnapshot* snapshot_;
165  const char* name_;
166  SnapshotObjectId id_;
167  // id of allocation stack trace top node
168  unsigned trace_node_id_;
169 };
170 
171 // HeapSnapshot represents a single heap snapshot. It is stored in
172 // HeapProfiler, which is also a factory for
173 // HeapSnapshots. All HeapSnapshots share strings copied from JS heap
174 // to be able to return them even if they were collected.
175 // HeapSnapshotGenerator fills in a HeapSnapshot.
177  public:
178  explicit HeapSnapshot(HeapProfiler* profiler);
179  void Delete();
180 
181  HeapProfiler* profiler() const { return profiler_; }
182  HeapEntry* root() const { return root_entry_; }
183  HeapEntry* gc_roots() const { return gc_roots_entry_; }
184  HeapEntry* gc_subroot(Root root) const {
185  return gc_subroot_entries_[static_cast<int>(root)];
186  }
187  std::deque<HeapEntry>& entries() { return entries_; }
188  std::deque<HeapGraphEdge>& edges() { return edges_; }
189  std::vector<HeapGraphEdge*>& children() { return children_; }
190  const std::vector<SourceLocation>& locations() const { return locations_; }
191  void RememberLastJSObjectId();
192  SnapshotObjectId max_snapshot_js_object_id() const {
193  return max_snapshot_js_object_id_;
194  }
195  bool is_complete() const { return !children_.empty(); }
196 
197  void AddLocation(HeapEntry* entry, int scriptId, int line, int col);
198  HeapEntry* AddEntry(HeapEntry::Type type,
199  const char* name,
200  SnapshotObjectId id,
201  size_t size,
202  unsigned trace_node_id);
203  void AddSyntheticRootEntries();
204  HeapEntry* GetEntryById(SnapshotObjectId id);
205  void FillChildren();
206 
207  void Print(int max_depth);
208 
209  private:
210  void AddRootEntry();
211  void AddGcRootsEntry();
212  void AddGcSubrootEntry(Root root, SnapshotObjectId id);
213 
214  HeapProfiler* profiler_;
215  HeapEntry* root_entry_ = nullptr;
216  HeapEntry* gc_roots_entry_ = nullptr;
217  HeapEntry* gc_subroot_entries_[static_cast<int>(Root::kNumberOfRoots)];
218  // For |entries_| we rely on the deque property, that it never reallocates
219  // backing storage, thus all entry pointers remain valid for the duration
220  // of snapshotting.
221  std::deque<HeapEntry> entries_;
222  std::deque<HeapGraphEdge> edges_;
223  std::vector<HeapGraphEdge*> children_;
224  std::unordered_map<SnapshotObjectId, HeapEntry*> entries_by_id_cache_;
225  std::vector<SourceLocation> locations_;
226  SnapshotObjectId max_snapshot_js_object_id_ = -1;
227 
228  DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
229 };
230 
231 
233  public:
234  struct TimeInterval {
235  explicit TimeInterval(SnapshotObjectId id)
236  : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
237  SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; }
238  SnapshotObjectId id;
239  uint32_t size;
240  uint32_t count;
241  base::TimeTicks timestamp;
242  };
243 
244  explicit HeapObjectsMap(Heap* heap);
245 
246  Heap* heap() const { return heap_; }
247 
248  SnapshotObjectId FindEntry(Address addr);
249  SnapshotObjectId FindOrAddEntry(Address addr,
250  unsigned int size,
251  bool accessed = true);
252  bool MoveObject(Address from, Address to, int size);
253  void UpdateObjectSize(Address addr, int size);
254  SnapshotObjectId last_assigned_id() const {
255  return next_id_ - kObjectIdStep;
256  }
257 
258  void StopHeapObjectsTracking();
259  SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
260  int64_t* timestamp_us);
261  const std::vector<TimeInterval>& samples() const { return time_intervals_; }
262 
263  SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
264 
265  static const int kObjectIdStep = 2;
266  static const SnapshotObjectId kInternalRootObjectId;
267  static const SnapshotObjectId kGcRootsObjectId;
268  static const SnapshotObjectId kGcRootsFirstSubrootId;
269  static const SnapshotObjectId kFirstAvailableObjectId;
270 
271  void UpdateHeapObjectsMap();
272  void RemoveDeadEntries();
273 
274  private:
275  struct EntryInfo {
276  EntryInfo(SnapshotObjectId id, Address addr, unsigned int size,
277  bool accessed)
278  : id(id), addr(addr), size(size), accessed(accessed) {}
279  SnapshotObjectId id;
280  Address addr;
281  unsigned int size;
282  bool accessed;
283  };
284 
285  SnapshotObjectId next_id_;
286  // TODO(jkummerow): Use a map that uses {Address} as the key type.
287  base::HashMap entries_map_;
288  std::vector<EntryInfo> entries_;
289  std::vector<TimeInterval> time_intervals_;
290  Heap* heap_;
291 
292  DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
293 };
294 
295 // A typedef for referencing anything that can be snapshotted living
296 // in any kind of heap memory.
297 typedef void* HeapThing;
298 
299 // An interface that creates HeapEntries by HeapThings.
301  public:
302  virtual ~HeapEntriesAllocator() = default;
303  virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
304 };
305 
307  public:
308  virtual ~SnapshottingProgressReportingInterface() = default;
309  virtual void ProgressStep() = 0;
310  virtual bool ProgressReport(bool force) = 0;
311 };
312 
313 // An implementation of V8 heap graph extractor.
315  public:
316  V8HeapExplorer(HeapSnapshot* snapshot,
319  ~V8HeapExplorer() override = default;
320 
321  HeapEntry* AllocateEntry(HeapThing ptr) override;
322  int EstimateObjectsCount();
323  bool IterateAndExtractReferences(HeapSnapshotGenerator* generator);
324  void TagGlobalObjects();
325  void TagCodeObject(Code code);
326  void TagBuiltinCodeObject(Code code, const char* name);
327  HeapEntry* AddEntry(Address address,
328  HeapEntry::Type type,
329  const char* name,
330  size_t size);
331 
332  static JSFunction* GetConstructor(JSReceiver* receiver);
333  static String GetConstructorName(JSObject* object);
334 
335  private:
336  void MarkVisitedField(int offset);
337 
338  HeapEntry* AddEntry(HeapObject* object);
339  HeapEntry* AddEntry(HeapObject* object,
340  HeapEntry::Type type,
341  const char* name);
342 
343  const char* GetSystemEntryName(HeapObject* object);
344 
345  void ExtractLocation(HeapEntry* entry, HeapObject* object);
346  void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction* func);
347  void ExtractReferences(HeapEntry* entry, HeapObject* obj);
348  void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy* proxy);
349  void ExtractJSObjectReferences(HeapEntry* entry, JSObject* js_obj);
350  void ExtractStringReferences(HeapEntry* entry, String obj);
351  void ExtractSymbolReferences(HeapEntry* entry, Symbol symbol);
352  void ExtractJSCollectionReferences(HeapEntry* entry,
353  JSCollection* collection);
354  void ExtractJSWeakCollectionReferences(HeapEntry* entry,
355  JSWeakCollection* collection);
356  void ExtractEphemeronHashTableReferences(HeapEntry* entry,
357  EphemeronHashTable table);
358  void ExtractContextReferences(HeapEntry* entry, Context context);
359  void ExtractMapReferences(HeapEntry* entry, Map map);
360  void ExtractSharedFunctionInfoReferences(HeapEntry* entry,
361  SharedFunctionInfo* shared);
362  void ExtractScriptReferences(HeapEntry* entry, Script* script);
363  void ExtractAccessorInfoReferences(HeapEntry* entry,
364  AccessorInfo* accessor_info);
365  void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair* accessors);
366  void ExtractCodeReferences(HeapEntry* entry, Code code);
367  void ExtractCellReferences(HeapEntry* entry, Cell* cell);
368  void ExtractFeedbackCellReferences(HeapEntry* entry,
369  FeedbackCell* feedback_cell);
370  void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell* cell);
371  void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite* site);
372  void ExtractArrayBoilerplateDescriptionReferences(
373  HeapEntry* entry, ArrayBoilerplateDescription* value);
374  void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer* buffer);
375  void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise* promise);
376  void ExtractJSGeneratorObjectReferences(HeapEntry* entry,
377  JSGeneratorObject* generator);
378  void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray array);
379  void ExtractFeedbackVectorReferences(HeapEntry* entry,
380  FeedbackVector* feedback_vector);
381  void ExtractDescriptorArrayReferences(HeapEntry* entry,
382  DescriptorArray* array);
383  template <typename T>
384  void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T* array);
385  void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
386  void ExtractAccessorPairProperty(HeapEntry* entry, Name key,
387  Object* callback_obj, int field_offset = -1);
388  void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
389  void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
390 
391  bool IsEssentialObject(Object* object);
392  bool IsEssentialHiddenReference(Object* parent, int field_offset);
393 
394  void SetContextReference(HeapEntry* parent_entry, String reference_name,
395  Object* child, int field_offset);
396  void SetNativeBindReference(HeapEntry* parent_entry,
397  const char* reference_name, Object* child);
398  void SetElementReference(HeapEntry* parent_entry, int index, Object* child);
399  void SetInternalReference(HeapEntry* parent_entry, const char* reference_name,
400  Object* child, int field_offset = -1);
401  void SetInternalReference(HeapEntry* parent_entry, int index, Object* child,
402  int field_offset = -1);
403  void SetHiddenReference(HeapObject* parent_obj, HeapEntry* parent_entry,
404  int index, Object* child, int field_offset);
405  void SetWeakReference(HeapEntry* parent_entry, const char* reference_name,
406  Object* child_obj, int field_offset);
407  void SetWeakReference(HeapEntry* parent_entry, int index, Object* child_obj,
408  int field_offset);
409  void SetPropertyReference(HeapEntry* parent_entry, Name reference_name,
410  Object* child,
411  const char* name_format_string = nullptr,
412  int field_offset = -1);
413  void SetDataOrAccessorPropertyReference(
414  PropertyKind kind, HeapEntry* parent_entry, Name reference_name,
415  Object* child, const char* name_format_string = nullptr,
416  int field_offset = -1);
417 
418  void SetUserGlobalReference(Object* user_global);
419  void SetRootGcRootsReference();
420  void SetGcRootsReference(Root root);
421  void SetGcSubrootReference(Root root, const char* description, bool is_weak,
422  Object* child);
423  const char* GetStrongGcSubrootName(Object* object);
424  void TagObject(Object* obj, const char* tag);
425 
426  HeapEntry* GetEntry(Object* obj);
427 
428  Heap* heap_;
429  HeapSnapshot* snapshot_;
430  StringsStorage* names_;
431  HeapObjectsMap* heap_object_map_;
433  HeapSnapshotGenerator* generator_ = nullptr;
434  std::unordered_map<JSGlobalObject*, const char*> objects_tags_;
435  std::unordered_map<Object*, const char*> strong_gc_subroot_names_;
436  std::unordered_set<JSGlobalObject*> user_roots_;
437  v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;
438 
439  std::vector<bool> visited_fields_;
440 
441  friend class IndexedReferencesExtractor;
442  friend class RootsReferencesExtractor;
443 
444  DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
445 };
446 
447 
449 
450 
451 // An implementation of retained native objects extractor.
453  public:
456  virtual ~NativeObjectsExplorer();
457  int EstimateObjectsCount();
458  bool IterateAndExtractReferences(HeapSnapshotGenerator* generator);
459 
460  private:
461  void FillRetainedObjects();
462  void FillEdges();
463  std::vector<HeapObject*>* GetVectorMaybeDisposeInfo(
464  v8::RetainedObjectInfo* info);
465  void SetNativeRootReference(v8::RetainedObjectInfo* info);
466  void SetRootNativeRootsReference();
467  void SetWrapperNativeReferences(HeapObject* wrapper,
468  v8::RetainedObjectInfo* info);
469  void VisitSubtreeWrapper(Object** p, uint16_t class_id);
470 
471  struct RetainedInfoHasher {
472  std::size_t operator()(v8::RetainedObjectInfo* info) const {
473  return ComputeUnseededHash(static_cast<uint32_t>(info->GetHash()));
474  }
475  };
476  struct RetainedInfoEquals {
477  bool operator()(v8::RetainedObjectInfo* info1,
478  v8::RetainedObjectInfo* info2) const {
479  return info1 == info2 || info1->IsEquivalent(info2);
480  }
481  };
482 
483  NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
484 
485  HeapEntry* EntryForEmbedderGraphNode(EmbedderGraph::Node* node);
486 
487  Isolate* isolate_;
488  HeapSnapshot* snapshot_;
489  StringsStorage* names_;
490  bool embedder_queried_;
491  std::unordered_set<Object*> in_groups_;
492  std::unordered_map<v8::RetainedObjectInfo*, std::vector<HeapObject*>*,
493  RetainedInfoHasher, RetainedInfoEquals>
494  objects_by_info_;
495  std::unordered_map<const char*, NativeGroupRetainedObjectInfo*,
497  native_groups_;
498  std::unique_ptr<HeapEntriesAllocator> synthetic_entries_allocator_;
499  std::unique_ptr<HeapEntriesAllocator> native_entries_allocator_;
500  std::unique_ptr<HeapEntriesAllocator> embedder_graph_entries_allocator_;
501  // Used during references extraction.
502  HeapSnapshotGenerator* generator_ = nullptr;
503  v8::HeapProfiler::RetainerEdges edges_;
504 
505  static HeapThing const kNativesRootObject;
506 
507  friend class GlobalHandlesExtractor;
508 
509  DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
510 };
511 
513  public:
514  // The HeapEntriesMap instance is used to track a mapping between
515  // real heap objects and their representations in heap snapshots.
516  using HeapEntriesMap = std::unordered_map<HeapThing, HeapEntry*>;
517 
519  v8::ActivityControl* control,
521  Heap* heap);
522  bool GenerateSnapshot();
523 
524  HeapEntry* FindEntry(HeapThing ptr) {
525  auto it = entries_map_.find(ptr);
526  return it != entries_map_.end() ? it->second : nullptr;
527  }
528 
529  HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
530  return entries_map_.emplace(ptr, allocator->AllocateEntry(ptr))
531  .first->second;
532  }
533 
534  HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
535  HeapEntry* entry = FindEntry(ptr);
536  return entry != nullptr ? entry : AddEntry(ptr, allocator);
537  }
538 
539  private:
540  bool FillReferences();
541  void ProgressStep() override;
542  bool ProgressReport(bool force = false) override;
543  void InitProgressCounter();
544 
545  HeapSnapshot* snapshot_;
546  v8::ActivityControl* control_;
547  V8HeapExplorer v8_heap_explorer_;
548  NativeObjectsExplorer dom_explorer_;
549  // Mapping from HeapThing pointers to HeapEntry indices.
550  HeapEntriesMap entries_map_;
551  // Used during snapshot generation.
552  int progress_counter_;
553  int progress_total_;
554  Heap* heap_;
555 
556  DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
557 };
558 
559 class OutputStreamWriter;
560 
562  public:
563  explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
564  : snapshot_(snapshot),
565  strings_(StringsMatch),
566  next_node_id_(1),
567  next_string_id_(1),
568  writer_(nullptr) {}
569  void Serialize(v8::OutputStream* stream);
570 
571  private:
572  V8_INLINE static bool StringsMatch(void* key1, void* key2) {
573  return strcmp(reinterpret_cast<char*>(key1),
574  reinterpret_cast<char*>(key2)) == 0;
575  }
576 
577  V8_INLINE static uint32_t StringHash(const void* string);
578 
579  int GetStringId(const char* s);
580  V8_INLINE int to_node_index(const HeapEntry* e);
581  V8_INLINE int to_node_index(int entry_index);
582  void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
583  void SerializeEdges();
584  void SerializeImpl();
585  void SerializeNode(const HeapEntry* entry);
586  void SerializeNodes();
587  void SerializeSnapshot();
588  void SerializeTraceTree();
589  void SerializeTraceNode(AllocationTraceNode* node);
590  void SerializeTraceNodeInfos();
591  void SerializeSamples();
592  void SerializeString(const unsigned char* s);
593  void SerializeStrings();
594  void SerializeLocation(const SourceLocation& location);
595  void SerializeLocations();
596 
597  static const int kEdgeFieldsCount;
598  static const int kNodeFieldsCount;
599 
600  HeapSnapshot* snapshot_;
601  base::CustomMatcherHashMap strings_;
602  int next_node_id_;
603  int next_string_id_;
604  OutputStreamWriter* writer_;
605 
606  friend class HeapSnapshotJSONSerializerEnumerator;
607  friend class HeapSnapshotJSONSerializerIterator;
608 
609  DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
610 };
611 
612 
613 } // namespace internal
614 } // namespace v8
615 
616 #endif // V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
virtual bool IsEquivalent(RetainedObjectInfo *other)=0
Definition: libplatform.h:13
virtual intptr_t GetHash()=0