marker.h 6.66 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
// Copyright 2020 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_CPPGC_MARKER_H_
#define V8_HEAP_CPPGC_MARKER_H_

#include <memory>

#include "include/cppgc/heap.h"
#include "include/cppgc/visitor.h"
12
#include "src/base/macros.h"
13
#include "src/base/platform/time.h"
14
#include "src/heap/cppgc/globals.h"
15
#include "src/heap/cppgc/incremental-marking-schedule.h"
16
#include "src/heap/cppgc/marking-state.h"
17
#include "src/heap/cppgc/marking-visitor.h"
18
#include "src/heap/cppgc/marking-worklists.h"
19
#include "src/heap/cppgc/task-handle.h"
20 21 22 23 24
#include "src/heap/cppgc/worklist.h"

namespace cppgc {
namespace internal {

25
class HeapBase;
26
class MarkerFactory;
27

28 29
// Marking algorithm. Example for a valid call sequence creating the marking
// phase:
30 31
// 1. StartMarking() [Called implicitly when creating a Marker using
//                    MarkerFactory]
32 33 34 35 36 37
// 2. AdvanceMarkingWithDeadline() [Optional, depending on environment.]
// 3. EnterAtomicPause()
// 4. AdvanceMarkingWithDeadline()
// 5. LeaveAtomicPause()
//
// Alternatively, FinishMarking combines steps 3.-5.
38
class V8_EXPORT_PRIVATE MarkerBase {
39 40
 public:
  struct MarkingConfig {
41 42 43 44
    enum class CollectionType : uint8_t {
      kMinor,
      kMajor,
    };
45
    using StackState = cppgc::Heap::StackState;
46 47 48 49 50 51 52 53
    enum MarkingType : uint8_t {
      kAtomic,
      kIncremental,
      kIncrementalAndConcurrent
    };

    static constexpr MarkingConfig Default() { return {}; }

54
    const CollectionType collection_type = CollectionType::kMajor;
55
    StackState stack_state = StackState::kMayContainHeapPointers;
56
    MarkingType marking_type = MarkingType::kIncremental;
57 58
  };

59
  virtual ~MarkerBase();
60

61 62
  MarkerBase(const MarkerBase&) = delete;
  MarkerBase& operator=(const MarkerBase&) = delete;
63

64 65 66 67
  // Signals entering the atomic marking pause. The method
  // - stops incremental/concurrent marking;
  // - flushes back any in-construction worklists if needed;
  // - Updates the MarkingConfig if the stack state has changed;
68
  void EnterAtomicPause(MarkingConfig::StackState);
69 70

  // Makes marking progress.
71 72
  // TODO(chromium:1056170): Remove TimeDelta argument when unified heap no
  // longer uses it.
73
  bool AdvanceMarkingWithMaxDuration(v8::base::TimeDelta);
74

75 76 77
  // Makes marking progress when allocation a new lab.
  bool AdvanceMarkingOnAllocation();

78 79 80 81
  // Signals leaving the atomic marking pause. This method expects no more
  // objects to be marked and merely updates marking states if needed.
  void LeaveAtomicPause();

82 83 84 85
  // Combines:
  // - EnterAtomicPause()
  // - AdvanceMarkingWithDeadline()
  // - LeaveAtomicPause()
86
  void FinishMarking(MarkingConfig::StackState);
87 88 89

  void ProcessWeakness();

90
  inline void WriteBarrierForInConstructionObject(HeapObjectHeader&);
91 92
  inline void WriteBarrierForObject(HeapObjectHeader&);

93
  HeapBase& heap() { return heap_; }
94

95 96
  MarkingWorklists& MarkingWorklistsForTesting() { return marking_worklists_; }
  MarkingState& MarkingStateForTesting() { return mutator_marking_state_; }
97
  cppgc::Visitor& VisitorForTesting() { return visitor(); }
98 99
  void ClearAllWorklistsForTesting();

100
  bool IncrementalMarkingStepForTesting(MarkingConfig::StackState);
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117

  class IncrementalMarkingTask final : public v8::Task {
   public:
    using Handle = SingleThreadedHandle;

    explicit IncrementalMarkingTask(MarkerBase*);

    static Handle Post(v8::TaskRunner*, MarkerBase*);

   private:
    void Run() final;

    MarkerBase* const marker_;
    // TODO(chromium:1056170): Change to CancelableTask.
    Handle handle_;
  };

118
 protected:
119 120 121
  static constexpr v8::base::TimeDelta kMaximumIncrementalStepDuration =
      v8::base::TimeDelta::FromMilliseconds(2);

122 123 124 125 126 127 128 129 130 131 132
  class Key {
   private:
    Key() = default;
    friend class MarkerFactory;
  };

  MarkerBase(Key, HeapBase&, cppgc::Platform*, MarkingConfig);

  // Initialize marking according to the given config. This method will
  // trigger incremental/concurrent marking if needed.
  void StartMarking();
133 134 135 136

  virtual cppgc::Visitor& visitor() = 0;
  virtual ConservativeTracingVisitor& conservative_visitor() = 0;
  virtual heap::base::StackVisitor& stack_visitor() = 0;
137

138 139 140 141 142 143
  // Makes marking progress.
  // TODO(chromium:1056170): Remove TimeDelta argument when unified heap no
  // longer uses it.
  bool AdvanceMarkingWithDeadline(
      v8::base::TimeDelta = kMaximumIncrementalStepDuration);

144
  bool ProcessWorklistsWithDeadline(size_t, v8::base::TimeDelta);
145 146

  void VisitRoots(MarkingConfig::StackState);
147

148
  void MarkNotFullyConstructedObjects();
149

150 151
  void ScheduleIncrementalMarkingTask();

152
  bool IncrementalMarkingStep(MarkingConfig::StackState);
153

154
  HeapBase& heap_;
155 156
  MarkingConfig config_ = MarkingConfig::Default();

157 158 159 160
  cppgc::Platform* platform_;
  std::shared_ptr<v8::TaskRunner> foreground_task_runner_;
  IncrementalMarkingTask::Handle incremental_marking_handle_;

161 162
  MarkingWorklists marking_worklists_;
  MarkingState mutator_marking_state_;
163
  bool is_marking_started_ = false;
164

165 166
  IncrementalMarkingSchedule schedule_;

167 168 169 170 171 172 173 174 175 176 177 178 179 180
  friend class MarkerFactory;
};

class V8_EXPORT_PRIVATE MarkerFactory {
 public:
  template <typename T, typename... Args>
  static std::unique_ptr<T> CreateAndStartMarking(Args&&... args) {
    static_assert(std::is_base_of<MarkerBase, T>::value,
                  "MarkerFactory can only create subclasses of MarkerBase");
    std::unique_ptr<T> marker =
        std::make_unique<T>(MarkerBase::Key(), std::forward<Args>(args)...);
    marker->StartMarking();
    return marker;
  }
181 182 183 184
};

class V8_EXPORT_PRIVATE Marker final : public MarkerBase {
 public:
185 186
  Marker(Key, HeapBase&, cppgc::Platform*,
         MarkingConfig = MarkingConfig::Default());
187 188 189 190 191 192 193 194 195

 protected:
  cppgc::Visitor& visitor() final { return marking_visitor_; }
  ConservativeTracingVisitor& conservative_visitor() final {
    return conservative_marking_visitor_;
  }
  heap::base::StackVisitor& stack_visitor() final {
    return conservative_marking_visitor_;
  }
196

197 198 199
 private:
  MarkingVisitor marking_visitor_;
  ConservativeMarkingVisitor conservative_marking_visitor_;
200 201
};

202
void MarkerBase::WriteBarrierForInConstructionObject(HeapObjectHeader& header) {
203 204 205 206
  MarkingWorklists::NotFullyConstructedWorklist::View
      not_fully_constructed_worklist(
          marking_worklists_.not_fully_constructed_worklist(),
          MarkingWorklists::kMutatorThreadId);
207
  not_fully_constructed_worklist.Push(&header);
208 209 210 211 212 213 214 215 216
}

void MarkerBase::WriteBarrierForObject(HeapObjectHeader& header) {
  MarkingWorklists::WriteBarrierWorklist::View write_barrier_worklist(
      marking_worklists_.write_barrier_worklist(),
      MarkingWorklists::kMutatorThreadId);
  write_barrier_worklist.Push(&header);
}

217 218 219 220
}  // namespace internal
}  // namespace cppgc

#endif  // V8_HEAP_CPPGC_MARKER_H_