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