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 "src/profile-generator-inl.h"
13 class AllocationTracker;
14 class XDKAllocationTracker;
15 class AllocationTraceNode;
20 class HeapGraphEdge BASE_EMBEDDED {
23 kContextVariable = v8::HeapGraphEdge::kContextVariable,
24 kElement = v8::HeapGraphEdge::kElement,
25 kProperty = v8::HeapGraphEdge::kProperty,
26 kInternal = v8::HeapGraphEdge::kInternal,
27 kHidden = v8::HeapGraphEdge::kHidden,
28 kShortcut = v8::HeapGraphEdge::kShortcut,
29 kWeak = v8::HeapGraphEdge::kWeak
33 HeapGraphEdge(Type type, const char* name, int from, int to);
34 HeapGraphEdge(Type type, int index, int from, int to);
35 void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
37 Type type() const { return static_cast<Type>(type_); }
39 DCHECK(type_ == kElement || type_ == kHidden);
42 const char* name() const {
43 DCHECK(type_ == kContextVariable
50 INLINE(HeapEntry* from() const);
51 HeapEntry* to() const { return to_entry_; }
54 INLINE(HeapSnapshot* snapshot() const);
59 // During entries population |to_index_| is used for storing the index,
60 // afterwards it is replaced with a pointer to the entry.
71 // HeapEntry instances represent an entity from the heap (or a special
72 // virtual node, e.g. root).
73 class HeapEntry BASE_EMBEDDED {
76 kHidden = v8::HeapGraphNode::kHidden,
77 kArray = v8::HeapGraphNode::kArray,
78 kString = v8::HeapGraphNode::kString,
79 kObject = v8::HeapGraphNode::kObject,
80 kCode = v8::HeapGraphNode::kCode,
81 kClosure = v8::HeapGraphNode::kClosure,
82 kRegExp = v8::HeapGraphNode::kRegExp,
83 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
84 kNative = v8::HeapGraphNode::kNative,
85 kSynthetic = v8::HeapGraphNode::kSynthetic,
86 kConsString = v8::HeapGraphNode::kConsString,
87 kSlicedString = v8::HeapGraphNode::kSlicedString,
88 kSymbol = v8::HeapGraphNode::kSymbol
90 static const int kNoEntry;
93 HeapEntry(HeapSnapshot* snapshot,
94 const List<HeapEntry>* entries,
99 unsigned trace_node_id);
101 HeapSnapshot* snapshot() { return snapshot_; }
102 Type type() { return static_cast<Type>(type_); }
103 const char* name() { return name_; }
104 void set_name(const char* name) { name_ = name; }
105 SnapshotObjectId id() { return id_; }
106 size_t self_size() { return self_size_; }
107 unsigned trace_node_id() const { return trace_node_id_; }
108 INLINE(int index() const);
109 int children_count() const { return children_count_; }
110 INLINE(int set_children_index(int index));
111 void add_child(HeapGraphEdge* edge) {
112 children_arr()[children_count_++] = edge;
114 Vector<HeapGraphEdge*> children() {
115 return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
117 void SetIndexedReference(
118 HeapGraphEdge::Type type, int index, HeapEntry* entry);
119 void SetNamedReference(
120 HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
123 const char* prefix, const char* edge_name, int max_depth, int indent);
126 INLINE(HeapGraphEdge** children_arr());
127 const char* TypeAsString();
130 int children_count_: 28;
133 HeapSnapshot* snapshot_;
134 const List<HeapEntry>* entries_;
136 SnapshotObjectId id_;
137 // id of allocation stack trace top node
138 unsigned trace_node_id_;
142 // HeapSnapshot represents a single heap snapshot. It is stored in
143 // HeapProfiler, which is also a factory for
144 // HeapSnapshots. All HeapSnapshots share strings copied from JS heap
145 // to be able to return them even if they were collected.
146 // HeapSnapshotGenerator fills in a HeapSnapshot.
149 HeapSnapshot(HeapProfiler* profiler,
154 HeapProfiler* profiler() { return profiler_; }
155 const char* title() { return title_; }
156 unsigned uid() { return uid_; }
157 size_t RawSnapshotSize() const;
158 HeapEntry* root() { return &entries_[root_index_]; }
159 HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
160 HeapEntry* gc_subroot(int index) {
161 return &entries_[gc_subroot_indexes_[index]];
163 List<HeapEntry>& entries() { return entries_; }
164 List<HeapGraphEdge>& edges() { return edges_; }
165 List<HeapGraphEdge*>& children() { return children_; }
166 void RememberLastJSObjectId();
167 SnapshotObjectId max_snapshot_js_object_id() const {
168 return max_snapshot_js_object_id_;
171 HeapEntry* AddEntry(HeapEntry::Type type,
175 unsigned trace_node_id);
176 void AddSyntheticRootEntries();
177 HeapEntry* GetEntryById(SnapshotObjectId id);
178 List<HeapEntry*>* GetSortedEntriesList();
181 void Print(int max_depth);
182 void PrintEntriesSize();
185 HeapEntry* AddRootEntry();
186 HeapEntry* AddGcRootsEntry();
187 HeapEntry* AddGcSubrootEntry(int tag, SnapshotObjectId id);
189 HeapProfiler* profiler_;
194 int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
195 List<HeapEntry> entries_;
196 List<HeapGraphEdge> edges_;
197 List<HeapGraphEdge*> children_;
198 List<HeapEntry*> sorted_entries_;
199 SnapshotObjectId max_snapshot_js_object_id_;
201 friend class HeapSnapshotTester;
203 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
207 class HeapObjectsMap {
209 explicit HeapObjectsMap(Heap* heap);
211 Heap* heap() const { return heap_; }
213 SnapshotObjectId FindEntry(Address addr);
214 SnapshotObjectId FindOrAddEntry(Address addr,
216 bool accessed = true);
217 bool MoveObject(Address from, Address to, int size);
218 void UpdateObjectSize(Address addr, int size);
219 SnapshotObjectId last_assigned_id() const {
220 return next_id_ - kObjectIdStep;
223 void StopHeapObjectsTracking();
224 SnapshotObjectId PushHeapObjectsStats(OutputStream* stream);
225 size_t GetUsedMemorySize() const;
227 SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info);
229 static const int kObjectIdStep = 2;
230 static const SnapshotObjectId kInternalRootObjectId;
231 static const SnapshotObjectId kGcRootsObjectId;
232 static const SnapshotObjectId kGcRootsFirstSubrootId;
233 static const SnapshotObjectId kFirstAvailableObjectId;
235 int FindUntrackedObjects();
237 void UpdateHeapObjectsMap();
238 void RemoveDeadEntries();
242 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size)
243 : id(id), addr(addr), size(size), accessed(true) { }
244 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed)
245 : id(id), addr(addr), size(size), accessed(accessed) { }
251 struct TimeInterval {
252 explicit TimeInterval(SnapshotObjectId id) : id(id), size(0), count(0) { }
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;
329 class SnapshotFiller {
331 virtual ~SnapshotFiller() {}
333 virtual HeapEntry* AddEntry(HeapThing ptr,
334 HeapEntriesAllocator* allocator) = 0;
335 virtual HeapEntry* FindEntry(HeapThing ptr) = 0;
336 virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
337 HeapEntriesAllocator* allocator) = 0;
338 virtual void SetIndexedReference(HeapGraphEdge::Type type,
341 HeapEntry* child_entry) = 0;
342 virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
344 HeapEntry* child_entry) = 0;
345 virtual void SetNamedReference(HeapGraphEdge::Type type,
347 const char* reference_name,
348 HeapEntry* child_entry) = 0;
349 virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
351 HeapEntry* child_entry) = 0;
354 // An implementation of V8 heap graph extractor.
355 class V8HeapExplorer : public HeapEntriesAllocator {
357 V8HeapExplorer(HeapProfiler* profiler,
358 HeapSnapshot* snapshot,
359 SnapshottingProgressReportingInterface* progress,
360 v8::HeapProfiler::ObjectNameResolver* resolver);
361 virtual ~V8HeapExplorer();
362 virtual HeapEntry* AllocateEntry(HeapThing ptr);
363 void AddRootEntries(SnapshotFiller* filler);
364 int EstimateObjectsCount(HeapIterator* iterator);
365 bool IterateAndExtractReferences(SnapshotFiller* filler);
366 void TagGlobalObjects();
367 void TagCodeObject(Code* code);
368 void TagBuiltinCodeObject(Code* code, const char* name);
369 HeapEntry* AddEntry(Address address,
370 HeapEntry::Type type,
374 static String* GetConstructorName(JSObject* object);
377 typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
380 HeapEntry* AddEntry(HeapObject* object);
381 HeapEntry* AddEntry(HeapObject* object,
382 HeapEntry::Type type,
385 const char* GetSystemEntryName(HeapObject* object);
387 template<V8HeapExplorer::ExtractReferencesMethod extractor>
388 bool IterateAndExtractSinglePass();
390 bool ExtractReferencesPass1(int entry, HeapObject* obj);
391 bool ExtractReferencesPass2(int entry, HeapObject* obj);
392 void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
393 void ExtractJSObjectReferences(int entry, JSObject* js_obj);
394 void ExtractStringReferences(int entry, String* obj);
395 void ExtractSymbolReferences(int entry, Symbol* symbol);
396 void ExtractJSCollectionReferences(int entry, JSCollection* collection);
397 void ExtractJSWeakCollectionReferences(int entry,
398 JSWeakCollection* collection);
399 void ExtractContextReferences(int entry, Context* context);
400 void ExtractMapReferences(int entry, Map* map);
401 void ExtractSharedFunctionInfoReferences(int entry,
402 SharedFunctionInfo* shared);
403 void ExtractScriptReferences(int entry, Script* script);
404 void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info);
405 void ExtractAccessorPairReferences(int entry, AccessorPair* accessors);
406 void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
407 void ExtractCodeReferences(int entry, Code* code);
408 void ExtractBoxReferences(int entry, Box* box);
409 void ExtractCellReferences(int entry, Cell* cell);
410 void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
411 void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
412 void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
413 void ExtractFixedArrayReferences(int entry, FixedArray* array);
414 void ExtractClosureReferences(JSObject* js_obj, int entry);
415 void ExtractPropertyReferences(JSObject* js_obj, int entry);
416 bool ExtractAccessorPairProperty(JSObject* js_obj, int entry,
417 Object* key, Object* callback_obj);
418 void ExtractElementReferences(JSObject* js_obj, int entry);
419 void ExtractInternalReferences(JSObject* js_obj, int entry);
421 bool IsEssentialObject(Object* object);
422 void SetContextReference(HeapObject* parent_obj,
424 String* reference_name,
427 void SetNativeBindReference(HeapObject* parent_obj,
429 const char* reference_name,
431 void SetElementReference(HeapObject* parent_obj,
435 void SetInternalReference(HeapObject* parent_obj,
437 const char* reference_name,
439 int field_offset = -1);
440 void SetInternalReference(HeapObject* parent_obj,
444 int field_offset = -1);
445 void SetHiddenReference(HeapObject* parent_obj,
449 void SetWeakReference(HeapObject* parent_obj,
451 const char* reference_name,
454 void SetWeakReference(HeapObject* parent_obj,
459 void SetPropertyReference(HeapObject* parent_obj,
461 Name* reference_name,
463 const char* name_format_string = NULL,
464 int field_offset = -1);
465 void SetUserGlobalReference(Object* user_global);
466 void SetRootGcRootsReference();
467 void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
468 void SetGcSubrootReference(
469 VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
470 const char* GetStrongGcSubrootName(Object* object);
471 void TagObject(Object* obj, const char* tag);
472 void MarkAsWeakContainer(Object* object);
474 HeapEntry* GetEntry(Object* obj);
477 HeapSnapshot* snapshot_;
478 StringsStorage* names_;
479 HeapObjectsMap* heap_object_map_;
480 SnapshottingProgressReportingInterface* progress_;
481 SnapshotFiller* filler_;
482 HeapObjectsSet objects_tags_;
483 HeapObjectsSet strong_gc_subroot_names_;
484 HeapObjectsSet user_roots_;
485 HeapObjectsSet weak_containers_;
486 v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;
488 friend class IndexedReferencesExtractor;
489 friend class RootsReferencesExtractor;
491 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
495 class NativeGroupRetainedObjectInfo;
498 // An implementation of retained native objects extractor.
499 class NativeObjectsExplorer {
501 NativeObjectsExplorer(HeapProfiler* profiler,
502 HeapSnapshot* snapshot,
503 SnapshottingProgressReportingInterface* progress);
504 virtual ~NativeObjectsExplorer();
505 void AddRootEntries(SnapshotFiller* filler);
506 int EstimateObjectsCount();
507 bool IterateAndExtractReferences(SnapshotFiller* filler);
510 void FillRetainedObjects();
511 void FillImplicitReferences();
512 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
513 void SetNativeRootReference(v8::RetainedObjectInfo* info);
514 void SetRootNativeRootsReference();
515 void SetWrapperNativeReferences(HeapObject* wrapper,
516 v8::RetainedObjectInfo* info);
517 void VisitSubtreeWrapper(Object** p, uint16_t class_id);
519 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
520 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
521 v8::internal::kZeroHashSeed);
523 static bool RetainedInfosMatch(void* key1, void* key2) {
524 return key1 == key2 ||
525 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
526 reinterpret_cast<v8::RetainedObjectInfo*>(key2));
528 INLINE(static bool StringsMatch(void* key1, void* key2)) {
529 return strcmp(reinterpret_cast<char*>(key1),
530 reinterpret_cast<char*>(key2)) == 0;
533 NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
536 HeapSnapshot* snapshot_;
537 StringsStorage* names_;
538 SnapshottingProgressReportingInterface* progress_;
539 bool embedder_queried_;
540 HeapObjectsSet in_groups_;
541 // RetainedObjectInfo* -> List<HeapObject*>*
542 HashMap objects_by_info_;
543 HashMap native_groups_;
544 HeapEntriesAllocator* synthetic_entries_allocator_;
545 HeapEntriesAllocator* native_entries_allocator_;
546 // Used during references extraction.
547 SnapshotFiller* filler_;
549 static HeapThing const kNativesRootObject;
551 friend class GlobalHandlesExtractor;
553 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
557 class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
559 HeapSnapshotGenerator(HeapProfiler* profiler,
560 HeapSnapshot* snapshot,
561 v8::ActivityControl* control,
562 v8::HeapProfiler::ObjectNameResolver* resolver,
564 SnapshotFiller* filler = NULL);
565 bool GenerateSnapshot();
568 bool FillReferences();
570 bool ProgressReport(bool force = false);
571 void SetProgressTotal(int iterations_count);
573 HeapSnapshot* snapshot_;
574 v8::ActivityControl* control_;
575 V8HeapExplorer v8_heap_explorer_;
576 NativeObjectsExplorer dom_explorer_;
577 // Mapping from HeapThing pointers to HeapEntry* pointers.
578 HeapEntriesMap entries_;
579 // Used during snapshot generation.
580 int progress_counter_;
583 SnapshotFiller* filler_;
585 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
588 class OutputStreamWriter;
590 class HeapSnapshotJSONSerializer {
592 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
593 : snapshot_(snapshot),
594 strings_(StringsMatch),
599 void Serialize(v8::OutputStream* stream);
602 INLINE(static bool StringsMatch(void* key1, void* key2)) {
603 return strcmp(reinterpret_cast<char*>(key1),
604 reinterpret_cast<char*>(key2)) == 0;
607 INLINE(static uint32_t StringHash(const void* string)) {
608 const char* s = reinterpret_cast<const char*>(string);
609 int len = static_cast<int>(strlen(s));
610 return StringHasher::HashSequentialString(
611 s, len, v8::internal::kZeroHashSeed);
614 int GetStringId(const char* s);
615 int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
616 void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
617 void SerializeEdges();
618 void SerializeImpl();
619 void SerializeNode(HeapEntry* entry);
620 void SerializeNodes();
621 void SerializeSnapshot();
622 void SerializeTraceTree();
623 void SerializeTraceNode(AllocationTraceNode* node);
624 void SerializeTraceNodeInfos();
625 void SerializeString(const unsigned char* s);
626 void SerializeStrings();
628 static const int kEdgeFieldsCount;
629 static const int kNodeFieldsCount;
631 HeapSnapshot* snapshot_;
635 OutputStreamWriter* writer_;
637 friend class HeapSnapshotJSONSerializerEnumerator;
638 friend class HeapSnapshotJSONSerializerIterator;
640 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
644 } } // namespace v8::internal
646 #endif // V8_HEAP_SNAPSHOT_GENERATOR_H_