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.
5 #ifndef V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
6 #define V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
8 #include "include/v8-profiler.h"
9 #include "src/base/platform/time.h"
10 #include "src/objects.h"
11 #include "src/strings-storage.h"
16 class AllocationTracker;
17 class AllocationTraceNode;
24 class HeapGraphEdge BASE_EMBEDDED {
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
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);
40 Type type() const { return TypeField::decode(bit_field_); }
42 DCHECK(type() == kElement || type() == kHidden);
45 const char* name() const {
46 DCHECK(type() == kContextVariable || type() == kProperty ||
47 type() == kInternal || type() == kShortcut || type() == kWeak);
50 INLINE(HeapEntry* from() const);
51 HeapEntry* to() const { return to_entry_; }
54 INLINE(HeapSnapshot* snapshot() const);
55 int from_index() const { return FromIndexField::decode(bit_field_); }
57 class TypeField : public BitField<Type, 0, 3> {};
58 class FromIndexField : public BitField<int, 3, 29> {};
61 // During entries population |to_index_| is used for storing the index,
62 // afterwards it is replaced with a pointer to the entry.
73 // HeapEntry instances represent an entity from the heap (or a special
74 // virtual node, e.g. root).
75 class HeapEntry BASE_EMBEDDED {
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
93 static const int kNoEntry;
96 HeapEntry(HeapSnapshot* snapshot,
101 unsigned trace_node_id);
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;
116 Vector<HeapGraphEdge*> children() {
117 return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
119 void SetIndexedReference(
120 HeapGraphEdge::Type type, int index, HeapEntry* entry);
121 void SetNamedReference(
122 HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
125 const char* prefix, const char* edge_name, int max_depth, int indent);
128 INLINE(HeapGraphEdge** children_arr());
129 const char* TypeAsString();
132 int children_count_: 28;
135 HeapSnapshot* snapshot_;
137 SnapshotObjectId id_;
138 // id of allocation stack trace top node
139 unsigned trace_node_id_;
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.
150 explicit HeapSnapshot(HeapProfiler* profiler);
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]];
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_;
168 HeapEntry* AddEntry(HeapEntry::Type type,
172 unsigned trace_node_id);
173 void AddSyntheticRootEntries();
174 HeapEntry* GetEntryById(SnapshotObjectId id);
175 List<HeapEntry*>* GetSortedEntriesList();
178 void Print(int max_depth);
181 HeapEntry* AddRootEntry();
182 HeapEntry* AddGcRootsEntry();
183 HeapEntry* AddGcSubrootEntry(int tag, SnapshotObjectId id);
185 HeapProfiler* profiler_;
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_;
195 friend class HeapSnapshotTester;
197 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
201 class HeapObjectsMap {
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; }
210 base::TimeTicks timestamp;
213 explicit HeapObjectsMap(Heap* heap);
215 Heap* heap() const { return heap_; }
217 SnapshotObjectId FindEntry(Address addr);
218 SnapshotObjectId FindOrAddEntry(Address addr,
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;
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;
233 SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
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;
241 int FindUntrackedObjects();
243 void UpdateHeapObjectsMap();
244 void RemoveDeadEntries();
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) { }
258 SnapshotObjectId next_id_;
259 HashMap entries_map_;
260 List<EntryInfo> entries_;
261 List<TimeInterval> time_intervals_;
264 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
268 // A typedef for referencing anything that can be snapshotted living
269 // in any kind of heap memory.
270 typedef void* HeapThing;
273 // An interface that creates HeapEntries by HeapThings.
274 class HeapEntriesAllocator {
276 virtual ~HeapEntriesAllocator() { }
277 virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
281 // The HeapEntriesMap instance is used to track a mapping between
282 // real heap objects and their representations in heap snapshots.
283 class HeapEntriesMap {
287 int Map(HeapThing thing);
288 void Pair(HeapThing thing, int entry);
291 static uint32_t Hash(HeapThing thing) {
292 return ComputeIntegerHash(
293 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
294 v8::internal::kZeroHashSeed);
299 friend class HeapObjectsSet;
301 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
305 class HeapObjectsSet {
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; }
318 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
322 class SnapshottingProgressReportingInterface {
324 virtual ~SnapshottingProgressReportingInterface() { }
325 virtual void ProgressStep() = 0;
326 virtual bool ProgressReport(bool force) = 0;
330 // An implementation of V8 heap graph extractor.
331 class V8HeapExplorer : public HeapEntriesAllocator {
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,
348 static String* GetConstructorName(JSObject* object);
351 typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
354 HeapEntry* AddEntry(HeapObject* object);
355 HeapEntry* AddEntry(HeapObject* object,
356 HeapEntry::Type type,
359 const char* GetSystemEntryName(HeapObject* object);
361 template<V8HeapExplorer::ExtractReferencesMethod extractor>
362 bool IterateAndExtractSinglePass();
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);
395 bool IsEssentialObject(Object* object);
396 void SetContextReference(HeapObject* parent_obj,
398 String* reference_name,
401 void SetNativeBindReference(HeapObject* parent_obj,
403 const char* reference_name,
405 void SetElementReference(HeapObject* parent_obj,
409 void SetInternalReference(HeapObject* parent_obj,
411 const char* reference_name,
413 int field_offset = -1);
414 void SetInternalReference(HeapObject* parent_obj,
418 int field_offset = -1);
419 void SetHiddenReference(HeapObject* parent_obj,
423 void SetWeakReference(HeapObject* parent_obj,
425 const char* reference_name,
428 void SetWeakReference(HeapObject* parent_obj,
433 void SetPropertyReference(HeapObject* parent_obj,
435 Name* reference_name,
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);
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);
454 HeapEntry* GetEntry(Object* obj);
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_;
468 friend class IndexedReferencesExtractor;
469 friend class RootsReferencesExtractor;
471 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
475 class NativeGroupRetainedObjectInfo;
478 // An implementation of retained native objects extractor.
479 class NativeObjectsExplorer {
481 NativeObjectsExplorer(HeapSnapshot* snapshot,
482 SnapshottingProgressReportingInterface* progress);
483 virtual ~NativeObjectsExplorer();
484 int EstimateObjectsCount();
485 bool IterateAndExtractReferences(SnapshotFiller* filler);
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);
497 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
498 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
499 v8::internal::kZeroHashSeed);
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));
506 INLINE(static bool StringsMatch(void* key1, void* key2)) {
507 return strcmp(reinterpret_cast<char*>(key1),
508 reinterpret_cast<char*>(key2)) == 0;
511 NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
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_;
526 static HeapThing const kNativesRootObject;
528 friend class GlobalHandlesExtractor;
530 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
534 class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
536 HeapSnapshotGenerator(HeapSnapshot* snapshot,
537 v8::ActivityControl* control,
538 v8::HeapProfiler::ObjectNameResolver* resolver,
540 bool GenerateSnapshot();
543 bool FillReferences();
545 bool ProgressReport(bool force = false);
546 void SetProgressTotal(int iterations_count);
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_;
559 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
562 class OutputStreamWriter;
564 class HeapSnapshotJSONSerializer {
566 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
567 : snapshot_(snapshot),
568 strings_(StringsMatch),
573 void Serialize(v8::OutputStream* stream);
576 INLINE(static bool StringsMatch(void* key1, void* key2)) {
577 return strcmp(reinterpret_cast<char*>(key1),
578 reinterpret_cast<char*>(key2)) == 0;
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);
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();
603 static const int kEdgeFieldsCount;
604 static const int kNodeFieldsCount;
606 HeapSnapshot* snapshot_;
610 OutputStreamWriter* writer_;
612 friend class HeapSnapshotJSONSerializerEnumerator;
613 friend class HeapSnapshotJSONSerializerIterator;
615 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
619 } } // namespace v8::internal
621 #endif // V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_