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

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

Issue 2796233003: [heap] Evacuation for young generation (Closed)
Patch Set: Rebase after smaller refactorings landed 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 281 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 void VerifyPointers(Object** start, Object** end) override { 292 void VerifyPointers(Object** start, Object** end) override {
293 for (Object** current = start; current < end; current++) { 293 for (Object** current = start; current < end; current++) {
294 if ((*current)->IsHeapObject()) { 294 if ((*current)->IsHeapObject()) {
295 HeapObject* object = HeapObject::cast(*current); 295 HeapObject* object = HeapObject::cast(*current);
296 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object)); 296 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object));
297 } 297 }
298 } 298 }
299 } 299 }
300 }; 300 };
301 301
302 class YoungGenerationEvacuationVerifier : public EvacuationVerifier {
303 public:
304 explicit YoungGenerationEvacuationVerifier(Heap* heap)
305 : EvacuationVerifier(heap) {}
306
307 void Run() override {
308 VerifyRoots(VISIT_ALL_IN_SCAVENGE);
309 VerifyEvacuation(heap_->new_space());
ulan 2017/04/26 09:51:28 Verification should be done for the whole heap.
Michael Lippautz 2017/05/02 11:22:00 Done.
310 }
311
312 protected:
313 void VerifyPointers(Object** start, Object** end) override {
314 for (Object** current = start; current < end; current++) {
315 if ((*current)->IsHeapObject()) {
316 HeapObject* object = HeapObject::cast(*current);
317 if (!heap_->InNewSpace(object)) return;
ulan 2017/04/26 09:51:28 Let's instead do a check that object is not in fro
Michael Lippautz 2017/05/02 11:22:00 Done.
318 CHECK(!MarkCompactCollector::IsOnEvacuationCandidate(object));
319 }
320 }
321 }
322 };
323
302 } // namespace 324 } // namespace
303 #endif // VERIFY_HEAP 325 #endif // VERIFY_HEAP
304 326
305 // ============================================================================= 327 // =============================================================================
306 // MarkCompactCollectorBase, MinorMarkCompactCollector, MarkCompactCollector 328 // MarkCompactCollectorBase, MinorMarkCompactCollector, MarkCompactCollector
307 // ============================================================================= 329 // =============================================================================
308 330
309 int MarkCompactCollectorBase::NumberOfParallelCompactionTasks( 331 int MarkCompactCollectorBase::NumberOfParallelCompactionTasks(
310 int pages, intptr_t live_bytes) { 332 int pages, intptr_t live_bytes) {
311 if (!FLAG_parallel_compaction) return 1; 333 if (!FLAG_parallel_compaction) return 1;
(...skipping 1276 matching lines...) Expand 10 before | Expand all | Expand 10 after
1588 *p = the_hole; 1610 *p = the_hole;
1589 } 1611 }
1590 } 1612 }
1591 } 1613 }
1592 } 1614 }
1593 1615
1594 private: 1616 private:
1595 Heap* heap_; 1617 Heap* heap_;
1596 }; 1618 };
1597 1619
1620 // Helper class for pruning the string table.
1621 class YoungGenerationExternalStringTableCleaner : public RootVisitor {
1622 public:
1623 YoungGenerationExternalStringTableCleaner(
1624 const MinorMarkCompactCollector& collector)
1625 : heap_(collector.heap()), collector_(collector) {}
1626
1627 void VisitRootPointers(Root root, Object** start, Object** end) override {
1628 DCHECK_EQ(root, Root::kExternalStringsTable);
1629 // Visit all HeapObject pointers in [start, end).
1630 for (Object** p = start; p < end; p++) {
1631 Object* o = *p;
1632 if (o->IsHeapObject()) {
1633 HeapObject* heap_object = HeapObject::cast(o);
1634 if (ObjectMarking::IsWhite(heap_object,
1635 collector_.marking_state(heap_object))) {
1636 if (o->IsExternalString()) {
1637 heap_->FinalizeExternalString(String::cast(*p));
1638 } else {
1639 // The original external string may have been internalized.
1640 DCHECK(o->IsThinString());
1641 }
1642 // Set the entry to the_hole_value (as deleted).
1643 *p = heap_->the_hole_value();
1644 }
1645 }
1646 }
1647 }
1648
1649 private:
1650 Heap* heap_;
1651 const MinorMarkCompactCollector& collector_;
1652 };
1653
1654 // Marked young generation objects and all old generation objects will be
1655 // retained.
1656 class MinorMarkCompactWeakObjectRetainer : public WeakObjectRetainer {
1657 public:
1658 explicit MinorMarkCompactWeakObjectRetainer(
1659 const MinorMarkCompactCollector& collector)
1660 : collector_(collector) {}
1661
1662 virtual Object* RetainAs(Object* object) {
1663 HeapObject* heap_object = HeapObject::cast(object);
1664 if (!collector_.heap()->InNewSpace(heap_object)) return object;
1665
1666 DCHECK(!ObjectMarking::IsGrey(heap_object,
1667 MarkingState::External(heap_object)));
ulan 2017/04/26 09:51:28 Did you mean collector_.marking_state(heap_object)
Michael Lippautz 2017/05/02 11:22:00 Done.
1668 if (ObjectMarking::IsBlack(heap_object,
1669 collector_.marking_state(heap_object))) {
1670 return object;
1671 }
1672 return nullptr;
1673 }
1674
1675 private:
1676 const MinorMarkCompactCollector& collector_;
1677 };
1678
1598 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects 1679 // Implementation of WeakObjectRetainer for mark compact GCs. All marked objects
1599 // are retained. 1680 // are retained.
1600 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer { 1681 class MarkCompactWeakObjectRetainer : public WeakObjectRetainer {
1601 public: 1682 public:
1602 virtual Object* RetainAs(Object* object) { 1683 virtual Object* RetainAs(Object* object) {
1603 HeapObject* heap_object = HeapObject::cast(object); 1684 HeapObject* heap_object = HeapObject::cast(object);
1604 DCHECK(!ObjectMarking::IsGrey(heap_object, 1685 DCHECK(!ObjectMarking::IsGrey(heap_object,
1605 MarkingState::Internal(heap_object))); 1686 MarkingState::Internal(heap_object)));
1606 if (ObjectMarking::IsBlack(heap_object, 1687 if (ObjectMarking::IsBlack(heap_object,
1607 MarkingState::Internal(heap_object))) { 1688 MarkingState::Internal(heap_object))) {
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1712 inline void VisitCellPointer(Code* host, RelocInfo* rinfo) override { 1793 inline void VisitCellPointer(Code* host, RelocInfo* rinfo) override {
1713 DCHECK_EQ(host, rinfo->host()); 1794 DCHECK_EQ(host, rinfo->host());
1714 DCHECK(rinfo->rmode() == RelocInfo::CELL); 1795 DCHECK(rinfo->rmode() == RelocInfo::CELL);
1715 Cell* cell = rinfo->target_cell(); 1796 Cell* cell = rinfo->target_cell();
1716 // The cell is always in old space, we don't have to record the slot in 1797 // The cell is always in old space, we don't have to record the slot in
1717 // the old-to-new remembered set. 1798 // the old-to-new remembered set.
1718 DCHECK(!collector_->heap()->InNewSpace(cell)); 1799 DCHECK(!collector_->heap()->InNewSpace(cell));
1719 collector_->RecordRelocSlot(host, rinfo, cell); 1800 collector_->RecordRelocSlot(host, rinfo, cell);
1720 } 1801 }
1721 1802
1722 // Entries that will never move.
1723 inline void VisitCodeAgeSequence(Code* host, RelocInfo* rinfo) override { 1803 inline void VisitCodeAgeSequence(Code* host, RelocInfo* rinfo) override {
1724 DCHECK_EQ(host, rinfo->host()); 1804 DCHECK_EQ(host, rinfo->host());
1725 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode())); 1805 DCHECK(RelocInfo::IsCodeAgeSequence(rinfo->rmode()));
1726 Code* stub = rinfo->code_age_stub(); 1806 Code* stub = rinfo->code_age_stub();
1727 USE(stub); 1807 USE(stub);
1728 DCHECK(!Page::FromAddress(stub->address())->IsEvacuationCandidate()); 1808 DCHECK(!Page::FromAddress(stub->address())->IsEvacuationCandidate());
1729 } 1809 }
1730 1810
1731 // Entries that are skipped for recording. 1811 // Entries that are skipped for recording.
1732 inline void VisitExternalReference(Code* host, RelocInfo* rinfo) final {} 1812 inline void VisitExternalReference(Code* host, RelocInfo* rinfo) final {}
(...skipping 10 matching lines...) Expand all
1743 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot); 1823 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
1744 } else if (p->IsEvacuationCandidate()) { 1824 } else if (p->IsEvacuationCandidate()) {
1745 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot); 1825 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot);
1746 } 1826 }
1747 } 1827 }
1748 } 1828 }
1749 1829
1750 MarkCompactCollector* collector_; 1830 MarkCompactCollector* collector_;
1751 }; 1831 };
1752 1832
1833 class YoungGenerationRecordMigratedSlotVisitor final
1834 : public RecordMigratedSlotVisitor {
1835 public:
1836 explicit YoungGenerationRecordMigratedSlotVisitor(
1837 MarkCompactCollector* collector)
1838 : RecordMigratedSlotVisitor(collector) {}
1839
1840 inline void VisitCodeEntry(JSFunction* host, Address code_entry_slot) final {
1841 Address code_entry = Memory::Address_at(code_entry_slot);
1842 if (Page::FromAddress(code_entry)->IsEvacuationCandidate() &&
1843 IsLive(host)) {
1844 RememberedSet<OLD_TO_OLD>::InsertTyped(Page::FromAddress(code_entry_slot),
1845 nullptr, CODE_ENTRY_SLOT,
1846 code_entry_slot);
1847 }
1848 }
1849
1850 void VisitCodeTarget(Code* host, RelocInfo* rinfo) final { UNREACHABLE(); }
1851 void VisitDebugTarget(Code* host, RelocInfo* rinfo) final { UNREACHABLE(); }
1852 void VisitEmbeddedPointer(Code* host, RelocInfo* rinfo) final {
1853 UNREACHABLE();
1854 }
1855 void VisitCellPointer(Code* host, RelocInfo* rinfo) final { UNREACHABLE(); }
1856 void VisitCodeAgeSequence(Code* host, RelocInfo* rinfo) final {
1857 UNREACHABLE();
1858 }
1859
1860 private:
1861 // Only record slots for host objects that are considered as live by the full
1862 // collector.
1863 inline bool IsLive(HeapObject* object) {
1864 return ObjectMarking::IsBlack(object, collector_->marking_state(object));
1865 }
1866
1867 inline void RecordMigratedSlot(HeapObject* host, Object* value,
1868 Address slot) final {
1869 if (value->IsHeapObject()) {
1870 Page* p = Page::FromAddress(reinterpret_cast<Address>(value));
1871 if (p->InNewSpace()) {
1872 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot);
1873 } else if (p->IsEvacuationCandidate() && IsLive(host)) {
1874 RememberedSet<OLD_TO_OLD>::Insert(Page::FromAddress(slot), slot);
1875 }
1876 }
1877 }
1878 };
1879
1753 class HeapObjectVisitor { 1880 class HeapObjectVisitor {
1754 public: 1881 public:
1755 virtual ~HeapObjectVisitor() {} 1882 virtual ~HeapObjectVisitor() {}
1756 virtual bool Visit(HeapObject* object) = 0; 1883 virtual bool Visit(HeapObject* object) = 0;
1757 }; 1884 };
1758 1885
1886 class MigrationObserver {
1887 public:
1888 explicit MigrationObserver(Heap* heap) : heap_(heap) {}
1889
1890 virtual ~MigrationObserver() {}
1891 virtual inline void Move(HeapObject* src, HeapObject* dst) {}
1892
1893 protected:
1894 Heap* heap_;
1895 };
1896
1897 class YoungGenerationMigrationObserver : public MigrationObserver {
1898 public:
1899 YoungGenerationMigrationObserver(
1900 Heap* heap, MarkCompactCollector* mark_compact_collector,
1901 std::vector<HeapObject*>* black_allocation_objects)
1902 : MigrationObserver(heap),
1903 mark_compact_collector_(mark_compact_collector),
1904 black_allocation_objects_(black_allocation_objects) {}
1905
1906 inline void Move(HeapObject* src, HeapObject* dst) final {
1907 // Migrate color to old generation marking in case the object survived young
1908 // generation garbage collection.
1909 if (heap_->incremental_marking()->IsMarking()) {
1910 const MarkingState state = mark_compact_collector_->marking_state(dst);
1911 if (heap_->incremental_marking()->black_allocation() &&
1912 ObjectMarking::IsBlack(dst, state)) {
ulan 2017/04/26 09:51:28 if (ObjectMarking::IsBlack(dst, state)) { DCHECK
Michael Lippautz 2017/05/02 11:22:00 Done.
1913 base::LockGuard<base::Mutex> guard(&mutex_);
1914 black_allocation_objects_->push_back(dst);
1915 }
1916
1917 // Transfer old generation marking state.
1918 if (!ObjectMarking::IsBlack(dst, state)) {
1919 IncrementalMarking::TransferColor<MarkBit::ATOMIC>(src, dst);
1920 }
1921 }
1922 }
1923
1924 protected:
1925 base::Mutex mutex_;
1926 MarkCompactCollector* mark_compact_collector_;
1927 std::vector<HeapObject*>* black_allocation_objects_;
1928 };
1929
1759 class EvacuateVisitorBase : public HeapObjectVisitor { 1930 class EvacuateVisitorBase : public HeapObjectVisitor {
1760 protected: 1931 protected:
1761 enum MigrationMode { kFast, kProfiled }; 1932 enum MigrationMode { kFast, kProfiled };
1762 1933
1763 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces, 1934 EvacuateVisitorBase(Heap* heap, CompactionSpaceCollection* compaction_spaces,
1764 RecordMigratedSlotVisitor* record_visitor) 1935 RecordMigratedSlotVisitor* record_visitor,
1936 MigrationObserver* migration_observer)
1765 : heap_(heap), 1937 : heap_(heap),
1766 compaction_spaces_(compaction_spaces), 1938 compaction_spaces_(compaction_spaces),
1767 record_visitor_(record_visitor), 1939 record_visitor_(record_visitor),
1940 migration_observer_(migration_observer),
1768 profiling_( 1941 profiling_(
1769 heap->isolate()->is_profiling() || 1942 heap->isolate()->is_profiling() ||
1770 heap->isolate()->logger()->is_logging_code_events() || 1943 heap->isolate()->logger()->is_logging_code_events() ||
1771 heap->isolate()->heap_profiler()->is_tracking_object_moves()) {} 1944 heap->isolate()->heap_profiler()->is_tracking_object_moves()) {}
1772 1945
1773 inline bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object, 1946 inline bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object,
1774 HeapObject** target_object) { 1947 HeapObject** target_object) {
1775 #ifdef VERIFY_HEAP 1948 #ifdef VERIFY_HEAP
1776 if (AbortCompactionForTesting(object)) return false; 1949 if (AbortCompactionForTesting(object)) return false;
1777 #endif // VERIFY_HEAP 1950 #endif // VERIFY_HEAP
(...skipping 24 matching lines...) Expand all
1802 DCHECK(heap_->AllowedToBeMigrated(src, dest)); 1975 DCHECK(heap_->AllowedToBeMigrated(src, dest));
1803 DCHECK(dest != LO_SPACE); 1976 DCHECK(dest != LO_SPACE);
1804 if (dest == OLD_SPACE) { 1977 if (dest == OLD_SPACE) {
1805 DCHECK_OBJECT_SIZE(size); 1978 DCHECK_OBJECT_SIZE(size);
1806 DCHECK(IsAligned(size, kPointerSize)); 1979 DCHECK(IsAligned(size, kPointerSize));
1807 heap_->CopyBlock(dst_addr, src_addr, size); 1980 heap_->CopyBlock(dst_addr, src_addr, size);
1808 if ((mode == kProfiled) && dst->IsBytecodeArray()) { 1981 if ((mode == kProfiled) && dst->IsBytecodeArray()) {
1809 PROFILE(heap_->isolate(), 1982 PROFILE(heap_->isolate(),
1810 CodeMoveEvent(AbstractCode::cast(src), dst_addr)); 1983 CodeMoveEvent(AbstractCode::cast(src), dst_addr));
1811 } 1984 }
1985 migration_observer_->Move(src, dst);
1812 dst->IterateBodyFast(dst->map()->instance_type(), size, record_visitor_); 1986 dst->IterateBodyFast(dst->map()->instance_type(), size, record_visitor_);
1813 } else if (dest == CODE_SPACE) { 1987 } else if (dest == CODE_SPACE) {
1814 DCHECK_CODEOBJECT_SIZE(size, heap_->code_space()); 1988 DCHECK_CODEOBJECT_SIZE(size, heap_->code_space());
1815 if (mode == kProfiled) { 1989 if (mode == kProfiled) {
1816 PROFILE(heap_->isolate(), 1990 PROFILE(heap_->isolate(),
1817 CodeMoveEvent(AbstractCode::cast(src), dst_addr)); 1991 CodeMoveEvent(AbstractCode::cast(src), dst_addr));
1818 } 1992 }
1819 heap_->CopyBlock(dst_addr, src_addr, size); 1993 heap_->CopyBlock(dst_addr, src_addr, size);
1820 Code::cast(dst)->Relocate(dst_addr - src_addr); 1994 Code::cast(dst)->Relocate(dst_addr - src_addr);
1821 RecordMigratedSlotVisitor visitor(heap_->mark_compact_collector()); 1995 migration_observer_->Move(src, dst);
1822 dst->IterateBodyFast(dst->map()->instance_type(), size, record_visitor_); 1996 dst->IterateBodyFast(dst->map()->instance_type(), size, record_visitor_);
1823 } else { 1997 } else {
1824 DCHECK_OBJECT_SIZE(size); 1998 DCHECK_OBJECT_SIZE(size);
1825 DCHECK(dest == NEW_SPACE); 1999 DCHECK(dest == NEW_SPACE);
1826 heap_->CopyBlock(dst_addr, src_addr, size); 2000 heap_->CopyBlock(dst_addr, src_addr, size);
2001 migration_observer_->Move(src, dst);
1827 } 2002 }
1828 if (mode == kProfiled) { 2003 if (mode == kProfiled) {
1829 heap_->OnMoveEvent(dst, src, size); 2004 heap_->OnMoveEvent(dst, src, size);
1830 } 2005 }
1831 base::NoBarrier_Store(reinterpret_cast<base::AtomicWord*>(src_addr), 2006 base::NoBarrier_Store(reinterpret_cast<base::AtomicWord*>(src_addr),
1832 reinterpret_cast<base::AtomicWord>(dst_addr)); 2007 reinterpret_cast<base::AtomicWord>(dst_addr));
1833 } 2008 }
1834 2009
1835 #ifdef VERIFY_HEAP 2010 #ifdef VERIFY_HEAP
1836 bool AbortCompactionForTesting(HeapObject* object) { 2011 bool AbortCompactionForTesting(HeapObject* object) {
(...skipping 11 matching lines...) Expand all
1848 } 2023 }
1849 } 2024 }
1850 } 2025 }
1851 return false; 2026 return false;
1852 } 2027 }
1853 #endif // VERIFY_HEAP 2028 #endif // VERIFY_HEAP
1854 2029
1855 Heap* heap_; 2030 Heap* heap_;
1856 CompactionSpaceCollection* compaction_spaces_; 2031 CompactionSpaceCollection* compaction_spaces_;
1857 RecordMigratedSlotVisitor* record_visitor_; 2032 RecordMigratedSlotVisitor* record_visitor_;
2033 MigrationObserver* migration_observer_;
1858 bool profiling_; 2034 bool profiling_;
1859 }; 2035 };
1860 2036
1861 class EvacuateNewSpaceVisitor final : public EvacuateVisitorBase { 2037 class EvacuateNewSpaceVisitor final : public EvacuateVisitorBase {
1862 public: 2038 public:
1863 static const intptr_t kLabSize = 4 * KB; 2039 static const intptr_t kLabSize = 4 * KB;
1864 static const intptr_t kMaxLabObjectSize = 256; 2040 static const intptr_t kMaxLabObjectSize = 256;
1865 2041
1866 explicit EvacuateNewSpaceVisitor(Heap* heap, 2042 explicit EvacuateNewSpaceVisitor(Heap* heap,
1867 CompactionSpaceCollection* compaction_spaces, 2043 CompactionSpaceCollection* compaction_spaces,
1868 RecordMigratedSlotVisitor* record_visitor, 2044 RecordMigratedSlotVisitor* record_visitor,
2045 MigrationObserver* migration_observer,
1869 base::HashMap* local_pretenuring_feedback) 2046 base::HashMap* local_pretenuring_feedback)
1870 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor), 2047 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor,
2048 migration_observer),
1871 buffer_(LocalAllocationBuffer::InvalidBuffer()), 2049 buffer_(LocalAllocationBuffer::InvalidBuffer()),
1872 space_to_allocate_(NEW_SPACE), 2050 space_to_allocate_(NEW_SPACE),
1873 promoted_size_(0), 2051 promoted_size_(0),
1874 semispace_copied_size_(0), 2052 semispace_copied_size_(0),
1875 local_pretenuring_feedback_(local_pretenuring_feedback) {} 2053 local_pretenuring_feedback_(local_pretenuring_feedback) {}
1876 2054
1877 inline bool Visit(HeapObject* object) override { 2055 inline bool Visit(HeapObject* object) override {
1878 heap_->UpdateAllocationSite<Heap::kCached>(object, 2056 heap_->UpdateAllocationSite<Heap::kCached>(object,
1879 local_pretenuring_feedback_); 2057 local_pretenuring_feedback_);
1880 int size = object->Size(); 2058 int size = object->Size();
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
2043 Heap* heap_; 2221 Heap* heap_;
2044 RecordMigratedSlotVisitor* record_visitor_; 2222 RecordMigratedSlotVisitor* record_visitor_;
2045 intptr_t moved_bytes_; 2223 intptr_t moved_bytes_;
2046 base::HashMap* local_pretenuring_feedback_; 2224 base::HashMap* local_pretenuring_feedback_;
2047 }; 2225 };
2048 2226
2049 class EvacuateOldSpaceVisitor final : public EvacuateVisitorBase { 2227 class EvacuateOldSpaceVisitor final : public EvacuateVisitorBase {
2050 public: 2228 public:
2051 EvacuateOldSpaceVisitor(Heap* heap, 2229 EvacuateOldSpaceVisitor(Heap* heap,
2052 CompactionSpaceCollection* compaction_spaces, 2230 CompactionSpaceCollection* compaction_spaces,
2053 RecordMigratedSlotVisitor* record_visitor) 2231 RecordMigratedSlotVisitor* record_visitor,
2054 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor) {} 2232 MigrationObserver* migration_observer)
2233 : EvacuateVisitorBase(heap, compaction_spaces, record_visitor,
2234 migration_observer) {}
2055 2235
2056 inline bool Visit(HeapObject* object) override { 2236 inline bool Visit(HeapObject* object) override {
2057 CompactionSpace* target_space = compaction_spaces_->Get( 2237 CompactionSpace* target_space = compaction_spaces_->Get(
2058 Page::FromAddress(object->address())->owner()->identity()); 2238 Page::FromAddress(object->address())->owner()->identity());
2059 HeapObject* target_object = nullptr; 2239 HeapObject* target_object = nullptr;
2060 if (TryEvacuateObject(target_space, object, &target_object)) { 2240 if (TryEvacuateObject(target_space, object, &target_object)) {
2061 DCHECK(object->map_word().IsForwardingAddress()); 2241 DCHECK(object->map_word().IsForwardingAddress());
2062 return true; 2242 return true;
2063 } 2243 }
2064 return false; 2244 return false;
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
2404 heap_object); 2584 heap_object);
2405 return KEEP_SLOT; 2585 return KEEP_SLOT;
2406 } 2586 }
2407 return REMOVE_SLOT; 2587 return REMOVE_SLOT;
2408 } 2588 }
2409 2589
2410 static bool IsUnmarkedObject(Heap* heap, Object** p) { 2590 static bool IsUnmarkedObject(Heap* heap, Object** p) {
2411 DCHECK_IMPLIES(heap->InNewSpace(*p), heap->InToSpace(*p)); 2591 DCHECK_IMPLIES(heap->InNewSpace(*p), heap->InToSpace(*p));
2412 return heap->InNewSpace(*p) && 2592 return heap->InNewSpace(*p) &&
2413 !ObjectMarking::IsBlack(HeapObject::cast(*p), 2593 !ObjectMarking::IsBlack(HeapObject::cast(*p),
2414 MarkingState::Internal(HeapObject::cast(*p))); 2594 MarkingState::External(HeapObject::cast(*p)));
2415 } 2595 }
2416 2596
2417 void MinorMarkCompactCollector::MarkLiveObjects() { 2597 void MinorMarkCompactCollector::MarkLiveObjects() {
2418 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK); 2598 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK);
2419 2599
2420 PostponeInterruptsScope postpone(isolate()); 2600 PostponeInterruptsScope postpone(isolate());
2421 2601
2422 StaticYoungGenerationMarkingVisitor::Initialize(heap()); 2602 StaticYoungGenerationMarkingVisitor::Initialize(heap());
2423 RootMarkingVisitor root_visitor(this); 2603 RootMarkingVisitor root_visitor(this);
2424 2604
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2456 heap()->IterateEncounteredWeakCollections(&root_visitor); 2636 heap()->IterateEncounteredWeakCollections(&root_visitor);
2457 ProcessMarkingDeque(); 2637 ProcessMarkingDeque();
2458 } 2638 }
2459 2639
2460 { 2640 {
2461 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_GLOBAL_HANDLES); 2641 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_MARK_GLOBAL_HANDLES);
2462 isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending( 2642 isolate()->global_handles()->MarkNewSpaceWeakUnmodifiedObjectsPending(
2463 &IsUnmarkedObject); 2643 &IsUnmarkedObject);
2464 isolate() 2644 isolate()
2465 ->global_handles() 2645 ->global_handles()
2466 ->IterateNewSpaceWeakUnmodifiedRoots<GlobalHandles::VISIT_OTHERS>( 2646 ->IterateNewSpaceWeakUnmodifiedRoots<
2467 &root_visitor); 2647 GlobalHandles::HANDLE_PHANTOM_NODES_VISIT_OTHERS>(&root_visitor);
2468 ProcessMarkingDeque(); 2648 ProcessMarkingDeque();
2469 } 2649 }
2470 2650
2471 marking_deque()->StopUsing(); 2651 marking_deque()->StopUsing();
2472 } 2652 }
2473 2653
2474 void MinorMarkCompactCollector::ProcessMarkingDeque() { 2654 void MinorMarkCompactCollector::ProcessMarkingDeque() {
2475 EmptyMarkingDeque(); 2655 EmptyMarkingDeque();
2476 DCHECK(!marking_deque()->overflowed()); 2656 DCHECK(!marking_deque()->overflowed());
2477 DCHECK(marking_deque()->IsEmpty()); 2657 DCHECK(marking_deque()->IsEmpty());
(...skipping 11 matching lines...) Expand all
2489 object, MarkingState::External(object)))); 2669 object, MarkingState::External(object))));
2490 2670
2491 Map* map = object->map(); 2671 Map* map = object->map();
2492 DCHECK((ObjectMarking::IsBlack<MarkBit::NON_ATOMIC>( 2672 DCHECK((ObjectMarking::IsBlack<MarkBit::NON_ATOMIC>(
2493 object, MarkingState::External(object)))); 2673 object, MarkingState::External(object))));
2494 StaticYoungGenerationMarkingVisitor::IterateBody(map, object); 2674 StaticYoungGenerationMarkingVisitor::IterateBody(map, object);
2495 } 2675 }
2496 } 2676 }
2497 2677
2498 void MinorMarkCompactCollector::CollectGarbage() { 2678 void MinorMarkCompactCollector::CollectGarbage() {
2679 heap()->mark_compact_collector()->sweeper().EnsureNewSpaceCompleted();
2680
2499 MarkLiveObjects(); 2681 MarkLiveObjects();
2500 2682 ClearNonLiveReferences();
2501 #ifdef VERIFY_HEAP 2683 #ifdef VERIFY_HEAP
2502 if (FLAG_verify_heap) { 2684 if (FLAG_verify_heap) {
2503 YoungGenerationMarkingVerifier verifier(heap()); 2685 YoungGenerationMarkingVerifier verifier(heap());
2504 verifier.Run(); 2686 verifier.Run();
2505 } 2687 }
2506 #endif // VERIFY_HEAP 2688 #endif // VERIFY_HEAP
2689
2690 std::vector<HeapObject*> black_allocation_objects;
2691 EvacuateNewSpace(&black_allocation_objects);
2692 #ifdef VERIFY_HEAP
2693 if (FLAG_verify_heap) {
2694 YoungGenerationEvacuationVerifier verifier(heap());
2695 verifier.Run();
2696 }
2697 #endif // VERIFY_HEAP
2698
2699 heap()->incremental_marking()->UpdateMarkingDequeAfterScavenge();
2700
2701 // Process black allocation objects after updating pointers as we otherwise
2702 // would end up with objects on the marking deque that potentially forward
2703 // to white objects.
2704 // TODO(mlippautz): Instead of processing them explicitly, we should just add
2705 // them to the marking deque for further processing.
2706 {
2707 TRACE_GC(heap()->tracer(),
2708 GCTracer::Scope::MINOR_MC_EVACUATE_PROCESS_BLACK_ALLOCATION);
2709 for (HeapObject* object : black_allocation_objects) {
2710 CHECK(ObjectMarking::IsBlack(object, MarkingState::Internal(object)));
2711 heap()->incremental_marking()->IterateBlackObject(object);
2712 }
2713 heap()->local_embedder_heap_tracer()->RegisterWrappersWithRemoteTracer();
2714 }
2715
2716 {
2717 TRACE_GC(heap()->tracer(), GCTracer::Scope::MINOR_MC_CLEAR_LIVENESS);
2718 for (Page* p : PageRange(heap()->new_space()->FromSpaceStart(),
2719 heap()->new_space()->FromSpaceEnd())) {
2720 marking_state(p).ClearLiveness();
2721 }
2722 }
2723 }
2724
2725 void MinorMarkCompactCollector::ClearNonLiveReferences() {
2726 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR);
2727
2728 {
2729 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_STRING_TABLE);
2730 // Internalized strings are always stored in old space, so there is no need
2731 // to clean them here.
2732 YoungGenerationExternalStringTableCleaner external_visitor(*this);
2733 heap()->external_string_table_.IterateNewSpaceStrings(&external_visitor);
2734 heap()->external_string_table_.CleanUpNewSpaceStrings();
2735 }
2736
2737 {
2738 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_WEAK_LISTS);
2739 // Process the weak references.
2740 MinorMarkCompactWeakObjectRetainer retainer(*this);
2741 heap()->ProcessYoungWeakReferences(&retainer);
2742 }
2743 }
2744
2745 void MinorMarkCompactCollector::EvacuatePrologue() {
2746 NewSpace* new_space = heap()->new_space();
2747 // Append the list of new space pages to be processed.
2748 for (Page* p : PageRange(new_space->bottom(), new_space->top())) {
2749 new_space_evacuation_pages_.Add(p);
2750 }
2751 new_space->Flip();
2752 new_space->ResetAllocationInfo();
2753 }
2754
2755 void MinorMarkCompactCollector::EvacuateEpilogue() {
2756 heap()->new_space()->set_age_mark(heap()->new_space()->top());
2757 }
2758
2759 void MinorMarkCompactCollector::EvacuateNewSpace(
2760 std::vector<HeapObject*>* black_allocation_objects) {
2761 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE);
2762 Heap::RelocationLock relocation_lock(heap());
2763
2764 {
2765 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_PROLOGUE);
2766 EvacuatePrologue();
2767 }
2768
2769 {
2770 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_COPY);
2771 EvacuatePagesInParallel(black_allocation_objects);
2772 }
2773
2774 UpdatePointersAfterEvacuation();
2775
2776 {
2777 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_REBALANCE);
2778 if (!heap()->new_space()->Rebalance()) {
2779 FatalProcessOutOfMemory("NewSpace::Rebalance");
2780 }
2781 }
2782
2783 // Give pages that are queued to be freed back to the OS.
2784 heap()->memory_allocator()->unmapper()->FreeQueuedChunks();
2785
2786 {
2787 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_CLEAN_UP);
2788 // TODO(mlippautz): Implement page promotion.
2789 new_space_evacuation_pages_.Rewind(0);
2790 }
2791
2792 {
2793 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_EPILOGUE);
2794 EvacuateEpilogue();
2795 }
2507 } 2796 }
2508 2797
2509 void MarkCompactCollector::MarkLiveObjects() { 2798 void MarkCompactCollector::MarkLiveObjects() {
2510 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK); 2799 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_MARK);
2511 // The recursive GC marker detects when it is nearing stack overflow, 2800 // The recursive GC marker detects when it is nearing stack overflow,
2512 // and switches to a different marking system. JS interrupts interfere 2801 // and switches to a different marking system. JS interrupts interfere
2513 // with the C stack limit check. 2802 // with the C stack limit check.
2514 PostponeInterruptsScope postpone(isolate()); 2803 PostponeInterruptsScope postpone(isolate());
2515 2804
2516 { 2805 {
(...skipping 659 matching lines...) Expand 10 before | Expand all | Expand 10 after
3176 } 3465 }
3177 3466
3178 // NewSpacePages with more live bytes than this threshold qualify for fast 3467 // NewSpacePages with more live bytes than this threshold qualify for fast
3179 // evacuation. 3468 // evacuation.
3180 static int PageEvacuationThreshold() { 3469 static int PageEvacuationThreshold() {
3181 if (FLAG_page_promotion) 3470 if (FLAG_page_promotion)
3182 return FLAG_page_promotion_threshold * Page::kAllocatableMemory / 100; 3471 return FLAG_page_promotion_threshold * Page::kAllocatableMemory / 100;
3183 return Page::kAllocatableMemory + kPointerSize; 3472 return Page::kAllocatableMemory + kPointerSize;
3184 } 3473 }
3185 3474
3186 Evacuator(Heap* heap, RecordMigratedSlotVisitor* record_visitor) 3475 Evacuator(Heap* heap, RecordMigratedSlotVisitor* record_visitor,
3476 MigrationObserver* migration_observer)
3187 : heap_(heap), 3477 : heap_(heap),
3188 compaction_spaces_(heap_), 3478 compaction_spaces_(heap_),
3189 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity), 3479 local_pretenuring_feedback_(kInitialLocalPretenuringFeedbackCapacity),
3190 new_space_visitor_(heap_, &compaction_spaces_, record_visitor, 3480 new_space_visitor_(heap_, &compaction_spaces_, record_visitor,
3191 &local_pretenuring_feedback_), 3481 migration_observer, &local_pretenuring_feedback_),
3192 new_to_new_page_visitor_(heap_, record_visitor, 3482 new_to_new_page_visitor_(heap_, record_visitor,
3193 &local_pretenuring_feedback_), 3483 &local_pretenuring_feedback_),
3194 new_to_old_page_visitor_(heap_, record_visitor, 3484 new_to_old_page_visitor_(heap_, record_visitor,
3195 &local_pretenuring_feedback_), 3485 &local_pretenuring_feedback_),
3196 3486
3197 old_space_visitor_(heap_, &compaction_spaces_, record_visitor), 3487 old_space_visitor_(heap_, &compaction_spaces_, record_visitor,
3488 migration_observer),
3198 duration_(0.0), 3489 duration_(0.0),
3199 bytes_compacted_(0) {} 3490 bytes_compacted_(0) {}
3200 3491
3201 virtual ~Evacuator() {} 3492 virtual ~Evacuator() {}
3202 3493
3203 bool EvacuatePage(Page* page); 3494 bool EvacuatePage(Page* page);
3204 3495
3205 // Merge back locally cached info sequentially. Note that this method needs 3496 // Merge back locally cached info sequentially. Note that this method needs
3206 // to be called from the main thread. 3497 // to be called from the main thread.
3207 inline void Finalize(); 3498 inline void Finalize();
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
3283 new_space_visitor_.promoted_size() + 3574 new_space_visitor_.promoted_size() +
3284 new_space_visitor_.semispace_copied_size() + 3575 new_space_visitor_.semispace_copied_size() +
3285 new_to_old_page_visitor_.moved_bytes() + 3576 new_to_old_page_visitor_.moved_bytes() +
3286 new_to_new_page_visitor_.moved_bytes()); 3577 new_to_new_page_visitor_.moved_bytes());
3287 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_); 3578 heap()->MergeAllocationSitePretenuringFeedback(local_pretenuring_feedback_);
3288 } 3579 }
3289 3580
3290 class FullEvacuator : public Evacuator { 3581 class FullEvacuator : public Evacuator {
3291 public: 3582 public:
3292 FullEvacuator(MarkCompactCollector* collector, 3583 FullEvacuator(MarkCompactCollector* collector,
3293 RecordMigratedSlotVisitor* record_visitor) 3584 RecordMigratedSlotVisitor* record_visitor,
3294 : Evacuator(collector->heap(), record_visitor), collector_(collector) {} 3585 MigrationObserver* migration_observer)
3586 : Evacuator(collector->heap(), record_visitor, migration_observer),
3587 collector_(collector) {}
3295 3588
3296 protected: 3589 protected:
3297 bool RawEvacuatePage(Page* page, intptr_t* live_bytes) override; 3590 bool RawEvacuatePage(Page* page, intptr_t* live_bytes) override;
3298 3591
3299 MarkCompactCollector* collector_; 3592 MarkCompactCollector* collector_;
3300 }; 3593 };
3301 3594
3302 bool FullEvacuator::RawEvacuatePage(Page* page, intptr_t* live_bytes) { 3595 bool FullEvacuator::RawEvacuatePage(Page* page, intptr_t* live_bytes) {
3303 bool success = false; 3596 bool success = false;
3304 LiveObjectVisitor object_visitor; 3597 LiveObjectVisitor object_visitor;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
3348 success = false; 3641 success = false;
3349 } else { 3642 } else {
3350 ArrayBufferTracker::ProcessBuffers( 3643 ArrayBufferTracker::ProcessBuffers(
3351 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers); 3644 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
3352 } 3645 }
3353 break; 3646 break;
3354 } 3647 }
3355 return success; 3648 return success;
3356 } 3649 }
3357 3650
3651 class YoungGenerationEvacuator : public Evacuator {
3652 public:
3653 YoungGenerationEvacuator(MinorMarkCompactCollector* collector,
3654 RecordMigratedSlotVisitor* record_visitor,
3655 MigrationObserver* migration_observer)
3656 : Evacuator(collector->heap(), record_visitor, migration_observer),
3657 collector_(collector) {}
3658
3659 protected:
3660 bool RawEvacuatePage(Page* page, intptr_t* live_bytes) override;
3661
3662 MinorMarkCompactCollector* collector_;
3663 };
3664
3665 bool YoungGenerationEvacuator::RawEvacuatePage(Page* page,
3666 intptr_t* live_bytes) {
3667 bool success = false;
3668 LiveObjectVisitor object_visitor;
3669 const MarkingState state = collector_->marking_state(page);
3670 *live_bytes = state.live_bytes();
3671 switch (ComputeEvacuationMode(page)) {
3672 case kObjectsNewToOld:
3673 success = object_visitor.VisitBlackObjects(
3674 page, state, &new_space_visitor_, LiveObjectVisitor::kClearMarkbits);
3675 DCHECK(success);
3676 ArrayBufferTracker::ProcessBuffers(
3677 page, ArrayBufferTracker::kUpdateForwardedRemoveOthers);
3678 break;
3679 case kPageNewToOld:
3680 // TODO(mlippautz): Implement page promotion.
3681 UNREACHABLE();
3682 break;
3683 case kPageNewToNew:
3684 // TODO(mlippautz): Implement page promotion.
3685 UNREACHABLE();
3686 break;
3687 case kObjectsOldToOld:
3688 UNREACHABLE();
3689 break;
3690 }
3691 return success;
3692 }
3693
3358 class EvacuationJobTraits { 3694 class EvacuationJobTraits {
3359 public: 3695 public:
3360 typedef int* PerPageData; // Pointer to number of aborted pages. 3696 struct PageData {
3697 int* abandoned_pages; // Pointer to number of aborted pages.
3698 MarkingState marking_state;
3699 };
3700
3701 typedef PageData PerPageData;
3361 typedef Evacuator* PerTaskData; 3702 typedef Evacuator* PerTaskData;
3362 3703
3363 static const bool NeedSequentialFinalization = true; 3704 static const bool NeedSequentialFinalization = true;
3364 3705
3365 static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator, 3706 static bool ProcessPageInParallel(Heap* heap, PerTaskData evacuator,
3366 MemoryChunk* chunk, PerPageData) { 3707 MemoryChunk* chunk, PerPageData) {
3367 return evacuator->EvacuatePage(reinterpret_cast<Page*>(chunk)); 3708 return evacuator->EvacuatePage(reinterpret_cast<Page*>(chunk));
3368 } 3709 }
3369 3710
3370 static void FinalizePageSequentially(Heap* heap, MemoryChunk* chunk, 3711 static void FinalizePageSequentially(Heap* heap, MemoryChunk* chunk,
(...skipping 12 matching lines...) Expand all
3383 if (success) { 3724 if (success) {
3384 DCHECK(p->IsEvacuationCandidate()); 3725 DCHECK(p->IsEvacuationCandidate());
3385 DCHECK(p->SweepingDone()); 3726 DCHECK(p->SweepingDone());
3386 p->Unlink(); 3727 p->Unlink();
3387 } else { 3728 } else {
3388 // We have partially compacted the page, i.e., some objects may have 3729 // We have partially compacted the page, i.e., some objects may have
3389 // moved, others are still in place. 3730 // moved, others are still in place.
3390 p->ClearEvacuationCandidate(); 3731 p->ClearEvacuationCandidate();
3391 // Slots have already been recorded so we just need to add it to the 3732 // Slots have already been recorded so we just need to add it to the
3392 // sweeper, which will happen after updating pointers. 3733 // sweeper, which will happen after updating pointers.
3393 *data += 1; 3734 *data.abandoned_pages += 1;
3394 } 3735 }
3395 break; 3736 break;
3396 default: 3737 default:
3397 UNREACHABLE(); 3738 UNREACHABLE();
3398 } 3739 }
3399 } 3740 }
3400 }; 3741 };
3401 3742
3743 template <class Evacuator, class Collector>
3744 void MarkCompactCollectorBase::CreateAndExecuteEvacuationTasks(
3745 Collector* collector, PageParallelJob<EvacuationJobTraits>* job,
3746 RecordMigratedSlotVisitor* record_visitor, MigrationObserver* observer,
3747 const intptr_t live_bytes, const int& abandoned_pages) {
3748 // Used for trace summary.
3749 double compaction_speed = 0;
3750 if (FLAG_trace_evacuation) {
3751 compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
3752 }
3753
3754 const int wanted_num_tasks =
3755 NumberOfParallelCompactionTasks(job->NumberOfPages(), live_bytes);
3756 Evacuator** evacuators = new Evacuator*[wanted_num_tasks];
3757 for (int i = 0; i < wanted_num_tasks; i++) {
3758 evacuators[i] = new Evacuator(collector, record_visitor, observer);
3759 }
3760 job->Run(wanted_num_tasks, [evacuators](int i) { return evacuators[i]; });
3761 const Address top = heap()->new_space()->top();
3762 for (int i = 0; i < wanted_num_tasks; i++) {
3763 evacuators[i]->Finalize();
3764 // Try to find the last LAB that was used for new space allocation in
3765 // evacuation tasks. If it was adjacent to the current top, move top back.
3766 const AllocationInfo info = evacuators[i]->CloseNewSpaceLAB();
3767 if (info.limit() != nullptr && info.limit() == top) {
3768 DCHECK_NOT_NULL(info.top());
3769 *heap()->new_space()->allocation_top_address() = info.top();
3770 }
3771 delete evacuators[i];
3772 }
3773 delete[] evacuators;
3774
3775 if (FLAG_trace_evacuation) {
3776 PrintIsolate(isolate(),
3777 "%8.0f ms: evacuation-summary: parallel=%s pages=%d "
3778 "aborted=%d wanted_tasks=%d tasks=%d cores=%" PRIuS
3779 " live_bytes=%" V8PRIdPTR " compaction_speed=%.f\n",
3780 isolate()->time_millis_since_init(),
3781 FLAG_parallel_compaction ? "yes" : "no", job->NumberOfPages(),
3782 abandoned_pages, wanted_num_tasks, job->NumberOfTasks(),
3783 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads(),
3784 live_bytes, compaction_speed);
3785 }
3786 }
3787
3402 void MarkCompactCollector::EvacuatePagesInParallel() { 3788 void MarkCompactCollector::EvacuatePagesInParallel() {
3403 PageParallelJob<EvacuationJobTraits> job( 3789 PageParallelJob<EvacuationJobTraits> job(
3404 heap_, heap_->isolate()->cancelable_task_manager(), 3790 heap_, heap_->isolate()->cancelable_task_manager(),
3405 &page_parallel_job_semaphore_); 3791 &page_parallel_job_semaphore_);
3406 3792
3407 int abandoned_pages = 0; 3793 int abandoned_pages = 0;
3408 intptr_t live_bytes = 0; 3794 intptr_t live_bytes = 0;
3409 for (Page* page : old_space_evacuation_pages_) { 3795 for (Page* page : old_space_evacuation_pages_) {
3410 live_bytes += MarkingState::Internal(page).live_bytes(); 3796 live_bytes += MarkingState::Internal(page).live_bytes();
3411 job.AddPage(page, &abandoned_pages); 3797 job.AddPage(page, {&abandoned_pages, marking_state(page)});
3412 } 3798 }
3413 3799
3414 const bool reduce_memory = heap()->ShouldReduceMemory(); 3800 const bool reduce_memory = heap()->ShouldReduceMemory();
3415 const Address age_mark = heap()->new_space()->age_mark(); 3801 const Address age_mark = heap()->new_space()->age_mark();
3416 for (Page* page : new_space_evacuation_pages_) { 3802 for (Page* page : new_space_evacuation_pages_) {
3417 intptr_t live_bytes_on_page = MarkingState::Internal(page).live_bytes(); 3803 intptr_t live_bytes_on_page = MarkingState::Internal(page).live_bytes();
3418 live_bytes += live_bytes_on_page; 3804 live_bytes += live_bytes_on_page;
3419 if (!reduce_memory && !page->NeverEvacuate() && 3805 if (!reduce_memory && !page->NeverEvacuate() &&
3420 (live_bytes_on_page > Evacuator::PageEvacuationThreshold()) && 3806 (live_bytes_on_page > Evacuator::PageEvacuationThreshold()) &&
3421 !page->Contains(age_mark) && 3807 !page->Contains(age_mark) &&
3422 heap()->CanExpandOldGeneration(live_bytes_on_page)) { 3808 heap()->CanExpandOldGeneration(live_bytes_on_page)) {
3423 if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) { 3809 if (page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK)) {
3424 EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page); 3810 EvacuateNewSpacePageVisitor<NEW_TO_OLD>::Move(page);
3425 } else { 3811 } else {
3426 EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page); 3812 EvacuateNewSpacePageVisitor<NEW_TO_NEW>::Move(page);
3427 } 3813 }
3428 } 3814 }
3429 3815
3430 job.AddPage(page, &abandoned_pages); 3816 job.AddPage(page, {&abandoned_pages, marking_state(page)});
3431 } 3817 }
3432 DCHECK_GE(job.NumberOfPages(), 1); 3818 DCHECK_GE(job.NumberOfPages(), 1);
3433 3819
3434 // Used for trace summary. 3820 MigrationObserver observer(heap());
3435 double compaction_speed = 0; 3821 RecordMigratedSlotVisitor record_visitor(this);
3436 if (FLAG_trace_evacuation) { 3822 CreateAndExecuteEvacuationTasks<FullEvacuator>(
3437 compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); 3823 this, &job, &record_visitor, &observer, live_bytes, abandoned_pages);
3824 }
3825
3826 void MinorMarkCompactCollector::EvacuatePagesInParallel(
3827 std::vector<HeapObject*>* black_allocation_objects) {
3828 PageParallelJob<EvacuationJobTraits> job(
3829 heap_, heap_->isolate()->cancelable_task_manager(),
3830 &page_parallel_job_semaphore_);
3831 int abandoned_pages = 0;
3832 intptr_t live_bytes = 0;
3833
3834 for (Page* page : new_space_evacuation_pages_) {
3835 intptr_t live_bytes_on_page = marking_state(page).live_bytes();
3836 live_bytes += live_bytes_on_page;
3837 // TODO(mlippautz): Implement page promotion.
3838 job.AddPage(page, {&abandoned_pages, marking_state(page)});
3438 } 3839 }
3840 DCHECK_GE(job.NumberOfPages(), 1);
3439 3841
3440 const int wanted_num_tasks = 3842 YoungGenerationMigrationObserver observer(
3441 NumberOfParallelCompactionTasks(job.NumberOfPages(), live_bytes); 3843 heap(), heap()->mark_compact_collector(), black_allocation_objects);
3442 FullEvacuator** evacuators = new FullEvacuator*[wanted_num_tasks]; 3844 YoungGenerationRecordMigratedSlotVisitor record_visitor(
3443 RecordMigratedSlotVisitor record_visitor(this); 3845 heap()->mark_compact_collector());
3444 for (int i = 0; i < wanted_num_tasks; i++) { 3846 CreateAndExecuteEvacuationTasks<YoungGenerationEvacuator>(
3445 evacuators[i] = new FullEvacuator(this, &record_visitor); 3847 this, &job, &record_visitor, &observer, live_bytes, abandoned_pages);
3446 }
3447 job.Run(wanted_num_tasks, [evacuators](int i) { return evacuators[i]; });
3448 const Address top = heap()->new_space()->top();
3449 for (int i = 0; i < wanted_num_tasks; i++) {
3450 evacuators[i]->Finalize();
3451 // Try to find the last LAB that was used for new space allocation in
3452 // evacuation tasks. If it was adjacent to the current top, move top back.
3453 const AllocationInfo info = evacuators[i]->CloseNewSpaceLAB();
3454 if (info.limit() != nullptr && info.limit() == top) {
3455 DCHECK_NOT_NULL(info.top());
3456 *heap()->new_space()->allocation_top_address() = info.top();
3457 }
3458 delete evacuators[i];
3459 }
3460 delete[] evacuators;
3461
3462 if (FLAG_trace_evacuation) {
3463 PrintIsolate(isolate(),
3464 "%8.0f ms: evacuation-summary: parallel=%s pages=%d "
3465 "aborted=%d wanted_tasks=%d tasks=%d cores=%" PRIuS
3466 " live_bytes=%" V8PRIdPTR " compaction_speed=%.f\n",
3467 isolate()->time_millis_since_init(),
3468 FLAG_parallel_compaction ? "yes" : "no", job.NumberOfPages(),
3469 abandoned_pages, wanted_num_tasks, job.NumberOfTasks(),
3470 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads(),
3471 live_bytes, compaction_speed);
3472 }
3473 } 3848 }
3474 3849
3475 class EvacuationWeakObjectRetainer : public WeakObjectRetainer { 3850 class EvacuationWeakObjectRetainer : public WeakObjectRetainer {
3476 public: 3851 public:
3477 virtual Object* RetainAs(Object* object) { 3852 virtual Object* RetainAs(Object* object) {
3478 if (object->IsHeapObject()) { 3853 if (object->IsHeapObject()) {
3479 HeapObject* heap_object = HeapObject::cast(object); 3854 HeapObject* heap_object = HeapObject::cast(object);
3480 MapWord map_word = heap_object->map_word(); 3855 MapWord map_word = heap_object->map_word();
3481 if (map_word.IsForwardingAddress()) { 3856 if (map_word.IsForwardingAddress()) {
3482 return map_word.ToForwardingAddress(); 3857 return map_word.ToForwardingAddress();
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after
3787 UpdateUntypedPointers(heap, chunk); 4162 UpdateUntypedPointers(heap, chunk);
3788 UpdateTypedPointers(heap, chunk); 4163 UpdateTypedPointers(heap, chunk);
3789 return true; 4164 return true;
3790 } 4165 }
3791 static const bool NeedSequentialFinalization = false; 4166 static const bool NeedSequentialFinalization = false;
3792 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { 4167 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) {
3793 } 4168 }
3794 4169
3795 private: 4170 private:
3796 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) { 4171 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) {
4172 base::LockGuard<base::RecursiveMutex> guard(chunk->mutex());
3797 if (type == OLD_TO_NEW) { 4173 if (type == OLD_TO_NEW) {
3798 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) { 4174 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) {
3799 return CheckAndUpdateOldToNewSlot(heap, slot); 4175 return CheckAndUpdateOldToNewSlot(heap, slot);
3800 }); 4176 });
3801 } else { 4177 } else {
3802 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) { 4178 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) {
3803 return UpdateSlot(reinterpret_cast<Object**>(slot)); 4179 return UpdateSlot(reinterpret_cast<Object**>(slot));
3804 }); 4180 });
3805 } 4181 }
3806 } 4182 }
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
3893 heap, heap->isolate()->cancelable_task_manager(), semaphore); 4269 heap, heap->isolate()->cancelable_task_manager(), semaphore);
3894 RememberedSet<type>::IterateMemoryChunks( 4270 RememberedSet<type>::IterateMemoryChunks(
3895 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); }); 4271 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); });
3896 int num_pages = job.NumberOfPages(); 4272 int num_pages = job.NumberOfPages();
3897 int num_tasks = NumberOfPointerUpdateTasks(num_pages); 4273 int num_tasks = NumberOfPointerUpdateTasks(num_pages);
3898 job.Run(num_tasks, [](int i) { return 0; }); 4274 job.Run(num_tasks, [](int i) { return 0; });
3899 } 4275 }
3900 4276
3901 class ToSpacePointerUpdateJobTraits { 4277 class ToSpacePointerUpdateJobTraits {
3902 public: 4278 public:
3903 typedef std::pair<Address, Address> PerPageData; 4279 struct PageData {
4280 Address start;
4281 Address end;
4282 MarkingState marking_state;
4283 };
4284
4285 typedef PageData PerPageData;
3904 typedef PointersUpdatingVisitor* PerTaskData; 4286 typedef PointersUpdatingVisitor* PerTaskData;
3905 4287
3906 static bool ProcessPageInParallel(Heap* heap, PerTaskData visitor, 4288 static bool ProcessPageInParallel(Heap* heap, PerTaskData visitor,
3907 MemoryChunk* chunk, PerPageData limits) { 4289 MemoryChunk* chunk, PerPageData page_data) {
3908 if (chunk->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION)) { 4290 if (chunk->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION)) {
3909 // New->new promoted pages contain garbage so they require iteration 4291 // New->new promoted pages contain garbage so they require iteration
3910 // using markbits. 4292 // using markbits.
3911 ProcessPageInParallelVisitLive(heap, visitor, chunk, limits); 4293 ProcessPageInParallelVisitLive(heap, visitor, chunk, page_data);
3912 } else { 4294 } else {
3913 ProcessPageInParallelVisitAll(heap, visitor, chunk, limits); 4295 ProcessPageInParallelVisitAll(heap, visitor, chunk, page_data);
3914 } 4296 }
3915 return true; 4297 return true;
3916 } 4298 }
3917 4299
3918 static const bool NeedSequentialFinalization = false; 4300 static const bool NeedSequentialFinalization = false;
3919 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { 4301 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) {
3920 } 4302 }
3921 4303
3922 private: 4304 private:
3923 static void ProcessPageInParallelVisitAll(Heap* heap, PerTaskData visitor, 4305 static void ProcessPageInParallelVisitAll(Heap* heap, PerTaskData visitor,
3924 MemoryChunk* chunk, 4306 MemoryChunk* chunk,
3925 PerPageData limits) { 4307 PerPageData page_data) {
3926 for (Address cur = limits.first; cur < limits.second;) { 4308 for (Address cur = page_data.start; cur < page_data.end;) {
3927 HeapObject* object = HeapObject::FromAddress(cur); 4309 HeapObject* object = HeapObject::FromAddress(cur);
3928 Map* map = object->map(); 4310 Map* map = object->map();
3929 int size = object->SizeFromMap(map); 4311 int size = object->SizeFromMap(map);
3930 object->IterateBody(map->instance_type(), size, visitor); 4312 object->IterateBody(map->instance_type(), size, visitor);
3931 cur += size; 4313 cur += size;
3932 } 4314 }
3933 } 4315 }
3934 4316
3935 static void ProcessPageInParallelVisitLive(Heap* heap, PerTaskData visitor, 4317 static void ProcessPageInParallelVisitLive(Heap* heap, PerTaskData visitor,
3936 MemoryChunk* chunk, 4318 MemoryChunk* chunk,
3937 PerPageData limits) { 4319 PerPageData page_data) {
3938 LiveObjectIterator<kBlackObjects> it(chunk, MarkingState::Internal(chunk)); 4320 LiveObjectIterator<kBlackObjects> it(chunk, page_data.marking_state);
3939 HeapObject* object = NULL; 4321 HeapObject* object = NULL;
3940 while ((object = it.Next()) != NULL) { 4322 while ((object = it.Next()) != NULL) {
3941 Map* map = object->map(); 4323 Map* map = object->map();
3942 int size = object->SizeFromMap(map); 4324 int size = object->SizeFromMap(map);
3943 object->IterateBody(map->instance_type(), size, visitor); 4325 object->IterateBody(map->instance_type(), size, visitor);
3944 } 4326 }
3945 } 4327 }
3946 }; 4328 };
3947 4329
3948 void UpdateToSpacePointersInParallel(Heap* heap, base::Semaphore* semaphore) { 4330 template <class MarkingStateProvider>
4331 void UpdateToSpacePointersInParallel(
4332 Heap* heap, base::Semaphore* semaphore,
4333 const MarkingStateProvider& marking_state_provider) {
3949 PageParallelJob<ToSpacePointerUpdateJobTraits> job( 4334 PageParallelJob<ToSpacePointerUpdateJobTraits> job(
3950 heap, heap->isolate()->cancelable_task_manager(), semaphore); 4335 heap, heap->isolate()->cancelable_task_manager(), semaphore);
3951 Address space_start = heap->new_space()->bottom(); 4336 Address space_start = heap->new_space()->bottom();
3952 Address space_end = heap->new_space()->top(); 4337 Address space_end = heap->new_space()->top();
3953 for (Page* page : PageRange(space_start, space_end)) { 4338 for (Page* page : PageRange(space_start, space_end)) {
3954 Address start = 4339 Address start =
3955 page->Contains(space_start) ? space_start : page->area_start(); 4340 page->Contains(space_start) ? space_start : page->area_start();
3956 Address end = page->Contains(space_end) ? space_end : page->area_end(); 4341 Address end = page->Contains(space_end) ? space_end : page->area_end();
3957 job.AddPage(page, std::make_pair(start, end)); 4342 job.AddPage(page, {start, end, marking_state_provider.marking_state(page)});
3958 } 4343 }
3959 PointersUpdatingVisitor visitor; 4344 PointersUpdatingVisitor visitor;
3960 int num_tasks = FLAG_parallel_pointer_update ? job.NumberOfPages() : 1; 4345 int num_tasks = FLAG_parallel_pointer_update ? job.NumberOfPages() : 1;
3961 job.Run(num_tasks, [&visitor](int i) { return &visitor; }); 4346 job.Run(num_tasks, [&visitor](int i) { return &visitor; });
3962 } 4347 }
3963 4348
3964 void MarkCompactCollector::UpdatePointersAfterEvacuation() { 4349 void MarkCompactCollector::UpdatePointersAfterEvacuation() {
3965 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS); 4350 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS);
3966 4351
3967 4352
3968 { 4353 {
3969 TRACE_GC(heap()->tracer(), 4354 TRACE_GC(heap()->tracer(),
3970 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW); 4355 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW);
3971 UpdateToSpacePointersInParallel(heap_, &page_parallel_job_semaphore_); 4356 UpdateToSpacePointersInParallel(heap_, &page_parallel_job_semaphore_,
4357 *this);
3972 // Update roots. 4358 // Update roots.
3973 PointersUpdatingVisitor updating_visitor; 4359 PointersUpdatingVisitor updating_visitor;
3974 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); 4360 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
3975 UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_); 4361 UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_);
3976 } 4362 }
3977 4363
3978 { 4364 {
3979 Heap* heap = this->heap(); 4365 Heap* heap = this->heap();
3980 TRACE_GC(heap->tracer(), 4366 TRACE_GC(heap->tracer(),
3981 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED); 4367 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_EVACUATED);
3982 UpdatePointersInParallel<OLD_TO_OLD>(heap_, &page_parallel_job_semaphore_); 4368 UpdatePointersInParallel<OLD_TO_OLD>(heap_, &page_parallel_job_semaphore_);
3983 } 4369 }
3984 4370
3985 { 4371 {
3986 TRACE_GC(heap()->tracer(), 4372 TRACE_GC(heap()->tracer(),
3987 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK); 4373 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK);
3988 // Update pointers from external string table. 4374 // Update pointers from external string table.
3989 heap_->UpdateReferencesInExternalStringTable( 4375 heap_->UpdateReferencesInExternalStringTable(
3990 &UpdateReferenceInExternalStringTableEntry); 4376 &UpdateReferenceInExternalStringTableEntry);
3991 4377
3992 EvacuationWeakObjectRetainer evacuation_object_retainer; 4378 EvacuationWeakObjectRetainer evacuation_object_retainer;
3993 heap()->ProcessWeakListRoots(&evacuation_object_retainer); 4379 heap()->ProcessWeakListRoots(&evacuation_object_retainer);
3994 } 4380 }
3995 } 4381 }
3996 4382
4383 void MinorMarkCompactCollector::UpdatePointersAfterEvacuation() {
4384 TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS);
4385
4386 PointersUpdatingVisitor updating_visitor;
4387
4388 {
4389 TRACE_GC(heap()->tracer(),
4390 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_TO_NEW);
4391 UpdateToSpacePointersInParallel(heap_, &page_parallel_job_semaphore_,
4392 *this);
4393 // TODO(mlippautz): Iteration mode is not optimal as we process all
4394 // global handles. Find a way to only process the ones related to new
4395 // space.
4396 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
4397 UpdatePointersInParallel<OLD_TO_NEW>(heap_, &page_parallel_job_semaphore_);
4398 }
4399
4400 {
4401 TRACE_GC(heap()->tracer(),
4402 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_WEAK);
4403
4404 EvacuationWeakObjectRetainer evacuation_object_retainer;
4405 heap()->ProcessWeakListRoots(&evacuation_object_retainer);
4406
4407 // Update pointers from external string table.
4408 heap()->UpdateNewSpaceReferencesInExternalStringTable(
4409 &UpdateReferenceInExternalStringTableEntry);
4410 heap()->IterateEncounteredWeakCollections(&updating_visitor);
4411 heap()->set_encountered_weak_collections(Smi::kZero);
4412 }
4413 }
3997 4414
3998 void MarkCompactCollector::ReleaseEvacuationCandidates() { 4415 void MarkCompactCollector::ReleaseEvacuationCandidates() {
3999 for (Page* p : old_space_evacuation_pages_) { 4416 for (Page* p : old_space_evacuation_pages_) {
4000 if (!p->IsEvacuationCandidate()) continue; 4417 if (!p->IsEvacuationCandidate()) continue;
4001 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 4418 PagedSpace* space = static_cast<PagedSpace*>(p->owner());
4002 MarkingState::Internal(p).SetLiveBytes(0); 4419 MarkingState::Internal(p).SetLiveBytes(0);
4003 CHECK(p->SweepingDone()); 4420 CHECK(p->SweepingDone());
4004 space->ReleasePage(p); 4421 space->ReleasePage(p);
4005 } 4422 }
4006 old_space_evacuation_pages_.Rewind(0); 4423 old_space_evacuation_pages_.Rewind(0);
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
4209 // The target is always in old space, we don't have to record the slot in 4626 // The target is always in old space, we don't have to record the slot in
4210 // the old-to-new remembered set. 4627 // the old-to-new remembered set.
4211 DCHECK(!heap()->InNewSpace(target)); 4628 DCHECK(!heap()->InNewSpace(target));
4212 RecordRelocSlot(host, &rinfo, target); 4629 RecordRelocSlot(host, &rinfo, target);
4213 } 4630 }
4214 } 4631 }
4215 } 4632 }
4216 4633
4217 } // namespace internal 4634 } // namespace internal
4218 } // namespace v8 4635 } // namespace v8
OLDNEW
« no previous file with comments | « src/heap/mark-compact.h ('k') | src/heap/spaces.h » ('j') | src/heap/spaces.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698