| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_HEAP_SWEEPER_H_ |
| #define V8_HEAP_SWEEPER_H_ |
| |
| #include <deque> |
| #include <vector> |
| |
| #include "src/base/platform/semaphore.h" |
| #include "src/cancelable-task.h" |
| #include "src/globals.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class MajorNonAtomicMarkingState; |
| class Page; |
| class PagedSpace; |
| |
| enum FreeSpaceTreatmentMode { IGNORE_FREE_SPACE, ZAP_FREE_SPACE }; |
| |
| class Sweeper { |
| public: |
| typedef std::vector<Page*> IterabilityList; |
| typedef std::deque<Page*> SweepingList; |
| typedef std::vector<Page*> SweptList; |
| |
| // Pauses the sweeper tasks or completes sweeping. |
| class PauseOrCompleteScope final { |
| public: |
| explicit PauseOrCompleteScope(Sweeper* sweeper); |
| ~PauseOrCompleteScope(); |
| |
| private: |
| Sweeper* const sweeper_; |
| }; |
| |
| // Temporary filters old space sweeping lists. Requires the concurrent |
| // sweeper to be paused. Allows for pages to be added to the sweeper while |
| // in this scope. Note that the original list of sweeping pages is restored |
| // after exiting this scope. |
| class FilterSweepingPagesScope final { |
| public: |
| explicit FilterSweepingPagesScope( |
| Sweeper* sweeper, const PauseOrCompleteScope& pause_or_complete_scope); |
| ~FilterSweepingPagesScope(); |
| |
| template <typename Callback> |
| void FilterOldSpaceSweepingPages(Callback callback) { |
| if (!sweeping_in_progress_) return; |
| |
| SweepingList* sweeper_list = &sweeper_->sweeping_list_[OLD_SPACE]; |
| // Iteration here is from most free space to least free space. |
| for (auto it = old_space_sweeping_list_.begin(); |
| it != old_space_sweeping_list_.end(); it++) { |
| if (callback(*it)) { |
| sweeper_list->push_back(*it); |
| } |
| } |
| } |
| |
| private: |
| Sweeper* const sweeper_; |
| SweepingList old_space_sweeping_list_; |
| const PauseOrCompleteScope& pause_or_complete_scope_; |
| bool sweeping_in_progress_; |
| }; |
| |
| enum FreeListRebuildingMode { REBUILD_FREE_LIST, IGNORE_FREE_LIST }; |
| enum ClearOldToNewSlotsMode { |
| DO_NOT_CLEAR, |
| CLEAR_REGULAR_SLOTS, |
| CLEAR_TYPED_SLOTS |
| }; |
| enum AddPageMode { REGULAR, READD_TEMPORARY_REMOVED_PAGE }; |
| |
| Sweeper(Heap* heap, MajorNonAtomicMarkingState* marking_state) |
| : heap_(heap), |
| marking_state_(marking_state), |
| num_tasks_(0), |
| pending_sweeper_tasks_semaphore_(0), |
| incremental_sweeper_pending_(false), |
| sweeping_in_progress_(false), |
| num_sweeping_tasks_(0), |
| stop_sweeper_tasks_(false), |
| iterability_task_semaphore_(0), |
| iterability_in_progress_(false), |
| iterability_task_started_(false) {} |
| |
| bool sweeping_in_progress() const { return sweeping_in_progress_; } |
| |
| void AddPage(AllocationSpace space, Page* page, AddPageMode mode); |
| |
| int ParallelSweepSpace(AllocationSpace identity, int required_freed_bytes, |
| int max_pages = 0); |
| int ParallelSweepPage(Page* page, AllocationSpace identity); |
| |
| void ScheduleIncrementalSweepingTask(); |
| |
| int RawSweep(Page* p, FreeListRebuildingMode free_list_mode, |
| FreeSpaceTreatmentMode free_space_mode); |
| |
| // After calling this function sweeping is considered to be in progress |
| // and the main thread can sweep lazily, but the background sweeper tasks |
| // are not running yet. |
| void StartSweeping(); |
| void StartSweeperTasks(); |
| void EnsureCompleted(); |
| bool AreSweeperTasksRunning(); |
| |
| Page* GetSweptPageSafe(PagedSpace* space); |
| |
| void EnsurePageIsIterable(Page* page); |
| |
| void AddPageForIterability(Page* page); |
| void StartIterabilityTasks(); |
| void EnsureIterabilityCompleted(); |
| |
| private: |
| class IncrementalSweeperTask; |
| class IterabilityTask; |
| class SweeperTask; |
| |
| static const int kNumberOfSweepingSpaces = LAST_PAGED_SPACE + 1; |
| static const int kMaxSweeperTasks = 3; |
| |
| template <typename Callback> |
| void ForAllSweepingSpaces(Callback callback) const { |
| callback(OLD_SPACE); |
| callback(CODE_SPACE); |
| callback(MAP_SPACE); |
| } |
| |
| // Can only be called on the main thread when no tasks are running. |
| bool IsDoneSweeping() const { |
| bool is_done = true; |
| ForAllSweepingSpaces([this, &is_done](AllocationSpace space) { |
| if (!sweeping_list_[space].empty()) is_done = false; |
| }); |
| return is_done; |
| } |
| |
| void SweepSpaceFromTask(AllocationSpace identity); |
| |
| // Sweeps incrementally one page from the given space. Returns true if |
| // there are no more pages to sweep in the given space. |
| bool SweepSpaceIncrementallyFromTask(AllocationSpace identity); |
| |
| void AbortAndWaitForTasks(); |
| |
| Page* GetSweepingPageSafe(AllocationSpace space); |
| |
| void PrepareToBeSweptPage(AllocationSpace space, Page* page); |
| |
| void SweepOrWaitUntilSweepingCompleted(Page* page); |
| |
| void MakeIterable(Page* page); |
| |
| bool IsValidIterabilitySpace(AllocationSpace space) { |
| return space == NEW_SPACE; |
| } |
| |
| bool IsValidSweepingSpace(AllocationSpace space) { |
| return space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE; |
| } |
| |
| Heap* const heap_; |
| MajorNonAtomicMarkingState* marking_state_; |
| int num_tasks_; |
| CancelableTaskManager::Id task_ids_[kNumberOfSweepingSpaces]; |
| base::Semaphore pending_sweeper_tasks_semaphore_; |
| base::Mutex mutex_; |
| SweptList swept_list_[kNumberOfSweepingSpaces]; |
| SweepingList sweeping_list_[kNumberOfSweepingSpaces]; |
| bool incremental_sweeper_pending_; |
| bool sweeping_in_progress_; |
| // Counter is actively maintained by the concurrent tasks to avoid querying |
| // the semaphore for maintaining a task counter on the main thread. |
| base::AtomicNumber<intptr_t> num_sweeping_tasks_; |
| // Used by PauseOrCompleteScope to signal early bailout to tasks. |
| base::AtomicValue<bool> stop_sweeper_tasks_; |
| |
| // Pages that are only made iterable but have their free lists ignored. |
| IterabilityList iterability_list_; |
| CancelableTaskManager::Id iterability_task_id_; |
| base::Semaphore iterability_task_semaphore_; |
| bool iterability_in_progress_; |
| bool iterability_task_started_; |
| }; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_HEAP_SWEEPER_H_ |