sweeper.h 5.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// 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:
26
  typedef std::vector<Page*> IterabilityList;
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
  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;

54 55
      SweepingList* sweeper_list =
          &sweeper_->sweeping_list_[GetSweepSpaceIndex(OLD_SPACE)];
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
      // 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 };

80
  Sweeper(Heap* heap, MajorNonAtomicMarkingState* marking_state);
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

  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);

105 106 107 108 109 110
  void EnsurePageIsIterable(Page* page);

  void AddPageForIterability(Page* page);
  void StartIterabilityTasks();
  void EnsureIterabilityCompleted();

111 112
 private:
  class IncrementalSweeperTask;
113
  class IterabilityTask;
114 115
  class SweeperTask;

116 117
  static const int kNumberOfSweepingSpaces =
      LAST_GROWABLE_PAGED_SPACE - FIRST_GROWABLE_PAGED_SPACE + 1;
118
  static const int kMaxSweeperTasks = 3;
119 120

  template <typename Callback>
121 122 123 124
  void ForAllSweepingSpaces(Callback callback) const {
    callback(OLD_SPACE);
    callback(CODE_SPACE);
    callback(MAP_SPACE);
125 126 127 128
  }

  // Can only be called on the main thread when no tasks are running.
  bool IsDoneSweeping() const {
129 130
    bool is_done = true;
    ForAllSweepingSpaces([this, &is_done](AllocationSpace space) {
131
      if (!sweeping_list_[GetSweepSpaceIndex(space)].empty()) is_done = false;
132 133
    });
    return is_done;
134 135 136 137 138 139 140 141 142 143 144 145 146 147
  }

  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);

148 149 150 151 152
  void SweepOrWaitUntilSweepingCompleted(Page* page);

  void MakeIterable(Page* page);

  bool IsValidIterabilitySpace(AllocationSpace space) {
153
    return space == NEW_SPACE || space == RO_SPACE;
154 155
  }

156
  static bool IsValidSweepingSpace(AllocationSpace space) {
157 158
    return space >= FIRST_GROWABLE_PAGED_SPACE &&
           space <= LAST_GROWABLE_PAGED_SPACE;
159 160
  }

161 162 163 164 165
  static int GetSweepSpaceIndex(AllocationSpace space) {
    DCHECK(IsValidSweepingSpace(space));
    return space - FIRST_GROWABLE_PAGED_SPACE;
  }

166 167 168
  Heap* const heap_;
  MajorNonAtomicMarkingState* marking_state_;
  int num_tasks_;
169
  CancelableTaskManager::Id task_ids_[kNumberOfSweepingSpaces];
170 171
  base::Semaphore pending_sweeper_tasks_semaphore_;
  base::Mutex mutex_;
172 173
  SweptList swept_list_[kNumberOfSweepingSpaces];
  SweepingList sweeping_list_[kNumberOfSweepingSpaces];
174 175 176 177
  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.
178
  std::atomic<intptr_t> num_sweeping_tasks_;
179
  // Used by PauseOrCompleteScope to signal early bailout to tasks.
180
  std::atomic<bool> stop_sweeper_tasks_;
181 182 183 184 185 186 187

  // 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_;
188
  bool should_reduce_memory_;
189 190 191 192 193 194
};

}  // namespace internal
}  // namespace v8

#endif  // V8_HEAP_SWEEPER_H_