| 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 |