cppgc: Add getters internal heap state
Adds getters for GC phases to be used by advanced embedders to ensure and check consistency conditions as needed. Bug: chromium:1056170 Change-Id: Ia0b219f838bf31f0edbfe40585b95bb5eafa734d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2658328 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Omer Katz <omerkatz@chromium.org> Commit-Queue: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#72430}
This commit is contained in:
parent
a3be3e83c1
commit
732e22e088
@ -143,10 +143,31 @@ class V8_EXPORT HeapState final {
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the garbage collector is currently marking, and false
|
||||
* otherwise.
|
||||
* otherwise.
|
||||
*/
|
||||
static bool IsMarking(HeapHandle& heap_handle);
|
||||
|
||||
/*
|
||||
* Returns whether the garbage collector is sweeping. This API is experimental
|
||||
* and is expected to be removed in future.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the garbage collector is currently sweeping, and false
|
||||
* otherwise.
|
||||
*/
|
||||
static bool IsSweeping(HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* Returns whether the garbage collector is in the atomic pause, i.e., the
|
||||
* mutator is stopped from running. This API is experimental and is expected
|
||||
* to be removed in future.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
* \returns true if the garbage collector is currently in the atomic pause,
|
||||
* and false otherwise.
|
||||
*/
|
||||
static bool IsInAtomicPause(HeapHandle& heap_handle);
|
||||
|
||||
private:
|
||||
HeapState() = delete;
|
||||
};
|
||||
@ -177,7 +198,7 @@ class V8_EXPORT V8_NODISCARD DisallowGarbageCollectionScope final {
|
||||
static void Enter(HeapHandle& heap_handle);
|
||||
|
||||
/**
|
||||
* LEaves a disallow garbage collection scope. Must be paired with `Enter()`.
|
||||
* Leaves a disallow garbage collection scope. Must be paired with `Enter()`.
|
||||
* Prefer a scope instance of `DisallowGarbageCollectionScope`.
|
||||
*
|
||||
* \param heap_handle The corresponding heap.
|
||||
|
@ -241,17 +241,16 @@ bool CppHeap::AdvanceTracing(double deadline_in_ms) {
|
||||
// accounting since this scope is also accounted under an outer v8 scope.
|
||||
// Make sure to only account this scope once.
|
||||
cppgc::internal::StatsCollector::EnabledScope stats_scope(
|
||||
AsBase(), is_in_final_pause_
|
||||
AsBase(), in_atomic_pause_
|
||||
? cppgc::internal::StatsCollector::kAtomicMark
|
||||
: cppgc::internal::StatsCollector::kIncrementalMark);
|
||||
v8::base::TimeDelta deadline =
|
||||
is_in_final_pause_
|
||||
? v8::base::TimeDelta::Max()
|
||||
: v8::base::TimeDelta::FromMillisecondsD(deadline_in_ms);
|
||||
in_atomic_pause_ ? v8::base::TimeDelta::Max()
|
||||
: v8::base::TimeDelta::FromMillisecondsD(deadline_in_ms);
|
||||
// TODO(chromium:1056170): Replace when unified heap transitions to
|
||||
// bytes-based deadline.
|
||||
marking_done_ = marker_->AdvanceMarkingWithMaxDuration(deadline);
|
||||
DCHECK_IMPLIES(is_in_final_pause_, marking_done_);
|
||||
DCHECK_IMPLIES(in_atomic_pause_, marking_done_);
|
||||
return marking_done_;
|
||||
}
|
||||
|
||||
@ -261,7 +260,7 @@ void CppHeap::EnterFinalPause(EmbedderStackState stack_state) {
|
||||
CHECK(!in_disallow_gc_scope());
|
||||
cppgc::internal::StatsCollector::EnabledScope stats_scope(
|
||||
AsBase(), cppgc::internal::StatsCollector::kAtomicMark);
|
||||
is_in_final_pause_ = true;
|
||||
in_atomic_pause_ = true;
|
||||
marker_->EnterAtomicPause(stack_state);
|
||||
if (compactor_.CancelIfShouldNotCompact(cppgc::Heap::MarkingType::kAtomic,
|
||||
stack_state)) {
|
||||
@ -270,14 +269,13 @@ void CppHeap::EnterFinalPause(EmbedderStackState stack_state) {
|
||||
}
|
||||
|
||||
void CppHeap::TraceEpilogue(TraceSummary* trace_summary) {
|
||||
CHECK(is_in_final_pause_);
|
||||
CHECK(in_atomic_pause_);
|
||||
CHECK(marking_done_);
|
||||
{
|
||||
cppgc::internal::StatsCollector::EnabledScope stats_scope(
|
||||
AsBase(), cppgc::internal::StatsCollector::kAtomicMark);
|
||||
cppgc::subtle::DisallowGarbageCollectionScope disallow_gc_scope(*this);
|
||||
marker_->LeaveAtomicPause();
|
||||
is_in_final_pause_ = false;
|
||||
}
|
||||
{
|
||||
cppgc::subtle::DisallowGarbageCollectionScope disallow_gc_scope(*this);
|
||||
@ -300,6 +298,7 @@ void CppHeap::TraceEpilogue(TraceSummary* trace_summary) {
|
||||
compactable_space_handling};
|
||||
sweeper().Start(sweeping_config);
|
||||
}
|
||||
in_atomic_pause_ = false;
|
||||
sweeper().NotifyDoneIfNeeded();
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,6 @@ class V8_EXPORT_PRIVATE CppHeap final
|
||||
|
||||
Isolate& isolate_;
|
||||
bool marking_done_ = false;
|
||||
bool is_in_final_pause_ = false;
|
||||
|
||||
// Buffered allocated bytes. Reporting allocated bytes to V8 can trigger a GC
|
||||
// atomic pause. Allocated bytes are buffer in case this is temporarily
|
||||
|
@ -42,6 +42,13 @@ class GarbageCollector {
|
||||
MarkingType::kIncremental, SweepingType::kAtomic};
|
||||
}
|
||||
|
||||
static constexpr Config
|
||||
PreciseIncrementalMarkingConcurrentSweepingConfig() {
|
||||
return {CollectionType::kMajor, StackState::kNoHeapPointers,
|
||||
MarkingType::kIncremental,
|
||||
SweepingType::kIncrementalAndConcurrent};
|
||||
}
|
||||
|
||||
static constexpr Config MinorPreciseAtomicConfig() {
|
||||
return {CollectionType::kMinor, StackState::kNoHeapPointers,
|
||||
MarkingType::kAtomic, SweepingType::kAtomic};
|
||||
|
@ -108,6 +108,7 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
|
||||
const ObjectAllocator& object_allocator() const { return object_allocator_; }
|
||||
|
||||
Sweeper& sweeper() { return sweeper_; }
|
||||
const Sweeper& sweeper() const { return sweeper_; }
|
||||
|
||||
PersistentRegion& GetStrongPersistentRegion() {
|
||||
return strong_persistent_region_;
|
||||
@ -150,6 +151,7 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
|
||||
void Terminate();
|
||||
|
||||
bool in_disallow_gc_scope() const { return disallow_gc_scope_ > 0; }
|
||||
bool in_atomic_pause() const { return in_atomic_pause_; }
|
||||
|
||||
protected:
|
||||
virtual void FinalizeIncrementalGarbageCollectionIfNeeded(
|
||||
@ -189,6 +191,8 @@ class V8_EXPORT_PRIVATE HeapBase : public cppgc::HeapHandle {
|
||||
|
||||
const StackSupport stack_support_;
|
||||
|
||||
bool in_atomic_pause_ = false;
|
||||
|
||||
friend class MarkerBase::IncrementalMarkingTask;
|
||||
friend class testing::TestWithHeap;
|
||||
friend class cppgc::subtle::DisallowGarbageCollectionScope;
|
||||
|
@ -68,5 +68,17 @@ bool HeapState::IsMarking(HeapHandle& heap_handle) {
|
||||
return heap_base.marker();
|
||||
}
|
||||
|
||||
// static
|
||||
bool HeapState::IsSweeping(HeapHandle& heap_handle) {
|
||||
const auto& heap_base = internal::HeapBase::From(heap_handle);
|
||||
return heap_base.sweeper().IsSweepingInProgress();
|
||||
}
|
||||
|
||||
// static
|
||||
bool HeapState::IsInAtomicPause(HeapHandle& heap_handle) {
|
||||
const auto& heap_base = internal::HeapBase::From(heap_handle);
|
||||
return heap_base.in_atomic_pause();
|
||||
}
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace cppgc
|
||||
|
@ -173,6 +173,7 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
|
||||
DCHECK(!in_no_gc_scope());
|
||||
CHECK(!in_disallow_gc_scope());
|
||||
config_.stack_state = 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.
|
||||
@ -196,6 +197,7 @@ void Heap::FinalizeGarbageCollection(Config::StackState stack_state) {
|
||||
config_.sweeping_type,
|
||||
Sweeper::SweepingConfig::CompactableSpaceHandling::kSweep};
|
||||
sweeper_.Start(sweeping_config);
|
||||
in_atomic_pause_ = false;
|
||||
sweeper_.NotifyDoneIfNeeded();
|
||||
}
|
||||
|
||||
|
@ -654,6 +654,8 @@ class Sweeper::SweeperImpl final {
|
||||
return is_sweeping_on_mutator_thread_;
|
||||
}
|
||||
|
||||
bool IsSweepingInProgress() const { return is_in_progress_; }
|
||||
|
||||
private:
|
||||
class MutatorThreadSweepingScope final {
|
||||
public:
|
||||
@ -791,5 +793,9 @@ bool Sweeper::IsSweepingOnMutatorThread() const {
|
||||
return impl_->IsSweepingOnMutatorThread();
|
||||
}
|
||||
|
||||
bool Sweeper::IsSweepingInProgress() const {
|
||||
return impl_->IsSweepingInProgress();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace cppgc
|
||||
|
@ -48,6 +48,7 @@ class V8_EXPORT_PRIVATE Sweeper final {
|
||||
bool SweepForAllocationIfRunning(NormalPageSpace* space, size_t size);
|
||||
|
||||
bool IsSweepingOnMutatorThread() const;
|
||||
bool IsSweepingInProgress() const;
|
||||
|
||||
private:
|
||||
void WaitForConcurrentSweepingForTesting();
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "include/cppgc/allocation.h"
|
||||
#include "include/cppgc/heap-consistency.h"
|
||||
#include "include/cppgc/persistent.h"
|
||||
#include "include/cppgc/prefinalizer.h"
|
||||
#include "src/heap/cppgc/globals.h"
|
||||
#include "test/unittests/heap/cppgc/tests.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
@ -186,15 +187,65 @@ TEST_F(GCHeapTest, IsGarbageCollectionAllowed) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(GCHeapTest, IsIncrementalMarking) {
|
||||
GarbageCollector::Config config =
|
||||
GarbageCollector::Config::PreciseIncrementalConfig();
|
||||
TEST_F(GCHeapTest, IsMarking) {
|
||||
GarbageCollector::Config config = GarbageCollector::Config::
|
||||
PreciseIncrementalMarkingConcurrentSweepingConfig();
|
||||
auto* heap = Heap::From(GetHeap());
|
||||
EXPECT_FALSE(subtle::HeapState::IsMarking(*heap));
|
||||
heap->StartIncrementalGarbageCollection(config);
|
||||
EXPECT_TRUE(subtle::HeapState::IsMarking(*heap));
|
||||
heap->FinalizeIncrementalGarbageCollectionIfRunning(config);
|
||||
EXPECT_FALSE(subtle::HeapState::IsMarking(*heap));
|
||||
heap->AsBase().sweeper().FinishIfRunning();
|
||||
EXPECT_FALSE(subtle::HeapState::IsMarking(*heap));
|
||||
}
|
||||
|
||||
TEST_F(GCHeapTest, IsSweeping) {
|
||||
GarbageCollector::Config config = GarbageCollector::Config::
|
||||
PreciseIncrementalMarkingConcurrentSweepingConfig();
|
||||
auto* heap = Heap::From(GetHeap());
|
||||
EXPECT_FALSE(subtle::HeapState::IsSweeping(*heap));
|
||||
heap->StartIncrementalGarbageCollection(config);
|
||||
EXPECT_FALSE(subtle::HeapState::IsSweeping(*heap));
|
||||
heap->FinalizeIncrementalGarbageCollectionIfRunning(config);
|
||||
EXPECT_TRUE(subtle::HeapState::IsSweeping(*heap));
|
||||
heap->AsBase().sweeper().FinishIfRunning();
|
||||
EXPECT_FALSE(subtle::HeapState::IsSweeping(*heap));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ExpectAtomicPause final : public GarbageCollected<ExpectAtomicPause> {
|
||||
CPPGC_USING_PRE_FINALIZER(ExpectAtomicPause, PreFinalizer);
|
||||
|
||||
public:
|
||||
explicit ExpectAtomicPause(HeapHandle& handle) : handle_(handle) {}
|
||||
~ExpectAtomicPause() {
|
||||
EXPECT_TRUE(subtle::HeapState::IsInAtomicPause(handle_));
|
||||
}
|
||||
void PreFinalizer() {
|
||||
EXPECT_TRUE(subtle::HeapState::IsInAtomicPause(handle_));
|
||||
}
|
||||
void Trace(Visitor*) const {}
|
||||
|
||||
private:
|
||||
HeapHandle& handle_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(GCHeapTest, IsInAtomicPause) {
|
||||
GarbageCollector::Config config =
|
||||
GarbageCollector::Config::PreciseIncrementalConfig();
|
||||
auto* heap = Heap::From(GetHeap());
|
||||
MakeGarbageCollected<ExpectAtomicPause>(heap->object_allocator(), *heap);
|
||||
EXPECT_FALSE(subtle::HeapState::IsInAtomicPause(*heap));
|
||||
heap->StartIncrementalGarbageCollection(config);
|
||||
EXPECT_FALSE(subtle::HeapState::IsInAtomicPause(*heap));
|
||||
heap->FinalizeIncrementalGarbageCollectionIfRunning(config);
|
||||
EXPECT_FALSE(subtle::HeapState::IsInAtomicPause(*heap));
|
||||
heap->AsBase().sweeper().FinishIfRunning();
|
||||
EXPECT_FALSE(subtle::HeapState::IsInAtomicPause(*heap));
|
||||
}
|
||||
|
||||
TEST_F(GCHeapTest, TerminateEmptyHeap) { Heap::From(GetHeap())->Terminate(); }
|
||||
|
Loading…
Reference in New Issue
Block a user