heap.cc 7.49 KB
Newer Older
1 2 3 4 5 6
// 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.

#include "src/heap/cppgc/heap.h"

7
#include "include/cppgc/heap-consistency.h"
8
#include "src/heap/base/stack.h"
9
#include "src/heap/cppgc/garbage-collector.h"
10
#include "src/heap/cppgc/gc-invoker.h"
11
#include "src/heap/cppgc/heap-object-header.h"
12
#include "src/heap/cppgc/heap-visitor.h"
13
#include "src/heap/cppgc/marker.h"
14
#include "src/heap/cppgc/marking-verifier.h"
15
#include "src/heap/cppgc/prefinalizer-handler.h"
16
#include "src/heap/cppgc/stats-collector.h"
17 18 19

namespace cppgc {

20 21 22 23 24 25 26 27
namespace {

void VerifyCustomSpaces(
    const std::vector<std::unique_ptr<CustomSpaceBase>>& custom_spaces) {
  // Ensures that user-provided custom spaces have indices that form a sequence
  // starting at 0.
#ifdef DEBUG
  for (size_t i = 0; i < custom_spaces.size(); ++i) {
28
    DCHECK_EQ(i, custom_spaces[i]->GetCustomSpaceIndex().value);
29 30 31 32 33 34
  }
#endif  // DEBUG
}

}  // namespace

35 36 37
std::unique_ptr<Heap> Heap::Create(std::shared_ptr<cppgc::Platform> platform,
                                   cppgc::Heap::HeapOptions options) {
  DCHECK(platform.get());
38
  VerifyCustomSpaces(options.custom_spaces);
39
  return std::make_unique<internal::Heap>(std::move(platform),
40
                                          std::move(options));
41 42
}

43 44
void Heap::ForceGarbageCollectionSlow(const char* source, const char* reason,
                                      Heap::StackState stack_state) {
45
  internal::Heap::From(this)->CollectGarbage(
46
      {internal::GarbageCollector::Config::CollectionType::kMajor, stack_state,
47
       MarkingType::kAtomic, SweepingType::kAtomic,
Omer Katz's avatar
Omer Katz committed
48
       internal::GarbageCollector::Config::IsForcedGC::kForced});
49 50
}

51
AllocationHandle& Heap::GetAllocationHandle() {
52
  return internal::Heap::From(this)->object_allocator();
53 54
}

55 56
HeapHandle& Heap::GetHeapHandle() { return *internal::Heap::From(this); }

57 58
namespace internal {

59 60 61 62 63 64
namespace {

class Unmarker final : private HeapVisitor<Unmarker> {
  friend class HeapVisitor<Unmarker>;

 public:
65
  explicit Unmarker(RawHeap& heap) { Traverse(heap); }
66 67

