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