Commit 0f50994d authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

cppgc: Add testing::Heap that allows invoking stand-alone GCs

Bug: chromium:1056170
Change-Id: Ib2b2788c7d59f873583e26a0716bacbf16766c93
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2716291Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#73010}
parent 40ebe845
......@@ -18,6 +18,20 @@ class HeapHandle;
*/
namespace testing {
/**
* Testing helper used to acces heap internals.
*/
class V8_EXPORT Heap final {
public:
/**
* Atomically collects garbage on the C++ heap.
*
* \param heap_handle The corresponding heap.
* \param stack_state The stack state to assume for the garbage collection.
*/
void CollectGarbage(HeapHandle& heap_handle, EmbedderStackState stack_state);
};
/**
* Overrides the state of the stack with the provided value. Takes precedence
* over other parameters that set the stack state. Must no be nested.
......
......@@ -147,5 +147,75 @@ HeapStatistics HeapBase::CollectStatistics(
return HeapStatisticsCollector().CollectStatistics(this);
}
void HeapBase::StandAloneGarbageCollectionForTesting(
GarbageCollector::Config::StackState stack_state) {
GarbageCollector::Config config = {
GarbageCollector::Config::CollectionType::kMajor, stack_state,
GarbageCollector::Config::MarkingType::kAtomic,
GarbageCollector::Config::SweepingType::kAtomic};
if (in_no_gc_scope()) return;
if (!IsMarking()) {
StartStandAloneGarbageCollection(config);
}
DCHECK(IsMarking());
FinalizeStandAloneGarbageCollection(config);
}
void HeapBase::StartStandAloneGarbageCollection(
GarbageCollector::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)
Unmarker unmarker(&raw_heap());
#endif
const Marker::MarkingConfig marking_config{
config.collection_type, config.stack_state, config.marking_type,
config.is_forced_gc};
marker_ = MarkerFactory::CreateAndStartMarking<Marker>(*this, platform_.get(),
marking_config);
}
void HeapBase::FinalizeStandAloneGarbageCollection(
GarbageCollector::Config config) {
DCHECK(IsMarking());
DCHECK(!in_no_gc_scope());
CHECK(!in_disallow_gc_scope());
if (override_stack_state_) {
config.stack_state = *override_stack_state_;
}
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);
verifier.Run(config.stack_state);
#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();
}
} // namespace internal
} // namespace cppgc
......@@ -14,6 +14,7 @@
#include "include/cppgc/macros.h"
#include "src/base/macros.h"
#include "src/heap/cppgc/compactor.h"
#include "src/heap/cppgc/garbage-collector.h"
#include "src/heap/cppgc/marker.h"
#include "src/heap/cppgc/metric-recorder.h"
#include "src/heap/cppgc/object-allocator.h"
......@@ -39,6 +40,7 @@ class NoGarbageCollectionScope;
} // namespace subtle
namespace testing {
class Heap;
class OverrideEmbedderStackStateScope;
} // namespace testing
......@@ -161,7 +163,14 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
HeapStatistics CollectStatistics(HeapStatistics::DetailLevel);
size_t epoch() const { return epoch_; }
protected:
// Starts and finalizes stand-alone garbage collections.
void StartStandAloneGarbageCollection(GarbageCollector::Config);
void FinalizeStandAloneGarbageCollection(GarbageCollector::Config);
// Used by the incremental scheduler to finalize a GC if supported.
virtual void FinalizeIncrementalGarbageCollectionIfNeeded(
cppgc::Heap::StackState) = 0;
......@@ -206,10 +215,17 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
bool in_atomic_pause_ = false;
size_t epoch_ = 0;
private:
void StandAloneGarbageCollectionForTesting(
GarbageCollector::Config::StackState);
friend class MarkerBase::IncrementalMarkingTask;
friend class testing::TestWithHeap;
friend class cppgc::subtle::DisallowGarbageCollectionScope;
friend class cppgc::subtle::NoGarbageCollectionScope;
friend class cppgc::testing::Heap;
friend class cppgc::testing::OverrideEmbedderStackStateScope;
};
......
......@@ -115,11 +115,11 @@ void Heap::CollectGarbage(Config config) {
config_ = config;
if (!IsMarking()) StartGarbageCollection(config);
if (!IsMarking()) {
StartStandAloneGarbageCollection(config);
}
DCHECK(IsMarking());
FinalizeGarbageCollection(config.stack_state);
FinalizeStandAloneGarbageCollection(config);
}
void Heap::StartIncrementalGarbageCollection(Config config) {
......@@ -131,7 +131,7 @@ void Heap::StartIncrementalGarbageCollection(Config config) {
config_ = config;
StartGarbageCollection(config);
StartStandAloneGarbageCollection(config);
}
void Heap::FinalizeIncrementalGarbageCollectionIfRunning(Config config) {
......@@ -144,60 +144,7 @@ void Heap::FinalizeIncrementalGarbageCollectionIfRunning(Config config) {
DCHECK_NE(Config::MarkingType::kAtomic, config_.marking_type);
config_ = config;
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)
Unmarker unmarker(&raw_heap());
#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_;
}
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);
verifier.Run(config_.stack_state);
#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();
FinalizeStandAloneGarbageCollection(config_);
}
void Heap::DisableHeapGrowingForTesting() { growing_.DisableForTesting(); }
......@@ -206,8 +153,10 @@ void Heap::FinalizeIncrementalGarbageCollectionIfNeeded(
Config::StackState stack_state) {
StatsCollector::EnabledScope stats_scope(
stats_collector(), StatsCollector::kMarkIncrementalFinalize);
FinalizeGarbageCollection(stack_state);
FinalizeStandAloneGarbageCollection(config_);
}
size_t Heap::epoch() const { return HeapBase::epoch(); }
} // namespace internal
} // namespace cppgc
......@@ -36,14 +36,11 @@ class V8_EXPORT_PRIVATE Heap final : public HeapBase,
void StartIncrementalGarbageCollection(Config) final;
void FinalizeIncrementalGarbageCollectionIfRunning(Config);
size_t epoch() const final { return epoch_; }
size_t epoch() const final;
void DisableHeapGrowingForTesting();
private:
void StartGarbageCollection(Config);
void FinalizeGarbageCollection(Config::StackState);
void FinalizeIncrementalGarbageCollectionIfNeeded(Config::StackState) final;
Config config_;
......@@ -52,8 +49,6 @@ class V8_EXPORT_PRIVATE Heap final : public HeapBase,
const MarkingType marking_support_;
const SweepingType sweeping_support_;
size_t epoch_ = 0;
};
} // namespace internal
......
......@@ -37,7 +37,7 @@ class V8_EXPORT_PRIVATE MarkingVerifierBase
MarkingVerifierBase(const MarkingVerifierBase&) = delete;
MarkingVerifierBase& operator=(const MarkingVerifierBase&) = delete;
void Run(Heap::Config::StackState);
void Run(GarbageCollector::Config::StackState);
protected:
MarkingVerifierBase(HeapBase&, std::unique_ptr<cppgc::Visitor>);
......
......@@ -10,6 +10,12 @@
namespace cppgc {
namespace testing {
void Heap::CollectGarbage(HeapHandle& heap_handle,
EmbedderStackState stack_state) {
auto& heap = internal::HeapBase::From(heap_handle);
heap.StandAloneGarbageCollectionForTesting(stack_state);
}
OverrideEmbedderStackStateScope::OverrideEmbedderStackStateScope(
HeapHandle& heap_handle, EmbedderStackState state)
: heap_handle_(heap_handle) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment