[K/N] custom-alloc: AtomicStack avoid loop on move ^KT-55364
This change avoids looping through the source stack, looking for the last element, in the case where the target stack is empty. This could matter in two places: * when merging ready_ and used_ into unswept_ in PrepareForGC. The first of these will be faster with this change. * when merging finalizer queues (in CR-592, not merged yet), where we expect the target queue to be empty. Since we can expect used_ to be larger than ready_, since we are about to do a GC, the order of these two has also been reversed. Co-authored-by: Troels Lund <troels@google.com> Merge-request: KOTLIN-MR-599 Merged-by: Alexander Shabalin <alexander.shabalin@jetbrains.com>
This commit is contained in:
committed by
Space
parent
e04c6220ff
commit
ec891474b0
@@ -40,17 +40,21 @@ public:
|
|||||||
while (!other.stack_.compare_exchange_weak(otherHead, nullptr, std::memory_order_acq_rel)) {}
|
while (!other.stack_.compare_exchange_weak(otherHead, nullptr, std::memory_order_acq_rel)) {}
|
||||||
// If the `other` stack was empty, do nothing.
|
// If the `other` stack was empty, do nothing.
|
||||||
if (!otherHead) return;
|
if (!otherHead) return;
|
||||||
// Now find the tail of `other`. If no deletions are performed, this is safe.
|
// If `this` stack is empty, just copy the `other` stack over
|
||||||
|
T* thisHead = nullptr;
|
||||||
|
if (stack_.compare_exchange_strong(thisHead, otherHead, std::memory_order_acq_rel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// `this` stack is not empty. Find the tail of `other`. If no deletions are performed, this is safe.
|
||||||
T* otherTail = otherHead;
|
T* otherTail = otherHead;
|
||||||
while (otherTail->next_) otherTail = otherTail->next_;
|
while (otherTail->next_) otherTail = otherTail->next_;
|
||||||
// Now make `otherTail->next_` point to the current head of `this` and
|
|
||||||
// simultaneously make `otherHead` the new current head.
|
|
||||||
T* thisHead = nullptr;
|
|
||||||
// can't be because of the loop above
|
// can't be because of the loop above
|
||||||
RuntimeAssert(otherTail->next_ == nullptr, "otherTail->next_ must be a tail");
|
RuntimeAssert(otherTail->next_ == nullptr, "otherTail->next_ must be a tail");
|
||||||
while (!stack_.compare_exchange_weak(thisHead, otherHead, std::memory_order_acq_rel)) {
|
// Now make `otherTail->next_` point to the current head of `this` and
|
||||||
|
// simultaneously make `otherHead` the new current head.
|
||||||
|
do {
|
||||||
otherTail->next_ = thisHead;
|
otherTail->next_ = thisHead;
|
||||||
}
|
} while (!stack_.compare_exchange_weak(thisHead, otherHead, std::memory_order_acq_rel));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isEmpty() noexcept { return stack_.load(std::memory_order_relaxed) == nullptr; }
|
bool isEmpty() noexcept { return stack_.load(std::memory_order_relaxed) == nullptr; }
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ template <class T>
|
|||||||
class PageStore {
|
class PageStore {
|
||||||
public:
|
public:
|
||||||
void PrepareForGC() noexcept {
|
void PrepareForGC() noexcept {
|
||||||
unswept_.TransferAllFrom(ready_);
|
|
||||||
unswept_.TransferAllFrom(used_);
|
unswept_.TransferAllFrom(used_);
|
||||||
|
unswept_.TransferAllFrom(ready_);
|
||||||
T* page;
|
T* page;
|
||||||
while ((page = empty_.Pop())) page->Destroy();
|
while ((page = empty_.Pop())) page->Destroy();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user