OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 SnapshotObjectId id, | 968 SnapshotObjectId id, |
969 int self_size, | 969 int self_size, |
970 int children_count, | 970 int children_count, |
971 int retainers_count) { | 971 int retainers_count) { |
972 snapshot_ = snapshot; | 972 snapshot_ = snapshot; |
973 type_ = type; | 973 type_ = type; |
974 painted_ = false; | 974 painted_ = false; |
975 name_ = name; | 975 name_ = name; |
976 self_size_ = self_size; | 976 self_size_ = self_size; |
977 retained_size_ = 0; | 977 retained_size_ = 0; |
| 978 entry_index_ = -1; |
978 children_count_ = children_count; | 979 children_count_ = children_count; |
979 retainers_count_ = retainers_count; | 980 retainers_count_ = retainers_count; |
980 dominator_ = NULL; | 981 dominator_ = NULL; |
981 id_ = id; | 982 id_ = id; |
982 } | 983 } |
983 | 984 |
984 | 985 |
985 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, | 986 void HeapEntry::SetNamedReference(HeapGraphEdge::Type type, |
986 int child_index, | 987 int child_index, |
987 const char* name, | 988 const char* name, |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1101 | 1102 |
1102 | 1103 |
1103 // It is very important to keep objects that form a heap snapshot | 1104 // It is very important to keep objects that form a heap snapshot |
1104 // as small as possible. | 1105 // as small as possible. |
1105 namespace { // Avoid littering the global namespace. | 1106 namespace { // Avoid littering the global namespace. |
1106 | 1107 |
1107 template <size_t ptr_size> struct SnapshotSizeConstants; | 1108 template <size_t ptr_size> struct SnapshotSizeConstants; |
1108 | 1109 |
1109 template <> struct SnapshotSizeConstants<4> { | 1110 template <> struct SnapshotSizeConstants<4> { |
1110 static const int kExpectedHeapGraphEdgeSize = 12; | 1111 static const int kExpectedHeapGraphEdgeSize = 12; |
1111 static const int kExpectedHeapEntrySize = 32; | 1112 static const int kExpectedHeapEntrySize = 36; |
1112 static const size_t kMaxSerializableSnapshotRawSize = 256 * MB; | 1113 static const size_t kMaxSerializableSnapshotRawSize = 256 * MB; |
1113 }; | 1114 }; |
1114 | 1115 |
1115 template <> struct SnapshotSizeConstants<8> { | 1116 template <> struct SnapshotSizeConstants<8> { |
1116 static const int kExpectedHeapGraphEdgeSize = 24; | 1117 static const int kExpectedHeapGraphEdgeSize = 24; |
1117 static const int kExpectedHeapEntrySize = 48; | 1118 static const int kExpectedHeapEntrySize = 48; |
1118 static const uint64_t kMaxSerializableSnapshotRawSize = | 1119 static const uint64_t kMaxSerializableSnapshotRawSize = |
1119 static_cast<uint64_t>(6000) * MB; | 1120 static_cast<uint64_t>(6000) * MB; |
1120 }; | 1121 }; |
1121 | 1122 |
1122 } // namespace | 1123 } // namespace |
1123 | 1124 |
1124 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, | 1125 HeapSnapshot::HeapSnapshot(HeapSnapshotsCollection* collection, |
1125 HeapSnapshot::Type type, | 1126 HeapSnapshot::Type type, |
1126 const char* title, | 1127 const char* title, |
1127 unsigned uid) | 1128 unsigned uid) |
1128 : collection_(collection), | 1129 : collection_(collection), |
1129 type_(type), | 1130 type_(type), |
1130 title_(title), | 1131 title_(title), |
1131 uid_(uid), | 1132 uid_(uid), |
1132 root_entry_(NULL), | 1133 root_entry_(NULL), |
1133 gc_roots_entry_(NULL), | 1134 gc_roots_entry_(NULL), |
1134 natives_root_entry_(NULL), | 1135 natives_root_entry_(NULL), |
1135 raw_entries_(NULL), | 1136 raw_entries_(NULL), |
1136 entries_sorted_(false), | |
1137 max_snapshot_js_object_id_(0) { | 1137 max_snapshot_js_object_id_(0) { |
1138 STATIC_CHECK( | 1138 STATIC_CHECK( |
1139 sizeof(HeapGraphEdge) == | 1139 sizeof(HeapGraphEdge) == |
1140 SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize); | 1140 SnapshotSizeConstants<kPointerSize>::kExpectedHeapGraphEdgeSize); |
1141 STATIC_CHECK( | 1141 STATIC_CHECK( |
1142 sizeof(HeapEntry) == | 1142 sizeof(HeapEntry) == |
1143 SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); | 1143 SnapshotSizeConstants<kPointerSize>::kExpectedHeapEntrySize); |
1144 for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { | 1144 for (int i = 0; i < VisitorSynchronization::kNumberOfSyncTags; ++i) { |
1145 gc_subroot_entries_[i] = NULL; | 1145 gc_subroot_entries_[i] = NULL; |
1146 } | 1146 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1178 } | 1178 } |
1179 | 1179 |
1180 | 1180 |
1181 void HeapSnapshot::ClearPaint() { | 1181 void HeapSnapshot::ClearPaint() { |
1182 entries_.Iterate(HeapEntryClearPaint); | 1182 entries_.Iterate(HeapEntryClearPaint); |
1183 } | 1183 } |
1184 | 1184 |
1185 | 1185 |
1186 HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { | 1186 HeapEntry* HeapSnapshot::AddRootEntry(int children_count) { |
1187 ASSERT(root_entry_ == NULL); | 1187 ASSERT(root_entry_ == NULL); |
| 1188 ASSERT(entries_.is_empty()); // Root entry must be the first one. |
1188 return (root_entry_ = AddEntry(HeapEntry::kObject, | 1189 return (root_entry_ = AddEntry(HeapEntry::kObject, |
1189 "", | 1190 "", |
1190 HeapObjectsMap::kInternalRootObjectId, | 1191 HeapObjectsMap::kInternalRootObjectId, |
1191 0, | 1192 0, |
1192 children_count, | 1193 children_count, |
1193 0)); | 1194 0)); |
1194 } | 1195 } |
1195 | 1196 |
1196 | 1197 |
1197 HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, | 1198 HeapEntry* HeapSnapshot::AddGcRootsEntry(int children_count, |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1278 | 1279 |
1279 template<class T> | 1280 template<class T> |
1280 static int SortByIds(const T* entry1_ptr, | 1281 static int SortByIds(const T* entry1_ptr, |
1281 const T* entry2_ptr) { | 1282 const T* entry2_ptr) { |
1282 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; | 1283 if ((*entry1_ptr)->id() == (*entry2_ptr)->id()) return 0; |
1283 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; | 1284 return (*entry1_ptr)->id() < (*entry2_ptr)->id() ? -1 : 1; |
1284 } | 1285 } |
1285 | 1286 |
1286 | 1287 |
1287 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { | 1288 List<HeapEntry*>* HeapSnapshot::GetSortedEntriesList() { |
1288 if (!entries_sorted_) { | 1289 if (sorted_entries_.is_empty()) { |
1289 entries_.Sort(SortByIds); | 1290 sorted_entries_.AddAll(entries_); |
1290 entries_sorted_ = true; | 1291 sorted_entries_.Sort(SortByIds); |
1291 } | 1292 } |
1292 return &entries_; | 1293 return &sorted_entries_; |
1293 } | 1294 } |
1294 | 1295 |
1295 | 1296 |
1296 void HeapSnapshot::Print(int max_depth) { | 1297 void HeapSnapshot::Print(int max_depth) { |
1297 root()->Print("", "", max_depth, 0); | 1298 root()->Print("", "", max_depth, 0); |
1298 } | 1299 } |
1299 | 1300 |
1300 | 1301 |
1301 // We split IDs on evens for embedder objects (see | 1302 // We split IDs on evens for embedder objects (see |
1302 // HeapObjectsMap::GenerateId) and odds for native objects. | 1303 // HeapObjectsMap::GenerateId) and odds for native objects. |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1507 } | 1508 } |
1508 | 1509 |
1509 | 1510 |
1510 HeapEntriesMap::~HeapEntriesMap() { | 1511 HeapEntriesMap::~HeapEntriesMap() { |
1511 for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { | 1512 for (HashMap::Entry* p = entries_.Start(); p != NULL; p = entries_.Next(p)) { |
1512 delete reinterpret_cast<EntryInfo*>(p->value); | 1513 delete reinterpret_cast<EntryInfo*>(p->value); |
1513 } | 1514 } |
1514 } | 1515 } |
1515 | 1516 |
1516 | 1517 |
1517 void HeapEntriesMap::AllocateEntries() { | 1518 void HeapEntriesMap::AllocateHeapEntryForMapEntry(HashMap::Entry* map_entry) { |
1518 for (HashMap::Entry* p = entries_.Start(); | 1519 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(map_entry->value); |
1519 p != NULL; | |
1520 p = entries_.Next(p)) { | |
1521 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(p->value); | |
1522 entry_info->entry = entry_info->allocator->AllocateEntry( | 1520 entry_info->entry = entry_info->allocator->AllocateEntry( |
1523 p->key, | 1521 map_entry->key, |
1524 entry_info->children_count, | 1522 entry_info->children_count, |
1525 entry_info->retainers_count); | 1523 entry_info->retainers_count); |
1526 ASSERT(entry_info->entry != NULL); | 1524 ASSERT(entry_info->entry != NULL); |
1527 ASSERT(entry_info->entry != kHeapEntryPlaceholder); | 1525 ASSERT(entry_info->entry != kHeapEntryPlaceholder); |
1528 entry_info->children_count = 0; | 1526 entry_info->children_count = 0; |
1529 entry_info->retainers_count = 0; | 1527 entry_info->retainers_count = 0; |
1530 } | |
1531 } | 1528 } |
1532 | 1529 |
1533 | 1530 |
| 1531 void HeapEntriesMap::AllocateEntries(HeapThing root_object) { |
| 1532 HashMap::Entry* root_entry = |
| 1533 entries_.Lookup(root_object, Hash(root_object), false); |
| 1534 ASSERT(root_entry != NULL); |
| 1535 // Make sure root entry is allocated first. |
| 1536 AllocateHeapEntryForMapEntry(root_entry); |
| 1537 void* root_entry_value = root_entry->value; |
| 1538 // Remove the root object from map while iterating through other entries. |
| 1539 entries_.Remove(root_object, Hash(root_object)); |
| 1540 root_entry = NULL; |
| 1541 |
| 1542 for (HashMap::Entry* p = entries_.Start(); |
| 1543 p != NULL; |
| 1544 p = entries_.Next(p)) { |
| 1545 AllocateHeapEntryForMapEntry(p); |
| 1546 } |
| 1547 |
| 1548 // Insert root entry back. |
| 1549 root_entry = entries_.Lookup(root_object, Hash(root_object), true); |
| 1550 root_entry->value = root_entry_value; |
| 1551 } |
| 1552 |
| 1553 |
1534 HeapEntry* HeapEntriesMap::Map(HeapThing thing) { | 1554 HeapEntry* HeapEntriesMap::Map(HeapThing thing) { |
1535 HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false); | 1555 HashMap::Entry* cache_entry = entries_.Lookup(thing, Hash(thing), false); |
1536 if (cache_entry != NULL) { | 1556 if (cache_entry != NULL) { |
1537 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); | 1557 EntryInfo* entry_info = reinterpret_cast<EntryInfo*>(cache_entry->value); |
1538 return entry_info->entry; | 1558 return entry_info->entry; |
1539 } else { | 1559 } else { |
1540 return NULL; | 1560 return NULL; |
1541 } | 1561 } |
1542 } | 1562 } |
1543 | 1563 |
(...skipping 1555 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3099 #ifdef DEBUG | 3119 #ifdef DEBUG |
3100 debug_heap->Verify(); | 3120 debug_heap->Verify(); |
3101 #endif | 3121 #endif |
3102 | 3122 |
3103 // Allocate memory for entries and references. | 3123 // Allocate memory for entries and references. |
3104 snapshot_->AllocateEntries(entries_.entries_count(), | 3124 snapshot_->AllocateEntries(entries_.entries_count(), |
3105 entries_.total_children_count(), | 3125 entries_.total_children_count(), |
3106 entries_.total_retainers_count()); | 3126 entries_.total_retainers_count()); |
3107 | 3127 |
3108 // Allocate heap objects to entries hash map. | 3128 // Allocate heap objects to entries hash map. |
3109 entries_.AllocateEntries(); | 3129 entries_.AllocateEntries(V8HeapExplorer::kInternalRootObject); |
3110 | 3130 |
3111 // Pass 2. Fill references. | 3131 // Pass 2. Fill references. |
3112 if (!FillReferences()) return false; | 3132 if (!FillReferences()) return false; |
3113 | 3133 |
3114 snapshot_->RememberLastJSObjectId(); | 3134 snapshot_->RememberLastJSObjectId(); |
3115 | 3135 |
3116 if (!SetEntriesDominators()) return false; | 3136 if (!SetEntriesDominators()) return false; |
3117 if (!CalculateRetainedSizes()) return false; | 3137 if (!CalculateRetainedSizes()) return false; |
3118 | 3138 |
3119 progress_counter_ = progress_total_; | 3139 progress_counter_ = progress_total_; |
(...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3410 | 3430 |
3411 HeapSnapshot* original_snapshot = NULL; | 3431 HeapSnapshot* original_snapshot = NULL; |
3412 if (snapshot_->raw_entries_size() >= | 3432 if (snapshot_->raw_entries_size() >= |
3413 SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) { | 3433 SnapshotSizeConstants<kPointerSize>::kMaxSerializableSnapshotRawSize) { |
3414 // The snapshot is too big. Serialize a fake snapshot. | 3434 // The snapshot is too big. Serialize a fake snapshot. |
3415 original_snapshot = snapshot_; | 3435 original_snapshot = snapshot_; |
3416 snapshot_ = CreateFakeSnapshot(); | 3436 snapshot_ = CreateFakeSnapshot(); |
3417 } | 3437 } |
3418 // Since nodes graph is cyclic, we need the first pass to enumerate | 3438 // Since nodes graph is cyclic, we need the first pass to enumerate |
3419 // them. Strings can be serialized in one pass. | 3439 // them. Strings can be serialized in one pass. |
3420 EnumerateNodes(); | |
3421 SerializeImpl(); | 3440 SerializeImpl(); |
3422 | 3441 |
3423 delete writer_; | 3442 delete writer_; |
3424 writer_ = NULL; | 3443 writer_ = NULL; |
3425 | 3444 |
3426 if (original_snapshot != NULL) { | 3445 if (original_snapshot != NULL) { |
3427 delete snapshot_; | 3446 delete snapshot_; |
3428 snapshot_ = original_snapshot; | 3447 snapshot_ = original_snapshot; |
3429 } | 3448 } |
3430 } | 3449 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3463 writer_->AddString("],\n"); | 3482 writer_->AddString("],\n"); |
3464 writer_->AddString("\"strings\":["); | 3483 writer_->AddString("\"strings\":["); |
3465 SerializeStrings(); | 3484 SerializeStrings(); |
3466 if (writer_->aborted()) return; | 3485 if (writer_->aborted()) return; |
3467 writer_->AddCharacter(']'); | 3486 writer_->AddCharacter(']'); |
3468 writer_->AddCharacter('}'); | 3487 writer_->AddCharacter('}'); |
3469 writer_->Finalize(); | 3488 writer_->Finalize(); |
3470 } | 3489 } |
3471 | 3490 |
3472 | 3491 |
3473 class HeapSnapshotJSONSerializerEnumerator { | |
3474 public: | |
3475 explicit HeapSnapshotJSONSerializerEnumerator(HeapSnapshotJSONSerializer* s) | |
3476 : s_(s) { | |
3477 } | |
3478 void Apply(HeapEntry** entry) { | |
3479 s_->GetNodeId(*entry); | |
3480 } | |
3481 private: | |
3482 HeapSnapshotJSONSerializer* s_; | |
3483 }; | |
3484 | |
3485 void HeapSnapshotJSONSerializer::EnumerateNodes() { | |
3486 GetNodeId(snapshot_->root()); // Make sure root gets the first id. | |
3487 HeapSnapshotJSONSerializerEnumerator iter(this); | |
3488 snapshot_->IterateEntries(&iter); | |
3489 } | |
3490 | |
3491 | |
3492 int HeapSnapshotJSONSerializer::GetNodeId(HeapEntry* entry) { | |
3493 HashMap::Entry* cache_entry = nodes_.Lookup(entry, ObjectHash(entry), true); | |
3494 if (cache_entry->value == NULL) { | |
3495 cache_entry->value = reinterpret_cast<void*>(next_node_id_++); | |
3496 } | |
3497 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); | |
3498 } | |
3499 | |
3500 | |
3501 int HeapSnapshotJSONSerializer::GetStringId(const char* s) { | 3492 int HeapSnapshotJSONSerializer::GetStringId(const char* s) { |
3502 HashMap::Entry* cache_entry = strings_.Lookup( | 3493 HashMap::Entry* cache_entry = strings_.Lookup( |
3503 const_cast<char*>(s), ObjectHash(s), true); | 3494 const_cast<char*>(s), ObjectHash(s), true); |
3504 if (cache_entry->value == NULL) { | 3495 if (cache_entry->value == NULL) { |
3505 cache_entry->value = reinterpret_cast<void*>(next_string_id_++); | 3496 cache_entry->value = reinterpret_cast<void*>(next_string_id_++); |
3506 } | 3497 } |
3507 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); | 3498 return static_cast<int>(reinterpret_cast<intptr_t>(cache_entry->value)); |
3508 } | 3499 } |
3509 | 3500 |
3510 | 3501 |
(...skipping 30 matching lines...) Expand all Loading... |
3541 int edge_name_or_index = edge->type() == HeapGraphEdge::kElement | 3532 int edge_name_or_index = edge->type() == HeapGraphEdge::kElement |
3542 || edge->type() == HeapGraphEdge::kHidden | 3533 || edge->type() == HeapGraphEdge::kHidden |
3543 || edge->type() == HeapGraphEdge::kWeak | 3534 || edge->type() == HeapGraphEdge::kWeak |
3544 ? edge->index() : GetStringId(edge->name()); | 3535 ? edge->index() : GetStringId(edge->name()); |
3545 int buffer_pos = 0; | 3536 int buffer_pos = 0; |
3546 buffer[buffer_pos++] = ','; | 3537 buffer[buffer_pos++] = ','; |
3547 buffer_pos = itoa(edge->type(), buffer, buffer_pos); | 3538 buffer_pos = itoa(edge->type(), buffer, buffer_pos); |
3548 buffer[buffer_pos++] = ','; | 3539 buffer[buffer_pos++] = ','; |
3549 buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos); | 3540 buffer_pos = itoa(edge_name_or_index, buffer, buffer_pos); |
3550 buffer[buffer_pos++] = ','; | 3541 buffer[buffer_pos++] = ','; |
3551 buffer_pos = itoa(GetNodeId(edge->to()), buffer, buffer_pos); | 3542 buffer_pos = itoa(edge->to()->entry_index(), buffer, buffer_pos); |
3552 buffer[buffer_pos++] = '\0'; | 3543 buffer[buffer_pos++] = '\0'; |
3553 writer_->AddString(buffer.start()); | 3544 writer_->AddString(buffer.start()); |
3554 } | 3545 } |
3555 | 3546 |
3556 | 3547 |
3557 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { | 3548 void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) { |
3558 // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 | 3549 // The buffer needs space for 6 ints, 1 uint32_t, 7 commas, \n and \0 |
3559 static const int kBufferSize = | 3550 static const int kBufferSize = |
3560 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT | 3551 6 * MaxDecimalDigitsIn<sizeof(int)>::kSigned // NOLINT |
3561 + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT | 3552 + MaxDecimalDigitsIn<sizeof(uint32_t)>::kUnsigned // NOLINT |
3562 + 7 + 1 + 1; | 3553 + 7 + 1 + 1; |
3563 EmbeddedVector<char, kBufferSize> buffer; | 3554 EmbeddedVector<char, kBufferSize> buffer; |
3564 Vector<HeapGraphEdge> children = entry->children(); | 3555 Vector<HeapGraphEdge> children = entry->children(); |
3565 int buffer_pos = 0; | 3556 int buffer_pos = 0; |
3566 buffer[buffer_pos++] = '\n'; | 3557 buffer[buffer_pos++] = '\n'; |
3567 buffer[buffer_pos++] = ','; | 3558 buffer[buffer_pos++] = ','; |
3568 buffer_pos = itoa(entry->type(), buffer, buffer_pos); | 3559 buffer_pos = itoa(entry->type(), buffer, buffer_pos); |
3569 buffer[buffer_pos++] = ','; | 3560 buffer[buffer_pos++] = ','; |
3570 buffer_pos = itoa(GetStringId(entry->name()), buffer, buffer_pos); | 3561 buffer_pos = itoa(GetStringId(entry->name()), buffer, buffer_pos); |
3571 buffer[buffer_pos++] = ','; | 3562 buffer[buffer_pos++] = ','; |
3572 buffer_pos = itoa(entry->id(), buffer, buffer_pos); | 3563 buffer_pos = itoa(entry->id(), buffer, buffer_pos); |
3573 buffer[buffer_pos++] = ','; | 3564 buffer[buffer_pos++] = ','; |
3574 buffer_pos = itoa(entry->self_size(), buffer, buffer_pos); | 3565 buffer_pos = itoa(entry->self_size(), buffer, buffer_pos); |
3575 buffer[buffer_pos++] = ','; | 3566 buffer[buffer_pos++] = ','; |
3576 buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos); | 3567 buffer_pos = itoa(entry->retained_size(), buffer, buffer_pos); |
3577 buffer[buffer_pos++] = ','; | 3568 buffer[buffer_pos++] = ','; |
3578 buffer_pos = itoa(GetNodeId(entry->dominator()), buffer, buffer_pos); | 3569 buffer_pos = itoa(entry->dominator()->entry_index(), buffer, buffer_pos); |
3579 buffer[buffer_pos++] = ','; | 3570 buffer[buffer_pos++] = ','; |
3580 buffer_pos = itoa(children.length(), buffer, buffer_pos); | 3571 buffer_pos = itoa(children.length(), buffer, buffer_pos); |
3581 buffer[buffer_pos++] = '\0'; | 3572 buffer[buffer_pos++] = '\0'; |
3582 writer_->AddString(buffer.start()); | 3573 writer_->AddString(buffer.start()); |
3583 for (int i = 0; i < children.length(); ++i) { | 3574 for (int i = 0; i < children.length(); ++i) { |
3584 SerializeEdge(&children[i]); | 3575 SerializeEdge(&children[i]); |
3585 if (writer_->aborted()) return; | 3576 if (writer_->aborted()) return; |
3586 } | 3577 } |
3587 } | 3578 } |
3588 | 3579 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3638 "," JSON_S("weak")) | 3629 "," JSON_S("weak")) |
3639 "," JSON_S("string_or_number") | 3630 "," JSON_S("string_or_number") |
3640 "," JSON_S("node")))))); | 3631 "," JSON_S("node")))))); |
3641 #undef JSON_S | 3632 #undef JSON_S |
3642 #undef JSON_O | 3633 #undef JSON_O |
3643 #undef JSON_A | 3634 #undef JSON_A |
3644 | 3635 |
3645 const int node_fields_count = 7; | 3636 const int node_fields_count = 7; |
3646 // type,name,id,self_size,retained_size,dominator,children_count. | 3637 // type,name,id,self_size,retained_size,dominator,children_count. |
3647 const int edge_fields_count = 3; // type,name|index,to_node. | 3638 const int edge_fields_count = 3; // type,name|index,to_node. |
3648 List<HashMap::Entry*> sorted_nodes; | 3639 |
3649 SortHashMap(&nodes_, &sorted_nodes); | 3640 List<HeapEntry*>& nodes = *(snapshot_->entries()); |
3650 // Rewrite node ids, so they refer to actual array positions. | 3641 // Root must be the first. |
3651 if (sorted_nodes.length() > 1) { | 3642 ASSERT(nodes.first() == snapshot_->root()); |
| 3643 // Rewrite node indexes, so they refer to actual array positions. Do this |
| 3644 // only once. |
| 3645 if (nodes[0]->entry_index() == -1) { |
3652 // Nodes start from array index 1. | 3646 // Nodes start from array index 1. |
3653 int prev_value = 1; | 3647 int index = 1; |
3654 sorted_nodes[0]->value = reinterpret_cast<void*>(prev_value); | 3648 for (int i = 0; i < nodes.length(); ++i) { |
3655 for (int i = 1; i < sorted_nodes.length(); ++i) { | 3649 HeapEntry* node = nodes[i]; |
3656 HeapEntry* prev_heap_entry = | 3650 node->set_entry_index(index); |
3657 reinterpret_cast<HeapEntry*>(sorted_nodes[i-1]->key); | 3651 index += node_fields_count + |
3658 prev_value += node_fields_count + | 3652 node->children().length() * edge_fields_count; |
3659 prev_heap_entry->children().length() * edge_fields_count; | |
3660 sorted_nodes[i]->value = reinterpret_cast<void*>(prev_value); | |
3661 } | 3653 } |
3662 } | 3654 } |
3663 for (int i = 0; i < sorted_nodes.length(); ++i) { | 3655 |
3664 SerializeNode(reinterpret_cast<HeapEntry*>(sorted_nodes[i]->key)); | 3656 for (int i = 0; i < nodes.length(); ++i) { |
| 3657 SerializeNode(nodes[i]); |
3665 if (writer_->aborted()) return; | 3658 if (writer_->aborted()) return; |
3666 } | 3659 } |
3667 } | 3660 } |
3668 | 3661 |
3669 | 3662 |
3670 void HeapSnapshotJSONSerializer::SerializeSnapshot() { | 3663 void HeapSnapshotJSONSerializer::SerializeSnapshot() { |
3671 writer_->AddString("\"title\":\""); | 3664 writer_->AddString("\"title\":\""); |
3672 writer_->AddString(snapshot_->title()); | 3665 writer_->AddString(snapshot_->title()); |
3673 writer_->AddString("\""); | 3666 writer_->AddString("\""); |
3674 writer_->AddString(",\"uid\":"); | 3667 writer_->AddString(",\"uid\":"); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3763 | 3756 |
3764 | 3757 |
3765 void HeapSnapshotJSONSerializer::SortHashMap( | 3758 void HeapSnapshotJSONSerializer::SortHashMap( |
3766 HashMap* map, List<HashMap::Entry*>* sorted_entries) { | 3759 HashMap* map, List<HashMap::Entry*>* sorted_entries) { |
3767 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) | 3760 for (HashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) |
3768 sorted_entries->Add(p); | 3761 sorted_entries->Add(p); |
3769 sorted_entries->Sort(SortUsingEntryValue); | 3762 sorted_entries->Sort(SortUsingEntryValue); |
3770 } | 3763 } |
3771 | 3764 |
3772 } } // namespace v8::internal | 3765 } } // namespace v8::internal |
OLD | NEW |