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 <deque>
      9 #include <unordered_map>
     10 
     11 #include "include/v8-profiler.h"
     12 #include "src/base/platform/time.h"
     13 #include "src/objects.h"
     14 #include "src/profiler/strings-storage.h"
     15 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 class AllocationTracker;
     20 class AllocationTraceNode;
     21 class HeapEntry;
     22 class HeapIterator;
     23 class HeapProfiler;
     24 class HeapSnapshot;
     25 class SnapshotFiller;
     26 
     27 class HeapGraphEdge BASE_EMBEDDED {
     28  public:
     29   enum Type {
     30     kContextVariable = v8::HeapGraphEdge::kContextVariable,
     31     kElement = v8::HeapGraphEdge::kElement,
     32     kProperty = v8::HeapGraphEdge::kProperty,
     33     kInternal = v8::HeapGraphEdge::kInternal,
     34     kHidden = v8::HeapGraphEdge::kHidden,
     35     kShortcut = v8::HeapGraphEdge::kShortcut,
     36     kWeak = v8::HeapGraphEdge::kWeak
     37   };
     38 
     39   HeapGraphEdge(Type type, const char* name, int from, int to);
     40   HeapGraphEdge(Type type, int index, int from, int to);
     41   void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
     42 
     43   Type type() const { return TypeField::decode(bit_field_); }
     44   int index() const {
     45     DCHECK(type() == kElement || type() == kHidden);
     46     return index_;
     47   }
     48   const char* name() const {
     49     DCHECK(type() == kContextVariable || type() == kProperty ||
     50            type() == kInternal || type() == kShortcut || type() == kWeak);
     51     return name_;
     52   }
     53   INLINE(HeapEntry* from() const);
     54   HeapEntry* to() const { return to_entry_; }
     55 
     56   INLINE(Isolate* isolate() const);
     57 
     58  private:
     59   INLINE(HeapSnapshot* snapshot() const);
     60   int from_index() const { return FromIndexField::decode(bit_field_); }
     61 
     62   class TypeField : public BitField<Type, 0, 3> {};
     63   class FromIndexField : public BitField<int, 3, 29> {};
     64   uint32_t bit_field_;
     65   union {
     66     // During entries population |to_index_| is used for storing the index,
     67     // afterwards it is replaced with a pointer to the entry.
     68     int to_index_;
     69     HeapEntry* to_entry_;
     70   };
     71   union {
     72     int index_;
     73     const char* name_;
     74   };
     75 };
     76 
     77 
     78 // HeapEntry instances represent an entity from the heap (or a special
     79 // virtual node, e.g. root).
     80 class HeapEntry BASE_EMBEDDED {
     81  public:
     82   enum Type {
     83     kHidden = v8::HeapGraphNode::kHidden,
     84     kArray = v8::HeapGraphNode::kArray,
     85     kString = v8::HeapGraphNode::kString,
     86     kObject = v8::HeapGraphNode::kObject,
     87     kCode = v8::HeapGraphNode::kCode,
     88     kClosure = v8::HeapGraphNode::kClosure,
     89     kRegExp = v8::HeapGraphNode::kRegExp,
     90     kHeapNumber = v8::HeapGraphNode::kHeapNumber,
     91     kNative = v8::HeapGraphNode::kNative,
     92     kSynthetic = v8::HeapGraphNode::kSynthetic,
     93     kConsString = v8::HeapGraphNode::kConsString,
     94     kSlicedString = v8::HeapGraphNode::kSlicedString,
     95     kSymbol = v8::HeapGraphNode::kSymbol
     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_begin() + children_count_++) = edge;
    119   }
    120   HeapGraphEdge* child(int i) { return *(children_begin() + i); }
    121   INLINE(Isolate* isolate() const);
    122 
    123   void SetIndexedReference(
    124       HeapGraphEdge::Type type, int index, HeapEntry* entry);
    125   void SetNamedReference(
    126       HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
    127 
    128   void Print(
    129       const char* prefix, const char* edge_name, int max_depth, int indent);
    130 
    131  private:
    132   INLINE(std::deque<HeapGraphEdge*>::iterator children_begin());
    133   INLINE(std::deque<HeapGraphEdge*>::iterator children_end());
    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   std::deque<HeapGraphEdge>& edges() { return edges_; }
    167   std::deque<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   std::deque<HeapGraphEdge> edges_;
    196   std::deque<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 ExtractCellReferences(int entry, Cell* cell);
    389   void ExtractWeakCellReferences(int entry, WeakCell* weak_cell);
    390   void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
    391   void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
    392   void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
    393   void ExtractFixedArrayReferences(int entry, FixedArray* array);
    394   void ExtractPropertyReferences(JSObject* js_obj, int entry);
    395   void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
    396                                    Object* callback_obj, int field_offset = -1);
    397   void ExtractElementReferences(JSObject* js_obj, int entry);
    398   void ExtractInternalReferences(JSObject* js_obj, int entry);
    399 
    400   bool IsEssentialObject(Object* object);
    401   bool IsEssentialHiddenReference(Object* parent, int field_offset);
    402 
    403   void SetContextReference(HeapObject* parent_obj,
    404                            int parent,
    405                            String* reference_name,
    406                            Object* child,
    407                            int field_offset);
    408   void SetNativeBindReference(HeapObject* parent_obj,
    409                               int parent,
    410                               const char* reference_name,
    411                               Object* child);
    412   void SetElementReference(HeapObject* parent_obj,
    413                            int parent,
    414                            int index,
    415                            Object* child);
    416   void SetInternalReference(HeapObject* parent_obj,
    417                             int parent,
    418                             const char* reference_name,
    419                             Object* child,
    420                             int field_offset = -1);
    421   void SetInternalReference(HeapObject* parent_obj,
    422                             int parent,
    423                             int index,
    424                             Object* child,
    425                             int field_offset = -1);
    426   void SetHiddenReference(HeapObject* parent_obj, int parent, int index,
    427                           Object* child, int field_offset);
    428   void SetWeakReference(HeapObject* parent_obj,
    429                         int parent,
    430                         const char* reference_name,
    431                         Object* child_obj,
    432                         int field_offset);
    433   void SetWeakReference(HeapObject* parent_obj,
    434                         int parent,
    435                         int index,
    436                         Object* child_obj,
    437                         int field_offset);
    438   void SetPropertyReference(HeapObject* parent_obj,
    439                             int parent,
    440                             Name* reference_name,
    441                             Object* child,
    442                             const char* name_format_string = NULL,
    443                             int field_offset = -1);
    444   void SetDataOrAccessorPropertyReference(PropertyKind kind,
    445                                           JSObject* parent_obj, int parent,
    446                                           Name* reference_name, Object* child,
    447                                           const char* name_format_string = NULL,
    448                                           int field_offset = -1);
    449 
    450   void SetUserGlobalReference(Object* user_global);
    451   void SetRootGcRootsReference();
    452   void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
    453   void SetGcSubrootReference(
    454       VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
    455   const char* GetStrongGcSubrootName(Object* object);
    456   void TagObject(Object* obj, const char* tag);
    457   void TagFixedArraySubType(const FixedArray* array,
    458                             FixedArraySubInstanceType type);
    459 
    460   HeapEntry* GetEntry(Object* obj);
    461 
    462   Heap* heap_;
    463   HeapSnapshot* snapshot_;
    464   StringsStorage* names_;
    465   HeapObjectsMap* heap_object_map_;
    466   SnapshottingProgressReportingInterface* progress_;
    467   SnapshotFiller* filler_;
    468   HeapObjectsSet objects_tags_;
    469   HeapObjectsSet strong_gc_subroot_names_;
    470   HeapObjectsSet user_roots_;
    471   std::unordered_map<const FixedArray*, FixedArraySubInstanceType> array_types_;
    472   v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;
    473 
    474   std::vector<bool> marks_;
    475 
    476   friend class IndexedReferencesExtractor;
    477   friend class RootsReferencesExtractor;
    478 
    479   DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
    480 };
    481 
    482 
    483 class NativeGroupRetainedObjectInfo;
    484 
    485 
    486 // An implementation of retained native objects extractor.
    487 class NativeObjectsExplorer {
    488  public:
    489   NativeObjectsExplorer(HeapSnapshot* snapshot,
    490                         SnapshottingProgressReportingInterface* progress);
    491   virtual ~NativeObjectsExplorer();
    492   int EstimateObjectsCount();
    493   bool IterateAndExtractReferences(SnapshotFiller* filler);
    494 
    495  private:
    496   void FillRetainedObjects();
    497   void FillEdges();
    498   List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
    499   void SetNativeRootReference(v8::RetainedObjectInfo* info);
    500   void SetRootNativeRootsReference();
    501   void SetWrapperNativeReferences(HeapObject* wrapper,
    502                                       v8::RetainedObjectInfo* info);
    503   void VisitSubtreeWrapper(Object** p, uint16_t class_id);
    504 
    505   static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
    506     return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
    507                               v8::internal::kZeroHashSeed);
    508   }
    509   static bool RetainedInfosMatch(void* key1, void* key2) {
    510     return key1 == key2 ||
    511         (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
    512             reinterpret_cast<v8::RetainedObjectInfo*>(key2));
    513   }
    514   INLINE(static bool StringsMatch(void* key1, void* key2)) {
    515     return strcmp(reinterpret_cast<char*>(key1),
    516                   reinterpret_cast<char*>(key2)) == 0;
    517   }
    518 
    519   NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
    520 
    521   Isolate* isolate_;
    522   HeapSnapshot* snapshot_;
    523   StringsStorage* names_;
    524   bool embedder_queried_;
    525   HeapObjectsSet in_groups_;
    526   // RetainedObjectInfo* -> List<HeapObject*>*
    527   base::CustomMatcherHashMap objects_by_info_;
    528   base::CustomMatcherHashMap native_groups_;
    529   HeapEntriesAllocator* synthetic_entries_allocator_;
    530   HeapEntriesAllocator* native_entries_allocator_;
    531   // Used during references extraction.
    532   SnapshotFiller* filler_;
    533   v8::HeapProfiler::RetainerEdges edges_;
    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