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

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

Issue 1577853007: [heap] Parallel newspace evacuation, semispace copy, and compaction \o/ (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase (2 changes factored out) and addressed comments Created 4 years, 11 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 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 void MarkCompactCollector::ClearInvalidStoreAndSlotsBufferEntries() { 313 void MarkCompactCollector::ClearInvalidStoreAndSlotsBufferEntries() {
314 { 314 {
315 GCTracer::Scope gc_scope(heap()->tracer(), 315 GCTracer::Scope gc_scope(heap()->tracer(),
316 GCTracer::Scope::MC_CLEAR_STORE_BUFFER); 316 GCTracer::Scope::MC_CLEAR_STORE_BUFFER);
317 heap_->store_buffer()->ClearInvalidStoreBufferEntries(); 317 heap_->store_buffer()->ClearInvalidStoreBufferEntries();
318 } 318 }
319 319
320 { 320 {
321 GCTracer::Scope gc_scope(heap()->tracer(), 321 GCTracer::Scope gc_scope(heap()->tracer(),
322 GCTracer::Scope::MC_CLEAR_SLOTS_BUFFER); 322 GCTracer::Scope::MC_CLEAR_SLOTS_BUFFER);
323 int number_of_pages = evacuation_candidates_.length(); 323 for (Page* p : evacuation_candidates_) {
324 for (int i = 0; i < number_of_pages; i++) {
325 Page* p = evacuation_candidates_[i];
326 SlotsBuffer::RemoveInvalidSlots(heap_, p->slots_buffer()); 324 SlotsBuffer::RemoveInvalidSlots(heap_, p->slots_buffer());
327 } 325 }
328 } 326 }
329 #ifdef VERIFY_HEAP 327 #ifdef VERIFY_HEAP
330 if (FLAG_verify_heap) { 328 if (FLAG_verify_heap) {
331 VerifyValidStoreAndSlotsBufferEntries(); 329 VerifyValidStoreAndSlotsBufferEntries();
332 } 330 }
333 #endif 331 #endif
334 } 332 }
335 333
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after
824 "compaction-selection: space=%s reduce_memory=%d pages=%d " 822 "compaction-selection: space=%s reduce_memory=%d pages=%d "
825 "total_live_bytes=%d\n", 823 "total_live_bytes=%d\n",
826 AllocationSpaceName(space->identity()), reduce_memory, 824 AllocationSpaceName(space->identity()), reduce_memory,
827 candidate_count, total_live_bytes / KB); 825 candidate_count, total_live_bytes / KB);
828 } 826 }
829 } 827 }
830 828
831 829
832 void MarkCompactCollector::AbortCompaction() { 830 void MarkCompactCollector::AbortCompaction() {
833 if (compacting_) { 831 if (compacting_) {
834 int npages = evacuation_candidates_.length(); 832 for (Page* p : evacuation_candidates_) {
835 for (int i = 0; i < npages; i++) {
836 Page* p = evacuation_candidates_[i];
837 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); 833 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address());
838 p->ClearEvacuationCandidate(); 834 p->ClearEvacuationCandidate();
839 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION); 835 p->ClearFlag(MemoryChunk::RESCAN_ON_EVACUATION);
840 } 836 }
841 compacting_ = false; 837 compacting_ = false;
842 evacuation_candidates_.Rewind(0); 838 evacuation_candidates_.Rewind(0);
843 } 839 }
844 DCHECK_EQ(0, evacuation_candidates_.length()); 840 DCHECK_EQ(0, evacuation_candidates_.length());
845 } 841 }
846 842
(...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after
1541 class MarkCompactCollector::HeapObjectVisitor { 1537 class MarkCompactCollector::HeapObjectVisitor {
1542 public: 1538 public:
1543 virtual ~HeapObjectVisitor() {} 1539 virtual ~HeapObjectVisitor() {}
1544 virtual bool Visit(HeapObject* object) = 0; 1540 virtual bool Visit(HeapObject* object) = 0;
1545 }; 1541 };
1546 1542
1547 1543
1548 class MarkCompactCollector::EvacuateVisitorBase 1544 class MarkCompactCollector::EvacuateVisitorBase
1549 : public MarkCompactCollector::HeapObjectVisitor { 1545 : public MarkCompactCollector::HeapObjectVisitor {
1550 public: 1546 public:
1551 EvacuateVisitorBase(Heap* heap, SlotsBuffer** evacuation_slots_buffer) 1547 EvacuateVisitorBase(Heap* heap, SlotsBuffer** evacuation_slots_buffer,
1552 : heap_(heap), evacuation_slots_buffer_(evacuation_slots_buffer) {} 1548 CompactionSpaceCollection* compaction_spaces)
1549 : heap_(heap),
1550 evacuation_slots_buffer_(evacuation_slots_buffer),
1551 compaction_spaces_(compaction_spaces) {}
1553 1552
1554 bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object, 1553 bool TryEvacuateObject(PagedSpace* target_space, HeapObject* object,
1555 HeapObject** target_object) { 1554 HeapObject** target_object) {
1556 int size = object->Size(); 1555 int size = object->Size();
1557 AllocationAlignment alignment = object->RequiredAlignment(); 1556 AllocationAlignment alignment = object->RequiredAlignment();
1558 AllocationResult allocation = target_space->AllocateRaw(size, alignment); 1557 AllocationResult allocation = target_space->AllocateRaw(size, alignment);
1559 if (allocation.To(target_object)) { 1558 if (allocation.To(target_object)) {
1560 heap_->mark_compact_collector()->MigrateObject( 1559 heap_->mark_compact_collector()->MigrateObject(
1561 *target_object, object, size, target_space->identity(), 1560 *target_object, object, size, target_space->identity(),
1562 evacuation_slots_buffer_); 1561 evacuation_slots_buffer_, compaction_spaces_->local_store_buffer());
1563 return true; 1562 return true;
1564 } 1563 }
1565 return false; 1564 return false;
1566 } 1565 }
1567 1566
1568 protected: 1567 protected:
1569 Heap* heap_; 1568 Heap* heap_;
1570 SlotsBuffer** evacuation_slots_buffer_; 1569 SlotsBuffer** evacuation_slots_buffer_;
1570 CompactionSpaceCollection* compaction_spaces_;
1571 }; 1571 };
1572 1572
1573 1573
1574 class MarkCompactCollector::EvacuateNewSpaceVisitor final 1574 class MarkCompactCollector::EvacuateNewSpaceVisitor final
1575 : public MarkCompactCollector::EvacuateVisitorBase { 1575 : public MarkCompactCollector::EvacuateVisitorBase {
1576 public: 1576 public:
1577 static const intptr_t kLabSize = 4 * KB; 1577 static const intptr_t kLabSize = 4 * KB;
1578 static const intptr_t kMaxLabObjectSize = 256; 1578 static const intptr_t kMaxLabObjectSize = 256;
1579 1579
1580 explicit EvacuateNewSpaceVisitor(Heap* heap, 1580 explicit EvacuateNewSpaceVisitor(Heap* heap,
1581 SlotsBuffer** evacuation_slots_buffer, 1581 SlotsBuffer** evacuation_slots_buffer,
1582 HashMap* local_pretenuring_feedback) 1582 CompactionSpaceCollection* compaction_spaces)
1583 : EvacuateVisitorBase(heap, evacuation_slots_buffer), 1583 : EvacuateVisitorBase(heap, evacuation_slots_buffer, compaction_spaces),
1584 buffer_(LocalAllocationBuffer::InvalidBuffer()), 1584 buffer_(LocalAllocationBuffer::InvalidBuffer()),
1585 space_to_allocate_(NEW_SPACE), 1585 space_to_allocate_(NEW_SPACE),
1586 promoted_size_(0), 1586 promoted_size_(0),
1587 semispace_copied_size_(0), 1587 semispace_copied_size_(0),
1588 local_pretenuring_feedback_(local_pretenuring_feedback) {} 1588 local_pretenuring_feedback_(
1589 compaction_spaces->local_pretenuring_feedback()) {}
1589 1590
1590 bool Visit(HeapObject* object) override { 1591 bool Visit(HeapObject* object) override {
1591 heap_->UpdateAllocationSite(object, local_pretenuring_feedback_); 1592 heap_->UpdateAllocationSite(object, local_pretenuring_feedback_);
1592 int size = object->Size(); 1593 int size = object->Size();
1593 HeapObject* target_object = nullptr; 1594 HeapObject* target_object = nullptr;
1594 if (heap_->ShouldBePromoted(object->address(), size) && 1595 if (heap_->ShouldBePromoted(object->address(), size) &&
1595 TryEvacuateObject(heap_->old_space(), object, &target_object)) { 1596 TryEvacuateObject(compaction_spaces_->Get(OLD_SPACE), object,
1597 &target_object)) {
1596 // If we end up needing more special cases, we should factor this out. 1598 // If we end up needing more special cases, we should factor this out.
1597 if (V8_UNLIKELY(target_object->IsJSArrayBuffer())) { 1599 if (V8_UNLIKELY(target_object->IsJSArrayBuffer())) {
1598 heap_->array_buffer_tracker()->Promote( 1600 heap_->array_buffer_tracker()->Promote(
1599 JSArrayBuffer::cast(target_object)); 1601 JSArrayBuffer::cast(target_object));
1600 } 1602 }
1601 promoted_size_ += size; 1603 promoted_size_ += size;
1602 return true; 1604 return true;
1603 } 1605 }
1604 HeapObject* target = nullptr; 1606 HeapObject* target = nullptr;
1605 AllocationSpace space = AllocateTargetObject(object, &target); 1607 AllocationSpace space = AllocateTargetObject(object, &target);
1606 heap_->mark_compact_collector()->MigrateObject( 1608 heap_->mark_compact_collector()->MigrateObject(
1607 HeapObject::cast(target), object, size, space, 1609 HeapObject::cast(target), object, size, space,
1608 (space == NEW_SPACE) ? nullptr : evacuation_slots_buffer_); 1610 (space == NEW_SPACE) ? nullptr : evacuation_slots_buffer_,
1611 compaction_spaces_->local_store_buffer());
1609 if (V8_UNLIKELY(target->IsJSArrayBuffer())) { 1612 if (V8_UNLIKELY(target->IsJSArrayBuffer())) {
1610 heap_->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(target)); 1613 heap_->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(target));
1611 } 1614 }
1612 semispace_copied_size_ += size; 1615 semispace_copied_size_ += size;
1613 return true; 1616 return true;
1614 } 1617 }
1615 1618
1616 intptr_t promoted_size() { return promoted_size_; } 1619 intptr_t promoted_size() { return promoted_size_; }
1617 intptr_t semispace_copied_size() { return semispace_copied_size_; } 1620 intptr_t semispace_copied_size() { return semispace_copied_size_; }
1618 1621
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1670 if (allocation.IsRetry()) { 1673 if (allocation.IsRetry()) {
1671 if (mode == kStickyBailoutOldSpace) space_to_allocate_ = OLD_SPACE; 1674 if (mode == kStickyBailoutOldSpace) space_to_allocate_ = OLD_SPACE;
1672 } 1675 }
1673 } 1676 }
1674 } 1677 }
1675 return allocation; 1678 return allocation;
1676 } 1679 }
1677 1680
1678 inline AllocationResult AllocateInOldSpace(int size_in_bytes, 1681 inline AllocationResult AllocateInOldSpace(int size_in_bytes,
1679 AllocationAlignment alignment) { 1682 AllocationAlignment alignment) {
1680 AllocationResult allocation = 1683 AllocationResult allocation = compaction_spaces_->Get(OLD_SPACE)
1681 heap_->old_space()->AllocateRaw(size_in_bytes, alignment); 1684 ->AllocateRaw(size_in_bytes, alignment);
1682 if (allocation.IsRetry()) { 1685 if (allocation.IsRetry()) {
1683 FatalProcessOutOfMemory( 1686 FatalProcessOutOfMemory(
1684 "MarkCompactCollector: semi-space copy, fallback in old gen\n"); 1687 "MarkCompactCollector: semi-space copy, fallback in old gen\n");
1685 } 1688 }
1686 return allocation; 1689 return allocation;
1687 } 1690 }
1688 1691
1689 inline AllocationResult AllocateInLab(int size_in_bytes, 1692 inline AllocationResult AllocateInLab(int size_in_bytes,
1690 AllocationAlignment alignment) { 1693 AllocationAlignment alignment) {
1691 AllocationResult allocation; 1694 AllocationResult allocation;
(...skipping 26 matching lines...) Expand all
1718 HashMap* local_pretenuring_feedback_; 1721 HashMap* local_pretenuring_feedback_;
1719 }; 1722 };
1720 1723
1721 1724
1722 class MarkCompactCollector::EvacuateOldSpaceVisitor final 1725 class MarkCompactCollector::EvacuateOldSpaceVisitor final
1723 : public MarkCompactCollector::EvacuateVisitorBase { 1726 : public MarkCompactCollector::EvacuateVisitorBase {
1724 public: 1727 public:
1725 EvacuateOldSpaceVisitor(Heap* heap, 1728 EvacuateOldSpaceVisitor(Heap* heap,
1726 CompactionSpaceCollection* compaction_spaces, 1729 CompactionSpaceCollection* compaction_spaces,
1727 SlotsBuffer** evacuation_slots_buffer) 1730 SlotsBuffer** evacuation_slots_buffer)
1728 : EvacuateVisitorBase(heap, evacuation_slots_buffer), 1731 : EvacuateVisitorBase(heap, evacuation_slots_buffer, compaction_spaces) {}
1729 compaction_spaces_(compaction_spaces) {}
1730 1732
1731 bool Visit(HeapObject* object) override { 1733 bool Visit(HeapObject* object) override {
1732 CompactionSpace* target_space = compaction_spaces_->Get( 1734 CompactionSpace* target_space = compaction_spaces_->Get(
1733 Page::FromAddress(object->address())->owner()->identity()); 1735 Page::FromAddress(object->address())->owner()->identity());
1734 HeapObject* target_object = nullptr; 1736 HeapObject* target_object = nullptr;
1735 if (TryEvacuateObject(target_space, object, &target_object)) { 1737 if (TryEvacuateObject(target_space, object, &target_object)) {
1736 DCHECK(object->map_word().IsForwardingAddress()); 1738 DCHECK(object->map_word().IsForwardingAddress());
1737 return true; 1739 return true;
1738 } 1740 }
1739 return false; 1741 return false;
1740 } 1742 }
1741 1743
1742 private: 1744 private:
1743 CompactionSpaceCollection* compaction_spaces_;
1744 }; 1745 };
1745 1746
1746 1747
1747 void MarkCompactCollector::DiscoverGreyObjectsInSpace(PagedSpace* space) { 1748 void MarkCompactCollector::DiscoverGreyObjectsInSpace(PagedSpace* space) {
1748 PageIterator it(space); 1749 PageIterator it(space);
1749 while (it.has_next()) { 1750 while (it.has_next()) {
1750 Page* p = it.next(); 1751 Page* p = it.next();
1751 DiscoverGreyObjectsOnPage(p); 1752 DiscoverGreyObjectsOnPage(p);
1752 if (marking_deque()->IsFull()) return; 1753 if (marking_deque()->IsFull()) return;
1753 } 1754 }
(...skipping 789 matching lines...) Expand 10 before | Expand all | Expand 10 after
2543 while (obj != Smi::FromInt(0)) { 2544 while (obj != Smi::FromInt(0)) {
2544 TransitionArray* array = TransitionArray::cast(obj); 2545 TransitionArray* array = TransitionArray::cast(obj);
2545 obj = array->next_link(); 2546 obj = array->next_link();
2546 array->set_next_link(undefined, SKIP_WRITE_BARRIER); 2547 array->set_next_link(undefined, SKIP_WRITE_BARRIER);
2547 } 2548 }
2548 heap()->set_encountered_transition_arrays(Smi::FromInt(0)); 2549 heap()->set_encountered_transition_arrays(Smi::FromInt(0));
2549 } 2550 }
2550 2551
2551 2552
2552 void MarkCompactCollector::RecordMigratedSlot( 2553 void MarkCompactCollector::RecordMigratedSlot(
2553 Object* value, Address slot, SlotsBuffer** evacuation_slots_buffer) { 2554 Object* value, Address slot, SlotsBuffer** evacuation_slots_buffer,
2555 LocalStoreBuffer* local_store_buffer) {
2554 // When parallel compaction is in progress, store and slots buffer entries 2556 // When parallel compaction is in progress, store and slots buffer entries
2555 // require synchronization. 2557 // require synchronization.
2556 if (heap_->InNewSpace(value)) { 2558 if (heap_->InNewSpace(value)) {
2557 if (compaction_in_progress_) { 2559 if (compaction_in_progress_) {
2558 heap_->store_buffer()->MarkSynchronized(slot); 2560 local_store_buffer->Record(slot);
2559 } else { 2561 } else {
2560 heap_->store_buffer()->Mark(slot); 2562 heap_->store_buffer()->Mark(slot);
2561 } 2563 }
2562 } else if (value->IsHeapObject() && IsOnEvacuationCandidate(value)) { 2564 } else if (value->IsHeapObject() && IsOnEvacuationCandidate(value)) {
2563 SlotsBuffer::AddTo(slots_buffer_allocator_, evacuation_slots_buffer, 2565 SlotsBuffer::AddTo(slots_buffer_allocator_, evacuation_slots_buffer,
2564 reinterpret_cast<Object**>(slot), 2566 reinterpret_cast<Object**>(slot),
2565 SlotsBuffer::IGNORE_OVERFLOW); 2567 SlotsBuffer::IGNORE_OVERFLOW);
2566 } 2568 }
2567 } 2569 }
2568 2570
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
2630 if (!success) { 2632 if (!success) {
2631 EvictPopularEvacuationCandidate(target_page); 2633 EvictPopularEvacuationCandidate(target_page);
2632 } 2634 }
2633 } 2635 }
2634 } 2636 }
2635 2637
2636 2638
2637 class RecordMigratedSlotVisitor final : public ObjectVisitor { 2639 class RecordMigratedSlotVisitor final : public ObjectVisitor {
2638 public: 2640 public:
2639 RecordMigratedSlotVisitor(MarkCompactCollector* collector, 2641 RecordMigratedSlotVisitor(MarkCompactCollector* collector,
2640 SlotsBuffer** evacuation_slots_buffer) 2642 SlotsBuffer** evacuation_slots_buffer,
2643 LocalStoreBuffer* local_store_buffer)
2641 : collector_(collector), 2644 : collector_(collector),
2642 evacuation_slots_buffer_(evacuation_slots_buffer) {} 2645 evacuation_slots_buffer_(evacuation_slots_buffer),
2646 local_store_buffer_(local_store_buffer) {}
2643 2647
2644 V8_INLINE void VisitPointer(Object** p) override { 2648 V8_INLINE void VisitPointer(Object** p) override {
2645 collector_->RecordMigratedSlot(*p, reinterpret_cast<Address>(p), 2649 collector_->RecordMigratedSlot(*p, reinterpret_cast<Address>(p),
2646 evacuation_slots_buffer_); 2650 evacuation_slots_buffer_,
2651 local_store_buffer_);
2647 } 2652 }
2648 2653
2649 V8_INLINE void VisitPointers(Object** start, Object** end) override { 2654 V8_INLINE void VisitPointers(Object** start, Object** end) override {
2650 while (start < end) { 2655 while (start < end) {
2651 collector_->RecordMigratedSlot(*start, reinterpret_cast<Address>(start), 2656 collector_->RecordMigratedSlot(*start, reinterpret_cast<Address>(start),
2652 evacuation_slots_buffer_); 2657 evacuation_slots_buffer_,
2658 local_store_buffer_);
2653 ++start; 2659 ++start;
2654 } 2660 }
2655 } 2661 }
2656 2662
2657 V8_INLINE void VisitCodeEntry(Address code_entry_slot) override { 2663 V8_INLINE void VisitCodeEntry(Address code_entry_slot) override {
2658 if (collector_->compacting_) { 2664 if (collector_->compacting_) {
2659 Address code_entry = Memory::Address_at(code_entry_slot); 2665 Address code_entry = Memory::Address_at(code_entry_slot);
2660 collector_->RecordMigratedCodeEntrySlot(code_entry, code_entry_slot, 2666 collector_->RecordMigratedCodeEntrySlot(code_entry, code_entry_slot,
2661 evacuation_slots_buffer_); 2667 evacuation_slots_buffer_);
2662 } 2668 }
2663 } 2669 }
2664 2670
2665 private: 2671 private:
2666 MarkCompactCollector* collector_; 2672 MarkCompactCollector* collector_;
2667 SlotsBuffer** evacuation_slots_buffer_; 2673 SlotsBuffer** evacuation_slots_buffer_;
2674 LocalStoreBuffer* local_store_buffer_;
2668 }; 2675 };
2669 2676
2670 2677
2671 // We scavenge new space simultaneously with sweeping. This is done in two 2678 // We scavenge new space simultaneously with sweeping. This is done in two
2672 // passes. 2679 // passes.
2673 // 2680 //
2674 // The first pass migrates all alive objects from one semispace to another or 2681 // The first pass migrates all alive objects from one semispace to another or
2675 // promotes them to old space. Forwarding address is written directly into 2682 // promotes them to old space. Forwarding address is written directly into
2676 // first word of object without any encoding. If object is dead we write 2683 // first word of object without any encoding. If object is dead we write
2677 // NULL as a forwarding address. 2684 // NULL as a forwarding address.
2678 // 2685 //
2679 // The second pass updates pointers to new space in all spaces. It is possible 2686 // The second pass updates pointers to new space in all spaces. It is possible
2680 // to encounter pointers to dead new space objects during traversal of pointers 2687 // to encounter pointers to dead new space objects during traversal of pointers
2681 // to new space. We should clear them to avoid encountering them during next 2688 // to new space. We should clear them to avoid encountering them during next
2682 // pointer iteration. This is an issue if the store buffer overflows and we 2689 // pointer iteration. This is an issue if the store buffer overflows and we
2683 // have to scan the entire old space, including dead objects, looking for 2690 // have to scan the entire old space, including dead objects, looking for
2684 // pointers to new space. 2691 // pointers to new space.
2685 void MarkCompactCollector::MigrateObject( 2692 void MarkCompactCollector::MigrateObject(HeapObject* dst, HeapObject* src,
2686 HeapObject* dst, HeapObject* src, int size, AllocationSpace dest, 2693 int size, AllocationSpace dest,
2687 SlotsBuffer** evacuation_slots_buffer) { 2694 SlotsBuffer** evacuation_slots_buffer,
2695 LocalStoreBuffer* local_store_buffer) {
2688 Address dst_addr = dst->address(); 2696 Address dst_addr = dst->address();
2689 Address src_addr = src->address(); 2697 Address src_addr = src->address();
2690 DCHECK(heap()->AllowedToBeMigrated(src, dest)); 2698 DCHECK(heap()->AllowedToBeMigrated(src, dest));
2691 DCHECK(dest != LO_SPACE); 2699 DCHECK(dest != LO_SPACE);
2692 if (dest == OLD_SPACE) { 2700 if (dest == OLD_SPACE) {
2693 DCHECK_OBJECT_SIZE(size); 2701 DCHECK_OBJECT_SIZE(size);
2694 DCHECK(evacuation_slots_buffer != nullptr); 2702 DCHECK(evacuation_slots_buffer != nullptr);
2695 DCHECK(IsAligned(size, kPointerSize)); 2703 DCHECK(IsAligned(size, kPointerSize));
2696 2704
2697 heap()->MoveBlock(dst->address(), src->address(), size); 2705 heap()->MoveBlock(dst->address(), src->address(), size);
2698 RecordMigratedSlotVisitor visitor(this, evacuation_slots_buffer); 2706 RecordMigratedSlotVisitor visitor(this, evacuation_slots_buffer,
2707 local_store_buffer);
2699 dst->IterateBody(&visitor); 2708 dst->IterateBody(&visitor);
2700 } else if (dest == CODE_SPACE) { 2709 } else if (dest == CODE_SPACE) {
2701 DCHECK_CODEOBJECT_SIZE(size, heap()->code_space()); 2710 DCHECK_CODEOBJECT_SIZE(size, heap()->code_space());
2702 DCHECK(evacuation_slots_buffer != nullptr); 2711 DCHECK(evacuation_slots_buffer != nullptr);
2703 PROFILE(isolate(), CodeMoveEvent(src_addr, dst_addr)); 2712 PROFILE(isolate(), CodeMoveEvent(src_addr, dst_addr));
2704 heap()->MoveBlock(dst_addr, src_addr, size); 2713 heap()->MoveBlock(dst_addr, src_addr, size);
2705 RecordMigratedCodeObjectSlot(dst_addr, evacuation_slots_buffer); 2714 RecordMigratedCodeObjectSlot(dst_addr, evacuation_slots_buffer);
2706 Code::cast(dst)->Relocate(dst_addr - src_addr); 2715 Code::cast(dst)->Relocate(dst_addr - src_addr);
2707 } else { 2716 } else {
2708 DCHECK_OBJECT_SIZE(size); 2717 DCHECK_OBJECT_SIZE(size);
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
3050 CHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); 3059 CHECK(Marking::IsBlack(Marking::MarkBitFrom(object)));
3051 3060
3052 // The target object is black but we don't know if the source slot is black. 3061 // The target object is black but we don't know if the source slot is black.
3053 // The source object could have died and the slot could be part of a free 3062 // The source object could have died and the slot could be part of a free
3054 // space. Use the mark bit iterator to find out about liveness of the slot. 3063 // space. Use the mark bit iterator to find out about liveness of the slot.
3055 CHECK(IsSlotInBlackObjectSlow(Page::FromAddress(slot), slot)); 3064 CHECK(IsSlotInBlackObjectSlow(Page::FromAddress(slot), slot));
3056 } 3065 }
3057 3066
3058 3067
3059 void MarkCompactCollector::EvacuateNewSpacePrologue() { 3068 void MarkCompactCollector::EvacuateNewSpacePrologue() {
3060 // There are soft limits in the allocation code, designed trigger a mark
3061 // sweep collection by failing allocations. But since we are already in
3062 // a mark-sweep allocation, there is no sense in trying to trigger one.
3063 AlwaysAllocateScope scope(isolate());
3064
3065 NewSpace* new_space = heap()->new_space(); 3069 NewSpace* new_space = heap()->new_space();
3066 3070 NewSpacePageIterator it(new_space->bottom(), new_space->top());
3067 // Store allocation range before flipping semispaces. 3071 // Append the list of new space pages to be processed.
3068 Address from_bottom = new_space->bottom();
3069 Address from_top = new_space->top();
3070
3071 // Flip the semispaces. After flipping, to space is empty, from space has
3072 // live objects.
3073 new_space->Flip();
3074 new_space->ResetAllocationInfo();
3075
3076 newspace_evacuation_candidates_.Clear();
3077 NewSpacePageIterator it(from_bottom, from_top);
3078 while (it.has_next()) { 3072 while (it.has_next()) {
3079 newspace_evacuation_candidates_.Add(it.next()); 3073 newspace_evacuation_candidates_.Add(it.next());
3080 } 3074 }
3075 new_space->Flip();
3076 new_space->ResetAllocationInfo();
3081 } 3077 }
3082 3078
3083 3079
3084 HashMap* MarkCompactCollector::EvacuateNewSpaceInParallel() { 3080 void MarkCompactCollector::EvacuateNewSpaceEpilogue() {
3085 HashMap* local_pretenuring_feedback = new HashMap( 3081 newspace_evacuation_candidates_.Rewind(0);
3086 HashMap::PointersMatch, kInitialLocalPretenuringFeedbackCapacity);
3087 EvacuateNewSpaceVisitor new_space_visitor(heap(), &migration_slots_buffer_,
3088 local_pretenuring_feedback);
3089 // First pass: traverse all objects in inactive semispace, remove marks,
3090 // migrate live objects and write forwarding addresses. This stage puts
3091 // new entries in the store buffer and may cause some pages to be marked
3092 // scan-on-scavenge.
3093 for (int i = 0; i < newspace_evacuation_candidates_.length(); i++) {
3094 NewSpacePage* p =
3095 reinterpret_cast<NewSpacePage*>(newspace_evacuation_candidates_[i]);
3096 bool ok = VisitLiveObjects(p, &new_space_visitor, kClearMarkbits);
3097 USE(ok);
3098 DCHECK(ok);
3099 }
3100 heap_->IncrementPromotedObjectsSize(new_space_visitor.promoted_size());
3101 heap_->IncrementSemiSpaceCopiedObjectSize(
3102 new_space_visitor.semispace_copied_size());
3103 heap_->IncrementYoungSurvivorsCounter(
3104 new_space_visitor.promoted_size() +
3105 new_space_visitor.semispace_copied_size());
3106 return local_pretenuring_feedback;
3107 } 3082 }
3108 3083
3109 3084
3110 void MarkCompactCollector::AddEvacuationSlotsBufferSynchronized( 3085 void MarkCompactCollector::AddEvacuationSlotsBufferSynchronized(
3111 SlotsBuffer* evacuation_slots_buffer) { 3086 SlotsBuffer* evacuation_slots_buffer) {
3112 base::LockGuard<base::Mutex> lock_guard(&evacuation_slots_buffers_mutex_); 3087 base::LockGuard<base::Mutex> lock_guard(&evacuation_slots_buffers_mutex_);
3113 evacuation_slots_buffers_.Add(evacuation_slots_buffer); 3088 evacuation_slots_buffers_.Add(evacuation_slots_buffer);
3114 } 3089 }
3115 3090
3116 3091
3117 int MarkCompactCollector::NumberOfParallelCompactionTasks() { 3092 int MarkCompactCollector::NumberOfParallelCompactionTasks(int pages,
3093 intptr_t live_bytes) {
3118 if (!FLAG_parallel_compaction) return 1; 3094 if (!FLAG_parallel_compaction) return 1;
3119 // Compute the number of needed tasks based on a target compaction time, the 3095 // Compute the number of needed tasks based on a target compaction time, the
3120 // profiled compaction speed and marked live memory. 3096 // profiled compaction speed and marked live memory.
3121 // 3097 //
3122 // The number of parallel compaction tasks is limited by: 3098 // The number of parallel compaction tasks is limited by:
3123 // - #evacuation pages 3099 // - #evacuation pages
3124 // - (#cores - 1) 3100 // - (#cores - 1)
3125 // - a hard limit
3126 const double kTargetCompactionTimeInMs = 1; 3101 const double kTargetCompactionTimeInMs = 1;
3127 const int kMaxCompactionTasks = 8; 3102 const int kNumSweepingTasks = 3;
3128 3103
3129 intptr_t compaction_speed = 3104 intptr_t compaction_speed =
3130 heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); 3105 heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
3131 if (compaction_speed == 0) return 1;
3132 3106
3133 intptr_t live_bytes = 0; 3107 const int cores =
3134 for (Page* page : evacuation_candidates_) { 3108 Max(1, base::SysInfo::NumberOfProcessors() - kNumSweepingTasks - 1);
3135 live_bytes += page->LiveBytes(); 3109 int tasks;
3110 if (compaction_speed > 0) {
3111 tasks = 1 + static_cast<int>(static_cast<double>(live_bytes) /
3112 compaction_speed / kTargetCompactionTimeInMs);
3113 } else {
3114 tasks = pages;
3136 } 3115 }
3137 3116 const int tasks_capped_pages = Min(pages, tasks);
3138 const int cores = Max(1, base::SysInfo::NumberOfProcessors() - 1);
3139 const int tasks =
3140 1 + static_cast<int>(static_cast<double>(live_bytes) / compaction_speed /
3141 kTargetCompactionTimeInMs);
3142 const int tasks_capped_pages = Min(evacuation_candidates_.length(), tasks);
3143 const int tasks_capped_cores = Min(cores, tasks_capped_pages); 3117 const int tasks_capped_cores = Min(cores, tasks_capped_pages);
3144 const int tasks_capped_hard = Min(kMaxCompactionTasks, tasks_capped_cores); 3118 return tasks_capped_cores;
3145 return tasks_capped_hard;
3146 } 3119 }
3147 3120
3148 3121
3149 void MarkCompactCollector::EvacuatePagesInParallel() { 3122 void MarkCompactCollector::EvacuatePagesInParallel() {
3150 const int num_pages = evacuation_candidates_.length(); 3123 int num_pages = 0;
3151 if (num_pages == 0) return; 3124 intptr_t live_bytes = 0;
3125 for (Page* page : evacuation_candidates_) {
3126 num_pages++;
3127 live_bytes += page->LiveBytes();
3128 }
3129 for (NewSpacePage* page : newspace_evacuation_candidates_) {
3130 num_pages++;
3131 live_bytes += page->LiveBytes();
3132 }
3133 DCHECK_GE(num_pages, 1);
3134
3152 3135
3153 // Used for trace summary. 3136 // Used for trace summary.
3154 intptr_t live_bytes = 0;
3155 intptr_t compaction_speed = 0; 3137 intptr_t compaction_speed = 0;
3156 if (FLAG_trace_fragmentation) { 3138 if (FLAG_trace_fragmentation) {
3157 for (Page* page : evacuation_candidates_) {
3158 live_bytes += page->LiveBytes();
3159 }
3160 compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond(); 3139 compaction_speed = heap()->tracer()->CompactionSpeedInBytesPerMillisecond();
3161 } 3140 }
3162 const int num_tasks = NumberOfParallelCompactionTasks(); 3141
3142 const int num_tasks = NumberOfParallelCompactionTasks(num_pages, live_bytes);
3163 3143
3164 // Set up compaction spaces. 3144 // Set up compaction spaces.
3165 CompactionSpaceCollection** compaction_spaces_for_tasks = 3145 CompactionSpaceCollection** compaction_spaces_for_tasks =
3166 new CompactionSpaceCollection*[num_tasks]; 3146 new CompactionSpaceCollection*[num_tasks];
3167 for (int i = 0; i < num_tasks; i++) { 3147 for (int i = 0; i < num_tasks; i++) {
3168 compaction_spaces_for_tasks[i] = new CompactionSpaceCollection(heap()); 3148 compaction_spaces_for_tasks[i] = new CompactionSpaceCollection(heap());
3169 } 3149 }
3170 3150
3171 heap()->old_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks, 3151 heap()->old_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks,
3172 num_tasks); 3152 num_tasks);
3173 heap()->code_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks, 3153 heap()->code_space()->DivideUponCompactionSpaces(compaction_spaces_for_tasks,
3174 num_tasks); 3154 num_tasks);
3175 3155
3176 uint32_t* task_ids = new uint32_t[num_tasks - 1]; 3156 uint32_t* task_ids = new uint32_t[num_tasks - 1];
3177 // Kick off parallel tasks. 3157 // Kick off parallel tasks.
3178 StartParallelCompaction(compaction_spaces_for_tasks, task_ids, num_tasks); 3158 StartParallelCompaction(compaction_spaces_for_tasks, task_ids, num_tasks);
3179 // Wait for unfinished and not-yet-started tasks. 3159 // Wait for unfinished and not-yet-started tasks.
3180 WaitUntilCompactionCompleted(task_ids, num_tasks - 1); 3160 WaitUntilCompactionCompleted(task_ids, num_tasks - 1);
3181 delete[] task_ids; 3161 delete[] task_ids;
3182 3162
3183 double compaction_duration = 0.0; 3163 double compaction_duration = 0.0;
3184 intptr_t compacted_memory = 0; 3164 intptr_t compacted_memory = 0;
3185 // Merge back memory (compacted and unused) from compaction spaces. 3165 // Merge back memory (compacted and unused) from compaction spaces and update
3166 // pretenuring feedback.
3186 for (int i = 0; i < num_tasks; i++) { 3167 for (int i = 0; i < num_tasks; i++) {
3187 heap()->old_space()->MergeCompactionSpace( 3168 heap()->old_space()->MergeCompactionSpace(
3188 compaction_spaces_for_tasks[i]->Get(OLD_SPACE)); 3169 compaction_spaces_for_tasks[i]->Get(OLD_SPACE));
3189 heap()->code_space()->MergeCompactionSpace( 3170 heap()->code_space()->MergeCompactionSpace(
3190 compaction_spaces_for_tasks[i]->Get(CODE_SPACE)); 3171 compaction_spaces_for_tasks[i]->Get(CODE_SPACE));
3191 compacted_memory += compaction_spaces_for_tasks[i]->bytes_compacted(); 3172 compacted_memory += compaction_spaces_for_tasks[i]->bytes_compacted();
3192 compaction_duration += compaction_spaces_for_tasks[i]->duration(); 3173 compaction_duration += compaction_spaces_for_tasks[i]->duration();
3174 heap()->MergeAllocationSitePretenuringFeedback(
3175 *compaction_spaces_for_tasks[i]->local_pretenuring_feedback());
3176 compaction_spaces_for_tasks[i]->local_store_buffer()->Process(
3177 heap()->store_buffer());
3193 delete compaction_spaces_for_tasks[i]; 3178 delete compaction_spaces_for_tasks[i];
3194 } 3179 }
3195 delete[] compaction_spaces_for_tasks; 3180 delete[] compaction_spaces_for_tasks;
3196 heap()->tracer()->AddCompactionEvent(compaction_duration, compacted_memory); 3181 heap()->tracer()->AddCompactionEvent(compaction_duration, compacted_memory);
3197 3182
3198 // Finalize sequentially. 3183 // Finalize sequentially.
3184 for (NewSpacePage* p : newspace_evacuation_candidates_) {
3185 DCHECK_EQ(p->parallel_compaction_state().Value(),
3186 MemoryChunk::kCompactingFinalize);
3187 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone);
3188 }
3189
3199 int abandoned_pages = 0; 3190 int abandoned_pages = 0;
3200 for (int i = 0; i < num_pages; i++) { 3191 for (Page* p : evacuation_candidates_) {
3201 Page* p = evacuation_candidates_[i];
3202 switch (p->parallel_compaction_state().Value()) { 3192 switch (p->parallel_compaction_state().Value()) {
3203 case MemoryChunk::ParallelCompactingState::kCompactingAborted: 3193 case MemoryChunk::ParallelCompactingState::kCompactingAborted:
3204 // We have partially compacted the page, i.e., some objects may have 3194 // We have partially compacted the page, i.e., some objects may have
3205 // moved, others are still in place. 3195 // moved, others are still in place.
3206 // We need to: 3196 // We need to:
3207 // - Leave the evacuation candidate flag for later processing of 3197 // - Leave the evacuation candidate flag for later processing of
3208 // slots buffer entries. 3198 // slots buffer entries.
3209 // - Leave the slots buffer there for processing of entries added by 3199 // - Leave the slots buffer there for processing of entries added by
3210 // the write barrier. 3200 // the write barrier.
3211 // - Rescan the page as slot recording in the migration buffer only 3201 // - Rescan the page as slot recording in the migration buffer only
(...skipping 12 matching lines...) Expand all
3224 case MemoryChunk::kCompactingFinalize: 3214 case MemoryChunk::kCompactingFinalize:
3225 DCHECK(p->IsEvacuationCandidate()); 3215 DCHECK(p->IsEvacuationCandidate());
3226 p->SetWasSwept(); 3216 p->SetWasSwept();
3227 p->Unlink(); 3217 p->Unlink();
3228 break; 3218 break;
3229 case MemoryChunk::kCompactingDone: 3219 case MemoryChunk::kCompactingDone:
3230 DCHECK(p->IsFlagSet(Page::POPULAR_PAGE)); 3220 DCHECK(p->IsFlagSet(Page::POPULAR_PAGE));
3231 DCHECK(p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3221 DCHECK(p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
3232 break; 3222 break;
3233 default: 3223 default:
3234 // We should not observe kCompactingInProgress, or kCompactingDone. 3224 // MemoryChunk::kCompactingInProgress.
3235 UNREACHABLE(); 3225 UNREACHABLE();
3236 } 3226 }
3237 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone); 3227 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone);
3238 } 3228 }
3239 if (FLAG_trace_fragmentation) { 3229 if (FLAG_trace_fragmentation) {
3240 PrintIsolate(isolate(), 3230 PrintIsolate(isolate(),
3241 "%8.0f ms: compaction: parallel=%d pages=%d aborted=%d " 3231 "%8.0f ms: compaction: parallel=%d pages=%d aborted=%d "
3242 "tasks=%d cores=%d live_bytes=%" V8_PTR_PREFIX 3232 "tasks=%d cores=%d live_bytes=%" V8_PTR_PREFIX
3243 "d compaction_speed=%" V8_PTR_PREFIX "d\n", 3233 "d compaction_speed=%" V8_PTR_PREFIX "d\n",
3244 isolate()->time_millis_since_init(), FLAG_parallel_compaction, 3234 isolate()->time_millis_since_init(), FLAG_parallel_compaction,
(...skipping 28 matching lines...) Expand all
3273 // semaphore signal. 3263 // semaphore signal.
3274 for (int i = 0; i < len; i++) { 3264 for (int i = 0; i < len; i++) {
3275 if (!heap()->isolate()->cancelable_task_manager()->TryAbort(task_ids[i])) { 3265 if (!heap()->isolate()->cancelable_task_manager()->TryAbort(task_ids[i])) {
3276 pending_compaction_tasks_semaphore_.Wait(); 3266 pending_compaction_tasks_semaphore_.Wait();
3277 } 3267 }
3278 } 3268 }
3279 compaction_in_progress_ = false; 3269 compaction_in_progress_ = false;
3280 } 3270 }
3281 3271
3282 3272
3273 bool MarkCompactCollector::EvacuateSinglePage(
3274 MemoryChunk* p, HeapObjectVisitor* visitor,
3275 CompactionSpaceCollection* compaction_spaces) {
3276 bool aborted = false;
3277 if (p->parallel_compaction_state().TrySetValue(
3278 MemoryChunk::kCompactingDone, MemoryChunk::kCompactingInProgress)) {
3279 if (p->IsEvacuationCandidate() || p->InNewSpace()) {
3280 DCHECK_EQ(p->parallel_compaction_state().Value(),
3281 MemoryChunk::kCompactingInProgress);
3282 int saved_live_bytes = p->LiveBytes();
3283 double evacuation_time;
3284 bool success;
3285 {
3286 AlwaysAllocateScope always_allocate(isolate());
3287 TimedScope timed_scope(heap(), &evacuation_time);
3288 success = VisitLiveObjects(p, visitor, kClearMarkbits);
3289 }
3290 if (success) {
3291 compaction_spaces->ReportCompactionProgress(evacuation_time,
3292 saved_live_bytes);
3293 p->parallel_compaction_state().SetValue(
3294 MemoryChunk::kCompactingFinalize);
3295 } else {
3296 p->parallel_compaction_state().SetValue(
3297 MemoryChunk::kCompactingAborted);
3298 aborted = true;
3299 }
3300 } else {
3301 // There could be popular pages in the list of evacuation candidates
3302 // which we do compact.
3303 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone);
3304 }
3305 }
3306 return !aborted;
3307 }
3308
3309
3283 void MarkCompactCollector::EvacuatePages( 3310 void MarkCompactCollector::EvacuatePages(
3284 CompactionSpaceCollection* compaction_spaces, 3311 CompactionSpaceCollection* compaction_spaces,
3285 SlotsBuffer** evacuation_slots_buffer) { 3312 SlotsBuffer** evacuation_slots_buffer) {
3286 EvacuateOldSpaceVisitor visitor(heap(), compaction_spaces, 3313 EvacuateOldSpaceVisitor old_space_visitor(heap(), compaction_spaces,
3287 evacuation_slots_buffer); 3314 evacuation_slots_buffer);
3288 for (int i = 0; i < evacuation_candidates_.length(); i++) { 3315 EvacuateNewSpaceVisitor new_space_visitor(heap(), evacuation_slots_buffer,
3289 Page* p = evacuation_candidates_[i]; 3316 compaction_spaces);
3317 for (NewSpacePage* p : newspace_evacuation_candidates_) {
3318 DCHECK(p->InNewSpace());
3319 DCHECK_EQ(static_cast<int>(p->parallel_sweeping_state().Value()),
3320 MemoryChunk::kSweepingDone);
3321 bool success = EvacuateSinglePage(p, &new_space_visitor, compaction_spaces);
3322 DCHECK(success);
3323 USE(success);
3324 }
3325 for (Page* p : evacuation_candidates_) {
3290 DCHECK(p->IsEvacuationCandidate() || 3326 DCHECK(p->IsEvacuationCandidate() ||
3291 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3327 p->IsFlagSet(MemoryChunk::RESCAN_ON_EVACUATION));
3292 DCHECK(static_cast<int>(p->parallel_sweeping_state().Value()) == 3328 DCHECK_EQ(static_cast<int>(p->parallel_sweeping_state().Value()),
3293 MemoryChunk::kSweepingDone); 3329 MemoryChunk::kSweepingDone);
3294 if (p->parallel_compaction_state().TrySetValue( 3330 EvacuateSinglePage(p, &old_space_visitor, compaction_spaces);
3295 MemoryChunk::kCompactingDone, MemoryChunk::kCompactingInProgress)) {
3296 if (p->IsEvacuationCandidate()) {
3297 DCHECK_EQ(p->parallel_compaction_state().Value(),
3298 MemoryChunk::kCompactingInProgress);
3299 double start = heap()->MonotonicallyIncreasingTimeInMs();
3300 intptr_t live_bytes = p->LiveBytes();
3301 AlwaysAllocateScope always_allocate(isolate());
3302 if (VisitLiveObjects(p, &visitor, kClearMarkbits)) {
3303 p->ResetLiveBytes();
3304 p->parallel_compaction_state().SetValue(
3305 MemoryChunk::kCompactingFinalize);
3306 compaction_spaces->ReportCompactionProgress(
3307 heap()->MonotonicallyIncreasingTimeInMs() - start, live_bytes);
3308 } else {
3309 p->parallel_compaction_state().SetValue(
3310 MemoryChunk::kCompactingAborted);
3311 }
3312 } else {
3313 // There could be popular pages in the list of evacuation candidates
3314 // which we do compact.
3315 p->parallel_compaction_state().SetValue(MemoryChunk::kCompactingDone);
3316 }
3317 }
3318 } 3331 }
3332
3333 heap()->IncrementPromotedObjectsSize(new_space_visitor.promoted_size());
3334 heap()->IncrementSemiSpaceCopiedObjectSize(
3335 new_space_visitor.semispace_copied_size());
3336 heap()->IncrementYoungSurvivorsCounter(
3337 new_space_visitor.promoted_size() +
3338 new_space_visitor.semispace_copied_size());
3319 } 3339 }
3320 3340
3321 3341
3322 class EvacuationWeakObjectRetainer : public WeakObjectRetainer { 3342 class EvacuationWeakObjectRetainer : public WeakObjectRetainer {
3323 public: 3343 public:
3324 virtual Object* RetainAs(Object* object) { 3344 virtual Object* RetainAs(Object* object) {
3325 if (object->IsHeapObject()) { 3345 if (object->IsHeapObject()) {
3326 HeapObject* heap_object = HeapObject::cast(object); 3346 HeapObject* heap_object = HeapObject::cast(object);
3327 MapWord map_word = heap_object->map_word(); 3347 MapWord map_word = heap_object->map_word();
3328 if (map_word.IsForwardingAddress()) { 3348 if (map_word.IsForwardingAddress()) {
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
3461 // Return true if the given code is deoptimized or will be deoptimized. 3481 // Return true if the given code is deoptimized or will be deoptimized.
3462 bool MarkCompactCollector::WillBeDeoptimized(Code* code) { 3482 bool MarkCompactCollector::WillBeDeoptimized(Code* code) {
3463 return code->is_optimized_code() && code->marked_for_deoptimization(); 3483 return code->is_optimized_code() && code->marked_for_deoptimization();
3464 } 3484 }
3465 3485
3466 3486
3467 void MarkCompactCollector::RemoveObjectSlots(Address start_slot, 3487 void MarkCompactCollector::RemoveObjectSlots(Address start_slot,
3468 Address end_slot) { 3488 Address end_slot) {
3469 // Remove entries by replacing them with an old-space slot containing a smi 3489 // Remove entries by replacing them with an old-space slot containing a smi
3470 // that is located in an unmovable page. 3490 // that is located in an unmovable page.
3471 int npages = evacuation_candidates_.length(); 3491 for (Page* p : evacuation_candidates_) {
3472 for (int i = 0; i < npages; i++) {
3473 Page* p = evacuation_candidates_[i];
3474 DCHECK(p->IsEvacuationCandidate() || 3492 DCHECK(p->IsEvacuationCandidate() ||
3475 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3493 p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
3476 if (p->IsEvacuationCandidate()) { 3494 if (p->IsEvacuationCandidate()) {
3477 SlotsBuffer::RemoveObjectSlots(heap_, p->slots_buffer(), start_slot, 3495 SlotsBuffer::RemoveObjectSlots(heap_, p->slots_buffer(), start_slot,
3478 end_slot); 3496 end_slot);
3479 } 3497 }
3480 } 3498 }
3481 } 3499 }
3482 3500
3483 3501
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
3543 DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object))); 3561 DCHECK(Marking::IsBlack(Marking::MarkBitFrom(object)));
3544 Map* map = object->synchronized_map(); 3562 Map* map = object->synchronized_map();
3545 int size = object->SizeFromMap(map); 3563 int size = object->SizeFromMap(map);
3546 object->IterateBody(map->instance_type(), size, visitor); 3564 object->IterateBody(map->instance_type(), size, visitor);
3547 } 3565 }
3548 } 3566 }
3549 3567
3550 3568
3551 void MarkCompactCollector::SweepAbortedPages() { 3569 void MarkCompactCollector::SweepAbortedPages() {
3552 // Second pass on aborted pages. 3570 // Second pass on aborted pages.
3553 for (int i = 0; i < evacuation_candidates_.length(); i++) { 3571 for (Page* p : evacuation_candidates_) {
3554 Page* p = evacuation_candidates_[i];
3555 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) { 3572 if (p->IsFlagSet(Page::COMPACTION_WAS_ABORTED)) {
3556 p->ClearFlag(MemoryChunk::COMPACTION_WAS_ABORTED); 3573 p->ClearFlag(MemoryChunk::COMPACTION_WAS_ABORTED);
3557 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 3574 PagedSpace* space = static_cast<PagedSpace*>(p->owner());
3558 switch (space->identity()) { 3575 switch (space->identity()) {
3559 case OLD_SPACE: 3576 case OLD_SPACE:
3560 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, IGNORE_SKIP_LIST, 3577 Sweep<SWEEP_ONLY, SWEEP_ON_MAIN_THREAD, IGNORE_SKIP_LIST,
3561 IGNORE_FREE_SPACE>(space, nullptr, p, nullptr); 3578 IGNORE_FREE_SPACE>(space, nullptr, p, nullptr);
3562 break; 3579 break;
3563 case CODE_SPACE: 3580 case CODE_SPACE:
3564 if (FLAG_zap_code_space) { 3581 if (FLAG_zap_code_space) {
(...skipping 10 matching lines...) Expand all
3575 } 3592 }
3576 } 3593 }
3577 } 3594 }
3578 } 3595 }
3579 3596
3580 3597
3581 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() { 3598 void MarkCompactCollector::EvacuateNewSpaceAndCandidates() {
3582 GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_EVACUATE); 3599 GCTracer::Scope gc_scope(heap()->tracer(), GCTracer::Scope::MC_EVACUATE);
3583 Heap::RelocationLock relocation_lock(heap()); 3600 Heap::RelocationLock relocation_lock(heap());
3584 3601
3585 HashMap* local_pretenuring_feedback = nullptr;
3586 { 3602 {
3587 GCTracer::Scope gc_scope(heap()->tracer(), 3603 GCTracer::Scope gc_scope(heap()->tracer(),
3588 GCTracer::Scope::MC_EVACUATE_NEW_SPACE); 3604 GCTracer::Scope::MC_EVACUATE_NEW_SPACE);
3589 EvacuationScope evacuation_scope(this); 3605 EvacuationScope evacuation_scope(this);
3606
3590 EvacuateNewSpacePrologue(); 3607 EvacuateNewSpacePrologue();
3591 local_pretenuring_feedback = EvacuateNewSpaceInParallel();
3592 heap_->new_space()->set_age_mark(heap_->new_space()->top());
3593 }
3594
3595 {
3596 GCTracer::Scope gc_scope(heap()->tracer(),
3597 GCTracer::Scope::MC_EVACUATE_CANDIDATES);
3598 EvacuationScope evacuation_scope(this);
3599 EvacuatePagesInParallel(); 3608 EvacuatePagesInParallel();
3600 } 3609 EvacuateNewSpaceEpilogue();
3601 3610 heap()->new_space()->set_age_mark(heap()->new_space()->top());
3602 {
3603 heap_->MergeAllocationSitePretenuringFeedback(*local_pretenuring_feedback);
3604 delete local_pretenuring_feedback;
3605 } 3611 }
3606 3612
3607 UpdatePointersAfterEvacuation(); 3613 UpdatePointersAfterEvacuation();
3608 3614
3609 { 3615 {
3610 GCTracer::Scope gc_scope(heap()->tracer(), 3616 GCTracer::Scope gc_scope(heap()->tracer(),
3611 GCTracer::Scope::MC_EVACUATE_CLEAN_UP); 3617 GCTracer::Scope::MC_EVACUATE_CLEAN_UP);
3612 // After updating all pointers, we can finally sweep the aborted pages, 3618 // After updating all pointers, we can finally sweep the aborted pages,
3613 // effectively overriding any forward pointers. 3619 // effectively overriding any forward pointers.
3614 SweepAbortedPages(); 3620 SweepAbortedPages();
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
3671 &updating_visitor); 3677 &updating_visitor);
3672 } 3678 }
3673 // Update roots. 3679 // Update roots.
3674 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE); 3680 heap_->IterateRoots(&updating_visitor, VISIT_ALL_IN_SWEEP_NEWSPACE);
3675 3681
3676 StoreBufferRebuildScope scope(heap_, heap_->store_buffer(), 3682 StoreBufferRebuildScope scope(heap_, heap_->store_buffer(),
3677 &Heap::ScavengeStoreBufferCallback); 3683 &Heap::ScavengeStoreBufferCallback);
3678 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer); 3684 heap_->store_buffer()->IteratePointersToNewSpace(&UpdatePointer);
3679 } 3685 }
3680 3686
3681 int npages = evacuation_candidates_.length();
3682 { 3687 {
3683 GCTracer::Scope gc_scope( 3688 GCTracer::Scope gc_scope(
3684 heap()->tracer(), 3689 heap()->tracer(),
3685 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_BETWEEN_EVACUATED); 3690 GCTracer::Scope::MC_EVACUATE_UPDATE_POINTERS_BETWEEN_EVACUATED);
3686 for (int i = 0; i < npages; i++) { 3691 for (Page* p : evacuation_candidates_) {
3687 Page* p = evacuation_candidates_[i];
3688 DCHECK(p->IsEvacuationCandidate() || 3692 DCHECK(p->IsEvacuationCandidate() ||
3689 p->IsFlagSet(Page::RESCAN_ON_EVACUATION)); 3693 p->IsFlagSet(Page::RESCAN_ON_EVACUATION));
3690 3694
3691 if (p->IsEvacuationCandidate()) { 3695 if (p->IsEvacuationCandidate()) {
3692 UpdateSlotsRecordedIn(p->slots_buffer()); 3696 UpdateSlotsRecordedIn(p->slots_buffer());
3693 if (FLAG_trace_fragmentation_verbose) { 3697 if (FLAG_trace_fragmentation_verbose) {
3694 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p), 3698 PrintF(" page %p slots buffer: %d\n", reinterpret_cast<void*>(p),
3695 SlotsBuffer::SizeOfChain(p->slots_buffer())); 3699 SlotsBuffer::SizeOfChain(p->slots_buffer()));
3696 } 3700 }
3697 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address()); 3701 slots_buffer_allocator_->DeallocateChain(p->slots_buffer_address());
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
3751 heap_->UpdateReferencesInExternalStringTable( 3755 heap_->UpdateReferencesInExternalStringTable(
3752 &UpdateReferenceInExternalStringTableEntry); 3756 &UpdateReferenceInExternalStringTableEntry);
3753 3757
3754 EvacuationWeakObjectRetainer evacuation_object_retainer; 3758 EvacuationWeakObjectRetainer evacuation_object_retainer;
3755 heap()->ProcessAllWeakReferences(&evacuation_object_retainer); 3759 heap()->ProcessAllWeakReferences(&evacuation_object_retainer);
3756 } 3760 }
3757 } 3761 }
3758 3762
3759 3763
3760 void MarkCompactCollector::MoveEvacuationCandidatesToEndOfPagesList() { 3764 void MarkCompactCollector::MoveEvacuationCandidatesToEndOfPagesList() {
3761 int npages = evacuation_candidates_.length(); 3765 for (Page* p : evacuation_candidates_) {
3762 for (int i = 0; i < npages; i++) {
3763 Page* p = evacuation_candidates_[i];
3764 if (!p->IsEvacuationCandidate()) continue; 3766 if (!p->IsEvacuationCandidate()) continue;
3765 p->Unlink(); 3767 p->Unlink();
3766 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 3768 PagedSpace* space = static_cast<PagedSpace*>(p->owner());
3767 p->InsertAfter(space->LastPage()); 3769 p->InsertAfter(space->LastPage());
3768 } 3770 }
3769 } 3771 }
3770 3772
3771 3773
3772 void MarkCompactCollector::ReleaseEvacuationCandidates() { 3774 void MarkCompactCollector::ReleaseEvacuationCandidates() {
3773 int npages = evacuation_candidates_.length(); 3775 for (Page* p : evacuation_candidates_) {
3774 for (int i = 0; i < npages; i++) {
3775 Page* p = evacuation_candidates_[i];
3776 if (!p->IsEvacuationCandidate()) continue; 3776 if (!p->IsEvacuationCandidate()) continue;
3777 PagedSpace* space = static_cast<PagedSpace*>(p->owner()); 3777 PagedSpace* space = static_cast<PagedSpace*>(p->owner());
3778 space->Free(p->area_start(), p->area_size()); 3778 space->Free(p->area_start(), p->area_size());
3779 p->set_scan_on_scavenge(false); 3779 p->set_scan_on_scavenge(false);
3780 p->ResetLiveBytes(); 3780 p->ResetLiveBytes();
3781 CHECK(p->WasSwept()); 3781 CHECK(p->WasSwept());
3782 space->ReleasePage(p); 3782 space->ReleasePage(p);
3783 } 3783 }
3784 evacuation_candidates_.Rewind(0); 3784 evacuation_candidates_.Rewind(0);
3785 compacting_ = false; 3785 compacting_ = false;
3786 heap()->FilterStoreBufferEntriesOnAboutToBeFreedPages(); 3786 heap()->FilterStoreBufferEntriesOnAboutToBeFreedPages();
3787 heap()->FreeQueuedChunks(); 3787 heap()->FreeQueuedChunks();
3788 } 3788 }
3789 3789
3790 3790
3791 int MarkCompactCollector::SweepInParallel(PagedSpace* space, 3791 int MarkCompactCollector::SweepInParallel(PagedSpace* space,
3792 int required_freed_bytes) { 3792 int required_freed_bytes,
3793 int max_pages) {
Hannes Payer (out of office) 2016/01/18 11:46:34 We should optimize for sweeping as many pages as p
Michael Lippautz 2016/01/19 14:56:52 As discussed offline, this will go in separately:
3794 int page_count = 0;
3793 int max_freed = 0; 3795 int max_freed = 0;
3794 int max_freed_overall = 0; 3796 int max_freed_overall = 0;
3795 PageIterator it(space); 3797 PageIterator it(space);
3796 while (it.has_next()) { 3798 while (it.has_next()) {
3797 Page* p = it.next(); 3799 Page* p = it.next();
3798 max_freed = SweepInParallel(p, space); 3800 max_freed = SweepInParallel(p, space);
3799 DCHECK(max_freed >= 0); 3801 DCHECK(max_freed >= 0);
3800 if (required_freed_bytes > 0 && max_freed >= required_freed_bytes) { 3802 if ((required_freed_bytes > 0) && (max_freed >= required_freed_bytes)) {
3801 return max_freed; 3803 return max_freed;
3802 } 3804 }
3803 max_freed_overall = Max(max_freed, max_freed_overall); 3805 max_freed_overall = Max(max_freed, max_freed_overall);
3804 if (p == space->end_of_unswept_pages()) break; 3806 if (p == space->end_of_unswept_pages()) break;
3807 page_count++;
3808 if ((max_pages > 0) && (page_count == max_pages)) {
3809 return max_freed;
3810 }
3805 } 3811 }
3806 return max_freed_overall; 3812 return max_freed_overall;
3807 } 3813 }
3808 3814
3809 3815
3810 int MarkCompactCollector::SweepInParallel(Page* page, PagedSpace* space) { 3816 int MarkCompactCollector::SweepInParallel(Page* page, PagedSpace* space) {
3811 int max_freed = 0; 3817 int max_freed = 0;
3812 if (page->TryLock()) { 3818 if (page->TryLock()) {
3813 // If this page was already swept in the meantime, we can return here. 3819 // If this page was already swept in the meantime, we can return here.
3814 if (page->parallel_sweeping_state().Value() != 3820 if (page->parallel_sweeping_state().Value() !=
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
4064 MarkBit mark_bit = Marking::MarkBitFrom(host); 4070 MarkBit mark_bit = Marking::MarkBitFrom(host);
4065 if (Marking::IsBlack(mark_bit)) { 4071 if (Marking::IsBlack(mark_bit)) {
4066 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host); 4072 RelocInfo rinfo(isolate(), pc, RelocInfo::CODE_TARGET, 0, host);
4067 RecordRelocSlot(&rinfo, target); 4073 RecordRelocSlot(&rinfo, target);
4068 } 4074 }
4069 } 4075 }
4070 } 4076 }
4071 4077
4072 } // namespace internal 4078 } // namespace internal
4073 } // namespace v8 4079 } // namespace v8
OLDNEW
« src/heap/heap-inl.h ('K') | « src/heap/mark-compact.h ('k') | src/heap/spaces.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698