Skip to content

Commit c580c67

Browse files
haitakaSpace Team
authored andcommitted
[K/N] Remember StableRefs, released during RC colleciton (KT-70159)
Merge-request: KT-MR-17260 Merged-by: Alexey Glushko <[email protected]>
1 parent 565a35c commit c580c67

File tree

16 files changed

+107
-51
lines changed

16 files changed

+107
-51
lines changed

kotlin-native/runtime/src/gc/cms/cpp/Barriers.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,14 @@ void gc::barriers::disableBarriers() noexcept {
126126
namespace {
127127

128128
// TODO decide whether it's really beneficial to NO_INLINE the slow path
129-
NO_INLINE void beforeHeapRefUpdateSlowPath(mm::DirectRefAccessor ref, ObjHeader* value) noexcept {
130-
auto prev = ref.load();
129+
NO_INLINE void beforeHeapRefUpdateSlowPath(mm::DirectRefAccessor ref, ObjHeader* value, bool loadAtomic) noexcept {
130+
ObjHeader* prev;
131+
if (loadAtomic) {
132+
prev = ref.loadAtomic(std::memory_order_relaxed);
133+
} else {
134+
prev = ref.load();
135+
}
136+
131137
if (prev != nullptr && prev->heap()) {
132138
// TODO Redundant if the destination object is black.
133139
// Yet at the moment there is now efficient way to distinguish black and gray objects.
@@ -143,11 +149,11 @@ NO_INLINE void beforeHeapRefUpdateSlowPath(mm::DirectRefAccessor ref, ObjHeader*
143149

144150
} // namespace
145151

146-
ALWAYS_INLINE void gc::barriers::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value) noexcept {
152+
ALWAYS_INLINE void gc::barriers::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value, bool loadAtomic) noexcept {
147153
auto phase = currentPhase();
148154
BarriersLogDebug(phase, "Write *%p <- %p (%p overwritten)", ref.location(), value, ref.load());
149155
if (__builtin_expect(phase == BarriersPhase::kMarkClosure, false)) {
150-
beforeHeapRefUpdateSlowPath(ref, value);
156+
beforeHeapRefUpdateSlowPath(ref, value, loadAtomic);
151157
}
152158
}
153159

@@ -175,7 +181,7 @@ NO_INLINE ObjHeader* weakRefReadInWeakSweepSlowPath(ObjHeader* weakReferee) noex
175181

176182
} // namespace
177183

178-
ALWAYS_INLINE ObjHeader* gc::barriers::weakRefReadBarrier(std::atomic<ObjHeader*>& weakReferee) noexcept {
184+
ALWAYS_INLINE ObjHeader* gc::barriers::weakRefReadBarrier(std_support::atomic_ref<ObjHeader*> weakReferee) noexcept {
179185
if (__builtin_expect(currentPhase() != BarriersPhase::kDisabled, false)) {
180186
// Mark dispatcher requires weak reads be protected by the following:
181187
auto weakReadProtector = markDispatcher().weakReadProtector();

kotlin-native/runtime/src/gc/cms/cpp/Barriers.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ void enableBarriers(int64_t epoch) noexcept;
3434
void switchToWeakProcessingBarriers() noexcept;
3535
void disableBarriers() noexcept;
3636

37-
void beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value) noexcept;
37+
void beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value, bool loadAtomic) noexcept;
3838

39-
ObjHeader* weakRefReadBarrier(std::atomic<ObjHeader*>& weakReferee) noexcept;
39+
ObjHeader* weakRefReadBarrier(std_support::atomic_ref<ObjHeader*> weakReferee) noexcept;
4040

4141
} // namespace kotlin::gc::barriers

kotlin-native/runtime/src/gc/cms/cpp/ConcurrentMarkAndSweepTest.cpp

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ConcurrentMarkAndSweep.hpp"
77

88
#include <mutex>
9+
#include <atomic>
910

1011
#include "gtest/gtest.h"
1112

@@ -110,5 +111,41 @@ TYPED_TEST_P(TracingGCTest, WeakResurrectionAtMarkTermination) {
110111
}
111112
}
112113

113-
REGISTER_TYPED_TEST_SUITE_WITH_LISTS(TracingGCTest, TRACING_GC_TEST_LIST, WeakResurrectionAtMarkTermination);
114+
TYPED_TEST_P(TracingGCTest, ReleaseStableRefDuringRSCollection) {
115+
std::vector<Mutator> mutators(kDefaultThreadCount);
116+
117+
std::atomic<size_t> readyThreads = 0;
118+
std::atomic<bool> gcDone = false;
119+
120+
std::vector<std::future<void>> mutatorFutures;
121+
for (int i = 0; i < kDefaultThreadCount; ++i) {
122+
mutatorFutures.push_back(mutators[i].Execute([&](mm::ThreadData& threadData, Mutator& mutator) {
123+
auto& obj = AllocateObject(threadData);
124+
auto stableRef = mm::StableRef::create(obj.header());
125+
126+
++readyThreads;
127+
while (!mm::IsThreadSuspensionRequested()) {}
128+
129+
mm::safePoint();
130+
131+
mutator.AddStackRoot(obj.header());
132+
std::move(stableRef).dispose();
133+
134+
while (!gcDone) { mm::safePoint(); }
135+
136+
EXPECT_THAT(mutator.Alive(), testing::Contains(obj.header()));
137+
}));
138+
}
139+
140+
while (readyThreads < kDefaultThreadCount) {}
141+
142+
mm::GlobalData::Instance().gcScheduler().scheduleAndWaitFinalized();
143+
gcDone = true;
144+
145+
for (auto& future : mutatorFutures) {
146+
future.wait();
147+
}
148+
}
149+
150+
REGISTER_TYPED_TEST_SUITE_WITH_LISTS(TracingGCTest, TRACING_GC_TEST_LIST, WeakResurrectionAtMarkTermination, ReleaseStableRefDuringRSCollection);
114151
INSTANTIATE_TYPED_TEST_SUITE_P(CMS, TracingGCTest, ConcurrentMarkAndSweepTest);

kotlin-native/runtime/src/gc/cms/cpp/GCImpl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ bool gc::GC::mainThreadFinalizerProcessorAvailable() noexcept {
8787
return impl_->gc().mainThreadFinalizerProcessor().available();
8888
}
8989

90-
ALWAYS_INLINE void gc::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value) noexcept {
91-
barriers::beforeHeapRefUpdate(ref, value);
90+
ALWAYS_INLINE void gc::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value, bool loadAtomic) noexcept {
91+
barriers::beforeHeapRefUpdate(ref, value, loadAtomic);
9292
}
9393

94-
ALWAYS_INLINE OBJ_GETTER(gc::weakRefReadBarrier, std::atomic<ObjHeader*>& weakReferee) noexcept {
94+
ALWAYS_INLINE OBJ_GETTER(gc::weakRefReadBarrier, std_support::atomic_ref<ObjHeader*> weakReferee) noexcept {
9595
RETURN_OBJ(gc::barriers::weakRefReadBarrier(weakReferee));
9696
}
9797

kotlin-native/runtime/src/gc/common/cpp/GC.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ class GC : private Pinned {
8787
std::unique_ptr<Impl> impl_;
8888
};
8989

90-
void beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value) noexcept;
91-
OBJ_GETTER(weakRefReadBarrier, std::atomic<ObjHeader*>& weakReferee) noexcept;
90+
void beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value, bool loadAtomic) noexcept;
91+
OBJ_GETTER(weakRefReadBarrier, std_support::atomic_ref<ObjHeader*> weakReferee) noexcept;
9292

