profile-generator.h revision 7f4d5bd8c03935e2c0cd412e561b8fc5a6a880ae
1// Copyright 2010 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#ifndef V8_PROFILE_GENERATOR_H_ 29#define V8_PROFILE_GENERATOR_H_ 30 31#ifdef ENABLE_LOGGING_AND_PROFILING 32 33#include "hashmap.h" 34#include "../include/v8-profiler.h" 35 36namespace v8 { 37namespace internal { 38 39class TokenEnumerator { 40 public: 41 TokenEnumerator(); 42 ~TokenEnumerator(); 43 int GetTokenId(Object* token); 44 45 static const int kNoSecurityToken = -1; 46 static const int kInheritsSecurityToken = -2; 47 48 private: 49 static void TokenRemovedCallback(v8::Persistent<v8::Value> handle, 50 void* parameter); 51 void TokenRemoved(Object** token_location); 52 53 List<Object**> token_locations_; 54 List<bool> token_removed_; 55 56 friend class TokenEnumeratorTester; 57 58 DISALLOW_COPY_AND_ASSIGN(TokenEnumerator); 59}; 60 61 62// Provides a storage of strings allocated in C++ heap, to hold them 63// forever, even if they disappear from JS heap or external storage. 64class StringsStorage { 65 public: 66 StringsStorage(); 67 ~StringsStorage(); 68 69 const char* GetName(String* name); 70 71 private: 72 INLINE(static bool StringsMatch(void* key1, void* key2)) { 73 return strcmp(reinterpret_cast<char*>(key1), 74 reinterpret_cast<char*>(key2)) == 0; 75 } 76 77 // String::Hash -> const char* 78 HashMap names_; 79 80 DISALLOW_COPY_AND_ASSIGN(StringsStorage); 81}; 82 83 84class CodeEntry { 85 public: 86 explicit INLINE(CodeEntry(int security_token_id)); 87 // CodeEntry doesn't own name strings, just references them. 88 INLINE(CodeEntry(Logger::LogEventsAndTags tag, 89 const char* name_prefix, 90 const char* name, 91 const char* resource_name, 92 int line_number, 93 int security_token_id)); 94 95 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); } 96 INLINE(const char* name_prefix() const) { return name_prefix_; } 97 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; } 98 INLINE(const char* name() const) { return name_; } 99 INLINE(const char* resource_name() const) { return resource_name_; } 100 INLINE(int line_number() const) { return line_number_; } 101 INLINE(unsigned call_uid() const) { return call_uid_; } 102 INLINE(int security_token_id() const) { return security_token_id_; } 103 104 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag)); 105 106 void CopyData(const CodeEntry& source); 107 108 static const char* kEmptyNamePrefix; 109 110 private: 111 unsigned call_uid_; 112 Logger::LogEventsAndTags tag_; 113 const char* name_prefix_; 114 const char* name_; 115 const char* resource_name_; 116 int line_number_; 117 int security_token_id_; 118 119 static unsigned next_call_uid_; 120 121 DISALLOW_COPY_AND_ASSIGN(CodeEntry); 122}; 123 124 125class ProfileTree; 126 127class ProfileNode { 128 public: 129 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry)); 130 131 ProfileNode* FindChild(CodeEntry* entry); 132 ProfileNode* FindOrAddChild(CodeEntry* entry); 133 INLINE(void IncrementSelfTicks()) { ++self_ticks_; } 134 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; } 135 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; } 136 137 INLINE(CodeEntry* entry() const) { return entry_; } 138 INLINE(unsigned self_ticks() const) { return self_ticks_; } 139 INLINE(unsigned total_ticks() const) { return total_ticks_; } 140 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; } 141 double GetSelfMillis() const; 142 double GetTotalMillis() const; 143 144 void Print(int indent); 145 146 private: 147 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) { 148 return entry1 == entry2; 149 } 150 151 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) { 152 return static_cast<int32_t>(reinterpret_cast<intptr_t>(entry)); 153 } 154 155 ProfileTree* tree_; 156 CodeEntry* entry_; 157 unsigned total_ticks_; 158 unsigned self_ticks_; 159 // CodeEntry* -> ProfileNode* 160 HashMap children_; 161 List<ProfileNode*> children_list_; 162 163 DISALLOW_COPY_AND_ASSIGN(ProfileNode); 164}; 165 166 167class ProfileTree { 168 public: 169 ProfileTree(); 170 ~ProfileTree(); 171 172 void AddPathFromEnd(const Vector<CodeEntry*>& path); 173 void AddPathFromStart(const Vector<CodeEntry*>& path); 174 void CalculateTotalTicks(); 175 void FilteredClone(ProfileTree* src, int security_token_id); 176 177 double TicksToMillis(unsigned ticks) const { 178 return ticks * ms_to_ticks_scale_; 179 } 180 ProfileNode* root() const { return root_; } 181 void SetTickRatePerMs(double ticks_per_ms); 182 183 void ShortPrint(); 184 void Print() { 185 root_->Print(0); 186 } 187 188 private: 189 template <typename Callback> 190 void TraverseDepthFirst(Callback* callback); 191 192 CodeEntry root_entry_; 193 ProfileNode* root_; 194 double ms_to_ticks_scale_; 195 196 DISALLOW_COPY_AND_ASSIGN(ProfileTree); 197}; 198 199 200class CpuProfile { 201 public: 202 CpuProfile(const char* title, unsigned uid) 203 : title_(title), uid_(uid) { } 204 205 // Add pc -> ... -> main() call path to the profile. 206 void AddPath(const Vector<CodeEntry*>& path); 207 void CalculateTotalTicks(); 208 void SetActualSamplingRate(double actual_sampling_rate); 209 CpuProfile* FilteredClone(int security_token_id); 210 211 INLINE(const char* title() const) { return title_; } 212 INLINE(unsigned uid() const) { return uid_; } 213 INLINE(const ProfileTree* top_down() const) { return &top_down_; } 214 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; } 215 216 void UpdateTicksScale(); 217 218 void ShortPrint(); 219 void Print(); 220 221 private: 222 const char* title_; 223 unsigned uid_; 224 ProfileTree top_down_; 225 ProfileTree bottom_up_; 226 227 DISALLOW_COPY_AND_ASSIGN(CpuProfile); 228}; 229 230 231class CodeMap { 232 public: 233 CodeMap() { } 234 INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size)); 235 INLINE(void MoveCode(Address from, Address to)); 236 INLINE(void DeleteCode(Address addr)); 237 void AddAlias(Address start, CodeEntry* entry, Address code_start); 238 CodeEntry* FindEntry(Address addr); 239 240 void Print(); 241 242 private: 243 struct CodeEntryInfo { 244 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) 245 : entry(an_entry), size(a_size) { } 246 CodeEntry* entry; 247 unsigned size; 248 }; 249 250 struct CodeTreeConfig { 251 typedef Address Key; 252 typedef CodeEntryInfo Value; 253 static const Key kNoKey; 254 static const Value kNoValue; 255 static int Compare(const Key& a, const Key& b) { 256 return a < b ? -1 : (a > b ? 1 : 0); 257 } 258 }; 259 typedef SplayTree<CodeTreeConfig> CodeTree; 260 261 class CodeTreePrinter { 262 public: 263 void Call(const Address& key, const CodeEntryInfo& value); 264 }; 265 266 CodeTree tree_; 267 268 DISALLOW_COPY_AND_ASSIGN(CodeMap); 269}; 270 271 272class CpuProfilesCollection { 273 public: 274 CpuProfilesCollection(); 275 ~CpuProfilesCollection(); 276 277 bool StartProfiling(const char* title, unsigned uid); 278 bool StartProfiling(String* title, unsigned uid); 279 CpuProfile* StopProfiling(int security_token_id, 280 const char* title, 281 double actual_sampling_rate); 282 CpuProfile* StopProfiling(int security_token_id, 283 String* title, 284 double actual_sampling_rate); 285 List<CpuProfile*>* Profiles(int security_token_id); 286 const char* GetName(String* name) { 287 return function_and_resource_names_.GetName(name); 288 } 289 CpuProfile* GetProfile(int security_token_id, unsigned uid); 290 inline bool is_last_profile(); 291 292 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, 293 String* name, String* resource_name, int line_number); 294 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name); 295 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, 296 const char* name_prefix, String* name); 297 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count); 298 CodeEntry* NewCodeEntry(int security_token_id); 299 300 // Called from profile generator thread. 301 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path); 302 303 private: 304 INLINE(const char* GetFunctionName(String* name)); 305 INLINE(const char* GetFunctionName(const char* name)); 306 const char* GetName(int args_count); 307 List<CpuProfile*>* GetProfilesList(int security_token_id); 308 int TokenToIndex(int security_token_id); 309 310 INLINE(static bool UidsMatch(void* key1, void* key2)) { 311 return key1 == key2; 312 } 313 314 StringsStorage function_and_resource_names_; 315 // args_count -> char* 316 List<char*> args_count_names_; 317 List<CodeEntry*> code_entries_; 318 List<List<CpuProfile*>* > profiles_by_token_; 319 // uid -> index 320 HashMap profiles_uids_; 321 322 // Accessed by VM thread and profile generator thread. 323 List<CpuProfile*> current_profiles_; 324 Semaphore* current_profiles_semaphore_; 325 326 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); 327}; 328 329 330class SampleRateCalculator { 331 public: 332 SampleRateCalculator() 333 : result_(Logger::kSamplingIntervalMs * kResultScale), 334 ticks_per_ms_(Logger::kSamplingIntervalMs), 335 measurements_count_(0), 336 wall_time_query_countdown_(1) { 337 } 338 339 double ticks_per_ms() { 340 return result_ / static_cast<double>(kResultScale); 341 } 342 void Tick(); 343 void UpdateMeasurements(double current_time); 344 345 // Instead of querying current wall time each tick, 346 // we use this constant to control query intervals. 347 static const unsigned kWallTimeQueryIntervalMs = 100; 348 349 private: 350 // As the result needs to be accessed from a different thread, we 351 // use type that guarantees atomic writes to memory. There should 352 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5 353 // order should provide enough precision while keeping away from a 354 // potential overflow. 355 static const int kResultScale = 100000; 356 357 AtomicWord result_; 358 // All other fields are accessed only from the sampler thread. 359 double ticks_per_ms_; 360 unsigned measurements_count_; 361 unsigned wall_time_query_countdown_; 362 double last_wall_time_; 363 364 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator); 365}; 366 367 368class ProfileGenerator { 369 public: 370 explicit ProfileGenerator(CpuProfilesCollection* profiles); 371 372 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, 373 String* name, 374 String* resource_name, 375 int line_number)) { 376 return profiles_->NewCodeEntry(tag, name, resource_name, line_number); 377 } 378 379 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, 380 const char* name)) { 381 return profiles_->NewCodeEntry(tag, name); 382 } 383 384 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, 385 const char* name_prefix, 386 String* name)) { 387 return profiles_->NewCodeEntry(tag, name_prefix, name); 388 } 389 390 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, 391 int args_count)) { 392 return profiles_->NewCodeEntry(tag, args_count); 393 } 394 395 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) { 396 return profiles_->NewCodeEntry(security_token_id); 397 } 398 399 void RecordTickSample(const TickSample& sample); 400 401 INLINE(CodeMap* code_map()) { return &code_map_; } 402 403 INLINE(void Tick()) { sample_rate_calc_.Tick(); } 404 INLINE(double actual_sampling_rate()) { 405 return sample_rate_calc_.ticks_per_ms(); 406 } 407 408 static const char* kAnonymousFunctionName; 409 static const char* kProgramEntryName; 410 static const char* kGarbageCollectorEntryName; 411 412 private: 413 INLINE(CodeEntry* EntryForVMState(StateTag tag)); 414 415 CpuProfilesCollection* profiles_; 416 CodeMap code_map_; 417 CodeEntry* program_entry_; 418 CodeEntry* gc_entry_; 419 SampleRateCalculator sample_rate_calc_; 420 421 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); 422}; 423 424 425class HeapSnapshot; 426class HeapEntry; 427 428 429class HeapGraphEdge { 430 public: 431 enum Type { 432 CONTEXT_VARIABLE, 433 ELEMENT, 434 PROPERTY 435 }; 436 437 HeapGraphEdge(Type type, const char* name, HeapEntry* from, HeapEntry* to); 438 HeapGraphEdge(int index, HeapEntry* from, HeapEntry* to); 439 440 Type type() const { return type_; } 441 int index() const { 442 ASSERT(type_ == ELEMENT); 443 return index_; 444 } 445 const char* name() const { 446 ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY); 447 return name_; 448 } 449 HeapEntry* from() const { return from_; } 450 HeapEntry* to() const { return to_; } 451 452 private: 453 Type type_; 454 union { 455 int index_; 456 const char* name_; 457 }; 458 HeapEntry* from_; 459 HeapEntry* to_; 460 461 DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge); 462}; 463 464 465class HeapGraphPath; 466class CachedHeapGraphPath; 467 468class HeapEntry { 469 public: 470 enum Type { 471 INTERNAL, 472 ARRAY, 473 STRING, 474 JS_OBJECT, 475 CODE, 476 CLOSURE 477 }; 478 479 explicit HeapEntry(HeapSnapshot* snapshot) 480 : snapshot_(snapshot), 481 visited_(false), 482 type_(INTERNAL), 483 name_(""), 484 next_auto_index_(0), 485 self_size_(0), 486 security_token_id_(TokenEnumerator::kNoSecurityToken), 487 children_(1), 488 retainers_(0), 489 retaining_paths_(0), 490 total_size_(kUnknownSize), 491 non_shared_total_size_(kUnknownSize), 492 painted_(kUnpainted) { } 493 HeapEntry(HeapSnapshot* snapshot, 494 Type type, 495 const char* name, 496 int self_size, 497 int security_token_id) 498 : snapshot_(snapshot), 499 visited_(false), 500 type_(type), 501 name_(name), 502 next_auto_index_(1), 503 self_size_(self_size), 504 security_token_id_(security_token_id), 505 children_(4), 506 retainers_(4), 507 retaining_paths_(4), 508 total_size_(kUnknownSize), 509 non_shared_total_size_(kUnknownSize), 510 painted_(kUnpainted) { } 511 ~HeapEntry(); 512 513 bool visited() const { return visited_; } 514 Type type() const { return type_; } 515 const char* name() const { return name_; } 516 int self_size() const { return self_size_; } 517 int security_token_id() const { return security_token_id_; } 518 bool painted_reachable() { return painted_ == kPaintReachable; } 519 bool not_painted_reachable_from_others() { 520 return painted_ != kPaintReachableFromOthers; 521 } 522 const List<HeapGraphEdge*>* children() const { return &children_; } 523 const List<HeapGraphEdge*>* retainers() const { return &retainers_; } 524 const List<HeapGraphPath*>* GetRetainingPaths(); 525 526 void ClearPaint() { painted_ = kUnpainted; } 527 void CutEdges(); 528 void MarkAsVisited() { visited_ = true; } 529 void PaintReachable() { 530 ASSERT(painted_ == kUnpainted); 531 painted_ = kPaintReachable; 532 } 533 void PaintReachableFromOthers() { painted_ = kPaintReachableFromOthers; } 534 void SetClosureReference(const char* name, HeapEntry* entry); 535 void SetElementReference(int index, HeapEntry* entry); 536 void SetPropertyReference(const char* name, HeapEntry* entry); 537 void SetAutoIndexReference(HeapEntry* entry); 538 539 int TotalSize(); 540 int NonSharedTotalSize(); 541 542 void Print(int max_depth, int indent); 543 544 private: 545 int CalculateTotalSize(); 546 int CalculateNonSharedTotalSize(); 547 void FindRetainingPaths(HeapEntry* node, CachedHeapGraphPath* prev_path); 548 void RemoveChild(HeapGraphEdge* edge); 549 void RemoveRetainer(HeapGraphEdge* edge); 550 551 const char* TypeAsString(); 552 553 HeapSnapshot* snapshot_; 554 bool visited_; 555 Type type_; 556 const char* name_; 557 int next_auto_index_; 558 int self_size_; 559 int security_token_id_; 560 List<HeapGraphEdge*> children_; 561 List<HeapGraphEdge*> retainers_; 562 List<HeapGraphPath*> retaining_paths_; 563 int total_size_; 564 int non_shared_total_size_; 565 int painted_; 566 567 static const int kUnknownSize = -1; 568 static const int kUnpainted = 0; 569 static const int kPaintReachable = 1; 570 static const int kPaintReachableFromOthers = 2; 571 572 DISALLOW_IMPLICIT_CONSTRUCTORS(HeapEntry); 573}; 574 575 576class HeapGraphPath { 577 public: 578 HeapGraphPath() 579 : path_(8) { } 580 explicit HeapGraphPath(const List<HeapGraphEdge*>& path); 581 582 void Add(HeapGraphEdge* edge) { path_.Add(edge); } 583 void Set(int index, HeapGraphEdge* edge) { path_[index] = edge; } 584 const List<HeapGraphEdge*>* path() const { return &path_; } 585 586 void Print(); 587 588 private: 589 List<HeapGraphEdge*> path_; 590 591 DISALLOW_COPY_AND_ASSIGN(HeapGraphPath); 592}; 593 594 595class HeapEntriesMap { 596 public: 597 HeapEntriesMap(); 598 ~HeapEntriesMap(); 599 600 void Alias(HeapObject* object, HeapEntry* entry); 601 void Apply(void (HeapEntry::*Func)(void)); 602 template<class Visitor> 603 void Apply(Visitor* visitor); 604 HeapEntry* Map(HeapObject* object); 605 void Pair(HeapObject* object, HeapEntry* entry); 606 607 private: 608 INLINE(uint32_t Hash(HeapObject* object)) { 609 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(object)); 610 } 611 INLINE(static bool HeapObjectsMatch(void* key1, void* key2)) { 612 return key1 == key2; 613 } 614 INLINE(bool IsAlias(void* ptr)) { 615 return reinterpret_cast<intptr_t>(ptr) & kAliasTag; 616 } 617 618 static const intptr_t kAliasTag = 1; 619 620 HashMap entries_; 621 622 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap); 623}; 624 625 626class HeapSnapshotsCollection; 627 628// HeapSnapshot represents a single heap snapshot. It is stored in 629// HeapSnapshotsCollection, which is also a factory for 630// HeapSnapshots. All HeapSnapshots share strings copied from JS heap 631// to be able to return them even if they were collected. 632// HeapSnapshotGenerator fills in a HeapSnapshot. 633class HeapSnapshot { 634 public: 635 HeapSnapshot(HeapSnapshotsCollection* collection, 636 const char* title, 637 unsigned uid); 638 void ClearPaint(); 639 void CutObjectsFromForeignSecurityContexts(); 640 HeapEntry* GetEntry(Object* object); 641 void SetClosureReference( 642 HeapEntry* parent, String* reference_name, Object* child); 643 void SetElementReference(HeapEntry* parent, int index, Object* child); 644 void SetPropertyReference( 645 HeapEntry* parent, String* reference_name, Object* child); 646 647 INLINE(const char* title() const) { return title_; } 648 INLINE(unsigned uid() const) { return uid_; } 649 const HeapEntry* const_root() const { return &root_; } 650 HeapEntry* root() { return &root_; } 651 template<class Visitor> 652 void IterateEntries(Visitor* visitor) { entries_.Apply(visitor); } 653 654 void Print(int max_depth); 655 656 private: 657 HeapEntry* AddEntry(HeapObject* object, HeapEntry::Type type) { 658 return AddEntry(object, type, ""); 659 } 660 HeapEntry* AddEntry( 661 HeapObject* object, HeapEntry::Type type, const char* name); 662 void AddEntryAlias(HeapObject* object, HeapEntry* entry) { 663 entries_.Alias(object, entry); 664 } 665 HeapEntry* FindEntry(HeapObject* object) { 666 return entries_.Map(object); 667 } 668 int GetGlobalSecurityToken(); 669 int GetObjectSecurityToken(HeapObject* obj); 670 static int GetObjectSize(HeapObject* obj); 671 static int CalculateNetworkSize(JSObject* obj); 672 673 HeapSnapshotsCollection* collection_; 674 const char* title_; 675 unsigned uid_; 676 HeapEntry root_; 677 // HeapObject* -> HeapEntry* 678 HeapEntriesMap entries_; 679 680 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot); 681}; 682 683 684class HeapSnapshotsCollection { 685 public: 686 HeapSnapshotsCollection(); 687 ~HeapSnapshotsCollection(); 688 689 HeapSnapshot* NewSnapshot(const char* name, unsigned uid); 690 List<HeapSnapshot*>* snapshots() { return &snapshots_; } 691 HeapSnapshot* GetSnapshot(unsigned uid); 692 693 const char* GetName(String* name) { return names_.GetName(name); } 694 695 TokenEnumerator* token_enumerator() { return token_enumerator_; } 696 697 private: 698 INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) { 699 return key1 == key2; 700 } 701 702 List<HeapSnapshot*> snapshots_; 703 // uid -> HeapSnapshot* 704 HashMap snapshots_uids_; 705 StringsStorage names_; 706 TokenEnumerator* token_enumerator_; 707 708 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection); 709}; 710 711 712class HeapSnapshotGenerator { 713 public: 714 explicit HeapSnapshotGenerator(HeapSnapshot* snapshot); 715 void GenerateSnapshot(); 716 717 private: 718 void ExtractReferences(HeapObject* obj); 719 void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry); 720 void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry); 721 void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry); 722 723 HeapSnapshot* snapshot_; 724 725 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator); 726}; 727 728} } // namespace v8::internal 729 730#endif // ENABLE_LOGGING_AND_PROFILING 731 732#endif // V8_PROFILE_GENERATOR_H_ 733