Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(268)

Side by Side Diff: src/heap/mark-compact.cc

Issue 2796233003: [heap] Evacuation for young generation (Closed)
Patch Set: Fix recording Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/heap/mark-compact.h" 5 #include "src/heap/mark-compact.h"
6 6
7 #include "src/base/atomicops.h" 7 #include "src/base/atomicops.h"
8 #include "src/base/bits.h" 8 #include "src/base/bits.h"
9 #include "src/base/sys-info.h" 9 #include "src/base/sys-info.h"
10 #include "src/code-stubs.h" 10 #include "src/code-stubs.h"
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
203 CHECK(ObjectMarking::IsBlackOrGrey(object, marking_state(object))); 203 CHECK(ObjectMarking::IsBlackOrGrey(object, marking_state(object)));
204 } 204 }
205 } 205 }
206 } 206 }
207 }; 207 };
208 208
209 class EvacuationVerifier : public ObjectVisitor { 209 class EvacuationVerifier : public ObjectVisitor {
210 public: 210 public:
211 virtual void Run() = 0; 211 virtual void Run() = 0;
212 212
213 void VisitPointers(Object** start, Object** end) override {
214 for (Object** current = start; current < end; current++) {
215 if ((*current)->IsHeapObject()) {
216 HeapObject* object = HeapObject::cast(*current);
217 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object));
218 }
219 }
220 }
221
222 protected: 213 protected:
223 explicit EvacuationVerifier(Heap* heap) : heap_(heap) {} 214 explicit EvacuationVerifier(Heap* heap) : heap_(heap) {}
224 215
225 void VerifyRoots(VisitMode mode); 216 void VerifyRoots(VisitMode mode);
226 void VerifyEvacuationOnPage(Address start, Address end); 217 void VerifyEvacuationOnPage(Address start, Address end);
227 void VerifyEvacuation(NewSpace* new_space); 218 void VerifyEvacuation(NewSpace* new_space);
228 void VerifyEvacuation(PagedSpace* paged_space); 219 void VerifyEvacuation(PagedSpace* paged_space);
229 220
230 Heap* heap_; 221 Heap* heap_;
231 }; 222 };
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 public: 261 public:
271 explicit FullEvacuationVerifier(Heap* heap) : EvacuationVerifier(heap) {} 262 explicit FullEvacuationVerifier(Heap* heap) : EvacuationVerifier(heap) {}
272 263
273 void Run() override { 264 void Run() override {
274 VerifyRoots(VISIT_ALL); 265 VerifyRoots(VISIT_ALL);
275 VerifyEvacuation(heap_->new_space()); 266 VerifyEvacuation(heap_->new_space());
276 VerifyEvacuation(heap_->old_space()); 267 VerifyEvacuation(heap_->old_space());
277 VerifyEvacuation(heap_->code_space()); 268 VerifyEvacuation(heap_->code_space());
278 VerifyEvacuation(heap_->map_space()); 269 VerifyEvacuation(heap_->map_space());
279 } 270 }
271
272 void VisitPointers(Object** start, Object** end) override {
273 for (Object** current = start; current < end; current++) {
274 if ((*current)->IsHeapObject()) {
275 HeapObject* object = HeapObject::cast(*current);
276 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object));
277 }
278 }
279 }
280 };
281
282 class YoungGenerationEvacuationVerifier : public EvacuationVerifier {
283 public:
284 explicit YoungGenerationEvacuationVerifier(Heap* heap)
285 : EvacuationVerifier(heap) {}
286
287 void Run() override {
288 VerifyRoots(VISIT_ALL_IN_SCAVENGE);
289 VerifyEvacuation(heap_->new_space());
290 }
291
292 void VisitPointers(Object** start, Object** end) override {
293 for (Object** current = start; current < end; current++) {
294 if ((*current)->IsHeapObject()) {
295 HeapObject* object = HeapObject::cast(*current);
296 if (!heap_->InNewSpace(object)) return;
297 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object));
298 }
299 }
300 }
280 }; 301 };
281 302
282 } // namespace 303 } // namespace
283 #endif // VERIFY_HEAP 304 #endif // VERIFY_HEAP
284 305
285 // ============================================================================= 306 // =============================================================================
286 // MarkCompactCollector 307 // MarkCompactCollector
287 // ============================================================================= 308 // =============================================================================
288 309
289 MarkCompactCollector::MarkCompactCollector(Heap* heap) 310 MarkCompactCollector::MarkCompactCollector(Heap* heap)
(...skipping 1251 matching lines...) Expand 10 before | Expand all | Expand 10 after
1541 1562
1542 private: 1563 private:
1543 Heap* heap_; 1564 Heap* heap_;
1544 int pointers_removed_; 1565 int pointers_removed_;
1545 HeapObject* table_; 1566 HeapObject* table_;
1546 }; 1567 };
1547 1568
1548 typedef StringTableCleaner<false, true> InternalizedStringTableCleaner; 1569 typedef StringTableCleaner<false, true> InternalizedStringTableCleaner;
1549 typedef StringTableCleaner<true, false> ExternalStringTableCleaner; 1570 typedef StringTableCleaner<true, false> ExternalStringTableCleaner;
1550 1571
1572 // Helper class for pruning the string table.
1573 class YoungGenerationExternalStringTableCleaner : public ObjectVisitor {
1574 public:
1575 YoungGenerationExternalStringTableCleaner(
1576 const MinorMarkCompactCollector& collector)
1577 : heap_(collector.heap()), collector_(collector) {}
1578
1579 void VisitPointers(Object** start, Object** end) override {
1580 // Visit all HeapObject pointers in [start, end).
1581 for (Object** p = start; p < end; p++) {
1582 Object* o = *p;
1583 if (o->IsHeapObject()) {
1584 HeapObject* heap_object = HeapObject::cast(o);
1585 if (ObjectMarking::IsWhite(heap_object,
1586 collector_.marking_state(heap_object))) {
1587 if (o->IsExternalString()) {
1588 heap_->FinalizeExternalString(String::cast(*p));
1589 } else {
1590 // The original external string may have been internalized.
1591 DCHECK(o->IsThinString());
1592 }
1593 // Set the entry to the_hole_value (as deleted).
1594 *p = heap_->the_hole_value();
1595 }
1596 }
1597 }
1598 }
1599
1600 private:
1601 Heap* heap_;
1602 const MinorMarkCompactCollector& collector_;
1603 };
1604
1605 // Marked young generation objects and all old generation objects will be
1606 // retained.
1607 class MinorMarkCompactWeakObjectRetainer : public WeakObjectRetainer {
1608 public:
1609 explicit MinorMarkCompactWeakObjectRetainer(
1610 const MinorMarkCompactCollector& collector)
1611 : collector_(collector) {}
1612
1613 virtual Object* RetainAs(Object* object) {
1614 HeapObject* heap_object = HeapObject::cast(object);
1615 if (!collector_.heap()->InNewSpace(heap_object)) return object;
1616
1617 DCHECK(!ObjectMarking::IsGrey(heap_object,
1618 MarkingState::External(heap_object)));
1619 if (ObjectMarking::IsBlack(heap_object,
1620 collector_.marking_state(heap_object))) {
1621 return object;
1622 }
1623 return nullptr;
1624 }
1625
1626 private:
1627 const MinorMarkCompactCollector& collector_;
1628 };
1629
1551 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects 1630 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects
1552 // are retained. 1631 // are retained.
1553 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { 1632 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer {
1554 public: 1633 public:
1555 virtual Object* RetainAs(Object* object) { 1634 virtual Object* RetainAs(Object* object) {
1556 HeapObject* heap_object = HeapObject::cast(object); 1635 HeapObject* heap_object = HeapObject::cast(object);
1557 DCHECK(!ObjectMarking::IsGrey(heap_object, 1636 DCHECK(!ObjectMarking::IsGrey(heap_object,
1558 MarkingState::Internal(heap_object))); 1637 MarkingState::Internal(heap_object)));
1559 if (ObjectMarking::IsBlack(heap_object, 1638 if (ObjectMarking::IsBlack(heap_object,
1560 MarkingState::Internal(heap_object))) { 1639 MarkingState::Internal(heap_object))) {
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1599 LiveObjectIterator<kGreyObjects> it(p, MarkingState::Internal(p)); 1678 LiveObjectIterator<kGreyObjects> it(p, MarkingState::Internal(p));
1600 HeapObject* object = NULL; 1679 HeapObject* object = NULL;
1601 while ((object = it.Next()) != NULL) { 1680 while ((object = it.Next()) != NULL) {
1602 DCHECK(ObjectMarking::IsGrey(object, MarkingState::Internal(object))); 1681 DCHECK(ObjectMarking::IsGrey(object, MarkingState::Internal(object)));
1603 ObjectMarking::GreyToBlack(object, MarkingState::Internal(object)); 1682 ObjectMarking::GreyToBlack(object, MarkingState::Internal(object));
1604 PushBlack(object); 1683 PushBlack(object);
1605 if (marking_deque()->IsFull()) return; 1684 if (marking_deque()->IsFull()) return;
1606 } 1685 }
1607 } 1686 }
1608 1687
1609 class RecordMigratedSlotVisitor final : public ObjectVisitor { 1688 class RecordMigratedSlotVisitor : public ObjectVisitor {
1610 public: 1689 public:
1690 class HostScope {
1691 public:
1692 HostScope(RecordMigratedSlotVisitor* visitor, HeapObject* object)
1693 : visitor_(visitor) {
1694 DCHECK_NOT_NULL(object);
1695 visitor_->set_host(object);
1696 }
1697 ~HostScope() { visitor_->set_host(nullptr); }
1698
1699 private:
1700 RecordMigratedSlotVisitor* visitor_;
1701 };
1702
1611 explicit RecordMigratedSlotVisitor(MarkCompactCollector* collector) 1703 explicit RecordMigratedSlotVisitor(MarkCompactCollector* collector)
1612 : collector_(collector) {} 1704 : collector_(collector), host_(nullptr) {}
1613 1705
1614 inline void VisitPointer(Object** p) final { 1706 inline void VisitPointer(Object** p) final {
1615 RecordMigratedSlot(*p, reinterpret_cast<Address>(p)); 1707 RecordMigratedSlot(*p, reinterpret_cast<Address>(p));
1616 } 1708 }
1617 1709
1618 inline void VisitPointers(Object** start, Object** end) final { 1710 inline void VisitPointers(Object** start, Object** end) final {
1619 while (start < end) { 1711 while (start < end) {
1620 RecordMigratedSlot(*start, reinterpret_cast<Address>(start)); 1712 RecordMigratedSlot(*start, reinterpret_cast<Address>(start));
1621 ++start; 1713 ++start;
1622 } 1714 }
1623 } 1715 }
1624 1716
1625 inline void VisitCodeEntry(Address code_entry_slot) final { 1717 inline void VisitCodeEntry(Address code_entry_slot) override {
1626 Address code_entry = Memory::Address_at(code_entry_slot); 1718 Address code_entry = Memory::Address_at(code_entry_slot);
1627 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) { 1719 if (Page::FromAddress(code_entry)->IsEvacuationCandidate()) {
1628 RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(code_entry_slot), 1720 RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(code_entry_slot),
1629 nullptr, CODE_ENTRY_SLOT, 1721 nullptr, CODE_ENTRY_SLOT,
1630 code_entry_slot); 1722 code_entry_slot);
1631 } 1723 }
1632 } 1724 }
1633 1725
1634 inline void VisitCodeTarget(RelocInfo* rinfo) final { 1726 inline void VisitCodeTarget(RelocInfo* rinfo) override {
1635 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode())); 1727 DCHECK(RelocInfo::IsCodeTarget(rinfo->rmode()));
1636 Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address()); 1728 Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1637 Code* host = rinfo->host(); 1729 Code* host = rinfo->host();
1638 // The target is always in old space, we don't have to record the slot in 1730 // The target is always in old space, we don't have to record the slot in
1639 // the old-to-new remembered set. 1731 // the old-to-new remembered set.
1640 DCHECK(!collector_->heap()->InNewSpace(target)); 1732 DCHECK(!collector_->heap()->InNewSpace(target));
1641 collector_->RecordRelocSlot(host, rinfo, target); 1733 collector_->RecordRelocSlot(host, rinfo, target);
1642 } 1734 }
1643 1735
1644 inline void VisitDebugTarget(RelocInfo* rinfo) final { 1736 inline void VisitDebugTarget(RelocInfo* rinfo) override {
1645 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) && 1737 DCHECK(RelocInfo::IsDebugBreakSlot(rinfo->rmode()) &&
1646 rinfo->IsPatchedDebugBreakSlotSequence()); 1738 rinfo->IsPatchedDebugBreakSlotSequence());
1647 Code* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address()); 1739 Code* target = Code::GetCodeFromTargetAddress(rinfo->debug_call_address());
1648 Code* host = rinfo->host(); 1740 Code* host = rinfo->host();
1649 // The target is always in old space, we don't have to record the slot in 1741 // The target is always in old space, we don't have to record the slot in
1650 // the old-to-new remembered set. 1742 // the old-to-new remembered set.
1651 DCHECK(!collector_->heap()->InNewSpace(target)); 1743 DCHECK(!collector_->heap()->InNewSpace(target));
1652 collector_->RecordRelocSlot(host, rinfo, target); 1744 collector_->RecordRelocSlot(host, rinfo, target);
1653 } 1745 }
1654 1746
1655 inline void VisitEmbeddedPointer(RelocInfo* rinfo) final { 1747 inline void VisitEmbeddedPointer(RelocInfo* rinfo) override {
1656 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT); 1748 DCHECK(rinfo->rmode() == RelocInfo::EMBEDDED_OBJECT);
1657 HeapObject* object = HeapObject::cast(rinfo->target_object()); 1749 HeapObject* object = HeapObject::cast(rinfo->target_object());
1658 Code* host = rinfo->host(); 1750 Code* host = rinfo->host();
1659 collector_->heap()->RecordWriteIntoCode(host, rinfo, object); 1751 collector_->heap()->RecordWriteIntoCode(host, rinfo, object);
1660 collector_->RecordRelocSlot(host, rinfo, object); 1752 collector_->RecordRelocSlot(host, rinfo, object);
1661 } 1753 }
1662 1754
1663 inline void VisitCell(RelocInfo* rinfo) final { 1755 inline void VisitCell(RelocInfo* rinfo) override {
1664 DCHECK(rinfo->rmode() == RelocInfo::CELL); 1756 DCHECK(rinfo->rmode() == RelocInfo::CELL);
1665 Cell* cell = rinfo->target_cell(); 1757 Cell* cell = rinfo->target_cell();
1666 Code* host = rinfo->host(); 1758 Code* host = rinfo->host();
1667 // The cell is always in old space, we don't have to record the slot in 1759 // The cell is always in old space, we don't have to record the slot in
1668 // the old-to-new remembered set. 1760 // the old-to-new remembered set.
1669 DCHECK(!collector_->heap()->InNewSpace(cell)); 1761 DCHECK(!collector_->heap()->InNewSpace(cell));
1670 collector_->RecordRelocSlot(host, rinfo, cell); 1762 collector_->RecordRelocSlot(host, rinfo, cell);
1671 } 1763 }
1672 1764
1673 // Entries that will never move. 1765 // Entries that will never move.
1674 inline void VisitCodeAgeSequence(RelocInfo* rinfo) final { 1766 inline void VisitCodeAgeSequence(RelocInfo* rinfo) override {
1675 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); 1767 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
1676 Code* stub = rinfo->code_age_stub(); 1768 Code* stub = rinfo->code_age_stub();
1677 USE(stub); 1769 USE(stub);
1678 DCHECK(!Page::FromAddress(stub->address())->IsEvacuationCandidate()); 1770 DCHECK(!Page::FromAddress(stub->address())->IsEvacuationCandidate());
1679 } 1771 }
1680 1772
1681 // Entries that are skipped for recording. 1773 // Entries that are skipped for recording.
1682 inline void VisitExternalReference(RelocInfo* rinfo) final {} 1774 inline void VisitExternalReference(RelocInfo* rinfo) final {}
1683 inline void VisitExternalReference(Address* p) final {} 1775 inline void VisitExternalReference(Address* p) final {}
1684 inline void VisitRuntimeEntry(RelocInfo* rinfo) final {} 1776 inline void VisitRuntimeEntry(RelocInfo* rinfo) final {}
1685 inline void VisitInternalReference(RelocInfo* rinfo) final {} 1777 inline void VisitInternalReference(RelocInfo* rinfo) final {}
1686 1778
1687 private: 1779 protected:
1688 inline void RecordMigratedSlot(Object* value, Address slot) { 1780 void set_host(HeapObject* host) { host_ = host; }
1781
1782 inline virtual void RecordMigratedSlot(Object* value, Address slot) {
1689 if (value->IsHeapObject()) { 1783 if (value->IsHeapObject()) {
1690 Page* p = Page::FromAddress(reinterpret_cast<Address>(value)); 1784 Page* p = Page::FromAddress(reinterpret_cast<Address>(value));
1691 if (p->InNewSpace()) { 1785 if (p->InNewSpace()) {
1692 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot); 1786 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
1693 } else if (p->IsEvacuationCandidate()) { 1787 } else if (p->IsEvacuationCandidate()) {
1694 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot); 1788 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot);
1695 } 1789 }
1696 } 1790 }
1697 } 1791 }
1698 1792
1699 MarkCompactCollector* collector_; 1793 MarkCompactCollector* collector_;
1794 HeapObject* host_;
1795 };
1796
1797 class YoungGenerationRecordMigratedSlotVisitor final
1798 : public RecordMigratedSlotVisitor {
1799 public:
1800 explicit YoungGenerationRecordMigratedSlotVisitor(
1801 MarkCompactCollector* collector)
1802 : RecordMigratedSlotVisitor(collector) {}
1803
1804 inline void VisitCodeEntry(Address code_entry_slot) final {
1805 Address code_entry = Memory::Address_at(code_entry_slot);
1806 if (Page::FromAddress(code_entry)->IsEvacuationCandidate() &&
1807 IsHostObjectLive()) {
1808 RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(code_entry_slot),
1809 nullptr, CODE_ENTRY_SLOT,
1810 code_entry_slot);
1811 }
1812 }
1813
1814 inline void VisitCodeTarget(RelocInfo* rinfo) final { UNREACHABLE(); }
1815 inline void VisitDebugTarget(RelocInfo* rinfo) final { UNREACHABLE(); }
1816 inline void VisitEmbeddedPointer(RelocInfo* rinfo) final { UNREACHABLE(); }
1817 inline void VisitCell(RelocInfo* rinfo) final { UNREACHABLE(); }
1818 inline void VisitCodeAgeSequence(RelocInfo* rinfo) final { UNREACHABLE(); }
1819
1820 private:
1821 // Only record slots for host objects that are considered as live by the full
1822 // collector.
1823 inline bool IsHostObjectLive() {
1824 DCHECK_NOT_NULL(host_);
1825 return ObjectMarking::IsBlack(host_, collector_->marking_state(host_));
1826 }
1827
1828 inline void RecordMigratedSlot(Object* value, Address slot) final {
1829 if (value->IsHeapObject()) {
1830 Page* p = Page::FromAddress(reinterpret_cast<Address>(value));
1831 if (p->InNewSpace()) {
1832 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
1833 } else if (p->IsEvacuationCandidate() && IsHostObjectLive()) {
1834 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot);
1835 }
1836 }
1837 }
1700 }; 1838 };
1701 1839
1702 class HeapObjectVisitor { 1840 class HeapObjectVisitor {
1703 public: 1841 public:
1704 virtual ~HeapObjectVisitor() {} 1842 virtual ~HeapObjectVisitor() {}
1705 virtual bool Visit(HeapObject* object) = 0; 1843 virtual bool Visit(HeapObject* object) = 0;
1706 }; 1844 };
1707 1845
1846 class MigrationObserver {
1847 public:
1848 explicit MigrationObserver(Heap* heap) : heap_(heap) {}
1849
1850 virtual ~MigrationObserver() {}
1851 virtual inline void Move(HeapObject* src, HeapObject* dst) {}
1852
1853 protected:
1854 Heap* heap_;
1855 };
1856
1857 class YoungGenerationMigrationObserver : public MigrationObserver {
1858 public:
1859 YoungGenerationMigrationObserver(
1860 Heap* heap, MarkCompactCollector* mark_compact_collector,
1861 std::vector<HeapObject*>* black_allocation_objects)
1862 : MigrationObserver(heap),
1863 mark_compact_collector_(mark_compact_collector),
1864 black_allocation_objects_(black_allocation_objects) {}
1865
1866 inline void Move(HeapObject* src, HeapObject* dst) final {
1867 // Migrate color to old generation marking in case the object survived young
1868 // generation garbage collection.
1869 if (heap_->incremental_marking()->IsMarking()) {
1870 const MarkingState state = mark_compact_collector_->marking_state(dst);
1871 if (heap_->incremental_marking()->black_allocation() &&
1872 ObjectMarking::IsBlack(dst, state)) {
1873 base::LockGuard<base::Mutex> guard(&mutex_);
1874 black_allocation_objects_->push_back(dst);
1875 }
1876
1877 // Transfer old generation marking state.
1878 if (!ObjectMarking::IsBlack(dst, state)) {
1879 IncrementalMarking::TransferColor<MarkBit::ATOMIC>(src, dst);
1880 }
1881 }
1882 }
1883
1884 protected:
1885 base::Mutex mutex_;
1886 MarkCompactCollector* mark_compact_collector_;
1887 std::vector<HeapObject*>* black_allocation_objects_;
1888 };
1889
1708 class EvacuateVisitorBase : public HeapObjectVisitor { 1890 class EvacuateVisitorBase : public HeapObjectVisitor {
1709 protected: 1891 protected:
1710 enum MigrationMode { kFast, kProfiled }; 1892 enum MigrationMode { kFast, kProfiled };
1711 1893
1712 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces, 1894 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces,
1713 RecordMigratedSlotVisitor* record_visitor) 1895 RecordMigratedSlotVisitor* record_visitor,
1896 MigrationObserver* migration_observer)
1714 : heap_(heap), 1897 : heap_(heap),
1715 compaction_spaces_(compaction_spaces), 1898 compaction_spaces_(compaction_spaces),
1716 record_visitor_(record_visitor), 1899 record_visitor_(record_visitor),
1900 migration_observer_(migration_observer),
1717 profiling_( 1901 profiling_(
1718 heap->isolate()->is_profiling() || 1902 heap->isolate()->is_profiling() ||
1719 heap->isolate()->logger()->is_logging_code_events() || 1903 heap->isolate()->logger()->is_logging_code_events() ||
1720 heap->isolate()->heap_profiler()->is_tracking_object_moves()) {} 1904 heap->isolate()->heap_profiler()->is_tracking_object_moves()) {}
1721 1905
1722 inline bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object, 1906 inline bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object,
1723 HeapObject** target_object) { 1907 HeapObject** target_object) {
1724 #ifdef VERIFY_HEAP 1908 #ifdef VERIFY_HEAP
1725 if (AbortCompactionForTesting(object)) return false; 1909 if (AbortCompactionForTesting(object)) return false;
1726 #endif // VERIFY_HEAP 1910 #endif // VERIFY_HEAP
(...skipping 24 matching lines...) Expand all
1751 DCHECK(heap_->AllowedToBeMigrated(src, dest)); 1935 DCHECK(heap_->AllowedToBeMigrated(src, dest));
1752 DCHECK(dest != LO_SPACE); 1936 DCHECK(dest != LO_SPACE);
1753 if (dest == OLD_SPACE) { 1937 if (dest == OLD_SPACE) {
1754 DCHECK_OBJECT_SIZE(size); 1938 DCHECK_OBJECT_SIZE(size);
1755 DCHECK(IsAligned(size, kPointerSize)); 1939 DCHECK(IsAligned(size, kPointerSize));
1756 heap_->CopyBlock(dst_addr, src_addr, size); 1940 heap_->CopyBlock(dst_addr, src_addr, size);
1757 if ((mode == kProfiled) && dst->IsBytecodeArray()) { 1941 if ((mode == kProfiled) && dst->IsBytecodeArray()) {
1758 PROFILE(heap_->isolate(), 1942 PROFILE(heap_->isolate(),
1759 CodeMoveEvent(AbstractCode::cast(src), dst_addr)); 1943 CodeMoveEvent(AbstractCode::cast(src), dst_addr));
1760 } 1944 }
1761 dst->IterateBodyFast(dst->map()->instance_type(), size, record_visitor_); 1945 migration_observer_->Move(src, dst);
1946 {
1947 RecordMigratedSlotVisitor::HostScope host_scope(record_visitor_, dst);
Michael Lippautz 2017/04/21 07:05:52 This hack and all its consequences (stateful visit
Hannes Payer (out of office) 2017/04/21 14:46:26 Nice!
1948 dst->IterateBodyFast(dst->map()->instance_type(), size,
1949 record_visitor_);
1950 }
1762 } else if (dest == CODE_SPACE) { 1951 } else if (dest == CODE_SPACE) {
1763 DCHECK_CODEOBJECT_SIZE(size, heap_->code_space()); 1952 DCHECK_CODEOBJECT_SIZE(size, heap_->code_space());
1764 if (mode == kProfiled) { 1953 if (mode == kProfiled) {
1765 PROFILE(heap_->isolate(), 1954 PROFILE(heap_->isolate(),
1766 CodeMoveEvent(AbstractCode::cast(src), dst_addr)); 1955 CodeMoveEvent(AbstractCode::cast(src), dst_addr));
1767 } 1956 }
1768 heap_->CopyBlock(dst_addr, src_addr, size); 1957 heap_->CopyBlock(dst_addr, src_addr, size);
1769 Code::cast(dst)->Relocate(dst_addr - src_addr); 1958 Code::cast(dst)->Relocate(dst_addr - src_addr);
1770 RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector()); 1959 migration_observer_->Move(src, dst);
Michael Lippautz 2017/04/21 07:05:52 I plan to make the use of MigrationObserver templa
Hannes Payer (out of office) 2017/04/21 14:46:26 During evacuation you mean, right?
Michael Lippautz 2017/04/24 13:15:08 Yes.
1771 dst->IterateBodyFast(dst->map()->instance_type(), size, record_visitor_); 1960 {
1961 RecordMigratedSlotVisitor::HostScope host_scope(record_visitor_, dst);
1962 dst->IterateBodyFast(dst->map()->instance_type(), size,
1963 record_visitor_);
1964 }
1772 } else { 1965 } else {
1773 DCHECK_OBJECT_SIZE(size); 1966 DCHECK_OBJECT_SIZE(size);
1774 DCHECK(dest == NEW_SPACE); 1967 DCHECK(dest == NEW_SPACE);
1775 heap_->CopyBlock(dst_addr, src_addr, size); 1968 heap_->CopyBlock(dst_addr, src_addr, size);
1969 migration_observer_->Move(src, dst);
1776 } 1970 }
1777 if (mode == kProfiled) { 1971 if (mode == kProfiled) {
1778 heap_->OnMoveEvent(dst, src, size); 1972 heap_->OnMoveEvent(dst, src, size);
1779 } 1973 }
1780 base::NoBarrier_Store(reinterpret_cast<base::AtomicWord*>(src_addr), 1974 base::NoBarrier_Store(reinterpret_cast<base::AtomicWord*>(src_addr),
1781 reinterpret_cast<base::AtomicWord>(dst_addr)); 1975 reinterpret_cast<base::AtomicWord>(dst_addr));
1782 } 1976 }
1783 1977
1784 #ifdef VERIFY_HEAP 1978 #ifdef VERIFY_HEAP
1785 bool AbortCompactionForTesting(HeapObject* object) { 1979 bool AbortCompactionForTesting(HeapObject* object) {
(...skipping 11 matching lines...) Expand all
1797 } 1991 }
1798 } 1992 }
1799 } 1993 }
1800 return false; 1994 return false;
1801 } 1995 }
1802 #endif // VERIFY_HEAP 1996 #endif // VERIFY_HEAP
1803 1997
1804 Heap* heap_; 1998 Heap* heap_;
1805 CompactionSpaceCollection* compaction_spaces_; 1999 CompactionSpaceCollection* compaction_spaces_;
1806 RecordMigratedSlotVisitor* record_visitor_; 2000 RecordMigratedSlotVisitor* record_visitor_;
2001 MigrationObserver* migration_observer_;
1807 bool profiling_; 2002 bool profiling_;
1808 }; 2003 };
1809 2004
1810 class EvacuateNewSpaceVisitor final : public EvacuateVisitorBase { 2005 class EvacuateNewSpaceVisitor final : public EvacuateVisitorBase {
1811 public: 2006 public:
1812 static const intptr_t kLabSize = 4 * KB; 2007 static const intptr_t kLabSize = 4 * KB;
1813 static const intptr_t kMaxLabObjectSize = 256; 2008 static const intptr_t kMaxLabObjectSize = 256;
1814 2009
1815 explicit EvacuateNewSpaceVisitor(Heap* heap, 2010 explicit EvacuateNewSpaceVisitor(Heap* heap,
1816 CompactionSpaceCollection* compaction_spaces, 2011 CompactionSpaceCollection* compaction_spaces,
1817 RecordMigratedSlotVisitor* record_visitor, 2012 RecordMigratedSlotVisitor* record_visitor,
2013 MigrationObserver* migration_observer,
1818 base::HashMap* local_pretenuring_feedback) 2014 base::HashMap* local_pretenuring_feedback)
1819 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor), 2015 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor,
2016 migration_observer),
1820 buffer_(LocalAllocationBuffer::InvalidBuffer()), 2017 buffer_(LocalAllocationBuffer::InvalidBuffer()),
1821 space_to_allocate_(NEW_SPACE), 2018 space_to_allocate_(NEW_SPACE),
1822 promoted_size_(0), 2019 promoted_size_(0),
1823 semispace_copied_size_(0), 2020 semispace_copied_size_(0),
1824 local_pretenuring_feedback_(local_pretenuring_feedback) {} 2021 local_pretenuring_feedback_(local_pretenuring_feedback) {}
1825 2022
1826 inline bool Visit(HeapObject* object) override { 2023 inline bool Visit(HeapObject* object) override {
1827 heap_->UpdateAllocationSite<Heap::kCached>(object, 2024 heap_->UpdateAllocationSite<Heap::kCached>(object,
1828 local_pretenuring_feedback_); 2025 local_pretenuring_feedback_);
1829 int size = object->Size(); 2026 int size = object->Size();
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
1992 Heap* heap_; 2189 Heap* heap_;
1993 RecordMigratedSlotVisitor* record_visitor_; 2190 RecordMigratedSlotVisitor* record_visitor_;
1994 intptr_t moved_bytes_; 2191 intptr_t moved_bytes_;
1995 base::HashMap* local_pretenuring_feedback_; 2192 base::HashMap* local_pretenuring_feedback_;
1996 }; 2193 };
1997 2194
1998 class EvacuateOldSpaceVisitor final : public EvacuateVisitorBase { 2195 class EvacuateOldSpaceVisitor final : public EvacuateVisitorBase {
1999 public: 2196 public:
2000 EvacuateOldSpaceVisitor(Heap* heap, 2197 EvacuateOldSpaceVisitor(Heap* heap,
2001 CompactionSpaceCollection* compaction_spaces, 2198 CompactionSpaceCollection* compaction_spaces,
2002 RecordMigratedSlotVisitor* record_visitor) 2199 RecordMigratedSlotVisitor* record_visitor,
2003 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor) {} 2200 MigrationObserver* migration_observer)
2201 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor,
2202 migration_observer) {}
2004 2203
2005 inline bool Visit(HeapObject* object) override { 2204 inline bool Visit(HeapObject* object) override {
2006 CompactionSpace* target_space = compaction_spaces_->Get( 2205 CompactionSpace* target_space = compaction_spaces_->Get(
2007 Page::FromAddress(object->address())->owner()->identity()); 2206 Page::FromAddress(object->address())->owner()->identity());
2008 HeapObject* target_object = nullptr; 2207 HeapObject* target_object = nullptr;
2009 if (TryEvacuateObject(target_space, object, &target_object)) { 2208 if (TryEvacuateObject(target_space, object, &target_object)) {
2010 DCHECK(object->map_word().IsForwardingAddress()); 2209 DCHECK(object->map_word().IsForwardingAddress());
2011 return true; 2210 return true;
2012 } 2211 }
2013 return false; 2212 return false;
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after
2352 heap_object); 2551 heap_object);
2353 return KEEP_SLOT; 2552 return KEEP_SLOT;
2354 } 2553 }
2355 return REMOVE_SLOT; 2554 return REMOVE_SLOT;
2356 } 2555 }
2357 2556
2358 static bool IsUnmarkedObject(Heap* heap, Object** p) { 2557 static bool IsUnmarkedObject(Heap* heap, Object** p) {
2359 DCHECK_IMPLIES(heap->InNewSpace(*p), heap->InToSpace(*p)); 2558 DCHECK_IMPLIES(heap->InNewSpace(*p), heap->InToSpace(*p));
2360 return heap->InNewSpace(*p) && 2559 return heap->InNewSpace(*p) &&
2361 !ObjectMarking::IsBlack(HeapObject::cast(*p), 2560 !ObjectMarking::IsBlack(HeapObject::cast(*p),
2362 MarkingState::Internal(HeapObject::cast(*p))); 2561 MarkingState::External(HeapObject::cast(*p)));
2363 } 2562 }
2364 2563
2365 void MinorMarkCompactCollector::MarkLiveObjects() { 2564 void MinorMarkCompactCollector::MarkLiveObjects() {
2366 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK); 2565 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK);
2367 2566
2368 PostponeInterruptsScope postpone(isolate()); 2567 PostponeInterruptsScope postpone(isolate());
2369 2568
2370 StaticYoungGenerationMarkingVisitor::Initialize(heap()); 2569 StaticYoungGenerationMarkingVisitor::Initialize(heap());
2371 RootMarkingVisitor root_visitor(this); 2570 RootMarkingVisitor root_visitor(this);
2372 2571
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2404 heap()->VisitEncounteredWeakCollections(&root_visitor); 2603 heap()->VisitEncounteredWeakCollections(&root_visitor);
2405 ProcessMarkingDeque(); 2604 ProcessMarkingDeque();
2406 } 2605 }
2407 2606
2408 { 2607 {
2409 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_GLOBAL_HANDLES); 2608 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_GLOBAL_HANDLES);
2410 isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending( 2609 isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
2411 &IsUnmarkedObject); 2610 &IsUnmarkedObject);
2412 isolate() 2611 isolate()
2413 ->global_handles() 2612 ->global_handles()
2414 ->IterateNewSpaceWeakUnmodifiedRoots<GlobalHandles::VISIT_OTHERS>( 2613 ->IterateNewSpaceWeakUnmodifiedRoots<
2415 &root_visitor); 2614 GlobalHandles::HANDLE_PHANTOM_NODES_VISIT_OTHERS>(&root_visitor);
2416 ProcessMarkingDeque(); 2615 ProcessMarkingDeque();
2417 } 2616 }
2418 2617
2419 marking_deque()->StopUsing(); 2618 marking_deque()->StopUsing();
2420 } 2619 }
2421 2620
2422 void MinorMarkCompactCollector::ProcessMarkingDeque() { 2621 void MinorMarkCompactCollector::ProcessMarkingDeque() {
2423 EmptyMarkingDeque(); 2622 EmptyMarkingDeque();
2424 DCHECK(!marking_deque()->overflowed()); 2623 DCHECK(!marking_deque()->overflowed());
2425 DCHECK(marking_deque()->IsEmpty()); 2624 DCHECK(marking_deque()->IsEmpty());
(...skipping 11 matching lines...) Expand all
2437 object, MarkingState::External(object)))); 2636 object, MarkingState::External(object))));
2438 2637
2439 Map* map = object->map(); 2638 Map* map = object->map();
2440 DCHECK((ObjectMarking::IsBlack<MarkBit::NON_ATOMIC>( 2639 DCHECK((ObjectMarking::IsBlack<MarkBit::NON_ATOMIC>(
2441 object, MarkingState::External(object)))); 2640 object, MarkingState::External(object))));
2442 StaticYoungGenerationMarkingVisitor::IterateBody(map, object); 2641 StaticYoungGenerationMarkingVisitor::IterateBody(map, object);
2443 } 2642 }
2444 } 2643 }
2445 2644
2446 void MinorMarkCompactCollector::CollectGarbage() { 2645 void MinorMarkCompactCollector::CollectGarbage() {
2646 heap()->mark_compact_collector()->sweeper().EnsureNewSpaceCompleted();
2647
2447 MarkLiveObjects(); 2648 MarkLiveObjects();
2448 2649 ClearNonLiveReferences();
2449 #ifdef VERIFY_HEAP 2650 #ifdef VERIFY_HEAP
2450 if (FLAG_verify_heap) { 2651 if (FLAG_verify_heap) {
2451 YoungGenerationMarkingVerifier verifier(heap()); 2652 YoungGenerationMarkingVerifier verifier(heap());
2452 verifier.Run(); 2653 verifier.Run();
2453 } 2654 }
2454 #endif // VERIFY_HEAP 2655 #endif // VERIFY_HEAP
2656
2657 std::vector<HeapObject*> black_allocation_objects;
2658 EvacuateNewSpace(&black_allocation_objects);
2659 #ifdef VERIFY_HEAP
2660 if (FLAG_verify_heap) {
2661 YoungGenerationEvacuationVerifier verifier(heap());
2662 verifier.Run();
2663 }
2664 #endif // VERIFY_HEAP
2665
2666 heap()->incremental_marking()->UpdateMarkingDequeAfterScavenge();
2667
2668 // Process black allocation objects after updating pointers as we otherwise
2669 // would end up with objects on the marking deque that potentially forward
2670 // to white objects.
2671 // TODO(mlippautz): Instead of processing them explicitly, we should just add
2672 // them to the marking deque for further processing.
2673 {
2674 TRACE_GC(heap()->tracer(),
2675 GCTracer::Scope::MINOR_MC_EVACUATE_PROCESS_BLACK_ALLOCATION);
2676 for (HeapObject* object : black_allocation_objects) {
2677 CHECK(ObjectMarking::IsBlack(object, MarkingState::Internal(object)));
2678 heap()->incremental_marking()->IterateBlackObject(object);
2679 }
2680 heap()->local_embedder_heap_tracer()->RegisterWrappersWithRemoteTracer();
2681 }
2682
2683 {
2684 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_CLEAR_LIVENESS);
2685 for (Page* p : PageRange(heap()->new_space()->FromSpaceStart(),
2686 heap()->new_space()->FromSpaceEnd())) {
2687 marking_state(p).ClearLiveness();
2688 }
2689 }
2690 }
2691
2692 void MinorMarkCompactCollector::ClearNonLiveReferences() {
2693 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR);
2694
2695 {
2696 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_STRING_TABLE);
2697 // Internalized strings are always stored in old space, so there is no need
2698 // to clean them here.
2699 YoungGenerationExternalStringTableCleaner external_visitor(*this);
2700 heap()->external_string_table_.IterateNewSpaceStrings(&external_visitor);
2701 heap()->external_string_table_.CleanUpNewSpaceStrings();
2702 }
2703
2704 {
2705 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_WEAK_LISTS);
2706 // Process the weak references.
2707 MinorMarkCompactWeakObjectRetainer retainer(*this);
2708 heap()->ProcessYoungWeakReferences(&retainer);
2709 }
2710 }
2711
2712 void MinorMarkCompactCollector::EvacuatePrologue() {
2713 NewSpace* new_space = heap()->new_space();
2714 // Append the list of new space pages to be processed.
2715 for (Page* p : PageRange(new_space->bottom(), new_space->top())) {
2716 new_space_evacuation_pages_.Add(p);
2717 }
2718 new_space->Flip();
2719 new_space->ResetAllocationInfo();
2720 }
2721
2722 void MinorMarkCompactCollector::EvacuateEpilogue() {
2723 heap()->new_space()->set_age_mark(heap()->new_space()->top());
2724 }
2725
2726 void MinorMarkCompactCollector::EvacuateNewSpace(
2727 std::vector<HeapObject*>* black_allocation_objects) {
2728 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE);
2729 Heap::RelocationLock relocation_lock(heap());
2730
2731 {
2732 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_PROLOGUE);
2733 EvacuatePrologue();
2734 }
2735
2736 {
2737 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_COPY);
2738 EvacuatePagesInParallel(black_allocation_objects);
2739 }
2740
2741 UpdatePointersAfterEvacuation();
2742
2743 {
2744 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_REBALANCE);
2745 if (!heap()->new_space()->Rebalance()) {
2746 FatalProcessOutOfMemory("NewSpace::Rebalance");
2747 }
2748 }
2749
2750 // Give pages that are queued to be freed back to the OS.
2751 heap()->memory_allocator()->unmapper()->FreeQueuedChunks();
2752
2753 {
2754 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_CLEAN_UP);
2755 // TODO(mlippautz): Implement page promotion.
2756 new_space_evacuation_pages_.Rewind(0);
2757 }
2758
2759 {
2760 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_EPILOGUE);
2761 EvacuateEpilogue();
2762 }
2455 } 2763 }
2456 2764
2457 void MarkCompactCollector::MarkLiveObjects() { 2765 void MarkCompactCollector::MarkLiveObjects() {
2458 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK); 2766 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK);
2459 // The recursive GC marker detects when it is nearing stack overflow, 2767 // The recursive GC marker detects when it is nearing stack overflow,
2460 // and switches to a different marking system. JS interrupts interfere 2768 // and switches to a different marking system. JS interrupts interfere
2461 // with the C stack limit check. 2769 // with the C stack limit check.
2462 PostponeInterruptsScope postpone(isolate()); 2770 PostponeInterruptsScope postpone(isolate());
2463 2771
2464 { 2772 {
(...skipping 651 matching lines...) Expand 10 before | Expand all | Expand 10 after
3116 } 3424 }
3117 3425
3118 // NewSpacePages with more live bytes than this threshold qualify for fast 3426 // NewSpacePages with more live bytes than this threshold qualify for fast
3119 // evacuation. 3427 // evacuation.
3120 static int PageEvacuationThreshold() { 3428 static int PageEvacuationThreshold() {
3121 if (FLAG_page_promotion) 3429 if (FLAG_page_promotion)
3122 return FLAG_page_promotion_threshold * Page::kAllocatableMemory / 100; 3430 return FLAG_page_promotion_threshold * Page::kAllocatableMemory / 100;
3123 return Page::kAllocatableMemory + kPointerSize; 3431 return Page::kAllocatableMemory + kPointerSize;
3124 } 3432 }
3125 3433
3126 Evacuator(Heap* heap, RecordMigratedSlotVisitor* record_visitor) 3434 Evacuator(Heap* heap, RecordMigratedSlotVisitor* record_visitor,
3435 MigrationObserver* migration_observer)
3127 : heap_(heap), 3436 : heap_(heap),
3128 compaction_spaces_(heap_), 3437 compaction_spaces_(heap_),
3129 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity), 3438 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity),
3130 new_space_visitor_(heap_, &compaction_spaces_, record_visitor, 3439 new_space_visitor_(heap_, &compaction_spaces_, record_visitor,
3131 &local_pretenuring_feedback_), 3440 migration_observer, &local_pretenuring_feedback_),
3132 new_to_new_page_visitor_(heap_, record_visitor, 3441 new_to_new_page_visitor_(heap_, record_visitor,
3133 &local_pretenuring_feedback_), 3442 &local_pretenuring_feedback_),
3134 new_to_old_page_visitor_(heap_, record_visitor, 3443 new_to_old_page_visitor_(heap_, record_visitor,
3135 &local_pretenuring_feedback_), 3444 &local_pretenuring_feedback_),
3136 3445
3137 old_space_visitor_(heap_, &compaction_spaces_, record_visitor), 3446 old_space_visitor_(heap_, &compaction_spaces_, record_visitor,
3447 migration_observer),
3138 duration_(0.0), 3448 duration_(0.0),
3139 bytes_compacted_(0) {} 3449 bytes_compacted_(0) {}
3140 3450
3141 virtual ~Evacuator() {} 3451 virtual ~Evacuator() {}
3142 3452
3143 virtual bool EvacuatePage(Page* page, const MarkingState& state) = 0; 3453 bool EvacuatePage(Page* page, const MarkingState& state);
3454 virtual bool EvacuatePageImpl(Page* page, const MarkingState& state) = 0;
3144 3455
3145 // Merge back locally cached info sequentially. Note that this method needs 3456 // Merge back locally cached info sequentially. Note that this method needs
3146 // to be called from the main thread. 3457 // to be called from the main thread.
3147 inline void Finalize(); 3458 inline void Finalize();
3148 3459
3149 CompactionSpaceCollection* compaction_spaces() { return &compaction_spaces_; } 3460 CompactionSpaceCollection* compaction_spaces() { return &compaction_spaces_; }
3150 AllocationInfo CloseNewSpaceLAB() { return new_space_visitor_.CloseLAB(); } 3461 AllocationInfo CloseNewSpaceLAB() { return new_space_visitor_.CloseLAB(); }
3151 3462
3152 protected: 3463 protected:
3153 static const int kInitialLocalPretenuringFeedbackCapacity = 256; 3464 static const int kInitialLocalPretenuringFeedbackCapacity = 256;
(...skipping 17 matching lines...) Expand all
3171 new_to_new_page_visitor_; 3482 new_to_new_page_visitor_;
3172 EvacuateNewSpacePageVisitor<PageEvacuationMode::NEW_TO_OLD> 3483 EvacuateNewSpacePageVisitor<PageEvacuationMode::NEW_TO_OLD>
3173 new_to_old_page_visitor_; 3484 new_to_old_page_visitor_;
3174 EvacuateOldSpaceVisitor old_space_visitor_; 3485 EvacuateOldSpaceVisitor old_space_visitor_;
3175 3486
3176 // Book keeping info. 3487 // Book keeping info.
3177 double duration_; 3488 double duration_;
3178 intptr_t bytes_compacted_; 3489 intptr_t bytes_compacted_;
3179 }; 3490 };
3180 3491
3492 bool Evacuator::EvacuatePage(Page* page, const MarkingState& state) {
3493 bool success = false;
3494 DCHECK(page->SweepingDone());
3495 intptr_t saved_live_bytes = state.live_bytes();
3496 double evacuation_time = 0.0;
3497 {
3498 AlwaysAllocateScope always_allocate(heap()->isolate());
3499 TimedScope timed_scope(&evacuation_time);
3500 success = EvacuatePageImpl(page, state);
3501 }
3502 ReportCompactionProgress(evacuation_time, saved_live_bytes);
3503 if (FLAG_trace_evacuation) {
3504 PrintIsolate(
3505 heap()->isolate(),
3506 "evacuation[%p]: page=%p new_space=%d "
3507 "page_evacuation=%d executable=%d contains_age_mark=%d "
3508 "live_bytes=%" V8PRIdPTR " time=%f page_promotion_qualifies=%d\n",
3509 static_cast<void*>(this), static_cast<void*>(page), page->InNewSpace(),
3510 page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) ||
3511 page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION),
3512 page->IsFlagSet(MemoryChunk::IS_EXECUTABLE),
3513 page->Contains(heap()->new_space()->age_mark()), saved_live_bytes,
3514 evacuation_time,
3515 saved_live_bytes > Evacuator::PageEvacuationThreshold());
3516 }
3517 return success;
3518 }
3519
3181 void Evacuator::Finalize() { 3520 void Evacuator::Finalize() {
3182 heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE)); 3521 heap()->old_space()->MergeCompactionSpace(compaction_spaces_.Get(OLD_SPACE));
3183 heap()->code_space()->MergeCompactionSpace( 3522 heap()->code_space()->MergeCompactionSpace(
3184 compaction_spaces_.Get(CODE_SPACE)); 3523 compaction_spaces_.Get(CODE_SPACE));
3185 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_); 3524 heap()->tracer()->AddCompactionEvent(duration_, bytes_compacted_);
3186 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size() + 3525 heap()->IncrementPromotedObjectsSize(new_space_visitor_.promoted_size() +
3187 new_to_old_page_visitor_.moved_bytes()); 3526 new_to_old_page_visitor_.moved_bytes());
3188 heap()->IncrementSemiSpaceCopiedObjectSize( 3527 heap()->IncrementSemiSpaceCopiedObjectSize(
3189 new_space_visitor_.semispace_copied_size() + 3528 new_space_visitor_.semispace_copied_size() +
3190 new_to_new_page_visitor_.moved_bytes()); 3529 new_to_new_page_visitor_.moved_bytes());
3191 heap()->IncrementYoungSurvivorsCounter( 3530 heap()->IncrementYoungSurvivorsCounter(
3192 new_space_visitor_.promoted_size() + 3531 new_space_visitor_.promoted_size() +
3193 new_space_visitor_.semispace_copied_size() + 3532 new_space_visitor_.semispace_copied_size() +
3194 new_to_old_page_visitor_.moved_bytes() + 3533 new_to_old_page_visitor_.moved_bytes() +
3195 new_to_new_page_visitor_.moved_bytes()); 3534 new_to_new_page_visitor_.moved_bytes());
3196 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_); 3535 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_);
3197 } 3536 }
3198 3537
3199 class FullEvacuator : public Evacuator { 3538 class FullEvacuator : public Evacuator {
3200 public: 3539 public:
3201 FullEvacuator(Heap* heap, RecordMigratedSlotVisitor* record_visitor) 3540 FullEvacuator(Heap* heap, RecordMigratedSlotVisitor* record_visitor,
3202 : Evacuator(heap, record_visitor) {} 3541 MigrationObserver* migration_observer)
3542 : Evacuator(heap, record_visitor, migration_observer) {}
3203 3543
3204 bool EvacuatePage(Page* page, const MarkingState& state) override; 3544 bool EvacuatePageImpl(Page* page, const MarkingState& state) override;
3205 }; 3545 };
3206 3546
3207 bool FullEvacuator::EvacuatePage(Page* page, const MarkingState& state) { 3547 bool FullEvacuator::EvacuatePageImpl(Page* page, const MarkingState& state) {
3208 bool success = false; 3548 bool success = false;
3209 DCHECK(page->SweepingDone()); 3549 LiveObjectVisitor object_visitor;
3210 intptr_t saved_live_bytes = state.live_bytes(); 3550 switch (ComputeEvacuationMode(page)) {
3211 double evacuation_time = 0.0; 3551 case kObjectsNewToOld:
3212 { 3552 success = object_visitor.VisitBlackObjects(
3213 AlwaysAllocateScope always_allocate(heap()->isolate()); 3553 page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits);
3214 TimedScope timed_scope(&evacuation_time); 3554 DCHECK(success);
3215 LiveObjectVisitor object_visitor; 3555 ArrayBufferTracker::ProcessBuffers(
3216 switch (ComputeEvacuationMode(page)) { 3556 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
3217 case kObjectsNewToOld: 3557 break;
3218 success = 3558 case kPageNewToOld:
3219 object_visitor.VisitBlackObjects(page, state, &new_space_visitor_, 3559 success = object_visitor.VisitBlackObjects(
3220 LiveObjectVisitor::kClearMarkbits); 3560 page, state, &new_to_old_page_visitor_,
3561 LiveObjectVisitor::kKeepMarking);
3562 DCHECK(success);
3563 new_to_old_page_visitor_.account_moved_bytes(
3564 MarkingState::Internal(page).live_bytes());
3565 // ArrayBufferTracker will be updated during sweeping.
3566 break;
3567 case kPageNewToNew:
3568 success = object_visitor.VisitBlackObjects(
3569 page, state, &new_to_new_page_visitor_,
3570 LiveObjectVisitor::kKeepMarking);
3571 DCHECK(success);
3572 new_to_new_page_visitor_.account_moved_bytes(
3573 MarkingState::Internal(page).live_bytes());
3574 // ArrayBufferTracker will be updated during sweeping.
3575 break;
3576 case kObjectsOldToOld:
3577 success = object_visitor.VisitBlackObjects(
3578 page, state, &old_space_visitor_, LiveObjectVisitor::kClearMarkbits);
3579 if (!success) {
3580 // Aborted compaction page. We have to record slots here, since we
3581 // might not have recorded them in first place.
3582 // Note: We mark the page as aborted here to be able to record slots
3583 // for code objects in |RecordMigratedSlotVisitor|.
3584 page->SetFlag(Page::COMPACTION_WAS_ABORTED);
3585 EvacuateRecordOnlyVisitor record_visitor(heap());
3586 success = object_visitor.VisitBlackObjects(
3587 page, state, &record_visitor, LiveObjectVisitor::kKeepMarking);
3588 ArrayBufferTracker::ProcessBuffers(
3589 page, ArrayBufferTracker::kUpdateForwardedKeepOthers);
3221 DCHECK(success); 3590 DCHECK(success);
3591 // We need to return failure here to indicate that we want this page
3592 // added to the sweeper.
3593 success = false;
3594 } else {
3222 ArrayBufferTracker::ProcessBuffers( 3595 ArrayBufferTracker::ProcessBuffers(
3223 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); 3596 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
3224 break; 3597 }
3225 case kPageNewToOld: 3598 break;
3226 success = object_visitor.VisitBlackObjects(
3227 page, state, &new_to_old_page_visitor_,
3228 LiveObjectVisitor::kKeepMarking);
3229 DCHECK(success);
3230 new_to_old_page_visitor_.account_moved_bytes(
3231 MarkingState::Internal(page).live_bytes());
3232 // ArrayBufferTracker will be updated during sweeping.
3233 break;
3234 case kPageNewToNew:
3235 success = object_visitor.VisitBlackObjects(
3236 page, state, &new_to_new_page_visitor_,
3237 LiveObjectVisitor::kKeepMarking);
3238 DCHECK(success);
3239 new_to_new_page_visitor_.account_moved_bytes(
3240 MarkingState::Internal(page).live_bytes());
3241 // ArrayBufferTracker will be updated during sweeping.
3242 break;
3243 case kObjectsOldToOld:
3244 success =
3245 object_visitor.VisitBlackObjects(page, state, &old_space_visitor_,
3246 LiveObjectVisitor::kClearMarkbits);
3247 if (!success) {
3248 // Aborted compaction page. We have to record slots here, since we
3249 // might not have recorded them in first place.
3250 // Note: We mark the page as aborted here to be able to record slots
3251 // for code objects in |RecordMigratedSlotVisitor|.
3252 page->SetFlag(Page::COMPACTION_WAS_ABORTED);
3253 EvacuateRecordOnlyVisitor record_visitor(heap());
3254 success = object_visitor.VisitBlackObjects(
3255 page, state, &record_visitor, LiveObjectVisitor::kKeepMarking);
3256 ArrayBufferTracker::ProcessBuffers(
3257 page, ArrayBufferTracker::kUpdateForwardedKeepOthers);
3258 DCHECK(success);
3259 // We need to return failure here to indicate that we want this page
3260 // added to the sweeper.
3261 success = false;
3262 } else {
3263 ArrayBufferTracker::ProcessBuffers(
3264 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
3265 }
3266 break;
3267 }
3268 }
3269 ReportCompactionProgress(evacuation_time, saved_live_bytes);
3270 if (FLAG_trace_evacuation) {
3271 PrintIsolate(heap()->isolate(),
3272 "evacuation[%p]: page=%p new_space=%d "
3273 "page_evacuation=%d executable=%d contains_age_mark=%d "
3274 "live_bytes=%" V8PRIdPTR " time=%f\n",
3275 static_cast<void*>(this), static_cast<void*>(page),
3276 page->InNewSpace(),
3277 page->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION) ||
3278 page->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION),
3279 page->IsFlagSet(MemoryChunk::IS_EXECUTABLE),
3280 page->Contains(heap()->new_space()->age_mark()),
3281 saved_live_bytes, evacuation_time);
3282 } 3599 }
3283 return success; 3600 return success;
3284 } 3601 }
3285 3602
3286 int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages, 3603 class YoungGenerationEvacuator : public Evacuator {
3287 intptr_t live_bytes) { 3604 public:
3288 if (!FLAG_parallel_compaction) return 1; 3605 YoungGenerationEvacuator(Heap* heap,
3289 // Compute the number of needed tasks based on a target compaction time, the 3606 RecordMigratedSlotVisitor* record_visitor,
3290 // profiled compaction speed and marked live memory. 3607 MigrationObserver* migration_observer)
3291 // 3608 : Evacuator(heap, record_visitor, migration_observer) {}
3292 // The number of parallel compaction tasks is limited by:
3293 // - #evacuation pages
3294 // - #cores
3295 const double kTargetCompactionTimeInMs = .5;
3296 3609
3297 double compaction_speed = 3610 bool EvacuatePageImpl(Page* page, const MarkingState& state) override;
3298 heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); 3611 };
3299 3612
3300 const int available_cores = Max( 3613 bool YoungGenerationEvacuator::EvacuatePageImpl(Page* page,
3301 1, static_cast<int>( 3614 const MarkingState& state) {
3302 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); 3615 bool success = false;
3303 int tasks; 3616 LiveObjectVisitor object_visitor;
3304 if (compaction_speed > 0) { 3617 switch (ComputeEvacuationMode(page)) {
3305 tasks = 1 + static_cast<int>(live_bytes / compaction_speed / 3618 case kObjectsNewToOld:
3306 kTargetCompactionTimeInMs); 3619 success = object_visitor.VisitBlackObjects(
3307 } else { 3620 page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits);
3308 tasks = pages; 3621 DCHECK(success);
3622 ArrayBufferTracker::ProcessBuffers(
3623 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
3624 break;
3625 case kPageNewToOld:
3626 // TODO(mlippautz): Implement page promotion.
3627 UNREACHABLE();
3628 break;
3629 case kPageNewToNew:
3630 // TODO(mlippautz): Implement page promotion.
3631 UNREACHABLE();
3632 break;
3633 case kObjectsOldToOld:
3634 UNREACHABLE();
3635 break;
3309 } 3636 }
3310 const int tasks_capped_pages = Min(pages, tasks); 3637 return success;
3311 return Min(available_cores, tasks_capped_pages);
3312 } 3638 }
3313 3639
3314 class EvacuationJobTraits { 3640 class EvacuationJobTraits {
3315 public: 3641 public:
3316 typedef int* PerPageData; // Pointer to number of aborted pages. 3642 struct PageData {
3643 int* abandoned_pages; // Pointer to number of aborted pages.
3644 MarkingState marking_state;
3645 };
3646
3647 typedef PageData PerPageData;
3317 typedef Evacuator* PerTaskData; 3648 typedef Evacuator* PerTaskData;
3318 3649
3319 static const bool NeedSequentialFinalization = true; 3650 static const bool NeedSequentialFinalization = true;
3320 3651
3321 static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator, 3652 static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator,
3322 MemoryChunk* chunk, PerPageData) { 3653 MemoryChunk* chunk, PerPageData data) {
3323 return evacuator->EvacuatePage(reinterpret_cast<Page*>(chunk), 3654 return evacuator->EvacuatePage(reinterpret_cast<Page*>(chunk),
3324 MarkingState::Internal(chunk)); 3655 data.marking_state);
3325 } 3656 }
3326 3657
3327 static void FinalizePageSequentially(Heap* heap, MemoryChunk* chunk, 3658 static void FinalizePageSequentially(Heap* heap, MemoryChunk* chunk,
3328 bool success, PerPageData data) { 3659 bool success, PerPageData data) {
3329 Page* p = static_cast<Page*>(chunk); 3660 Page* p = static_cast<Page*>(chunk);
3330 switch (Evacuator::ComputeEvacuationMode(p)) { 3661 switch (Evacuator::ComputeEvacuationMode(p)) {
3331 case Evacuator::kPageNewToOld: 3662 case Evacuator::kPageNewToOld:
3332 break; 3663 break;
3333 case Evacuator::kPageNewToNew: 3664 case Evacuator::kPageNewToNew:
3334 DCHECK(success); 3665 DCHECK(success);
3335 break; 3666 break;
3336 case Evacuator::kObjectsNewToOld: 3667 case Evacuator::kObjectsNewToOld:
3337 DCHECK(success); 3668 DCHECK(success);
3338 break; 3669 break;
3339 case Evacuator::kObjectsOldToOld: 3670 case Evacuator::kObjectsOldToOld:
3340 if (success) { 3671 if (success) {
3341 DCHECK(p->IsEvacuationCandidate()); 3672 DCHECK(p->IsEvacuationCandidate());
3342 DCHECK(p->SweepingDone()); 3673 DCHECK(p->SweepingDone());
3343 p->Unlink(); 3674 p->Unlink();
3344 } else { 3675 } else {
3345 // We have partially compacted the page, i.e., some objects may have 3676 // We have partially compacted the page, i.e., some objects may have
3346 // moved, others are still in place. 3677 // moved, others are still in place.
3347 p->ClearEvacuationCandidate(); 3678 p->ClearEvacuationCandidate();
3348 // Slots have already been recorded so we just need to add it to the 3679 // Slots have already been recorded so we just need to add it to the
3349 // sweeper, which will happen after updating pointers. 3680 // sweeper, which will happen after updating pointers.
3350 *data += 1; 3681 *data.abandoned_pages += 1;
3351 } 3682 }
3352 break; 3683 break;
3353 default: 3684 default:
3354 UNREACHABLE(); 3685 UNREACHABLE();
3355 } 3686 }
3356 } 3687 }
3357 }; 3688 };
3358 3689
3690 namespace {
3691
3692 // The number of parallel compaction tasks, including the main thread.
3693 int NumberOfParallelCompactionTasks(Heap* heap, int pages,
3694 intptr_t live_bytes) {
3695 if (!FLAG_parallel_compaction) return 1;
3696 // Compute the number of needed tasks based on a target compaction time, the
3697 // profiled compaction speed and marked live memory.
3698 //
3699 // The number of parallel compaction tasks is limited by:
3700 // - #evacuation pages
3701 // - #cores
3702 const double kTargetCompactionTimeInMs = .5;
3703
3704 const double compaction_speed =
3705 heap->tracer()->CompactionSpeedInBytesPerMillisecond();
3706
3707 const int available_cores = Max(
3708 1, static_cast<int>(
3709 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads()));
3710 int tasks;
3711 if (compaction_speed > 0) {
3712 tasks = 1 + static_cast<int>(live_bytes / compaction_speed /
3713 kTargetCompactionTimeInMs);
3714 } else {
3715 tasks = pages;
3716 }
3717 const int tasks_capped_pages = Min(pages, tasks);
3718 return Min(available_cores, tasks_capped_pages);
3719 }
3720
3721 template <class E, class SV>
3722 void CreateAndExecuteEvacuationTasks(Heap* heap,
3723 PageParallelJob<EvacuationJobTraits>* job,
3724 RecordMigratedSlotVisitor* record_visitor,
3725 MigrationObserver* observer,
3726 const intptr_t live_bytes,
3727 const int& abandoned_pages) {
3728 // Used for trace summary.
3729 double compaction_speed = 0;
3730 if (FLAG_trace_evacuation) {
3731 compaction_speed = heap->tracer()->CompactionSpeedInBytesPerMillisecond();
3732 }
3733
3734 const int wanted_num_tasks =
3735 NumberOfParallelCompactionTasks(heap, job->NumberOfPages(), live_bytes);
3736 E** evacuators = new E*[wanted_num_tasks];
3737 SV** slots_recorders = new SV*[wanted_num_tasks];
3738 for (int i = 0; i < wanted_num_tasks; i++) {
3739 slots_recorders[i] = new SV(heap->mark_compact_collector());
3740 evacuators[i] = new E(heap, slots_recorders[i], observer);
3741 }
3742 job->Run(wanted_num_tasks, [evacuators](int i) { return evacuators[i]; });
3743 const Address top = heap->new_space()->top();
3744 for (int i = 0; i < wanted_num_tasks; i++) {
3745 evacuators[i]->Finalize();
3746 // Try to find the last LAB that was used for new space allocation in
3747 // evacuation tasks. If it was adjacent to the current top, move top back.
3748 const AllocationInfo info = evacuators[i]->CloseNewSpaceLAB();
3749 if (info.limit() != nullptr && info.limit() == top) {
3750 DCHECK_NOT_NULL(info.top());
3751 *heap->new_space()->allocation_top_address() = info.top();
3752 }
3753 delete evacuators[i];
3754 delete slots_recorders[i];
3755 }
3756 delete[] evacuators;
3757 delete[] slots_recorders;
3758
3759 if (FLAG_trace_evacuation) {
3760 PrintIsolate(heap->isolate(),
3761 "%8.0f ms: evacuation-summary: parallel=%s pages=%d "
3762 "aborted=%d wanted_tasks=%d tasks=%d cores=%" PRIuS
3763 " live_bytes=%" V8PRIdPTR " compaction_speed=%.f\n",
3764 heap->isolate()->time_millis_since_init(),
3765 FLAG_parallel_compaction ? "yes" : "no", job->NumberOfPages(),
3766 abandoned_pages, wanted_num_tasks, job->NumberOfTasks(),
3767 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads(),
3768 live_bytes, compaction_speed);
3769 }
3770 }
3771
3772 } // namespace
3773
3359 void MarkCompactCollector::EvacuatePagesInParallel() { 3774 void MarkCompactCollector::EvacuatePagesInParallel() {
3360 PageParallelJob<EvacuationJobTraits> job( 3775 PageParallelJob<EvacuationJobTraits> job(
3361 heap_, heap_->isolate()->cancelable_task_manager(), 3776 heap_, heap_->isolate()->cancelable_task_manager(),
3362 &page_parallel_job_semaphore_); 3777 &page_parallel_job_semaphore_);
3363 3778
3364 int abandoned_pages = 0; 3779 int abandoned_pages = 0;
3365 intptr_t live_bytes = 0; 3780 intptr_t live_bytes = 0;
3366 for (Page* page : old_space_evacuation_pages_) { 3781 for (Page* page : old_space_evacuation_pages_) {
3367 live_bytes += MarkingState::Internal(page).live_bytes(); 3782 live_bytes += MarkingState::Internal(page).live_bytes();
3368 job.AddPage(page, &abandoned_pages); 3783 job.AddPage(page, {&abandoned_pages, marking_state(page)});
3369 } 3784 }
3370 3785
3371 const bool reduce_memory = heap()->ShouldReduceMemory(); 3786 const bool reduce_memory = heap()->ShouldReduceMemory();
3372 const Address age_mark = heap()->new_space()->age_mark(); 3787 const Address age_mark = heap()->new_space()->age_mark();
3373 for (Page* page : new_space_evacuation_pages_) { 3788 for (Page* page : new_space_evacuation_pages_) {
3374 intptr_t live_bytes_on_page = MarkingState::Internal(page).live_bytes(); 3789 intptr_t live_bytes_on_page = MarkingState::Internal(page).live_bytes();
3375 live_bytes += live_bytes_on_page; 3790 live_bytes += live_bytes_on_page;
3376 if (!reduce_memory && !page->NeverEvacuate() && 3791 if (!reduce_memory && !page->NeverEvacuate() &&
3377 (live_bytes_on_page > Evacuator::PageEvacuationThreshold()) && 3792 (live_bytes_on_page > Evacuator::PageEvacuationThreshold()) &&
3378 !page->Contains(age_mark) && 3793 !page->Contains(age_mark) &&
3379 heap()->CanExpandOldGeneration(live_bytes_on_page)) { 3794 heap()->CanExpandOldGeneration(live_bytes_on_page)) {
3380 if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) { 3795 if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) {
3381 EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page); 3796 EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page);
3382 } else { 3797 } else {
3383 EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page); 3798 EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page);
3384 } 3799 }
3385 } 3800 }
3386 3801
3387 job.AddPage(page, &abandoned_pages); 3802 job.AddPage(page, {&abandoned_pages, marking_state(page)});
3388 } 3803 }
3389 DCHECK_GE(job.NumberOfPages(), 1); 3804 DCHECK_GE(job.NumberOfPages(), 1);
3390 3805
3391 // Used for trace summary. 3806 MigrationObserver observer(heap());
3392 double compaction_speed = 0; 3807 CreateAndExecuteEvacuationTasks<FullEvacuator, RecordMigratedSlotVisitor>(
3393 if (FLAG_trace_evacuation) { 3808 heap(), &job, nullptr, &observer, live_bytes, abandoned_pages);
3394 compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); 3809 }
3810
3811 void MinorMarkCompactCollector::EvacuatePagesInParallel(
3812 std::vector<HeapObject*>* black_allocation_objects) {
3813 PageParallelJob<EvacuationJobTraits> job(
3814 heap_, heap_->isolate()->cancelable_task_manager(),
3815 &page_parallel_job_semaphore_);
3816
3817 int abandoned_pages = 0;
3818 intptr_t live_bytes = 0;
3819
3820 for (Page* page : new_space_evacuation_pages_) {
3821 intptr_t live_bytes_on_page = marking_state(page).live_bytes();
3822 live_bytes += live_bytes_on_page;
3823 // TODO(mlippautz): Implement page promotion.
3824 job.AddPage(page, {&abandoned_pages, marking_state(page)});
3395 } 3825 }
3826 DCHECK_GE(job.NumberOfPages(), 1);
3396 3827
3397 const int wanted_num_tasks = 3828 YoungGenerationMigrationObserver observer(
3398 NumberOfParallelCompactionTasks(job.NumberOfPages(), live_bytes); 3829 heap(), heap()->mark_compact_collector(), black_allocation_objects);
3399 FullEvacuator** evacuators = new FullEvacuator*[wanted_num_tasks]; 3830 CreateAndExecuteEvacuationTasks<YoungGenerationEvacuator,
Michael Lippautz 2017/04/21 07:05:52 The idea is to have a stateless YoungGenerationRec
Hannes Payer (out of office) 2017/04/21 14:46:26 Acknowledged.
3400 RecordMigratedSlotVisitor record_visitor(this); 3831 YoungGenerationRecordMigratedSlotVisitor>(
3401 for (int i = 0; i < wanted_num_tasks; i++) { 3832 heap(), &job, nullptr, &observer, live_bytes, abandoned_pages);
3402 evacuators[i] = new FullEvacuator(heap(), &record_visitor);
3403 }
3404 job.Run(wanted_num_tasks, [evacuators](int i) { return evacuators[i]; });
3405 const Address top = heap()->new_space()->top();
3406 for (int i = 0; i < wanted_num_tasks; i++) {
3407 evacuators[i]->Finalize();
3408 // Try to find the last LAB that was used for new space allocation in
3409 // evacuation tasks. If it was adjacent to the current top, move top back.
3410 const AllocationInfo info = evacuators[i]->CloseNewSpaceLAB();
3411 if (info.limit() != nullptr && info.limit() == top) {
3412 DCHECK_NOT_NULL(info.top());
3413 *heap()->new_space()->allocation_top_address() = info.top();
3414 }
3415 delete evacuators[i];
3416 }
3417 delete[] evacuators;
3418
3419 if (FLAG_trace_evacuation) {
3420 PrintIsolate(isolate(),
3421 "%8.0f ms: evacuation-summary: parallel=%s pages=%d "
3422 "aborted=%d wanted_tasks=%d tasks=%d cores=%" PRIuS
3423 " live_bytes=%" V8PRIdPTR " compaction_speed=%.f\n",
3424 isolate()->time_millis_since_init(),
3425 FLAG_parallel_compaction ? "yes" : "no", job.NumberOfPages(),
3426 abandoned_pages, wanted_num_tasks, job.NumberOfTasks(),
3427 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads(),
3428 live_bytes, compaction_speed);
3429 }
3430 } 3833 }
3431 3834
3432 class EvacuationWeakObjectRetainer : public WeakObjectRetainer { 3835 class EvacuationWeakObjectRetainer : public WeakObjectRetainer {
3433 public: 3836 public:
3434 virtual Object* RetainAs(Object* object) { 3837 virtual Object* RetainAs(Object* object) {
3435 if (object->IsHeapObject()) { 3838 if (object->IsHeapObject()) {
3436 HeapObject* heap_object = HeapObject::cast(object); 3839 HeapObject* heap_object = HeapObject::cast(object);
3437 MapWord map_word = heap_object->map_word(); 3840 MapWord map_word = heap_object->map_word();
3438 if (map_word.IsForwardingAddress()) { 3841 if (map_word.IsForwardingAddress()) {
3439 return map_word.ToForwardingAddress(); 3842 return map_word.ToForwardingAddress();
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
3744 UpdateUntypedPointers(heap, chunk); 4147 UpdateUntypedPointers(heap, chunk);
3745 UpdateTypedPointers(heap, chunk); 4148 UpdateTypedPointers(heap, chunk);
3746 return true; 4149 return true;
3747 } 4150 }
3748 static const bool NeedSequentialFinalization = false; 4151 static const bool NeedSequentialFinalization = false;
3749 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { 4152 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) {
3750 } 4153 }
3751 4154
3752 private: 4155 private:
3753 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) { 4156 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) {
4157 base::LockGuard<base::RecursiveMutex> guard(chunk->mutex());
3754 if (type == OLD_TO_NEW) { 4158 if (type == OLD_TO_NEW) {
3755 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) { 4159 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) {
3756 return CheckAndUpdateOldToNewSlot(heap, slot); 4160 return CheckAndUpdateOldToNewSlot(heap, slot);
3757 }); 4161 });
3758 } else { 4162 } else {
3759 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) { 4163 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) {
3760 return UpdateSlot(reinterpret_cast<Object**>(slot)); 4164 return UpdateSlot(reinterpret_cast<Object**>(slot));
3761 }); 4165 });
3762 } 4166 }
3763 } 4167 }
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
3850 heap, heap->isolate()->cancelable_task_manager(), semaphore); 4254 heap, heap->isolate()->cancelable_task_manager(), semaphore);
3851 RememberedSet<type>::IterateMemoryChunks( 4255 RememberedSet<type>::IterateMemoryChunks(
3852 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); }); 4256 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); });
3853 int num_pages = job.NumberOfPages(); 4257 int num_pages = job.NumberOfPages();
3854 int num_tasks = NumberOfPointerUpdateTasks(num_pages); 4258 int num_tasks = NumberOfPointerUpdateTasks(num_pages);
3855 job.Run(num_tasks, [](int i) { return 0; }); 4259 job.Run(num_tasks, [](int i) { return 0; });
3856 } 4260 }
3857 4261
3858 class ToSpacePointerUpdateJobTraits { 4262 class ToSpacePointerUpdateJobTraits {
3859 public: 4263 public:
3860 typedef std::pair<Address, Address> PerPageData; 4264 struct PageData {
4265 Address start;
4266 Address end;
4267 MarkingState marking_state;
4268 };
4269
4270 typedef PageData PerPageData;
3861 typedef PointersUpdatingVisitor* PerTaskData; 4271 typedef PointersUpdatingVisitor* PerTaskData;
3862 4272
3863 static bool ProcessPageInParallel(Heap* heap, PerTaskData visitor, 4273 static bool ProcessPageInParallel(Heap* heap, PerTaskData visitor,
3864 MemoryChunk* chunk, PerPageData limits) { 4274 MemoryChunk* chunk, PerPageData page_data) {
3865 if (chunk->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION)) { 4275 if (chunk->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION)) {
3866 // New->new promoted pages contain garbage so they require iteration 4276 // New->new promoted pages contain garbage so they require iteration
3867 // using markbits. 4277 // using markbits.
3868 ProcessPageInParallelVisitLive(heap, visitor, chunk, limits); 4278 ProcessPageInParallelVisitLive(heap, visitor, chunk, page_data);
3869 } else { 4279 } else {
3870 ProcessPageInParallelVisitAll(heap, visitor, chunk, limits); 4280 ProcessPageInParallelVisitAll(heap, visitor, chunk, page_data);
3871 } 4281 }
3872 return true; 4282 return true;
3873 } 4283 }
3874 4284
3875 static const bool NeedSequentialFinalization = false; 4285 static const bool NeedSequentialFinalization = false;
3876 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { 4286 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) {
3877 } 4287 }
3878 4288
3879 private: 4289 private:
3880 static void ProcessPageInParallelVisitAll(Heap* heap, PerTaskData visitor, 4290 static void ProcessPageInParallelVisitAll(Heap* heap, PerTaskData visitor,
3881 MemoryChunk* chunk, 4291 MemoryChunk* chunk,
3882 PerPageData limits) { 4292 PerPageData page_data) {
3883 for (Address cur = limits.first; cur < limits.second;) { 4293 for (Address cur = page_data.start; cur < page_data.end;) {
3884 HeapObject* object = HeapObject::FromAddress(cur); 4294 HeapObject* object = HeapObject::FromAddress(cur);
3885 Map* map = object->map(); 4295 Map* map = object->map();
3886 int size = object->SizeFromMap(map); 4296 int size = object->SizeFromMap(map);
3887 object->IterateBody(map->instance_type(), size, visitor); 4297 object->IterateBody(map->instance_type(), size, visitor);
3888 cur += size; 4298 cur += size;
3889 } 4299 }
3890 } 4300 }
3891 4301
3892 static void ProcessPageInParallelVisitLive(Heap* heap, PerTaskData visitor, 4302 static void ProcessPageInParallelVisitLive(Heap* heap, PerTaskData visitor,
3893 MemoryChunk* chunk, 4303 MemoryChunk* chunk,
3894 PerPageData limits) { 4304 PerPageData page_data) {
3895 LiveObjectIterator<kBlackObjects> it(chunk, MarkingState::Internal(chunk)); 4305 LiveObjectIterator<kBlackObjects> it(chunk, page_data.marking_state);
3896 HeapObject* object = NULL; 4306 HeapObject* object = NULL;
3897 while ((object = it.Next()) != NULL) { 4307 while ((object = it.Next()) != NULL) {
3898 Map* map = object->map(); 4308 Map* map = object->map();
3899 int size = object->SizeFromMap(map); 4309 int size = object->SizeFromMap(map);
3900 object->IterateBody(map->instance_type(), size, visitor); 4310 object->IterateBody(map->instance_type(), size, visitor);
3901 } 4311 }
3902 } 4312 }
3903 }; 4313 };
3904 4314
3905 void UpdateToSpacePointersInParallel(Heap* heap, base::Semaphore* semaphore) { 4315 template <class MarkingStateProvider>
4316 void UpdateToSpacePointersInParallel(
4317 Heap* heap, base::Semaphore* semaphore,
4318 const MarkingStateProvider& marking_state_provider) {
3906 PageParallelJob<ToSpacePointerUpdateJobTraits> job( 4319 PageParallelJob<ToSpacePointerUpdateJobTraits> job(
3907 heap, heap->isolate()->cancelable_task_manager(), semaphore); 4320 heap, heap->isolate()->cancelable_task_manager(), semaphore);
3908 Address space_start = heap->new_space()->bottom(); 4321 Address space_start = heap->new_space()->bottom();
3909 Address space_end = heap->new_space()->top(); 4322 Address space_end = heap->new_space()->top();
3910 for (Page* page : PageRange(space_start, space_end)) { 4323 for (Page* page : PageRange(space_start, space_end)) {
3911 Address start = 4324 Address start =
3912 page->Contains(space_start) ? space_start : page->area_start(); 4325 page->Contains(space_start) ? space_start : page->area_start();
3913 Address end = page->Contains(space_end) ? space_end : page->area_end(); 4326 Address end = page->Contains(space_end) ? space_end : page->area_end();
3914 job.AddPage(page, std::make_pair(start, end)); 4327 job.AddPage(page, {start, end, marking_state_provider.marking_state(page)});
3915 } 4328 }
3916 PointersUpdatingVisitor visitor; 4329 PointersUpdatingVisitor visitor;
3917 int num_tasks = FLAG_parallel_pointer_update ? job.NumberOfPages() : 1; 4330 int num_tasks = FLAG_parallel_pointer_update ? job.NumberOfPages() : 1;
3918 job.Run(num_tasks, [&visitor](int i) { return &visitor; }); 4331 job.Run(num_tasks, [&visitor](int i) { return &visitor; });
3919 } 4332 }
3920 4333
3921 void MarkCompactCollector::UpdatePointersAfterEvacuation() { 4334 void MarkCompactCollector::UpdatePointersAfterEvacuation() {
3922 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS); 4335 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS);
3923 4336
3924 PointersUpdatingVisitor updating_visitor; 4337 PointersUpdatingVisitor updating_visitor;
3925 4338
3926 { 4339 {
3927 TRACE_GC(heap()->tracer(), 4340 TRACE_GC(heap()->tracer(),
3928 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW); 4341 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW);
3929 UpdateToSpacePointersInParallel(heap_, &page_parallel_job_semaphore_); 4342 UpdateToSpacePointersInParallel(heap_, &page_parallel_job_semaphore_,
4343 *this);
3930 // Update roots. 4344 // Update roots.
3931 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); 4345 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
3932 UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_); 4346 UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_);
3933 } 4347 }
3934 4348
3935 { 4349 {
3936 Heap* heap = this->heap(); 4350 Heap* heap = this->heap();
3937 TRACE_GC(heap->tracer(), 4351 TRACE_GC(heap->tracer(),
3938 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED); 4352 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED);
3939 UpdatePointersInParallel<OLD_TO_OLD>(heap_, &page_parallel_job_semaphore_); 4353 UpdatePointersInParallel<OLD_TO_OLD>(heap_, &page_parallel_job_semaphore_);
3940 } 4354 }
3941 4355
3942 { 4356 {
3943 TRACE_GC(heap()->tracer(), 4357 TRACE_GC(heap()->tracer(),
3944 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK); 4358 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK);
3945 // Update pointers from external string table. 4359 // Update pointers from external string table.
3946 heap_->UpdateReferencesInExternalStringTable( 4360 heap_->UpdateReferencesInExternalStringTable(
3947 &UpdateReferenceInExternalStringTableEntry); 4361 &UpdateReferenceInExternalStringTableEntry);
3948 4362
3949 EvacuationWeakObjectRetainer evacuation_object_retainer; 4363 EvacuationWeakObjectRetainer evacuation_object_retainer;
3950 heap()->ProcessWeakListRoots(&evacuation_object_retainer); 4364 heap()->ProcessWeakListRoots(&evacuation_object_retainer);
3951 } 4365 }
3952 } 4366 }
3953 4367
4368 void MinorMarkCompactCollector::UpdatePointersAfterEvacuation() {
4369 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS);
4370
4371 PointersUpdatingVisitor updating_visitor;
4372
4373 {
4374 TRACE_GC(heap()->tracer(),
4375 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW);
4376 UpdateToSpacePointersInParallel(heap_, &page_parallel_job_semaphore_,
4377 *this);
4378 // TODO(mlippautz): Iteration mode is not optimal as we process all
4379 // global handles. Find a way to only process the ones related to new
4380 // space.
4381 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
4382 UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_);
4383 }
4384
4385 {
4386 TRACE_GC(heap()->tracer(),
4387 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK);
4388
4389 EvacuationWeakObjectRetainer evacuation_object_retainer;
4390 heap()->ProcessWeakListRoots(&evacuation_object_retainer);
4391
4392 // Update pointers from external string table.
4393 heap()->UpdateNewSpaceReferencesInExternalStringTable(
4394 &UpdateReferenceInExternalStringTableEntry);
4395 heap()->VisitEncounteredWeakCollections(&updating_visitor);
4396 heap()->set_encountered_weak_collections(Smi::kZero);
4397 }
4398 }
3954 4399
3955 void MarkCompactCollector::ReleaseEvacuationCandidates() { 4400 void MarkCompactCollector::ReleaseEvacuationCandidates() {
3956 for (Page* p : old_space_evacuation_pages_) { 4401 for (Page* p : old_space_evacuation_pages_) {
3957 if (!p->IsEvacuationCandidate()) continue; 4402 if (!p->IsEvacuationCandidate()) continue;
3958 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 4403 PagedSpace* space = static_cast<PagedSpace*>(p->owner());
3959 MarkingState::Internal(p).SetLiveBytes(0); 4404 MarkingState::Internal(p).SetLiveBytes(0);
3960 CHECK(p->SweepingDone()); 4405 CHECK(p->SweepingDone());
3961 space->ReleasePage(p); 4406 space->ReleasePage(p);
3962 } 4407 }
3963 old_space_evacuation_pages_.Rewind(0); 4408 old_space_evacuation_pages_.Rewind(0);
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
4169 // The target is always in old space, we don't have to record the slot in 4614 // The target is always in old space, we don't have to record the slot in
4170 // the old-to-new remembered set. 4615 // the old-to-new remembered set.
4171 DCHECK(!heap()->InNewSpace(target)); 4616 DCHECK(!heap()->InNewSpace(target));
4172 RecordRelocSlot(host, &rinfo, target); 4617 RecordRelocSlot(host, &rinfo, target);
4173 } 4618 }
4174 } 4619 }
4175 } 4620 }
4176 4621
4177 } // namespace internal 4622 } // namespace internal
4178 } // namespace v8 4623 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698