diff --git a/include/cppgc/heap-state.h b/include/cppgc/heap-state.h index 3fd6b54a8a..28212589f8 100644 --- a/include/cppgc/heap-state.h +++ b/include/cppgc/heap-state.h @@ -38,6 +38,18 @@ class V8_EXPORT HeapState final { */ static bool IsSweeping(const HeapHandle& heap_handle); + /* + * Returns whether the garbage collector is currently sweeping on the thread + * owning this heap. This API allows the caller to determine whether it has + * been called from a destructor of a managed object. This API is experimental + * and may be removed in future. + * + * \param heap_handle The corresponding heap. + * \returns true if the garbage collector is currently sweeping on this + * thread, and false otherwise. + */ + static bool IsSweepingOnOwningThread(const 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 diff --git a/src/heap/cppgc/heap-state.cc b/src/heap/cppgc/heap-state.cc index 364f03c643..756c19aa8f 100644 --- a/src/heap/cppgc/heap-state.cc +++ b/src/heap/cppgc/heap-state.cc @@ -21,6 +21,13 @@ bool HeapState::IsSweeping(const HeapHandle& heap_handle) { return internal::HeapBase::From(heap_handle).sweeper().IsSweepingInProgress(); } +// static +bool HeapState::IsSweepingOnOwningThread(const HeapHandle& heap_handle) { + return internal::HeapBase::From(heap_handle) + .sweeper() + .IsSweepingOnMutatorThread(); +} + // static bool HeapState::IsInAtomicPause(const HeapHandle& heap_handle) { return internal::HeapBase::From(heap_handle).in_atomic_pause(); diff --git a/test/unittests/heap/cppgc/heap-unittest.cc b/test/unittests/heap/cppgc/heap-unittest.cc index 315d1ff962..5fa0afd68f 100644 --- a/test/unittests/heap/cppgc/heap-unittest.cc +++ b/test/unittests/heap/cppgc/heap-unittest.cc @@ -11,6 +11,7 @@ #include "include/cppgc/allocation.h" #include "include/cppgc/cross-thread-persistent.h" #include "include/cppgc/heap-consistency.h" +#include "include/cppgc/heap-state.h" #include "include/cppgc/persistent.h" #include "include/cppgc/prefinalizer.h" #include "src/heap/cppgc/globals.h" @@ -261,6 +262,40 @@ TEST_F(GCHeapTest, IsSweeping) { namespace { +class GCedExpectSweepingOnOwningThread final + : public GarbageCollected { + public: + explicit GCedExpectSweepingOnOwningThread(const HeapHandle& heap_handle) + : heap_handle_(heap_handle) {} + ~GCedExpectSweepingOnOwningThread() { + EXPECT_TRUE(subtle::HeapState::IsSweepingOnOwningThread(heap_handle_)); + } + + void Trace(Visitor*) const {} + + private: + const HeapHandle& heap_handle_; +}; + +} // namespace + +TEST_F(GCHeapTest, IsSweepingOnOwningThread) { + GarbageCollector::Config config = GarbageCollector::Config:: + PreciseIncrementalMarkingConcurrentSweepingConfig(); + auto* heap = Heap::From(GetHeap()); + MakeGarbageCollected( + heap->GetAllocationHandle(), *heap); + EXPECT_FALSE(subtle::HeapState::IsSweepingOnOwningThread(*heap)); + heap->StartIncrementalGarbageCollection(config); + EXPECT_FALSE(subtle::HeapState::IsSweepingOnOwningThread(*heap)); + heap->FinalizeIncrementalGarbageCollectionIfRunning(config); + EXPECT_FALSE(subtle::HeapState::IsSweepingOnOwningThread(*heap)); + heap->AsBase().sweeper().FinishIfRunning(); + EXPECT_FALSE(subtle::HeapState::IsSweepingOnOwningThread(*heap)); +} + +namespace { + class ExpectAtomicPause final : public GarbageCollected { CPPGC_USING_PRE_FINALIZER(ExpectAtomicPause, PreFinalizer);