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 612 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 space->top() == space->limit() | 623 space->top() == space->limit() |
624 ? nullptr | 624 ? nullptr |
625 : Page::FromAllocationAreaAddress(space->top()); | 625 : Page::FromAllocationAreaAddress(space->top()); |
626 for (Page* p : *space) { | 626 for (Page* p : *space) { |
627 if (p->NeverEvacuate() || p == owner_of_linear_allocation_area) continue; | 627 if (p->NeverEvacuate() || p == owner_of_linear_allocation_area) continue; |
628 // Invariant: Evacuation candidates are just created when marking is | 628 // Invariant: Evacuation candidates are just created when marking is |
629 // started. This means that sweeping has finished. Furthermore, at the end | 629 // started. This means that sweeping has finished. Furthermore, at the end |
630 // of a GC all evacuation candidates are cleared and their slot buffers are | 630 // of a GC all evacuation candidates are cleared and their slot buffers are |
631 // released. | 631 // released. |
632 CHECK(!p->IsEvacuationCandidate()); | 632 CHECK(!p->IsEvacuationCandidate()); |
633 CHECK_NULL(p->old_to_old_slots()); | 633 CHECK_NULL(p->slot_set<OLD_TO_OLD>()); |
634 CHECK_NULL(p->typed_old_to_old_slots()); | 634 CHECK_NULL(p->typed_slot_set<OLD_TO_OLD>()); |
635 CHECK(p->SweepingDone()); | 635 CHECK(p->SweepingDone()); |
636 DCHECK(p->area_size() == area_size); | 636 DCHECK(p->area_size() == area_size); |
637 pages.push_back(std::make_pair(p->LiveBytesFromFreeList(), p)); | 637 pages.push_back(std::make_pair(p->LiveBytesFromFreeList(), p)); |
638 } | 638 } |
639 | 639 |
640 int candidate_count = 0; | 640 int candidate_count = 0; |
641 size_t total_live_bytes = 0; | 641 size_t total_live_bytes = 0; |
642 | 642 |
643 const bool reduce_memory = heap()->ShouldReduceMemory(); | 643 const bool reduce_memory = heap()->ShouldReduceMemory(); |
644 if (FLAG_manual_evacuation_candidates_selection) { | 644 if (FLAG_manual_evacuation_candidates_selection) { |
(...skipping 2652 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3297 return map_word.ToForwardingAddress(); | 3297 return map_word.ToForwardingAddress(); |
3298 } | 3298 } |
3299 } | 3299 } |
3300 return object; | 3300 return object; |
3301 } | 3301 } |
3302 }; | 3302 }; |
3303 | 3303 |
3304 MarkCompactCollector::Sweeper::ClearOldToNewSlotsMode | 3304 MarkCompactCollector::Sweeper::ClearOldToNewSlotsMode |
3305 MarkCompactCollector::Sweeper::GetClearOldToNewSlotsMode(Page* p) { | 3305 MarkCompactCollector::Sweeper::GetClearOldToNewSlotsMode(Page* p) { |
3306 AllocationSpace identity = p->owner()->identity(); | 3306 AllocationSpace identity = p->owner()->identity(); |
3307 if (p->old_to_new_slots() && | 3307 if (p->slot_set<OLD_TO_NEW>() && |
3308 (identity == OLD_SPACE || identity == MAP_SPACE)) { | 3308 (identity == OLD_SPACE || identity == MAP_SPACE)) { |
3309 return MarkCompactCollector::Sweeper::CLEAR_REGULAR_SLOTS; | 3309 return MarkCompactCollector::Sweeper::CLEAR_REGULAR_SLOTS; |
3310 } else if (p->typed_old_to_new_slots() && identity == CODE_SPACE) { | 3310 } else if (p->typed_slot_set<OLD_TO_NEW>() && identity == CODE_SPACE) { |
3311 return MarkCompactCollector::Sweeper::CLEAR_TYPED_SLOTS; | 3311 return MarkCompactCollector::Sweeper::CLEAR_TYPED_SLOTS; |
3312 } | 3312 } |
3313 return MarkCompactCollector::Sweeper::DO_NOT_CLEAR; | 3313 return MarkCompactCollector::Sweeper::DO_NOT_CLEAR; |
3314 } | 3314 } |
3315 | 3315 |
3316 int MarkCompactCollector::Sweeper::RawSweep( | 3316 int MarkCompactCollector::Sweeper::RawSweep( |
3317 Page* p, FreeListRebuildingMode free_list_mode, | 3317 Page* p, FreeListRebuildingMode free_list_mode, |
3318 FreeSpaceTreatmentMode free_space_mode) { | 3318 FreeSpaceTreatmentMode free_space_mode) { |
3319 Space* space = p->owner(); | 3319 Space* space = p->owner(); |
3320 DCHECK_NOT_NULL(space); | 3320 DCHECK_NOT_NULL(space); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3414 SlotSet::KEEP_EMPTY_BUCKETS); | 3414 SlotSet::KEEP_EMPTY_BUCKETS); |
3415 } else if (slots_clearing_mode == CLEAR_TYPED_SLOTS) { | 3415 } else if (slots_clearing_mode == CLEAR_TYPED_SLOTS) { |
3416 free_ranges.insert(std::pair<uint32_t, uint32_t>( | 3416 free_ranges.insert(std::pair<uint32_t, uint32_t>( |
3417 static_cast<uint32_t>(free_start - p->address()), | 3417 static_cast<uint32_t>(free_start - p->address()), |
3418 static_cast<uint32_t>(p->area_end() - p->address()))); | 3418 static_cast<uint32_t>(p->area_end() - p->address()))); |
3419 } | 3419 } |
3420 } | 3420 } |
3421 | 3421 |
3422 // Clear invalid typed slots after collection all free ranges. | 3422 // Clear invalid typed slots after collection all free ranges. |
3423 if (slots_clearing_mode == CLEAR_TYPED_SLOTS) { | 3423 if (slots_clearing_mode == CLEAR_TYPED_SLOTS) { |
3424 p->typed_old_to_new_slots()->RemoveInvaldSlots(free_ranges); | 3424 p->typed_slot_set<OLD_TO_NEW>()->RemoveInvaldSlots(free_ranges); |
3425 } | 3425 } |
3426 | 3426 |
3427 // Clear the mark bits of that page and reset live bytes count. | 3427 // Clear the mark bits of that page and reset live bytes count. |
3428 p->ClearLiveness(); | 3428 p->ClearLiveness(); |
3429 | 3429 |
3430 p->concurrent_sweeping_state().SetValue(Page::kSweepingDone); | 3430 p->concurrent_sweeping_state().SetValue(Page::kSweepingDone); |
3431 if (free_list_mode == IGNORE_FREE_LIST) return 0; | 3431 if (free_list_mode == IGNORE_FREE_LIST) return 0; |
3432 return static_cast<int>(FreeList::GuaranteedAllocatable(max_freed_bytes)); | 3432 return static_cast<int>(FreeList::GuaranteedAllocatable(max_freed_bytes)); |
3433 } | 3433 } |
3434 | 3434 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3469 IterationMode mode) { | 3469 IterationMode mode) { |
3470 LiveObjectIterator<kBlackObjects> it(page); | 3470 LiveObjectIterator<kBlackObjects> it(page); |
3471 HeapObject* object = nullptr; | 3471 HeapObject* object = nullptr; |
3472 while ((object = it.Next()) != nullptr) { | 3472 while ((object = it.Next()) != nullptr) { |
3473 DCHECK(ObjectMarking::IsBlack(object)); | 3473 DCHECK(ObjectMarking::IsBlack(object)); |
3474 if (!visitor->Visit(object)) { | 3474 if (!visitor->Visit(object)) { |
3475 if (mode == kClearMarkbits) { | 3475 if (mode == kClearMarkbits) { |
3476 page->markbits()->ClearRange( | 3476 page->markbits()->ClearRange( |
3477 page->AddressToMarkbitIndex(page->area_start()), | 3477 page->AddressToMarkbitIndex(page->area_start()), |
3478 page->AddressToMarkbitIndex(object->address())); | 3478 page->AddressToMarkbitIndex(object->address())); |
3479 if (page->old_to_new_slots() != nullptr) { | 3479 SlotSet* slot_set = page->slot_set<OLD_TO_NEW>(); |
3480 page->old_to_new_slots()->RemoveRange( | 3480 if (slot_set != nullptr) { |
| 3481 slot_set->RemoveRange( |
3481 0, static_cast<int>(object->address() - page->address()), | 3482 0, static_cast<int>(object->address() - page->address()), |
3482 SlotSet::PREFREE_EMPTY_BUCKETS); | 3483 SlotSet::PREFREE_EMPTY_BUCKETS); |
3483 } | 3484 } |
3484 if (page->typed_old_to_new_slots() != nullptr) { | 3485 RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, page->address(), |
3485 RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, page->address(), | 3486 object->address()); |
3486 object->address()); | |
3487 } | |
3488 RecomputeLiveBytes(page); | 3487 RecomputeLiveBytes(page); |
3489 } | 3488 } |
3490 return false; | 3489 return false; |
3491 } | 3490 } |
3492 } | 3491 } |
3493 if (mode == kClearMarkbits) { | 3492 if (mode == kClearMarkbits) { |
3494 page->ClearLiveness(); | 3493 page->ClearLiveness(); |
3495 } | 3494 } |
3496 return true; | 3495 return true; |
3497 } | 3496 } |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3577 EvacuateEpilogue(); | 3576 EvacuateEpilogue(); |
3578 } | 3577 } |
3579 | 3578 |
3580 #ifdef VERIFY_HEAP | 3579 #ifdef VERIFY_HEAP |
3581 if (FLAG_verify_heap && !sweeper().sweeping_in_progress()) { | 3580 if (FLAG_verify_heap && !sweeper().sweeping_in_progress()) { |
3582 VerifyEvacuation(heap()); | 3581 VerifyEvacuation(heap()); |
3583 } | 3582 } |
3584 #endif | 3583 #endif |
3585 } | 3584 } |
3586 | 3585 |
3587 template <PointerDirection direction> | 3586 template <RememberedSetType type> |
3588 class PointerUpdateJobTraits { | 3587 class PointerUpdateJobTraits { |
3589 public: | 3588 public: |
3590 typedef int PerPageData; // Per page data is not used in this job. | 3589 typedef int PerPageData; // Per page data is not used in this job. |
3591 typedef int PerTaskData; // Per task data is not used in this job. | 3590 typedef int PerTaskData; // Per task data is not used in this job. |
3592 | 3591 |
3593 static bool ProcessPageInParallel(Heap* heap, PerTaskData, MemoryChunk* chunk, | 3592 static bool ProcessPageInParallel(Heap* heap, PerTaskData, MemoryChunk* chunk, |
3594 PerPageData) { | 3593 PerPageData) { |
3595 UpdateUntypedPointers(heap, chunk); | 3594 UpdateUntypedPointers(heap, chunk); |
3596 UpdateTypedPointers(heap, chunk); | 3595 UpdateTypedPointers(heap, chunk); |
3597 return true; | 3596 return true; |
3598 } | 3597 } |
3599 static const bool NeedSequentialFinalization = false; | 3598 static const bool NeedSequentialFinalization = false; |
3600 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { | 3599 static void FinalizePageSequentially(Heap*, MemoryChunk*, bool, PerPageData) { |
3601 } | 3600 } |
3602 | 3601 |
3603 private: | 3602 private: |
3604 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) { | 3603 static void UpdateUntypedPointers(Heap* heap, MemoryChunk* chunk) { |
3605 if (direction == OLD_TO_NEW) { | 3604 if (type == OLD_TO_NEW) { |
3606 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) { | 3605 RememberedSet<OLD_TO_NEW>::Iterate(chunk, [heap](Address slot) { |
3607 return CheckAndUpdateOldToNewSlot(heap, slot); | 3606 return CheckAndUpdateOldToNewSlot(heap, slot); |
3608 }); | 3607 }); |
3609 } else { | 3608 } else { |
3610 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) { | 3609 RememberedSet<OLD_TO_OLD>::Iterate(chunk, [](Address slot) { |
3611 return UpdateSlot(reinterpret_cast<Object**>(slot)); | 3610 return UpdateSlot(reinterpret_cast<Object**>(slot)); |
3612 }); | 3611 }); |
3613 } | 3612 } |
3614 } | 3613 } |
3615 | 3614 |
3616 static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk) { | 3615 static void UpdateTypedPointers(Heap* heap, MemoryChunk* chunk) { |
3617 if (direction == OLD_TO_OLD) { | 3616 if (type == OLD_TO_OLD) { |
3618 Isolate* isolate = heap->isolate(); | 3617 Isolate* isolate = heap->isolate(); |
3619 RememberedSet<OLD_TO_OLD>::IterateTyped( | 3618 RememberedSet<OLD_TO_OLD>::IterateTyped( |
3620 chunk, [isolate](SlotType type, Address host_addr, Address slot) { | 3619 chunk, |
3621 return UpdateTypedSlotHelper::UpdateTypedSlot(isolate, type, slot, | 3620 [isolate](SlotType slot_type, Address host_addr, Address slot) { |
3622 UpdateSlot); | 3621 return UpdateTypedSlotHelper::UpdateTypedSlot(isolate, slot_type, |
| 3622 slot, UpdateSlot); |
3623 }); | 3623 }); |
3624 } else { | 3624 } else { |
3625 Isolate* isolate = heap->isolate(); | 3625 Isolate* isolate = heap->isolate(); |
3626 RememberedSet<OLD_TO_NEW>::IterateTyped( | 3626 RememberedSet<OLD_TO_NEW>::IterateTyped( |
3627 chunk, | 3627 chunk, |
3628 [isolate, heap](SlotType type, Address host_addr, Address slot) { | 3628 [isolate, heap](SlotType slot_type, Address host_addr, Address slot) { |
3629 return UpdateTypedSlotHelper::UpdateTypedSlot( | 3629 return UpdateTypedSlotHelper::UpdateTypedSlot( |
3630 isolate, type, slot, [heap](Object** slot) { | 3630 isolate, slot_type, slot, [heap](Object** slot) { |
3631 return CheckAndUpdateOldToNewSlot( | 3631 return CheckAndUpdateOldToNewSlot( |
3632 heap, reinterpret_cast<Address>(slot)); | 3632 heap, reinterpret_cast<Address>(slot)); |
3633 }); | 3633 }); |
3634 }); | 3634 }); |
3635 } | 3635 } |
3636 } | 3636 } |
3637 | 3637 |
3638 static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap, | 3638 static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap, |
3639 Address slot_address) { | 3639 Address slot_address) { |
3640 // There may be concurrent action on slots in dead objects. Concurrent | 3640 // There may be concurrent action on slots in dead objects. Concurrent |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3685 | 3685 |
3686 int NumberOfPointerUpdateTasks(int pages) { | 3686 int NumberOfPointerUpdateTasks(int pages) { |
3687 if (!FLAG_parallel_pointer_update) return 1; | 3687 if (!FLAG_parallel_pointer_update) return 1; |
3688 const int available_cores = Max( | 3688 const int available_cores = Max( |
3689 1, static_cast<int>( | 3689 1, static_cast<int>( |
3690 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); | 3690 V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads())); |
3691 const int kPagesPerTask = 4; | 3691 const int kPagesPerTask = 4; |
3692 return Min(available_cores, (pages + kPagesPerTask - 1) / kPagesPerTask); | 3692 return Min(available_cores, (pages + kPagesPerTask - 1) / kPagesPerTask); |
3693 } | 3693 } |
3694 | 3694 |
3695 template <PointerDirection direction> | 3695 template <RememberedSetType type> |
3696 void UpdatePointersInParallel(Heap* heap, base::Semaphore* semaphore) { | 3696 void UpdatePointersInParallel(Heap* heap, base::Semaphore* semaphore) { |
3697 PageParallelJob<PointerUpdateJobTraits<direction> > job( | 3697 PageParallelJob<PointerUpdateJobTraits<type> > job( |
3698 heap, heap->isolate()->cancelable_task_manager(), semaphore); | 3698 heap, heap->isolate()->cancelable_task_manager(), semaphore); |
3699 RememberedSet<direction>::IterateMemoryChunks( | 3699 RememberedSet<type>::IterateMemoryChunks( |
3700 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); }); | 3700 heap, [&job](MemoryChunk* chunk) { job.AddPage(chunk, 0); }); |
3701 int num_pages = job.NumberOfPages(); | 3701 int num_pages = job.NumberOfPages(); |
3702 int num_tasks = NumberOfPointerUpdateTasks(num_pages); | 3702 int num_tasks = NumberOfPointerUpdateTasks(num_pages); |
3703 job.Run(num_tasks, [](int i) { return 0; }); | 3703 job.Run(num_tasks, [](int i) { return 0; }); |
3704 } | 3704 } |
3705 | 3705 |
3706 class ToSpacePointerUpdateJobTraits { | 3706 class ToSpacePointerUpdateJobTraits { |
3707 public: | 3707 public: |
3708 typedef std::pair<Address, Address> PerPageData; | 3708 typedef std::pair<Address, Address> PerPageData; |
3709 typedef PointersUpdatingVisitor* PerTaskData; | 3709 typedef PointersUpdatingVisitor* PerTaskData; |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3844 const Sweeper::FreeSpaceTreatmentMode free_space_mode = | 3844 const Sweeper::FreeSpaceTreatmentMode free_space_mode = |
3845 Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE; | 3845 Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE; |
3846 if (identity == NEW_SPACE) { | 3846 if (identity == NEW_SPACE) { |
3847 RawSweep(page, IGNORE_FREE_LIST, free_space_mode); | 3847 RawSweep(page, IGNORE_FREE_LIST, free_space_mode); |
3848 } else { | 3848 } else { |
3849 max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode); | 3849 max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode); |
3850 } | 3850 } |
3851 DCHECK(page->SweepingDone()); | 3851 DCHECK(page->SweepingDone()); |
3852 | 3852 |
3853 // After finishing sweeping of a page we clean up its remembered set. | 3853 // After finishing sweeping of a page we clean up its remembered set. |
3854 if (page->typed_old_to_new_slots()) { | 3854 TypedSlotSet* typed_slot_set = page->typed_slot_set<OLD_TO_NEW>(); |
3855 page->typed_old_to_new_slots()->FreeToBeFreedChunks(); | 3855 if (typed_slot_set) { |
| 3856 page->typed_slot_set<OLD_TO_NEW>()->FreeToBeFreedChunks(); |
3856 } | 3857 } |
3857 if (page->old_to_new_slots()) { | 3858 SlotSet* slot_set = page->slot_set<OLD_TO_NEW>(); |
3858 page->old_to_new_slots()->FreeToBeFreedBuckets(); | 3859 if (slot_set) { |
| 3860 page->slot_set<OLD_TO_NEW>()->FreeToBeFreedBuckets(); |
3859 } | 3861 } |
3860 } | 3862 } |
3861 | 3863 |
3862 { | 3864 { |
3863 base::LockGuard<base::Mutex> guard(&mutex_); | 3865 base::LockGuard<base::Mutex> guard(&mutex_); |
3864 swept_list_[identity].Add(page); | 3866 swept_list_[identity].Add(page); |
3865 } | 3867 } |
3866 return max_freed; | 3868 return max_freed; |
3867 } | 3869 } |
3868 | 3870 |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4013 // The target is always in old space, we don't have to record the slot in | 4015 // The target is always in old space, we don't have to record the slot in |
4014 // the old-to-new remembered set. | 4016 // the old-to-new remembered set. |
4015 DCHECK(!heap()->InNewSpace(target)); | 4017 DCHECK(!heap()->InNewSpace(target)); |
4016 RecordRelocSlot(host, &rinfo, target); | 4018 RecordRelocSlot(host, &rinfo, target); |
4017 } | 4019 } |
4018 } | 4020 } |
4019 } | 4021 } |
4020 | 4022 |
4021 } // namespace internal | 4023 } // namespace internal |
4022 } // namespace v8 | 4024 } // namespace v8 |
OLD | NEW |