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