 private:
68 69
  bool VisitHeapObjectHeader(HeapObjectHeader& header) {
    if (header.IsMarked()) header.Unmark();
70 71 72 73
    return true;
  }
};

74 75
void CheckConfig(Heap::Config config, Heap::MarkingType marking_support,
                 Heap::SweepingType sweeping_support) {
76 77 78 79
  CHECK_WITH_MSG(
      (config.collection_type != Heap::Config::CollectionType::kMinor) ||
          (config.stack_state == Heap::Config::StackState::kNoHeapPointers),
      "Minor GCs with stack is currently not supported");
80 81 82 83
  CHECK_LE(static_cast<int>(config.marking_type),
           static_cast<int>(marking_support));
  CHECK_LE(static_cast<int>(config.sweeping_type),
           static_cast<int>(sweeping_support));
84 85 86 87
}

}  // namespace

88 89
Heap::Heap(std::shared_ptr<cppgc::Platform> platform,
           cppgc::Heap::HeapOptions options)
90
    : HeapBase(platform, options.custom_spaces, options.stack_support),
91 92
      gc_invoker_(this, platform_.get(), options.stack_support),
      growing_(&gc_invoker_, stats_collector_.get(),
93 94 95 96 97 98 99 100 101
               options.resource_constraints, options.marking_support,
               options.sweeping_support),
      marking_support_(options.marking_support),
      sweeping_support_(options.sweeping_support) {
  CHECK_IMPLIES(options.marking_support != MarkingType::kAtomic,
                platform_->GetForegroundTaskRunner());
  CHECK_IMPLIES(options.sweeping_support != SweepingType::kAtomic,
                platform_->GetForegroundTaskRunner());
}
102

103
Heap::~Heap() {
104
  subtle::NoGarbageCollectionScope no_gc(*this);
105
  // Finish already running GC if any, but don't finalize live objects.
106
  sweeper_.FinishIfRunning();
107 108
}

109
void Heap::CollectGarbage(Config config) {
110
  DCHECK_EQ(Config::MarkingType::kAtomic, config.marking_type);
111
  CheckConfig(config, marking_support_, sweeping_support_);
112

113 114
  if (in_no_gc_scope()) return;

115 116
  config_ = config;

117
  if (!IsMarking()) {
118
    StartGarbageCollection(config);
119
  }
120
  DCHECK(IsMarking());
121
  FinalizeGarbageCollection(config.stack_state);
122 123 124 125
}

void Heap::StartIncrementalGarbageCollection(Config config) {
  DCHECK_NE(Config::MarkingType::kAtomic, config.marking_type);
126 127
  DCHECK_NE(marking_support_, MarkingType::kAtomic);
  CheckConfig(config, marking_support_, sweeping_support_);
128

129
  if (IsMarking() || in_no_gc_scope()) return;
130 131

  config_ = config;
132

133
  StartGarbageCollection(config);
134 135 136
}

void Heap::FinalizeIncrementalGarbageCollectionIfRunning(Config config) {
137 138 139
  DCHECK_NE(marking_support_, MarkingType::kAtomic);
  CheckConfig(config, marking_support_, sweeping_support_);

140
  if (!IsMarking()) return;
141 142 143 144 145

  DCHECK(!in_no_gc_scope());

  DCHECK_NE(Config::MarkingType::kAtomic, config_.marking_type);
  config_ = config;
146 147 148 149 150 151 152 153 154 155 156 157 158 159
  FinalizeGarbageCollection(config.stack_state);
}

void Heap::StartGarbageCollection(Config config) {
  DCHECK(!IsMarking());
  DCHECK(!in_no_gc_scope());

  // Finish sweeping in case it is still running.
  sweeper_.FinishIfRunning();

  epoch_++;

#if defined(CPPGC_YOUNG_GENERATION)
  if (config.collection_type == Config::CollectionType::kMajor)
160
    Unmarker unmarker(raw_heap());
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
#endif

  const Marker::MarkingConfig marking_config{
      config.collection_type, config.stack_state, config.marking_type,
      config.is_forced_gc};
  marker_ = MarkerFactory::CreateAndStartMarking<Marker>(
      AsBase(), platform_.get(), marking_config);
}

void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
  DCHECK(IsMarking());
  DCHECK(!in_no_gc_scope());
  CHECK(!in_disallow_gc_scope());
  config_.stack_state = stack_state;
  if (override_stack_state_) {
    config_.stack_state = *override_stack_state_;
  }
178
  SetStackEndOfCurrentGC(v8::base::Stack::GetCurrentStackPosition());
179 180 181 182 183 184 185 186 187 188 189 190
  in_atomic_pause_ = true;
  {
    // This guards atomic pause marking, meaning that no internal method or
    // external callbacks are allowed to allocate new objects.
    cppgc::subtle::DisallowGarbageCollectionScope no_gc_scope(*this);
    marker_->FinishMarking(config_.stack_state);
  }
  marker_.reset();
  ExecutePreFinalizers();
  // TODO(chromium:1056170): replace build flag with dedicated flag.
#if DEBUG
  MarkingVerifier verifier(*this);
191 192
  verifier.Run(config_.stack_state, stack_end_of_current_gc(),
               stats_collector()->marked_bytes());
193 194 195 196 197 198 199 200 201
#endif

  subtle::NoGarbageCollectionScope no_gc(*this);
  const Sweeper::SweepingConfig sweeping_config{
      config_.sweeping_type,
      Sweeper::SweepingConfig::CompactableSpaceHandling::kSweep};
  sweeper_.Start(sweeping_config);
  in_atomic_pause_ = false;
  sweeper_.NotifyDoneIfNeeded();
202 203
}

204 205
void Heap::DisableHeapGrowingForTesting() { growing_.DisableForTesting(); }

206 207 208
void Heap::FinalizeIncrementalGarbageCollectionIfNeeded(
    Config::StackState stack_state) {
  StatsCollector::EnabledScope stats_scope(
209
      stats_collector(), StatsCollector::kMarkIncrementalFinalize);
210
  FinalizeGarbageCollection(stack_state);
211 212
}

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
void Heap::StartIncrementalGarbageCollectionForTesting() {
  DCHECK(!IsMarking());
  DCHECK(!in_no_gc_scope());
  StartGarbageCollection({Config::CollectionType::kMajor,
                          Config::StackState::kNoHeapPointers,
                          Config::MarkingType::kIncrementalAndConcurrent,
                          Config::SweepingType::kIncrementalAndConcurrent});
}

void Heap::FinalizeIncrementalGarbageCollectionForTesting(
    EmbedderStackState stack_state) {
  DCHECK(!in_no_gc_scope());
  DCHECK(IsMarking());
  FinalizeGarbageCollection(stack_state);
  sweeper_.FinishIfRunning();
}

230 231
}  // namespace internal
}  // namespace cppgc