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 "include/v8-profiler.h" 9#include "src/base/platform/time.h" 10#include "src/objects.h" 11#include "src/profiler/strings-storage.h" 12 13namespace v8 { 14namespace internal { 15 16class AllocationTracker; 17class AllocationTraceNode; 18class HeapEntry; 19class HeapIterator; 20class HeapProfiler; 21class HeapSnapshot; 22class SnapshotFiller; 23 24class HeapGraphEdge BASE_EMBEDDED { 25 public: 26 enum Type { 27 kContextVariable = v8::HeapGraphEdge::kContextVariable, 28 kElement = v8::HeapGraphEdge::kElement, 29 kProperty = v8::HeapGraphEdge::kProperty, 30 kInternal = v8::HeapGraphEdge::kInternal, 31 kHidden = v8::HeapGraphEdge::kHidden, 32 kShortcut = v8::HeapGraphEdge::kShortcut, 33 kWeak = v8::HeapGraphEdge::kWeak 34 }; 35 36 HeapGraphEdge(Type type, const char* name, int from, int to); 37 HeapGraphEdge(Type type, int index, int from, int to); 38 void ReplaceToIndexWithEntry(HeapSnapshot* snapshot); 39 40 Type type() const { return TypeField::decode(bit_field_); } 41 int index() const { 42 DCHECK(type() == kElement || type() == kHidden); 43 return index_; 44 } 45 const char* name() const { 46 DCHECK(type() == kContextVariable || type() == kProperty || 47 type() == kInternal || type() == kShortcut || type() == kWeak); 48 return name_; 49 } 50 INLINE(HeapEntry* from() const); 51 HeapEntry* to() const { return to_entry_; } 52 53 INLINE(Isolate* isolate() const); 54 55 private: 56 INLINE(HeapSnapshot* snapshot() const); 57 int from_index() const { return FromIndexField::decode(bit_field_); } 58 59 class TypeField : public BitField<Type, 0, 3> {}; 60 class FromIndexField : public BitField<int, 3, 29> {}; 61 uint32_t bit_field_; 62 union { 63 // During entries population |to_index_| is used for storing the index, 64 // afterwards it is replaced with a pointer to the entry. 65 int to_index_; 66 HeapEntry* to_entry_; 67 }; 68 union { 69 int index_; 70 const char* name_; 71 }; 72}; 73 74 75// HeapEntry instances represent an entity from the heap (or a special 76// virtual node, e.g. root). 77class HeapEntry BASE_EMBEDDED { 78 public: 79 enum Type { 80 kHidden = v8::HeapGraphNode::kHidden, 81 kArray = v8::HeapGraphNode::kArray, 82 kString = v8::HeapGraphNode::kString, 83 kObject = v8::HeapGraphNode::kObject, 84 kCode = v8::HeapGraphNode::kCode, 85 kClosure = v8::HeapGraphNode::kClosure, 86 kRegExp = v8::HeapGraphNode::kRegExp, 87 kHeapNumber = v8::HeapGraphNode::kHeapNumber, 88 kNative = v8::HeapGraphNode::kNative, 89 kSynthetic = v8::HeapGraphNode::kSynthetic, 90 kConsString = v8::HeapGraphNode::kConsString, 91 kSlicedString = v8::HeapGraphNode::kSlicedString, 92 kSymbol = v8::HeapGraphNode::kSymbol, 93 kSimdValue = v8::HeapGraphNode::kSimdValue 94 }; 95 static const int kNoEntry; 96 97 HeapEntry() { } 98 HeapEntry(HeapSnapshot* snapshot, 99 Type type, 100 const char* name, 101 SnapshotObjectId id, 102 size_t self_size, 103 unsigned trace_node_id); 104 105 HeapSnapshot* snapshot() { return snapshot_; } 106 Type type() { return static_cast<Type>(type_); } 107 const char* name() { return name_; } 108 void set_name(const char* name) { name_ = name; } 109 SnapshotObjectId id() { return id_; } 110 size_t self_size() { return self_size_; } 111 unsigned trace_node_id() const { return trace_node_id_; } 112 INLINE(int index() const); 113 int children_count() const { return children_count_; } 114 INLINE(int set_children_index(int index)); 115 void add_child(HeapGraphEdge* edge) { 116 children_arr()[children_count_++] = edge; 117 } 118 Vector<HeapGraphEdge*> children() { 119 return Vector<HeapGraphEdge*>(children_arr(), children_count_); } 120 INLINE(Isolate* isolate() const); 121 122 void SetIndexedReference( 123 HeapGraphEdge::Type type, int index, HeapEntry* entry); 124 void SetNamedReference( 125 HeapGraphEdge::Type type, const char* name, HeapEntry* entry); 126 127 void Print( 128 const char* prefix, const char* edge_name, int max_depth, int indent); 129 130 private: 131 INLINE(HeapGraphEdge** children_arr()); 132 const char* TypeAsString(); 133 134 unsigned type_: 4; 135 int children_count_: 28; 136 int children_index_; 137 size_t self_size_; 138 HeapSnapshot* snapshot_; 139 const char* name_; 140 SnapshotObjectId id_; 141 // id of allocation stack trace top node 142 unsigned trace_node_id_; 143}; 144 145 146// HeapSnapshot represents a single heap snapshot. It is stored in 147// HeapProfiler, which is also a factory for 148// HeapSnapshots. All HeapSnapshots share strings copied from JS heap 149// to be able to return them even if they were collected. 150// HeapSnapshotGenerator fills in a HeapSnapshot. 151class HeapSnapshot { 152 public: 153 explicit HeapSnapshot(HeapProfiler* profiler); 154 void Delete(); 155 156 HeapProfiler* profiler() { return profiler_; } 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]]; 162 } 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_; 169 } 170 171 HeapEntry* AddEntry(HeapEntry::Type type, 172 const char* name, 173 SnapshotObjectId id, 174 size_t size, 175 unsigned trace_node_id); 176 void AddSyntheticRootEntries(); 177 HeapEntry* GetEntryById(SnapshotObjectId id); 178 List<HeapEntry*>* GetSortedEntriesList(); 179 void FillChildren(); 180 181 void Print(int max_depth); 182 183 private: 184 HeapEntry* AddRootEntry(); 185 HeapEntry* AddGcRootsEntry(); 186 HeapEntry* AddGcSubrootEntry(int tag, SnapshotObjectId id); 187 188 HeapProfiler* profiler_; 189 int root_index_; 190 int gc_roots_index_; 191 int gc_subroot_indexes_[VisitorSynchronization::kNumberOfSyncTags]; 192 List<HeapEntry> entries_; 193 List<HeapGraphEdge> edges_; 194 List<HeapGraphEdge*> children_; 195 List<HeapEntry*> sorted_entries_; 196 SnapshotObjectId max_snapshot_js_object_id_; 197 198 friend class HeapSnapshotTester; 199 200 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot); 201}; 202 203 204class HeapObjectsMap { 205 public: 206 struct TimeInterval { 207 explicit TimeInterval(SnapshotObjectId id) 208 : id(id), size(0), count(0), timestamp(base::TimeTicks::Now()) {} 209 SnapshotObjectId last_assigned_id() const { return id - kObjectIdStep; } 210 SnapshotObjectId id; 211 uint32_t size; 212 uint32_t count; 213 base::TimeTicks timestamp; 214 }; 215 216 explicit HeapObjectsMap(Heap* heap); 217 218 Heap* heap() const { return heap_; } 219 220 SnapshotObjectId FindEntry(Address addr); 221 SnapshotObjectId FindOrAddEntry(Address addr, 222 unsigned int size, 223 bool accessed = true); 224 bool MoveObject(Address from, Address to, int size); 225 void UpdateObjectSize(Address addr, int size); 226 SnapshotObjectId last_assigned_id() const { 227 return next_id_ - kObjectIdStep; 228 } 229 230 void StopHeapObjectsTracking(); 231 SnapshotObjectId PushHeapObjectsStats(OutputStream* stream, 232 int64_t* timestamp_us); 233 const List<TimeInterval>& samples() const { return time_intervals_; } 234 size_t GetUsedMemorySize() const; 235 236 SnapshotObjectId GenerateId(v8::RetainedObjectInfo* info); 237 238 static const int kObjectIdStep = 2; 239 static const SnapshotObjectId kInternalRootObjectId; 240 static const SnapshotObjectId kGcRootsObjectId; 241 static const SnapshotObjectId kGcRootsFirstSubrootId; 242 static const SnapshotObjectId kFirstAvailableObjectId; 243 244 int FindUntrackedObjects(); 245 246 void UpdateHeapObjectsMap(); 247 void RemoveDeadEntries(); 248 249 private: 250 struct EntryInfo { 251 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size) 252 : id(id), addr(addr), size(size), accessed(true) { } 253 EntryInfo(SnapshotObjectId id, Address addr, unsigned int size, bool accessed) 254 : id(id), addr(addr), size(size), accessed(accessed) { } 255 SnapshotObjectId id; 256 Address addr; 257 unsigned int size; 258 bool accessed; 259 }; 260 261 SnapshotObjectId next_id_; 262 base::HashMap entries_map_; 263 List<EntryInfo> entries_; 264 List<TimeInterval> time_intervals_; 265 Heap* heap_; 266 267 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap); 268}; 269 270 271// A typedef for referencing anything that can be snapshotted living 272// in any kind of heap memory. 273typedef void* HeapThing; 274 275 276// An interface that creates HeapEntries by HeapThings. 277class HeapEntriesAllocator { 278 public: 279 virtual ~HeapEntriesAllocator() { } 280 virtual HeapEntry* AllocateEntry(HeapThing ptr) = 0; 281}; 282 283 284// The HeapEntriesMap instance is used to track a mapping between 285// real heap objects and their representations in heap snapshots. 286class HeapEntriesMap { 287 public: 288 HeapEntriesMap(); 289 290 int Map(HeapThing thing); 291 void Pair(HeapThing thing, int entry); 292 293 private: 294 static uint32_t Hash(HeapThing thing) { 295 return ComputeIntegerHash( 296 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)), 297 v8::internal::kZeroHashSeed); 298 } 299 300 base::HashMap entries_; 301 302 friend class HeapObjectsSet; 303 304 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap); 305}; 306 307 308class HeapObjectsSet { 309 public: 310 HeapObjectsSet(); 311 void Clear(); 312 bool Contains(Object* object); 313 void Insert(Object* obj); 314 const char* GetTag(Object* obj); 315 void SetTag(Object* obj, const char* tag); 316 bool is_empty() const { return entries_.occupancy() == 0; } 317 318 private: 319 base::HashMap entries_; 320 321 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet); 322}; 323 324 325class SnapshottingProgressReportingInterface { 326 public: 327 virtual ~SnapshottingProgressReportingInterface() { } 328 virtual void ProgressStep() = 0; 329 virtual bool ProgressReport(bool force) = 0; 330}; 331 332 333// An implementation of V8 heap graph extractor. 334class V8HeapExplorer : public HeapEntriesAllocator { 335 public: 336 V8HeapExplorer(HeapSnapshot* snapshot, 337 SnapshottingProgressReportingInterface* progress, 338 v8::HeapProfiler::ObjectNameResolver* resolver); 339 virtual ~V8HeapExplorer(); 340 virtual HeapEntry* AllocateEntry(HeapThing ptr); 341 int EstimateObjectsCount(HeapIterator* iterator); 342 bool IterateAndExtractReferences(SnapshotFiller* filler); 343 void TagGlobalObjects(); 344 void TagCodeObject(Code* code); 345 void TagBuiltinCodeObject(Code* code, const char* name); 346 HeapEntry* AddEntry(Address address, 347 HeapEntry::Type type, 348 const char* name, 349 size_t size); 350 351 static String* GetConstructorName(JSObject* object); 352 353 private: 354 typedef bool (V8HeapExplorer::*ExtractReferencesMethod)(int entry, 355 HeapObject* object); 356 357 void MarkVisitedField(HeapObject* obj, int offset); 358 359 HeapEntry* AddEntry(HeapObject* object); 360 HeapEntry* AddEntry(HeapObject* object, 361 HeapEntry::Type type, 362 const char* name); 363 364 const char* GetSystemEntryName(HeapObject* object); 365 366 template<V8HeapExplorer::ExtractReferencesMethod extractor> 367 bool IterateAndExtractSinglePass(); 368 369 bool ExtractReferencesPass1(int entry, HeapObject* obj); 370 bool ExtractReferencesPass2(int entry, HeapObject* obj); 371 void ExtractJSGlobalProxyReferences(int entry, JSGlobalProxy* proxy); 372 void ExtractJSObjectReferences(int entry, JSObject* js_obj); 373 void ExtractStringReferences(int entry, String* obj); 374 void ExtractSymbolReferences(int entry, Symbol* symbol); 375 void ExtractJSCollectionReferences(int entry, JSCollection* collection); 376 void ExtractJSWeakCollectionReferences(int entry, 377 JSWeakCollection* collection); 378 void ExtractContextReferences(int entry, Context* context); 379 void ExtractMapReferences(int entry, Map* map); 380 void ExtractSharedFunctionInfoReferences(int entry, 381 SharedFunctionInfo* shared); 382 void ExtractScriptReferences(int entry, Script* script); 383 void ExtractAccessorInfoReferences(int entry, AccessorInfo* accessor_info); 384 void ExtractAccessorPairReferences(int entry, AccessorPair* accessors); 385 void ExtractCodeReferences(int entry, Code* code); 386 void ExtractBoxReferences(int entry, Box* box); 387 void ExtractCellReferences(int entry, Cell* cell); 388 void ExtractPropertyCellReferences(int entry, PropertyCell* cell); 389 void ExtractAllocationSiteReferences(int entry, AllocationSite* site); 390 void ExtractJSArrayBufferReferences(int entry, JSArrayBuffer* buffer); 391 void ExtractFixedArrayReferences(int entry, FixedArray* array); 392 void ExtractPropertyReferences(JSObject* js_obj, int entry); 393 void ExtractAccessorPairProperty(JSObject* js_obj, int entry, Name* key, 394 Object* callback_obj, int field_offset = -1); 395 void ExtractElementReferences(JSObject* js_obj, int entry); 396 void ExtractInternalReferences(JSObject* js_obj, int entry); 397 398 bool IsEssentialObject(Object* object); 399 void SetContextReference(HeapObject* parent_obj, 400 int parent, 401 String* reference_name, 402 Object* child, 403 int field_offset); 404 void SetNativeBindReference(HeapObject* parent_obj, 405 int parent, 406 const char* reference_name, 407 Object* child); 408 void SetElementReference(HeapObject* parent_obj, 409 int parent, 410 int index, 411 Object* child); 412 void SetInternalReference(HeapObject* parent_obj, 413 int parent, 414 const char* reference_name, 415 Object* child, 416 int field_offset = -1); 417 void SetInternalReference(HeapObject* parent_obj, 418 int parent, 419 int index, 420 Object* child, 421 int field_offset = -1); 422 void SetHiddenReference(HeapObject* parent_obj, 423 int parent, 424 int index, 425 Object* child); 426 void SetWeakReference(HeapObject* parent_obj, 427 int parent, 428 const char* reference_name, 429 Object* child_obj, 430 int field_offset); 431 void SetWeakReference(HeapObject* parent_obj, 432 int parent, 433 int index, 434 Object* child_obj, 435 int field_offset); 436 void SetPropertyReference(HeapObject* parent_obj, 437 int parent, 438 Name* reference_name, 439 Object* child, 440 const char* name_format_string = NULL, 441 int field_offset = -1); 442 void SetDataOrAccessorPropertyReference(PropertyKind kind, 443 JSObject* parent_obj, int parent, 444 Name* reference_name, Object* child, 445 const char* name_format_string = NULL, 446 int field_offset = -1); 447 448 void SetUserGlobalReference(Object* user_global); 449 void SetRootGcRootsReference(); 450 void SetGcRootsReference(VisitorSynchronization::SyncTag tag); 451 void SetGcSubrootReference( 452 VisitorSynchronization::SyncTag tag, bool is_weak, Object* child); 453 const char* GetStrongGcSubrootName(Object* object); 454 void TagObject(Object* obj, const char* tag); 455 void MarkAsWeakContainer(Object* object); 456 457 HeapEntry* GetEntry(Object* obj); 458 459 Heap* heap_; 460 HeapSnapshot* snapshot_; 461 StringsStorage* names_; 462 HeapObjectsMap* heap_object_map_; 463 SnapshottingProgressReportingInterface* progress_; 464 SnapshotFiller* filler_; 465 HeapObjectsSet objects_tags_; 466 HeapObjectsSet strong_gc_subroot_names_; 467 HeapObjectsSet user_roots_; 468 HeapObjectsSet weak_containers_; 469 v8::HeapProfiler::ObjectNameResolver* global_object_name_resolver_; 470 471 std::vector<bool> marks_; 472 473 friend class IndexedReferencesExtractor; 474 friend class RootsReferencesExtractor; 475 476 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer); 477}; 478 479 480class NativeGroupRetainedObjectInfo; 481 482 483// An implementation of retained native objects extractor. 484class NativeObjectsExplorer { 485 public: 486 NativeObjectsExplorer(HeapSnapshot* snapshot, 487 SnapshottingProgressReportingInterface* progress); 488 virtual ~NativeObjectsExplorer(); 489 int EstimateObjectsCount(); 490 bool IterateAndExtractReferences(SnapshotFiller* filler); 491 492 private: 493 void FillRetainedObjects(); 494 void FillImplicitReferences(); 495 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info); 496 void SetNativeRootReference(v8::RetainedObjectInfo* info); 497 void SetRootNativeRootsReference(); 498 void SetWrapperNativeReferences(HeapObject* wrapper, 499 v8::RetainedObjectInfo* info); 500 void VisitSubtreeWrapper(Object** p, uint16_t class_id); 501 502 static uint32_t InfoHash(v8::RetainedObjectInfo* info) { 503 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()), 504 v8::internal::kZeroHashSeed); 505 } 506 static bool RetainedInfosMatch(void* key1, void* key2) { 507 return key1 == key2 || 508 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent( 509 reinterpret_cast<v8::RetainedObjectInfo*>(key2)); 510 } 511 INLINE(static bool StringsMatch(void* key1, void* key2)) { 512 return strcmp(reinterpret_cast<char*>(key1), 513 reinterpret_cast<char*>(key2)) == 0; 514 } 515 516 NativeGroupRetainedObjectInfo* FindOrAddGroupInfo(const char* label); 517 518 Isolate* isolate_; 519 HeapSnapshot* snapshot_; 520 StringsStorage* names_; 521 bool embedder_queried_; 522 HeapObjectsSet in_groups_; 523 // RetainedObjectInfo* -> List<HeapObject*>* 524 base::HashMap objects_by_info_; 525 base::HashMap native_groups_; 526 HeapEntriesAllocator* synthetic_entries_allocator_; 527 HeapEntriesAllocator* native_entries_allocator_; 528 // Used during references extraction. 529 SnapshotFiller* filler_; 530 531 static HeapThing const kNativesRootObject; 532 533 friend class GlobalHandlesExtractor; 534 535 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer); 536}; 537 538 539class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface { 540 public: 541 HeapSnapshotGenerator(HeapSnapshot* snapshot, 542 v8::ActivityControl* control, 543 v8::HeapProfiler::ObjectNameResolver* resolver, 544 Heap* heap); 545 bool GenerateSnapshot(); 546 547 private: 548 bool FillReferences(); 549 void ProgressStep(); 550 bool ProgressReport(bool force = false); 551 void SetProgressTotal(int iterations_count); 552 553 HeapSnapshot* snapshot_; 554 v8::ActivityControl* control_; 555 V8HeapExplorer v8_heap_explorer_; 556 NativeObjectsExplorer dom_explorer_; 557 // Mapping from HeapThing pointers to HeapEntry* pointers. 558 HeapEntriesMap entries_; 559 // Used during snapshot generation. 560 int progress_counter_; 561 int progress_total_; 562 Heap* heap_; 563 564 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator); 565}; 566 567class OutputStreamWriter; 568 569class HeapSnapshotJSONSerializer { 570 public: 571 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot) 572 : snapshot_(snapshot), 573 strings_(StringsMatch), 574 next_node_id_(1), 575 next_string_id_(1), 576 writer_(NULL) { 577 } 578 void Serialize(v8::OutputStream* stream); 579 580 private: 581 INLINE(static bool StringsMatch(void* key1, void* key2)) { 582 return strcmp(reinterpret_cast<char*>(key1), 583 reinterpret_cast<char*>(key2)) == 0; 584 } 585 586 INLINE(static uint32_t StringHash(const void* string)) { 587 const char* s = reinterpret_cast<const char*>(string); 588 int len = static_cast<int>(strlen(s)); 589 return StringHasher::HashSequentialString( 590 s, len, v8::internal::kZeroHashSeed); 591 } 592 593 int GetStringId(const char* s); 594 int entry_index(HeapEntry* e) { return e->index() * kNodeFieldsCount; } 595 void SerializeEdge(HeapGraphEdge* edge, bool first_edge); 596 void SerializeEdges(); 597 void SerializeImpl(); 598 void SerializeNode(HeapEntry* entry); 599 void SerializeNodes(); 600 void SerializeSnapshot(); 601 void SerializeTraceTree(); 602 void SerializeTraceNode(AllocationTraceNode* node); 603 void SerializeTraceNodeInfos(); 604 void SerializeSamples(); 605 void SerializeString(const unsigned char* s); 606 void SerializeStrings(); 607 608 static const int kEdgeFieldsCount; 609 static const int kNodeFieldsCount; 610 611 HeapSnapshot* snapshot_; 612 base::HashMap strings_; 613 int next_node_id_; 614 int next_string_id_; 615 OutputStreamWriter* writer_; 616 617 friend class HeapSnapshotJSONSerializerEnumerator; 618 friend class HeapSnapshotJSONSerializerIterator; 619 620 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer); 621}; 622 623 624} // namespace internal 625} // namespace v8 626 627#endif // V8_PROFILER_HEAP_SNAPSHOT_GENERATOR_H_ 628