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_HEAP_SNAPSHOT_GENERATOR_H_
6 #define V8_HEAP_SNAPSHOT_GENERATOR_H_
8 #include "profile-generator-inl.h"
13 class AllocationTracker;
14 class AllocationTraceNode;
19 class HeapGraphEdge BASE_EMBEDDED {
22 kContextVariable = v8::HeapGraphEdge::kContextVariable,
23 kElement = v8::HeapGraphEdge::kElement,
24 kProperty = v8::HeapGraphEdge::kProperty,
25 kInternal = v8::HeapGraphEdge::kInternal,
26 kHidden = v8::HeapGraphEdge::kHidden,
27 kShortcut = v8::HeapGraphEdge::kShortcut,
28 kWeak = v8::HeapGraphEdge::kWeak
32 HeapGraphEdge(Type type, const char* name, int from, int to);
33 HeapGraphEdge(Type type, int index, int from, int to);
34 void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
36 Type type() const { return static_cast<Type>(type_); }
38 ASSERT(type_ == kElement || type_ == kHidden);
41 const char* name() const {
42 ASSERT(type_ == kContextVariable
49 INLINE(HeapEntry* from() const);
50 HeapEntry* to() const { return to_entry_; }
53 INLINE(HeapSnapshot* snapshot() const);
58 // During entries population |to_index_| is used for storing the index,
59 // afterwards it is replaced with a pointer to the entry.
70 // HeapEntry instances represent an entity from the heap (or a special
71 // virtual node, e.g. root).
72 class HeapEntry BASE_EMBEDDED {
75 kHidden = v8::HeapGraphNode::kHidden,
76 kArray = v8::HeapGraphNode::kArray,
77 kString = v8::HeapGraphNode::kString,
78 kObject = v8::HeapGraphNode::kObject,
79 kCode = v8::HeapGraphNode::kCode,
80 kClosure = v8::HeapGraphNode::kClosure,
81 kRegExp = v8::HeapGraphNode::kRegExp,
82 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
83 kNative = v8::HeapGraphNode::kNative,
84 kSynthetic = v8::HeapGraphNode::kSynthetic,
85 kConsString = v8::HeapGraphNode::kConsString,
86 kSlicedString = v8::HeapGraphNode::kSlicedString
88 static const int kNoEntry;
91 HeapEntry(HeapSnapshot* snapshot,
96 unsigned trace_node_id);
98 HeapSnapshot* snapshot() { return snapshot_; }
99 Type type() { return static_cast<Type>(type_); }
100 const char* name() { return name_; }
101 void set_name(const char* name) { name_ = name; }
102 inline SnapshotObjectId id() { return id_; }
103 size_t self_size() { return self_size_; }
104 unsigned trace_node_id() const { return trace_node_id_; }
105 INLINE(int index() const);
106 int children_count() const { return children_count_; }
107 INLINE(int set_children_index(int index));
108 void add_child(HeapGraphEdge* edge) {
109 children_arr()[children_count_++] = edge;
111 Vector<HeapGraphEdge*> children() {
112 return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
114 void SetIndexedReference(
115 HeapGraphEdge::Type type, int index, HeapEntry* entry);
116 void SetNamedReference(
117 HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
120 const char* prefix, const char* edge_name, int max_depth, int indent);
123 INLINE(HeapGraphEdge** children_arr());
124 const char* TypeAsString();
127 int children_count_: 28;
130 HeapSnapshot* snapshot_;
132 SnapshotObjectId id_;
133 // id of allocation stack trace top node
134 unsigned trace_node_id_;
138 // HeapSnapshot represents a single heap snapshot. It is stored in
139 // HeapProfiler, which is also a factory for
140 // HeapSnapshots. All HeapSnapshots share strings copied from JS heap
141 // to be able to return them even if they were collected.
142 // HeapSnapshotGenerator fills in a HeapSnapshot.
145 HeapSnapshot(HeapProfiler* profiler,
150 HeapProfiler* profiler() { return profiler_; }
151 const char* title() { return title_; }
152 unsigned uid() { return uid_; }
153 size_t RawSnapshotSize() const;
154 HeapEntry* root() { return &entries_[root_index_]; }
155 HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
156 HeapEntry* natives_root() { return &entries_[natives_root_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 HeapEntry* AddRootEntry();
174 HeapEntry* AddGcRootsEntry();
175 HeapEntry* AddGcSubrootEntry(int tag);
176 HeapEntry* AddNativesRootEntry();
177 HeapEntry* GetEntryById(SnapshotObjectId id);
178 List<HeapEntry*>* GetSortedEntriesList();
181 void Print(int max_depth);
182 void PrintEntriesSize();
185 HeapProfiler* profiler_;
190 int natives_root_index_;
191 int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
192 List<HeapEntry> entries_;
193 List<HeapGraphEdge> edges_;
194 List<HeapGraphEdge*> children_;
195 List<HeapEntry*> sorted_entries_;
196 SnapshotObjectId max_snapshot_js_object_id_;
198 friend class HeapSnapshotTester;
200 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
204 class HeapObjectsMap {
206 explicit HeapObjectsMap(Heap* heap);
208 Heap* heap() const { return heap_; }
210 SnapshotObjectId FindEntry(Address addr);
211 SnapshotObjectId FindOrAddEntry(Address addr,
213 bool accessed = true);
214 bool MoveObject(Address from, Address to, int size);
215 void UpdateObjectSize(Address addr, int size);
216 SnapshotObjectId last_assigned_id() const {
217 return next_id_ - kObjectIdStep;
220 void StopHeapObjectsTracking();
221 SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
222 size_t GetUsedMemorySize() const;
224 SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
225 static inline SnapshotObjectId GetNthGcSubrootId(int delta);
227 static const int kObjectIdStep = 2;
228 static const SnapshotObjectId kInternalRootObjectId;
229 static const SnapshotObjectId kGcRootsObjectId;
230 static const SnapshotObjectId kNativesRootObjectId;
231 static const SnapshotObjectId kGcRootsFirstSubrootId;
232 static const SnapshotObjectId kFirstAvailableObjectId;
234 int FindUntrackedObjects();
236 void UpdateHeapObjectsMap();
237 void RemoveDeadEntries();
241 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size)
242 : id(id), addr(addr), size(size), accessed(true) { }
243 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed)
244 : id(id), addr(addr), size(size), accessed(accessed) { }
250 struct TimeInterval {
251 explicit TimeInterval(SnapshotObjectId id) : id(id), size(0), count(0) { }
257 SnapshotObjectId next_id_;
258 HashMap entries_map_;
259 List<EntryInfo> entries_;
260 List<TimeInterval> time_intervals_;
263 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
267 // A typedef for referencing anything that can be snapshotted living
268 // in any kind of heap memory.
269 typedef void* HeapThing;
272 // An interface that creates HeapEntries by HeapThings.
273 class HeapEntriesAllocator {
275 virtual ~HeapEntriesAllocator() { }
276 virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
280 // The HeapEntriesMap instance is used to track a mapping between
281 // real heap objects and their representations in heap snapshots.
282 class HeapEntriesMap {
286 int Map(HeapThing thing);
287 void Pair(HeapThing thing, int entry);
290 static uint32_t Hash(HeapThing thing) {
291 return ComputeIntegerHash(
292 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
293 v8::internal::kZeroHashSeed);
298 friend class HeapObjectsSet;
300 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
304 class HeapObjectsSet {
308 bool Contains(Object* object);
309 void Insert(Object* obj);
310 const char* GetTag(Object* obj);
311 void SetTag(Object* obj, const char* tag);
312 bool is_empty() const { return entries_.occupancy() == 0; }
317 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
321 class SnapshottingProgressReportingInterface {
323 virtual ~SnapshottingProgressReportingInterface() { }
324 virtual void ProgressStep() = 0;
325 virtual bool ProgressReport(bool force) = 0;
329 // An implementation of V8 heap graph extractor.
330 class V8HeapExplorer : public HeapEntriesAllocator {
332 V8HeapExplorer(HeapSnapshot* snapshot,
333 SnapshottingProgressReportingInterface* progress,
334 v8::HeapProfiler::ObjectNameResolver* resolver);
335 virtual ~V8HeapExplorer();
336 virtual HeapEntry* AllocateEntry(HeapThing ptr);
337 void AddRootEntries(SnapshotFiller* filler);
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);
350 static HeapObject* const kInternalRootObject;
353 typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
356 HeapEntry* AddEntry(HeapObject* object);
357 HeapEntry* AddEntry(HeapObject* object,
358 HeapEntry::Type type,
361 const char* GetSystemEntryName(HeapObject* object);
363 template<V8HeapExplorer::ExtractReferencesMethod extractor>
364 bool IterateAndExtractSinglePass();
366 bool ExtractReferencesPass1(int entry, HeapObject* obj);
367 bool ExtractReferencesPass2(int entry, HeapObject* obj);
368 void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
369 void ExtractJSObjectReferences(int entry, JSObject* js_obj);
370 void ExtractStringReferences(int entry, String* obj);
371 void ExtractContextReferences(int entry, Context* context);
372 void ExtractMapReferences(int entry, Map* map);
373 void ExtractSharedFunctionInfoReferences(int entry,
374 SharedFunctionInfo* shared);
375 void ExtractScriptReferences(int entry, Script* script);
376 void ExtractAccessorPairReferences(int entry, AccessorPair* accessors);
377 void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
378 void ExtractCodeReferences(int entry, Code* code);
379 void ExtractBoxReferences(int entry, Box* box);
380 void ExtractCellReferences(int entry, Cell* cell);
381 void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
382 void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
383 void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
384 void ExtractFixedArrayReferences(int entry, FixedArray* array);
385 void ExtractClosureReferences(JSObject* js_obj, int entry);
386 void ExtractPropertyReferences(JSObject* js_obj, int entry);
387 bool ExtractAccessorPairProperty(JSObject* js_obj, int entry,
388 Object* key, Object* callback_obj);
389 void ExtractElementReferences(JSObject* js_obj, int entry);
390 void ExtractInternalReferences(JSObject* js_obj, int entry);
392 bool IsEssentialObject(Object* object);
393 void SetContextReference(HeapObject* parent_obj,
395 String* reference_name,
398 void SetNativeBindReference(HeapObject* parent_obj,
400 const char* reference_name,
402 void SetElementReference(HeapObject* parent_obj,
406 void SetInternalReference(HeapObject* parent_obj,
408 const char* reference_name,
410 int field_offset = -1);
411 void SetInternalReference(HeapObject* parent_obj,
415 int field_offset = -1);
416 void SetHiddenReference(HeapObject* parent_obj,
420 void SetWeakReference(HeapObject* parent_obj,
422 const char* reference_name,
425 void SetWeakReference(HeapObject* parent_obj,
430 void SetPropertyReference(HeapObject* parent_obj,
432 Name* reference_name,
434 const char* name_format_string = NULL,
435 int field_offset = -1);
436 void SetUserGlobalReference(Object* user_global);
437 void SetRootGcRootsReference();
438 void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
439 void SetGcSubrootReference(
440 VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
441 const char* GetStrongGcSubrootName(Object* object);
442 void TagObject(Object* obj, const char* tag);
443 void MarkAsWeakContainer(Object* object);
445 HeapEntry* GetEntry(Object* obj);
447 static inline HeapObject* GetNthGcSubrootObject(int delta);
448 static inline int GetGcSubrootOrder(HeapObject* subroot);
451 HeapSnapshot* snapshot_;
452 StringsStorage* names_;
453 HeapObjectsMap* heap_object_map_;
454 SnapshottingProgressReportingInterface* progress_;
455 SnapshotFiller* filler_;
456 HeapObjectsSet objects_tags_;
457 HeapObjectsSet strong_gc_subroot_names_;
458 HeapObjectsSet user_roots_;
459 HeapObjectsSet weak_containers_;
460 v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;
462 static HeapObject* const kGcRootsObject;
463 static HeapObject* const kFirstGcSubrootObject;
464 static HeapObject* const kLastGcSubrootObject;
466 friend class IndexedReferencesExtractor;
467 friend class GcSubrootsEnumerator;
468 friend class RootsReferencesExtractor;
470 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
474 class NativeGroupRetainedObjectInfo;
477 // An implementation of retained native objects extractor.
478 class NativeObjectsExplorer {
480 NativeObjectsExplorer(HeapSnapshot* snapshot,
481 SnapshottingProgressReportingInterface* progress);
482 virtual ~NativeObjectsExplorer();
483 void AddRootEntries(SnapshotFiller* filler);
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 SnapshottingProgressReportingInterface* progress_;
517 bool embedder_queried_;
518 HeapObjectsSet in_groups_;
519 // RetainedObjectInfo* -> List<HeapObject*>*
520 HashMap objects_by_info_;
521 HashMap native_groups_;
522 HeapEntriesAllocator* synthetic_entries_allocator_;
523 HeapEntriesAllocator* native_entries_allocator_;
524 // Used during references extraction.
525 SnapshotFiller* filler_;
527 static HeapThing const kNativesRootObject;
529 friend class GlobalHandlesExtractor;
531 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
535 class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
537 HeapSnapshotGenerator(HeapSnapshot* snapshot,
538 v8::ActivityControl* control,
539 v8::HeapProfiler::ObjectNameResolver* resolver,
541 bool GenerateSnapshot();
544 bool FillReferences();
546 bool ProgressReport(bool force = false);
547 void SetProgressTotal(int iterations_count);
549 HeapSnapshot* snapshot_;
550 v8::ActivityControl* control_;
551 V8HeapExplorer v8_heap_explorer_;
552 NativeObjectsExplorer dom_explorer_;
553 // Mapping from HeapThing pointers to HeapEntry* pointers.
554 HeapEntriesMap entries_;
555 // Used during snapshot generation.
556 int progress_counter_;
560 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
563 class OutputStreamWriter;
565 class HeapSnapshotJSONSerializer {
567 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
568 : snapshot_(snapshot),
569 strings_(StringsMatch),
574 void Serialize(v8::OutputStream* stream);
577 INLINE(static bool StringsMatch(void* key1, void* key2)) {
578 return strcmp(reinterpret_cast<char*>(key1),
579 reinterpret_cast<char*>(key2)) == 0;
582 INLINE(static uint32_t StringHash(const void* string)) {
583 const char* s = reinterpret_cast<const char*>(string);
584 int len = static_cast<int>(strlen(s));
585 return StringHasher::HashSequentialString(
586 s, len, v8::internal::kZeroHashSeed);
589 int GetStringId(const char* s);
590 int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
591 void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
592 void SerializeEdges();
593 void SerializeImpl();
594 void SerializeNode(HeapEntry* entry);
595 void SerializeNodes();
596 void SerializeSnapshot();
597 void SerializeTraceTree();
598 void SerializeTraceNode(AllocationTraceNode* node);
599 void SerializeTraceNodeInfos();
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_HEAP_SNAPSHOT_GENERATOR_H_