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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); | 174 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); |
175 OS::Print("\n"); | 175 OS::Print("\n"); |
176 for (HashMap::Entry* p = children_.Start(); | 176 for (HashMap::Entry* p = children_.Start(); |
177 p != NULL; | 177 p != NULL; |
178 p = children_.Next(p)) { | 178 p = children_.Next(p)) { |
179 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); | 179 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2); |
180 } | 180 } |
181 } | 181 } |
182 | 182 |
183 | 183 |
184 namespace { | |
185 | |
186 class DeleteNodesCallback { | 184 class DeleteNodesCallback { |
187 public: | 185 public: |
188 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } | 186 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
189 | 187 |
190 void AfterAllChildrenTraversed(ProfileNode* node) { | 188 void AfterAllChildrenTraversed(ProfileNode* node) { |
191 delete node; | 189 delete node; |
192 } | 190 } |
193 | 191 |
194 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } | 192 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } |
195 }; | 193 }; |
196 | 194 |
197 } // namespace | |
198 | |
199 | 195 |
200 ProfileTree::ProfileTree() | 196 ProfileTree::ProfileTree() |
201 : root_entry_(Logger::FUNCTION_TAG, | 197 : root_entry_(Logger::FUNCTION_TAG, |
202 "", | 198 "", |
203 "(root)", | 199 "(root)", |
204 "", | 200 "", |
205 0, | 201 0, |
206 TokenEnumerator::kNoSecurityToken), | 202 TokenEnumerator::kNoSecurityToken), |
207 root_(new ProfileNode(this, &root_entry_)) { | 203 root_(new ProfileNode(this, &root_entry_)) { |
208 } | 204 } |
(...skipping 24 matching lines...) Expand all Loading... |
233 entry != path.start() + path.length(); | 229 entry != path.start() + path.length(); |
234 ++entry) { | 230 ++entry) { |
235 if (*entry != NULL) { | 231 if (*entry != NULL) { |
236 node = node->FindOrAddChild(*entry); | 232 node = node->FindOrAddChild(*entry); |
237 } | 233 } |
238 } | 234 } |
239 node->IncrementSelfTicks(); | 235 node->IncrementSelfTicks(); |
240 } | 236 } |
241 | 237 |
242 | 238 |
243 namespace { | |
244 | |
245 struct NodesPair { | 239 struct NodesPair { |
246 NodesPair(ProfileNode* src, ProfileNode* dst) | 240 NodesPair(ProfileNode* src, ProfileNode* dst) |
247 : src(src), dst(dst) { } | 241 : src(src), dst(dst) { } |
248 ProfileNode* src; | 242 ProfileNode* src; |
249 ProfileNode* dst; | 243 ProfileNode* dst; |
250 }; | 244 }; |
251 | 245 |
252 | 246 |
253 class FilteredCloneCallback { | 247 class FilteredCloneCallback { |
254 public: | 248 public: |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 return parent_token == TokenEnumerator::kNoSecurityToken | 281 return parent_token == TokenEnumerator::kNoSecurityToken |
288 || parent_token == security_token_id_; | 282 || parent_token == security_token_id_; |
289 } | 283 } |
290 return false; | 284 return false; |
291 } | 285 } |
292 | 286 |
293 List<NodesPair> stack_; | 287 List<NodesPair> stack_; |
294 int security_token_id_; | 288 int security_token_id_; |
295 }; | 289 }; |
296 | 290 |
297 } // namespace | |
298 | |
299 void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) { | 291 void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) { |
300 ms_to_ticks_scale_ = src->ms_to_ticks_scale_; | 292 ms_to_ticks_scale_ = src->ms_to_ticks_scale_; |
301 FilteredCloneCallback cb(root_, security_token_id); | 293 FilteredCloneCallback cb(root_, security_token_id); |
302 src->TraverseDepthFirst(&cb); | 294 src->TraverseDepthFirst(&cb); |
303 CalculateTotalTicks(); | 295 CalculateTotalTicks(); |
304 } | 296 } |
305 | 297 |
306 | 298 |
307 void ProfileTree::SetTickRatePerMs(double ticks_per_ms) { | 299 void ProfileTree::SetTickRatePerMs(double ticks_per_ms) { |
308 ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0; | 300 ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0; |
309 } | 301 } |
310 | 302 |
311 | 303 |
312 namespace { | |
313 | |
314 class Position { | 304 class Position { |
315 public: | 305 public: |
316 explicit Position(ProfileNode* node) | 306 explicit Position(ProfileNode* node) |
317 : node(node), child_idx_(0) { } | 307 : node(node), child_idx_(0) { } |
318 INLINE(ProfileNode* current_child()) { | 308 INLINE(ProfileNode* current_child()) { |
319 return node->children()->at(child_idx_); | 309 return node->children()->at(child_idx_); |
320 } | 310 } |
321 INLINE(bool has_current_child()) { | 311 INLINE(bool has_current_child()) { |
322 return child_idx_ < node->children()->length(); | 312 return child_idx_ < node->children()->length(); |
323 } | 313 } |
324 INLINE(void next_child()) { ++child_idx_; } | 314 INLINE(void next_child()) { ++child_idx_; } |
325 | 315 |
326 ProfileNode* node; | 316 ProfileNode* node; |
327 private: | 317 private: |
328 int child_idx_; | 318 int child_idx_; |
329 }; | 319 }; |
330 | 320 |
331 } // namespace | |
332 | |
333 | 321 |
334 // Non-recursive implementation of a depth-first post-order tree traversal. | 322 // Non-recursive implementation of a depth-first post-order tree traversal. |
335 template <typename Callback> | 323 template <typename Callback> |
336 void ProfileTree::TraverseDepthFirst(Callback* callback) { | 324 void ProfileTree::TraverseDepthFirst(Callback* callback) { |
337 List<Position> stack(10); | 325 List<Position> stack(10); |
338 stack.Add(Position(root_)); | 326 stack.Add(Position(root_)); |
339 while (stack.length() > 0) { | 327 while (stack.length() > 0) { |
340 Position& current = stack.last(); | 328 Position& current = stack.last(); |
341 if (current.has_current_child()) { | 329 if (current.has_current_child()) { |
342 callback->BeforeTraversingChild(current.node, current.current_child()); | 330 callback->BeforeTraversingChild(current.node, current.current_child()); |
343 stack.Add(Position(current.current_child())); | 331 stack.Add(Position(current.current_child())); |
344 } else { | 332 } else { |
345 callback->AfterAllChildrenTraversed(current.node); | 333 callback->AfterAllChildrenTraversed(current.node); |
346 if (stack.length() > 1) { | 334 if (stack.length() > 1) { |
347 Position& parent = stack[stack.length() - 2]; | 335 Position& parent = stack[stack.length() - 2]; |
348 callback->AfterChildTraversed(parent.node, current.node); | 336 callback->AfterChildTraversed(parent.node, current.node); |
349 parent.next_child(); | 337 parent.next_child(); |
350 } | 338 } |
351 // Remove child from the stack. | 339 // Remove child from the stack. |
352 stack.RemoveLast(); | 340 stack.RemoveLast(); |
353 } | 341 } |
354 } | 342 } |
355 } | 343 } |
356 | 344 |
357 | 345 |
358 namespace { | |
359 | |
360 class CalculateTotalTicksCallback { | 346 class CalculateTotalTicksCallback { |
361 public: | 347 public: |
362 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } | 348 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { } |
363 | 349 |
364 void AfterAllChildrenTraversed(ProfileNode* node) { | 350 void AfterAllChildrenTraversed(ProfileNode* node) { |
365 node->IncreaseTotalTicks(node->self_ticks()); | 351 node->IncreaseTotalTicks(node->self_ticks()); |
366 } | 352 } |
367 | 353 |
368 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { | 354 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) { |
369 parent->IncreaseTotalTicks(child->total_ticks()); | 355 parent->IncreaseTotalTicks(child->total_ticks()); |
370 } | 356 } |
371 }; | 357 }; |
372 | 358 |
373 } // namespace | |
374 | |
375 | 359 |
376 void ProfileTree::CalculateTotalTicks() { | 360 void ProfileTree::CalculateTotalTicks() { |
377 CalculateTotalTicksCallback cb; | 361 CalculateTotalTicksCallback cb; |
378 TraverseDepthFirst(&cb); | 362 TraverseDepthFirst(&cb); |
379 } | 363 } |
380 | 364 |
381 | 365 |
382 void ProfileTree::ShortPrint() { | 366 void ProfileTree::ShortPrint() { |
383 OS::Print("root: %u %u %.2fms %.2fms\n", | 367 OS::Print("root: %u %u %.2fms %.2fms\n", |
384 root_->total_ticks(), root_->self_ticks(), | 368 root_->total_ticks(), root_->self_ticks(), |
(...skipping 485 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
870 void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) { | 854 void HeapEntry::SetPropertyReference(const char* name, HeapEntry* entry) { |
871 AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry)); | 855 AddEdge(new HeapGraphEdge(HeapGraphEdge::PROPERTY, name, this, entry)); |
872 } | 856 } |
873 | 857 |
874 | 858 |
875 void HeapEntry::SetAutoIndexReference(HeapEntry* entry) { | 859 void HeapEntry::SetAutoIndexReference(HeapEntry* entry) { |
876 SetElementReference(next_auto_index_++, entry); | 860 SetElementReference(next_auto_index_++, entry); |
877 } | 861 } |
878 | 862 |
879 | 863 |
| 864 void HeapEntry::SetUnidirAutoIndexReference(HeapEntry* entry) { |
| 865 children_.Add(new HeapGraphEdge(next_auto_index_++, this, entry)); |
| 866 } |
| 867 |
| 868 |
880 int HeapEntry::TotalSize() { | 869 int HeapEntry::TotalSize() { |
881 return total_size_ != kUnknownSize ? total_size_ : CalculateTotalSize(); | 870 return total_size_ != kUnknownSize ? total_size_ : CalculateTotalSize(); |
882 } | 871 } |
883 | 872 |
884 | 873 |
885 int HeapEntry::NonSharedTotalSize() { | 874 int HeapEntry::NonSharedTotalSize() { |
886 return non_shared_total_size_ != kUnknownSize ? | 875 return non_shared_total_size_ != kUnknownSize ? |
887 non_shared_total_size_ : CalculateNonSharedTotalSize(); | 876 non_shared_total_size_ : CalculateNonSharedTotalSize(); |
888 } | 877 } |
889 | 878 |
890 | 879 |
891 int HeapEntry::CalculateTotalSize() { | 880 template<class Visitor> |
892 snapshot_->ClearPaint(); | 881 void HeapEntry::ApplyAndPaintAllReachable(Visitor* visitor) { |
893 List<HeapEntry*> list(10); | 882 List<HeapEntry*> list(10); |
894 list.Add(this); | 883 list.Add(this); |
895 total_size_ = self_size_; | |
896 this->PaintReachable(); | 884 this->PaintReachable(); |
| 885 visitor->Apply(this); |
897 while (!list.is_empty()) { | 886 while (!list.is_empty()) { |
898 HeapEntry* entry = list.RemoveLast(); | 887 HeapEntry* entry = list.RemoveLast(); |
899 const int children_count = entry->children_.length(); | 888 const int children_count = entry->children_.length(); |
900 for (int i = 0; i < children_count; ++i) { | 889 for (int i = 0; i < children_count; ++i) { |
901 HeapEntry* child = entry->children_[i]->to(); | 890 HeapEntry* child = entry->children_[i]->to(); |
902 if (!child->painted_reachable()) { | 891 if (!child->painted_reachable()) { |
903 list.Add(child); | 892 list.Add(child); |
904 child->PaintReachable(); | 893 child->PaintReachable(); |
905 total_size_ += child->self_size_; | 894 visitor->Apply(child); |
906 } | 895 } |
907 } | 896 } |
908 } | 897 } |
| 898 } |
| 899 |
| 900 |
| 901 class NullClass { |
| 902 public: |
| 903 void Apply(HeapEntry* entry) { } |
| 904 }; |
| 905 |
| 906 void HeapEntry::PaintAllReachable() { |
| 907 NullClass null; |
| 908 ApplyAndPaintAllReachable(&null); |
| 909 } |
| 910 |
| 911 |
| 912 class TotalSizeCalculator { |
| 913 public: |
| 914 TotalSizeCalculator() |
| 915 : total_size_(0) { |
| 916 } |
| 917 |
| 918 int total_size() const { return total_size_; } |
| 919 |
| 920 void Apply(HeapEntry* entry) { |
| 921 total_size_ += entry->self_size(); |
| 922 } |
| 923 |
| 924 private: |
| 925 int total_size_; |
| 926 }; |
| 927 |
| 928 int HeapEntry::CalculateTotalSize() { |
| 929 snapshot_->ClearPaint(); |
| 930 TotalSizeCalculator calc; |
| 931 ApplyAndPaintAllReachable(&calc); |
| 932 total_size_ = calc.total_size(); |
909 return total_size_; | 933 return total_size_; |
910 } | 934 } |
911 | 935 |
912 | 936 |
913 namespace { | |
914 | |
915 class NonSharedSizeCalculator { | 937 class NonSharedSizeCalculator { |
916 public: | 938 public: |
917 NonSharedSizeCalculator() | 939 NonSharedSizeCalculator() |
918 : non_shared_total_size_(0) { | 940 : non_shared_total_size_(0) { |
919 } | 941 } |
920 | 942 |
921 int non_shared_total_size() const { return non_shared_total_size_; } | 943 int non_shared_total_size() const { return non_shared_total_size_; } |
922 | 944 |
923 void Apply(HeapEntry* entry) { | 945 void Apply(HeapEntry* entry) { |
924 if (entry->painted_reachable()) { | 946 if (entry->painted_reachable()) { |
925 non_shared_total_size_ += entry->self_size(); | 947 non_shared_total_size_ += entry->self_size(); |
926 } | 948 } |
927 } | 949 } |
928 | 950 |
929 private: | 951 private: |
930 int non_shared_total_size_; | 952 int non_shared_total_size_; |
931 }; | 953 }; |
932 | 954 |
933 } // namespace | |
934 | |
935 int HeapEntry::CalculateNonSharedTotalSize() { | 955 int HeapEntry::CalculateNonSharedTotalSize() { |
936 // To calculate non-shared total size, first we paint all reachable | 956 // To calculate non-shared total size, first we paint all reachable |
937 // nodes in one color, then we paint all nodes reachable from other | 957 // nodes in one color, then we paint all nodes reachable from other |
938 // nodes with a different color. Then we consider only nodes painted | 958 // nodes with a different color. Then we consider only nodes painted |
939 // with the first color for caclulating the total size. | 959 // with the first color for calculating the total size. |
940 snapshot_->ClearPaint(); | 960 snapshot_->ClearPaint(); |
| 961 PaintAllReachable(); |
| 962 |
941 List<HeapEntry*> list(10); | 963 List<HeapEntry*> list(10); |
942 list.Add(this); | 964 if (this != snapshot_->root()) { |
943 this->PaintReachable(); | 965 list.Add(snapshot_->root()); |
| 966 snapshot_->root()->PaintReachableFromOthers(); |
| 967 } |
944 while (!list.is_empty()) { | 968 while (!list.is_empty()) { |
945 HeapEntry* entry = list.RemoveLast(); | 969 HeapEntry* entry = list.RemoveLast(); |
946 const int children_count = entry->children_.length(); | 970 const int children_count = entry->children_.length(); |
947 for (int i = 0; i < children_count; ++i) { | 971 for (int i = 0; i < children_count; ++i) { |
948 HeapEntry* child = entry->children_[i]->to(); | 972 HeapEntry* child = entry->children_[i]->to(); |
949 if (!child->painted_reachable()) { | 973 if (child != this && child->not_painted_reachable_from_others()) { |
950 list.Add(child); | 974 list.Add(child); |
951 child->PaintReachable(); | |
952 } | |
953 } | |
954 } | |
955 | |
956 List<HeapEntry*> list2(10); | |
957 if (this != snapshot_->root()) { | |
958 list2.Add(snapshot_->root()); | |
959 snapshot_->root()->PaintReachableFromOthers(); | |
960 } | |
961 while (!list2.is_empty()) { | |
962 HeapEntry* entry = list2.RemoveLast(); | |
963 const int children_count = entry->children_.length(); | |
964 for (int i = 0; i < children_count; ++i) { | |
965 HeapEntry* child = entry->children_[i]->to(); | |
966 if (child != this && child->not_painted_reachable_from_others()) { | |
967 list2.Add(child); | |
968 child->PaintReachableFromOthers(); | 975 child->PaintReachableFromOthers(); |
969 } | 976 } |
970 } | 977 } |
971 } | 978 } |
972 | 979 |
973 NonSharedSizeCalculator calculator; | 980 NonSharedSizeCalculator calculator; |
974 snapshot_->IterateEntries(&calculator); | 981 snapshot_->IterateEntries(&calculator); |
975 return calculator.non_shared_total_size(); | 982 non_shared_total_size_ = calculator.non_shared_total_size(); |
| 983 return non_shared_total_size_; |
976 } | 984 } |
977 | 985 |
978 | 986 |
979 class CachedHeapGraphPath { | 987 class CachedHeapGraphPath { |
980 public: | 988 public: |
981 CachedHeapGraphPath() | 989 CachedHeapGraphPath() |
982 : nodes_(NodesMatch) { } | 990 : nodes_(NodesMatch) { } |
983 CachedHeapGraphPath(const CachedHeapGraphPath& src) | 991 CachedHeapGraphPath(const CachedHeapGraphPath& src) |
984 : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()), | 992 : nodes_(NodesMatch, &HashMap::DefaultAllocator, src.nodes_.capacity()), |
985 path_(src.path_.length() + 1) { | 993 path_(src.path_.length() + 1) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1071 | 1079 |
1072 for (int i = 0; i < retainers_.length(); ++i) { | 1080 for (int i = 0; i < retainers_.length(); ++i) { |
1073 HeapGraphEdge* edge = retainers_[i]; | 1081 HeapGraphEdge* edge = retainers_[i]; |
1074 edge->from()->RemoveChild(edge); | 1082 edge->from()->RemoveChild(edge); |
1075 } | 1083 } |
1076 retainers_.Clear(); | 1084 retainers_.Clear(); |
1077 } | 1085 } |
1078 | 1086 |
1079 | 1087 |
1080 void HeapEntry::Print(int max_depth, int indent) { | 1088 void HeapEntry::Print(int max_depth, int indent) { |
1081 OS::Print("%6d %6d %6d ", self_size_, TotalSize(), NonSharedTotalSize()); | 1089 OS::Print("%6d %6d %6d [%ld] ", |
| 1090 self_size_, TotalSize(), NonSharedTotalSize(), id_); |
1082 if (type_ != STRING) { | 1091 if (type_ != STRING) { |
1083 OS::Print("%s %.40s\n", TypeAsString(), name_); | 1092 OS::Print("%s %.40s\n", TypeAsString(), name_); |
1084 } else { | 1093 } else { |
1085 OS::Print("\""); | 1094 OS::Print("\""); |
1086 const char* c = name_; | 1095 const char* c = name_; |
1087 while (*c && (c - name_) <= 40) { | 1096 while (*c && (c - name_) <= 40) { |
1088 if (*c != '\n') | 1097 if (*c != '\n') |
1089 OS::Print("%c", *c); | 1098 OS::Print("%c", *c); |
1090 else | 1099 else |
1091 OS::Print("\\n"); | 1100 OS::Print("\\n"); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1237 cache_entry->value = entry; | 1246 cache_entry->value = entry; |
1238 } | 1247 } |
1239 | 1248 |
1240 | 1249 |
1241 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, | 1250 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
1242 const char* title, | 1251 const char* title, |
1243 unsigned uid) | 1252 unsigned uid) |
1244 : collection_(collection), | 1253 : collection_(collection), |
1245 title_(title), | 1254 title_(title), |
1246 uid_(uid), | 1255 uid_(uid), |
1247 root_(this) { | 1256 root_(this), |
| 1257 sorted_entries_(NULL) { |
1248 } | 1258 } |
1249 | 1259 |
1250 | 1260 |
| 1261 HeapSnapshot::~HeapSnapshot() { |
| 1262 delete sorted_entries_; |
| 1263 } |
| 1264 |
| 1265 |
1251 void HeapSnapshot::ClearPaint() { | 1266 void HeapSnapshot::ClearPaint() { |
1252 root_.ClearPaint(); | 1267 root_.ClearPaint(); |
1253 entries_.Apply(&HeapEntry::ClearPaint); | 1268 entries_.Apply(&HeapEntry::ClearPaint); |
1254 } | 1269 } |
1255 | 1270 |
1256 | 1271 |
1257 HeapEntry* HeapSnapshot::GetEntry(Object* obj) { | 1272 HeapEntry* HeapSnapshot::GetEntry(Object* obj) { |
1258 if (!obj->IsHeapObject()) return NULL; | 1273 if (!obj->IsHeapObject()) return NULL; |
1259 HeapObject* object = HeapObject::cast(obj); | 1274 HeapObject* object = HeapObject::cast(obj); |
1260 | 1275 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1348 } | 1363 } |
1349 } | 1364 } |
1350 | 1365 |
1351 | 1366 |
1352 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, | 1367 HeapEntry* HeapSnapshot::AddEntry(HeapObject* object, |
1353 HeapEntry::Type type, | 1368 HeapEntry::Type type, |
1354 const char* name) { | 1369 const char* name) { |
1355 HeapEntry* entry = new HeapEntry(this, | 1370 HeapEntry* entry = new HeapEntry(this, |
1356 type, | 1371 type, |
1357 name, | 1372 name, |
| 1373 collection_->GetObjectId(object->address()), |
1358 GetObjectSize(object), | 1374 GetObjectSize(object), |
1359 GetObjectSecurityToken(object)); | 1375 GetObjectSecurityToken(object)); |
1360 entries_.Pair(object, entry); | 1376 entries_.Pair(object, entry); |
1361 | 1377 |
1362 // Detect, if this is a JS global object of the current context, and | 1378 // Detect, if this is a JS global object of the current context, and |
1363 // add it to snapshot's roots. There can be several JS global objects | 1379 // add it to snapshot's roots. There can be several JS global objects |
1364 // in a context. | 1380 // in a context. |
1365 if (object->IsJSGlobalProxy()) { | 1381 if (object->IsJSGlobalProxy()) { |
1366 int global_security_token = GetGlobalSecurityToken(); | 1382 int global_security_token = GetGlobalSecurityToken(); |
1367 int object_security_token = | 1383 int object_security_token = |
1368 collection_->token_enumerator()->GetTokenId( | 1384 collection_->token_enumerator()->GetTokenId( |
1369 Context::cast( | 1385 Context::cast( |
1370 JSGlobalProxy::cast(object)->context())->security_token()); | 1386 JSGlobalProxy::cast(object)->context())->security_token()); |
1371 if (object_security_token == TokenEnumerator::kNoSecurityToken | 1387 if (object_security_token == TokenEnumerator::kNoSecurityToken |
1372 || object_security_token == global_security_token) { | 1388 || object_security_token == global_security_token) { |
1373 HeapEntry* global_object_entry = | 1389 HeapEntry* global_object_entry = |
1374 GetEntry(HeapObject::cast(object->map()->prototype())); | 1390 GetEntry(HeapObject::cast(object->map()->prototype())); |
1375 ASSERT(global_object_entry != NULL); | 1391 ASSERT(global_object_entry != NULL); |
1376 root_.SetAutoIndexReference(global_object_entry); | 1392 root_.SetAutoIndexReference(global_object_entry); |
1377 } | 1393 } |
1378 } | 1394 } |
1379 | 1395 |
1380 return entry; | 1396 return entry; |
1381 } | 1397 } |
1382 | 1398 |
1383 | 1399 |
1384 namespace { | |
1385 | |
1386 class EdgesCutter { | 1400 class EdgesCutter { |
1387 public: | 1401 public: |
1388 explicit EdgesCutter(int global_security_token) | 1402 explicit EdgesCutter(int global_security_token) |
1389 : global_security_token_(global_security_token) { | 1403 : global_security_token_(global_security_token) { |
1390 } | 1404 } |
1391 | 1405 |
1392 void Apply(HeapEntry* entry) { | 1406 void Apply(HeapEntry* entry) { |
1393 if (entry->security_token_id() != TokenEnumerator::kNoSecurityToken | 1407 if (entry->security_token_id() != TokenEnumerator::kNoSecurityToken |
1394 && entry->security_token_id() != global_security_token_) { | 1408 && entry->security_token_id() != global_security_token_) { |
1395 entry->CutEdges(); | 1409 entry->CutEdges(); |
1396 } | 1410 } |
1397 } | 1411 } |
1398 | 1412 |
1399 private: | 1413 private: |
1400 const int global_security_token_; | 1414 const int global_security_token_; |
1401 }; | 1415 }; |
1402 | 1416 |
1403 } // namespace | |
1404 | |
1405 void HeapSnapshot::CutObjectsFromForeignSecurityContexts() { | 1417 void HeapSnapshot::CutObjectsFromForeignSecurityContexts() { |
1406 EdgesCutter cutter(GetGlobalSecurityToken()); | 1418 EdgesCutter cutter(GetGlobalSecurityToken()); |
1407 entries_.Apply(&cutter); | 1419 entries_.Apply(&cutter); |
1408 } | 1420 } |
1409 | 1421 |
1410 | 1422 |
1411 int HeapSnapshot::GetGlobalSecurityToken() { | 1423 int HeapSnapshot::GetGlobalSecurityToken() { |
1412 return collection_->token_enumerator()->GetTokenId( | 1424 return collection_->token_enumerator()->GetTokenId( |
1413 Top::context()->global()->global_context()->security_token()); | 1425 Top::context()->global()->global_context()->security_token()); |
1414 } | 1426 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1447 size += f->context()->Size(); | 1459 size += f->context()->Size(); |
1448 } | 1460 } |
1449 if (f->literals()->length() != 0) { | 1461 if (f->literals()->length() != 0) { |
1450 size += f->literals()->Size(); | 1462 size += f->literals()->Size(); |
1451 } | 1463 } |
1452 } | 1464 } |
1453 return size; | 1465 return size; |
1454 } | 1466 } |
1455 | 1467 |
1456 | 1468 |
| 1469 class EntriesCollector { |
| 1470 public: |
| 1471 explicit EntriesCollector(List<HeapEntry*>* list) : list_(list) { } |
| 1472 void Apply(HeapEntry* entry) { |
| 1473 list_->Add(entry); |
| 1474 } |
| 1475 private: |
| 1476 List<HeapEntry*>* list_; |
| 1477 }; |
| 1478 |
| 1479 template<class T> |
| 1480 static int SortByIds(const T* entry1_ptr, |
| 1481 const T* entry2_ptr) { |
| 1482 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; |
| 1483 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; |
| 1484 } |
| 1485 |
| 1486 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
| 1487 if (sorted_entries_ != NULL) return sorted_entries_; |
| 1488 sorted_entries_ = new List<HeapEntry*>(entries_.capacity()); |
| 1489 EntriesCollector collector(sorted_entries_); |
| 1490 entries_.Apply(&collector); |
| 1491 sorted_entries_->Sort(SortByIds); |
| 1492 return sorted_entries_; |
| 1493 } |
| 1494 |
| 1495 |
| 1496 HeapSnapshotsDiff* HeapSnapshot::CompareWith(HeapSnapshot* snapshot) { |
| 1497 return collection_->CompareSnapshots(this, snapshot); |
| 1498 } |
| 1499 |
| 1500 |
1457 void HeapSnapshot::Print(int max_depth) { | 1501 void HeapSnapshot::Print(int max_depth) { |
1458 root_.Print(max_depth, 0); | 1502 root_.Print(max_depth, 0); |
1459 } | 1503 } |
1460 | 1504 |
1461 | 1505 |
| 1506 HeapObjectsMap::HeapObjectsMap() |
| 1507 : initial_fill_mode_(true), |
| 1508 next_id_(1), |
| 1509 entries_map_(AddressesMatch), |
| 1510 entries_(new List<EntryInfo>()) { } |
| 1511 |
| 1512 |
| 1513 HeapObjectsMap::~HeapObjectsMap() { |
| 1514 delete entries_; |
| 1515 } |
| 1516 |
| 1517 |
| 1518 void HeapObjectsMap::SnapshotGenerationFinished() { |
| 1519 initial_fill_mode_ = false; |
| 1520 RemoveDeadEntries(); |
| 1521 } |
| 1522 |
| 1523 |
| 1524 uint64_t HeapObjectsMap::FindObject(Address addr) { |
| 1525 if (!initial_fill_mode_) { |
| 1526 uint64_t existing = FindEntry(addr); |
| 1527 if (existing != 0) return existing; |
| 1528 } |
| 1529 uint64_t id = next_id_++; |
| 1530 AddEntry(addr, id); |
| 1531 return id; |
| 1532 } |
| 1533 |
| 1534 |
| 1535 void HeapObjectsMap::MoveObject(Address from, Address to) { |
| 1536 HashMap::Entry* entry = entries_map_.Lookup(from, AddressHash(from), false); |
| 1537 if (entry != NULL) { |
| 1538 void* value = entry->value; |
| 1539 entries_map_.Remove(from, AddressHash(from)); |
| 1540 entry = entries_map_.Lookup(to, AddressHash(to), true); |
| 1541 ASSERT(entry->value == NULL); |
| 1542 entry->value = value; |
| 1543 } |
| 1544 } |
| 1545 |
| 1546 |
| 1547 void HeapObjectsMap::AddEntry(Address addr, uint64_t id) { |
| 1548 HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), true); |
| 1549 ASSERT(entry->value == NULL); |
| 1550 entry->value = reinterpret_cast<void*>(entries_->length()); |
| 1551 entries_->Add(EntryInfo(id)); |
| 1552 } |
| 1553 |
| 1554 |
| 1555 uint64_t HeapObjectsMap::FindEntry(Address addr) { |
| 1556 HashMap::Entry* entry = entries_map_.Lookup(addr, AddressHash(addr), false); |
| 1557 if (entry != NULL) { |
| 1558 int entry_index = reinterpret_cast<intptr_t>(entry->value); |
| 1559 EntryInfo& entry_info = entries_->at(entry_index); |
| 1560 entry_info.accessed = true; |
| 1561 return entry_info.id; |
| 1562 } else { |
| 1563 return 0; |
| 1564 } |
| 1565 } |
| 1566 |
| 1567 |
| 1568 void HeapObjectsMap::RemoveDeadEntries() { |
| 1569 List<EntryInfo>* new_entries = new List<EntryInfo>(); |
| 1570 for (HashMap::Entry* entry = entries_map_.Start(); |
| 1571 entry != NULL; |
| 1572 entry = entries_map_.Next(entry)) { |
| 1573 int entry_index = reinterpret_cast<intptr_t>(entry->value); |
| 1574 EntryInfo& entry_info = entries_->at(entry_index); |
| 1575 if (entry_info.accessed) { |
| 1576 entry->value = reinterpret_cast<void*>(new_entries->length()); |
| 1577 new_entries->Add(EntryInfo(entry_info.id, false)); |
| 1578 } |
| 1579 } |
| 1580 delete entries_; |
| 1581 entries_ = new_entries; |
| 1582 } |
| 1583 |
| 1584 |
1462 HeapSnapshotsCollection::HeapSnapshotsCollection() | 1585 HeapSnapshotsCollection::HeapSnapshotsCollection() |
1463 : snapshots_uids_(HeapSnapshotsMatch), | 1586 : is_tracking_objects_(false), |
| 1587 snapshots_uids_(HeapSnapshotsMatch), |
1464 token_enumerator_(new TokenEnumerator()) { | 1588 token_enumerator_(new TokenEnumerator()) { |
1465 } | 1589 } |
1466 | 1590 |
1467 | 1591 |
1468 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) { | 1592 static void DeleteHeapSnapshot(HeapSnapshot** snapshot_ptr) { |
1469 delete *snapshot_ptr; | 1593 delete *snapshot_ptr; |
1470 } | 1594 } |
1471 | 1595 |
1472 | 1596 |
1473 HeapSnapshotsCollection::~HeapSnapshotsCollection() { | 1597 HeapSnapshotsCollection::~HeapSnapshotsCollection() { |
1474 delete token_enumerator_; | 1598 delete token_enumerator_; |
1475 snapshots_.Iterate(DeleteHeapSnapshot); | 1599 snapshots_.Iterate(DeleteHeapSnapshot); |
1476 } | 1600 } |
1477 | 1601 |
1478 | 1602 |
1479 HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name, | 1603 HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(const char* name, |
1480 unsigned uid) { | 1604 unsigned uid) { |
| 1605 is_tracking_objects_ = true; // Start watching for heap objects moves. |
1481 HeapSnapshot* snapshot = new HeapSnapshot(this, name, uid); | 1606 HeapSnapshot* snapshot = new HeapSnapshot(this, name, uid); |
1482 snapshots_.Add(snapshot); | 1607 snapshots_.Add(snapshot); |
1483 HashMap::Entry* entry = | 1608 HashMap::Entry* entry = |
1484 snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()), | 1609 snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()), |
1485 static_cast<uint32_t>(snapshot->uid()), | 1610 static_cast<uint32_t>(snapshot->uid()), |
1486 true); | 1611 true); |
1487 ASSERT(entry->value == NULL); | 1612 ASSERT(entry->value == NULL); |
1488 entry->value = snapshot; | 1613 entry->value = snapshot; |
1489 return snapshot; | 1614 return snapshot; |
1490 } | 1615 } |
1491 | 1616 |
1492 | 1617 |
1493 HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) { | 1618 HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) { |
1494 HashMap::Entry* entry = snapshots_uids_.Lookup(reinterpret_cast<void*>(uid), | 1619 HashMap::Entry* entry = snapshots_uids_.Lookup(reinterpret_cast<void*>(uid), |
1495 static_cast<uint32_t>(uid), | 1620 static_cast<uint32_t>(uid), |
1496 false); | 1621 false); |
1497 return entry != NULL ? reinterpret_cast<HeapSnapshot*>(entry->value) : NULL; | 1622 return entry != NULL ? reinterpret_cast<HeapSnapshot*>(entry->value) : NULL; |
1498 } | 1623 } |
1499 | 1624 |
1500 | 1625 |
| 1626 HeapSnapshotsDiff* HeapSnapshotsCollection::CompareSnapshots( |
| 1627 HeapSnapshot* snapshot1, |
| 1628 HeapSnapshot* snapshot2) { |
| 1629 return comparator_.Compare(snapshot1, snapshot2); |
| 1630 } |
| 1631 |
| 1632 |
1501 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) | 1633 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) |
1502 : snapshot_(snapshot) { | 1634 : snapshot_(snapshot) { |
1503 } | 1635 } |
1504 | 1636 |
1505 | 1637 |
1506 void HeapSnapshotGenerator::GenerateSnapshot() { | 1638 void HeapSnapshotGenerator::GenerateSnapshot() { |
1507 AssertNoAllocation no_alloc; | 1639 AssertNoAllocation no_alloc; |
1508 | 1640 |
1509 // Iterate heap contents. | 1641 // Iterate heap contents. |
1510 HeapIterator iterator; | 1642 HeapIterator iterator; |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1623 Object* k = dictionary->KeyAt(i); | 1755 Object* k = dictionary->KeyAt(i); |
1624 if (dictionary->IsKey(k)) { | 1756 if (dictionary->IsKey(k)) { |
1625 ASSERT(k->IsNumber()); | 1757 ASSERT(k->IsNumber()); |
1626 uint32_t index = static_cast<uint32_t>(k->Number()); | 1758 uint32_t index = static_cast<uint32_t>(k->Number()); |
1627 snapshot_->SetElementReference(entry, index, dictionary->ValueAt(i)); | 1759 snapshot_->SetElementReference(entry, index, dictionary->ValueAt(i)); |
1628 } | 1760 } |
1629 } | 1761 } |
1630 } | 1762 } |
1631 } | 1763 } |
1632 | 1764 |
| 1765 |
| 1766 static void DeleteHeapSnapshotsDiff(HeapSnapshotsDiff** diff_ptr) { |
| 1767 delete *diff_ptr; |
| 1768 } |
| 1769 |
| 1770 HeapSnapshotsComparator::~HeapSnapshotsComparator() { |
| 1771 diffs_.Iterate(DeleteHeapSnapshotsDiff); |
| 1772 } |
| 1773 |
| 1774 |
| 1775 HeapSnapshotsDiff* HeapSnapshotsComparator::Compare(HeapSnapshot* snapshot1, |
| 1776 HeapSnapshot* snapshot2) { |
| 1777 HeapSnapshotsDiff* diff = new HeapSnapshotsDiff(snapshot1, snapshot2); |
| 1778 diffs_.Add(diff); |
| 1779 List<HeapEntry*>* entries1 = snapshot1->GetSortedEntriesList(); |
| 1780 List<HeapEntry*>* entries2 = snapshot2->GetSortedEntriesList(); |
| 1781 int i = 0, j = 0; |
| 1782 List<HeapEntry*> added_entries, deleted_entries; |
| 1783 while (i < entries1->length() && j < entries2->length()) { |
| 1784 uint64_t id1 = entries1->at(i)->id(); |
| 1785 uint64_t id2 = entries2->at(j)->id(); |
| 1786 if (id1 == id2) { |
| 1787 i++; |
| 1788 j++; |
| 1789 } else if (id1 < id2) { |
| 1790 HeapEntry* entry = entries1->at(i++); |
| 1791 deleted_entries.Add(entry); |
| 1792 } else { |
| 1793 HeapEntry* entry = entries2->at(j++); |
| 1794 added_entries.Add(entry); |
| 1795 } |
| 1796 } |
| 1797 while (i < entries1->length()) { |
| 1798 HeapEntry* entry = entries1->at(i++); |
| 1799 deleted_entries.Add(entry); |
| 1800 } |
| 1801 while (j < entries2->length()) { |
| 1802 HeapEntry* entry = entries2->at(j++); |
| 1803 added_entries.Add(entry); |
| 1804 } |
| 1805 |
| 1806 snapshot1->ClearPaint(); |
| 1807 snapshot1->root()->PaintAllReachable(); |
| 1808 for (int i = 0; i < deleted_entries.length(); ++i) { |
| 1809 HeapEntry* entry = deleted_entries[i]; |
| 1810 if (entry->painted_reachable()) |
| 1811 diff->AddDeletedEntry(entry); |
| 1812 } |
| 1813 snapshot2->ClearPaint(); |
| 1814 snapshot2->root()->PaintAllReachable(); |
| 1815 for (int i = 0; i < added_entries.length(); ++i) { |
| 1816 HeapEntry* entry = added_entries[i]; |
| 1817 if (entry->painted_reachable()) |
| 1818 diff->AddAddedEntry(entry); |
| 1819 } |
| 1820 return diff; |
| 1821 } |
| 1822 |
1633 } } // namespace v8::internal | 1823 } } // namespace v8::internal |
1634 | 1824 |
1635 #endif // ENABLE_LOGGING_AND_PROFILING | 1825 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |