| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #ifdef ENABLE_LOGGING_AND_PROFILING | 28 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 29 | 29 |
| 30 #include "v8.h" | 30 #include "v8.h" |
| 31 #include "global-handles.h" | 31 #include "global-handles.h" |
| 32 #include "heap-profiler.h" |
| 32 #include "scopeinfo.h" | 33 #include "scopeinfo.h" |
| 33 #include "top.h" | 34 #include "top.h" |
| 34 #include "unicode.h" | 35 #include "unicode.h" |
| 35 #include "zone-inl.h" | 36 #include "zone-inl.h" |
| 36 | 37 |
| 37 #include "profile-generator-inl.h" | 38 #include "profile-generator-inl.h" |
| 38 | 39 |
| 39 namespace v8 { | 40 namespace v8 { |
| 40 namespace internal { | 41 namespace internal { |
| 41 | 42 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 } | 88 } |
| 88 } | 89 } |
| 89 } | 90 } |
| 90 | 91 |
| 91 | 92 |
| 92 StringsStorage::StringsStorage() | 93 StringsStorage::StringsStorage() |
| 93 : names_(StringsMatch) { | 94 : names_(StringsMatch) { |
| 94 } | 95 } |
| 95 | 96 |
| 96 | 97 |
| 97 static void DeleteIndexName(char** name_ptr) { | |
| 98 DeleteArray(*name_ptr); | |
| 99 } | |
| 100 | |
| 101 | |
| 102 StringsStorage::~StringsStorage() { | 98 StringsStorage::~StringsStorage() { |
| 103 for (HashMap::Entry* p = names_.Start(); | 99 for (HashMap::Entry* p = names_.Start(); |
| 104 p != NULL; | 100 p != NULL; |
| 105 p = names_.Next(p)) { | 101 p = names_.Next(p)) { |
| 106 DeleteArray(reinterpret_cast<const char*>(p->value)); | 102 DeleteArray(reinterpret_cast<const char*>(p->value)); |
| 107 } | 103 } |
| 108 index_names_.Iterate(DeleteIndexName); | 104 } |
| 105 |
| 106 |
| 107 const char* StringsStorage::GetCopy(const char* src) { |
| 108 int len = static_cast<int>(strlen(src)); |
| 109 Vector<char> dst = Vector<char>::New(len + 1); |
| 110 OS::StrNCpy(dst, src, len); |
| 111 dst[len] = '\0'; |
| 112 uint32_t hash = HashSequentialString(dst.start(), len); |
| 113 return AddOrDisposeString(dst.start(), hash); |
| 114 } |
| 115 |
| 116 |
| 117 const char* StringsStorage::GetFormatted(const char* format, ...) { |
| 118 va_list args; |
| 119 va_start(args, format); |
| 120 const char* result = GetVFormatted(format, args); |
| 121 va_end(args); |
| 122 return result; |
| 123 } |
| 124 |
| 125 |
| 126 const char* StringsStorage::AddOrDisposeString(char* str, uint32_t hash) { |
| 127 HashMap::Entry* cache_entry = names_.Lookup(str, hash, true); |
| 128 if (cache_entry->value == NULL) { |
| 129 // New entry added. |
| 130 cache_entry->value = str; |
| 131 } else { |
| 132 DeleteArray(str); |
| 133 } |
| 134 return reinterpret_cast<const char*>(cache_entry->value); |
| 135 } |
| 136 |
| 137 |
| 138 const char* StringsStorage::GetVFormatted(const char* format, va_list args) { |
| 139 Vector<char> str = Vector<char>::New(1024); |
| 140 int len = OS::VSNPrintF(str, format, args); |
| 141 if (len == -1) { |
| 142 DeleteArray(str.start()); |
| 143 return format; |
| 144 } |
| 145 uint32_t hash = HashSequentialString(str.start(), len); |
| 146 return AddOrDisposeString(str.start(), hash); |
| 109 } | 147 } |
| 110 | 148 |
| 111 | 149 |
| 112 const char* StringsStorage::GetName(String* name) { | 150 const char* StringsStorage::GetName(String* name) { |
| 113 if (name->IsString()) { | 151 if (name->IsString()) { |
| 114 char* c_name = | 152 return AddOrDisposeString( |
| 115 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(); | 153 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).Detach(), |
| 116 HashMap::Entry* cache_entry = names_.Lookup(c_name, name->Hash(), true); | 154 name->Hash()); |
| 117 if (cache_entry->value == NULL) { | |
| 118 // New entry added. | |
| 119 cache_entry->value = c_name; | |
| 120 } else { | |
| 121 DeleteArray(c_name); | |
| 122 } | |
| 123 return reinterpret_cast<const char*>(cache_entry->value); | |
| 124 } | 155 } |
| 125 return ""; | 156 return ""; |
| 126 } | 157 } |
| 127 | 158 |
| 128 | 159 |
| 129 const char* StringsStorage::GetName(int index) { | 160 const char* StringsStorage::GetName(int index) { |
| 130 ASSERT(index >= 0); | 161 return GetFormatted("%d", index); |
| 131 if (index_names_.length() <= index) { | |
| 132 index_names_.AddBlock( | |
| 133 NULL, index - index_names_.length() + 1); | |
| 134 } | |
| 135 if (index_names_[index] == NULL) { | |
| 136 const int kMaximumNameLength = 32; | |
| 137 char* name = NewArray<char>(kMaximumNameLength); | |
| 138 OS::SNPrintF(Vector<char>(name, kMaximumNameLength), "%d", index); | |
| 139 index_names_[index] = name; | |
| 140 } | |
| 141 return index_names_[index]; | |
| 142 } | 162 } |
| 143 | 163 |
| 144 | 164 |
| 145 const char* CodeEntry::kEmptyNamePrefix = ""; | 165 const char* CodeEntry::kEmptyNamePrefix = ""; |
| 146 | 166 |
| 147 | 167 |
| 148 void CodeEntry::CopyData(const CodeEntry& source) { | 168 void CodeEntry::CopyData(const CodeEntry& source) { |
| 149 tag_ = source.tag_; | 169 tag_ = source.tag_; |
| 150 name_prefix_ = source.name_prefix_; | 170 name_prefix_ = source.name_prefix_; |
| 151 name_ = source.name_; | 171 name_ = source.name_; |
| 152 resource_name_ = source.resource_name_; | 172 resource_name_ = source.resource_name_; |
| 153 line_number_ = source.line_number_; | 173 line_number_ = source.line_number_; |
| 154 } | 174 } |
| 155 | 175 |
| 156 | 176 |
| 157 uint32_t CodeEntry::GetCallUid() const { | 177 uint32_t CodeEntry::GetCallUid() const { |
| 158 uint32_t hash = ComputeIntegerHash(tag_); | 178 uint32_t hash = ComputeIntegerHash(tag_); |
| 159 hash ^= ComputeIntegerHash( | 179 if (shared_id_ != 0) { |
| 160 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_))); | 180 hash ^= ComputeIntegerHash( |
| 161 hash ^= ComputeIntegerHash( | 181 static_cast<uint32_t>(shared_id_)); |
| 162 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_))); | 182 } else { |
| 163 hash ^= ComputeIntegerHash( | 183 hash ^= ComputeIntegerHash( |
| 164 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_))); | 184 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_))); |
| 165 hash ^= ComputeIntegerHash(line_number_); | 185 hash ^= ComputeIntegerHash( |
| 186 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_))); |
| 187 hash ^= ComputeIntegerHash( |
| 188 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_))); |
| 189 hash ^= ComputeIntegerHash(line_number_); |
| 190 } |
| 166 return hash; | 191 return hash; |
| 167 } | 192 } |
| 168 | 193 |
| 169 | 194 |
| 170 bool CodeEntry::IsSameAs(CodeEntry* entry) const { | 195 bool CodeEntry::IsSameAs(CodeEntry* entry) const { |
| 171 return this == entry | 196 return this == entry |
| 172 || (tag_ == entry->tag_ | 197 || (tag_ == entry->tag_ |
| 173 && name_prefix_ == entry->name_prefix_ | 198 && shared_id_ == entry->shared_id_ |
| 174 && name_ == entry->name_ | 199 && (shared_id_ != 0 |
| 175 && resource_name_ == entry->resource_name_ | 200 || (name_prefix_ == entry->name_prefix_ |
| 176 && line_number_ == entry->line_number_); | 201 && name_ == entry->name_ |
| 202 && resource_name_ == entry->resource_name_ |
| 203 && line_number_ == entry->line_number_))); |
| 177 } | 204 } |
| 178 | 205 |
| 179 | 206 |
| 180 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { | 207 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
| 181 HashMap::Entry* map_entry = | 208 HashMap::Entry* map_entry = |
| 182 children_.Lookup(entry, CodeEntryHash(entry), false); | 209 children_.Lookup(entry, CodeEntryHash(entry), false); |
| 183 return map_entry != NULL ? | 210 return map_entry != NULL ? |
| 184 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 211 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
| 185 } | 212 } |
| 186 | 213 |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 | 478 |
| 452 | 479 |
| 453 void CpuProfile::Print() { | 480 void CpuProfile::Print() { |
| 454 OS::Print("[Top down]:\n"); | 481 OS::Print("[Top down]:\n"); |
| 455 top_down_.Print(); | 482 top_down_.Print(); |
| 456 OS::Print("[Bottom up]:\n"); | 483 OS::Print("[Bottom up]:\n"); |
| 457 bottom_up_.Print(); | 484 bottom_up_.Print(); |
| 458 } | 485 } |
| 459 | 486 |
| 460 | 487 |
| 488 CodeEntry* const CodeMap::kSharedFunctionCodeEntry = NULL; |
| 461 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; | 489 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; |
| 462 const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue = | 490 const CodeMap::CodeTreeConfig::Value CodeMap::CodeTreeConfig::kNoValue = |
| 463 CodeMap::CodeEntryInfo(NULL, 0); | 491 CodeMap::CodeEntryInfo(NULL, 0); |
| 464 | 492 |
| 465 | 493 |
| 466 void CodeMap::AddAlias(Address start, CodeEntry* entry, Address code_start) { | |
| 467 CodeTree::Locator locator; | |
| 468 if (tree_.Find(code_start, &locator)) { | |
| 469 const CodeEntryInfo& code_info = locator.value(); | |
| 470 if (tree_.Insert(start, &locator)) { | |
| 471 entry->CopyData(*code_info.entry); | |
| 472 locator.set_value(CodeEntryInfo(entry, code_info.size)); | |
| 473 } | |
| 474 } | |
| 475 } | |
| 476 | |
| 477 | |
| 478 CodeEntry* CodeMap::FindEntry(Address addr) { | 494 CodeEntry* CodeMap::FindEntry(Address addr) { |
| 479 CodeTree::Locator locator; | 495 CodeTree::Locator locator; |
| 480 if (tree_.FindGreatestLessThan(addr, &locator)) { | 496 if (tree_.FindGreatestLessThan(addr, &locator)) { |
| 481 // locator.key() <= addr. Need to check that addr is within entry. | 497 // locator.key() <= addr. Need to check that addr is within entry. |
| 482 const CodeEntryInfo& entry = locator.value(); | 498 const CodeEntryInfo& entry = locator.value(); |
| 483 if (addr < (locator.key() + entry.size)) | 499 if (addr < (locator.key() + entry.size)) |
| 484 return entry.entry; | 500 return entry.entry; |
| 485 } | 501 } |
| 486 return NULL; | 502 return NULL; |
| 487 } | 503 } |
| 488 | 504 |
| 489 | 505 |
| 506 int CodeMap::GetSharedId(Address addr) { |
| 507 CodeTree::Locator locator; |
| 508 // For shared function entries, 'size' field is used to store their IDs. |
| 509 if (tree_.Find(addr, &locator)) { |
| 510 const CodeEntryInfo& entry = locator.value(); |
| 511 ASSERT(entry.entry == kSharedFunctionCodeEntry); |
| 512 return entry.size; |
| 513 } else { |
| 514 tree_.Insert(addr, &locator); |
| 515 int id = next_shared_id_++; |
| 516 locator.set_value(CodeEntryInfo(kSharedFunctionCodeEntry, id)); |
| 517 return id; |
| 518 } |
| 519 } |
| 520 |
| 521 |
| 490 void CodeMap::CodeTreePrinter::Call( | 522 void CodeMap::CodeTreePrinter::Call( |
| 491 const Address& key, const CodeMap::CodeEntryInfo& value) { | 523 const Address& key, const CodeMap::CodeEntryInfo& value) { |
| 492 OS::Print("%p %5d %s\n", key, value.size, value.entry->name()); | 524 OS::Print("%p %5d %s\n", key, value.size, value.entry->name()); |
| 493 } | 525 } |
| 494 | 526 |
| 495 | 527 |
| 496 void CodeMap::Print() { | 528 void CodeMap::Print() { |
| 497 CodeTreePrinter printer; | 529 CodeTreePrinter printer; |
| 498 tree_.ForEach(&printer); | 530 tree_.ForEach(&printer); |
| 499 } | 531 } |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 708 "args_count: ", | 740 "args_count: ", |
| 709 GetName(args_count), | 741 GetName(args_count), |
| 710 "", | 742 "", |
| 711 v8::CpuProfileNode::kNoLineNumberInfo, | 743 v8::CpuProfileNode::kNoLineNumberInfo, |
| 712 TokenEnumerator::kInheritsSecurityToken); | 744 TokenEnumerator::kInheritsSecurityToken); |
| 713 code_entries_.Add(entry); | 745 code_entries_.Add(entry); |
| 714 return entry; | 746 return entry; |
| 715 } | 747 } |
| 716 | 748 |
| 717 | 749 |
| 718 CodeEntry* CpuProfilesCollection::NewCodeEntry(int security_token_id) { | |
| 719 CodeEntry* entry = new CodeEntry(security_token_id); | |
| 720 code_entries_.Add(entry); | |
| 721 return entry; | |
| 722 } | |
| 723 | |
| 724 | |
| 725 void CpuProfilesCollection::AddPathToCurrentProfiles( | 750 void CpuProfilesCollection::AddPathToCurrentProfiles( |
| 726 const Vector<CodeEntry*>& path) { | 751 const Vector<CodeEntry*>& path) { |
| 727 // As starting / stopping profiles is rare relatively to this | 752 // As starting / stopping profiles is rare relatively to this |
| 728 // method, we don't bother minimizing the duration of lock holding, | 753 // method, we don't bother minimizing the duration of lock holding, |
| 729 // e.g. copying contents of the list to a local vector. | 754 // e.g. copying contents of the list to a local vector. |
| 730 current_profiles_semaphore_->Wait(); | 755 current_profiles_semaphore_->Wait(); |
| 731 for (int i = 0; i < current_profiles_.length(); ++i) { | 756 for (int i = 0; i < current_profiles_.length(); ++i) { |
| 732 current_profiles_[i]->AddPath(path); | 757 current_profiles_[i]->AddPath(path); |
| 733 } | 758 } |
| 734 current_profiles_semaphore_->Signal(); | 759 current_profiles_semaphore_->Signal(); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 802 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
| 778 // Allocate space for stack frames + pc + function + vm-state. | 803 // Allocate space for stack frames + pc + function + vm-state. |
| 779 ScopedVector<CodeEntry*> entries(sample.frames_count + 3); | 804 ScopedVector<CodeEntry*> entries(sample.frames_count + 3); |
| 780 // As actual number of decoded code entries may vary, initialize | 805 // As actual number of decoded code entries may vary, initialize |
| 781 // entries vector with NULL values. | 806 // entries vector with NULL values. |
| 782 CodeEntry** entry = entries.start(); | 807 CodeEntry** entry = entries.start(); |
| 783 memset(entry, 0, entries.length() * sizeof(*entry)); | 808 memset(entry, 0, entries.length() * sizeof(*entry)); |
| 784 if (sample.pc != NULL) { | 809 if (sample.pc != NULL) { |
| 785 *entry++ = code_map_.FindEntry(sample.pc); | 810 *entry++ = code_map_.FindEntry(sample.pc); |
| 786 | 811 |
| 787 if (sample.function != NULL) { | 812 if (sample.tos != NULL) { |
| 788 *entry = code_map_.FindEntry(sample.function); | 813 *entry = code_map_.FindEntry(sample.tos); |
| 789 if (*entry != NULL && !(*entry)->is_js_function()) { | 814 if (*entry != NULL && !(*entry)->is_js_function()) { |
| 790 *entry = NULL; | 815 *entry = NULL; |
| 791 } else { | |
| 792 CodeEntry* pc_entry = *entries.start(); | |
| 793 if (pc_entry == NULL) { | |
| 794 *entry = NULL; | |
| 795 } else if (pc_entry->is_js_function()) { | |
| 796 // Use function entry in favor of pc entry, as function | |
| 797 // entry has security token. | |
| 798 *entries.start() = NULL; | |
| 799 } | |
| 800 } | 816 } |
| 801 entry++; | 817 entry++; |
| 802 } | 818 } |
| 803 | 819 |
| 804 for (const Address *stack_pos = sample.stack, | 820 for (const Address *stack_pos = sample.stack, |
| 805 *stack_end = stack_pos + sample.frames_count; | 821 *stack_end = stack_pos + sample.frames_count; |
| 806 stack_pos != stack_end; | 822 stack_pos != stack_end; |
| 807 ++stack_pos) { | 823 ++stack_pos) { |
| 808 *entry++ = code_map_.FindEntry(*stack_pos); | 824 *entry++ = code_map_.FindEntry(*stack_pos); |
| 809 } | 825 } |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1006 const char* HeapEntry::TypeAsString() { | 1022 const char* HeapEntry::TypeAsString() { |
| 1007 switch (type()) { | 1023 switch (type()) { |
| 1008 case kHidden: return "/hidden/"; | 1024 case kHidden: return "/hidden/"; |
| 1009 case kObject: return "/object/"; | 1025 case kObject: return "/object/"; |
| 1010 case kClosure: return "/closure/"; | 1026 case kClosure: return "/closure/"; |
| 1011 case kString: return "/string/"; | 1027 case kString: return "/string/"; |
| 1012 case kCode: return "/code/"; | 1028 case kCode: return "/code/"; |
| 1013 case kArray: return "/array/"; | 1029 case kArray: return "/array/"; |
| 1014 case kRegExp: return "/regexp/"; | 1030 case kRegExp: return "/regexp/"; |
| 1015 case kHeapNumber: return "/number/"; | 1031 case kHeapNumber: return "/number/"; |
| 1032 case kNative: return "/native/"; |
| 1016 default: return "???"; | 1033 default: return "???"; |
| 1017 } | 1034 } |
| 1018 } | 1035 } |
| 1019 | 1036 |
| 1020 | 1037 |
| 1021 int HeapEntry::EntriesSize(int entries_count, | 1038 int HeapEntry::EntriesSize(int entries_count, |
| 1022 int children_count, | 1039 int children_count, |
| 1023 int retainers_count) { | 1040 int retainers_count) { |
| 1024 return sizeof(HeapEntry) * entries_count // NOLINT | 1041 return sizeof(HeapEntry) * entries_count // NOLINT |
| 1025 + sizeof(HeapGraphEdge) * children_count // NOLINT | 1042 + sizeof(HeapGraphEdge) * children_count // NOLINT |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1174 break; | 1191 break; |
| 1175 default: | 1192 default: |
| 1176 OS::Print("!!! unknown edge type: %d ", edge->type()); | 1193 OS::Print("!!! unknown edge type: %d ", edge->type()); |
| 1177 } | 1194 } |
| 1178 edge->to()->Print(1, 0); | 1195 edge->to()->Print(1, 0); |
| 1179 } | 1196 } |
| 1180 OS::Print("\n"); | 1197 OS::Print("\n"); |
| 1181 } | 1198 } |
| 1182 | 1199 |
| 1183 | 1200 |
| 1184 HeapObject *const HeapSnapshot::kInternalRootObject = | |
| 1185 reinterpret_cast<HeapObject*>(1); | |
| 1186 HeapObject *const HeapSnapshot::kGcRootsObject = | |
| 1187 reinterpret_cast<HeapObject*>(2); | |
| 1188 | |
| 1189 | |
| 1190 // It is very important to keep objects that form a heap snapshot | 1201 // It is very important to keep objects that form a heap snapshot |
| 1191 // as small as possible. | 1202 // as small as possible. |
| 1192 namespace { // Avoid littering the global namespace. | 1203 namespace { // Avoid littering the global namespace. |
| 1193 | 1204 |
| 1194 template <size_t ptr_size> struct SnapshotSizeConstants; | 1205 template <size_t ptr_size> struct SnapshotSizeConstants; |
| 1195 | 1206 |
| 1196 template <> struct SnapshotSizeConstants<4> { | 1207 template <> struct SnapshotSizeConstants<4> { |
| 1197 static const int kExpectedHeapGraphEdgeSize = 12; | 1208 static const int kExpectedHeapGraphEdgeSize = 12; |
| 1198 static const int kExpectedHeapEntrySize = 36; | 1209 static const int kExpectedHeapEntrySize = 36; |
| 1199 }; | 1210 }; |
| 1200 | 1211 |
| 1201 template <> struct SnapshotSizeConstants<8> { | 1212 template <> struct SnapshotSizeConstants<8> { |
| 1202 static const int kExpectedHeapGraphEdgeSize = 24; | 1213 static const int kExpectedHeapGraphEdgeSize = 24; |
| 1203 static const int kExpectedHeapEntrySize = 48; | 1214 static const int kExpectedHeapEntrySize = 48; |
| 1204 }; | 1215 }; |
| 1205 | 1216 |
| 1206 } // namespace | 1217 } // namespace |
| 1207 | 1218 |
| 1208 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, | 1219 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
| 1209 HeapSnapshot::Type type, | 1220 HeapSnapshot::Type type, |
| 1210 const char* title, | 1221 const char* title, |
| 1211 unsigned uid) | 1222 unsigned uid) |
| 1212 : collection_(collection), | 1223 : collection_(collection), |
| 1213 type_(type), | 1224 type_(type), |
| 1214 title_(title), | 1225 title_(title), |
| 1215 uid_(uid), | 1226 uid_(uid), |
| 1216 root_entry_(NULL), | 1227 root_entry_(NULL), |
| 1217 gc_roots_entry_(NULL), | 1228 gc_roots_entry_(NULL), |
| 1229 natives_root_entry_(NULL), |
| 1218 raw_entries_(NULL), | 1230 raw_entries_(NULL), |
| 1219 entries_sorted_(false), | 1231 entries_sorted_(false), |
| 1220 retaining_paths_(HeapEntry::Match) { | 1232 retaining_paths_(HeapEntry::Match) { |
| 1221 STATIC_ASSERT( | 1233 STATIC_ASSERT( |
| 1222 sizeof(HeapGraphEdge) == | 1234 sizeof(HeapGraphEdge) == |
| 1223 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOL
INT | 1235 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapGraphEdgeSize); // NOL
INT |
| 1224 STATIC_ASSERT( | 1236 STATIC_ASSERT( |
| 1225 sizeof(HeapEntry) == | 1237 sizeof(HeapEntry) == |
| 1226 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT | 1238 SnapshotSizeConstants<sizeof(void*)>::kExpectedHeapEntrySize); // NOLINT |
| 1227 } | 1239 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1250 ASSERT(raw_entries_ == NULL); | 1262 ASSERT(raw_entries_ == NULL); |
| 1251 raw_entries_ = NewArray<char>( | 1263 raw_entries_ = NewArray<char>( |
| 1252 HeapEntry::EntriesSize(entries_count, children_count, retainers_count)); | 1264 HeapEntry::EntriesSize(entries_count, children_count, retainers_count)); |
| 1253 #ifdef DEBUG | 1265 #ifdef DEBUG |
| 1254 raw_entries_size_ = | 1266 raw_entries_size_ = |
| 1255 HeapEntry::EntriesSize(entries_count, children_count, retainers_count); | 1267 HeapEntry::EntriesSize(entries_count, children_count, retainers_count); |
| 1256 #endif | 1268 #endif |
| 1257 } | 1269 } |
| 1258 | 1270 |
| 1259 | 1271 |
| 1260 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, | |
| 1261 int children_count, | |
| 1262 int retainers_count) { | |
| 1263 if (object == kInternalRootObject) { | |
| 1264 ASSERT(root_entry_ == NULL); | |
| 1265 ASSERT(retainers_count == 0); | |
| 1266 return (root_entry_ = AddEntry(HeapEntry::kObject, | |
| 1267 "", | |
| 1268 HeapObjectsMap::kInternalRootObjectId, | |
| 1269 0, | |
| 1270 children_count, | |
| 1271 retainers_count)); | |
| 1272 } else if (object == kGcRootsObject) { | |
| 1273 ASSERT(gc_roots_entry_ == NULL); | |
| 1274 return (gc_roots_entry_ = AddEntry(HeapEntry::kObject, | |
| 1275 "(GC roots)", | |
| 1276 HeapObjectsMap::kGcRootsObjectId, | |
| 1277 0, | |
| 1278 children_count, | |
| 1279 retainers_count)); | |
| 1280 } else if (object->IsJSFunction()) { | |
| 1281 JSFunction* func = JSFunction::cast(object); | |
| 1282 SharedFunctionInfo* shared = func->shared(); | |
| 1283 return AddEntry(object, | |
| 1284 HeapEntry::kClosure, | |
| 1285 collection_->GetName(String::cast(shared->name())), | |
| 1286 children_count, | |
| 1287 retainers_count); | |
| 1288 } else if (object->IsJSRegExp()) { | |
| 1289 JSRegExp* re = JSRegExp::cast(object); | |
| 1290 return AddEntry(object, | |
| 1291 HeapEntry::kRegExp, | |
| 1292 collection_->GetName(re->Pattern()), | |
| 1293 children_count, | |
| 1294 retainers_count); | |
| 1295 } else if (object->IsJSObject()) { | |
| 1296 return AddEntry(object, | |
| 1297 HeapEntry::kObject, | |
| 1298 collection_->GetName(GetConstructorNameForHeapProfile( | |
| 1299 JSObject::cast(object))), | |
| 1300 children_count, | |
| 1301 retainers_count); | |
| 1302 } else if (object->IsString()) { | |
| 1303 return AddEntry(object, | |
| 1304 HeapEntry::kString, | |
| 1305 collection_->GetName(String::cast(object)), | |
| 1306 children_count, | |
| 1307 retainers_count); | |
| 1308 } else if (object->IsCode()) { | |
| 1309 return AddEntry(object, | |
| 1310 HeapEntry::kCode, | |
| 1311 "", | |
| 1312 children_count, | |
| 1313 retainers_count); | |
| 1314 } else if (object->IsSharedFunctionInfo()) { | |
| 1315 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); | |
| 1316 return AddEntry(object, | |
| 1317 HeapEntry::kCode, | |
| 1318 collection_->GetName(String::cast(shared->name())), | |
| 1319 children_count, | |
| 1320 retainers_count); | |
| 1321 } else if (object->IsScript()) { | |
| 1322 Script* script = Script::cast(object); | |
| 1323 return AddEntry(object, | |
| 1324 HeapEntry::kCode, | |
| 1325 script->name()->IsString() ? | |
| 1326 collection_->GetName(String::cast(script->name())) : "", | |
| 1327 children_count, | |
| 1328 retainers_count); | |
| 1329 } else if (object->IsFixedArray()) { | |
| 1330 return AddEntry(object, | |
| 1331 HeapEntry::kArray, | |
| 1332 "", | |
| 1333 children_count, | |
| 1334 retainers_count); | |
| 1335 } else if (object->IsHeapNumber()) { | |
| 1336 return AddEntry(object, | |
| 1337 HeapEntry::kHeapNumber, | |
| 1338 "number", | |
| 1339 children_count, | |
| 1340 retainers_count); | |
| 1341 } | |
| 1342 return AddEntry(object, | |
| 1343 HeapEntry::kHidden, | |
| 1344 "system", | |
| 1345 children_count, | |
| 1346 retainers_count); | |
| 1347 } | |
| 1348 | |
| 1349 | |
| 1350 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { | 1272 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { |
| 1351 (*entry_ptr)->clear_paint(); | 1273 (*entry_ptr)->clear_paint(); |
| 1352 } | 1274 } |
| 1353 | 1275 |
| 1354 void HeapSnapshot::ClearPaint() { | 1276 void HeapSnapshot::ClearPaint() { |
| 1355 entries_.Iterate(HeapEntryClearPaint); | 1277 entries_.Iterate(HeapEntryClearPaint); |
| 1356 } | 1278 } |
| 1357 | 1279 |
| 1358 | 1280 |
| 1359 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, | 1281 HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { |
| 1360 HeapEntry::Type type, | 1282 ASSERT(root_entry_ == NULL); |
| 1361 const char* name, | 1283 return (root_entry_ = AddEntry(HeapEntry::kObject, |
| 1362 int children_count, | 1284 "", |
| 1363 int retainers_count) { | 1285 HeapObjectsMap::kInternalRootObjectId, |
| 1364 return AddEntry(type, | 1286 0, |
| 1365 name, | 1287 children_count, |
| 1366 collection_->GetObjectId(object->address()), | 1288 0)); |
| 1367 object->Size(), | 1289 } |
| 1368 children_count, | 1290 |
| 1369 retainers_count); | 1291 |
| 1292 HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, |
| 1293 int retainers_count) { |
| 1294 ASSERT(gc_roots_entry_ == NULL); |
| 1295 return (gc_roots_entry_ = AddEntry(HeapEntry::kObject, |
| 1296 "(GC roots)", |
| 1297 HeapObjectsMap::kGcRootsObjectId, |
| 1298 0, |
| 1299 children_count, |
| 1300 retainers_count)); |
| 1301 } |
| 1302 |
| 1303 |
| 1304 HeapEntry* HeapSnapshot::AddNativesRootEntry(int children_count, |
| 1305 int retainers_count) { |
| 1306 ASSERT(natives_root_entry_ == NULL); |
| 1307 return (natives_root_entry_ = AddEntry( |
| 1308 HeapEntry::kObject, |
| 1309 "(Native objects)", |
| 1310 HeapObjectsMap::kNativesRootObjectId, |
| 1311 0, |
| 1312 children_count, |
| 1313 retainers_count)); |
| 1370 } | 1314 } |
| 1371 | 1315 |
| 1372 | 1316 |
| 1373 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, | 1317 HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type, |
| 1374 const char* name, | 1318 const char* name, |
| 1375 uint64_t id, | 1319 uint64_t id, |
| 1376 int size, | 1320 int size, |
| 1377 int children_count, | 1321 int children_count, |
| 1378 int retainers_count) { | 1322 int retainers_count) { |
| 1379 HeapEntry* entry = GetNextEntryToInit(); | 1323 HeapEntry* entry = GetNextEntryToInit(); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1456 } | 1400 } |
| 1457 return &entries_; | 1401 return &entries_; |
| 1458 } | 1402 } |
| 1459 | 1403 |
| 1460 | 1404 |
| 1461 void HeapSnapshot::Print(int max_depth) { | 1405 void HeapSnapshot::Print(int max_depth) { |
| 1462 root()->Print(max_depth, 0); | 1406 root()->Print(max_depth, 0); |
| 1463 } | 1407 } |
| 1464 | 1408 |
| 1465 | 1409 |
| 1466 const uint64_t HeapObjectsMap::kInternalRootObjectId = 0; | 1410 // We split IDs on evens for embedder objects (see |
| 1467 const uint64_t HeapObjectsMap::kGcRootsObjectId = 1; | 1411 // HeapObjectsMap::GenerateId) and odds for native objects. |
| 1412 const uint64_t HeapObjectsMap::kInternalRootObjectId = 1; |
| 1413 const uint64_t HeapObjectsMap::kGcRootsObjectId = 3; |
| 1414 const uint64_t HeapObjectsMap::kNativesRootObjectId = 5; |
| 1468 // Increase kFirstAvailableObjectId if new 'special' objects appear. | 1415 // Increase kFirstAvailableObjectId if new 'special' objects appear. |
| 1469 const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 2; | 1416 const uint64_t HeapObjectsMap::kFirstAvailableObjectId = 7; |
| 1470 | 1417 |
| 1471 HeapObjectsMap::HeapObjectsMap() | 1418 HeapObjectsMap::HeapObjectsMap() |
| 1472 : initial_fill_mode_(true), | 1419 : initial_fill_mode_(true), |
| 1473 next_id_(kFirstAvailableObjectId), | 1420 next_id_(kFirstAvailableObjectId), |
| 1474 entries_map_(AddressesMatch), | 1421 entries_map_(AddressesMatch), |
| 1475 entries_(new List<EntryInfo>()) { } | 1422 entries_(new List<EntryInfo>()) { } |
| 1476 | 1423 |
| 1477 | 1424 |
| 1478 HeapObjectsMap::~HeapObjectsMap() { | 1425 HeapObjectsMap::~HeapObjectsMap() { |
| 1479 delete entries_; | 1426 delete entries_; |
| 1480 } | 1427 } |
| 1481 | 1428 |
| 1482 | 1429 |
| 1483 void HeapObjectsMap::SnapshotGenerationFinished() { | 1430 void HeapObjectsMap::SnapshotGenerationFinished() { |
| 1484 initial_fill_mode_ = false; | 1431 initial_fill_mode_ = false; |
| 1485 RemoveDeadEntries(); | 1432 RemoveDeadEntries(); |
| 1486 } | 1433 } |
| 1487 | 1434 |
| 1488 | 1435 |
| 1489 uint64_t HeapObjectsMap::FindObject(Address addr) { | 1436 uint64_t HeapObjectsMap::FindObject(Address addr) { |
| 1490 if (!initial_fill_mode_) { | 1437 if (!initial_fill_mode_) { |
| 1491 uint64_t existing = FindEntry(addr); | 1438 uint64_t existing = FindEntry(addr); |
| 1492 if (existing != 0) return existing; | 1439 if (existing != 0) return existing; |
| 1493 } | 1440 } |
| 1494 uint64_t id = next_id_++; | 1441 uint64_t id = next_id_; |
| 1442 next_id_ += 2; |
| 1495 AddEntry(addr, id); | 1443 AddEntry(addr, id); |
| 1496 return id; | 1444 return id; |
| 1497 } | 1445 } |
| 1498 | 1446 |
| 1499 | 1447 |
| 1500 void HeapObjectsMap::MoveObject(Address from, Address to) { | 1448 void HeapObjectsMap::MoveObject(Address from, Address to) { |
| 1501 if (from == to) return; | 1449 if (from == to) return; |
| 1502 HashMap::Entry* entry = entries_map_.Lookup(from, AddressHash(from), false); | 1450 HashMap::Entry* entry = entries_map_.Lookup(from, AddressHash(from), false); |
| 1503 if (entry != NULL) { | 1451 if (entry != NULL) { |
| 1504 void* value = entry->value; | 1452 void* value = entry->value; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1552 for (int i = 0; i < dead_entries.length(); ++i) { | 1500 for (int i = 0; i < dead_entries.length(); ++i) { |
| 1553 void* raw_entry = dead_entries[i]; | 1501 void* raw_entry = dead_entries[i]; |
| 1554 entries_map_.Remove( | 1502 entries_map_.Remove( |
| 1555 raw_entry, AddressHash(reinterpret_cast<Address>(raw_entry))); | 1503 raw_entry, AddressHash(reinterpret_cast<Address>(raw_entry))); |
| 1556 } | 1504 } |
| 1557 delete entries_; | 1505 delete entries_; |
| 1558 entries_ = new_entries; | 1506 entries_ = new_entries; |
| 1559 } | 1507 } |
| 1560 | 1508 |
| 1561 | 1509 |
| 1510 uint64_t HeapObjectsMap::GenerateId(v8::RetainedObjectInfo* info) { |
| 1511 uint64_t id = static_cast<uint64_t>(info->GetHash()); |
| 1512 const char* label = info->GetLabel(); |
| 1513 id ^= HashSequentialString(label, static_cast<int>(strlen(label))); |
| 1514 intptr_t element_count = info->GetElementCount(); |
| 1515 if (element_count != -1) |
| 1516 id ^= ComputeIntegerHash(static_cast<uint32_t>(element_count)); |
| 1517 return id << 1; |
| 1518 } |
| 1519 |
| 1520 |
| 1562 HeapSnapshotsCollection::HeapSnapshotsCollection() | 1521 HeapSnapshotsCollection::HeapSnapshotsCollection() |
| 1563 : is_tracking_objects_(false), | 1522 : is_tracking_objects_(false), |
| 1564 snapshots_uids_(HeapSnapshotsMatch), | 1523 snapshots_uids_(HeapSnapshotsMatch), |
| 1565 token_enumerator_(new TokenEnumerator()) { | 1524 token_enumerator_(new TokenEnumerator()) { |
| 1566 } | 1525 } |
| 1567 | 1526 |
| 1568 | 1527 |
| 1569 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) { | 1528 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) { |
| 1570 delete *snapshot_ptr; | 1529 delete *snapshot_ptr; |
| 1571 } | 1530 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1612 HeapSnapshot* snapshot1, | 1571 HeapSnapshot* snapshot1, |
| 1613 HeapSnapshot* snapshot2) { | 1572 HeapSnapshot* snapshot2) { |
| 1614 return comparator_.Compare(snapshot1, snapshot2); | 1573 return comparator_.Compare(snapshot1, snapshot2); |
| 1615 } | 1574 } |
| 1616 | 1575 |
| 1617 | 1576 |
| 1618 HeapEntry *const HeapEntriesMap::kHeapEntryPlaceholder = | 1577 HeapEntry *const HeapEntriesMap::kHeapEntryPlaceholder = |
| 1619 reinterpret_cast<HeapEntry*>(1); | 1578 reinterpret_cast<HeapEntry*>(1); |
| 1620 | 1579 |
| 1621 HeapEntriesMap::HeapEntriesMap() | 1580 HeapEntriesMap::HeapEntriesMap() |
| 1622 : entries_(HeapObjectsMatch), | 1581 : entries_(HeapThingsMatch), |
| 1623 entries_count_(0), | 1582 entries_count_(0), |
| 1624 total_children_count_(0), | 1583 total_children_count_(0), |
| 1625 total_retainers_count_(0) { | 1584 total_retainers_count_(0) { |
| 1626 } | 1585 } |
| 1627 | 1586 |
| 1628 | 1587 |
| 1629 HeapEntriesMap::~HeapEntriesMap() { | 1588 HeapEntriesMap::~HeapEntriesMap() { |
| 1630 for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { | 1589 for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { |
| 1631 delete reinterpret_cast<EntryInfo*>(p->value); | 1590 delete reinterpret_cast<EntryInfo*>(p->value); |
| 1632 } | 1591 } |
| 1633 } | 1592 } |
| 1634 | 1593 |
| 1635 | 1594 |
| 1636 HeapEntry* HeapEntriesMap::Map(HeapObject* object) { | 1595 void HeapEntriesMap::AllocateEntries() { |
| 1637 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false); | 1596 for (HashMap::Entry* p = entries_.Start(); |
| 1597 p != NULL; |
| 1598 p = entries_.Next(p)) { |
| 1599 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value); |
| 1600 entry_info->entry = entry_info->allocator->AllocateEntry( |
| 1601 p->key, |
| 1602 entry_info->children_count, |
| 1603 entry_info->retainers_count); |
| 1604 ASSERT(entry_info->entry != NULL); |
| 1605 ASSERT(entry_info->entry != kHeapEntryPlaceholder); |
| 1606 entry_info->children_count = 0; |
| 1607 entry_info->retainers_count = 0; |
| 1608 } |
| 1609 } |
| 1610 |
| 1611 |
| 1612 HeapEntry* HeapEntriesMap::Map(HeapThing thing) { |
| 1613 HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false); |
| 1638 if (cache_entry != NULL) { | 1614 if (cache_entry != NULL) { |
| 1639 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); | 1615 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); |
| 1640 return entry_info->entry; | 1616 return entry_info->entry; |
| 1641 } else { | 1617 } else { |
| 1642 return NULL; | 1618 return NULL; |
| 1643 } | 1619 } |
| 1644 } | 1620 } |
| 1645 | 1621 |
| 1646 | 1622 |
| 1647 void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) { | 1623 void HeapEntriesMap::Pair( |
| 1648 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true); | 1624 HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry) { |
| 1625 HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), true); |
| 1649 ASSERT(cache_entry->value == NULL); | 1626 ASSERT(cache_entry->value == NULL); |
| 1650 cache_entry->value = new EntryInfo(entry); | 1627 cache_entry->value = new EntryInfo(entry, allocator); |
| 1651 ++entries_count_; | 1628 ++entries_count_; |
| 1652 } | 1629 } |
| 1653 | 1630 |
| 1654 | 1631 |
| 1655 void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to, | 1632 void HeapEntriesMap::CountReference(HeapThing from, HeapThing to, |
| 1656 int* prev_children_count, | 1633 int* prev_children_count, |
| 1657 int* prev_retainers_count) { | 1634 int* prev_retainers_count) { |
| 1658 HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false); | 1635 HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), false); |
| 1659 HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false); | 1636 HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false); |
| 1660 ASSERT(from_cache_entry != NULL); | 1637 ASSERT(from_cache_entry != NULL); |
| 1661 ASSERT(to_cache_entry != NULL); | 1638 ASSERT(to_cache_entry != NULL); |
| 1662 EntryInfo* from_entry_info = | 1639 EntryInfo* from_entry_info = |
| 1663 reinterpret_cast<EntryInfo*>(from_cache_entry->value); | 1640 reinterpret_cast<EntryInfo*>(from_cache_entry->value); |
| 1664 EntryInfo* to_entry_info = | 1641 EntryInfo* to_entry_info = |
| 1665 reinterpret_cast<EntryInfo*>(to_cache_entry->value); | 1642 reinterpret_cast<EntryInfo*>(to_cache_entry->value); |
| 1666 if (prev_children_count) | 1643 if (prev_children_count) |
| 1667 *prev_children_count = from_entry_info->children_count; | 1644 *prev_children_count = from_entry_info->children_count; |
| 1668 if (prev_retainers_count) | 1645 if (prev_retainers_count) |
| 1669 *prev_retainers_count = to_entry_info->retainers_count; | 1646 *prev_retainers_count = to_entry_info->retainers_count; |
| 1670 ++from_entry_info->children_count; | 1647 ++from_entry_info->children_count; |
| 1671 ++to_entry_info->retainers_count; | 1648 ++to_entry_info->retainers_count; |
| 1672 ++total_children_count_; | 1649 ++total_children_count_; |
| 1673 ++total_retainers_count_; | 1650 ++total_retainers_count_; |
| 1674 } | 1651 } |
| 1675 | 1652 |
| 1676 | 1653 |
| 1677 HeapObjectsSet::HeapObjectsSet() | 1654 HeapObjectsSet::HeapObjectsSet() |
| 1678 : entries_(HeapEntriesMap::HeapObjectsMatch) { | 1655 : entries_(HeapEntriesMap::HeapThingsMatch) { |
| 1679 } | 1656 } |
| 1680 | 1657 |
| 1681 | 1658 |
| 1682 void HeapObjectsSet::Clear() { | 1659 void HeapObjectsSet::Clear() { |
| 1683 entries_.Clear(); | 1660 entries_.Clear(); |
| 1684 } | 1661 } |
| 1685 | 1662 |
| 1686 | 1663 |
| 1687 bool HeapObjectsSet::Contains(Object* obj) { | 1664 bool HeapObjectsSet::Contains(Object* obj) { |
| 1688 if (!obj->IsHeapObject()) return false; | 1665 if (!obj->IsHeapObject()) return false; |
| 1689 HeapObject* object = HeapObject::cast(obj); | 1666 HeapObject* object = HeapObject::cast(obj); |
| 1690 HashMap::Entry* cache_entry = | 1667 HashMap::Entry* cache_entry = |
| 1691 entries_.Lookup(object, HeapEntriesMap::Hash(object), false); | 1668 entries_.Lookup(object, HeapEntriesMap::Hash(object), false); |
| 1692 return cache_entry != NULL; | 1669 return cache_entry != NULL; |
| 1693 } | 1670 } |
| 1694 | 1671 |
| 1695 | 1672 |
| 1696 void HeapObjectsSet::Insert(Object* obj) { | 1673 void HeapObjectsSet::Insert(Object* obj) { |
| 1697 if (!obj->IsHeapObject()) return; | 1674 if (!obj->IsHeapObject()) return; |
| 1698 HeapObject* object = HeapObject::cast(obj); | 1675 HeapObject* object = HeapObject::cast(obj); |
| 1699 HashMap::Entry* cache_entry = | 1676 HashMap::Entry* cache_entry = |
| 1700 entries_.Lookup(object, HeapEntriesMap::Hash(object), true); | 1677 entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
| 1701 if (cache_entry->value == NULL) { | 1678 if (cache_entry->value == NULL) { |
| 1702 cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; | 1679 cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; |
| 1703 } | 1680 } |
| 1704 } | 1681 } |
| 1705 | 1682 |
| 1706 | 1683 |
| 1707 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, | 1684 HeapObject *const V8HeapExplorer::kInternalRootObject = |
| 1708 v8::ActivityControl* control) | 1685 reinterpret_cast<HeapObject*>( |
| 1686 static_cast<intptr_t>(HeapObjectsMap::kInternalRootObjectId)); |
| 1687 HeapObject *const V8HeapExplorer::kGcRootsObject = |
| 1688 reinterpret_cast<HeapObject*>( |
| 1689 static_cast<intptr_t>(HeapObjectsMap::kGcRootsObjectId)); |
| 1690 |
| 1691 |
| 1692 V8HeapExplorer::V8HeapExplorer( |
| 1693 HeapSnapshot* snapshot, |
| 1694 SnapshottingProgressReportingInterface* progress) |
| 1709 : snapshot_(snapshot), | 1695 : snapshot_(snapshot), |
| 1710 control_(control), | 1696 collection_(snapshot_->collection()), |
| 1711 collection_(snapshot->collection()), | 1697 progress_(progress), |
| 1712 filler_(NULL) { | 1698 filler_(NULL) { |
| 1713 } | 1699 } |
| 1714 | 1700 |
| 1715 class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface { | |
| 1716 public: | |
| 1717 explicit SnapshotCounter(HeapEntriesMap* entries) | |
| 1718 : entries_(entries) { } | |
| 1719 HeapEntry* AddEntry(HeapObject* obj) { | |
| 1720 entries_->Pair(obj, HeapEntriesMap::kHeapEntryPlaceholder); | |
| 1721 return HeapEntriesMap::kHeapEntryPlaceholder; | |
| 1722 } | |
| 1723 void SetIndexedReference(HeapGraphEdge::Type, | |
| 1724 HeapObject* parent_obj, | |
| 1725 HeapEntry*, | |
| 1726 int, | |
| 1727 Object* child_obj, | |
| 1728 HeapEntry*) { | |
| 1729 entries_->CountReference(parent_obj, HeapObject::cast(child_obj)); | |
| 1730 } | |
| 1731 void SetNamedReference(HeapGraphEdge::Type, | |
| 1732 HeapObject* parent_obj, | |
| 1733 HeapEntry*, | |
| 1734 const char*, | |
| 1735 Object* child_obj, | |
| 1736 HeapEntry*) { | |
| 1737 entries_->CountReference(parent_obj, HeapObject::cast(child_obj)); | |
| 1738 } | |
| 1739 void SetRootShortcutReference(Object* child_obj, HeapEntry*) { | |
| 1740 entries_->CountReference( | |
| 1741 HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj)); | |
| 1742 } | |
| 1743 void SetRootGcRootsReference() { | |
| 1744 entries_->CountReference( | |
| 1745 HeapSnapshot::kInternalRootObject, HeapSnapshot::kGcRootsObject); | |
| 1746 } | |
| 1747 void SetStrongRootReference(Object* child_obj, HeapEntry*) { | |
| 1748 entries_->CountReference( | |
| 1749 HeapSnapshot::kGcRootsObject, HeapObject::cast(child_obj)); | |
| 1750 } | |
| 1751 private: | |
| 1752 HeapEntriesMap* entries_; | |
| 1753 }; | |
| 1754 | 1701 |
| 1755 | 1702 V8HeapExplorer::~V8HeapExplorer() { |
| 1756 class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface { | |
| 1757 public: | |
| 1758 explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) | |
| 1759 : snapshot_(snapshot), | |
| 1760 collection_(snapshot->collection()), | |
| 1761 entries_(entries) { } | |
| 1762 HeapEntry* AddEntry(HeapObject* obj) { | |
| 1763 UNREACHABLE(); | |
| 1764 return NULL; | |
| 1765 } | |
| 1766 void SetIndexedReference(HeapGraphEdge::Type type, | |
| 1767 HeapObject* parent_obj, | |
| 1768 HeapEntry* parent_entry, | |
| 1769 int index, | |
| 1770 Object* child_obj, | |
| 1771 HeapEntry* child_entry) { | |
| 1772 int child_index, retainer_index; | |
| 1773 entries_->CountReference(parent_obj, | |
| 1774 HeapObject::cast(child_obj), | |
| 1775 &child_index, | |
| 1776 &retainer_index); | |
| 1777 parent_entry->SetIndexedReference( | |
| 1778 type, child_index, index, child_entry, retainer_index); | |
| 1779 } | |
| 1780 void SetNamedReference(HeapGraphEdge::Type type, | |
| 1781 HeapObject* parent_obj, | |
| 1782 HeapEntry* parent_entry, | |
| 1783 const char* reference_name, | |
| 1784 Object* child_obj, | |
| 1785 HeapEntry* child_entry) { | |
| 1786 int child_index, retainer_index; | |
| 1787 entries_->CountReference(parent_obj, HeapObject::cast(child_obj), | |
| 1788 &child_index, &retainer_index); | |
| 1789 parent_entry->SetNamedReference(type, | |
| 1790 child_index, | |
| 1791 reference_name, | |
| 1792 child_entry, | |
| 1793 retainer_index); | |
| 1794 } | |
| 1795 void SetRootGcRootsReference() { | |
| 1796 int child_index, retainer_index; | |
| 1797 entries_->CountReference(HeapSnapshot::kInternalRootObject, | |
| 1798 HeapSnapshot::kGcRootsObject, | |
| 1799 &child_index, | |
| 1800 &retainer_index); | |
| 1801 snapshot_->root()->SetIndexedReference(HeapGraphEdge::kElement, | |
| 1802 child_index, | |
| 1803 child_index + 1, | |
| 1804 snapshot_->gc_roots(), | |
| 1805 retainer_index); | |
| 1806 } | |
| 1807 void SetRootShortcutReference(Object* child_obj, | |
| 1808 HeapEntry* child_entry) { | |
| 1809 int child_index, retainer_index; | |
| 1810 entries_->CountReference(HeapSnapshot::kInternalRootObject, | |
| 1811 HeapObject::cast(child_obj), | |
| 1812 &child_index, | |
| 1813 &retainer_index); | |
| 1814 snapshot_->root()->SetNamedReference(HeapGraphEdge::kShortcut, | |
| 1815 child_index, | |
| 1816 collection_->GetName(child_index + 1), | |
| 1817 child_entry, | |
| 1818 retainer_index); | |
| 1819 } | |
| 1820 void SetStrongRootReference(Object* child_obj, | |
| 1821 HeapEntry* child_entry) { | |
| 1822 int child_index, retainer_index; | |
| 1823 entries_->CountReference(HeapSnapshot::kGcRootsObject, | |
| 1824 HeapObject::cast(child_obj), | |
| 1825 &child_index, | |
| 1826 &retainer_index); | |
| 1827 snapshot_->gc_roots()->SetIndexedReference(HeapGraphEdge::kElement, | |
| 1828 child_index, | |
| 1829 child_index + 1, | |
| 1830 child_entry, | |
| 1831 retainer_index); | |
| 1832 } | |
| 1833 private: | |
| 1834 HeapSnapshot* snapshot_; | |
| 1835 HeapSnapshotsCollection* collection_; | |
| 1836 HeapEntriesMap* entries_; | |
| 1837 }; | |
| 1838 | |
| 1839 class SnapshotAllocator { | |
| 1840 public: | |
| 1841 explicit SnapshotAllocator(HeapSnapshot* snapshot) | |
| 1842 : snapshot_(snapshot) { } | |
| 1843 HeapEntry* GetEntry( | |
| 1844 HeapObject* obj, int children_count, int retainers_count) { | |
| 1845 HeapEntry* entry = | |
| 1846 snapshot_->AddEntry(obj, children_count, retainers_count); | |
| 1847 ASSERT(entry != NULL); | |
| 1848 return entry; | |
| 1849 } | |
| 1850 private: | |
| 1851 HeapSnapshot* snapshot_; | |
| 1852 }; | |
| 1853 | |
| 1854 class RootsReferencesExtractor : public ObjectVisitor { | |
| 1855 public: | |
| 1856 explicit RootsReferencesExtractor(HeapSnapshotGenerator* generator) | |
| 1857 : generator_(generator) { | |
| 1858 } | |
| 1859 void VisitPointers(Object** start, Object** end) { | |
| 1860 for (Object** p = start; p < end; p++) generator_->SetGcRootsReference(*p); | |
| 1861 } | |
| 1862 private: | |
| 1863 HeapSnapshotGenerator* generator_; | |
| 1864 }; | |
| 1865 | |
| 1866 | |
| 1867 bool HeapSnapshotGenerator::GenerateSnapshot() { | |
| 1868 AssertNoAllocation no_alloc; | |
| 1869 | |
| 1870 SetProgressTotal(4); // 2 passes + dominators + sizes. | |
| 1871 | |
| 1872 // Pass 1. Iterate heap contents to count entries and references. | |
| 1873 if (!CountEntriesAndReferences()) return false; | |
| 1874 | |
| 1875 // Allocate and fill entries in the snapshot, allocate references. | |
| 1876 snapshot_->AllocateEntries(entries_.entries_count(), | |
| 1877 entries_.total_children_count(), | |
| 1878 entries_.total_retainers_count()); | |
| 1879 SnapshotAllocator allocator(snapshot_); | |
| 1880 entries_.UpdateEntries(&allocator); | |
| 1881 | |
| 1882 // Pass 2. Fill references. | |
| 1883 if (!FillReferences()) return false; | |
| 1884 | |
| 1885 if (!SetEntriesDominators()) return false; | |
| 1886 if (!ApproximateRetainedSizes()) return false; | |
| 1887 | |
| 1888 progress_counter_ = progress_total_; | |
| 1889 if (!ReportProgress(true)) return false; | |
| 1890 return true; | |
| 1891 } | 1703 } |
| 1892 | 1704 |
| 1893 | 1705 |
| 1894 HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) { | 1706 HeapEntry* V8HeapExplorer::AllocateEntry( |
| 1895 if (!obj->IsHeapObject()) return NULL; | 1707 HeapThing ptr, int children_count, int retainers_count) { |
| 1896 HeapObject* object = HeapObject::cast(obj); | 1708 return AddEntry( |
| 1897 HeapEntry* entry = entries_.Map(object); | 1709 reinterpret_cast<HeapObject*>(ptr), children_count, retainers_count); |
| 1898 // A new entry. | 1710 } |
| 1899 if (entry == NULL) entry = filler_->AddEntry(object); | 1711 |
| 1900 return entry; | 1712 |
| 1713 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| 1714 int children_count, |
| 1715 int retainers_count) { |
| 1716 if (object == kInternalRootObject) { |
| 1717 ASSERT(retainers_count == 0); |
| 1718 return snapshot_->AddRootEntry(children_count); |
| 1719 } else if (object == kGcRootsObject) { |
| 1720 return snapshot_->AddGcRootsEntry(children_count, retainers_count); |
| 1721 } else if (object->IsJSFunction()) { |
| 1722 JSFunction* func = JSFunction::cast(object); |
| 1723 SharedFunctionInfo* shared = func->shared(); |
| 1724 return AddEntry(object, |
| 1725 HeapEntry::kClosure, |
| 1726 collection_->names()->GetName(String::cast(shared->name())), |
| 1727 children_count, |
| 1728 retainers_count); |
| 1729 } else if (object->IsJSRegExp()) { |
| 1730 JSRegExp* re = JSRegExp::cast(object); |
| 1731 return AddEntry(object, |
| 1732 HeapEntry::kRegExp, |
| 1733 collection_->names()->GetName(re->Pattern()), |
| 1734 children_count, |
| 1735 retainers_count); |
| 1736 } else if (object->IsJSObject()) { |
| 1737 return AddEntry(object, |
| 1738 HeapEntry::kObject, |
| 1739 collection_->names()->GetName( |
| 1740 GetConstructorNameForHeapProfile( |
| 1741 JSObject::cast(object))), |
| 1742 children_count, |
| 1743 retainers_count); |
| 1744 } else if (object->IsString()) { |
| 1745 return AddEntry(object, |
| 1746 HeapEntry::kString, |
| 1747 collection_->names()->GetName(String::cast(object)), |
| 1748 children_count, |
| 1749 retainers_count); |
| 1750 } else if (object->IsCode()) { |
| 1751 return AddEntry(object, |
| 1752 HeapEntry::kCode, |
| 1753 "", |
| 1754 children_count, |
| 1755 retainers_count); |
| 1756 } else if (object->IsSharedFunctionInfo()) { |
| 1757 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
| 1758 return AddEntry(object, |
| 1759 HeapEntry::kCode, |
| 1760 collection_->names()->GetName(String::cast(shared->name())), |
| 1761 children_count, |
| 1762 retainers_count); |
| 1763 } else if (object->IsScript()) { |
| 1764 Script* script = Script::cast(object); |
| 1765 return AddEntry(object, |
| 1766 HeapEntry::kCode, |
| 1767 script->name()->IsString() ? |
| 1768 collection_->names()->GetName( |
| 1769 String::cast(script->name())) |
| 1770 : "", |
| 1771 children_count, |
| 1772 retainers_count); |
| 1773 } else if (object->IsFixedArray()) { |
| 1774 return AddEntry(object, |
| 1775 HeapEntry::kArray, |
| 1776 "", |
| 1777 children_count, |
| 1778 retainers_count); |
| 1779 } else if (object->IsHeapNumber()) { |
| 1780 return AddEntry(object, |
| 1781 HeapEntry::kHeapNumber, |
| 1782 "number", |
| 1783 children_count, |
| 1784 retainers_count); |
| 1785 } |
| 1786 return AddEntry(object, |
| 1787 HeapEntry::kHidden, |
| 1788 "system", |
| 1789 children_count, |
| 1790 retainers_count); |
| 1791 } |
| 1792 |
| 1793 |
| 1794 HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object, |
| 1795 HeapEntry::Type type, |
| 1796 const char* name, |
| 1797 int children_count, |
| 1798 int retainers_count) { |
| 1799 return snapshot_->AddEntry(type, |
| 1800 name, |
| 1801 collection_->GetObjectId(object->address()), |
| 1802 object->Size(), |
| 1803 children_count, |
| 1804 retainers_count); |
| 1805 } |
| 1806 |
| 1807 |
| 1808 void V8HeapExplorer::AddRootEntries(SnapshotFillerInterface* filler) { |
| 1809 filler->AddEntry(kInternalRootObject, this); |
| 1810 filler->AddEntry(kGcRootsObject, this); |
| 1811 } |
| 1812 |
| 1813 |
| 1814 int V8HeapExplorer::EstimateObjectsCount() { |
| 1815 HeapIterator iterator(HeapIterator::kFilterUnreachable); |
| 1816 int objects_count = 0; |
| 1817 for (HeapObject* obj = iterator.next(); |
| 1818 obj != NULL; |
| 1819 obj = iterator.next(), ++objects_count) {} |
| 1820 return objects_count; |
| 1901 } | 1821 } |
| 1902 | 1822 |
| 1903 | 1823 |
| 1904 class IndexedReferencesExtractor : public ObjectVisitor { | 1824 class IndexedReferencesExtractor : public ObjectVisitor { |
| 1905 public: | 1825 public: |
| 1906 IndexedReferencesExtractor(HeapSnapshotGenerator* generator, | 1826 IndexedReferencesExtractor(V8HeapExplorer* generator, |
| 1907 HeapObject* parent_obj, | 1827 HeapObject* parent_obj, |
| 1908 HeapEntry* parent_entry, | 1828 HeapEntry* parent_entry, |
| 1909 HeapObjectsSet* known_references = NULL) | 1829 HeapObjectsSet* known_references = NULL) |
| 1910 : generator_(generator), | 1830 : generator_(generator), |
| 1911 parent_obj_(parent_obj), | 1831 parent_obj_(parent_obj), |
| 1912 parent_(parent_entry), | 1832 parent_(parent_entry), |
| 1913 known_references_(known_references), | 1833 known_references_(known_references), |
| 1914 next_index_(1) { | 1834 next_index_(1) { |
| 1915 } | 1835 } |
| 1916 void VisitPointers(Object** start, Object** end) { | 1836 void VisitPointers(Object** start, Object** end) { |
| 1917 for (Object** p = start; p < end; p++) { | 1837 for (Object** p = start; p < end; p++) { |
| 1918 if (!known_references_ || !known_references_->Contains(*p)) { | 1838 if (!known_references_ || !known_references_->Contains(*p)) { |
| 1919 generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); | 1839 generator_->SetHiddenReference(parent_obj_, parent_, next_index_++, *p); |
| 1920 } | 1840 } |
| 1921 } | 1841 } |
| 1922 } | 1842 } |
| 1923 private: | 1843 private: |
| 1924 HeapSnapshotGenerator* generator_; | 1844 V8HeapExplorer* generator_; |
| 1925 HeapObject* parent_obj_; | 1845 HeapObject* parent_obj_; |
| 1926 HeapEntry* parent_; | 1846 HeapEntry* parent_; |
| 1927 HeapObjectsSet* known_references_; | 1847 HeapObjectsSet* known_references_; |
| 1928 int next_index_; | 1848 int next_index_; |
| 1929 }; | 1849 }; |
| 1930 | 1850 |
| 1931 | 1851 |
| 1932 void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { | 1852 void V8HeapExplorer::ExtractReferences(HeapObject* obj) { |
| 1933 HeapEntry* entry = GetEntry(obj); | 1853 HeapEntry* entry = GetEntry(obj); |
| 1934 if (entry == NULL) return; // No interest in this object. | 1854 if (entry == NULL) return; // No interest in this object. |
| 1935 | 1855 |
| 1936 known_references_.Clear(); | 1856 known_references_.Clear(); |
| 1937 if (obj->IsJSGlobalProxy()) { | 1857 if (obj->IsJSGlobalProxy()) { |
| 1938 // We need to reference JS global objects from snapshot's root. | 1858 // We need to reference JS global objects from snapshot's root. |
| 1939 // We use JSGlobalProxy because this is what embedder (e.g. browser) | 1859 // We use JSGlobalProxy because this is what embedder (e.g. browser) |
| 1940 // uses for the global object. | 1860 // uses for the global object. |
| 1941 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); | 1861 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
| 1942 SetRootShortcutReference(proxy->map()->prototype()); | 1862 SetRootShortcutReference(proxy->map()->prototype()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1966 SetInternalReference(obj, entry, 1, cs->first()); | 1886 SetInternalReference(obj, entry, 1, cs->first()); |
| 1967 SetInternalReference(obj, entry, 2, cs->second()); | 1887 SetInternalReference(obj, entry, 2, cs->second()); |
| 1968 } | 1888 } |
| 1969 } else { | 1889 } else { |
| 1970 IndexedReferencesExtractor refs_extractor(this, obj, entry); | 1890 IndexedReferencesExtractor refs_extractor(this, obj, entry); |
| 1971 obj->Iterate(&refs_extractor); | 1891 obj->Iterate(&refs_extractor); |
| 1972 } | 1892 } |
| 1973 } | 1893 } |
| 1974 | 1894 |
| 1975 | 1895 |
| 1976 void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj, | 1896 void V8HeapExplorer::ExtractClosureReferences(JSObject* js_obj, |
| 1977 HeapEntry* entry) { | 1897 HeapEntry* entry) { |
| 1978 if (js_obj->IsJSFunction()) { | 1898 if (js_obj->IsJSFunction()) { |
| 1979 HandleScope hs; | 1899 HandleScope hs; |
| 1980 JSFunction* func = JSFunction::cast(js_obj); | 1900 JSFunction* func = JSFunction::cast(js_obj); |
| 1981 Context* context = func->context(); | 1901 Context* context = func->context(); |
| 1982 ZoneScope zscope(DELETE_ON_EXIT); | 1902 ZoneScope zscope(DELETE_ON_EXIT); |
| 1983 SerializedScopeInfo* serialized_scope_info = | 1903 SerializedScopeInfo* serialized_scope_info = |
| 1984 context->closure()->shared()->scope_info(); | 1904 context->closure()->shared()->scope_info(); |
| 1985 ScopeInfo<ZoneListAllocationPolicy> zone_scope_info(serialized_scope_info); | 1905 ScopeInfo<ZoneListAllocationPolicy> zone_scope_info(serialized_scope_info); |
| 1986 int locals_number = zone_scope_info.NumberOfLocals(); | 1906 int locals_number = zone_scope_info.NumberOfLocals(); |
| 1987 for (int i = 0; i < locals_number; ++i) { | 1907 for (int i = 0; i < locals_number; ++i) { |
| 1988 String* local_name = *zone_scope_info.LocalName(i); | 1908 String* local_name = *zone_scope_info.LocalName(i); |
| 1989 int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL); | 1909 int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL); |
| 1990 if (idx >= 0 && idx < context->length()) { | 1910 if (idx >= 0 && idx < context->length()) { |
| 1991 SetClosureReference(js_obj, entry, local_name, context->get(idx)); | 1911 SetClosureReference(js_obj, entry, local_name, context->get(idx)); |
| 1992 } | 1912 } |
| 1993 } | 1913 } |
| 1994 SetInternalReference(js_obj, entry, "code", func->shared()); | 1914 SetInternalReference(js_obj, entry, "code", func->shared()); |
| 1995 } | 1915 } |
| 1996 } | 1916 } |
| 1997 | 1917 |
| 1998 | 1918 |
| 1999 void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj, | 1919 void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, |
| 2000 HeapEntry* entry) { | 1920 HeapEntry* entry) { |
| 2001 if (js_obj->HasFastProperties()) { | 1921 if (js_obj->HasFastProperties()) { |
| 2002 DescriptorArray* descs = js_obj->map()->instance_descriptors(); | 1922 DescriptorArray* descs = js_obj->map()->instance_descriptors(); |
| 2003 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 1923 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 2004 switch (descs->GetType(i)) { | 1924 switch (descs->GetType(i)) { |
| 2005 case FIELD: { | 1925 case FIELD: { |
| 2006 int index = descs->GetFieldIndex(i); | 1926 int index = descs->GetFieldIndex(i); |
| 2007 SetPropertyReference( | 1927 SetPropertyReference( |
| 2008 js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index)); | 1928 js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index)); |
| 2009 break; | 1929 break; |
| 2010 } | 1930 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2031 String::cast(k), | 1951 String::cast(k), |
| 2032 JSGlobalPropertyCell::cast( | 1952 JSGlobalPropertyCell::cast( |
| 2033 target)->value()); | 1953 target)->value()); |
| 2034 } | 1954 } |
| 2035 } | 1955 } |
| 2036 } | 1956 } |
| 2037 } | 1957 } |
| 2038 } | 1958 } |
| 2039 | 1959 |
| 2040 | 1960 |
| 2041 void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj, | 1961 void V8HeapExplorer::ExtractElementReferences(JSObject* js_obj, |
| 2042 HeapEntry* entry) { | 1962 HeapEntry* entry) { |
| 2043 if (js_obj->HasFastElements()) { | 1963 if (js_obj->HasFastElements()) { |
| 2044 FixedArray* elements = FixedArray::cast(js_obj->elements()); | 1964 FixedArray* elements = FixedArray::cast(js_obj->elements()); |
| 2045 int length = js_obj->IsJSArray() ? | 1965 int length = js_obj->IsJSArray() ? |
| 2046 Smi::cast(JSArray::cast(js_obj)->length())->value() : | 1966 Smi::cast(JSArray::cast(js_obj)->length())->value() : |
| 2047 elements->length(); | 1967 elements->length(); |
| 2048 for (int i = 0; i < length; ++i) { | 1968 for (int i = 0; i < length; ++i) { |
| 2049 if (!elements->get(i)->IsTheHole()) { | 1969 if (!elements->get(i)->IsTheHole()) { |
| 2050 SetElementReference(js_obj, entry, i, elements->get(i)); | 1970 SetElementReference(js_obj, entry, i, elements->get(i)); |
| 2051 } | 1971 } |
| 2052 } | 1972 } |
| 2053 } else if (js_obj->HasDictionaryElements()) { | 1973 } else if (js_obj->HasDictionaryElements()) { |
| 2054 NumberDictionary* dictionary = js_obj->element_dictionary(); | 1974 NumberDictionary* dictionary = js_obj->element_dictionary(); |
| 2055 int length = dictionary->Capacity(); | 1975 int length = dictionary->Capacity(); |
| 2056 for (int i = 0; i < length; ++i) { | 1976 for (int i = 0; i < length; ++i) { |
| 2057 Object* k = dictionary->KeyAt(i); | 1977 Object* k = dictionary->KeyAt(i); |
| 2058 if (dictionary->IsKey(k)) { | 1978 if (dictionary->IsKey(k)) { |
| 2059 ASSERT(k->IsNumber()); | 1979 ASSERT(k->IsNumber()); |
| 2060 uint32_t index = static_cast<uint32_t>(k->Number()); | 1980 uint32_t index = static_cast<uint32_t>(k->Number()); |
| 2061 SetElementReference(js_obj, entry, index, dictionary->ValueAt(i)); | 1981 SetElementReference(js_obj, entry, index, dictionary->ValueAt(i)); |
| 2062 } | 1982 } |
| 2063 } | 1983 } |
| 2064 } | 1984 } |
| 2065 } | 1985 } |
| 2066 | 1986 |
| 2067 | 1987 |
| 2068 void HeapSnapshotGenerator::ExtractInternalReferences(JSObject* js_obj, | 1988 void V8HeapExplorer::ExtractInternalReferences(JSObject* js_obj, |
| 2069 HeapEntry* entry) { | 1989 HeapEntry* entry) { |
| 2070 int length = js_obj->GetInternalFieldCount(); | 1990 int length = js_obj->GetInternalFieldCount(); |
| 2071 for (int i = 0; i < length; ++i) { | 1991 for (int i = 0; i < length; ++i) { |
| 2072 Object* o = js_obj->GetInternalField(i); | 1992 Object* o = js_obj->GetInternalField(i); |
| 2073 SetInternalReference(js_obj, entry, i, o); | 1993 SetInternalReference(js_obj, entry, i, o); |
| 2074 } | 1994 } |
| 2075 } | 1995 } |
| 2076 | 1996 |
| 2077 | 1997 |
| 2078 void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj, | 1998 HeapEntry* V8HeapExplorer::GetEntry(Object* obj) { |
| 2079 HeapEntry* parent_entry, | 1999 if (!obj->IsHeapObject()) return NULL; |
| 2080 String* reference_name, | 2000 return filler_->FindOrAddEntry(obj, this); |
| 2081 Object* child_obj) { | 2001 } |
| 2002 |
| 2003 |
| 2004 class RootsReferencesExtractor : public ObjectVisitor { |
| 2005 public: |
| 2006 explicit RootsReferencesExtractor(V8HeapExplorer* explorer) |
| 2007 : explorer_(explorer) { |
| 2008 } |
| 2009 void VisitPointers(Object** start, Object** end) { |
| 2010 for (Object** p = start; p < end; p++) explorer_->SetGcRootsReference(*p); |
| 2011 } |
| 2012 private: |
| 2013 V8HeapExplorer* explorer_; |
| 2014 }; |
| 2015 |
| 2016 |
| 2017 bool V8HeapExplorer::IterateAndExtractReferences( |
| 2018 SnapshotFillerInterface* filler) { |
| 2019 filler_ = filler; |
| 2020 HeapIterator iterator(HeapIterator::kFilterUnreachable); |
| 2021 bool interrupted = false; |
| 2022 // Heap iteration with filtering must be finished in any case. |
| 2023 for (HeapObject* obj = iterator.next(); |
| 2024 obj != NULL; |
| 2025 obj = iterator.next(), progress_->ProgressStep()) { |
| 2026 if (!interrupted) { |
| 2027 ExtractReferences(obj); |
| 2028 if (!progress_->ProgressReport(false)) interrupted = true; |
| 2029 } |
| 2030 } |
| 2031 if (interrupted) { |
| 2032 filler_ = NULL; |
| 2033 return false; |
| 2034 } |
| 2035 SetRootGcRootsReference(); |
| 2036 RootsReferencesExtractor extractor(this); |
| 2037 Heap::IterateRoots(&extractor, VISIT_ALL); |
| 2038 filler_ = NULL; |
| 2039 return progress_->ProgressReport(false); |
| 2040 } |
| 2041 |
| 2042 |
| 2043 void V8HeapExplorer::SetClosureReference(HeapObject* parent_obj, |
| 2044 HeapEntry* parent_entry, |
| 2045 String* reference_name, |
| 2046 Object* child_obj) { |
| 2082 HeapEntry* child_entry = GetEntry(child_obj); | 2047 HeapEntry* child_entry = GetEntry(child_obj); |
| 2083 if (child_entry != NULL) { | 2048 if (child_entry != NULL) { |
| 2084 filler_->SetNamedReference(HeapGraphEdge::kContextVariable, | 2049 filler_->SetNamedReference(HeapGraphEdge::kContextVariable, |
| 2085 parent_obj, | 2050 parent_obj, |
| 2086 parent_entry, | 2051 parent_entry, |
| 2087 collection_->GetName(reference_name), | 2052 collection_->names()->GetName(reference_name), |
| 2088 child_obj, | 2053 child_obj, |
| 2089 child_entry); | 2054 child_entry); |
| 2090 known_references_.Insert(child_obj); | 2055 known_references_.Insert(child_obj); |
| 2091 } | 2056 } |
| 2092 } | 2057 } |
| 2093 | 2058 |
| 2094 | 2059 |
| 2095 void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj, | 2060 void V8HeapExplorer::SetElementReference(HeapObject* parent_obj, |
| 2096 HeapEntry* parent_entry, | 2061 HeapEntry* parent_entry, |
| 2097 int index, | 2062 int index, |
| 2098 Object* child_obj) { | 2063 Object* child_obj) { |
| 2099 HeapEntry* child_entry = GetEntry(child_obj); | 2064 HeapEntry* child_entry = GetEntry(child_obj); |
| 2100 if (child_entry != NULL) { | 2065 if (child_entry != NULL) { |
| 2101 filler_->SetIndexedReference(HeapGraphEdge::kElement, | 2066 filler_->SetIndexedReference(HeapGraphEdge::kElement, |
| 2102 parent_obj, | 2067 parent_obj, |
| 2103 parent_entry, | 2068 parent_entry, |
| 2104 index, | 2069 index, |
| 2105 child_obj, | 2070 child_obj, |
| 2106 child_entry); | 2071 child_entry); |
| 2107 known_references_.Insert(child_obj); | 2072 known_references_.Insert(child_obj); |
| 2108 } | 2073 } |
| 2109 } | 2074 } |
| 2110 | 2075 |
| 2111 | 2076 |
| 2112 void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, | 2077 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
| 2113 HeapEntry* parent_entry, | 2078 HeapEntry* parent_entry, |
| 2114 const char* reference_name, | 2079 const char* reference_name, |
| 2115 Object* child_obj) { | 2080 Object* child_obj) { |
| 2116 HeapEntry* child_entry = GetEntry(child_obj); | 2081 HeapEntry* child_entry = GetEntry(child_obj); |
| 2117 if (child_entry != NULL) { | 2082 if (child_entry != NULL) { |
| 2118 filler_->SetNamedReference(HeapGraphEdge::kInternal, | 2083 filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| 2119 parent_obj, | 2084 parent_obj, |
| 2120 parent_entry, | 2085 parent_entry, |
| 2121 reference_name, | 2086 reference_name, |
| 2122 child_obj, | 2087 child_obj, |
| 2123 child_entry); | 2088 child_entry); |
| 2124 known_references_.Insert(child_obj); | 2089 known_references_.Insert(child_obj); |
| 2125 } | 2090 } |
| 2126 } | 2091 } |
| 2127 | 2092 |
| 2128 | 2093 |
| 2129 void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, | 2094 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
| 2130 HeapEntry* parent_entry, | 2095 HeapEntry* parent_entry, |
| 2131 int index, | 2096 int index, |
| 2132 Object* child_obj) { | 2097 Object* child_obj) { |
| 2133 HeapEntry* child_entry = GetEntry(child_obj); | 2098 HeapEntry* child_entry = GetEntry(child_obj); |
| 2134 if (child_entry != NULL) { | 2099 if (child_entry != NULL) { |
| 2135 filler_->SetNamedReference(HeapGraphEdge::kInternal, | 2100 filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| 2136 parent_obj, | 2101 parent_obj, |
| 2137 parent_entry, | 2102 parent_entry, |
| 2138 collection_->GetName(index), | 2103 collection_->names()->GetName(index), |
| 2139 child_obj, | 2104 child_obj, |
| 2140 child_entry); | 2105 child_entry); |
| 2141 known_references_.Insert(child_obj); | 2106 known_references_.Insert(child_obj); |
| 2142 } | 2107 } |
| 2143 } | 2108 } |
| 2144 | 2109 |
| 2145 | 2110 |
| 2146 void HeapSnapshotGenerator::SetHiddenReference(HeapObject* parent_obj, | 2111 void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, |
| 2147 HeapEntry* parent_entry, | 2112 HeapEntry* parent_entry, |
| 2148 int index, | 2113 int index, |
| 2149 Object* child_obj) { | 2114 Object* child_obj) { |
| 2150 HeapEntry* child_entry = GetEntry(child_obj); | 2115 HeapEntry* child_entry = GetEntry(child_obj); |
| 2151 if (child_entry != NULL) { | 2116 if (child_entry != NULL) { |
| 2152 filler_->SetIndexedReference(HeapGraphEdge::kHidden, | 2117 filler_->SetIndexedReference(HeapGraphEdge::kHidden, |
| 2153 parent_obj, | 2118 parent_obj, |
| 2154 parent_entry, | 2119 parent_entry, |
| 2155 index, | 2120 index, |
| 2156 child_obj, | 2121 child_obj, |
| 2157 child_entry); | 2122 child_entry); |
| 2158 } | 2123 } |
| 2159 } | 2124 } |
| 2160 | 2125 |
| 2161 | 2126 |
| 2162 void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj, | 2127 void V8HeapExplorer::SetPropertyReference(HeapObject* parent_obj, |
| 2163 HeapEntry* parent_entry, | 2128 HeapEntry* parent_entry, |
| 2164 String* reference_name, | 2129 String* reference_name, |
| 2165 Object* child_obj) { | 2130 Object* child_obj) { |
| 2166 HeapEntry* child_entry = GetEntry(child_obj); | 2131 HeapEntry* child_entry = GetEntry(child_obj); |
| 2167 if (child_entry != NULL) { | 2132 if (child_entry != NULL) { |
| 2168 HeapGraphEdge::Type type = reference_name->length() > 0 ? | 2133 HeapGraphEdge::Type type = reference_name->length() > 0 ? |
| 2169 HeapGraphEdge::kProperty : HeapGraphEdge::kInternal; | 2134 HeapGraphEdge::kProperty : HeapGraphEdge::kInternal; |
| 2170 filler_->SetNamedReference(type, | 2135 filler_->SetNamedReference(type, |
| 2171 parent_obj, | 2136 parent_obj, |
| 2172 parent_entry, | 2137 parent_entry, |
| 2173 collection_->GetName(reference_name), | 2138 collection_->names()->GetName(reference_name), |
| 2174 child_obj, | 2139 child_obj, |
| 2175 child_entry); | 2140 child_entry); |
| 2176 known_references_.Insert(child_obj); | 2141 known_references_.Insert(child_obj); |
| 2177 } | 2142 } |
| 2178 } | 2143 } |
| 2179 | 2144 |
| 2180 | 2145 |
| 2181 void HeapSnapshotGenerator::SetPropertyShortcutReference( | 2146 void V8HeapExplorer::SetPropertyShortcutReference( |
| 2182 HeapObject* parent_obj, | 2147 HeapObject* parent_obj, |
| 2183 HeapEntry* parent_entry, | 2148 HeapEntry* parent_entry, |
| 2184 String* reference_name, | 2149 String* reference_name, |
| 2185 Object* child_obj) { | 2150 Object* child_obj) { |
| 2186 HeapEntry* child_entry = GetEntry(child_obj); | 2151 HeapEntry* child_entry = GetEntry(child_obj); |
| 2187 if (child_entry != NULL) { | 2152 if (child_entry != NULL) { |
| 2188 filler_->SetNamedReference(HeapGraphEdge::kShortcut, | 2153 filler_->SetNamedReference(HeapGraphEdge::kShortcut, |
| 2189 parent_obj, | 2154 parent_obj, |
| 2190 parent_entry, | 2155 parent_entry, |
| 2191 collection_->GetName(reference_name), | 2156 collection_->names()->GetName(reference_name), |
| 2192 child_obj, | 2157 child_obj, |
| 2193 child_entry); | 2158 child_entry); |
| 2194 } | 2159 } |
| 2195 } | 2160 } |
| 2196 | 2161 |
| 2197 | 2162 |
| 2198 void HeapSnapshotGenerator::SetRootGcRootsReference() { | 2163 void V8HeapExplorer::SetRootGcRootsReference() { |
| 2199 filler_->SetRootGcRootsReference(); | 2164 filler_->SetIndexedAutoIndexReference( |
| 2200 } | 2165 HeapGraphEdge::kElement, |
| 2201 | 2166 kInternalRootObject, snapshot_->root(), |
| 2202 | 2167 kGcRootsObject, snapshot_->gc_roots()); |
| 2203 void HeapSnapshotGenerator::SetRootShortcutReference(Object* child_obj) { | 2168 } |
| 2169 |
| 2170 |
| 2171 void V8HeapExplorer::SetRootShortcutReference(Object* child_obj) { |
| 2204 HeapEntry* child_entry = GetEntry(child_obj); | 2172 HeapEntry* child_entry = GetEntry(child_obj); |
| 2205 ASSERT(child_entry != NULL); | 2173 ASSERT(child_entry != NULL); |
| 2206 filler_->SetRootShortcutReference(child_obj, child_entry); | 2174 filler_->SetNamedAutoIndexReference( |
| 2207 } | 2175 HeapGraphEdge::kShortcut, |
| 2208 | 2176 kInternalRootObject, snapshot_->root(), |
| 2209 | 2177 child_obj, child_entry); |
| 2210 void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) { | 2178 } |
| 2179 |
| 2180 |
| 2181 void V8HeapExplorer::SetGcRootsReference(Object* child_obj) { |
| 2211 HeapEntry* child_entry = GetEntry(child_obj); | 2182 HeapEntry* child_entry = GetEntry(child_obj); |
| 2212 if (child_entry != NULL) { | 2183 if (child_entry != NULL) { |
| 2213 filler_->SetStrongRootReference(child_obj, child_entry); | 2184 filler_->SetIndexedAutoIndexReference( |
| 2214 } | 2185 HeapGraphEdge::kElement, |
| 2186 kGcRootsObject, snapshot_->gc_roots(), |
| 2187 child_obj, child_entry); |
| 2188 } |
| 2189 } |
| 2190 |
| 2191 |
| 2192 class GlobalHandlesExtractor : public ObjectVisitor { |
| 2193 public: |
| 2194 explicit GlobalHandlesExtractor(NativeObjectsExplorer* explorer) |
| 2195 : explorer_(explorer) {} |
| 2196 virtual ~GlobalHandlesExtractor() {} |
| 2197 virtual void VisitPointers(Object** start, Object** end) { |
| 2198 UNREACHABLE(); |
| 2199 } |
| 2200 virtual void VisitEmbedderReference(Object** p, uint16_t class_id) { |
| 2201 explorer_->VisitSubtreeWrapper(p, class_id); |
| 2202 } |
| 2203 private: |
| 2204 NativeObjectsExplorer* explorer_; |
| 2205 }; |
| 2206 |
| 2207 HeapThing const NativeObjectsExplorer::kNativesRootObject = |
| 2208 reinterpret_cast<HeapThing>( |
| 2209 static_cast<intptr_t>(HeapObjectsMap::kNativesRootObjectId)); |
| 2210 |
| 2211 |
| 2212 NativeObjectsExplorer::NativeObjectsExplorer( |
| 2213 HeapSnapshot* snapshot, SnapshottingProgressReportingInterface* progress) |
| 2214 : snapshot_(snapshot), |
| 2215 collection_(snapshot_->collection()), |
| 2216 progress_(progress), |
| 2217 embedder_queried_(false), |
| 2218 objects_by_info_(RetainedInfosMatch), |
| 2219 filler_(NULL) { |
| 2220 } |
| 2221 |
| 2222 |
| 2223 NativeObjectsExplorer::~NativeObjectsExplorer() { |
| 2224 for (HashMap::Entry* p = objects_by_info_.Start(); |
| 2225 p != NULL; |
| 2226 p = objects_by_info_.Next(p)) { |
| 2227 v8::RetainedObjectInfo* info = |
| 2228 reinterpret_cast<v8::RetainedObjectInfo*>(p->key); |
| 2229 info->Dispose(); |
| 2230 List<HeapObject*>* objects = |
| 2231 reinterpret_cast<List<HeapObject*>* >(p->value); |
| 2232 delete objects; |
| 2233 } |
| 2234 } |
| 2235 |
| 2236 |
| 2237 HeapEntry* NativeObjectsExplorer::AllocateEntry( |
| 2238 HeapThing ptr, int children_count, int retainers_count) { |
| 2239 if (ptr == kNativesRootObject) { |
| 2240 return snapshot_->AddNativesRootEntry(children_count, retainers_count); |
| 2241 } else { |
| 2242 v8::RetainedObjectInfo* info = |
| 2243 reinterpret_cast<v8::RetainedObjectInfo*>(ptr); |
| 2244 intptr_t elements = info->GetElementCount(); |
| 2245 intptr_t size = info->GetSizeInBytes(); |
| 2246 return snapshot_->AddEntry( |
| 2247 HeapEntry::kNative, |
| 2248 elements != -1 ? |
| 2249 collection_->names()->GetFormatted( |
| 2250 "%s / %" V8_PTR_PREFIX "d entries", |
| 2251 info->GetLabel(), |
| 2252 info->GetElementCount()) : |
| 2253 collection_->names()->GetCopy(info->GetLabel()), |
| 2254 HeapObjectsMap::GenerateId(info), |
| 2255 size != -1 ? static_cast<int>(size) : 0, |
| 2256 children_count, |
| 2257 retainers_count); |
| 2258 } |
| 2259 } |
| 2260 |
| 2261 |
| 2262 void NativeObjectsExplorer::AddRootEntries(SnapshotFillerInterface* filler) { |
| 2263 if (EstimateObjectsCount() <= 0) return; |
| 2264 filler->AddEntry(kNativesRootObject, this); |
| 2265 } |
| 2266 |
| 2267 |
| 2268 int NativeObjectsExplorer::EstimateObjectsCount() { |
| 2269 FillRetainedObjects(); |
| 2270 return objects_by_info_.occupancy(); |
| 2271 } |
| 2272 |
| 2273 |
| 2274 void NativeObjectsExplorer::FillRetainedObjects() { |
| 2275 if (embedder_queried_) return; |
| 2276 // Record objects that are joined into ObjectGroups. |
| 2277 Heap::CallGlobalGCPrologueCallback(); |
| 2278 List<ObjectGroup*>* groups = GlobalHandles::ObjectGroups(); |
| 2279 for (int i = 0; i < groups->length(); ++i) { |
| 2280 ObjectGroup* group = groups->at(i); |
| 2281 if (group->info_ == NULL) continue; |
| 2282 List<HeapObject*>* list = GetListMaybeDisposeInfo(group->info_); |
| 2283 for (int j = 0; j < group->objects_.length(); ++j) { |
| 2284 HeapObject* obj = HeapObject::cast(*group->objects_[j]); |
| 2285 list->Add(obj); |
| 2286 in_groups_.Insert(obj); |
| 2287 } |
| 2288 group->info_ = NULL; // Acquire info object ownership. |
| 2289 } |
| 2290 GlobalHandles::RemoveObjectGroups(); |
| 2291 Heap::CallGlobalGCEpilogueCallback(); |
| 2292 // Record objects that are not in ObjectGroups, but have class ID. |
| 2293 GlobalHandlesExtractor extractor(this); |
| 2294 GlobalHandles::IterateAllRootsWithClassIds(&extractor); |
| 2295 embedder_queried_ = true; |
| 2296 } |
| 2297 |
| 2298 |
| 2299 List<HeapObject*>* NativeObjectsExplorer::GetListMaybeDisposeInfo( |
| 2300 v8::RetainedObjectInfo* info) { |
| 2301 HashMap::Entry* entry = |
| 2302 objects_by_info_.Lookup(info, InfoHash(info), true); |
| 2303 if (entry->value != NULL) { |
| 2304 info->Dispose(); |
| 2305 } else { |
| 2306 entry->value = new List<HeapObject*>(4); |
| 2307 } |
| 2308 return reinterpret_cast<List<HeapObject*>* >(entry->value); |
| 2309 } |
| 2310 |
| 2311 |
| 2312 bool NativeObjectsExplorer::IterateAndExtractReferences( |
| 2313 SnapshotFillerInterface* filler) { |
| 2314 if (EstimateObjectsCount() <= 0) return true; |
| 2315 filler_ = filler; |
| 2316 FillRetainedObjects(); |
| 2317 for (HashMap::Entry* p = objects_by_info_.Start(); |
| 2318 p != NULL; |
| 2319 p = objects_by_info_.Next(p)) { |
| 2320 v8::RetainedObjectInfo* info = |
| 2321 reinterpret_cast<v8::RetainedObjectInfo*>(p->key); |
| 2322 SetNativeRootReference(info); |
| 2323 List<HeapObject*>* objects = |
| 2324 reinterpret_cast<List<HeapObject*>* >(p->value); |
| 2325 for (int i = 0; i < objects->length(); ++i) { |
| 2326 SetWrapperNativeReferences(objects->at(i), info); |
| 2327 } |
| 2328 } |
| 2329 SetRootNativesRootReference(); |
| 2330 filler_ = NULL; |
| 2331 return true; |
| 2332 } |
| 2333 |
| 2334 |
| 2335 void NativeObjectsExplorer::SetNativeRootReference( |
| 2336 v8::RetainedObjectInfo* info) { |
| 2337 HeapEntry* child_entry = filler_->FindOrAddEntry(info, this); |
| 2338 ASSERT(child_entry != NULL); |
| 2339 filler_->SetIndexedAutoIndexReference( |
| 2340 HeapGraphEdge::kElement, |
| 2341 kNativesRootObject, snapshot_->natives_root(), |
| 2342 info, child_entry); |
| 2343 } |
| 2344 |
| 2345 |
| 2346 void NativeObjectsExplorer::SetWrapperNativeReferences( |
| 2347 HeapObject* wrapper, v8::RetainedObjectInfo* info) { |
| 2348 HeapEntry* wrapper_entry = filler_->FindEntry(wrapper); |
| 2349 ASSERT(wrapper_entry != NULL); |
| 2350 HeapEntry* info_entry = filler_->FindOrAddEntry(info, this); |
| 2351 ASSERT(info_entry != NULL); |
| 2352 filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| 2353 wrapper, wrapper_entry, |
| 2354 "Native", |
| 2355 info, info_entry); |
| 2356 filler_->SetIndexedAutoIndexReference(HeapGraphEdge::kElement, |
| 2357 info, info_entry, |
| 2358 wrapper, wrapper_entry); |
| 2359 } |
| 2360 |
| 2361 |
| 2362 void NativeObjectsExplorer::SetRootNativesRootReference() { |
| 2363 filler_->SetIndexedAutoIndexReference( |
| 2364 HeapGraphEdge::kElement, |
| 2365 V8HeapExplorer::kInternalRootObject, snapshot_->root(), |
| 2366 kNativesRootObject, snapshot_->natives_root()); |
| 2367 } |
| 2368 |
| 2369 |
| 2370 void NativeObjectsExplorer::VisitSubtreeWrapper(Object** p, uint16_t class_id) { |
| 2371 if (in_groups_.Contains(*p)) return; |
| 2372 v8::RetainedObjectInfo* info = |
| 2373 HeapProfiler::ExecuteWrapperClassCallback(class_id, p); |
| 2374 if (info == NULL) return; |
| 2375 GetListMaybeDisposeInfo(info)->Add(HeapObject::cast(*p)); |
| 2376 } |
| 2377 |
| 2378 |
| 2379 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, |
| 2380 v8::ActivityControl* control) |
| 2381 : snapshot_(snapshot), |
| 2382 control_(control), |
| 2383 v8_heap_explorer_(snapshot_, this), |
| 2384 dom_explorer_(snapshot_, this) { |
| 2385 } |
| 2386 |
| 2387 |
| 2388 class SnapshotCounter : public SnapshotFillerInterface { |
| 2389 public: |
| 2390 explicit SnapshotCounter(HeapEntriesMap* entries) : entries_(entries) { } |
| 2391 HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| 2392 entries_->Pair(ptr, allocator, HeapEntriesMap::kHeapEntryPlaceholder); |
| 2393 return HeapEntriesMap::kHeapEntryPlaceholder; |
| 2394 } |
| 2395 HeapEntry* FindEntry(HeapThing ptr) { |
| 2396 return entries_->Map(ptr); |
| 2397 } |
| 2398 HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| 2399 HeapEntry* entry = FindEntry(ptr); |
| 2400 return entry != NULL ? entry : AddEntry(ptr, allocator); |
| 2401 } |
| 2402 void SetIndexedReference(HeapGraphEdge::Type, |
| 2403 HeapThing parent_ptr, |
| 2404 HeapEntry*, |
| 2405 int, |
| 2406 HeapThing child_ptr, |
| 2407 HeapEntry*) { |
| 2408 entries_->CountReference(parent_ptr, child_ptr); |
| 2409 } |
| 2410 void SetIndexedAutoIndexReference(HeapGraphEdge::Type, |
| 2411 HeapThing parent_ptr, |
| 2412 HeapEntry*, |
| 2413 HeapThing child_ptr, |
| 2414 HeapEntry*) { |
| 2415 entries_->CountReference(parent_ptr, child_ptr); |
| 2416 } |
| 2417 void SetNamedReference(HeapGraphEdge::Type, |
| 2418 HeapThing parent_ptr, |
| 2419 HeapEntry*, |
| 2420 const char*, |
| 2421 HeapThing child_ptr, |
| 2422 HeapEntry*) { |
| 2423 entries_->CountReference(parent_ptr, child_ptr); |
| 2424 } |
| 2425 void SetNamedAutoIndexReference(HeapGraphEdge::Type, |
| 2426 HeapThing parent_ptr, |
| 2427 HeapEntry*, |
| 2428 HeapThing child_ptr, |
| 2429 HeapEntry*) { |
| 2430 entries_->CountReference(parent_ptr, child_ptr); |
| 2431 } |
| 2432 private: |
| 2433 HeapEntriesMap* entries_; |
| 2434 }; |
| 2435 |
| 2436 |
| 2437 class SnapshotFiller : public SnapshotFillerInterface { |
| 2438 public: |
| 2439 explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) |
| 2440 : snapshot_(snapshot), |
| 2441 collection_(snapshot->collection()), |
| 2442 entries_(entries) { } |
| 2443 HeapEntry* AddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| 2444 UNREACHABLE(); |
| 2445 return NULL; |
| 2446 } |
| 2447 HeapEntry* FindEntry(HeapThing ptr) { |
| 2448 return entries_->Map(ptr); |
| 2449 } |
| 2450 HeapEntry* FindOrAddEntry(HeapThing ptr, HeapEntriesAllocator* allocator) { |
| 2451 HeapEntry* entry = FindEntry(ptr); |
| 2452 return entry != NULL ? entry : AddEntry(ptr, allocator); |
| 2453 } |
| 2454 void SetIndexedReference(HeapGraphEdge::Type type, |
| 2455 HeapThing parent_ptr, |
| 2456 HeapEntry* parent_entry, |
| 2457 int index, |
| 2458 HeapThing child_ptr, |
| 2459 HeapEntry* child_entry) { |
| 2460 int child_index, retainer_index; |
| 2461 entries_->CountReference( |
| 2462 parent_ptr, child_ptr, &child_index, &retainer_index); |
| 2463 parent_entry->SetIndexedReference( |
| 2464 type, child_index, index, child_entry, retainer_index); |
| 2465 } |
| 2466 void SetIndexedAutoIndexReference(HeapGraphEdge::Type type, |
| 2467 HeapThing parent_ptr, |
| 2468 HeapEntry* parent_entry, |
| 2469 HeapThing child_ptr, |
| 2470 HeapEntry* child_entry) { |
| 2471 int child_index, retainer_index; |
| 2472 entries_->CountReference( |
| 2473 parent_ptr, child_ptr, &child_index, &retainer_index); |
| 2474 parent_entry->SetIndexedReference( |
| 2475 type, child_index, child_index + 1, child_entry, retainer_index); |
| 2476 } |
| 2477 void SetNamedReference(HeapGraphEdge::Type type, |
| 2478 HeapThing parent_ptr, |
| 2479 HeapEntry* parent_entry, |
| 2480 const char* reference_name, |
| 2481 HeapThing child_ptr, |
| 2482 HeapEntry* child_entry) { |
| 2483 int child_index, retainer_index; |
| 2484 entries_->CountReference( |
| 2485 parent_ptr, child_ptr, &child_index, &retainer_index); |
| 2486 parent_entry->SetNamedReference( |
| 2487 type, child_index, reference_name, child_entry, retainer_index); |
| 2488 } |
| 2489 void SetNamedAutoIndexReference(HeapGraphEdge::Type type, |
| 2490 HeapThing parent_ptr, |
| 2491 HeapEntry* parent_entry, |
| 2492 HeapThing child_ptr, |
| 2493 HeapEntry* child_entry) { |
| 2494 int child_index, retainer_index; |
| 2495 entries_->CountReference( |
| 2496 parent_ptr, child_ptr, &child_index, &retainer_index); |
| 2497 parent_entry->SetNamedReference(type, |
| 2498 child_index, |
| 2499 collection_->names()->GetName(child_index + 1), |
| 2500 child_entry, |
| 2501 retainer_index); |
| 2502 } |
| 2503 private: |
| 2504 HeapSnapshot* snapshot_; |
| 2505 HeapSnapshotsCollection* collection_; |
| 2506 HeapEntriesMap* entries_; |
| 2507 }; |
| 2508 |
| 2509 |
| 2510 bool HeapSnapshotGenerator::GenerateSnapshot() { |
| 2511 AssertNoAllocation no_alloc; |
| 2512 |
| 2513 SetProgressTotal(4); // 2 passes + dominators + sizes. |
| 2514 |
| 2515 // Pass 1. Iterate heap contents to count entries and references. |
| 2516 if (!CountEntriesAndReferences()) return false; |
| 2517 |
| 2518 // Allocate and fill entries in the snapshot, allocate references. |
| 2519 snapshot_->AllocateEntries(entries_.entries_count(), |
| 2520 entries_.total_children_count(), |
| 2521 entries_.total_retainers_count()); |
| 2522 entries_.AllocateEntries(); |
| 2523 |
| 2524 // Pass 2. Fill references. |
| 2525 if (!FillReferences()) return false; |
| 2526 |
| 2527 if (!SetEntriesDominators()) return false; |
| 2528 if (!ApproximateRetainedSizes()) return false; |
| 2529 |
| 2530 progress_counter_ = progress_total_; |
| 2531 if (!ProgressReport(true)) return false; |
| 2532 return true; |
| 2533 } |
| 2534 |
| 2535 |
| 2536 void HeapSnapshotGenerator::ProgressStep() { |
| 2537 ++progress_counter_; |
| 2538 } |
| 2539 |
| 2540 |
| 2541 bool HeapSnapshotGenerator::ProgressReport(bool force) { |
| 2542 const int kProgressReportGranularity = 10000; |
| 2543 if (control_ != NULL |
| 2544 && (force || progress_counter_ % kProgressReportGranularity == 0)) { |
| 2545 return |
| 2546 control_->ReportProgressValue(progress_counter_, progress_total_) == |
| 2547 v8::ActivityControl::kContinue; |
| 2548 } |
| 2549 return true; |
| 2215 } | 2550 } |
| 2216 | 2551 |
| 2217 | 2552 |
| 2218 void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { | 2553 void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { |
| 2219 if (control_ == NULL) return; | 2554 if (control_ == NULL) return; |
| 2220 | 2555 progress_total_ = ( |
| 2221 HeapIterator iterator(HeapIterator::kFilterUnreachable); | 2556 v8_heap_explorer_.EstimateObjectsCount() + |
| 2222 int objects_count = 0; | 2557 dom_explorer_.EstimateObjectsCount()) * iterations_count; |
| 2223 for (HeapObject* obj = iterator.next(); | |
| 2224 obj != NULL; | |
| 2225 obj = iterator.next(), ++objects_count) {} | |
| 2226 progress_total_ = objects_count * iterations_count; | |
| 2227 progress_counter_ = 0; | 2558 progress_counter_ = 0; |
| 2228 } | 2559 } |
| 2229 | 2560 |
| 2230 | 2561 |
| 2231 bool HeapSnapshotGenerator::CountEntriesAndReferences() { | 2562 bool HeapSnapshotGenerator::CountEntriesAndReferences() { |
| 2232 SnapshotCounter counter(&entries_); | 2563 SnapshotCounter counter(&entries_); |
| 2233 filler_ = &counter; | 2564 v8_heap_explorer_.AddRootEntries(&counter); |
| 2234 filler_->AddEntry(HeapSnapshot::kInternalRootObject); | 2565 dom_explorer_.AddRootEntries(&counter); |
| 2235 filler_->AddEntry(HeapSnapshot::kGcRootsObject); | 2566 return |
| 2236 return IterateAndExtractReferences(); | 2567 v8_heap_explorer_.IterateAndExtractReferences(&counter) && |
| 2568 dom_explorer_.IterateAndExtractReferences(&counter); |
| 2237 } | 2569 } |
| 2238 | 2570 |
| 2239 | 2571 |
| 2240 bool HeapSnapshotGenerator::FillReferences() { | 2572 bool HeapSnapshotGenerator::FillReferences() { |
| 2241 SnapshotFiller filler(snapshot_, &entries_); | 2573 SnapshotFiller filler(snapshot_, &entries_); |
| 2242 filler_ = &filler; | 2574 return |
| 2243 return IterateAndExtractReferences(); | 2575 v8_heap_explorer_.IterateAndExtractReferences(&filler) && |
| 2244 } | 2576 dom_explorer_.IterateAndExtractReferences(&filler); |
| 2245 | 2577 } |
| 2246 | 2578 |
| 2579 |
| 2247 void HeapSnapshotGenerator::FillReversePostorderIndexes( | 2580 void HeapSnapshotGenerator::FillReversePostorderIndexes( |
| 2248 Vector<HeapEntry*>* entries) { | 2581 Vector<HeapEntry*>* entries) { |
| 2249 snapshot_->ClearPaint(); | 2582 snapshot_->ClearPaint(); |
| 2250 int current_entry = 0; | 2583 int current_entry = 0; |
| 2251 List<HeapEntry*> nodes_to_visit; | 2584 List<HeapEntry*> nodes_to_visit; |
| 2252 nodes_to_visit.Add(snapshot_->root()); | 2585 nodes_to_visit.Add(snapshot_->root()); |
| 2253 snapshot_->root()->paint_reachable(); | 2586 snapshot_->root()->paint_reachable(); |
| 2254 while (!nodes_to_visit.is_empty()) { | 2587 while (!nodes_to_visit.is_empty()) { |
| 2255 HeapEntry* entry = nodes_to_visit.last(); | 2588 HeapEntry* entry = nodes_to_visit.last(); |
| 2256 Vector<HeapGraphEdge> children = entry->children(); | 2589 Vector<HeapGraphEdge> children = entry->children(); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2319 } | 2652 } |
| 2320 } | 2653 } |
| 2321 if (new_idom != NULL && dominators->at(i) != new_idom) { | 2654 if (new_idom != NULL && dominators->at(i) != new_idom) { |
| 2322 (*dominators)[i] = new_idom; | 2655 (*dominators)[i] = new_idom; |
| 2323 ++changed; | 2656 ++changed; |
| 2324 } | 2657 } |
| 2325 } | 2658 } |
| 2326 int remaining = entries_length - changed; | 2659 int remaining = entries_length - changed; |
| 2327 if (remaining < 0) remaining = 0; | 2660 if (remaining < 0) remaining = 0; |
| 2328 progress_counter_ = base_progress_counter + remaining; | 2661 progress_counter_ = base_progress_counter + remaining; |
| 2329 if (!ReportProgress(true)) return false; | 2662 if (!ProgressReport(true)) return false; |
| 2330 } | 2663 } |
| 2331 return true; | 2664 return true; |
| 2332 } | 2665 } |
| 2333 | 2666 |
| 2334 | 2667 |
| 2335 bool HeapSnapshotGenerator::SetEntriesDominators() { | 2668 bool HeapSnapshotGenerator::SetEntriesDominators() { |
| 2336 // This array is used for maintaining reverse postorder of nodes. | 2669 // This array is used for maintaining reverse postorder of nodes. |
| 2337 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); | 2670 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); |
| 2338 FillReversePostorderIndexes(&ordered_entries); | 2671 FillReversePostorderIndexes(&ordered_entries); |
| 2339 ScopedVector<HeapEntry*> dominators(ordered_entries.length()); | 2672 ScopedVector<HeapEntry*> dominators(ordered_entries.length()); |
| 2340 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; | 2673 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
| 2341 for (int i = 0; i < ordered_entries.length(); ++i) { | 2674 for (int i = 0; i < ordered_entries.length(); ++i) { |
| 2342 ASSERT(dominators[i] != NULL); | 2675 ASSERT(dominators[i] != NULL); |
| 2343 ordered_entries[i]->set_dominator(dominators[i]); | 2676 ordered_entries[i]->set_dominator(dominators[i]); |
| 2344 } | 2677 } |
| 2345 return true; | 2678 return true; |
| 2346 } | 2679 } |
| 2347 | 2680 |
| 2348 | 2681 |
| 2349 bool HeapSnapshotGenerator::ApproximateRetainedSizes() { | 2682 bool HeapSnapshotGenerator::ApproximateRetainedSizes() { |
| 2350 // As for the dominators tree we only know parent nodes, not | 2683 // As for the dominators tree we only know parent nodes, not |
| 2351 // children, to sum up total sizes we "bubble" node's self size | 2684 // children, to sum up total sizes we "bubble" node's self size |
| 2352 // adding it to all of its parents. | 2685 // adding it to all of its parents. |
| 2353 for (int i = 0; i < snapshot_->entries()->length(); ++i) { | 2686 for (int i = 0; i < snapshot_->entries()->length(); ++i) { |
| 2354 HeapEntry* entry = snapshot_->entries()->at(i); | 2687 HeapEntry* entry = snapshot_->entries()->at(i); |
| 2355 entry->set_retained_size(entry->self_size()); | 2688 entry->set_retained_size(entry->self_size()); |
| 2356 } | 2689 } |
| 2357 for (int i = 0; | 2690 for (int i = 0; |
| 2358 i < snapshot_->entries()->length(); | 2691 i < snapshot_->entries()->length(); |
| 2359 ++i, IncProgressCounter()) { | 2692 ++i, ProgressStep()) { |
| 2360 HeapEntry* entry = snapshot_->entries()->at(i); | 2693 HeapEntry* entry = snapshot_->entries()->at(i); |
| 2361 int entry_size = entry->self_size(); | 2694 int entry_size = entry->self_size(); |
| 2362 for (HeapEntry* dominator = entry->dominator(); | 2695 for (HeapEntry* dominator = entry->dominator(); |
| 2363 dominator != entry; | 2696 dominator != entry; |
| 2364 entry = dominator, dominator = entry->dominator()) { | 2697 entry = dominator, dominator = entry->dominator()) { |
| 2365 dominator->add_retained_size(entry_size); | 2698 dominator->add_retained_size(entry_size); |
| 2366 } | 2699 } |
| 2367 if (!ReportProgress()) return false; | 2700 if (!ProgressReport()) return false; |
| 2368 } | 2701 } |
| 2369 return true; | 2702 return true; |
| 2370 } | 2703 } |
| 2371 | 2704 |
| 2372 | 2705 |
| 2373 bool HeapSnapshotGenerator::IterateAndExtractReferences() { | |
| 2374 HeapIterator iterator(HeapIterator::kFilterUnreachable); | |
| 2375 bool interrupted = false; | |
| 2376 // Heap iteration with filtering must be finished in any case. | |
| 2377 for (HeapObject* obj = iterator.next(); | |
| 2378 obj != NULL; | |
| 2379 obj = iterator.next(), IncProgressCounter()) { | |
| 2380 if (!interrupted) { | |
| 2381 ExtractReferences(obj); | |
| 2382 if (!ReportProgress()) interrupted = true; | |
| 2383 } | |
| 2384 } | |
| 2385 if (interrupted) return false; | |
| 2386 SetRootGcRootsReference(); | |
| 2387 RootsReferencesExtractor extractor(this); | |
| 2388 Heap::IterateRoots(&extractor, VISIT_ALL); | |
| 2389 return ReportProgress(); | |
| 2390 } | |
| 2391 | |
| 2392 | |
| 2393 void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { | 2706 void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { |
| 2394 raw_additions_root_ = | 2707 raw_additions_root_ = |
| 2395 NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); | 2708 NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); |
| 2396 additions_root()->Init( | 2709 additions_root()->Init( |
| 2397 snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0); | 2710 snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0); |
| 2398 raw_deletions_root_ = | 2711 raw_deletions_root_ = |
| 2399 NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0)); | 2712 NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0)); |
| 2400 deletions_root()->Init( | 2713 deletions_root()->Init( |
| 2401 snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0); | 2714 snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0); |
| 2402 } | 2715 } |
| (...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2671 "," JSON_S("children")) | 2984 "," JSON_S("children")) |
| 2672 "," JSON_S("types") ":" JSON_A( | 2985 "," JSON_S("types") ":" JSON_A( |
| 2673 JSON_A( | 2986 JSON_A( |
| 2674 JSON_S("hidden") | 2987 JSON_S("hidden") |
| 2675 "," JSON_S("array") | 2988 "," JSON_S("array") |
| 2676 "," JSON_S("string") | 2989 "," JSON_S("string") |
| 2677 "," JSON_S("object") | 2990 "," JSON_S("object") |
| 2678 "," JSON_S("code") | 2991 "," JSON_S("code") |
| 2679 "," JSON_S("closure") | 2992 "," JSON_S("closure") |
| 2680 "," JSON_S("regexp") | 2993 "," JSON_S("regexp") |
| 2681 "," JSON_S("number")) | 2994 "," JSON_S("number") |
| 2995 "," JSON_S("native")) |
| 2682 "," JSON_S("string") | 2996 "," JSON_S("string") |
| 2683 "," JSON_S("number") | 2997 "," JSON_S("number") |
| 2684 "," JSON_S("number") | 2998 "," JSON_S("number") |
| 2685 "," JSON_S("number") | 2999 "," JSON_S("number") |
| 2686 "," JSON_S("number") | 3000 "," JSON_S("number") |
| 2687 "," JSON_S("number") | 3001 "," JSON_S("number") |
| 2688 "," JSON_O( | 3002 "," JSON_O( |
| 2689 JSON_S("fields") ":" JSON_A( | 3003 JSON_S("fields") ":" JSON_A( |
| 2690 JSON_S("type") | 3004 JSON_S("type") |
| 2691 "," JSON_S("name_or_index") | 3005 "," JSON_S("name_or_index") |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2833 | 3147 |
| 2834 | 3148 |
| 2835 String* GetConstructorNameForHeapProfile(JSObject* object) { | 3149 String* GetConstructorNameForHeapProfile(JSObject* object) { |
| 2836 if (object->IsJSFunction()) return Heap::closure_symbol(); | 3150 if (object->IsJSFunction()) return Heap::closure_symbol(); |
| 2837 return object->constructor_name(); | 3151 return object->constructor_name(); |
| 2838 } | 3152 } |
| 2839 | 3153 |
| 2840 } } // namespace v8::internal | 3154 } } // namespace v8::internal |
| 2841 | 3155 |
| 2842 #endif // ENABLE_LOGGING_AND_PROFILING | 3156 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |