• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <deque>
9 #include <memory>
10 #include <unordered_map>
11 #include <unordered_set>
12 #include <vector>
13 
14 #include "include/v8-profiler.h"
15 #include "src/base/platform/time.h"
16 #include "src/execution/isolate.h"
17 #include "src/objects/fixed-array.h"
18 #include "src/objects/hash-table.h"
19 #include "src/objects/heap-object.h"
20 #include "src/objects/js-objects.h"
21 #include "src/objects/literal-objects.h"
22 #include "src/objects/objects.h"
23 #include "src/objects/visitors.h"
24 #include "src/profiler/strings-storage.h"
25 #include "src/strings/string-hasher.h"
26 
27 #ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
28 #include "src/heap/reference-summarizer.h"
29 #endif
30 
31 namespace v8 {
32 namespace internal {
33 
34 class AllocationTraceNode;
35 class HeapEntry;
36 class HeapProfiler;
37 class HeapSnapshot;
38 class HeapSnapshotGenerator;
39 class JSArrayBuffer;
40 class JSCollection;
41 class JSGeneratorObject;
42 class JSGlobalObject;
43 class JSGlobalProxy;
44 class JSPromise;
45 class JSWeakCollection;
46 class SafepointScope;
47 
48 struct SourceLocation {
SourceLocationSourceLocation49   SourceLocation(int entry_index, int scriptId, int line, int col)
50       : entry_index(entry_index), scriptId(scriptId), line(line), col(col) {}
51 
52   const int entry_index;
53   const int scriptId;
54   const int line;
55   const int col;
56 };
57 
58 class HeapGraphEdge {
59  public:
60   enum Type {
61     kContextVariable = v8::HeapGraphEdge::kContextVariable,
62     kElement = v8::HeapGraphEdge::kElement,
63     kProperty = v8::HeapGraphEdge::kProperty,
64     kInternal = v8::HeapGraphEdge::kInternal,
65     kHidden = v8::HeapGraphEdge::kHidden,
66     kShortcut = v8::HeapGraphEdge::kShortcut,
67     kWeak = v8::HeapGraphEdge::kWeak
68   };
69 
70   HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to);
71   HeapGraphEdge(Type type, int index, HeapEntry* from, HeapEntry* to);
72 
type()73   Type type() const { return TypeField::decode(bit_field_); }
index()74   int index() const {
75     DCHECK(type() == kElement || type() == kHidden);
76     return index_;
77   }
name()78   const char* name() const {
79     DCHECK(type() == kContextVariable || type() == kProperty ||
80            type() == kInternal || type() == kShortcut || type() == kWeak);
81     return name_;
82   }
83   V8_INLINE HeapEntry* from() const;
to()84   HeapEntry* to() const { return to_entry_; }
85 
86   V8_INLINE Isolate* isolate() const;
87 
88  private:
89   V8_INLINE HeapSnapshot* snapshot() const;
from_index()90   int from_index() const { return FromIndexField::decode(bit_field_); }
91 
92   using TypeField = base::BitField<Type, 0, 3>;
93   using FromIndexField = base::BitField<int, 3, 29>;
94   uint32_t bit_field_;
95   HeapEntry* to_entry_;
96   union {
97     int index_;
98     const char* name_;
99   };
100 };
101 
102 
103 // HeapEntry instances represent an entity from the heap (or a special
104 // virtual node, e.g. root).
105 class HeapEntry {
106  public:
107   enum Type {
108     kHidden = v8::HeapGraphNode::kHidden,
109     kArray = v8::HeapGraphNode::kArray,
110     kString = v8::HeapGraphNode::kString,
111     kObject = v8::HeapGraphNode::kObject,
112     kCode = v8::HeapGraphNode::kCode,
113     kClosure = v8::HeapGraphNode::kClosure,
114     kRegExp = v8::HeapGraphNode::kRegExp,
115     kHeapNumber = v8::HeapGraphNode::kHeapNumber,
116     kNative = v8::HeapGraphNode::kNative,
117     kSynthetic = v8::HeapGraphNode::kSynthetic,
118     kConsString = v8::HeapGraphNode::kConsString,
119     kSlicedString = v8::HeapGraphNode::kSlicedString,
120     kSymbol = v8::HeapGraphNode::kSymbol,
121     kBigInt = v8::HeapGraphNode::kBigInt
122   };
123 
124   HeapEntry(HeapSnapshot* snapshot, int index, Type type, const char* name,
125             SnapshotObjectId id, size_t self_size, unsigned trace_node_id);
126 
snapshot()127   HeapSnapshot* snapshot() { return snapshot_; }
type()128   Type type() const { return static_cast<Type>(type_); }
set_type(Type type)129   void set_type(Type type) { type_ = type; }
name()130   const char* name() const { return name_; }
set_name(const char * name)131   void set_name(const char* name) { name_ = name; }
id()132   SnapshotObjectId id() const { return id_; }
self_size()133   size_t self_size() const { return self_size_; }
add_self_size(size_t size)134   void add_self_size(size_t size) { self_size_ += size; }
trace_node_id()135   unsigned trace_node_id() const { return trace_node_id_; }
index()136   int index() const { return index_; }
137   V8_INLINE int children_count() const;
138   V8_INLINE int set_children_index(int index);
139   V8_INLINE void add_child(HeapGraphEdge* edge);
140   V8_INLINE HeapGraphEdge* child(int i);
141   V8_INLINE Isolate* isolate() const;
142 
set_detachedness(v8::EmbedderGraph::Node::Detachedness value)143   void set_detachedness(v8::EmbedderGraph::Node::Detachedness value) {
144     detachedness_ = static_cast<uint8_t>(value);
145   }
detachedness()146   uint8_t detachedness() const { return detachedness_; }
147 
148   enum ReferenceVerification {
149     // Verify that the reference can be found via marking, if verification is
150     // enabled.
151     kVerify,
152 
153     // Skip verifying that the reference can be found via marking, for any of
154     // the following reasons:
155 
156     kEphemeron,
157     kOffHeapPointer,
158     kCustomWeakPointer,
159   };
160 
161   void VerifyReference(HeapGraphEdge::Type type, HeapEntry* entry,
162                        HeapSnapshotGenerator* generator,
163                        ReferenceVerification verification);
164   void SetIndexedReference(HeapGraphEdge::Type type, int index,
165                            HeapEntry* entry, HeapSnapshotGenerator* generator,
166                            ReferenceVerification verification = kVerify);
167   void SetNamedReference(HeapGraphEdge::Type type, const char* name,
168                          HeapEntry* entry, HeapSnapshotGenerator* generator,
169                          ReferenceVerification verification = kVerify);
170   void SetIndexedAutoIndexReference(
171       HeapGraphEdge::Type type, HeapEntry* child,
172       HeapSnapshotGenerator* generator,
173       ReferenceVerification verification = kVerify) {
174     SetIndexedReference(type, children_count_ + 1, child, generator,
175                         verification);
176   }
177   void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
178                                   const char* description, HeapEntry* child,
179                                   StringsStorage* strings,
180                                   HeapSnapshotGenerator* generator,
181                                   ReferenceVerification verification = kVerify);
182 
183   V8_EXPORT_PRIVATE void Print(const char* prefix, const char* edge_name,
184                                int max_depth, int indent) const;
185 
186  private:
187   V8_INLINE std::vector<HeapGraphEdge*>::iterator children_begin() const;
188   V8_INLINE std::vector<HeapGraphEdge*>::iterator children_end() const;
189   const char* TypeAsString() const;
190 
191   unsigned type_: 4;
192   unsigned index_ : 28;  // Supports up to ~250M objects.
193   union {
194     // The count is used during the snapshot build phase,
195     // then it gets converted into the index by the |FillChildren| function.
196     unsigned children_count_;
197     unsigned children_end_index_;
198   };
199 #ifdef V8_TARGET_ARCH_64_BIT
200   size_t self_size_ : 48;
201 #else   // !V8_TARGET_ARCH_64_BIT
202   size_t self_size_;
203 #endif  // !V8_TARGET_ARCH_64_BIT
204   uint8_t detachedness_ = 0;
205   HeapSnapshot* snapshot_;
206   const char* name_;
207   SnapshotObjectId id_;
208   // id of allocation stack trace top node
209   unsigned trace_node_id_;
210 };
211 
212 // HeapSnapshot represents a single heap snapshot. It is stored in
213 // HeapProfiler, which is also a factory for
214 // HeapSnapshots. All HeapSnapshots share strings copied from JS heap
215 // to be able to return them even if they were collected.
216 // HeapSnapshotGenerator fills in a HeapSnapshot.
217 class HeapSnapshot {
218  public:
219   explicit HeapSnapshot(HeapProfiler* profiler, bool global_objects_as_roots,
220                         bool capture_numeric_value);
221   HeapSnapshot(const HeapSnapshot&) = delete;
222   HeapSnapshot& operator=(const HeapSnapshot&) = delete;
223   void Delete();
224 
profiler()225   HeapProfiler* profiler() const { return profiler_; }
root()226   HeapEntry* root() const { return root_entry_; }
gc_roots()227   HeapEntry* gc_roots() const { return gc_roots_entry_; }
gc_subroot(Root root)228   HeapEntry* gc_subroot(Root root) const {
229     return gc_subroot_entries_[static_cast<int>(root)];
230   }
entries()231   std::deque<HeapEntry>& entries() { return entries_; }
entries()232   const std::deque<HeapEntry>& entries() const { return entries_; }
edges()233   std::deque<HeapGraphEdge>& edges() { return edges_; }
edges()234   const std::deque<HeapGraphEdge>& edges() const { return edges_; }
children()235   std::vector<HeapGraphEdge*>& children() { return children_; }
locations()236   const std::vector<SourceLocation>& locations() const { return locations_; }
237   void RememberLastJSObjectId();
max_snapshot_js_object_id()238   SnapshotObjectId max_snapshot_js_object_id() const {
239     return max_snapshot_js_object_id_;
240   }
is_complete()241   bool is_complete() const { return !children_.empty(); }
treat_global_objects_as_roots()242   bool treat_global_objects_as_roots() const {
243     return treat_global_objects_as_roots_;
244   }
capture_numeric_value()245   bool capture_numeric_value() const { return capture_numeric_value_; }
246 
247   void AddLocation(HeapEntry* entry, int scriptId, int line, int col);
248   HeapEntry* AddEntry(HeapEntry::Type type,
249                       const char* name,
250                       SnapshotObjectId id,
251                       size_t size,
252                       unsigned trace_node_id);
253   void AddSyntheticRootEntries();
254   HeapEntry* GetEntryById(SnapshotObjectId id);
255   void FillChildren();
256 
257   void Print(int max_depth);
258 
259  private:
260   void AddRootEntry();
261   void AddGcRootsEntry();
262   void AddGcSubrootEntry(Root root, SnapshotObjectId id);
263 
264   HeapProfiler* profiler_;
265   HeapEntry* root_entry_ = nullptr;
266   HeapEntry* gc_roots_entry_ = nullptr;
267   HeapEntry* gc_subroot_entries_[static_cast<int>(Root::kNumberOfRoots)];
268   // For |entries_| we rely on the deque property, that it never reallocates
269   // backing storage, thus all entry pointers remain valid for the duration
270   // of snapshotting.
271   std::deque<HeapEntry> entries_;
272   std::deque<HeapGraphEdge> edges_;
273   std::vector<HeapGraphEdge*> children_;
274   std::unordered_map<SnapshotObjectId, HeapEntry*> entries_by_id_cache_;
275   std::vector<SourceLocation> locations_;
276   SnapshotObjectId max_snapshot_js_object_id_ = -1;
277   bool treat_global_objects_as_roots_;
278   bool capture_numeric_value_;
279 };
280 
281 
282 class HeapObjectsMap {
283  public:
284   struct TimeInterval {
TimeIntervalTimeInterval285     explicit TimeInterval(SnapshotObjectId id)
286         : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {}
last_assigned_idTimeInterval287     SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; }
288     SnapshotObjectId id;
289     uint32_t size;
290     uint32_t count;
291     base::TimeTicks timestamp;
292   };
293 
294   explicit HeapObjectsMap(Heap* heap);
295   HeapObjectsMap(const HeapObjectsMap&) = delete;
296   HeapObjectsMap& operator=(const HeapObjectsMap&) = delete;
297 
heap()298   Heap* heap() const { return heap_; }
299 
300   SnapshotObjectId FindEntry(Address addr);
301   SnapshotObjectId FindOrAddEntry(Address addr,
302                                   unsigned int size,
303                                   bool accessed = true);
304   SnapshotObjectId FindMergedNativeEntry(NativeObject addr);
305   void AddMergedNativeEntry(NativeObject addr, Address canonical_addr);
306   bool MoveObject(Address from, Address to, int size);
307   void UpdateObjectSize(Address addr, int size);
last_assigned_id()308   SnapshotObjectId last_assigned_id() const {
309     return next_id_ - kObjectIdStep;
310   }
get_next_id()311   SnapshotObjectId get_next_id() {
312     next_id_ += kObjectIdStep;
313     return next_id_ - kObjectIdStep;
314   }
315 
316   void StopHeapObjectsTracking();
317   SnapshotObjectId PushHeapObjectsStats(OutputStream* stream,
318                                         int64_t* timestamp_us);
samples()319   const std::vector<TimeInterval>& samples() const { return time_intervals_; }
320 
321   static const int kObjectIdStep = 2;
322   static const SnapshotObjectId kInternalRootObjectId;
323   static const SnapshotObjectId kGcRootsObjectId;
324   static const SnapshotObjectId kGcRootsFirstSubrootId;
325   static const SnapshotObjectId kFirstAvailableObjectId;
326 
327   void UpdateHeapObjectsMap();
328   void RemoveDeadEntries();
329 
330  private:
331   struct EntryInfo {
EntryInfoEntryInfo332     EntryInfo(SnapshotObjectId id, Address addr, unsigned int size,
333               bool accessed)
334         : id(id), addr(addr), size(size), accessed(accessed) {}
335     SnapshotObjectId id;
336     Address addr;
337     unsigned int size;
338     bool accessed;
339   };
340 
341   SnapshotObjectId next_id_;
342   // TODO(jkummerow): Use a map that uses {Address} as the key type.
343   base::HashMap entries_map_;
344   std::vector<EntryInfo> entries_;
345   std::vector<TimeInterval> time_intervals_;
346   // Map from NativeObject to EntryInfo index in entries_.
347   std::unordered_map<NativeObject, size_t> merged_native_entries_map_;
348   Heap* heap_;
349 };
350 
351 // A typedef for referencing anything that can be snapshotted living
352 // in any kind of heap memory.
353 using HeapThing = void*;
354 
355 // An interface that creates HeapEntries by HeapThings.
356 class HeapEntriesAllocator {
357  public:
358   virtual ~HeapEntriesAllocator() = default;
359   virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0;
360   virtual HeapEntry* AllocateEntry(Smi smi) = 0;
361 };
362 
363 class SnapshottingProgressReportingInterface {
364  public:
365   virtual ~SnapshottingProgressReportingInterface() = default;
366   virtual void ProgressStep() = 0;
367   virtual bool ProgressReport(bool force) = 0;
368 };
369 
370 // An implementation of V8 heap graph extractor.
371 class V8_EXPORT_PRIVATE V8HeapExplorer : public HeapEntriesAllocator {
372  public:
373   V8HeapExplorer(HeapSnapshot* snapshot,
374                  SnapshottingProgressReportingInterface* progress,
375                  v8::HeapProfiler::ObjectNameResolver* resolver);
376   ~V8HeapExplorer() override = default;
377   V8HeapExplorer(const V8HeapExplorer&) = delete;
378   V8HeapExplorer& operator=(const V8HeapExplorer&) = delete;
379 
isolate()380   V8_INLINE Isolate* isolate() { return Isolate::FromHeap(heap_); }
381 
382   HeapEntry* AllocateEntry(HeapThing ptr) override;
383   HeapEntry* AllocateEntry(Smi smi) override;
384   uint32_t EstimateObjectsCount();
385   bool IterateAndExtractReferences(HeapSnapshotGenerator* generator);
386   void CollectGlobalObjectsTags();
387   void MakeGlobalObjectTagMap(const SafepointScope& safepoint_scope);
388   void TagBuiltinCodeObject(CodeT code, const char* name);
389   HeapEntry* AddEntry(Address address,
390                       HeapEntry::Type type,
391                       const char* name,
392                       size_t size);
393 
394   static JSFunction GetConstructor(Isolate* isolate, JSReceiver receiver);
395   static String GetConstructorName(Isolate* isolate, JSObject object);
396 
397  private:
398   void MarkVisitedField(int offset);
399 
400   HeapEntry* AddEntry(HeapObject object);
401   HeapEntry* AddEntry(HeapObject object, HeapEntry::Type type,
402                       const char* name);
403 
404   const char* GetSystemEntryName(HeapObject object);
405   HeapEntry::Type GetSystemEntryType(HeapObject object);
406 
407   void ExtractLocation(HeapEntry* entry, HeapObject object);
408   void ExtractLocationForJSFunction(HeapEntry* entry, JSFunction func);
409   void ExtractReferences(HeapEntry* entry, HeapObject obj);
410   void ExtractJSGlobalProxyReferences(HeapEntry* entry, JSGlobalProxy proxy);
411   void ExtractJSObjectReferences(HeapEntry* entry, JSObject js_obj);
412   void ExtractStringReferences(HeapEntry* entry, String obj);
413   void ExtractSymbolReferences(HeapEntry* entry, Symbol symbol);
414   void ExtractJSCollectionReferences(HeapEntry* entry, JSCollection collection);
415   void ExtractJSWeakCollectionReferences(HeapEntry* entry,
416                                          JSWeakCollection collection);
417   void ExtractEphemeronHashTableReferences(HeapEntry* entry,
418                                            EphemeronHashTable table);
419   void ExtractContextReferences(HeapEntry* entry, Context context);
420   void ExtractMapReferences(HeapEntry* entry, Map map);
421   void ExtractSharedFunctionInfoReferences(HeapEntry* entry,
422                                            SharedFunctionInfo shared);
423   void ExtractScriptReferences(HeapEntry* entry, Script script);
424   void ExtractAccessorInfoReferences(HeapEntry* entry,
425                                      AccessorInfo accessor_info);
426   void ExtractAccessorPairReferences(HeapEntry* entry, AccessorPair accessors);
427   void ExtractCodeReferences(HeapEntry* entry, Code code);
428   void ExtractCellReferences(HeapEntry* entry, Cell cell);
429   void ExtractJSWeakRefReferences(HeapEntry* entry, JSWeakRef js_weak_ref);
430   void ExtractWeakCellReferences(HeapEntry* entry, WeakCell weak_cell);
431   void ExtractFeedbackCellReferences(HeapEntry* entry,
432                                      FeedbackCell feedback_cell);
433   void ExtractPropertyCellReferences(HeapEntry* entry, PropertyCell cell);
434   void ExtractAllocationSiteReferences(HeapEntry* entry, AllocationSite site);
435   void ExtractArrayBoilerplateDescriptionReferences(
436       HeapEntry* entry, ArrayBoilerplateDescription value);
437   void ExtractRegExpBoilerplateDescriptionReferences(
438       HeapEntry* entry, RegExpBoilerplateDescription value);
439   void ExtractJSArrayBufferReferences(HeapEntry* entry, JSArrayBuffer buffer);
440   void ExtractJSPromiseReferences(HeapEntry* entry, JSPromise promise);
441   void ExtractJSGeneratorObjectReferences(HeapEntry* entry,
442                                           JSGeneratorObject generator);
443   void ExtractFixedArrayReferences(HeapEntry* entry, FixedArray array);
444   void ExtractNumberReference(HeapEntry* entry, Object number);
445   void ExtractBytecodeArrayReferences(HeapEntry* entry, BytecodeArray bytecode);
446   void ExtractScopeInfoReferences(HeapEntry* entry, ScopeInfo info);
447   void ExtractFeedbackVectorReferences(HeapEntry* entry,
448                                        FeedbackVector feedback_vector);
449   void ExtractDescriptorArrayReferences(HeapEntry* entry,
450                                         DescriptorArray array);
451   template <typename T>
452   void ExtractWeakArrayReferences(int header_size, HeapEntry* entry, T array);
453   void ExtractPropertyReferences(JSObject js_obj, HeapEntry* entry);
454   void ExtractAccessorPairProperty(HeapEntry* entry, Name key,
455                                    Object callback_obj, int field_offset = -1);
456   void ExtractElementReferences(JSObject js_obj, HeapEntry* entry);
457   void ExtractInternalReferences(JSObject js_obj, HeapEntry* entry);
458 
459   bool IsEssentialObject(Object object);
460   bool IsEssentialHiddenReference(Object parent, int field_offset);
461 
462   void SetContextReference(HeapEntry* parent_entry, String reference_name,
463                            Object child, int field_offset);
464   void SetNativeBindReference(HeapEntry* parent_entry,
465                               const char* reference_name, Object child);
466   void SetElementReference(HeapEntry* parent_entry, int index, Object child);
467   void SetInternalReference(HeapEntry* parent_entry, const char* reference_name,
468                             Object child, int field_offset = -1);
469   void SetInternalReference(HeapEntry* parent_entry, int index, Object child,
470                             int field_offset = -1);
471   void SetHiddenReference(HeapObject parent_obj, HeapEntry* parent_entry,
472                           int index, Object child, int field_offset);
473   void SetWeakReference(
474       HeapEntry* parent_entry, const char* reference_name, Object child_obj,
475       int field_offset,
476       HeapEntry::ReferenceVerification verification = HeapEntry::kVerify);
477   void SetWeakReference(HeapEntry* parent_entry, int index, Object child_obj,
478                         base::Optional<int> field_offset);
479   void SetPropertyReference(HeapEntry* parent_entry, Name reference_name,
480                             Object child,
481                             const char* name_format_string = nullptr,
482                             int field_offset = -1);
483   void SetDataOrAccessorPropertyReference(
484       PropertyKind kind, HeapEntry* parent_entry, Name reference_name,
485       Object child, const char* name_format_string = nullptr,
486       int field_offset = -1);
487 
488   void SetUserGlobalReference(Object user_global);
489   void SetRootGcRootsReference();
490   void SetGcRootsReference(Root root);
491   void SetGcSubrootReference(Root root, const char* description, bool is_weak,
492                              Object child);
493   const char* GetStrongGcSubrootName(Object object);
494   void TagObject(Object obj, const char* tag,
495                  base::Optional<HeapEntry::Type> type = {});
496   void RecursivelyTagConstantPool(Object obj, const char* tag,
497                                   HeapEntry::Type type, int recursion_limit);
498 
499   HeapEntry* GetEntry(Object obj);
500 
501   Heap* heap_;
502   HeapSnapshot* snapshot_;
503   StringsStorage* names_;
504   HeapObjectsMap* heap_object_map_;
505   SnapshottingProgressReportingInterface* progress_;
506   HeapSnapshotGenerator* generator_ = nullptr;
507   std::vector<std::pair<Handle<JSGlobalObject>, const char*>>
508       global_object_tag_pairs_;
509   std::unordered_map<JSGlobalObject, const char*, Object::Hasher>
510       global_object_tag_map_;
511   std::unordered_map<Object, const char*, Object::Hasher>
512       strong_gc_subroot_names_;
513   std::unordered_set<JSGlobalObject, Object::Hasher> user_roots_;
514   v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_;
515 
516   std::vector<bool> visited_fields_;
517 
518   friend class IndexedReferencesExtractor;
519   friend class RootsReferencesExtractor;
520 };
521 
522 // An implementation of retained native objects extractor.
523 class NativeObjectsExplorer {
524  public:
525   NativeObjectsExplorer(HeapSnapshot* snapshot,
526                         SnapshottingProgressReportingInterface* progress);
527   NativeObjectsExplorer(const NativeObjectsExplorer&) = delete;
528   NativeObjectsExplorer& operator=(const NativeObjectsExplorer&) = delete;
529   bool IterateAndExtractReferences(HeapSnapshotGenerator* generator);
530 
531  private:
532   // Returns an entry for a given node, where node may be a V8 node or an
533   // embedder node. Returns the coresponding wrapper node if present.
534   HeapEntry* EntryForEmbedderGraphNode(EmbedderGraph::Node* node);
535   void MergeNodeIntoEntry(HeapEntry* entry, EmbedderGraph::Node* original_node,
536                           EmbedderGraph::Node* wrapper_node);
537 
538   Isolate* isolate_;
539   HeapSnapshot* snapshot_;
540   StringsStorage* names_;
541   HeapObjectsMap* heap_object_map_;
542   std::unique_ptr<HeapEntriesAllocator> embedder_graph_entries_allocator_;
543   // Used during references extraction.
544   HeapSnapshotGenerator* generator_ = nullptr;
545 
546   static HeapThing const kNativesRootObject;
547 
548   friend class GlobalHandlesExtractor;
549 };
550 
551 class HeapEntryVerifier;
552 
553 class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
554  public:
555   // The HeapEntriesMap instance is used to track a mapping between
556   // real heap objects and their representations in heap snapshots.
557   using HeapEntriesMap = std::unordered_map<HeapThing, HeapEntry*>;
558   // The SmiEntriesMap instance is used to track a mapping between smi and
559   // their representations in heap snapshots.
560   using SmiEntriesMap = std::unordered_map<int, HeapEntry*>;
561 
562   HeapSnapshotGenerator(HeapSnapshot* snapshot,
563                         v8::ActivityControl* control,
564                         v8::HeapProfiler::ObjectNameResolver* resolver,
565                         Heap* heap);
566   HeapSnapshotGenerator(const HeapSnapshotGenerator&) = delete;
567   HeapSnapshotGenerator& operator=(const HeapSnapshotGenerator&) = delete;
568   bool GenerateSnapshot();
569 
FindEntry(HeapThing ptr)570   HeapEntry* FindEntry(HeapThing ptr) {
571     auto it = entries_map_.find(ptr);
572     return it != entries_map_.end() ? it->second : nullptr;
573   }
574 
FindEntry(Smi smi)575   HeapEntry* FindEntry(Smi smi) {
576     auto it = smis_map_.find(smi.value());
577     return it != smis_map_.end() ? it->second : nullptr;
578   }
579 
AddEntry(HeapThing ptr,HeapEntriesAllocator * allocator)580   HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
581     HeapEntry* result =
582         entries_map_.emplace(ptr, allocator->AllocateEntry(ptr)).first->second;
583 #ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
584     if (FLAG_heap_snapshot_verify) {
585       reverse_entries_map_.emplace(result, ptr);
586     }
587 #endif
588     return result;
589   }
590 
591 #ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
FindHeapThingForHeapEntry(HeapEntry * entry)592   HeapThing FindHeapThingForHeapEntry(HeapEntry* entry) {
593     // The reverse lookup map is only populated if the verification flag is
594     // enabled.
595     DCHECK(FLAG_heap_snapshot_verify);
596 
597     auto it = reverse_entries_map_.find(entry);
598     return it == reverse_entries_map_.end() ? nullptr : it->second;
599   }
600 
verifier()601   HeapEntryVerifier* verifier() const { return verifier_; }
set_verifier(HeapEntryVerifier * verifier)602   void set_verifier(HeapEntryVerifier* verifier) {
603     DCHECK_IMPLIES(verifier_, !verifier);
604     verifier_ = verifier;
605   }
606 #endif
607 
AddEntry(Smi smi,HeapEntriesAllocator * allocator)608   HeapEntry* AddEntry(Smi smi, HeapEntriesAllocator* allocator) {
609     return smis_map_.emplace(smi.value(), allocator->AllocateEntry(smi))
610         .first->second;
611   }
612 
FindOrAddEntry(HeapThing ptr,HeapEntriesAllocator * allocator)613   HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) {
614     HeapEntry* entry = FindEntry(ptr);
615     return entry != nullptr ? entry : AddEntry(ptr, allocator);
616   }
617 
FindOrAddEntry(Smi smi,HeapEntriesAllocator * allocator)618   HeapEntry* FindOrAddEntry(Smi smi, HeapEntriesAllocator* allocator) {
619     HeapEntry* entry = FindEntry(smi);
620     return entry != nullptr ? entry : AddEntry(smi, allocator);
621   }
622 
heap()623   Heap* heap() const { return heap_; }
624 
625  private:
626   bool FillReferences();
627   void ProgressStep() override;
628   bool ProgressReport(bool force = false) override;
629   void InitProgressCounter();
630 
631   HeapSnapshot* snapshot_;
632   v8::ActivityControl* control_;
633   V8HeapExplorer v8_heap_explorer_;
634   NativeObjectsExplorer dom_explorer_;
635   // Mapping from HeapThing pointers to HeapEntry indices.
636   HeapEntriesMap entries_map_;
637   SmiEntriesMap smis_map_;
638   // Used during snapshot generation.
639   uint32_t progress_counter_;
640   uint32_t progress_total_;
641   Heap* heap_;
642 
643 #ifdef V8_ENABLE_HEAP_SNAPSHOT_VERIFY
644   std::unordered_map<HeapEntry*, HeapThing> reverse_entries_map_;
645   HeapEntryVerifier* verifier_ = nullptr;
646 #endif
647 };
648 
649 class OutputStreamWriter;
650 
651 class HeapSnapshotJSONSerializer {
652  public:
HeapSnapshotJSONSerializer(HeapSnapshot * snapshot)653   explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
654       : snapshot_(snapshot),
655         strings_(StringsMatch),
656         next_node_id_(1),
657         next_string_id_(1),
658         writer_(nullptr) {}
659   HeapSnapshotJSONSerializer(const HeapSnapshotJSONSerializer&) = delete;
660   HeapSnapshotJSONSerializer& operator=(const HeapSnapshotJSONSerializer&) =
661       delete;
662   void Serialize(v8::OutputStream* stream);
663 
664  private:
StringsMatch(void * key1,void * key2)665   V8_INLINE static bool StringsMatch(void* key1, void* key2) {
666     return strcmp(reinterpret_cast<char*>(key1),
667                   reinterpret_cast<char*>(key2)) == 0;
668   }
669 
670   V8_INLINE static uint32_t StringHash(const void* string);
671 
672   int GetStringId(const char* s);
673   V8_INLINE int to_node_index(const HeapEntry* e);
674   V8_INLINE int to_node_index(int entry_index);
675   void SerializeEdge(HeapGraphEdge* edge, bool first_edge);
676   void SerializeEdges();
677   void SerializeImpl();
678   void SerializeNode(const HeapEntry* entry);
679   void SerializeNodes();
680   void SerializeSnapshot();
681   void SerializeTraceTree();
682   void SerializeTraceNode(AllocationTraceNode* node);
683   void SerializeTraceNodeInfos();
684   void SerializeSamples();
685   void SerializeString(const unsigned char* s);
686   void SerializeStrings();
687   void SerializeLocation(const SourceLocation& location);
688   void SerializeLocations();
689 
690   static const int kEdgeFieldsCount;
691   static const int kNodeFieldsCount;
692 
693   HeapSnapshot* snapshot_;
694   base::CustomMatcherHashMap strings_;
695   int next_node_id_;
696   int next_string_id_;
697   OutputStreamWriter* writer_;
698 
699   friend class HeapSnapshotJSONSerializerEnumerator;
700   friend class HeapSnapshotJSONSerializerIterator;
701 };
702 
703 
704 }  // namespace internal
705 }  // namespace v8
706 
707 #endif  // V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_
708