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 
type()42   Type type() const { return TypeField::decode(bit_field_); }
index()43   int index() const {
44     DCHECK(type() == kElement || type() == kHidden);
45     return index_;
46   }
name()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);
to()53   HeapEntry* to() const { return to_entry_; }
54 
55   INLINE(Isolate* isolate() const);
56 
57  private:
58   INLINE(HeapSnapshot* snapshot() const);
from_index()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 
HeapEntry()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 
snapshot()107   HeapSnapshot* snapshot() { return snapshot_; }
type()108   Type type() { return static_cast<Type>(type_); }
name()109   const char* name() { return name_; }
set_name(const char * name)110   void set_name(const char* name) { name_ = name; }
id()111   SnapshotObjectId id() { return id_; }
self_size()112   size_t self_size() { return self_size_; }
trace_node_id()113   unsigned trace_node_id() const { return trace_node_id_; }
114   INLINE(int index() const);
children_count()115   int children_count() const { return children_count_; }
116   INLINE(int set_children_index(int index));
add_child(HeapGraphEdge * edge)117   void add_child(HeapGraphEdge* edge) {
118     children_arr()[children_count_++] = edge;
119   }
children()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 
profiler()158   HeapProfiler* profiler() { return profiler_; }
159   size_t RawSnapshotSize() const;
root()160   HeapEntry* root() { return &entries_[root_index_]; }
gc_roots()161   HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
gc_subroot(int index)162   HeapEntry* gc_subroot(int index) {
163     return &entries_[gc_subroot_indexes_[index]];
164   }
entries()165   List<HeapEntry>& entries() { return entries_; }
edges()166   List<HeapGraphEdge>& edges() { return edges_; }
children()167   List<HeapGraphEdge*>& children() { return children_; }
168   void RememberLastJSObjectId();
max_snapshot_js_object_id()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 {
TimeIntervalTimeInterval209     explicit TimeInterval(SnapshotObjectId id)
210         : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
last_assigned_idTimeInterval211     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 
heap()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);
last_assigned_id()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);
samples()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 {
EntryInfoEntryInfo253   EntryInfo(SnapshotObjectId id, Address addr, unsigned int size)
254       : id(id), addr(addr), size(size), accessed(true) { }
EntryInfoEntryInfo255   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:
~HeapEntriesAllocator()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:
Hash(HeapThing thing)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);
is_empty()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:
~SnapshottingProgressReportingInterface()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 
InfoHash(v8::RetainedObjectInfo * info)506   static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
507     return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
508                               v8::internal::kZeroHashSeed);
509   }
RetainedInfosMatch(void * key1,void * key2)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   }
INLINE(static bool StringsMatch (void * key1,void * key2))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:
HeapSnapshotJSONSerializer(HeapSnapshot * snapshot)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:
INLINE(static bool StringsMatch (void * key1,void * key2))585   INLINE(static bool StringsMatch(void* key1, void* key2)) {
586     return strcmp(reinterpret_cast<char*>(key1),
587                   reinterpret_cast<char*>(key2)) == 0;
588   }
589 
INLINE(static uint32_t StringHash (const void * string))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);
entry_index(HeapEntry * e)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