9393
bool isMarked(ObjHeader* object) noexcept;
9494

kotlin-native/runtime/src/gc/common/cpp/MarkAndSweepUtils.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,8 @@ void collectRootSet(GCHandle handle, typename Traits::MarkQueue& markQueue, F&&
162162
template <typename Traits>
163163
void processWeaks(GCHandle gcHandle, mm::SpecialRefRegistry& registry) noexcept {
164164
auto handle = gcHandle.processWeaks();
165-
for (auto& object : registry.lockForIter()) {
166-
auto* obj = object.load(std::memory_order_relaxed);
165+
for (auto objRef : registry.lockForIter()) {
166+
auto* obj = objRef.load(std::memory_order_relaxed);
167167
if (!obj) {
168168
// We already processed it at some point.
169169
handle.addUndisposed();
@@ -176,7 +176,7 @@ void processWeaks(GCHandle gcHandle, mm::SpecialRefRegistry& registry) noexcept
176176
continue;
177177
}
178178
// Object is not alive. Clear it out.
179-
object.store(nullptr, std::memory_order_relaxed);
179+
objRef.store(nullptr, std::memory_order_relaxed);
180180
handle.addNulled();
181181
}
182182
}

kotlin-native/runtime/src/gc/noop/cpp/GCImpl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ bool gc::GC::mainThreadFinalizerProcessorAvailable() noexcept {
6262
return false;
6363
}
6464

65-
ALWAYS_INLINE void gc::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value) noexcept {}
65+
ALWAYS_INLINE void gc::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value, bool loadAtomic) noexcept {}
6666

