Chromium Code Reviews| 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 |