diff --git a/kotlin-native/runtime/src/gc/cms/cpp/BarriersTest.cpp b/kotlin-native/runtime/src/gc/cms/cpp/BarriersTest.cpp index fda600246ee..09a0f8cb584 100644 --- a/kotlin-native/runtime/src/gc/cms/cpp/BarriersTest.cpp +++ b/kotlin-native/runtime/src/gc/cms/cpp/BarriersTest.cpp @@ -49,9 +49,14 @@ public: mm::GlobalData::Instance().allocator().clearForTests(); } - void initMutatorMarkQueue(mm::ThreadData& thread) { + auto withMutatorQueue(mm::ThreadData& thread) { auto& markData = thread.gc().impl().gc().mark(); - markData.markQueue().construct(parProc_); + return ScopeGuard{[&]{ + markData.markQueue().construct(parProc_); + }, [&]{ + markData.markQueue()->clear(); + markData.markQueue().destroy(); + }}; } private: @@ -62,7 +67,7 @@ private: TEST_F(BarriersTest, Deletion) { RunInNewThread([this](mm::ThreadData& threadData) { - initMutatorMarkQueue(threadData); + auto queueScope = withMutatorQueue(threadData); auto& prevObj = AllocateObject(threadData); auto& newObj = AllocateObject(threadData); @@ -93,7 +98,7 @@ TEST_F(BarriersTest, AllocationDuringMarkBarreirs) { gc::barriers::enableBarriers(gcHandle.getEpoch()); RunInNewThread([this](mm::ThreadData& threadData) { - initMutatorMarkQueue(threadData); + auto queueScope = withMutatorQueue(threadData); auto& obj = AllocateObject(threadData); EXPECT_THAT(gc::isMarked(obj.header()), true); }); @@ -125,7 +130,7 @@ TEST_F(BarriersTest, ConcurrentDeletion) { threads.emplace_back([&]() noexcept { ScopedMemoryInit memory; mm::ThreadData& threadData = *memory.memoryState()->GetThreadData(); - initMutatorMarkQueue(threadData); + auto queueScope = withMutatorQueue(threadData); while (!canStart.load()) std::this_thread::yield(); diff --git a/kotlin-native/runtime/src/gc/cms/cpp/ConcurrentMark.hpp b/kotlin-native/runtime/src/gc/cms/cpp/ConcurrentMark.hpp index 07872c4e91b..53259b20953 100644 --- a/kotlin-native/runtime/src/gc/cms/cpp/ConcurrentMark.hpp +++ b/kotlin-native/runtime/src/gc/cms/cpp/ConcurrentMark.hpp @@ -103,8 +103,8 @@ public: private: void ensureFlushActionExecuted() noexcept; - ManuallyScoped markQueue_{}; - ManuallyScoped flushAction_{}; + ManuallyScoped markQueue_{}; + ManuallyScoped flushAction_{}; }; void beginMarkingEpoch(GCHandle gcHandle); @@ -139,7 +139,7 @@ private: GCHandle gcHandle_ = GCHandle::invalid(); std::optional lockedMutatorsList_; - ManuallyScoped parallelProcessor_{}; + ManuallyScoped parallelProcessor_{}; RWSpinLock markTerminationMutex_; }; diff --git a/kotlin-native/runtime/src/gc/pmcs/cpp/ParallelMark.hpp b/kotlin-native/runtime/src/gc/pmcs/cpp/ParallelMark.hpp index 7b6173e87f4..ade7cc004a3 100644 --- a/kotlin-native/runtime/src/gc/pmcs/cpp/ParallelMark.hpp +++ b/kotlin-native/runtime/src/gc/pmcs/cpp/ParallelMark.hpp @@ -174,7 +174,7 @@ private: GCHandle gcHandle_ = GCHandle::invalid(); MarkPacer pacer_; std::optional lockedMutatorsList_; - ManuallyScoped parallelProcessor_{}; + ManuallyScoped parallelProcessor_{}; std::mutex workerCreationMutex_; std::atomic activeWorkersCount_ = 0; diff --git a/kotlin-native/runtime/src/main/cpp/ManuallyScoped.hpp b/kotlin-native/runtime/src/main/cpp/ManuallyScoped.hpp index 28673d188b5..838a4317526 100644 --- a/kotlin-native/runtime/src/main/cpp/ManuallyScoped.hpp +++ b/kotlin-native/runtime/src/main/cpp/ManuallyScoped.hpp @@ -13,7 +13,7 @@ namespace kotlin { // Like T but must be manually constructed and destroyed. -template +template class ManuallyScoped : private Pinned { public: // Construct T @@ -37,4 +37,51 @@ private: alignas(T) char implStorage_[sizeof(T)]; }; +template +class ManuallyScoped : private Pinned { +public: + ManuallyScoped() : constructed_(false) {} + ~ManuallyScoped() { assertDestroyed(); } + + // Construct T + template + void construct(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) { + assertDestroyed(); + impl_.construct(std::forward(args)...); + constructed_ = true; + } + + // Destroy T + void destroy() noexcept { + assertConstructed(); + impl_.destroy(); + constructed_ = false; + } + + T& operator*() noexcept { return *impl(); } + T* operator->() noexcept { return impl(); } + const T& operator*() const noexcept { return *impl(); } + const T* operator->() const noexcept { return impl(); } + +private: + T* impl() noexcept { + assertConstructed(); + return &*impl_; + } + const T* impl() const noexcept { + assertConstructed(); + return &*impl_; + } + + ALWAYS_INLINE void assertConstructed() const noexcept { + RuntimeAssert(constructed_, "ManuallyScoped value must have been constructed by this point"); + } + ALWAYS_INLINE void assertDestroyed() const noexcept { + RuntimeAssert(!constructed_, "ManuallyScoped value must have been destroyed by this point"); + } + + bool constructed_; + ManuallyScoped impl_; +}; + } // namespace kotlin