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 780 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 // If no frames were symbolized, put the VM state entry in. | 791 // If no frames were symbolized, put the VM state entry in. |
792 if (no_symbolized_entries) { | 792 if (no_symbolized_entries) { |
793 *entry++ = EntryForVMState(sample.state); | 793 *entry++ = EntryForVMState(sample.state); |
794 } | 794 } |
795 } | 795 } |
796 | 796 |
797 profiles_->AddPathToCurrentProfiles(entries); | 797 profiles_->AddPathToCurrentProfiles(entries); |
798 } | 798 } |
799 | 799 |
800 | 800 |
801 HeapGraphEdge::HeapGraphEdge(Type type, | 801 void HeapGraphEdge::Init( |
802 const char* name, | 802 int child_index, Type type, const char* name, HeapEntry* to) { |
803 HeapEntry* from, | 803 ASSERT(type == kContextVariable || type == kProperty || type == kInternal); |
804 HeapEntry* to) | 804 child_index_ = child_index; |
805 : type_(type), name_(name), from_(from), to_(to) { | 805 type_ = type; |
806 ASSERT(type_ == CONTEXT_VARIABLE || type_ == PROPERTY || type_ == INTERNAL); | 806 name_ = name; |
| 807 to_ = to; |
807 } | 808 } |
808 | 809 |
809 | 810 |
810 HeapGraphEdge::HeapGraphEdge(int index, | 811 void HeapGraphEdge::Init(int child_index, int index, HeapEntry* to) { |
811 HeapEntry* from, | 812 child_index_ = child_index; |
812 HeapEntry* to) | 813 type_ = kElement; |
813 : type_(ELEMENT), index_(index), from_(from), to_(to) { | 814 index_ = index; |
| 815 to_ = to; |
814 } | 816 } |
815 | 817 |
816 | 818 |
817 static void DeleteHeapGraphEdge(HeapGraphEdge** edge_ptr) { | 819 HeapEntry* HeapGraphEdge::From() { |
818 delete *edge_ptr; | 820 return reinterpret_cast<HeapEntry*>(this - child_index_) - 1; |
819 } | 821 } |
820 | 822 |
821 | 823 |
822 static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) { | 824 void HeapEntry::Init(HeapSnapshot* snapshot, |
823 delete *path_ptr; | 825 int children_count, |
| 826 int retainers_count) { |
| 827 Init(snapshot, kInternal, "", 0, 0, children_count, retainers_count); |
824 } | 828 } |
825 | 829 |
826 | 830 |
827 HeapEntry::~HeapEntry() { | 831 void HeapEntry::Init(HeapSnapshot* snapshot, |
828 children_.Iterate(DeleteHeapGraphEdge); | 832 Type type, |
829 retaining_paths_.Iterate(DeleteHeapGraphPath); | 833 const char* name, |
| 834 uint64_t id, |
| 835 int self_size, |
| 836 int children_count, |
| 837 int retainers_count) { |
| 838 snapshot_ = snapshot; |
| 839 type_ = type; |
| 840 painted_ = kUnpainted; |
| 841 calculated_data_index_ = kNoCalculatedData; |
| 842 name_ = name; |
| 843 id_ = id; |
| 844 self_size_ = self_size; |
| 845 children_count_ = children_count; |
| 846 retainers_count_ = retainers_count; |
830 } | 847 } |
831 | 848 |
832 | 849 |
833 void HeapEntry::AddEdge(HeapGraphEdge* edge) { | 850 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
834 children_.Add(edge); | 851 int child_index, |
835 edge->to()->retainers_.Add(edge); | 852 const char* name, |
| 853 HeapEntry* entry, |
| 854 int retainer_index) { |
| 855 children_arr()[child_index].Init(child_index, type, name, entry); |
| 856 entry->retainers_arr()[retainer_index] = children_arr() + child_index; |
836 } | 857 } |
837 | 858 |
838 | 859 |
839 void HeapEntry::SetClosureReference(const char* name, HeapEntry* entry) { | 860 void HeapEntry::SetElementReference( |
840 AddEdge( | 861 int child_index, int index, HeapEntry* entry, int retainer_index) { |
841 new HeapGraphEdge(HeapGraphEdge::CONTEXT_VARIABLE, name, this, entry)); | 862 children_arr()[child_index].Init(child_index, index, entry); |
| 863 entry->retainers_arr()[retainer_index] = children_arr() + child_index; |
842 } | 864 } |
843 | 865 |
844 | 866 |
845 void HeapEntry::SetElementReference(int index, HeapEntry* entry) { | 867 void HeapEntry::SetUnidirElementReference( |
846 AddEdge(new HeapGraphEdge(index, this, entry)); | 868 int child_index, int index, HeapEntry* entry) { |
| 869 children_arr()[child_index].Init(child_index, index, entry); |
847 } | 870 } |
848 | 871 |
849 | 872 |
850 void HeapEntry::SetInternalReference(const char* name, HeapEntry* entry) { | 873 int HeapEntry::ReachableSize() { |
851 AddEdge(new HeapGraphEdge(HeapGraphEdge::INTERNAL, name, this, entry)); | 874 if (calculated_data_index_ == kNoCalculatedData) { |
| 875 calculated_data_index_ = snapshot_->AddCalculatedData(); |
| 876 } |
| 877 return snapshot_->GetCalculatedData( |
| 878 calculated_data_index_).ReachableSize(this); |
852 } | 879 } |
853 | 880 |
854 | 881 |
855 void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) { | 882 int HeapEntry::RetainedSize() { |
856 AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry)); | 883 if (calculated_data_index_ == kNoCalculatedData) { |
| 884 calculated_data_index_ = snapshot_->AddCalculatedData(); |
| 885 } |
| 886 return snapshot_->GetCalculatedData( |
| 887 calculated_data_index_).RetainedSize(this); |
857 } | 888 } |
858 | 889 |
859 | 890 |
860 void HeapEntry::SetAutoIndexReference(HeapEntry* entry) { | 891 List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() { |
861 SetElementReference(next_auto_index_++, entry); | 892 if (calculated_data_index_ == kNoCalculatedData) { |
| 893 calculated_data_index_ = snapshot_->AddCalculatedData(); |
| 894 } |
| 895 return snapshot_->GetCalculatedData( |
| 896 calculated_data_index_).GetRetainingPaths(this); |
862 } | 897 } |
863 | 898 |
864 | 899 |
865 void HeapEntry::SetUnidirAutoIndexReference(HeapEntry* entry) { | |
866 children_.Add(new HeapGraphEdge(next_auto_index_++, this, entry)); | |
867 } | |
868 | |
869 | |
870 int HeapEntry::TotalSize() { | |
871 return total_size_ != kUnknownSize ? total_size_ : CalculateTotalSize(); | |
872 } | |
873 | |
874 | |
875 int HeapEntry::NonSharedTotalSize() { | |
876 return non_shared_total_size_ != kUnknownSize ? | |
877 non_shared_total_size_ : CalculateNonSharedTotalSize(); | |
878 } | |
879 | |
880 | |
881 template<class Visitor> | 900 template<class Visitor> |
882 void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) { | 901 void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) { |
883 List<HeapEntry*> list(10); | 902 List<HeapEntry*> list(10); |
884 list.Add(this); | 903 list.Add(this); |
885 this->PaintReachable(); | 904 this->paint_reachable(); |
886 visitor->Apply(this); | 905 visitor->Apply(this); |
887 while (!list.is_empty()) { | 906 while (!list.is_empty()) { |
888 HeapEntry* entry = list.RemoveLast(); | 907 HeapEntry* entry = list.RemoveLast(); |
889 const int children_count = entry->children_.length(); | 908 Vector<HeapGraphEdge> children = entry->children(); |
890 for (int i = 0; i < children_count; ++i) { | 909 for (int i = 0; i < children.length(); ++i) { |
891 HeapEntry* child = entry->children_[i]->to(); | 910 HeapEntry* child = children[i].to(); |
892 if (!child->painted_reachable()) { | 911 if (!child->painted_reachable()) { |
893 list.Add(child); | 912 list.Add(child); |
894 child->PaintReachable(); | 913 child->paint_reachable(); |
895 visitor->Apply(child); | 914 visitor->Apply(child); |
896 } | 915 } |
897 } | 916 } |
898 } | 917 } |
899 } | 918 } |
900 | 919 |
901 | 920 |
902 class NullClass { | 921 class NullClass { |
903 public: | 922 public: |
904 void Apply(HeapEntry* entry) { } | 923 void Apply(HeapEntry* entry) { } |
905 }; | 924 }; |
906 | 925 |
907 void HeapEntry::PaintAllReachable() { | 926 void HeapEntry::PaintAllReachable() { |
908 NullClass null; | 927 NullClass null; |
909 ApplyAndPaintAllReachable(&null); | 928 ApplyAndPaintAllReachable(&null); |
910 } | 929 } |
911 | 930 |
912 | 931 |
913 class TotalSizeCalculator { | 932 void HeapEntry::Print(int max_depth, int indent) { |
| 933 OS::Print("%6d %6d %6d [%ld] ", |
| 934 self_size(), ReachableSize(), RetainedSize(), id_); |
| 935 if (type() != kString) { |
| 936 OS::Print("%s %.40s\n", TypeAsString(), name_); |
| 937 } else { |
| 938 OS::Print("\""); |
| 939 const char* c = name_; |
| 940 while (*c && (c - name_) <= 40) { |
| 941 if (*c != '\n') |
| 942 OS::Print("%c", *c); |
| 943 else |
| 944 OS::Print("\\n"); |
| 945 ++c; |
| 946 } |
| 947 OS::Print("\"\n"); |
| 948 } |
| 949 if (--max_depth == 0) return; |
| 950 Vector<HeapGraphEdge> ch = children(); |
| 951 for (int i = 0; i < ch.length(); ++i) { |
| 952 HeapGraphEdge& edge = ch[i]; |
| 953 switch (edge.type()) { |
| 954 case HeapGraphEdge::kContextVariable: |
| 955 OS::Print(" %*c #%s: ", indent, ' ', edge.name()); |
| 956 break; |
| 957 case HeapGraphEdge::kElement: |
| 958 OS::Print(" %*c %d: ", indent, ' ', edge.index()); |
| 959 break; |
| 960 case HeapGraphEdge::kInternal: |
| 961 OS::Print(" %*c $%s: ", indent, ' ', edge.name()); |
| 962 break; |
| 963 case HeapGraphEdge::kProperty: |
| 964 OS::Print(" %*c %s: ", indent, ' ', edge.name()); |
| 965 break; |
| 966 default: |
| 967 OS::Print("!!! unknown edge type: %d ", edge.type()); |
| 968 } |
| 969 edge.to()->Print(max_depth, indent + 2); |
| 970 } |
| 971 } |
| 972 |
| 973 |
| 974 const char* HeapEntry::TypeAsString() { |
| 975 switch (type()) { |
| 976 case kInternal: return "/internal/"; |
| 977 case kObject: return "/object/"; |
| 978 case kClosure: return "/closure/"; |
| 979 case kString: return "/string/"; |
| 980 case kCode: return "/code/"; |
| 981 case kArray: return "/array/"; |
| 982 default: return "???"; |
| 983 } |
| 984 } |
| 985 |
| 986 |
| 987 int HeapEntry::EntriesSize(int entries_count, |
| 988 int children_count, |
| 989 int retainers_count) { |
| 990 return sizeof(HeapEntry) * entries_count // NOLINT |
| 991 + sizeof(HeapGraphEdge) * children_count // NOLINT |
| 992 + sizeof(HeapGraphEdge*) * retainers_count; // NOLINT |
| 993 } |
| 994 |
| 995 |
| 996 static void DeleteHeapGraphPath(HeapGraphPath** path_ptr) { |
| 997 delete *path_ptr; |
| 998 } |
| 999 |
| 1000 void HeapEntryCalculatedData::Dispose() { |
| 1001 if (retaining_paths_ != NULL) retaining_paths_->Iterate(DeleteHeapGraphPath); |
| 1002 delete retaining_paths_; |
| 1003 } |
| 1004 |
| 1005 |
| 1006 int HeapEntryCalculatedData::ReachableSize(HeapEntry* entry) { |
| 1007 if (reachable_size_ == kUnknownSize) CalculateSizes(entry); |
| 1008 return reachable_size_; |
| 1009 } |
| 1010 |
| 1011 |
| 1012 int HeapEntryCalculatedData::RetainedSize(HeapEntry* entry) { |
| 1013 if (retained_size_ == kUnknownSize) CalculateSizes(entry); |
| 1014 return retained_size_; |
| 1015 } |
| 1016 |
| 1017 |
| 1018 class ReachableSizeCalculator { |
914 public: | 1019 public: |
915 TotalSizeCalculator() | 1020 ReachableSizeCalculator() |
916 : total_size_(0) { | 1021 : reachable_size_(0) { |
917 } | 1022 } |
918 | 1023 |
919 int total_size() const { return total_size_; } | 1024 int reachable_size() const { return reachable_size_; } |
920 | 1025 |
921 void Apply(HeapEntry* entry) { | 1026 void Apply(HeapEntry* entry) { |
922 total_size_ += entry->self_size(); | 1027 reachable_size_ += entry->self_size(); |
923 } | 1028 } |
924 | 1029 |
925 private: | 1030 private: |
926 int total_size_; | 1031 int reachable_size_; |
927 }; | 1032 }; |
928 | 1033 |
929 int HeapEntry::CalculateTotalSize() { | 1034 class RetainedSizeCalculator { |
930 snapshot_->ClearPaint(); | |
931 TotalSizeCalculator calc; | |
932 ApplyAndPaintAllReachable(&calc); | |
933 total_size_ = calc.total_size(); | |
934 return total_size_; | |
935 } | |
936 | |
937 | |
938 class NonSharedSizeCalculator { | |
939 public: | 1035 public: |
940 NonSharedSizeCalculator() | 1036 RetainedSizeCalculator() |
941 : non_shared_total_size_(0) { | 1037 : retained_size_(0) { |
942 } | 1038 } |
943 | 1039 |
944 int non_shared_total_size() const { return non_shared_total_size_; } | 1040 int reained_size() const { return retained_size_; } |
945 | 1041 |
946 void Apply(HeapEntry* entry) { | 1042 void Apply(HeapEntry** entry_ptr) { |
947 if (entry->painted_reachable()) { | 1043 if ((*entry_ptr)->painted_reachable()) { |
948 non_shared_total_size_ += entry->self_size(); | 1044 retained_size_ += (*entry_ptr)->self_size(); |
949 } | 1045 } |
950 } | 1046 } |
951 | 1047 |
952 private: | 1048 private: |
953 int non_shared_total_size_; | 1049 int retained_size_; |
954 }; | 1050 }; |
955 | 1051 |
956 int HeapEntry::CalculateNonSharedTotalSize() { | 1052 void HeapEntryCalculatedData::CalculateSizes(HeapEntry* entry) { |
957 // To calculate non-shared total size, first we paint all reachable | 1053 // To calculate retained size, first we paint all reachable nodes in |
958 // nodes in one color, then we paint all nodes reachable from other | 1054 // one color (and calculate reachable size as a byproduct), then we |
959 // nodes with a different color. Then we consider only nodes painted | 1055 // paint (or re-paint) all nodes reachable from other nodes with a |
960 // with the first color for calculating the total size. | 1056 // different color. Then we consider only nodes painted with the |
961 snapshot_->ClearPaint(); | 1057 // first color for calculating the retained size. |
962 PaintAllReachable(); | 1058 entry->snapshot()->ClearPaint(); |
| 1059 ReachableSizeCalculator rch_size_calc; |
| 1060 entry->ApplyAndPaintAllReachable(&rch_size_calc); |
| 1061 reachable_size_ = rch_size_calc.reachable_size(); |
963 | 1062 |
964 List<HeapEntry*> list(10); | 1063 List<HeapEntry*> list(10); |
965 if (this != snapshot_->root()) { | 1064 HeapEntry* root = entry->snapshot()->root(); |
966 list.Add(snapshot_->root()); | 1065 if (entry != root) { |
967 snapshot_->root()->PaintReachableFromOthers(); | 1066 list.Add(root); |
| 1067 root->paint_reachable_from_others(); |
968 } | 1068 } |
969 while (!list.is_empty()) { | 1069 while (!list.is_empty()) { |
970 HeapEntry* entry = list.RemoveLast(); | 1070 HeapEntry* curr = list.RemoveLast(); |
971 const int children_count = entry->children_.length(); | 1071 Vector<HeapGraphEdge> children = curr->children(); |
972 for (int i = 0; i < children_count; ++i) { | 1072 for (int i = 0; i < children.length(); ++i) { |
973 HeapEntry* child = entry->children_[i]->to(); | 1073 HeapEntry* child = children[i].to(); |
974 if (child != this && child->not_painted_reachable_from_others()) { | 1074 if (child != entry && child->not_painted_reachable_from_others()) { |
975 list.Add(child); | 1075 list.Add(child); |
976 child->PaintReachableFromOthers(); | 1076 child->paint_reachable_from_others(); |
977 } | 1077 } |
978 } | 1078 } |
979 } | 1079 } |
980 | 1080 |
981 NonSharedSizeCalculator calculator; | 1081 RetainedSizeCalculator ret_size_calc; |
982 snapshot_->IterateEntries(&calculator); | 1082 entry->snapshot()->IterateEntries(&ret_size_calc); |
983 non_shared_total_size_ = calculator.non_shared_total_size(); | 1083 retained_size_ = ret_size_calc.reained_size(); |
984 return non_shared_total_size_; | |
985 } | 1084 } |
986 | 1085 |
987 | 1086 |
988 class CachedHeapGraphPath { | 1087 class CachedHeapGraphPath { |
989 public: | 1088 public: |
990 CachedHeapGraphPath() | 1089 CachedHeapGraphPath() |
991 : nodes_(NodesMatch) { } | 1090 : nodes_(NodesMatch) { } |
992 CachedHeapGraphPath(const CachedHeapGraphPath& src) | 1091 CachedHeapGraphPath(const CachedHeapGraphPath& src) |
993 : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()), | 1092 : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()), |
994 path_(src.path_.length() + 1) { | 1093 path_(src.path_.length() + 1) { |
(...skipping 17 matching lines...) Expand all Loading... |
1012 static uint32_t Hash(HeapEntry* entry) { | 1111 static uint32_t Hash(HeapEntry* entry) { |
1013 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry)); | 1112 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(entry)); |
1014 } | 1113 } |
1015 static bool NodesMatch(void* key1, void* key2) { return key1 == key2; } | 1114 static bool NodesMatch(void* key1, void* key2) { return key1 == key2; } |
1016 | 1115 |
1017 HashMap nodes_; | 1116 HashMap nodes_; |
1018 List<HeapGraphEdge*> path_; | 1117 List<HeapGraphEdge*> path_; |
1019 }; | 1118 }; |
1020 | 1119 |
1021 | 1120 |
1022 const List<HeapGraphPath*>* HeapEntry::GetRetainingPaths() { | 1121 List<HeapGraphPath*>* HeapEntryCalculatedData::GetRetainingPaths( |
1023 if (retaining_paths_.length() == 0 && retainers_.length() != 0) { | 1122 HeapEntry* entry) { |
| 1123 if (retaining_paths_ == NULL) retaining_paths_ = new List<HeapGraphPath*>(4); |
| 1124 if (retaining_paths_->length() == 0 && entry->retainers().length() != 0) { |
1024 CachedHeapGraphPath path; | 1125 CachedHeapGraphPath path; |
1025 FindRetainingPaths(this, &path); | 1126 FindRetainingPaths(entry, &path); |
1026 } | 1127 } |
1027 return &retaining_paths_; | 1128 return retaining_paths_; |
1028 } | 1129 } |
1029 | 1130 |
1030 | 1131 |
1031 void HeapEntry::FindRetainingPaths(HeapEntry* node, | 1132 void HeapEntryCalculatedData::FindRetainingPaths( |
1032 CachedHeapGraphPath* prev_path) { | 1133 HeapEntry* entry, |
1033 for (int i = 0; i < node->retainers_.length(); ++i) { | 1134 CachedHeapGraphPath* prev_path) { |
1034 HeapGraphEdge* ret_edge = node->retainers_[i]; | 1135 Vector<HeapGraphEdge*> retainers = entry->retainers(); |
1035 if (prev_path->ContainsNode(ret_edge->from())) continue; | 1136 for (int i = 0; i < retainers.length(); ++i) { |
1036 if (ret_edge->from() != snapshot_->root()) { | 1137 HeapGraphEdge* ret_edge = retainers[i]; |
| 1138 if (prev_path->ContainsNode(ret_edge->From())) continue; |
| 1139 if (ret_edge->From() != entry->snapshot()->root()) { |
1037 CachedHeapGraphPath path(*prev_path); | 1140 CachedHeapGraphPath path(*prev_path); |
1038 path.Add(ret_edge); | 1141 path.Add(ret_edge); |
1039 FindRetainingPaths(ret_edge->from(), &path); | 1142 FindRetainingPaths(ret_edge->From(), &path); |
1040 } else { | 1143 } else { |
1041 HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path()); | 1144 HeapGraphPath* ret_path = new HeapGraphPath(*prev_path->path()); |
1042 ret_path->Set(0, ret_edge); | 1145 ret_path->Set(0, ret_edge); |
1043 retaining_paths_.Add(ret_path); | 1146 retaining_paths_->Add(ret_path); |
1044 } | 1147 } |
1045 } | 1148 } |
1046 } | 1149 } |
1047 | 1150 |
1048 | |
1049 static void RemoveEdge(List<HeapGraphEdge*>* list, HeapGraphEdge* edge) { | |
1050 for (int i = 0; i < list->length(); ) { | |
1051 if (list->at(i) == edge) { | |
1052 list->Remove(i); | |
1053 return; | |
1054 } else { | |
1055 ++i; | |
1056 } | |
1057 } | |
1058 UNREACHABLE(); | |
1059 } | |
1060 | |
1061 | |
1062 void HeapEntry::RemoveChild(HeapGraphEdge* edge) { | |
1063 RemoveEdge(&children_, edge); | |
1064 delete edge; | |
1065 } | |
1066 | |
1067 | |
1068 void HeapEntry::RemoveRetainer(HeapGraphEdge* edge) { | |
1069 RemoveEdge(&retainers_, edge); | |
1070 } | |
1071 | |
1072 | |
1073 void HeapEntry::CutEdges() { | |
1074 for (int i = 0; i < children_.length(); ++i) { | |
1075 HeapGraphEdge* edge = children_[i]; | |
1076 edge->to()->RemoveRetainer(edge); | |
1077 } | |
1078 children_.Iterate(DeleteHeapGraphEdge); | |
1079 children_.Clear(); | |
1080 | |
1081 for (int i = 0; i < retainers_.length(); ++i) { | |
1082 HeapGraphEdge* edge = retainers_[i]; | |
1083 edge->from()->RemoveChild(edge); | |
1084 } | |
1085 retainers_.Clear(); | |
1086 } | |
1087 | |
1088 | |
1089 void HeapEntry::Print(int max_depth, int indent) { | |
1090 OS::Print("%6d %6d %6d [%ld] ", | |
1091 self_size_, TotalSize(), NonSharedTotalSize(), id_); | |
1092 if (type_ != STRING) { | |
1093 OS::Print("%s %.40s\n", TypeAsString(), name_); | |
1094 } else { | |
1095 OS::Print("\""); | |
1096 const char* c = name_; | |
1097 while (*c && (c - name_) <= 40) { | |
1098 if (*c != '\n') | |
1099 OS::Print("%c", *c); | |
1100 else | |
1101 OS::Print("\\n"); | |
1102 ++c; | |
1103 } | |
1104 OS::Print("\"\n"); | |
1105 } | |
1106 if (--max_depth == 0) return; | |
1107 const int children_count = children_.length(); | |
1108 for (int i = 0; i < children_count; ++i) { | |
1109 HeapGraphEdge* edge = children_[i]; | |
1110 switch (edge->type()) { | |
1111 case HeapGraphEdge::CONTEXT_VARIABLE: | |
1112 OS::Print(" %*c #%s: ", indent, ' ', edge->name()); | |
1113 break; | |
1114 case HeapGraphEdge::ELEMENT: | |
1115 OS::Print(" %*c %d: ", indent, ' ', edge->index()); | |
1116 break; | |
1117 case HeapGraphEdge::INTERNAL: | |
1118 OS::Print(" %*c $%s: ", indent, ' ', edge->name()); | |
1119 break; | |
1120 case HeapGraphEdge::PROPERTY: | |
1121 OS::Print(" %*c %s: ", indent, ' ', edge->name()); | |
1122 break; | |
1123 default: | |
1124 OS::Print("!!! unknown edge type: %d ", edge->type()); | |
1125 } | |
1126 edge->to()->Print(max_depth, indent + 2); | |
1127 } | |
1128 } | |
1129 | |
1130 | |
1131 const char* HeapEntry::TypeAsString() { | |
1132 switch (type_) { | |
1133 case INTERNAL: return "/internal/"; | |
1134 case OBJECT: return "/object/"; | |
1135 case CLOSURE: return "/closure/"; | |
1136 case STRING: return "/string/"; | |
1137 case CODE: return "/code/"; | |
1138 case ARRAY: return "/array/"; | |
1139 default: return "???"; | |
1140 } | |
1141 } | |
1142 | |
1143 | 1151 |
1144 HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path) | 1152 HeapGraphPath::HeapGraphPath(const List<HeapGraphEdge*>& path) |
1145 : path_(path.length() + 1) { | 1153 : path_(path.length() + 1) { |
1146 Add(NULL); | 1154 Add(NULL); |
1147 for (int i = path.length() - 1; i >= 0; --i) { | 1155 for (int i = path.length() - 1; i >= 0; --i) { |
1148 Add(path[i]); | 1156 Add(path[i]); |
1149 } | 1157 } |
1150 } | 1158 } |
1151 | 1159 |
1152 | 1160 |
1153 void HeapGraphPath::Print() { | 1161 void HeapGraphPath::Print() { |
1154 path_[0]->from()->Print(1, 0); | 1162 path_[0]->From()->Print(1, 0); |
1155 for (int i = 0; i < path_.length(); ++i) { | 1163 for (int i = 0; i < path_.length(); ++i) { |
1156 OS::Print(" -> "); | 1164 OS::Print(" -> "); |
1157 HeapGraphEdge* edge = path_[i]; | 1165 HeapGraphEdge* edge = path_[i]; |
1158 switch (edge->type()) { | 1166 switch (edge->type()) { |
1159 case HeapGraphEdge::CONTEXT_VARIABLE: | 1167 case HeapGraphEdge::kContextVariable: |
1160 OS::Print("[#%s] ", edge->name()); | 1168 OS::Print("[#%s] ", edge->name()); |
1161 break; | 1169 break; |
1162 case HeapGraphEdge::ELEMENT: | 1170 case HeapGraphEdge::kElement: |
1163 OS::Print("[%d] ", edge->index()); | 1171 OS::Print("[%d] ", edge->index()); |
1164 break; | 1172 break; |
1165 case HeapGraphEdge::INTERNAL: | 1173 case HeapGraphEdge::kInternal: |
1166 OS::Print("[$%s] ", edge->name()); | 1174 OS::Print("[$%s] ", edge->name()); |
1167 break; | 1175 break; |
1168 case HeapGraphEdge::PROPERTY: | 1176 case HeapGraphEdge::kProperty: |
1169 OS::Print("[%s] ", edge->name()); | 1177 OS::Print("[%s] ", edge->name()); |
1170 break; | 1178 break; |
1171 default: | 1179 default: |
1172 OS::Print("!!! unknown edge type: %d ", edge->type()); | 1180 OS::Print("!!! unknown edge type: %d ", edge->type()); |
1173 } | 1181 } |
1174 edge->to()->Print(1, 0); | 1182 edge->to()->Print(1, 0); |
1175 } | 1183 } |
1176 OS::Print("\n"); | 1184 OS::Print("\n"); |
1177 } | 1185 } |
1178 | 1186 |
1179 | 1187 |
1180 class IndexedReferencesExtractor : public ObjectVisitor { | 1188 HeapObject *const HeapSnapshot::kInternalRootObject = |
1181 public: | 1189 reinterpret_cast<HeapObject*>(1); |
1182 IndexedReferencesExtractor(HeapSnapshot* snapshot, HeapEntry* parent) | |
1183 : snapshot_(snapshot), | |
1184 parent_(parent) { | |
1185 } | |
1186 | |
1187 void VisitPointer(Object** o) { | |
1188 if (!(*o)->IsHeapObject()) return; | |
1189 HeapEntry* entry = snapshot_->GetEntry(HeapObject::cast(*o)); | |
1190 if (entry != NULL) { | |
1191 parent_->SetAutoIndexReference(entry); | |
1192 } | |
1193 } | |
1194 | |
1195 void VisitPointers(Object** start, Object** end) { | |
1196 for (Object** p = start; p < end; p++) VisitPointer(p); | |
1197 } | |
1198 | |
1199 private: | |
1200 HeapSnapshot* snapshot_; | |
1201 HeapEntry* parent_; | |
1202 }; | |
1203 | |
1204 | |
1205 HeapEntriesMap::HeapEntriesMap() | |
1206 : entries_(HeapObjectsMatch) { | |
1207 } | |
1208 | |
1209 | |
1210 HeapEntriesMap::~HeapEntriesMap() { | |
1211 for (HashMap::Entry* p = entries_.Start(); | |
1212 p != NULL; | |
1213 p = entries_.Next(p)) { | |
1214 if (!IsAlias(p->value)) delete reinterpret_cast<HeapEntry*>(p->value); | |
1215 } | |
1216 } | |
1217 | |
1218 | |
1219 void HeapEntriesMap::Alias(HeapObject* object, HeapEntry* entry) { | |
1220 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true); | |
1221 if (cache_entry->value == NULL) | |
1222 cache_entry->value = reinterpret_cast<void*>( | |
1223 reinterpret_cast<intptr_t>(entry) | kAliasTag); | |
1224 } | |
1225 | |
1226 | |
1227 void HeapEntriesMap::Apply(void (HeapEntry::*Func)(void)) { | |
1228 for (HashMap::Entry* p = entries_.Start(); | |
1229 p != NULL; | |
1230 p = entries_.Next(p)) { | |
1231 if (!IsAlias(p->value)) (reinterpret_cast<HeapEntry*>(p->value)->*Func)(); | |
1232 } | |
1233 } | |
1234 | |
1235 | |
1236 HeapEntry* HeapEntriesMap::Map(HeapObject* object) { | |
1237 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false); | |
1238 return cache_entry != NULL ? | |
1239 reinterpret_cast<HeapEntry*>( | |
1240 reinterpret_cast<intptr_t>(cache_entry->value) & (~kAliasTag)) : NULL; | |
1241 } | |
1242 | |
1243 | |
1244 void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) { | |
1245 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true); | |
1246 ASSERT(cache_entry->value == NULL); | |
1247 cache_entry->value = entry; | |
1248 } | |
1249 | |
1250 | 1190 |
1251 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, | 1191 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
1252 const char* title, | 1192 const char* title, |
1253 unsigned uid) | 1193 unsigned uid) |
1254 : collection_(collection), | 1194 : collection_(collection), |
1255 title_(title), | 1195 title_(title), |
1256 uid_(uid), | 1196 uid_(uid), |
1257 root_(this), | 1197 root_entry_index_(-1), |
1258 sorted_entries_(NULL) { | 1198 raw_entries_(NULL), |
| 1199 entries_sorted_(false) { |
1259 } | 1200 } |
1260 | 1201 |
1261 | 1202 |
| 1203 static void DisposeCalculatedData(HeapEntryCalculatedData* cdata) { |
| 1204 cdata->Dispose(); |
| 1205 } |
| 1206 |
1262 HeapSnapshot::~HeapSnapshot() { | 1207 HeapSnapshot::~HeapSnapshot() { |
1263 delete sorted_entries_; | 1208 DeleteArray(raw_entries_); |
| 1209 calculated_data_.Iterate(DisposeCalculatedData); |
1264 } | 1210 } |
1265 | 1211 |
1266 | 1212 |
1267 void HeapSnapshot::ClearPaint() { | 1213 void HeapSnapshot::AllocateEntries(int entries_count, |
1268 root_.ClearPaint(); | 1214 int children_count, |
1269 entries_.Apply(&HeapEntry::ClearPaint); | 1215 int retainers_count) { |
| 1216 ASSERT(raw_entries_ == NULL); |
| 1217 raw_entries_ = NewArray<char>( |
| 1218 HeapEntry::EntriesSize(entries_count, children_count, retainers_count)); |
1270 } | 1219 } |
1271 | 1220 |
1272 | 1221 |
1273 HeapEntry* HeapSnapshot::GetEntry(Object* obj) { | 1222 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
1274 if (!obj->IsHeapObject()) return NULL; | 1223 int children_count, |
1275 HeapObject* object = HeapObject::cast(obj); | 1224 int retainers_count) { |
1276 | 1225 if (object == kInternalRootObject) { |
1277 { | 1226 ASSERT(root_entry_index_ == -1); |
1278 HeapEntry* existing = FindEntry(object); | 1227 root_entry_index_ = entries_.length(); |
1279 if (existing != NULL) return existing; | 1228 HeapEntry* entry = GetNextEntryToInit(); |
1280 } | 1229 entry->Init(this, children_count, retainers_count); |
1281 | 1230 return entry; |
1282 // Add new entry. | 1231 } else if (object->IsJSFunction()) { |
1283 if (object->IsJSFunction()) { | |
1284 JSFunction* func = JSFunction::cast(object); | 1232 JSFunction* func = JSFunction::cast(object); |
1285 SharedFunctionInfo* shared = func->shared(); | 1233 SharedFunctionInfo* shared = func->shared(); |
1286 String* name = String::cast(shared->name())->length() > 0 ? | 1234 String* name = String::cast(shared->name())->length() > 0 ? |
1287 String::cast(shared->name()) : shared->inferred_name(); | 1235 String::cast(shared->name()) : shared->inferred_name(); |
1288 return AddEntry(object, HeapEntry::CLOSURE, collection_->GetName(name)); | 1236 return AddEntry(object, |
| 1237 HeapEntry::kClosure, |
| 1238 collection_->GetName(name), |
| 1239 children_count, |
| 1240 retainers_count); |
1289 } else if (object->IsJSObject()) { | 1241 } else if (object->IsJSObject()) { |
1290 return AddEntry(object, | 1242 return AddEntry(object, |
1291 HeapEntry::OBJECT, | 1243 HeapEntry::kObject, |
1292 collection_->GetName( | 1244 collection_->GetName( |
1293 JSObject::cast(object)->constructor_name())); | 1245 JSObject::cast(object)->constructor_name()), |
1294 } else if (object->IsJSGlobalPropertyCell()) { | 1246 children_count, |
1295 HeapEntry* value = GetEntry(JSGlobalPropertyCell::cast(object)->value()); | 1247 retainers_count); |
1296 // If GPC references an object that we have interest in, add the object. | |
1297 // We don't store HeapEntries for GPCs. Instead, we make our hash map | |
1298 // to point to object's HeapEntry by GPCs address. | |
1299 if (value != NULL) AddEntryAlias(object, value); | |
1300 return value; | |
1301 } else if (object->IsString()) { | 1248 } else if (object->IsString()) { |
1302 return AddEntry(object, | 1249 return AddEntry(object, |
1303 HeapEntry::STRING, | 1250 HeapEntry::kString, |
1304 collection_->GetName(String::cast(object))); | 1251 collection_->GetName(String::cast(object)), |
| 1252 children_count, |
| 1253 retainers_count); |
1305 } else if (object->IsCode()) { | 1254 } else if (object->IsCode()) { |
1306 return AddEntry(object, HeapEntry::CODE); | 1255 return AddEntry(object, |
| 1256 HeapEntry::kCode, |
| 1257 "", |
| 1258 children_count, |
| 1259 retainers_count); |
1307 } else if (object->IsSharedFunctionInfo()) { | 1260 } else if (object->IsSharedFunctionInfo()) { |
1308 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); | 1261 SharedFunctionInfo* shared = SharedFunctionInfo::cast(object); |
1309 String* name = String::cast(shared->name())->length() > 0 ? | 1262 String* name = String::cast(shared->name())->length() > 0 ? |
1310 String::cast(shared->name()) : shared->inferred_name(); | 1263 String::cast(shared->name()) : shared->inferred_name(); |
1311 return AddEntry(object, HeapEntry::CODE, collection_->GetName(name)); | 1264 return AddEntry(object, |
| 1265 HeapEntry::kCode, |
| 1266 collection_->GetName(name), |
| 1267 children_count, |
| 1268 retainers_count); |
1312 } else if (object->IsScript()) { | 1269 } else if (object->IsScript()) { |
1313 Script* script = Script::cast(object); | 1270 Script* script = Script::cast(object); |
1314 return AddEntry(object, | 1271 return AddEntry(object, |
1315 HeapEntry::CODE, | 1272 HeapEntry::kCode, |
1316 script->name()->IsString() ? | 1273 script->name()->IsString() ? |
1317 collection_->GetName(String::cast(script->name())) : ""); | 1274 collection_->GetName(String::cast(script->name())) : "", |
| 1275 children_count, |
| 1276 retainers_count); |
1318 } else if (object->IsFixedArray()) { | 1277 } else if (object->IsFixedArray()) { |
1319 return AddEntry(object, HeapEntry::ARRAY); | 1278 return AddEntry(object, |
| 1279 HeapEntry::kArray, |
| 1280 "", |
| 1281 children_count, |
| 1282 retainers_count); |
1320 } | 1283 } |
1321 // No interest in this object. | 1284 // No interest in this object. |
1322 return NULL; | 1285 return NULL; |
1323 } | 1286 } |
1324 | 1287 |
1325 | 1288 |
1326 void HeapSnapshot::SetClosureReference(HeapEntry* parent, | 1289 bool HeapSnapshot::WillAddEntry(HeapObject* object) { |
1327 String* reference_name, | 1290 return object == kInternalRootObject |
1328 Object* child) { | 1291 || object->IsJSFunction() |
1329 HeapEntry* child_entry = GetEntry(child); | 1292 || object->IsJSObject() |
1330 if (child_entry != NULL) { | 1293 || object->IsString() |
1331 parent->SetClosureReference( | 1294 || object->IsCode() |
1332 collection_->GetName(reference_name), child_entry); | 1295 || object->IsSharedFunctionInfo() |
1333 } | 1296 || object->IsScript() |
| 1297 || object->IsFixedArray(); |
1334 } | 1298 } |
1335 | 1299 |
1336 | 1300 |
1337 void HeapSnapshot::SetElementReference(HeapEntry* parent, | 1301 static void HeapEntryClearPaint(HeapEntry** entry_ptr) { |
1338 int index, | 1302 (*entry_ptr)->clear_paint(); |
1339 Object* child) { | 1303 } |
1340 HeapEntry* child_entry = GetEntry(child); | 1304 |
1341 if (child_entry != NULL) { | 1305 void HeapSnapshot::ClearPaint() { |
1342 parent->SetElementReference(index, child_entry); | 1306 entries_.Iterate(HeapEntryClearPaint); |
1343 } | |
1344 } | 1307 } |
1345 | 1308 |
1346 | 1309 |
1347 void HeapSnapshot::SetInternalReference(HeapEntry* parent, | 1310 int HeapSnapshot::AddCalculatedData() { |
1348 const char* reference_name, | 1311 calculated_data_.Add(HeapEntryCalculatedData()); |
1349 Object* child) { | 1312 return calculated_data_.length() - 1; |
1350 HeapEntry* child_entry = GetEntry(child); | |
1351 if (child_entry != NULL) { | |
1352 parent->SetInternalReference(reference_name, child_entry); | |
1353 } | |
1354 } | |
1355 | |
1356 | |
1357 void HeapSnapshot::SetPropertyReference(HeapEntry* parent, | |
1358 String* reference_name, | |
1359 Object* child) { | |
1360 HeapEntry* child_entry = GetEntry(child); | |
1361 if (child_entry != NULL) { | |
1362 parent->SetPropertyReference( | |
1363 collection_->GetName(reference_name), child_entry); | |
1364 } | |
1365 } | 1313 } |
1366 | 1314 |
1367 | 1315 |
1368 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, | 1316 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
1369 HeapEntry::Type type, | 1317 HeapEntry::Type type, |
1370 const char* name) { | 1318 const char* name, |
1371 HeapEntry* entry = new HeapEntry(this, | 1319 int children_count, |
1372 type, | 1320 int retainers_count) { |
1373 name, | 1321 HeapEntry* entry = GetNextEntryToInit(); |
1374 collection_->GetObjectId(object->address()), | 1322 entry->Init(this, |
1375 GetObjectSize(object), | 1323 type, |
1376 GetObjectSecurityToken(object)); | 1324 name, |
1377 entries_.Pair(object, entry); | 1325 collection_->GetObjectId(object->address()), |
1378 | 1326 GetObjectSize(object), |
1379 // Detect, if this is a JS global object of the current context, and | 1327 children_count, |
1380 // add it to snapshot's roots. There can be several JS global objects | 1328 retainers_count); |
1381 // in a context. | |
1382 if (object->IsJSGlobalProxy()) { | |
1383 int global_security_token = GetGlobalSecurityToken(); | |
1384 int object_security_token = | |
1385 collection_->token_enumerator()->GetTokenId( | |
1386 Context::cast( | |
1387 JSGlobalProxy::cast(object)->context())->security_token()); | |
1388 if (object_security_token == TokenEnumerator::kNoSecurityToken | |
1389 || object_security_token == global_security_token) { | |
1390 HeapEntry* global_object_entry = | |
1391 GetEntry(HeapObject::cast(object->map()->prototype())); | |
1392 ASSERT(global_object_entry != NULL); | |
1393 root_.SetAutoIndexReference(global_object_entry); | |
1394 } | |
1395 } | |
1396 | |
1397 return entry; | 1329 return entry; |
1398 } | 1330 } |
1399 | 1331 |
1400 | 1332 |
1401 class EdgesCutter { | 1333 HeapEntry* HeapSnapshot::GetNextEntryToInit() { |
1402 public: | 1334 if (entries_.length() > 0) { |
1403 explicit EdgesCutter(int global_security_token) | 1335 HeapEntry* last_entry = entries_.last(); |
1404 : global_security_token_(global_security_token) { | 1336 entries_.Add(reinterpret_cast<HeapEntry*>( |
| 1337 reinterpret_cast<char*>(last_entry) + last_entry->EntrySize())); |
| 1338 } else { |
| 1339 entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_)); |
1405 } | 1340 } |
1406 | 1341 return entries_.last(); |
1407 void Apply(HeapEntry* entry) { | |
1408 if (entry->security_token_id() != TokenEnumerator::kNoSecurityToken | |
1409 && entry->security_token_id() != global_security_token_) { | |
1410 entry->CutEdges(); | |
1411 } | |
1412 } | |
1413 | |
1414 private: | |
1415 const int global_security_token_; | |
1416 }; | |
1417 | |
1418 void HeapSnapshot::CutObjectsFromForeignSecurityContexts() { | |
1419 EdgesCutter cutter(GetGlobalSecurityToken()); | |
1420 entries_.Apply(&cutter); | |
1421 } | 1342 } |
1422 | 1343 |
1423 | 1344 |
1424 int HeapSnapshot::GetGlobalSecurityToken() { | |
1425 return collection_->token_enumerator()->GetTokenId( | |
1426 Top::context()->global()->global_context()->security_token()); | |
1427 } | |
1428 | |
1429 | |
1430 int HeapSnapshot::GetObjectSize(HeapObject* obj) { | 1345 int HeapSnapshot::GetObjectSize(HeapObject* obj) { |
1431 return obj->IsJSObject() ? | 1346 return obj->IsJSObject() ? |
1432 CalculateNetworkSize(JSObject::cast(obj)) : obj->Size(); | 1347 CalculateNetworkSize(JSObject::cast(obj)) : obj->Size(); |
1433 } | 1348 } |
1434 | 1349 |
1435 | 1350 |
1436 int HeapSnapshot::GetObjectSecurityToken(HeapObject* obj) { | |
1437 if (obj->IsGlobalContext()) { | |
1438 return collection_->token_enumerator()->GetTokenId( | |
1439 Context::cast(obj)->security_token()); | |
1440 } else { | |
1441 return TokenEnumerator::kNoSecurityToken; | |
1442 } | |
1443 } | |
1444 | |
1445 | |
1446 int HeapSnapshot::CalculateNetworkSize(JSObject* obj) { | 1351 int HeapSnapshot::CalculateNetworkSize(JSObject* obj) { |
1447 int size = obj->Size(); | 1352 int size = obj->Size(); |
1448 // If 'properties' and 'elements' are non-empty (thus, non-shared), | 1353 // If 'properties' and 'elements' are non-empty (thus, non-shared), |
1449 // take their size into account. | 1354 // take their size into account. |
1450 if (FixedArray::cast(obj->properties())->length() != 0) { | 1355 if (FixedArray::cast(obj->properties())->length() != 0) { |
1451 size += obj->properties()->Size(); | 1356 size += obj->properties()->Size(); |
1452 } | 1357 } |
1453 if (FixedArray::cast(obj->elements())->length() != 0) { | 1358 if (FixedArray::cast(obj->elements())->length() != 0) { |
1454 size += obj->elements()->Size(); | 1359 size += obj->elements()->Size(); |
1455 } | 1360 } |
1456 // For functions, also account non-empty context and literals sizes. | 1361 // For functions, also account non-empty context and literals sizes. |
1457 if (obj->IsJSFunction()) { | 1362 if (obj->IsJSFunction()) { |
1458 JSFunction* f = JSFunction::cast(obj); | 1363 JSFunction* f = JSFunction::cast(obj); |
1459 if (f->unchecked_context()->IsContext()) { | 1364 if (f->unchecked_context()->IsContext()) { |
1460 size += f->context()->Size(); | 1365 size += f->context()->Size(); |
1461 } | 1366 } |
1462 if (f->literals()->length() != 0) { | 1367 if (f->literals()->length() != 0) { |
1463 size += f->literals()->Size(); | 1368 size += f->literals()->Size(); |
1464 } | 1369 } |
1465 } | 1370 } |
1466 return size; | 1371 return size; |
1467 } | 1372 } |
1468 | 1373 |
1469 | 1374 |
1470 class EntriesCollector { | 1375 HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) { |
1471 public: | 1376 return collection_->CompareSnapshots(this, snapshot); |
1472 explicit EntriesCollector(List<HeapEntry*>* list) : list_(list) { } | 1377 } |
1473 void Apply(HeapEntry* entry) { | 1378 |
1474 list_->Add(entry); | |
1475 } | |
1476 private: | |
1477 List<HeapEntry*>* list_; | |
1478 }; | |
1479 | 1379 |
1480 template<class T> | 1380 template<class T> |
1481 static int SortByIds(const T* entry1_ptr, | 1381 static int SortByIds(const T* entry1_ptr, |
1482 const T* entry2_ptr) { | 1382 const T* entry2_ptr) { |
1483 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; | 1383 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; |
1484 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; | 1384 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; |
1485 } | 1385 } |
1486 | 1386 |
1487 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { | 1387 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
1488 if (sorted_entries_ != NULL) return sorted_entries_; | 1388 if (!entries_sorted_) { |
1489 sorted_entries_ = new List<HeapEntry*>(entries_.capacity()); | 1389 entries_.Sort(SortByIds); |
1490 EntriesCollector collector(sorted_entries_); | 1390 entries_sorted_ = true; |
1491 entries_.Apply(&collector); | 1391 } |
1492 sorted_entries_->Sort(SortByIds); | 1392 return &entries_; |
1493 return sorted_entries_; | |
1494 } | |
1495 | |
1496 | |
1497 HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) { | |
1498 return collection_->CompareSnapshots(this, snapshot); | |
1499 } | 1393 } |
1500 | 1394 |
1501 | 1395 |
1502 void HeapSnapshot::Print(int max_depth) { | 1396 void HeapSnapshot::Print(int max_depth) { |
1503 root_.Print(max_depth, 0); | 1397 root()->Print(max_depth, 0); |
1504 } | 1398 } |
1505 | 1399 |
1506 | 1400 |
1507 HeapObjectsMap::HeapObjectsMap() | 1401 HeapObjectsMap::HeapObjectsMap() |
1508 : initial_fill_mode_(true), | 1402 : initial_fill_mode_(true), |
1509 next_id_(1), | 1403 next_id_(1), |
1510 entries_map_(AddressesMatch), | 1404 entries_map_(AddressesMatch), |
1511 entries_(new List<EntryInfo>()) { } | 1405 entries_(new List<EntryInfo>()) { } |
1512 | 1406 |
1513 | 1407 |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1628 } | 1522 } |
1629 | 1523 |
1630 | 1524 |
1631 HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots( | 1525 HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots( |
1632 HeapSnapshot* snapshot1, | 1526 HeapSnapshot* snapshot1, |
1633 HeapSnapshot* snapshot2) { | 1527 HeapSnapshot* snapshot2) { |
1634 return comparator_.Compare(snapshot1, snapshot2); | 1528 return comparator_.Compare(snapshot1, snapshot2); |
1635 } | 1529 } |
1636 | 1530 |
1637 | 1531 |
| 1532 HeapEntriesMap::HeapEntriesMap() |
| 1533 : entries_(HeapObjectsMatch), |
| 1534 entries_count_(0), |
| 1535 total_children_count_(0), |
| 1536 total_retainers_count_(0) { |
| 1537 } |
| 1538 |
| 1539 |
| 1540 HeapEntriesMap::~HeapEntriesMap() { |
| 1541 for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { |
| 1542 if (!IsAlias(p->value)) delete reinterpret_cast<EntryInfo*>(p->value); |
| 1543 } |
| 1544 } |
| 1545 |
| 1546 |
| 1547 void HeapEntriesMap::Alias(HeapObject* from, HeapObject* to) { |
| 1548 HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), true); |
| 1549 HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false); |
| 1550 if (from_cache_entry->value == NULL) { |
| 1551 ASSERT(to_cache_entry != NULL); |
| 1552 from_cache_entry->value = MakeAlias(to_cache_entry->value); |
| 1553 } |
| 1554 } |
| 1555 |
| 1556 |
| 1557 HeapEntry* HeapEntriesMap::Map(HeapObject* object) { |
| 1558 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), false); |
| 1559 if (cache_entry != NULL) { |
| 1560 EntryInfo* entry_info = |
| 1561 reinterpret_cast<EntryInfo*>(Unalias(cache_entry->value)); |
| 1562 return entry_info->entry; |
| 1563 } else { |
| 1564 return NULL; |
| 1565 } |
| 1566 } |
| 1567 |
| 1568 |
| 1569 void HeapEntriesMap::Pair(HeapObject* object, HeapEntry* entry) { |
| 1570 HashMap::Entry* cache_entry = entries_.Lookup(object, Hash(object), true); |
| 1571 ASSERT(cache_entry->value == NULL); |
| 1572 cache_entry->value = new EntryInfo(entry); |
| 1573 ++entries_count_; |
| 1574 } |
| 1575 |
| 1576 |
| 1577 void HeapEntriesMap::CountReference(HeapObject* from, HeapObject* to, |
| 1578 int* prev_children_count, |
| 1579 int* prev_retainers_count) { |
| 1580 HashMap::Entry* from_cache_entry = entries_.Lookup(from, Hash(from), true); |
| 1581 HashMap::Entry* to_cache_entry = entries_.Lookup(to, Hash(to), false); |
| 1582 ASSERT(from_cache_entry != NULL); |
| 1583 ASSERT(to_cache_entry != NULL); |
| 1584 EntryInfo* from_entry_info = |
| 1585 reinterpret_cast<EntryInfo*>(Unalias(from_cache_entry->value)); |
| 1586 EntryInfo* to_entry_info = |
| 1587 reinterpret_cast<EntryInfo*>(Unalias(to_cache_entry->value)); |
| 1588 if (prev_children_count) |
| 1589 *prev_children_count = from_entry_info->children_count; |
| 1590 if (prev_retainers_count) |
| 1591 *prev_retainers_count = to_entry_info->retainers_count; |
| 1592 ++from_entry_info->children_count; |
| 1593 ++to_entry_info->retainers_count; |
| 1594 ++total_children_count_; |
| 1595 ++total_retainers_count_; |
| 1596 } |
| 1597 |
| 1598 |
| 1599 template<class Visitor> |
| 1600 void HeapEntriesMap::UpdateEntries(Visitor* visitor) { |
| 1601 for (HashMap::Entry* p = entries_.Start(); |
| 1602 p != NULL; |
| 1603 p = entries_.Next(p)) { |
| 1604 if (!IsAlias(p->value)) { |
| 1605 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value); |
| 1606 entry_info->entry = visitor->GetEntry( |
| 1607 reinterpret_cast<HeapObject*>(p->key), |
| 1608 entry_info->children_count, |
| 1609 entry_info->retainers_count); |
| 1610 entry_info->children_count = 0; |
| 1611 entry_info->retainers_count = 0; |
| 1612 } |
| 1613 } |
| 1614 } |
| 1615 |
| 1616 |
1638 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) | 1617 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) |
1639 : snapshot_(snapshot) { | 1618 : snapshot_(snapshot), |
1640 } | 1619 collection_(snapshot->collection()), |
1641 | 1620 filler_(NULL) { |
| 1621 } |
| 1622 |
| 1623 |
| 1624 HeapEntry *const |
| 1625 HeapSnapshotGenerator::SnapshotFillerInterface::kHeapEntryPlaceholder = |
| 1626 reinterpret_cast<HeapEntry*>(1); |
| 1627 |
| 1628 class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface { |
| 1629 public: |
| 1630 explicit SnapshotCounter(HeapEntriesMap* entries) |
| 1631 : entries_(entries) { } |
| 1632 HeapEntry* AddEntry(HeapObject* obj) { |
| 1633 entries_->Pair(obj, kHeapEntryPlaceholder); |
| 1634 return kHeapEntryPlaceholder; |
| 1635 } |
| 1636 void SetElementReference(HeapObject* parent_obj, |
| 1637 HeapEntry*, |
| 1638 int, |
| 1639 Object* child_obj, |
| 1640 HeapEntry*) { |
| 1641 entries_->CountReference(parent_obj, HeapObject::cast(child_obj)); |
| 1642 } |
| 1643 void SetNamedReference(HeapGraphEdge::Type, |
| 1644 HeapObject* parent_obj, |
| 1645 HeapEntry*, |
| 1646 const char*, |
| 1647 Object* child_obj, |
| 1648 HeapEntry*) { |
| 1649 entries_->CountReference(parent_obj, HeapObject::cast(child_obj)); |
| 1650 } |
| 1651 void SetRootReference(Object* child_obj, HeapEntry*) { |
| 1652 entries_->CountReference( |
| 1653 HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj)); |
| 1654 } |
| 1655 private: |
| 1656 HeapEntriesMap* entries_; |
| 1657 }; |
| 1658 |
| 1659 |
| 1660 class SnapshotFiller : public HeapSnapshotGenerator::SnapshotFillerInterface { |
| 1661 public: |
| 1662 explicit SnapshotFiller(HeapSnapshot* snapshot, HeapEntriesMap* entries) |
| 1663 : snapshot_(snapshot), |
| 1664 collection_(snapshot->collection()), |
| 1665 entries_(entries) { } |
| 1666 HeapEntry* AddEntry(HeapObject* obj) { |
| 1667 UNREACHABLE(); |
| 1668 return NULL; |
| 1669 } |
| 1670 void SetElementReference(HeapObject* parent_obj, |
| 1671 HeapEntry* parent_entry, |
| 1672 int index, |
| 1673 Object* child_obj, |
| 1674 HeapEntry* child_entry) { |
| 1675 int child_index, retainer_index; |
| 1676 entries_->CountReference(parent_obj, HeapObject::cast(child_obj), |
| 1677 &child_index, &retainer_index); |
| 1678 parent_entry->SetElementReference( |
| 1679 child_index, index, child_entry, retainer_index); |
| 1680 } |
| 1681 void SetNamedReference(HeapGraphEdge::Type type, |
| 1682 HeapObject* parent_obj, |
| 1683 HeapEntry* parent_entry, |
| 1684 const char* reference_name, |
| 1685 Object* child_obj, |
| 1686 HeapEntry* child_entry) { |
| 1687 int child_index, retainer_index; |
| 1688 entries_->CountReference(parent_obj, HeapObject::cast(child_obj), |
| 1689 &child_index, &retainer_index); |
| 1690 parent_entry->SetNamedReference(type, |
| 1691 child_index, |
| 1692 reference_name, |
| 1693 child_entry, |
| 1694 retainer_index); |
| 1695 } |
| 1696 void SetRootReference(Object* child_obj, HeapEntry* child_entry) { |
| 1697 int child_index, retainer_index; |
| 1698 entries_->CountReference( |
| 1699 HeapSnapshot::kInternalRootObject, HeapObject::cast(child_obj), |
| 1700 &child_index, &retainer_index); |
| 1701 snapshot_->root()->SetElementReference( |
| 1702 child_index, child_index + 1, child_entry, retainer_index); |
| 1703 } |
| 1704 private: |
| 1705 HeapSnapshot* snapshot_; |
| 1706 HeapSnapshotsCollection* collection_; |
| 1707 HeapEntriesMap* entries_; |
| 1708 }; |
| 1709 |
| 1710 class SnapshotAllocator { |
| 1711 public: |
| 1712 explicit SnapshotAllocator(HeapSnapshot* snapshot) |
| 1713 : snapshot_(snapshot) { } |
| 1714 HeapEntry* GetEntry( |
| 1715 HeapObject* obj, int children_count, int retainers_count) { |
| 1716 HeapEntry* entry = |
| 1717 snapshot_->AddEntry(obj, children_count, retainers_count); |
| 1718 ASSERT(entry != NULL); |
| 1719 return entry; |
| 1720 } |
| 1721 private: |
| 1722 HeapSnapshot* snapshot_; |
| 1723 }; |
1642 | 1724 |
1643 void HeapSnapshotGenerator::GenerateSnapshot() { | 1725 void HeapSnapshotGenerator::GenerateSnapshot() { |
1644 AssertNoAllocation no_alloc; | 1726 AssertNoAllocation no_alloc; |
1645 | 1727 |
1646 // Iterate heap contents. | 1728 // Pass 1. Iterate heap contents to count entries and references. |
1647 HeapIterator iterator; | 1729 SnapshotCounter counter(&entries_); |
1648 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | 1730 filler_ = &counter; |
| 1731 filler_->AddEntry(HeapSnapshot::kInternalRootObject); |
| 1732 HeapIterator iterator1; |
| 1733 for (HeapObject* obj = iterator1.next(); |
| 1734 obj != NULL; |
| 1735 obj = iterator1.next()) { |
1649 ExtractReferences(obj); | 1736 ExtractReferences(obj); |
1650 } | 1737 } |
1651 | 1738 |
1652 snapshot_->CutObjectsFromForeignSecurityContexts(); | 1739 // Allocate and fill entries in the snapshot, allocate references. |
1653 } | 1740 snapshot_->AllocateEntries(entries_.entries_count(), |
| 1741 entries_.total_children_count(), |
| 1742 entries_.total_retainers_count()); |
| 1743 SnapshotAllocator allocator(snapshot_); |
| 1744 entries_.UpdateEntries(&allocator); |
| 1745 |
| 1746 // Pass 2. Fill references. |
| 1747 SnapshotFiller filler(snapshot_, &entries_); |
| 1748 filler_ = &filler; |
| 1749 HeapIterator iterator2; |
| 1750 for (HeapObject* obj = iterator2.next(); |
| 1751 obj != NULL; |
| 1752 obj = iterator2.next()) { |
| 1753 ExtractReferences(obj); |
| 1754 } |
| 1755 } |
| 1756 |
| 1757 |
| 1758 HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) { |
| 1759 if (!obj->IsHeapObject()) return NULL; |
| 1760 HeapObject* object = HeapObject::cast(obj); |
| 1761 HeapEntry* entry = entries_.Map(object); |
| 1762 |
| 1763 // A new entry. |
| 1764 if (entry == NULL) { |
| 1765 if (obj->IsJSGlobalPropertyCell()) { |
| 1766 Object* cell_target = JSGlobalPropertyCell::cast(obj)->value(); |
| 1767 entry = GetEntry(cell_target); |
| 1768 // If GPC references an object that we have interest in (see |
| 1769 // HeapSnapshot::AddEntry, WillAddEntry), add the object. We |
| 1770 // don't store HeapEntries for GPCs. Instead, we make our hash |
| 1771 // map to point to object's HeapEntry by GPCs address. |
| 1772 if (entry != NULL) { |
| 1773 entries_.Alias(object, HeapObject::cast(cell_target)); |
| 1774 } |
| 1775 return entry; |
| 1776 } |
| 1777 |
| 1778 if (snapshot_->WillAddEntry(object)) entry = filler_->AddEntry(object); |
| 1779 } |
| 1780 |
| 1781 return entry; |
| 1782 } |
| 1783 |
| 1784 |
| 1785 int HeapSnapshotGenerator::GetGlobalSecurityToken() { |
| 1786 return collection_->token_enumerator()->GetTokenId( |
| 1787 Top::context()->global()->global_context()->security_token()); |
| 1788 } |
| 1789 |
| 1790 |
| 1791 int HeapSnapshotGenerator::GetObjectSecurityToken(HeapObject* obj) { |
| 1792 if (obj->IsGlobalContext()) { |
| 1793 return collection_->token_enumerator()->GetTokenId( |
| 1794 Context::cast(obj)->security_token()); |
| 1795 } else { |
| 1796 return TokenEnumerator::kNoSecurityToken; |
| 1797 } |
| 1798 } |
| 1799 |
| 1800 |
| 1801 class IndexedReferencesExtractor : public ObjectVisitor { |
| 1802 public: |
| 1803 IndexedReferencesExtractor(HeapSnapshotGenerator* generator, |
| 1804 HeapObject* parent_obj, |
| 1805 HeapEntry* parent_entry) |
| 1806 : generator_(generator), |
| 1807 parent_obj_(parent_obj), |
| 1808 parent_(parent_entry), |
| 1809 next_index_(1) { |
| 1810 } |
| 1811 |
| 1812 void VisitPointer(Object** o) { |
| 1813 generator_->SetElementReference(parent_obj_, parent_, next_index_++, *o); |
| 1814 } |
| 1815 |
| 1816 void VisitPointers(Object** start, Object** end) { |
| 1817 for (Object** p = start; p < end; p++) VisitPointer(p); |
| 1818 } |
| 1819 |
| 1820 private: |
| 1821 HeapSnapshotGenerator* generator_; |
| 1822 HeapObject* parent_obj_; |
| 1823 HeapEntry* parent_; |
| 1824 int next_index_; |
| 1825 }; |
1654 | 1826 |
1655 | 1827 |
1656 void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { | 1828 void HeapSnapshotGenerator::ExtractReferences(HeapObject* obj) { |
1657 HeapEntry* entry = snapshot_->GetEntry(obj); | 1829 // We need to reference JS global objects from snapshot's root. |
1658 if (entry == NULL) return; | 1830 // We also need to only include global objects from the current |
1659 if (entry->visited()) return; | 1831 // security context. And we don't want to add the global proxy, |
| 1832 // as we don't have a special type for it. |
| 1833 if (obj->IsJSGlobalProxy()) { |
| 1834 int global_security_token = GetGlobalSecurityToken(); |
| 1835 JSGlobalProxy* proxy = JSGlobalProxy::cast(obj); |
| 1836 int object_security_token = |
| 1837 collection_->token_enumerator()->GetTokenId( |
| 1838 Context::cast(proxy->context())->security_token()); |
| 1839 if (object_security_token == TokenEnumerator::kNoSecurityToken |
| 1840 || object_security_token == global_security_token) { |
| 1841 SetRootReference(proxy->map()->prototype()); |
| 1842 } |
| 1843 return; |
| 1844 } |
| 1845 |
| 1846 HeapEntry* entry = GetEntry(obj); |
| 1847 if (entry == NULL) return; // No interest in this object. |
1660 | 1848 |
1661 if (obj->IsJSObject()) { | 1849 if (obj->IsJSObject()) { |
1662 JSObject* js_obj = JSObject::cast(obj); | 1850 JSObject* js_obj = JSObject::cast(obj); |
1663 ExtractClosureReferences(js_obj, entry); | 1851 ExtractClosureReferences(js_obj, entry); |
1664 ExtractPropertyReferences(js_obj, entry); | 1852 ExtractPropertyReferences(js_obj, entry); |
1665 ExtractElementReferences(js_obj, entry); | 1853 ExtractElementReferences(js_obj, entry); |
1666 snapshot_->SetPropertyReference( | 1854 SetPropertyReference( |
1667 entry, Heap::prototype_symbol(), js_obj->map()->prototype()); | 1855 obj, entry, Heap::prototype_symbol(), js_obj->map()->prototype()); |
1668 } else if (obj->IsJSGlobalPropertyCell()) { | |
1669 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(obj); | |
1670 snapshot_->SetElementReference(entry, 0, cell->value()); | |
1671 } else if (obj->IsString()) { | 1856 } else if (obj->IsString()) { |
1672 if (obj->IsConsString()) { | 1857 if (obj->IsConsString()) { |
1673 ConsString* cs = ConsString::cast(obj); | 1858 ConsString* cs = ConsString::cast(obj); |
1674 snapshot_->SetElementReference(entry, 0, cs->first()); | 1859 SetElementReference(obj, entry, 0, cs->first()); |
1675 snapshot_->SetElementReference(entry, 1, cs->second()); | 1860 SetElementReference(obj, entry, 1, cs->second()); |
1676 } | 1861 } |
1677 } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) { | 1862 } else if (obj->IsCode() || obj->IsSharedFunctionInfo() || obj->IsScript()) { |
1678 IndexedReferencesExtractor refs_extractor(snapshot_, entry); | 1863 IndexedReferencesExtractor refs_extractor(this, obj, entry); |
1679 obj->Iterate(&refs_extractor); | 1864 obj->Iterate(&refs_extractor); |
1680 } else if (obj->IsFixedArray()) { | 1865 } else if (obj->IsFixedArray()) { |
1681 IndexedReferencesExtractor refs_extractor(snapshot_, entry); | 1866 IndexedReferencesExtractor refs_extractor(this, obj, entry); |
1682 obj->Iterate(&refs_extractor); | 1867 obj->Iterate(&refs_extractor); |
1683 } | 1868 } |
1684 entry->MarkAsVisited(); | 1869 } |
1685 } | 1870 |
1686 | 1871 |
1687 | |
1688 void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj, | 1872 void HeapSnapshotGenerator::ExtractClosureReferences(JSObject* js_obj, |
1689 HeapEntry* entry) { | 1873 HeapEntry* entry) { |
1690 if (js_obj->IsJSFunction()) { | 1874 if (js_obj->IsJSFunction()) { |
1691 HandleScope hs; | 1875 HandleScope hs; |
1692 JSFunction* func = JSFunction::cast(js_obj); | 1876 JSFunction* func = JSFunction::cast(js_obj); |
1693 Context* context = func->context(); | 1877 Context* context = func->context(); |
1694 ZoneScope zscope(DELETE_ON_EXIT); | 1878 ZoneScope zscope(DELETE_ON_EXIT); |
1695 SerializedScopeInfo* serialized_scope_info = | 1879 SerializedScopeInfo* serialized_scope_info = |
1696 context->closure()->shared()->scope_info(); | 1880 context->closure()->shared()->scope_info(); |
1697 ScopeInfo<ZoneListAllocationPolicy> zone_scope_info(serialized_scope_info); | 1881 ScopeInfo<ZoneListAllocationPolicy> zone_scope_info(serialized_scope_info); |
1698 int locals_number = zone_scope_info.NumberOfLocals(); | 1882 int locals_number = zone_scope_info.NumberOfLocals(); |
1699 for (int i = 0; i < locals_number; ++i) { | 1883 for (int i = 0; i < locals_number; ++i) { |
1700 String* local_name = *zone_scope_info.LocalName(i); | 1884 String* local_name = *zone_scope_info.LocalName(i); |
1701 int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL); | 1885 int idx = serialized_scope_info->ContextSlotIndex(local_name, NULL); |
1702 if (idx >= 0 && idx < context->length()) { | 1886 if (idx >= 0 && idx < context->length()) { |
1703 snapshot_->SetClosureReference(entry, local_name, context->get(idx)); | 1887 SetClosureReference(js_obj, entry, local_name, context->get(idx)); |
1704 } | 1888 } |
1705 } | 1889 } |
1706 snapshot_->SetInternalReference(entry, "code", func->shared()); | 1890 SetInternalReference(js_obj, entry, "code", func->shared()); |
1707 } | 1891 } |
1708 } | 1892 } |
1709 | 1893 |
1710 | 1894 |
1711 void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj, | 1895 void HeapSnapshotGenerator::ExtractPropertyReferences(JSObject* js_obj, |
1712 HeapEntry* entry) { | 1896 HeapEntry* entry) { |
1713 if (js_obj->HasFastProperties()) { | 1897 if (js_obj->HasFastProperties()) { |
1714 DescriptorArray* descs = js_obj->map()->instance_descriptors(); | 1898 DescriptorArray* descs = js_obj->map()->instance_descriptors(); |
1715 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 1899 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
1716 switch (descs->GetType(i)) { | 1900 switch (descs->GetType(i)) { |
1717 case FIELD: { | 1901 case FIELD: { |
1718 int index = descs->GetFieldIndex(i); | 1902 int index = descs->GetFieldIndex(i); |
1719 snapshot_->SetPropertyReference( | 1903 SetPropertyReference( |
1720 entry, descs->GetKey(i), js_obj->FastPropertyAt(index)); | 1904 js_obj, entry, descs->GetKey(i), js_obj->FastPropertyAt(index)); |
1721 break; | 1905 break; |
1722 } | 1906 } |
1723 case CONSTANT_FUNCTION: | 1907 case CONSTANT_FUNCTION: |
1724 snapshot_->SetPropertyReference( | 1908 SetPropertyReference( |
1725 entry, descs->GetKey(i), descs->GetConstantFunction(i)); | 1909 js_obj, entry, descs->GetKey(i), descs->GetConstantFunction(i)); |
1726 break; | 1910 break; |
1727 default: ; | 1911 default: ; |
1728 } | 1912 } |
1729 } | 1913 } |
1730 } else { | 1914 } else { |
1731 StringDictionary* dictionary = js_obj->property_dictionary(); | 1915 StringDictionary* dictionary = js_obj->property_dictionary(); |
1732 int length = dictionary->Capacity(); | 1916 int length = dictionary->Capacity(); |
1733 for (int i = 0; i < length; ++i) { | 1917 for (int i = 0; i < length; ++i) { |
1734 Object* k = dictionary->KeyAt(i); | 1918 Object* k = dictionary->KeyAt(i); |
1735 if (dictionary->IsKey(k)) { | 1919 if (dictionary->IsKey(k)) { |
1736 snapshot_->SetPropertyReference( | 1920 SetPropertyReference( |
1737 entry, String::cast(k), dictionary->ValueAt(i)); | 1921 js_obj, entry, String::cast(k), dictionary->ValueAt(i)); |
1738 } | 1922 } |
1739 } | 1923 } |
1740 } | 1924 } |
1741 } | 1925 } |
1742 | 1926 |
1743 | 1927 |
1744 void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj, | 1928 void HeapSnapshotGenerator::ExtractElementReferences(JSObject* js_obj, |
1745 HeapEntry* entry) { | 1929 HeapEntry* entry) { |
1746 if (js_obj->HasFastElements()) { | 1930 if (js_obj->HasFastElements()) { |
1747 FixedArray* elements = FixedArray::cast(js_obj->elements()); | 1931 FixedArray* elements = FixedArray::cast(js_obj->elements()); |
1748 int length = js_obj->IsJSArray() ? | 1932 int length = js_obj->IsJSArray() ? |
1749 Smi::cast(JSArray::cast(js_obj)->length())->value() : | 1933 Smi::cast(JSArray::cast(js_obj)->length())->value() : |
1750 elements->length(); | 1934 elements->length(); |
1751 for (int i = 0; i < length; ++i) { | 1935 for (int i = 0; i < length; ++i) { |
1752 if (!elements->get(i)->IsTheHole()) { | 1936 if (!elements->get(i)->IsTheHole()) { |
1753 snapshot_->SetElementReference(entry, i, elements->get(i)); | 1937 SetElementReference(js_obj, entry, i, elements->get(i)); |
1754 } | 1938 } |
1755 } | 1939 } |
1756 } else if (js_obj->HasDictionaryElements()) { | 1940 } else if (js_obj->HasDictionaryElements()) { |
1757 NumberDictionary* dictionary = js_obj->element_dictionary(); | 1941 NumberDictionary* dictionary = js_obj->element_dictionary(); |
1758 int length = dictionary->Capacity(); | 1942 int length = dictionary->Capacity(); |
1759 for (int i = 0; i < length; ++i) { | 1943 for (int i = 0; i < length; ++i) { |
1760 Object* k = dictionary->KeyAt(i); | 1944 Object* k = dictionary->KeyAt(i); |
1761 if (dictionary->IsKey(k)) { | 1945 if (dictionary->IsKey(k)) { |
1762 ASSERT(k->IsNumber()); | 1946 ASSERT(k->IsNumber()); |
1763 uint32_t index = static_cast<uint32_t>(k->Number()); | 1947 uint32_t index = static_cast<uint32_t>(k->Number()); |
1764 snapshot_->SetElementReference(entry, index, dictionary->ValueAt(i)); | 1948 SetElementReference(js_obj, entry, index, dictionary->ValueAt(i)); |
1765 } | 1949 } |
1766 } | 1950 } |
1767 } | 1951 } |
1768 } | 1952 } |
1769 | 1953 |
1770 | 1954 |
| 1955 void HeapSnapshotGenerator::SetClosureReference(HeapObject* parent_obj, |
| 1956 HeapEntry* parent_entry, |
| 1957 String* reference_name, |
| 1958 Object* child_obj) { |
| 1959 HeapEntry* child_entry = GetEntry(child_obj); |
| 1960 if (child_entry != NULL) { |
| 1961 filler_->SetNamedReference(HeapGraphEdge::kContextVariable, |
| 1962 parent_obj, |
| 1963 parent_entry, |
| 1964 collection_->GetName(reference_name), |
| 1965 child_obj, |
| 1966 child_entry); |
| 1967 } |
| 1968 } |
| 1969 |
| 1970 |
| 1971 void HeapSnapshotGenerator::SetElementReference(HeapObject* parent_obj, |
| 1972 HeapEntry* parent_entry, |
| 1973 int index, |
| 1974 Object* child_obj) { |
| 1975 HeapEntry* child_entry = GetEntry(child_obj); |
| 1976 if (child_entry != NULL) { |
| 1977 filler_->SetElementReference( |
| 1978 parent_obj, parent_entry, index, child_obj, child_entry); |
| 1979 } |
| 1980 } |
| 1981 |
| 1982 |
| 1983 void HeapSnapshotGenerator::SetInternalReference(HeapObject* parent_obj, |
| 1984 HeapEntry* parent_entry, |
| 1985 const char* reference_name, |
| 1986 Object* child_obj) { |
| 1987 HeapEntry* child_entry = GetEntry(child_obj); |
| 1988 if (child_entry != NULL) { |
| 1989 filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| 1990 parent_obj, |
| 1991 parent_entry, |
| 1992 reference_name, |
| 1993 child_obj, |
| 1994 child_entry); |
| 1995 } |
| 1996 } |
| 1997 |
| 1998 |
| 1999 void HeapSnapshotGenerator::SetPropertyReference(HeapObject* parent_obj, |
| 2000 HeapEntry* parent_entry, |
| 2001 String* reference_name, |
| 2002 Object* child_obj) { |
| 2003 HeapEntry* child_entry = GetEntry(child_obj); |
| 2004 if (child_entry != NULL) { |
| 2005 filler_->SetNamedReference(HeapGraphEdge::kProperty, |
| 2006 parent_obj, |
| 2007 parent_entry, |
| 2008 collection_->GetName(reference_name), |
| 2009 child_obj, |
| 2010 child_entry); |
| 2011 } |
| 2012 } |
| 2013 |
| 2014 |
| 2015 void HeapSnapshotGenerator::SetRootReference(Object* child_obj) { |
| 2016 HeapEntry* child_entry = GetEntry(child_obj); |
| 2017 ASSERT(child_entry != NULL); |
| 2018 filler_->SetRootReference(child_obj, child_entry); |
| 2019 } |
| 2020 |
| 2021 |
| 2022 void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { |
| 2023 raw_additions_root_ = |
| 2024 NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); |
| 2025 additions_root()->Init(snapshot2_, additions_count, 0); |
| 2026 raw_deletions_root_ = |
| 2027 NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0)); |
| 2028 deletions_root()->Init(snapshot1_, deletions_count, 0); |
| 2029 } |
| 2030 |
| 2031 |
1771 static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) { | 2032 static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) { |
1772 delete *diff_ptr; | 2033 delete *diff_ptr; |
1773 } | 2034 } |
1774 | 2035 |
1775 HeapSnapshotsComparator::~HeapSnapshotsComparator() { | 2036 HeapSnapshotsComparator::~HeapSnapshotsComparator() { |
1776 diffs_.Iterate(DeleteHeapSnapshotsDiff); | 2037 diffs_.Iterate(DeleteHeapSnapshotsDiff); |
1777 } | 2038 } |
1778 | 2039 |
1779 | 2040 |
1780 HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1, | 2041 HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1, |
1781 HeapSnapshot* snapshot2) { | 2042 HeapSnapshot* snapshot2) { |
1782 HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2); | |
1783 diffs_.Add(diff); | |
1784 List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList(); | 2043 List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList(); |
1785 List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList(); | 2044 List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList(); |
1786 int i = 0, j = 0; | 2045 int i = 0, j = 0; |
1787 List<HeapEntry*> added_entries, deleted_entries; | 2046 List<HeapEntry*> added_entries, deleted_entries; |
1788 while (i < entries1->length() && j < entries2->length()) { | 2047 while (i < entries1->length() && j < entries2->length()) { |
1789 uint64_t id1 = entries1->at(i)->id(); | 2048 uint64_t id1 = entries1->at(i)->id(); |
1790 uint64_t id2 = entries2->at(j)->id(); | 2049 uint64_t id2 = entries2->at(j)->id(); |
1791 if (id1 == id2) { | 2050 if (id1 == id2) { |
1792 i++; | 2051 i++; |
1793 j++; | 2052 j++; |
1794 } else if (id1 < id2) { | 2053 } else if (id1 < id2) { |
1795 HeapEntry* entry = entries1->at(i++); | 2054 HeapEntry* entry = entries1->at(i++); |
1796 deleted_entries.Add(entry); | 2055 deleted_entries.Add(entry); |
1797 } else { | 2056 } else { |
1798 HeapEntry* entry = entries2->at(j++); | 2057 HeapEntry* entry = entries2->at(j++); |
1799 added_entries.Add(entry); | 2058 added_entries.Add(entry); |
1800 } | 2059 } |
1801 } | 2060 } |
1802 while (i < entries1->length()) { | 2061 while (i < entries1->length()) { |
1803 HeapEntry* entry = entries1->at(i++); | 2062 HeapEntry* entry = entries1->at(i++); |
1804 deleted_entries.Add(entry); | 2063 deleted_entries.Add(entry); |
1805 } | 2064 } |
1806 while (j < entries2->length()) { | 2065 while (j < entries2->length()) { |
1807 HeapEntry* entry = entries2->at(j++); | 2066 HeapEntry* entry = entries2->at(j++); |
1808 added_entries.Add(entry); | 2067 added_entries.Add(entry); |
1809 } | 2068 } |
1810 | 2069 |
1811 snapshot1->ClearPaint(); | 2070 snapshot1->ClearPaint(); |
1812 snapshot1->root()->PaintAllReachable(); | 2071 snapshot1->root()->PaintAllReachable(); |
| 2072 snapshot2->ClearPaint(); |
| 2073 snapshot2->root()->PaintAllReachable(); |
| 2074 int reachable_deleted_entries = 0, reachable_added_entries = 0; |
| 2075 for (int i = 0; i < deleted_entries.length(); ++i) { |
| 2076 HeapEntry* entry = deleted_entries[i]; |
| 2077 if (entry->painted_reachable()) ++reachable_deleted_entries; |
| 2078 } |
| 2079 for (int i = 0; i < added_entries.length(); ++i) { |
| 2080 HeapEntry* entry = added_entries[i]; |
| 2081 if (entry->painted_reachable()) ++reachable_added_entries; |
| 2082 } |
| 2083 |
| 2084 HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2); |
| 2085 diffs_.Add(diff); |
| 2086 diff->CreateRoots(reachable_added_entries, reachable_deleted_entries); |
| 2087 |
| 2088 int del_child_index = 0, deleted_entry_index = 1; |
1813 for (int i = 0; i < deleted_entries.length(); ++i) { | 2089 for (int i = 0; i < deleted_entries.length(); ++i) { |
1814 HeapEntry* entry = deleted_entries[i]; | 2090 HeapEntry* entry = deleted_entries[i]; |
1815 if (entry->painted_reachable()) | 2091 if (entry->painted_reachable()) |
1816 diff->AddDeletedEntry(entry); | 2092 diff->AddDeletedEntry(del_child_index++, deleted_entry_index++, entry); |
1817 } | 2093 } |
1818 snapshot2->ClearPaint(); | 2094 int add_child_index = 0, added_entry_index = 1; |
1819 snapshot2->root()->PaintAllReachable(); | |
1820 for (int i = 0; i < added_entries.length(); ++i) { | 2095 for (int i = 0; i < added_entries.length(); ++i) { |
1821 HeapEntry* entry = added_entries[i]; | 2096 HeapEntry* entry = added_entries[i]; |
1822 if (entry->painted_reachable()) | 2097 if (entry->painted_reachable()) |
1823 diff->AddAddedEntry(entry); | 2098 diff->AddAddedEntry(add_child_index++, added_entry_index++, entry); |
1824 } | 2099 } |
1825 return diff; | 2100 return diff; |
1826 } | 2101 } |
1827 | 2102 |
1828 } } // namespace v8::internal | 2103 } } // namespace v8::internal |
1829 | 2104 |
1830 #endif // ENABLE_LOGGING_AND_PROFILING | 2105 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |