OLD | NEW |
---|---|
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 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
682 space->top() == space->limit() | 682 space->top() == space->limit() |
683 ? nullptr | 683 ? nullptr |
684 : Page::FromAllocationAreaAddress(space->top()); | 684 : Page::FromAllocationAreaAddress(space->top()); |
685 for (Page* p : *space) { | 685 for (Page* p : *space) { |
686 if (p->NeverEvacuate() || p == owner_of_linear_allocation_area) continue; | 686 if (p->NeverEvacuate() || p == owner_of_linear_allocation_area) continue; |
687 // Invariant: Evacuation candidates are just created when marking is | 687 // Invariant: Evacuation candidates are just created when marking is |
688 // started. This means that sweeping has finished. Furthermore, at the end | 688 // started. This means that sweeping has finished. Furthermore, at the end |
689 // of a GC all evacuation candidates are cleared and their slot buffers are | 689 // of a GC all evacuation candidates are cleared and their slot buffers are |
690 // released. | 690 // released. |
691 CHECK(!p->IsEvacuationCandidate()); | 691 CHECK(!p->IsEvacuationCandidate()); |
692 CHECK_NULL(p->old_to_old_slots()); | 692 CHECK_NULL(p->slot_set<OLD_TO_OLD>()); |
693 CHECK_NULL(p->typed_old_to_old_slots()); | 693 CHECK_NULL(p->typed_slot_set<OLD_TO_OLD>()); |
694 CHECK(p->SweepingDone()); | 694 CHECK(p->SweepingDone()); |
695 DCHECK(p->area_size() == area_size); | 695 DCHECK(p->area_size() == area_size); |
696 pages.push_back(std::make_pair(p->LiveBytesFromFreeList(), p)); | 696 pages.push_back(std::make_pair(p->LiveBytesFromFreeList(), p)); |
697 } | 697 } |
698 | 698 |
699 int candidate_count = 0; | 699 int candidate_count = 0; |
700 size_t total_live_bytes = 0; | 700 size_t total_live_bytes = 0; |
701 | 701 |
702 const bool reduce_memory = heap()->ShouldReduceMemory(); | 702 const bool reduce_memory = heap()->ShouldReduceMemory(); |
703 if (FLAG_manual_evacuation_candidates_selection) { | 703 if (FLAG_manual_evacuation_candidates_selection) { |
(...skipping 2719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3423 return map_word.ToForwardingAddress(); | 3423 return map_word.ToForwardingAddress(); |
3424 } | 3424 } |
3425 } | 3425 } |
3426 return object; | 3426 return object; |
3427 } | 3427 } |
3428 }; | 3428 }; |
3429 | 3429 |
3430 MarkCompactCollector::Sweeper::ClearOldToNewSlotsMode | 3430 MarkCompactCollector::Sweeper::ClearOldToNewSlotsMode |
3431 MarkCompactCollector::Sweeper::GetClearOldToNewSlotsMode(Page* p) { | 3431 MarkCompactCollector::Sweeper::GetClearOldToNewSlotsMode(Page* p) { |
3432 AllocationSpace identity = p->owner()->identity(); | 3432 AllocationSpace identity = p->owner()->identity(); |
3433 if (p->old_to_new_slots() && | 3433 if (p->slot_set<OLD_TO_NEW>() && |
3434 (identity == OLD_SPACE || identity == MAP_SPACE)) { | 3434 (identity == OLD_SPACE || identity == MAP_SPACE)) { |
3435 return MarkCompactCollector::Sweeper::CLEAR_REGULAR_SLOTS; | 3435 return MarkCompactCollector::Sweeper::CLEAR_REGULAR_SLOTS; |
3436 } else if (p->typed_old_to_new_slots() && identity == CODE_SPACE) { | 3436 } else if (p->typed_slot_set<OLD_TO_NEW>() && identity == CODE_SPACE) { |
3437 return MarkCompactCollector::Sweeper::CLEAR_TYPED_SLOTS; | 3437 return MarkCompactCollector::Sweeper::CLEAR_TYPED_SLOTS; |
3438 } | 3438 } |
3439 return MarkCompactCollector::Sweeper::DO_NOT_CLEAR; | 3439 return MarkCompactCollector::Sweeper::DO_NOT_CLEAR; |
3440 } | 3440 } |
3441 | 3441 |
3442 int MarkCompactCollector::Sweeper::RawSweep( | 3442 int MarkCompactCollector::Sweeper::RawSweep( |
3443 Page* p, FreeListRebuildingMode free_list_mode, | 3443 Page* p, FreeListRebuildingMode free_list_mode, |
3444 FreeSpaceTreatmentMode free_space_mode) { | 3444 FreeSpaceTreatmentMode free_space_mode) { |
3445 Space* space = p->owner(); | 3445 Space* space = p->owner(); |
3446 DCHECK_NOT_NULL(space); | 3446 DCHECK_NOT_NULL(space); |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3539 RememberedSet<OLD_TO_NEW>::RemoveRange(p, free_start, p->area_end(), | 3539 RememberedSet<OLD_TO_NEW>::RemoveRange(p, free_start, p->area_end(), |
3540 SlotSet::KEEP_EMPTY_BUCKETS); | 3540 SlotSet::KEEP_EMPTY_BUCKETS); |
3541 } else if (slots_clearing_mode == CLEAR_TYPED_SLOTS) { | 3541 } else if (slots_clearing_mode == CLEAR_TYPED_SLOTS) { |
3542 free_ranges.insert(std::pair<uint32_t, uint32_t>( | 3542 free_ranges.insert(std::pair<uint32_t, uint32_t>( |
3543 static_cast<uint32_t>(free_start - p->address()), | 3543 static_cast<uint32_t>(free_start - p->address()), |
3544 static_cast<uint32_t>(p->area_end() - p->address()))); | 3544 static_cast<uint32_t>(p->area_end() - p->address()))); |
3545 } | 3545 } |
3546 } | 3546 } |
3547 | 3547 |
3548 // Clear invalid typed slots after collection all free ranges. | 3548 // Clear invalid typed slots after collection all free ranges. |
3549 if (slots_clearing_mode == CLEAR_TYPED_SLOTS) { | 3549 TypedSlotSet* typed_slot_set = p->typed_slot_set<OLD_TO_NEW>(); |
3550 p->typed_old_to_new_slots()->RemoveInvaldSlots(free_ranges); | 3550 if (typed_slot_set != nullptr && slots_clearing_mode == CLEAR_TYPED_SLOTS) { |
ulan
2017/03/29 14:41:50
How about putting the type_slot_set inside the bra
Hannes Payer (out of office)
2017/03/29 14:53:15
Done.
| |
3551 typed_slot_set->RemoveInvaldSlots(free_ranges); | |
3551 } | 3552 } |
3552 | 3553 |
3553 // Clear the mark bits of that page and reset live bytes count. | 3554 // Clear the mark bits of that page and reset live bytes count. |
3554 MarkingState::Internal(p).ClearLiveness(); | 3555 MarkingState::Internal(p).ClearLiveness(); |
3555 | 3556 |
3556 p->concurrent_sweeping_state().SetValue(Page::kSweepingDone); | 3557 p->concurrent_sweeping_state().SetValue(Page::kSweepingDone); |
3557 if (free_list_mode == IGNORE_FREE_LIST) return 0; | 3558 if (free_list_mode == IGNORE_FREE_LIST) return 0; |
3558 return static_cast<int>(FreeList::GuaranteedAllocatable(max_freed_bytes)); | 3559 return static_cast<int>(FreeList::GuaranteedAllocatable(max_freed_bytes)); |
3559 } | 3560 } |
3560 | 3561 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3599 IterationMode iteration_mode) { | 3600 IterationMode iteration_mode) { |
3600 LiveObjectIterator<kBlackObjects> it(chunk, state); | 3601 LiveObjectIterator<kBlackObjects> it(chunk, state); |
3601 HeapObject* object = nullptr; | 3602 HeapObject* object = nullptr; |
3602 while ((object = it.Next()) != nullptr) { | 3603 while ((object = it.Next()) != nullptr) { |
3603 DCHECK(ObjectMarking::IsBlack(object, state)); | 3604 DCHECK(ObjectMarking::IsBlack(object, state)); |
3604 if (!visitor->Visit(object)) { | 3605 if (!visitor->Visit(object)) { |
3605 if (iteration_mode == kClearMarkbits) { | 3606 if (iteration_mode == kClearMarkbits) { |
3606 state.bitmap()->ClearRange( | 3607 state.bitmap()->ClearRange( |
3607 chunk->AddressToMarkbitIndex(chunk->area_start()), | 3608 chunk->AddressToMarkbitIndex(chunk->area_start()), |
3608 chunk->AddressToMarkbitIndex(object->address())); | 3609 chunk->AddressToMarkbitIndex(object->address())); |
3609 if (chunk->old_to_new_slots() != nullptr) { | 3610 SlotSet* slot_set = chunk->slot_set<OLD_TO_NEW>(); |
3610 chunk->old_to_new_slots()->RemoveRange( | 3611 if (slot_set != nullptr) { |
3612 slot_set->RemoveRange( | |
3611 0, static_cast<int>(object->address() - chunk->address()), | 3613 0, static_cast<int>(object->address() - chunk->address()), |
3612 SlotSet::PREFREE_EMPTY_BUCKETS); | 3614 SlotSet::PREFREE_EMPTY_BUCKETS); |
3613 } | 3615 } |
3614 if (chunk->typed_old_to_new_slots() != nullptr) { | 3616 RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(chunk, chunk->address(), |
3615 RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(chunk, chunk->address(), | 3617 object->address()); |
3616 object->address()); | |
3617 } | |
3618 RecomputeLiveBytes(chunk, state); | 3618 RecomputeLiveBytes(chunk, state); |
3619 } | 3619 } |
3620 return false; | 3620 return false; |
3621 } | 3621 } |
3622 } | 3622 } |
3623 if (iteration_mode == kClearMarkbits) { | 3623 if (iteration_mode == kClearMarkbits) { |
3624 state.ClearLiveness(); | 3624 state.ClearLiveness(); |
3625 } | 3625 } |
3626 return true; | 3626 return true; |
3627 } | 3627 } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3707 EvacuateEpilogue(); | 3707 EvacuateEpilogue(); |
3708 } | 3708 } |
3709 | 3709 |
3710 #ifdef VERIFY_HEAP | 3710 #ifdef VERIFY_HEAP |
3711 if (FLAG_verify_heap && !sweeper().sweeping_in_progress()) { | 3711 if (FLAG_verify_heap && !sweeper().sweeping_in_progress()) { |
3712 VerifyEvacuation(heap()); | 3712 VerifyEvacuation(heap()); |
3713 } | 3713 } |
3714 #endif | 3714 #endif |
3715 } | 3715 } |
3716 | 3716 |
3717 template <PointerDirection direction> | 3717 template <RememberedSetType type> |
3718 class PointerUpdateJobTraits { | 3718 class PointerUpdateJobTraits { |
3719 public: | 3719 public: |
3720 typedef int PerPageData; // Per page data is not used in this job. | 3720 typedef int PerPageData; // Per page data is not used in this job. |
3721 typedef int PerTaskData; // Per task data is not used in this job. | 3721 typedef int PerTaskData; // Per task data is not used in this job. |
3722 | 3722 |
3723 static bool ProcessPageInParallel(Heap* heap, PerTaskData, MemoryChunk* chunk, | 3723 static bool ProcessPageInParallel(Heap* heap, PerTaskData, MemoryChunk* chunk, |
3724 PerPageData) { | 3724 PerPageData) { |
3725 UpdateUntypedPointers(heap, chunk); | 3725 UpdateUntypedPointers(heap, chunk); |
3726 UpdateTypedPointers(heap, chunk); | 3726 UpdateTypedPointers(heap, chunk); |
3727 return true; | 3727 return true; |
3728 } | 3728 } |
3729 static const bool NeedSequentialFinalization = false; | 3729 static const bool NeedSequentialFinalization = false; |
3730 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { | 3730 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { |
3731 } | 3731 } |
3732 | 3732 |
3733 private: | 3733 private: |
3734 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) { | 3734 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) { |
3735 if (direction == OLD_TO_NEW) { | 3735 if (type == OLD_TO_NEW) { |
3736 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) { | 3736 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) { |
3737 return CheckAndUpdateOldToNewSlot(heap, slot); | 3737 return CheckAndUpdateOldToNewSlot(heap, slot); |
3738 }); | 3738 }); |
3739 } else { | 3739 } else { |
3740 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) { | 3740 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) { |
3741 return UpdateSlot(reinterpret_cast<Object**>(slot)); | 3741 return UpdateSlot(reinterpret_cast<Object**>(slot)); |
3742 }); | 3742 }); |
3743 } | 3743 } |
3744 } | 3744 } |
3745 | 3745 |
3746 static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk) { | 3746 static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk) { |
3747 if (direction == OLD_TO_OLD) { | 3747 if (type == OLD_TO_OLD) { |
3748 Isolate* isolate = heap->isolate(); | 3748 Isolate* isolate = heap->isolate(); |
3749 RememberedSet<OLD_TO_OLD>::IterateTyped( | 3749 RememberedSet<OLD_TO_OLD>::IterateTyped( |
3750 chunk, [isolate](SlotType type, Address host_addr, Address slot) { | 3750 chunk, |
3751 return UpdateTypedSlotHelper::UpdateTypedSlot(isolate, type, slot, | 3751 [isolate](SlotType slot_type, Address host_addr, Address slot) { |
3752 UpdateSlot); | 3752 return UpdateTypedSlotHelper::UpdateTypedSlot(isolate, slot_type, |
3753 slot, UpdateSlot); | |
3753 }); | 3754 }); |
3754 } else { | 3755 } else { |
3755 Isolate* isolate = heap->isolate(); | 3756 Isolate* isolate = heap->isolate(); |
3756 RememberedSet<OLD_TO_NEW>::IterateTyped( | 3757 RememberedSet<OLD_TO_NEW>::IterateTyped( |
3757 chunk, | 3758 chunk, |
3758 [isolate, heap](SlotType type, Address host_addr, Address slot) { | 3759 [isolate, heap](SlotType slot_type, Address host_addr, Address slot) { |
3759 return UpdateTypedSlotHelper::UpdateTypedSlot( | 3760 return UpdateTypedSlotHelper::UpdateTypedSlot( |
3760 isolate, type, slot, [heap](Object** slot) { | 3761 isolate, slot_type, slot, [heap](Object** slot) { |
3761 return CheckAndUpdateOldToNewSlot( | 3762 return CheckAndUpdateOldToNewSlot( |
3762 heap, reinterpret_cast<Address>(slot)); | 3763 heap, reinterpret_cast<Address>(slot)); |
3763 }); | 3764 }); |
3764 }); | 3765 }); |
3765 } | 3766 } |
3766 } | 3767 } |
3767 | 3768 |
3768 static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap, | 3769 static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap, |
3769 Address slot_address) { | 3770 Address slot_address) { |
3770 // There may be concurrent action on slots in dead objects. Concurrent | 3771 // There may be concurrent action on slots in dead objects. Concurrent |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3817 | 3818 |
3818 int NumberOfPointerUpdateTasks(int pages) { | 3819 int NumberOfPointerUpdateTasks(int pages) { |
3819 if (!FLAG_parallel_pointer_update) return 1; | 3820 if (!FLAG_parallel_pointer_update) return 1; |
3820 const int available_cores = Max( | 3821 const int available_cores = Max( |
3821 1, static_cast<int>( | 3822 1, static_cast<int>( |
3822 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); | 3823 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); |
3823 const int kPagesPerTask = 4; | 3824 const int kPagesPerTask = 4; |
3824 return Min(available_cores, (pages + kPagesPerTask - 1) / kPagesPerTask); | 3825 return Min(available_cores, (pages + kPagesPerTask - 1) / kPagesPerTask); |
3825 } | 3826 } |
3826 | 3827 |
3827 template <PointerDirection direction> | 3828 template <RememberedSetType type> |
3828 void UpdatePointersInParallel(Heap* heap, base::Semaphore* semaphore) { | 3829 void UpdatePointersInParallel(Heap* heap, base::Semaphore* semaphore) { |
3829 PageParallelJob<PointerUpdateJobTraits<direction> > job( | 3830 PageParallelJob<PointerUpdateJobTraits<type> > job( |
3830 heap, heap->isolate()->cancelable_task_manager(), semaphore); | 3831 heap, heap->isolate()->cancelable_task_manager(), semaphore); |
3831 RememberedSet<direction>::IterateMemoryChunks( | 3832 RememberedSet<type>::IterateMemoryChunks( |
3832 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); }); | 3833 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); }); |
3833 int num_pages = job.NumberOfPages(); | 3834 int num_pages = job.NumberOfPages(); |
3834 int num_tasks = NumberOfPointerUpdateTasks(num_pages); | 3835 int num_tasks = NumberOfPointerUpdateTasks(num_pages); |
3835 job.Run(num_tasks, [](int i) { return 0; }); | 3836 job.Run(num_tasks, [](int i) { return 0; }); |
3836 } | 3837 } |
3837 | 3838 |
3838 class ToSpacePointerUpdateJobTraits { | 3839 class ToSpacePointerUpdateJobTraits { |
3839 public: | 3840 public: |
3840 typedef std::pair<Address, Address> PerPageData; | 3841 typedef std::pair<Address, Address> PerPageData; |
3841 typedef PointersUpdatingVisitor* PerTaskData; | 3842 typedef PointersUpdatingVisitor* PerTaskData; |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3976 const Sweeper::FreeSpaceTreatmentMode free_space_mode = | 3977 const Sweeper::FreeSpaceTreatmentMode free_space_mode = |
3977 Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE; | 3978 Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE; |
3978 if (identity == NEW_SPACE) { | 3979 if (identity == NEW_SPACE) { |
3979 RawSweep(page, IGNORE_FREE_LIST, free_space_mode); | 3980 RawSweep(page, IGNORE_FREE_LIST, free_space_mode); |
3980 } else { | 3981 } else { |
3981 max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode); | 3982 max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode); |
3982 } | 3983 } |
3983 DCHECK(page->SweepingDone()); | 3984 DCHECK(page->SweepingDone()); |
3984 | 3985 |
3985 // After finishing sweeping of a page we clean up its remembered set. | 3986 // After finishing sweeping of a page we clean up its remembered set. |
3986 if (page->typed_old_to_new_slots()) { | 3987 TypedSlotSet* typed_slot_set = page->typed_slot_set<OLD_TO_NEW>(); |
3987 page->typed_old_to_new_slots()->FreeToBeFreedChunks(); | 3988 if (typed_slot_set) { |
3989 typed_slot_set->FreeToBeFreedChunks(); | |
3988 } | 3990 } |
3989 if (page->old_to_new_slots()) { | 3991 SlotSet* slot_set = page->slot_set<OLD_TO_NEW>(); |
3990 page->old_to_new_slots()->FreeToBeFreedBuckets(); | 3992 if (slot_set) { |
3993 slot_set->FreeToBeFreedBuckets(); | |
3991 } | 3994 } |
3992 } | 3995 } |
3993 | 3996 |
3994 { | 3997 { |
3995 base::LockGuard<base::Mutex> guard(&mutex_); | 3998 base::LockGuard<base::Mutex> guard(&mutex_); |
3996 swept_list_[identity].Add(page); | 3999 swept_list_[identity].Add(page); |
3997 } | 4000 } |
3998 return max_freed; | 4001 return max_freed; |
3999 } | 4002 } |
4000 | 4003 |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4147 // The target is always in old space, we don't have to record the slot in | 4150 // The target is always in old space, we don't have to record the slot in |
4148 // the old-to-new remembered set. | 4151 // the old-to-new remembered set. |
4149 DCHECK(!heap()->InNewSpace(target)); | 4152 DCHECK(!heap()->InNewSpace(target)); |
4150 RecordRelocSlot(host, &rinfo, target); | 4153 RecordRelocSlot(host, &rinfo, target); |
4151 } | 4154 } |
4152 } | 4155 } |
4153 } | 4156 } |
4154 | 4157 |
4155 } // namespace internal | 4158 } // namespace internal |
4156 } // namespace v8 | 4159 } // namespace v8 |
OLD | NEW |