Home | History | Annotate | Download | only in profiler
      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 <unordered_map>
      9 
     10 #include "include/v8-profiler.h"
     11 #include "src/base/platform/time.h"
     12 #include "src/objects.h"
     13 #include "src/profiler/strings-storage.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 class AllocationTracker;
     19 class AllocationTraceNode;
     20 class HeapEntry;
     21 class HeapIterator;
     22 class HeapProfiler;
     23 class HeapSnapshot;
     24 class SnapshotFiller;
     25 
     26 class HeapGraphEdge BASE_EMBEDDED {
     27  public:
     28   enum Type {
     29     kContextVariable = v8::HeapGraphEdge::kContextVariable,
     30     kElement = v8::HeapGraphEdge::kElement,
     31     kProperty = v8::HeapGraphEdge::kProperty,
     32     kInternal = v8::HeapGraphEdge::kInternal,
     33     kHidden = v8::HeapGraphEdge::kHidden,
     34     kShortcut = v8::HeapGraphEdge::kShortcut,
     35     kWeak = v8::HeapGraphEdge::kWeak
     36   };
     37 
     38   HeapGraphEdge(Type type, const char* name, int from, int to);
     39   HeapGraphEdge(Type type, int index, int from, int to);
     40   void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
     41 
     42   Type type() const { return TypeField::decode(bit_field_); }
     43   int index() const {
     44     DCHECK(type() == kElement || type() == kHidden);
     45     return index_;
     46   }
     47   const char* name() const {
     48     DCHECK(type() == kContextVariable || type() == kProperty ||
     49            type() == kInternal || type() == kShortcut || type() == kWeak);
     50     return name_;
     51   }
     52   INLINE(HeapEntry* from() const);
     53   HeapEntry* to() const { return to_entry_; }
     54 
     55   INLINE(Isolate* isolate() const);
     56 
     57  private:
     58   INLINE(HeapSnapshot* snapshot() const);
     59   int from_index() const { return FromIndexField::decode(bit_field_); }
     60 
     61   class TypeField : public BitField<Type, 0, 3> {};
     62   class FromIndexField : public BitField<int, 3, 29> {};
     63   uint32_t bit_field_;
     64   union {
     65     // During entries population |to_index_| is used for storing the index,
     66     // afterwards it is replaced with a pointer to the entry.
     67     int to_index_;
     68     HeapEntry* to_entry_;
     69   };
     70   union {
     71     int index_;
     72     const char* name_;
     73   };
     74 };
     75 
     76 
     77 // HeapEntry instances represent an entity from the heap (or a special
     78 // virtual node, e.g. root).
     79 class HeapEntry BASE_EMBEDDED {
     80  public:
     81   enum Type {
     82     kHidden = v8::HeapGraphNode::kHidden,
     83     kArray = v8::HeapGraphNode::kArray,
     84     kString = v8::HeapGraphNode::kString,
     85     kObject = v8::HeapGraphNode::kObject,
     86     kCode = v8::HeapGraphNode::kCode,
     87     kClosure = v8::HeapGraphNode::kClosure,
     88     kRegExp = v8::HeapGraphNode::kRegExp,
     89     kHeapNumber = v8::HeapGraphNode::kHeapNumber,
     90     kNative = v8::HeapGraphNode::kNative,
     91     kSynthetic = v8::HeapGraphNode::kSynthetic,
     92     kConsString = v8::HeapGraphNode::kConsString,
     93     kSlicedString = v8::HeapGraphNode::kSlicedString,
     94     kSymbol = v8::HeapGraphNode::kSymbol,
     95     kSimdValue = v8::HeapGraphNode::kSimdValue
     96   };
     97   static const int kNoEntry;
     98 
     99   HeapEntry() { }
    100   HeapEntry(HeapSnapshot* snapshot,
    101             Type type,
    102             const char* name,
    103             SnapshotObjectId id,
    104             size_t self_size,
    105             unsigned trace_node_id);
    106 
    107   HeapSnapshot* snapshot() { return snapshot_; }
    108   Type type() { return static_cast<Type>(type_); }
    109   const char* name() { return name_; }
    110   void set_name(const char* name) { name_ = name; }
    111   SnapshotObjectId id() { return id_; }
    112   size_t self_size() { return self_size_; }
    113   unsigned trace_node_id() const { return trace_node_id_; }
    114   INLINE(int index() const);
    115   int children_count() const { return children_count_; }
    116   INLINE(int set_children_index(int index));
    117   void add_child(HeapGraphEdge* edge) {
    118     children_arr()[children_count_++] = edge;
    119   }
    120   Vector<HeapGraphEdge*> children() {
    121     return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
    122   INLINE(Isolate* isolate() const);
    123 
    124   void SetIndexedReference(
    125       HeapGraphEdge::Type type, int index, HeapEntry* entry);
    126   void SetNamedReference(
    127       HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
    128 
    129   void Print(
    130       const char* prefix, const char* edge_name, int max_depth, int indent);
    131 
    132  private:
    133   INLINE(HeapGraphEdge** children_arr());
    134   const char* TypeAsString();
    135 
    136   unsigned type_: 4;
    137   int children_count_: 28;
    138   int children_index_;
    139   size_t self_size_;
    140   HeapSnapshot* snapshot_;
    141   const char* name_;
    142   SnapshotObjectId id_;
    143   // id of allocation stack trace top node
    144   unsigned trace_node_id_;
    145 };
    146 
    147 
    148 // HeapSnapshot represents a single heap snapshot. It is stored in
    149 // HeapProfiler, which is also a factory for
    150 // HeapSnapshots. All HeapSnapshots share strings copied from JS heap
    151 // to be able to return them even if they were collected.
    152 // HeapSnapshotGenerator fills in a HeapSnapshot.
    153 class HeapSnapshot {
    154  public:
    155   explicit HeapSnapshot(HeapProfiler* profiler);
    156   void Delete();
    157 
    158   HeapProfiler* profiler() { return profiler_; }
    159   size_t RawSnapshotSize() const;
    160   HeapEntry* root() { return &entries_[root_index_]; }
    161   HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
    162   HeapEntry* gc_subroot(int index) {
    163     return &entries_[gc_subroot_indexes_[index]];
    164   }
    165   List<HeapEntry>& entries() { return entries_; }
    166   List<HeapGraphEdge>& edges() { return edges_; }
    167   List<HeapGraphEdge*>& children() { return children_; }
    168   void RememberLastJSObjectId();
    169   SnapshotObjectId max_snapshot_js_object_id() const {
    170     return max_snapshot_js_object_id_;
    171   }
    172 
    173   HeapEntry* AddEntry(HeapEntry::Type type,
    174                       const char* name,
    175                       SnapshotObjectId id,
    176                       size_t size,
    177                       unsigned trace_node_id);
    178   void AddSyntheticRootEntries();
    179   HeapEntry* GetEntryById(SnapshotObjectId id);
    180   List<HeapEntry*>* GetSortedEntriesList();
    181   void FillChildren();
    182 
    183   void Print(int max_depth);
    184 
    185  private:
    186   HeapEntry* AddRootEntry();
    187   HeapEntry* AddGcRootsEntry();
    188   HeapEntry* AddGcSubrootEntry(int tag, SnapshotObjectId id);
    189 
    190   HeapProfiler* profiler_;
    191   int root_index_;
    192   int gc_roots_index_;
    193   int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
    194   List<HeapEntry> entries_;
    195   List<HeapGraphEdge> edges_;
    196   List<HeapGraphEdge*> children_;
    197   List<HeapEntry*> sorted_entries_;
    198   SnapshotObjectId max_snapshot_js_object_id_;
    199 
    200   friend class HeapSnapshotTester;
    201 
    202   DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
    203 };
    204 
    205 
    206 class HeapObjectsMap {
    207  public:
    208   struct TimeInterval {
    209     explicit TimeInterval(SnapshotObjectId id)
    210         : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
    211     SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; }
    212     SnapshotObjectId id;
    213     uint32_t size;
    214     uint32_t count;
    215     base::TimeTicks timestamp;
    216   };
    217 
    218   explicit HeapObjectsMap(Heap* heap);
    219 
    220   Heap* heap() const { return heap_; }
    221 
    222   SnapshotObjectId FindEntry(Address addr);
    223   SnapshotObjectId FindOrAddEntry(Address addr,
    224                                   unsigned int size,
    225                                   bool accessed = true);
    226   bool MoveObject(Address from, Address to, int size);
    227   void UpdateObjectSize(Address addr, int size);
    228   SnapshotObjectId last_assigned_id() const {
    229     return next_id_ - kObjectIdStep;
    230   }
    231 
    232   void StopHeapObjectsTracking();
    233   SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
    234                                         int64_t* timestamp_us);
    235   const List<TimeInterval>& samples() const { return time_intervals_; }
    236   size_t GetUsedMemorySize() const;
    237 
    238   SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
    239 
    240   static const int kObjectIdStep = 2;
    241   static const SnapshotObjectId kInternalRootObjectId;
    242   static const SnapshotObjectId kGcRootsObjectId;
    243   static const SnapshotObjectId kGcRootsFirstSubrootId;
    244   static const SnapshotObjectId kFirstAvailableObjectId;
    245 
    246   int FindUntrackedObjects();
    247 
    248   void UpdateHeapObjectsMap();
    249   void RemoveDeadEntries();
    250 
    251  private:
    252   struct EntryInfo {
    253   EntryInfo(SnapshotObjectId id, Address addr, unsigned int size)
    254       : id(id), addr(addr), size(size), accessed(true) { }
    255   EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed)
    256       : id(id), addr(addr), size(size), accessed(accessed) { }
    257     SnapshotObjectId id;
    258     Address addr;
    259     unsigned int size;
    260     bool accessed;
    261   };
    262 
    263   SnapshotObjectId next_id_;
    264   base::HashMap entries_map_;
    265   List<EntryInfo> entries_;
    266   List<TimeInterval> time_intervals_;
    267   Heap* heap_;
    268 
    269   DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
    270 };
    271 
    272 
    273 // A typedef for referencing anything that can be snapshotted living
    274 // in any kind of heap memory.
    275 typedef void* HeapThing;
    276 
    277 
    278 // An interface that creates HeapEntries by HeapThings.
    279 class HeapEntriesAllocator {
    280  public:
    281   virtual ~HeapEntriesAllocator() { }
    282   virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
    283 };
    284 
    285 
    286 // The HeapEntriesMap instance is used to track a mapping between
    287 // real heap objects and their representations in heap snapshots.
    288 class HeapEntriesMap {
    289  public:
    290   HeapEntriesMap();
    291 
    292   int Map(HeapThing thing);
    293   void Pair(HeapThing thing, int entry);
    294 
    295  private:
    296   static uint32_t Hash(HeapThing thing) {
    297     return ComputeIntegerHash(
    298         static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
    299         v8::internal::kZeroHashSeed);
    300   }
    301 
    302   base::HashMap entries_;
    303 
    304   friend class HeapObjectsSet;
    305 
    306   DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
    307 };
    308 
    309 
    310 class HeapObjectsSet {
    311  public:
    312   HeapObjectsSet();
    313   void Clear();
    314   bool Contains(Object* object);
    315   void Insert(Object* obj);
    316   const char* GetTag(Object* obj);
    317   void SetTag(Object* obj, const char* tag);
    318   bool is_empty() const { return entries_.occupancy() == 0; }
    319 
    320  private:
    321   base::HashMap entries_;
    322 
    323   DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
    324 };
    325 
    326 
    327 class SnapshottingProgressReportingInterface {
    328  public:
    329   virtual ~SnapshottingProgressReportingInterface() { }
    330   virtual void ProgressStep() = 0;
    331   virtual bool ProgressReport(bool force) = 0;
    332 };
    333 
    334 
    335 // An implementation of V8 heap graph extractor.
    336 class V8HeapExplorer : public HeapEntriesAllocator {
    337  public:
    338   V8HeapExplorer(HeapSnapshot* snapshot,
    339                  SnapshottingProgressReportingInterface* progress,
    340                  v8::HeapProfiler::ObjectNameResolver* resolver);
    341   virtual ~V8HeapExplorer();
    342   virtual HeapEntry* AllocateEntry(HeapThing ptr);
    343   int EstimateObjectsCount(HeapIterator* iterator);
    344   bool IterateAndExtractReferences(SnapshotFiller* filler);
    345   void TagGlobalObjects();
    346   void TagCodeObject(Code* code);
    347   void TagBuiltinCodeObject(Code* code, const char* name);
    348   HeapEntry* AddEntry(Address address,
    349                       HeapEntry::Type type,
    350                       const char* name,
    351                       size_t size);
    352 
    353   static String* GetConstructorName(JSObject* object);
    354 
    355  private:
    356   typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
    357                                                           HeapObject* object);
    358 
    359   void MarkVisitedField(HeapObject* obj, int offset);
    360 
    361   HeapEntry* AddEntry(HeapObject* object);
    362   HeapEntry* AddEntry(HeapObject* object,
    363                       HeapEntry::Type type,
    364                       const char* name);
    365 
    366   const char* GetSystemEntryName(HeapObject* object);
    367 
    368   template<V8HeapExplorer::ExtractReferencesMethod extractor>
    369   bool IterateAndExtractSinglePass();
    370 
    371   bool ExtractReferencesPass1(int entry, HeapObject* obj);
    372   bool ExtractReferencesPass2(int entry, HeapObject* obj);
    373   void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
    374   void ExtractJSObjectReferences(int entry, JSObject* js_obj);
    375   void ExtractStringReferences(int entry, String* obj);
    376   void ExtractSymbolReferences(int entry, Symbol* symbol);
    377   void ExtractJSCollectionReferences(int entry, JSCollection* collection);
    378   void ExtractJSWeakCollectionReferences(int entry,
    379                                          JSWeakCollection* collection);
    380   void ExtractContextReferences(int entry, Context* context);
    381   void ExtractMapReferences(int entry, Map* map);
    382   void ExtractSharedFunctionInfoReferences(int entry,
    383                                            SharedFunctionInfo* shared);
    384   void ExtractScriptReferences(int entry, Script* script);
    385   void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info);
    386   void ExtractAccessorPairReferences(int entry, AccessorPair* accessors);
    387   void ExtractCodeReferences(int entry, Code* code);
    388   void ExtractBoxReferences(int entry, Box* box);
    389   void ExtractCellReferences(int entry, Cell* cell);
    390   void ExtractWeakCellReferences(int entry, WeakCell* weak_cell);
    391   void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
    392   void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
    393   void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
    394   void ExtractFixedArrayReferences(int entry, FixedArray* array);
    395   void ExtractPropertyReferences(JSObject* js_obj, int entry);
    396   void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
    397                                    Object* callback_obj, int field_offset = -1);
    398   void ExtractElementReferences(JSObject* js_obj, int entry);
    399   void ExtractInternalReferences(JSObject* js_obj, int entry);
    400 
    401   bool IsEssentialObject(Object* object);
    402   bool IsEssentialHiddenReference(Object* parent, int field_offset);
    403 
    404   void SetContextReference(HeapObject* parent_obj,
    405                            int parent,
    406                            String* reference_name,
    407                            Object* child,
    408                            int field_offset);
    409   void SetNativeBindReference(HeapObject* parent_obj,
    410                               int parent,
    411                               const char* reference_name,
    412                               Object* child);
    413   void SetElementReference(HeapObject* parent_obj,
    414                            int parent,
    415                            int index,
    416                            Object* child);
    417   void SetInternalReference(HeapObject* parent_obj,
    418                             int parent,
    419                             const char* reference_name,
    420                             Object* child,
    421                             int field_offset = -1);
    422   void SetInternalReference(HeapObject* parent_obj,
    423                             int parent,
    424                             int index,
    425                             Object* child,
    426                             int field_offset = -1);
    427   void SetHiddenReference(HeapObject* parent_obj, int parent, int index,
    428                           Object* child, int field_offset);
    429   void SetWeakReference(HeapObject* parent_obj,
    430                         int parent,
    431                         const char* reference_name,
    432                         Object* child_obj,
    433                         int field_offset);
    434   void SetWeakReference(HeapObject* parent_obj,
    435                         int parent,
    436                         int index,
    437                         Object* child_obj,
    438                         int field_offset);
    439   void SetPropertyReference(HeapObject* parent_obj,
    440                             int parent,
    441                             Name* reference_name,
    442                             Object* child,
    443                             const char* name_format_string = NULL,
    444                             int field_offset = -1);
    445   void SetDataOrAccessorPropertyReference(PropertyKind kind,
    446                                           JSObject* parent_obj, int parent,
    447                                           Name* reference_name, Object* child,
    448                                           const char* name_format_string = NULL,
    449                                           int field_offset = -1);
    450 
    451   void SetUserGlobalReference(Object* user_global);
    452   void SetRootGcRootsReference();
    453   void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
    454   void SetGcSubrootReference(
    455       VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
    456   const char* GetStrongGcSubrootName(Object* object);
    457   void TagObject(Object* obj, const char* tag);
    458   void TagFixedArraySubType(const FixedArray* array,
    459                             FixedArraySubInstanceType type);
    460 
    461   HeapEntry* GetEntry(Object* obj);
    462 
    463   Heap* heap_;
    464   HeapSnapshot* snapshot_;
    465   StringsStorage* names_;
    466   HeapObjectsMap* heap_object_map_;
    467   SnapshottingProgressReportingInterface* progress_;
    468   SnapshotFiller* filler_;
    469   HeapObjectsSet objects_tags_;
    470   HeapObjectsSet strong_gc_subroot_names_;
    471   HeapObjectsSet user_roots_;
    472   std::unordered_map<const FixedArray*, FixedArraySubInstanceType> array_types_;
    473   v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;
    474 
    475   std::vector<bool> marks_;
    476 
    477   friend class IndexedReferencesExtractor;
    478   friend class RootsReferencesExtractor;
    479 
    480   DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
    481 };
    482 
    483 
    484 class NativeGroupRetainedObjectInfo;
    485 
    486 
    487 // An implementation of retained native objects extractor.
    488 class NativeObjectsExplorer {
    489  public:
    490   NativeObjectsExplorer(HeapSnapshot* snapshot,
    491                         SnapshottingProgressReportingInterface* progress);
    492   virtual ~NativeObjectsExplorer();
    493   int EstimateObjectsCount();
    494   bool IterateAndExtractReferences(SnapshotFiller* filler);
    495 
    496  private:
    497   void FillRetainedObjects();
    498   void FillImplicitReferences();
    499   List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
    500   void SetNativeRootReference(v8::RetainedObjectInfo* info);
    501   void SetRootNativeRootsReference();
    502   void SetWrapperNativeReferences(HeapObject* wrapper,
    503                                       v8::RetainedObjectInfo* info);
    504   void VisitSubtreeWrapper(Object** p, uint16_t class_id);
    505 
    506   static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
    507     return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
    508                               v8::internal::kZeroHashSeed);
    509   }
    510   static bool RetainedInfosMatch(void* key1, void* key2) {
    511     return key1 == key2 ||
    512         (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
    513             reinterpret_cast<v8::RetainedObjectInfo*>(key2));
    514   }
    515   INLINE(static bool StringsMatch(void* key1, void* key2)) {
    516     return strcmp(reinterpret_cast<char*>(key1),
    517                   reinterpret_cast<char*>(key2)) == 0;
    518   }
    519 
    520   NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
    521 
    522   Isolate* isolate_;
    523   HeapSnapshot* snapshot_;
    524   StringsStorage* names_;
    525   bool embedder_queried_;
    526   HeapObjectsSet in_groups_;
    527   // RetainedObjectInfo* -> List<HeapObject*>*
    528   base::CustomMatcherHashMap objects_by_info_;
    529   base::CustomMatcherHashMap native_groups_;
    530   HeapEntriesAllocator* synthetic_entries_allocator_;
    531   HeapEntriesAllocator* native_entries_allocator_;
    532   // Used during references extraction.
    533   SnapshotFiller* filler_;
    534 
    535   static HeapThing const kNativesRootObject;
    536 
    537   friend class GlobalHandlesExtractor;
    538 
    539   DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
    540 };
    541 
    542 
    543 class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
    544  public:
    545   HeapSnapshotGenerator(HeapSnapshot* snapshot,
    546                         v8::ActivityControl* control,
    547                         v8::HeapProfiler::ObjectNameResolver* resolver,
    548                         Heap* heap);
    549   bool GenerateSnapshot();
    550 
    551  private:
    552   bool FillReferences();
    553   void ProgressStep();
    554   bool ProgressReport(bool force = false);
    555   void SetProgressTotal(int iterations_count);
    556 
    557   HeapSnapshot* snapshot_;
    558   v8::ActivityControl* control_;
    559   V8HeapExplorer v8_heap_explorer_;
    560   NativeObjectsExplorer dom_explorer_;
    561   // Mapping from HeapThing pointers to HeapEntry* pointers.
    562   HeapEntriesMap entries_;
    563   // Used during snapshot generation.
    564   int progress_counter_;
    565   int progress_total_;
    566   Heap* heap_;
    567 
    568   DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
    569 };
    570 
    571 class OutputStreamWriter;
    572 
    573 class HeapSnapshotJSONSerializer {
    574  public:
    575   explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
    576       : snapshot_(snapshot),
    577         strings_(StringsMatch),
    578         next_node_id_(1),
    579         next_string_id_(1),
    580         writer_(NULL) {
    581   }
    582   void Serialize(v8::OutputStream* stream);
    583 
    584  private:
    585   INLINE(static bool StringsMatch(void* key1, void* key2)) {
    586     return strcmp(reinterpret_cast<char*>(key1),
    587                   reinterpret_cast<char*>(key2)) == 0;
    588   }
    589 
    590   INLINE(static uint32_t StringHash(const void* string)) {
    591     const char* s = reinterpret_cast<const char*>(string);
    592     int len = static_cast<int>(strlen(s));
    593     return StringHasher::HashSequentialString(
    594         s, len, v8::internal::kZeroHashSeed);
    595   }
    596 
    597   int GetStringId(const char* s);
    598   int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
    599   void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
    600   void SerializeEdges();
    601   void SerializeImpl();
    602   void SerializeNode(HeapEntry* entry);
    603   void SerializeNodes();
    604   void SerializeSnapshot();
    605   void SerializeTraceTree();
    606   void SerializeTraceNode(AllocationTraceNode* node);
    607   void SerializeTraceNodeInfos();
    608   void SerializeSamples();
    609   void SerializeString(const unsigned char* s);
    610   void SerializeStrings();
    611 
    612   static const int kEdgeFieldsCount;
    613   static const int kNodeFieldsCount;
    614 
    615   HeapSnapshot* snapshot_;
    616   base::CustomMatcherHashMap strings_;
    617   int next_node_id_;
    618   int next_string_id_;
    619   OutputStreamWriter* writer_;
    620 
    621   friend class HeapSnapshotJSONSerializerEnumerator;
    622   friend class HeapSnapshotJSONSerializerIterator;
    623 
    624   DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
    625 };
    626 
    627 
    628 }  // namespace internal
    629 }  // namespace v8
    630 
    631 #endif  // V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
    632