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/strings-storage.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
31 HeapGraphEdge(Type type, const char* name, int from, int to);
32 HeapGraphEdge(Type type, int index, int from, int to);
33 void ReplaceToIndexWithEntry(HeapSnapshot* snapshot);
35 Type type() const { return TypeField::decode(bit_field_); }
37 DCHECK(type() == kElement || type() == kHidden);
40 const char* name() const {
41 DCHECK(type() == kContextVariable || type() == kProperty ||
42 type() == kInternal || type() == kShortcut || type() == kWeak);
45 INLINE(HeapEntry* from() const);
46 HeapEntry* to() const { return to_entry_; }
49 INLINE(HeapSnapshot* snapshot() const);
50 int from_index() const { return FromIndexField::decode(bit_field_); }
52 class TypeField : public BitField<Type, 0, 3> {};
53 class FromIndexField : public BitField<int, 3, 29> {};
56 // During entries population |to_index_| is used for storing the index,
57 // afterwards it is replaced with a pointer to the entry.
68 // HeapEntry instances represent an entity from the heap (or a special
69 // virtual node, e.g. root).
70 class HeapEntry BASE_EMBEDDED {
73 kHidden = v8::HeapGraphNode::kHidden,
74 kArray = v8::HeapGraphNode::kArray,
75 kString = v8::HeapGraphNode::kString,
76 kObject = v8::HeapGraphNode::kObject,
77 kCode = v8::HeapGraphNode::kCode,
78 kClosure = v8::HeapGraphNode::kClosure,
79 kRegExp = v8::HeapGraphNode::kRegExp,
80 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
81 kNative = v8::HeapGraphNode::kNative,
82 kSynthetic = v8::HeapGraphNode::kSynthetic,
83 kConsString = v8::HeapGraphNode::kConsString,
84 kSlicedString = v8::HeapGraphNode::kSlicedString,
85 kSymbol = v8::HeapGraphNode::kSymbol
87 static const int kNoEntry;
90 HeapEntry(HeapSnapshot* snapshot,
95 unsigned trace_node_id);
97 HeapSnapshot* snapshot() { return snapshot_; }
98 Type type() { return static_cast<Type>(type_); }
99 const char* name() { return name_; }
100 void set_name(const char* name) { name_ = name; }
101 SnapshotObjectId id() { return id_; }
102 size_t self_size() { return self_size_; }
103 unsigned trace_node_id() const { return trace_node_id_; }
104 INLINE(int index() const);
105 int children_count() const { return children_count_; }
106 INLINE(int set_children_index(int index));
107 void add_child(HeapGraphEdge* edge) {
108 children_arr()[children_count_++] = edge;
110 Vector<HeapGraphEdge*> children() {
111 return Vector<HeapGraphEdge*>(children_arr(), children_count_); }
113 void SetIndexedReference(
114 HeapGraphEdge::Type type, int index, HeapEntry* entry);
115 void SetNamedReference(
116 HeapGraphEdge::Type type, const char* name, HeapEntry* entry);
119 const char* prefix, const char* edge_name, int max_depth, int indent);
122 INLINE(HeapGraphEdge** children_arr());
123 const char* TypeAsString();
126 int children_count_: 28;
129 HeapSnapshot* snapshot_;
131 SnapshotObjectId id_;
132 // id of allocation stack trace top node
133 unsigned trace_node_id_;
137 // HeapSnapshot represents a single heap snapshot. It is stored in
138 // HeapProfiler, which is also a factory for
139 // HeapSnapshots. All HeapSnapshots share strings copied from JS heap
140 // to be able to return them even if they were collected.
141 // HeapSnapshotGenerator fills in a HeapSnapshot.
144 explicit HeapSnapshot(HeapProfiler* profiler);
147 HeapProfiler* profiler() { return profiler_; }
148 size_t RawSnapshotSize() const;
149 HeapEntry* root() { return &entries_[root_index_]; }
150 HeapEntry* gc_roots() { return &entries_[gc_roots_index_]; }
151 HeapEntry* gc_subroot(int index) {
152 return &entries_[gc_subroot_indexes_[index]];
154 List<HeapEntry>& entries() { return entries_; }
155 List<HeapGraphEdge>& edges() { return edges_; }
156 List<HeapGraphEdge*>& children() { return children_; }
157 void RememberLastJSObjectId();
158 SnapshotObjectId max_snapshot_js_object_id() const {
159 return max_snapshot_js_object_id_;
162 HeapEntry* AddEntry(HeapEntry::Type type,
166 unsigned trace_node_id);
167 void AddSyntheticRootEntries();
168 HeapEntry* GetEntryById(SnapshotObjectId id);
169 List<HeapEntry*>* GetSortedEntriesList();
172 void Print(int max_depth);
175 HeapEntry* AddRootEntry();
176 HeapEntry* AddGcRootsEntry();
177 HeapEntry* AddGcSubrootEntry(int tag, SnapshotObjectId id);
179 HeapProfiler* profiler_;
182 int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags];
183 List<HeapEntry> entries_;
184 List<HeapGraphEdge> edges_;
185 List<HeapGraphEdge*> children_;
186 List<HeapEntry*> sorted_entries_;
187 SnapshotObjectId max_snapshot_js_object_id_;
189 friend class HeapSnapshotTester;
191 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
195 class HeapObjectsMap {
197 struct TimeInterval {
198 explicit TimeInterval(SnapshotObjectId id)
199 : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
200 SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; }
204 base::TimeTicks timestamp;
207 explicit HeapObjectsMap(Heap* heap);
209 Heap* heap() const { return heap_; }
211 SnapshotObjectId FindEntry(Address addr);
212 SnapshotObjectId FindOrAddEntry(Address addr,
214 bool accessed = true);
215 bool MoveObject(Address from, Address to, int size);
216 void UpdateObjectSize(Address addr, int size);
217 SnapshotObjectId last_assigned_id() const {
218 return next_id_ - kObjectIdStep;
221 void StopHeapObjectsTracking();
222 SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
223 int64_t* timestamp_us);
224 const List<TimeInterval>& samples() const { return time_intervals_; }
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) { }
252 SnapshotObjectId next_id_;
253 HashMap entries_map_;
254 List<EntryInfo> entries_;
255 List<TimeInterval> time_intervals_;
258 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
262 // A typedef for referencing anything that can be snapshotted living
263 // in any kind of heap memory.
264 typedef void* HeapThing;
267 // An interface that creates HeapEntries by HeapThings.
268 class HeapEntriesAllocator {
270 virtual ~HeapEntriesAllocator() { }
271 virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
275 // The HeapEntriesMap instance is used to track a mapping between
276 // real heap objects and their representations in heap snapshots.
277 class HeapEntriesMap {
281 int Map(HeapThing thing);
282 void Pair(HeapThing thing, int entry);
285 static uint32_t Hash(HeapThing thing) {
286 return ComputeIntegerHash(
287 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)),
288 v8::internal::kZeroHashSeed);
293 friend class HeapObjectsSet;
295 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
299 class HeapObjectsSet {
303 bool Contains(Object* object);
304 void Insert(Object* obj);
305 const char* GetTag(Object* obj);
306 void SetTag(Object* obj, const char* tag);
307 bool is_empty() const { return entries_.occupancy() == 0; }
312 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
316 class SnapshottingProgressReportingInterface {
318 virtual ~SnapshottingProgressReportingInterface() { }
319 virtual void ProgressStep() = 0;
320 virtual bool ProgressReport(bool force) = 0;
324 // An implementation of V8 heap graph extractor.
325 class V8HeapExplorer : public HeapEntriesAllocator {
327 V8HeapExplorer(HeapSnapshot* snapshot,
328 SnapshottingProgressReportingInterface* progress,
329 v8::HeapProfiler::ObjectNameResolver* resolver);
330 virtual ~V8HeapExplorer();
331 virtual HeapEntry* AllocateEntry(HeapThing ptr);
332 int EstimateObjectsCount(HeapIterator* iterator);
333 bool IterateAndExtractReferences(SnapshotFiller* filler);
334 void TagGlobalObjects();
335 void TagCodeObject(Code* code);
336 void TagBuiltinCodeObject(Code* code, const char* name);
337 HeapEntry* AddEntry(Address address,
338 HeapEntry::Type type,
342 static String* GetConstructorName(JSObject* object);
345 typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry,
348 HeapEntry* AddEntry(HeapObject* object);
349 HeapEntry* AddEntry(HeapObject* object,
350 HeapEntry::Type type,
353 const char* GetSystemEntryName(HeapObject* object);
355 template<V8HeapExplorer::ExtractReferencesMethod extractor>
356 bool IterateAndExtractSinglePass();
358 bool ExtractReferencesPass1(int entry, HeapObject* obj);
359 bool ExtractReferencesPass2(int entry, HeapObject* obj);
360 void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy);
361 void ExtractJSObjectReferences(int entry, JSObject* js_obj);
362 void ExtractStringReferences(int entry, String* obj);
363 void ExtractSymbolReferences(int entry, Symbol* symbol);
364 void ExtractJSCollectionReferences(int entry, JSCollection* collection);
365 void ExtractJSWeakCollectionReferences(int entry,
366 JSWeakCollection* collection);
367 void ExtractContextReferences(int entry, Context* context);
368 void ExtractMapReferences(int entry, Map* map);
369 void ExtractSharedFunctionInfoReferences(int entry,
370 SharedFunctionInfo* shared);
371 void ExtractScriptReferences(int entry, Script* script);
372 void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info);
373 void ExtractAccessorPairReferences(int entry, AccessorPair* accessors);
374 void ExtractCodeCacheReferences(int entry, CodeCache* code_cache);
375 void ExtractCodeReferences(int entry, Code* code);
376 void ExtractBoxReferences(int entry, Box* box);
377 void ExtractCellReferences(int entry, Cell* cell);
378 void ExtractPropertyCellReferences(int entry, PropertyCell* cell);
379 void ExtractAllocationSiteReferences(int entry, AllocationSite* site);
380 void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer);
381 void ExtractFixedArrayReferences(int entry, FixedArray* array);
382 void ExtractClosureReferences(JSObject* js_obj, int entry);
383 void ExtractPropertyReferences(JSObject* js_obj, int entry);
384 void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key,
385 Object* callback_obj, int field_offset = -1);
386 void ExtractElementReferences(JSObject* js_obj, int entry);
387 void ExtractInternalReferences(JSObject* js_obj, int entry);
389 bool IsEssentialObject(Object* object);
390 void SetContextReference(HeapObject* parent_obj,
392 String* reference_name,
395 void SetNativeBindReference(HeapObject* parent_obj,
397 const char* reference_name,
399 void SetElementReference(HeapObject* parent_obj,
403 void SetInternalReference(HeapObject* parent_obj,
405 const char* reference_name,
407 int field_offset = -1);
408 void SetInternalReference(HeapObject* parent_obj,
412 int field_offset = -1);
413 void SetHiddenReference(HeapObject* parent_obj,
417 void SetWeakReference(HeapObject* parent_obj,
419 const char* reference_name,
422 void SetWeakReference(HeapObject* parent_obj,
427 void SetPropertyReference(HeapObject* parent_obj,
429 Name* reference_name,
431 const char* name_format_string = NULL,
432 int field_offset = -1);
433 void SetDataOrAccessorPropertyReference(PropertyKind kind,
434 JSObject* parent_obj, int parent,
435 Name* reference_name, Object* child,
436 const char* name_format_string = NULL,
437 int field_offset = -1);
439 void SetUserGlobalReference(Object* user_global);
440 void SetRootGcRootsReference();
441 void SetGcRootsReference(VisitorSynchronization::SyncTag tag);
442 void SetGcSubrootReference(
443 VisitorSynchronization::SyncTag tag, bool is_weak, Object* child);
444 const char* GetStrongGcSubrootName(Object* object);
445 void TagObject(Object* obj, const char* tag);
446 void MarkAsWeakContainer(Object* object);
448 HeapEntry* GetEntry(Object* obj);
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 friend class IndexedReferencesExtractor;
463 friend class RootsReferencesExtractor;
465 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
469 class NativeGroupRetainedObjectInfo;
472 // An implementation of retained native objects extractor.
473 class NativeObjectsExplorer {
475 NativeObjectsExplorer(HeapSnapshot* snapshot,
476 SnapshottingProgressReportingInterface* progress);
477 virtual ~NativeObjectsExplorer();
478 int EstimateObjectsCount();
479 bool IterateAndExtractReferences(SnapshotFiller* filler);
482 void FillRetainedObjects();
483 void FillImplicitReferences();
484 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
485 void SetNativeRootReference(v8::RetainedObjectInfo* info);
486 void SetRootNativeRootsReference();
487 void SetWrapperNativeReferences(HeapObject* wrapper,
488 v8::RetainedObjectInfo* info);
489 void VisitSubtreeWrapper(Object** p, uint16_t class_id);
491 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
492 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()),
493 v8::internal::kZeroHashSeed);
495 static bool RetainedInfosMatch(void* key1, void* key2) {
496 return key1 == key2 ||
497 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
498 reinterpret_cast<v8::RetainedObjectInfo*>(key2));
500 INLINE(static bool StringsMatch(void* key1, void* key2)) {
501 return strcmp(reinterpret_cast<char*>(key1),
502 reinterpret_cast<char*>(key2)) == 0;
505 NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label);
508 HeapSnapshot* snapshot_;
509 StringsStorage* names_;
510 bool embedder_queried_;
511 HeapObjectsSet in_groups_;
512 // RetainedObjectInfo* -> List<HeapObject*>*
513 HashMap objects_by_info_;
514 HashMap native_groups_;
515 HeapEntriesAllocator* synthetic_entries_allocator_;
516 HeapEntriesAllocator* native_entries_allocator_;
517 // Used during references extraction.
518 SnapshotFiller* filler_;
520 static HeapThing const kNativesRootObject;
522 friend class GlobalHandlesExtractor;
524 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
528 class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
530 HeapSnapshotGenerator(HeapSnapshot* snapshot,
531 v8::ActivityControl* control,
532 v8::HeapProfiler::ObjectNameResolver* resolver,
534 bool GenerateSnapshot();
537 bool FillReferences();
539 bool ProgressReport(bool force = false);
540 void SetProgressTotal(int iterations_count);
542 HeapSnapshot* snapshot_;
543 v8::ActivityControl* control_;
544 V8HeapExplorer v8_heap_explorer_;
545 NativeObjectsExplorer dom_explorer_;
546 // Mapping from HeapThing pointers to HeapEntry* pointers.
547 HeapEntriesMap entries_;
548 // Used during snapshot generation.
549 int progress_counter_;
553 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
556 class OutputStreamWriter;
558 class HeapSnapshotJSONSerializer {
560 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
561 : snapshot_(snapshot),
562 strings_(StringsMatch),
567 void Serialize(v8::OutputStream* stream);
570 INLINE(static bool StringsMatch(void* key1, void* key2)) {
571 return strcmp(reinterpret_cast<char*>(key1),
572 reinterpret_cast<char*>(key2)) == 0;
575 INLINE(static uint32_t StringHash(const void* string)) {
576 const char* s = reinterpret_cast<const char*>(string);
577 int len = static_cast<int>(strlen(s));
578 return StringHasher::HashSequentialString(
579 s, len, v8::internal::kZeroHashSeed);
582 int GetStringId(const char* s);
583 int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; }
584 void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
585 void SerializeEdges();
586 void SerializeImpl();
587 void SerializeNode(HeapEntry* entry);
588 void SerializeNodes();
589 void SerializeSnapshot();
590 void SerializeTraceTree();
591 void SerializeTraceNode(AllocationTraceNode* node);
592 void SerializeTraceNodeInfos();
593 void SerializeSamples();
594 void SerializeString(const unsigned char* s);
595 void SerializeStrings();
597 static const int kEdgeFieldsCount;
598 static const int kNodeFieldsCount;
600 HeapSnapshot* snapshot_;
604 OutputStreamWriter* writer_;
606 friend class HeapSnapshotJSONSerializerEnumerator;
607 friend class HeapSnapshotJSONSerializerIterator;
609 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
613 } } // namespace v8::internal
615 #endif // V8_HEAP_SNAPSHOT_GENERATOR_H_