67-
ALWAYS_INLINE OBJ_GETTER(gc::weakRefReadBarrier, std::atomic<ObjHeader*>& weakReferee) noexcept {
67+
ALWAYS_INLINE OBJ_GETTER(gc::weakRefReadBarrier, std_support::atomic_ref<ObjHeader*> weakReferee) noexcept {
6868
RETURN_OBJ(weakReferee.load(std::memory_order_relaxed));
6969
}
7070

kotlin-native/runtime/src/gc/pmcs/cpp/Barriers.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ ObjHeader* weakRefBarrierImpl(ObjHeader* weakReferee) noexcept {
3030
return weakReferee;
3131
}
3232

33-
NO_INLINE ObjHeader* weakRefReadSlowPath(std::atomic<ObjHeader*>& weakReferee) noexcept {
33+
NO_INLINE ObjHeader* weakRefReadSlowPath(std_support::atomic_ref<ObjHeader*> weakReferee) noexcept {
3434
// reread an action to avoid register pollution outside the function
3535
auto barrier = weakRefBarrier.load(std::memory_order_seq_cst);
3636

@@ -107,7 +107,7 @@ void gc::DisableWeakRefBarriers() noexcept {
107107
}
108108
}
109109

110-
OBJ_GETTER(gc::WeakRefRead, std::atomic<ObjHeader*>& weakReferee) noexcept {
110+
OBJ_GETTER(gc::WeakRefRead, std_support::atomic_ref<ObjHeader*> weakReferee) noexcept {
111111
if (!compiler::concurrentWeakSweep()) {
112112
RETURN_OBJ(weakReferee.load(std::memory_order_relaxed));
113113
}

kotlin-native/runtime/src/gc/pmcs/cpp/Barriers.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ class BarriersThreadData : private Pinned {
3232
void EnableWeakRefBarriers(int64_t epoch) noexcept;
3333
void DisableWeakRefBarriers() noexcept;
3434

35-
OBJ_GETTER(WeakRefRead, std::atomic<ObjHeader*>& weakReferee) noexcept;
35+
OBJ_GETTER(WeakRefRead, std_support::atomic_ref<ObjHeader*> weakReferee) noexcept;
3636

3737
} // namespace kotlin::gc

kotlin-native/runtime/src/gc/pmcs/cpp/GCImpl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,9 @@ bool gc::GC::mainThreadFinalizerProcessorAvailable() noexcept {
8787
return impl_->gc().mainThreadFinalizerProcessor().available();
8888
}
8989

90-
ALWAYS_INLINE void gc::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value) noexcept {}
90+
ALWAYS_INLINE void gc::beforeHeapRefUpdate(mm::DirectRefAccessor ref, ObjHeader* value, bool loadAtomic) noexcept {}
9191

92-
ALWAYS_INLINE OBJ_GETTER(gc::weakRefReadBarrier, std::atomic<ObjHeader*>& weakReferee) noexcept {
92+
ALWAYS_INLINE OBJ_GETTER(gc::weakRefReadBarrier, std_support::atomic_ref<ObjHeader*> weakReferee) noexcept {
9393
RETURN_RESULT_OF(gc::WeakRefRead, weakReferee);
9494
}
9595

0 commit comments

Comments
 (0)