| 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 1368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1379 uint64_t id, | 1379 uint64_t id, |
| 1380 int size, | 1380 int size, |
| 1381 int children_count, | 1381 int children_count, |
| 1382 int retainers_count) { | 1382 int retainers_count) { |
| 1383 HeapEntry* entry = GetNextEntryToInit(); | 1383 HeapEntry* entry = GetNextEntryToInit(); |
| 1384 entry->Init(this, type, name, id, size, children_count, retainers_count); | 1384 entry->Init(this, type, name, id, size, children_count, retainers_count); |
| 1385 return entry; | 1385 return entry; |
| 1386 } | 1386 } |
| 1387 | 1387 |
| 1388 | 1388 |
| 1389 void HeapSnapshot::FillReversePostorderIndexes(Vector<HeapEntry*>* entries) { | |
| 1390 ClearPaint(); | |
| 1391 int current_entry = 0; | |
| 1392 List<HeapEntry*> nodes_to_visit; | |
| 1393 nodes_to_visit.Add(root()); | |
| 1394 root()->paint_reachable(); | |
| 1395 while (!nodes_to_visit.is_empty()) { | |
| 1396 HeapEntry* entry = nodes_to_visit.last(); | |
| 1397 Vector<HeapGraphEdge> children = entry->children(); | |
| 1398 bool has_new_edges = false; | |
| 1399 for (int i = 0; i < children.length(); ++i) { | |
| 1400 if (children[i].type() == HeapGraphEdge::kShortcut) continue; | |
| 1401 HeapEntry* child = children[i].to(); | |
| 1402 if (!child->painted_reachable()) { | |
| 1403 nodes_to_visit.Add(child); | |
| 1404 child->paint_reachable(); | |
| 1405 has_new_edges = true; | |
| 1406 } | |
| 1407 } | |
| 1408 if (!has_new_edges) { | |
| 1409 entry->set_ordered_index(current_entry); | |
| 1410 (*entries)[current_entry++] = entry; | |
| 1411 nodes_to_visit.RemoveLast(); | |
| 1412 } | |
| 1413 } | |
| 1414 entries->Truncate(current_entry); | |
| 1415 } | |
| 1416 | |
| 1417 | |
| 1418 static int Intersect(int i1, int i2, const Vector<HeapEntry*>& dominators) { | |
| 1419 int finger1 = i1, finger2 = i2; | |
| 1420 while (finger1 != finger2) { | |
| 1421 while (finger1 < finger2) finger1 = dominators[finger1]->ordered_index(); | |
| 1422 while (finger2 < finger1) finger2 = dominators[finger2]->ordered_index(); | |
| 1423 } | |
| 1424 return finger1; | |
| 1425 } | |
| 1426 | |
| 1427 // The algorithm is based on the article: | |
| 1428 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" | |
| 1429 // Softw. Pract. Exper. 4 (2001), pp. 1–10. | |
| 1430 void HeapSnapshot::BuildDominatorTree(const Vector<HeapEntry*>& entries, | |
| 1431 Vector<HeapEntry*>* dominators) { | |
| 1432 if (entries.length() == 0) return; | |
| 1433 const int root_index = entries.length() - 1; | |
| 1434 for (int i = 0; i < root_index; ++i) (*dominators)[i] = NULL; | |
| 1435 (*dominators)[root_index] = entries[root_index]; | |
| 1436 bool changed = true; | |
| 1437 while (changed) { | |
| 1438 changed = false; | |
| 1439 for (int i = root_index - 1; i >= 0; --i) { | |
| 1440 HeapEntry* new_idom = NULL; | |
| 1441 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); | |
| 1442 int j = 0; | |
| 1443 for (; j < rets.length(); ++j) { | |
| 1444 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; | |
| 1445 HeapEntry* ret = rets[j]->From(); | |
| 1446 if (dominators->at(ret->ordered_index()) != NULL) { | |
| 1447 new_idom = ret; | |
| 1448 break; | |
| 1449 } | |
| 1450 } | |
| 1451 for (++j; j < rets.length(); ++j) { | |
| 1452 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; | |
| 1453 HeapEntry* ret = rets[j]->From(); | |
| 1454 if (dominators->at(ret->ordered_index()) != NULL) { | |
| 1455 new_idom = entries[Intersect(ret->ordered_index(), | |
| 1456 new_idom->ordered_index(), | |
| 1457 *dominators)]; | |
| 1458 } | |
| 1459 } | |
| 1460 if (new_idom != NULL && dominators->at(i) != new_idom) { | |
| 1461 (*dominators)[i] = new_idom; | |
| 1462 changed = true; | |
| 1463 } | |
| 1464 } | |
| 1465 } | |
| 1466 } | |
| 1467 | |
| 1468 | |
| 1469 void HeapSnapshot::SetDominatorsToSelf() { | 1389 void HeapSnapshot::SetDominatorsToSelf() { |
| 1470 for (int i = 0; i < entries_.length(); ++i) { | 1390 for (int i = 0; i < entries_.length(); ++i) { |
| 1471 HeapEntry* entry = entries_[i]; | 1391 HeapEntry* entry = entries_[i]; |
| 1472 if (entry->dominator() == NULL) entry->set_dominator(entry); | 1392 if (entry->dominator() == NULL) entry->set_dominator(entry); |
| 1473 } | 1393 } |
| 1474 } | 1394 } |
| 1475 | 1395 |
| 1476 | 1396 |
| 1477 void HeapSnapshot::SetEntriesDominators() { | |
| 1478 // This array is used for maintaining reverse postorder of nodes. | |
| 1479 ScopedVector<HeapEntry*> ordered_entries(entries_.length()); | |
| 1480 FillReversePostorderIndexes(&ordered_entries); | |
| 1481 ScopedVector<HeapEntry*> dominators(ordered_entries.length()); | |
| 1482 BuildDominatorTree(ordered_entries, &dominators); | |
| 1483 for (int i = 0; i < ordered_entries.length(); ++i) { | |
| 1484 ASSERT(dominators[i] != NULL); | |
| 1485 ordered_entries[i]->set_dominator(dominators[i]); | |
| 1486 } | |
| 1487 // For nodes unreachable from root, set dominator to itself. | |
| 1488 SetDominatorsToSelf(); | |
| 1489 } | |
| 1490 | |
| 1491 | |
| 1492 void HeapSnapshot::ApproximateRetainedSizes() { | |
| 1493 SetEntriesDominators(); | |
| 1494 // As for the dominators tree we only know parent nodes, not | |
| 1495 // children, to sum up total sizes we traverse the tree level by | |
| 1496 // level upwards, starting from leaves. | |
| 1497 for (int i = 0; i < entries_.length(); ++i) { | |
| 1498 HeapEntry* entry = entries_[i]; | |
| 1499 entry->set_retained_size(entry->self_size()); | |
| 1500 entry->set_leaf(); | |
| 1501 } | |
| 1502 while (true) { | |
| 1503 bool onlyLeaves = true; | |
| 1504 for (int i = 0; i < entries_.length(); ++i) { | |
| 1505 HeapEntry *entry = entries_[i], *dominator = entry->dominator(); | |
| 1506 if (!entry->is_processed() && dominator != entry) { | |
| 1507 dominator->set_non_leaf(); | |
| 1508 onlyLeaves = false; | |
| 1509 } | |
| 1510 } | |
| 1511 if (onlyLeaves) break; | |
| 1512 | |
| 1513 for (int i = 0; i < entries_.length(); ++i) { | |
| 1514 HeapEntry *entry = entries_[i], *dominator = entry->dominator(); | |
| 1515 if (entry->is_leaf() && dominator != entry) { | |
| 1516 dominator->add_retained_size(entry->retained_size()); | |
| 1517 } | |
| 1518 } | |
| 1519 | |
| 1520 // Mark all current leaves as processed, reset non-leaves back to leaves. | |
| 1521 for (int i = 0; i < entries_.length(); ++i) { | |
| 1522 HeapEntry* entry = entries_[i]; | |
| 1523 if (entry->is_leaf()) | |
| 1524 entry->set_processed(); | |
| 1525 else if (entry->is_non_leaf()) | |
| 1526 entry->set_leaf(); | |
| 1527 } | |
| 1528 } | |
| 1529 } | |
| 1530 | |
| 1531 | |
| 1532 HeapEntry* HeapSnapshot::GetNextEntryToInit() { | 1397 HeapEntry* HeapSnapshot::GetNextEntryToInit() { |
| 1533 if (entries_.length() > 0) { | 1398 if (entries_.length() > 0) { |
| 1534 HeapEntry* last_entry = entries_.last(); | 1399 HeapEntry* last_entry = entries_.last(); |
| 1535 entries_.Add(reinterpret_cast<HeapEntry*>( | 1400 entries_.Add(reinterpret_cast<HeapEntry*>( |
| 1536 reinterpret_cast<char*>(last_entry) + last_entry->EntrySize())); | 1401 reinterpret_cast<char*>(last_entry) + last_entry->EntrySize())); |
| 1537 } else { | 1402 } else { |
| 1538 entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_)); | 1403 entries_.Add(reinterpret_cast<HeapEntry*>(raw_entries_)); |
| 1539 } | 1404 } |
| 1540 ASSERT(reinterpret_cast<char*>(entries_.last()) < | 1405 ASSERT(reinterpret_cast<char*>(entries_.last()) < |
| 1541 (raw_entries_ + raw_entries_size_)); | 1406 (raw_entries_ + raw_entries_size_)); |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1713 HeapSnapshotsCollection::~HeapSnapshotsCollection() { | 1578 HeapSnapshotsCollection::~HeapSnapshotsCollection() { |
| 1714 delete token_enumerator_; | 1579 delete token_enumerator_; |
| 1715 snapshots_.Iterate(DeleteHeapSnapshot); | 1580 snapshots_.Iterate(DeleteHeapSnapshot); |
| 1716 } | 1581 } |
| 1717 | 1582 |
| 1718 | 1583 |
| 1719 HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(HeapSnapshot::Type type, | 1584 HeapSnapshot* HeapSnapshotsCollection::NewSnapshot(HeapSnapshot::Type type, |
| 1720 const char* name, | 1585 const char* name, |
| 1721 unsigned uid) { | 1586 unsigned uid) { |
| 1722 is_tracking_objects_ = true; // Start watching for heap objects moves. | 1587 is_tracking_objects_ = true; // Start watching for heap objects moves. |
| 1723 HeapSnapshot* snapshot = new HeapSnapshot(this, type, name, uid); | 1588 return new HeapSnapshot(this, type, name, uid); |
| 1724 snapshots_.Add(snapshot); | 1589 } |
| 1725 HashMap::Entry* entry = | 1590 |
| 1726 snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()), | 1591 |
| 1727 static_cast<uint32_t>(snapshot->uid()), | 1592 void HeapSnapshotsCollection::SnapshotGenerationFinished( |
| 1728 true); | 1593 HeapSnapshot* snapshot) { |
| 1729 ASSERT(entry->value == NULL); | 1594 ids_.SnapshotGenerationFinished(); |
| 1730 entry->value = snapshot; | 1595 if (snapshot != NULL) { |
| 1731 return snapshot; | 1596 snapshots_.Add(snapshot); |
| 1597 HashMap::Entry* entry = |
| 1598 snapshots_uids_.Lookup(reinterpret_cast<void*>(snapshot->uid()), |
| 1599 static_cast<uint32_t>(snapshot->uid()), |
| 1600 true); |
| 1601 ASSERT(entry->value == NULL); |
| 1602 entry->value = snapshot; |
| 1603 } |
| 1732 } | 1604 } |
| 1733 | 1605 |
| 1734 | 1606 |
| 1735 HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) { | 1607 HeapSnapshot* HeapSnapshotsCollection::GetSnapshot(unsigned uid) { |
| 1736 HashMap::Entry* entry = snapshots_uids_.Lookup(reinterpret_cast<void*>(uid), | 1608 HashMap::Entry* entry = snapshots_uids_.Lookup(reinterpret_cast<void*>(uid), |
| 1737 static_cast<uint32_t>(uid), | 1609 static_cast<uint32_t>(uid), |
| 1738 false); | 1610 false); |
| 1739 return entry != NULL ? reinterpret_cast<HeapSnapshot*>(entry->value) : NULL; | 1611 return entry != NULL ? reinterpret_cast<HeapSnapshot*>(entry->value) : NULL; |
| 1740 } | 1612 } |
| 1741 | 1613 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1829 if (!obj->IsHeapObject()) return; | 1701 if (!obj->IsHeapObject()) return; |
| 1830 HeapObject* object = HeapObject::cast(obj); | 1702 HeapObject* object = HeapObject::cast(obj); |
| 1831 HashMap::Entry* cache_entry = | 1703 HashMap::Entry* cache_entry = |
| 1832 entries_.Lookup(object, HeapEntriesMap::Hash(object), true); | 1704 entries_.Lookup(object, HeapEntriesMap::Hash(object), true); |
| 1833 if (cache_entry->value == NULL) { | 1705 if (cache_entry->value == NULL) { |
| 1834 cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; | 1706 cache_entry->value = HeapEntriesMap::kHeapEntryPlaceholder; |
| 1835 } | 1707 } |
| 1836 } | 1708 } |
| 1837 | 1709 |
| 1838 | 1710 |
| 1839 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot) | 1711 HeapSnapshotGenerator::HeapSnapshotGenerator(HeapSnapshot* snapshot, |
| 1712 v8::ActivityControl* control) |
| 1840 : snapshot_(snapshot), | 1713 : snapshot_(snapshot), |
| 1714 control_(control), |
| 1841 collection_(snapshot->collection()), | 1715 collection_(snapshot->collection()), |
| 1842 filler_(NULL) { | 1716 filler_(NULL) { |
| 1843 } | 1717 } |
| 1844 | 1718 |
| 1845 class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface { | 1719 class SnapshotCounter : public HeapSnapshotGenerator::SnapshotFillerInterface { |
| 1846 public: | 1720 public: |
| 1847 explicit SnapshotCounter(HeapEntriesMap* entries) | 1721 explicit SnapshotCounter(HeapEntriesMap* entries) |
| 1848 : entries_(entries) { } | 1722 : entries_(entries) { } |
| 1849 HeapEntry* AddEntry(HeapObject* obj) { | 1723 HeapEntry* AddEntry(HeapObject* obj) { |
| 1850 entries_->Pair(obj, HeapEntriesMap::kHeapEntryPlaceholder); | 1724 entries_->Pair(obj, HeapEntriesMap::kHeapEntryPlaceholder); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1987 : generator_(generator) { | 1861 : generator_(generator) { |
| 1988 } | 1862 } |
| 1989 void VisitPointers(Object** start, Object** end) { | 1863 void VisitPointers(Object** start, Object** end) { |
| 1990 for (Object** p = start; p < end; p++) generator_->SetGcRootsReference(*p); | 1864 for (Object** p = start; p < end; p++) generator_->SetGcRootsReference(*p); |
| 1991 } | 1865 } |
| 1992 private: | 1866 private: |
| 1993 HeapSnapshotGenerator* generator_; | 1867 HeapSnapshotGenerator* generator_; |
| 1994 }; | 1868 }; |
| 1995 | 1869 |
| 1996 | 1870 |
| 1997 void HeapSnapshotGenerator::GenerateSnapshot() { | 1871 bool HeapSnapshotGenerator::GenerateSnapshot() { |
| 1998 AssertNoAllocation no_alloc; | 1872 AssertNoAllocation no_alloc; |
| 1999 | 1873 |
| 1874 SetProgressTotal(4); // 2 passes + dominators + sizes. |
| 1875 |
| 2000 // Pass 1. Iterate heap contents to count entries and references. | 1876 // Pass 1. Iterate heap contents to count entries and references. |
| 2001 SnapshotCounter counter(&entries_); | 1877 if (!CountEntriesAndReferences()) return false; |
| 2002 filler_ = &counter; | |
| 2003 filler_->AddEntry(HeapSnapshot::kInternalRootObject); | |
| 2004 filler_->AddEntry(HeapSnapshot::kGcRootsObject); | |
| 2005 HeapIterator iterator(HeapIterator::kPreciseFiltering); | |
| 2006 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | |
| 2007 ExtractReferences(obj); | |
| 2008 } | |
| 2009 SetRootGcRootsReference(); | |
| 2010 RootsReferencesExtractor extractor(this); | |
| 2011 HEAP->IterateRoots(&extractor, VISIT_ONLY_STRONG); | |
| 2012 | 1878 |
| 2013 // Allocate and fill entries in the snapshot, allocate references. | 1879 // Allocate and fill entries in the snapshot, allocate references. |
| 2014 snapshot_->AllocateEntries(entries_.entries_count(), | 1880 snapshot_->AllocateEntries(entries_.entries_count(), |
| 2015 entries_.total_children_count(), | 1881 entries_.total_children_count(), |
| 2016 entries_.total_retainers_count()); | 1882 entries_.total_retainers_count()); |
| 2017 SnapshotAllocator allocator(snapshot_); | 1883 SnapshotAllocator allocator(snapshot_); |
| 2018 entries_.UpdateEntries(&allocator); | 1884 entries_.UpdateEntries(&allocator); |
| 2019 | 1885 |
| 2020 // Pass 2. Fill references. | 1886 // Pass 2. Fill references. |
| 2021 SnapshotFiller filler(snapshot_, &entries_); | 1887 if (!FillReferences()) return false; |
| 2022 filler_ = &filler; | |
| 2023 iterator.reset(); | |
| 2024 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | |
| 2025 ExtractReferences(obj); | |
| 2026 } | |
| 2027 SetRootGcRootsReference(); | |
| 2028 HEAP->IterateRoots(&extractor, VISIT_ONLY_STRONG); | |
| 2029 | 1888 |
| 2030 snapshot_->ApproximateRetainedSizes(); | 1889 if (!SetEntriesDominators()) return false; |
| 1890 if (!ApproximateRetainedSizes()) return false; |
| 1891 |
| 1892 progress_counter_ = progress_total_; |
| 1893 if (!ReportProgress(true)) return false; |
| 1894 return true; |
| 2031 } | 1895 } |
| 2032 | 1896 |
| 2033 | 1897 |
| 2034 HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) { | 1898 HeapEntry* HeapSnapshotGenerator::GetEntry(Object* obj) { |
| 2035 if (!obj->IsHeapObject()) return NULL; | 1899 if (!obj->IsHeapObject()) return NULL; |
| 2036 HeapObject* object = HeapObject::cast(obj); | 1900 HeapObject* object = HeapObject::cast(obj); |
| 2037 HeapEntry* entry = entries_.Map(object); | 1901 HeapEntry* entry = entries_.Map(object); |
| 2038 // A new entry. | 1902 // A new entry. |
| 2039 if (entry == NULL) entry = filler_->AddEntry(object); | 1903 if (entry == NULL) entry = filler_->AddEntry(object); |
| 2040 return entry; | 1904 return entry; |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2348 | 2212 |
| 2349 | 2213 |
| 2350 void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) { | 2214 void HeapSnapshotGenerator::SetGcRootsReference(Object* child_obj) { |
| 2351 HeapEntry* child_entry = GetEntry(child_obj); | 2215 HeapEntry* child_entry = GetEntry(child_obj); |
| 2352 if (child_entry != NULL) { | 2216 if (child_entry != NULL) { |
| 2353 filler_->SetStrongRootReference(child_obj, child_entry); | 2217 filler_->SetStrongRootReference(child_obj, child_entry); |
| 2354 } | 2218 } |
| 2355 } | 2219 } |
| 2356 | 2220 |
| 2357 | 2221 |
| 2222 void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) { |
| 2223 if (control_ == NULL) return; |
| 2224 |
| 2225 HeapIterator iterator(HeapIterator::kFilterUnreachable); |
| 2226 int objects_count = 0; |
| 2227 for (HeapObject* obj = iterator.next(); |
| 2228 obj != NULL; |
| 2229 obj = iterator.next(), ++objects_count) {} |
| 2230 progress_total_ = objects_count * iterations_count; |
| 2231 progress_counter_ = 0; |
| 2232 } |
| 2233 |
| 2234 |
| 2235 bool HeapSnapshotGenerator::CountEntriesAndReferences() { |
| 2236 SnapshotCounter counter(&entries_); |
| 2237 filler_ = &counter; |
| 2238 filler_->AddEntry(HeapSnapshot::kInternalRootObject); |
| 2239 filler_->AddEntry(HeapSnapshot::kGcRootsObject); |
| 2240 return IterateAndExtractReferences(); |
| 2241 } |
| 2242 |
| 2243 |
| 2244 bool HeapSnapshotGenerator::FillReferences() { |
| 2245 SnapshotFiller filler(snapshot_, &entries_); |
| 2246 filler_ = &filler; |
| 2247 return IterateAndExtractReferences(); |
| 2248 } |
| 2249 |
| 2250 |
| 2251 void HeapSnapshotGenerator::FillReversePostorderIndexes( |
| 2252 Vector<HeapEntry*>* entries) { |
| 2253 snapshot_->ClearPaint(); |
| 2254 int current_entry = 0; |
| 2255 List<HeapEntry*> nodes_to_visit; |
| 2256 nodes_to_visit.Add(snapshot_->root()); |
| 2257 snapshot_->root()->paint_reachable(); |
| 2258 while (!nodes_to_visit.is_empty()) { |
| 2259 HeapEntry* entry = nodes_to_visit.last(); |
| 2260 Vector<HeapGraphEdge> children = entry->children(); |
| 2261 bool has_new_edges = false; |
| 2262 for (int i = 0; i < children.length(); ++i) { |
| 2263 if (children[i].type() == HeapGraphEdge::kShortcut) continue; |
| 2264 HeapEntry* child = children[i].to(); |
| 2265 if (!child->painted_reachable()) { |
| 2266 nodes_to_visit.Add(child); |
| 2267 child->paint_reachable(); |
| 2268 has_new_edges = true; |
| 2269 } |
| 2270 } |
| 2271 if (!has_new_edges) { |
| 2272 entry->set_ordered_index(current_entry); |
| 2273 (*entries)[current_entry++] = entry; |
| 2274 nodes_to_visit.RemoveLast(); |
| 2275 } |
| 2276 } |
| 2277 entries->Truncate(current_entry); |
| 2278 } |
| 2279 |
| 2280 |
| 2281 static int Intersect(int i1, int i2, const Vector<HeapEntry*>& dominators) { |
| 2282 int finger1 = i1, finger2 = i2; |
| 2283 while (finger1 != finger2) { |
| 2284 while (finger1 < finger2) finger1 = dominators[finger1]->ordered_index(); |
| 2285 while (finger2 < finger1) finger2 = dominators[finger2]->ordered_index(); |
| 2286 } |
| 2287 return finger1; |
| 2288 } |
| 2289 |
| 2290 // The algorithm is based on the article: |
| 2291 // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" |
| 2292 // Softw. Pract. Exper. 4 (2001), pp. 1–10. |
| 2293 bool HeapSnapshotGenerator::BuildDominatorTree( |
| 2294 const Vector<HeapEntry*>& entries, |
| 2295 Vector<HeapEntry*>* dominators) { |
| 2296 if (entries.length() == 0) return true; |
| 2297 const int entries_length = entries.length(), root_index = entries_length - 1; |
| 2298 for (int i = 0; i < root_index; ++i) (*dominators)[i] = NULL; |
| 2299 (*dominators)[root_index] = entries[root_index]; |
| 2300 int changed = 1; |
| 2301 const int base_progress_counter = progress_counter_; |
| 2302 while (changed != 0) { |
| 2303 changed = 0; |
| 2304 for (int i = root_index - 1; i >= 0; --i) { |
| 2305 HeapEntry* new_idom = NULL; |
| 2306 Vector<HeapGraphEdge*> rets = entries[i]->retainers(); |
| 2307 int j = 0; |
| 2308 for (; j < rets.length(); ++j) { |
| 2309 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; |
| 2310 HeapEntry* ret = rets[j]->From(); |
| 2311 if (dominators->at(ret->ordered_index()) != NULL) { |
| 2312 new_idom = ret; |
| 2313 break; |
| 2314 } |
| 2315 } |
| 2316 for (++j; j < rets.length(); ++j) { |
| 2317 if (rets[j]->type() == HeapGraphEdge::kShortcut) continue; |
| 2318 HeapEntry* ret = rets[j]->From(); |
| 2319 if (dominators->at(ret->ordered_index()) != NULL) { |
| 2320 new_idom = entries[Intersect(ret->ordered_index(), |
| 2321 new_idom->ordered_index(), |
| 2322 *dominators)]; |
| 2323 } |
| 2324 } |
| 2325 if (new_idom != NULL && dominators->at(i) != new_idom) { |
| 2326 (*dominators)[i] = new_idom; |
| 2327 ++changed; |
| 2328 } |
| 2329 } |
| 2330 int remaining = entries_length - changed; |
| 2331 if (remaining < 0) remaining = 0; |
| 2332 progress_counter_ = base_progress_counter + remaining; |
| 2333 if (!ReportProgress(true)) return false; |
| 2334 } |
| 2335 return true; |
| 2336 } |
| 2337 |
| 2338 |
| 2339 bool HeapSnapshotGenerator::SetEntriesDominators() { |
| 2340 // This array is used for maintaining reverse postorder of nodes. |
| 2341 ScopedVector<HeapEntry*> ordered_entries(snapshot_->entries()->length()); |
| 2342 FillReversePostorderIndexes(&ordered_entries); |
| 2343 ScopedVector<HeapEntry*> dominators(ordered_entries.length()); |
| 2344 if (!BuildDominatorTree(ordered_entries, &dominators)) return false; |
| 2345 for (int i = 0; i < ordered_entries.length(); ++i) { |
| 2346 ASSERT(dominators[i] != NULL); |
| 2347 ordered_entries[i]->set_dominator(dominators[i]); |
| 2348 } |
| 2349 return true; |
| 2350 } |
| 2351 |
| 2352 |
| 2353 bool HeapSnapshotGenerator::ApproximateRetainedSizes() { |
| 2354 // As for the dominators tree we only know parent nodes, not |
| 2355 // children, to sum up total sizes we "bubble" node's self size |
| 2356 // adding it to all of its parents. |
| 2357 for (int i = 0; i < snapshot_->entries()->length(); ++i) { |
| 2358 HeapEntry* entry = snapshot_->entries()->at(i); |
| 2359 entry->set_retained_size(entry->self_size()); |
| 2360 } |
| 2361 for (int i = 0; |
| 2362 i < snapshot_->entries()->length(); |
| 2363 ++i, IncProgressCounter()) { |
| 2364 HeapEntry* entry = snapshot_->entries()->at(i); |
| 2365 int entry_size = entry->self_size(); |
| 2366 for (HeapEntry* dominator = entry->dominator(); |
| 2367 dominator != entry; |
| 2368 entry = dominator, dominator = entry->dominator()) { |
| 2369 dominator->add_retained_size(entry_size); |
| 2370 } |
| 2371 if (!ReportProgress()) return false; |
| 2372 } |
| 2373 return true; |
| 2374 } |
| 2375 |
| 2376 |
| 2377 bool HeapSnapshotGenerator::IterateAndExtractReferences() { |
| 2378 HeapIterator iterator(HeapIterator::kFilterUnreachable); |
| 2379 bool interrupted = false; |
| 2380 // Heap iteration with filtering must be finished in any case. |
| 2381 for (HeapObject* obj = iterator.next(); |
| 2382 obj != NULL; |
| 2383 obj = iterator.next(), IncProgressCounter()) { |
| 2384 if (!interrupted) { |
| 2385 ExtractReferences(obj); |
| 2386 if (!ReportProgress()) interrupted = true; |
| 2387 } |
| 2388 } |
| 2389 if (interrupted) return false; |
| 2390 SetRootGcRootsReference(); |
| 2391 RootsReferencesExtractor extractor(this); |
| 2392 HEAP->IterateRoots(&extractor, VISIT_ONLY_STRONG); |
| 2393 return ReportProgress(); |
| 2394 } |
| 2395 |
| 2396 |
| 2358 void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { | 2397 void HeapSnapshotsDiff::CreateRoots(int additions_count, int deletions_count) { |
| 2359 raw_additions_root_ = | 2398 raw_additions_root_ = |
| 2360 NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); | 2399 NewArray<char>(HeapEntry::EntriesSize(1, additions_count, 0)); |
| 2361 additions_root()->Init( | 2400 additions_root()->Init( |
| 2362 snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0); | 2401 snapshot2_, HeapEntry::kHidden, "", 0, 0, additions_count, 0); |
| 2363 raw_deletions_root_ = | 2402 raw_deletions_root_ = |
| 2364 NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0)); | 2403 NewArray<char>(HeapEntry::EntriesSize(1, deletions_count, 0)); |
| 2365 deletions_root()->Init( | 2404 deletions_root()->Init( |
| 2366 snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0); | 2405 snapshot1_, HeapEntry::kHidden, "", 0, 0, deletions_count, 0); |
| 2367 } | 2406 } |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2798 | 2837 |
| 2799 | 2838 |
| 2800 String* GetConstructorNameForHeapProfile(JSObject* object) { | 2839 String* GetConstructorNameForHeapProfile(JSObject* object) { |
| 2801 if (object->IsJSFunction()) return HEAP->closure_symbol(); | 2840 if (object->IsJSFunction()) return HEAP->closure_symbol(); |
| 2802 return object->constructor_name(); | 2841 return object->constructor_name(); |
| 2803 } | 2842 } |
| 2804 | 2843 |
| 2805 } } // namespace v8::internal | 2844 } } // namespace v8::internal |
| 2806 | 2845 |
| 2807 #endif // ENABLE_LOGGING_AND_PROFILING | 2846 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |