Skip to content

Commit 14d3c5d

Browse files
committed
[Runtime] Move ConcurrentReadableArray's allocate/deallocate functions into Storage. Mark ConcurrentReadableArray as un-copyable, un-assignable, and un-movable. Use SWIFT_MEMORY_ORDER_CONSUME instead of std::memory_order_consume. Make read() pass a const pointer.
rdar://problem/37173156
1 parent e2b6464 commit 14d3c5d

File tree

4 files changed

+63
-36
lines changed

4 files changed

+63
-36
lines changed

include/swift/Runtime/Atomic.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===--- Atomic.h - Utilities for atomic operations. ------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utilities for atomic operations, to use with std::atomic.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_RUNTIME_ATOMIC_H
18+
#define SWIFT_RUNTIME_ATOMIC_H
19+
20+
// FIXME: Workaround for rdar://problem/18889711. 'Consume' does not require
21+
// a barrier on ARM64, but LLVM doesn't know that. Although 'relaxed'
22+
// is formally UB by C++11 language rules, we should be OK because neither
23+
// the processor model nor the optimizer can realistically reorder our uses
24+
// of 'consume'.
25+
#if __arm64__ || __arm__
26+
# define SWIFT_MEMORY_ORDER_CONSUME (std::memory_order_relaxed)
27+
#else
28+
# define SWIFT_MEMORY_ORDER_CONSUME (std::memory_order_consume)
29+
#endif
30+
31+
#endif

include/swift/Runtime/Concurrent.h

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <functional>
1818
#include <stdint.h>
1919
#include "llvm/Support/Allocator.h"
20+
#include "Atomic.h"
2021
#include "Debug.h"
2122
#include "Mutex.h"
2223

@@ -422,7 +423,22 @@ template <class ElemTy> struct ConcurrentReadableArray {
422423
struct Storage {
423424
std::atomic<size_t> Count;
424425
typename std::aligned_storage<sizeof(ElemTy), alignof(ElemTy)>::type Elem;
425-
426+
427+
static Storage *allocate(size_t capacity) {
428+
auto size = sizeof(Storage) + (capacity - 1) * sizeof(Storage().Elem);
429+
auto *ptr = reinterpret_cast<Storage *>(malloc(size));
430+
if (!ptr) swift::crash("Could not allocate memory.");
431+
ptr->Count.store(0, std::memory_order_relaxed);
432+
return ptr;
433+
}
434+
435+
void deallocate() {
436+
for (size_t i = 0; i < Count; i++) {
437+
data()[i].~ElemTy();
438+
}
439+
free(this);
440+
}
441+
426442
ElemTy *data() {
427443
return reinterpret_cast<ElemTy *>(&Elem);
428444
}
@@ -434,33 +450,22 @@ template <class ElemTy> struct ConcurrentReadableArray {
434450
Mutex WriterLock;
435451
std::vector<Storage *> FreeList;
436452

437-
Storage *allocate(size_t capacity) {
438-
auto size = sizeof(Storage) + (capacity - 1) * sizeof(Storage().Elem);
439-
auto *ptr = reinterpret_cast<Storage *>(malloc(size));
440-
if (!ptr) swift::crash("Could not allocate memory.");
441-
ptr->Count.store(0, std::memory_order_relaxed);
442-
return ptr;
443-
}
453+
public:
454+
// This type cannot be safely copied, moved, or deleted.
455+
ConcurrentReadableArray(const ConcurrentReadableArray &) = delete;
456+
ConcurrentReadableArray(ConcurrentReadableArray &&) = delete;
457+
ConcurrentReadableArray &operator=(const ConcurrentReadableArray &) = delete;
444458

445-
void deallocate(Storage *storage) {
446-
if (storage == nullptr) return;
447-
448-
auto *data = storage->data();
449-
for (size_t i = 0; i < storage->Count; i++) {
450-
data[i].~ElemTy();
451-
}
452-
free(storage);
453-
}
459+
ConcurrentReadableArray() : Capacity(0), ReaderCount(0), Elements(nullptr) {}
454460

455-
public:
456461
void push_back(const ElemTy &elem) {
457462
ScopedLock guard(WriterLock);
458463

459464
auto *storage = Elements.load(std::memory_order_relaxed);
460465
auto count = storage ? storage->Count.load(std::memory_order_relaxed) : 0;
461466
if (count >= Capacity) {
462467
auto newCapacity = std::max((size_t)16, count * 2);
463-
auto *newStorage = allocate(newCapacity);
468+
auto *newStorage = Storage::allocate(newCapacity);
464469
if (storage) {
465470
std::copy(storage->data(), storage->data() + count, newStorage->data());
466471
newStorage->Count.store(count, std::memory_order_relaxed);
@@ -477,7 +482,7 @@ template <class ElemTy> struct ConcurrentReadableArray {
477482

478483
if (ReaderCount.load(std::memory_order_acquire) == 0)
479484
for (Storage *storage : FreeList)
480-
deallocate(storage);
485+
storage->deallocate();
481486
}
482487

483488
/// Read the contents of the array. The parameter `f` is called with
@@ -486,9 +491,9 @@ template <class ElemTy> struct ConcurrentReadableArray {
486491
/// `read` was called. The pointer becomes invalid after `f` returns.
487492
template <class F> auto read(F f) -> decltype(f(nullptr, 0)) {
488493
ReaderCount.fetch_add(1, std::memory_order_acquire);
489-
auto *storage = Elements.load(std::memory_order_consume);
494+
auto *storage = Elements.load(SWIFT_MEMORY_ORDER_CONSUME);
490495
auto count = storage->Count.load(std::memory_order_acquire);
491-
auto *ptr = storage->data();
496+
const auto *ptr = storage->data();
492497

493498
decltype(f(nullptr, 0)) result = f(ptr, count);
494499

@@ -499,7 +504,7 @@ template <class ElemTy> struct ConcurrentReadableArray {
499504

500505
/// Get the current count. It's just a snapshot and may be obsolete immediately.
501506
size_t count() {
502-
return read([](ElemTy *ptr, size_t count) -> size_t {
507+
return read([](const ElemTy *ptr, size_t count) -> size_t {
503508
return count;
504509
});
505510
}

stdlib/public/SwiftShims/RefCount.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,10 @@ typedef InlineRefCountsPlaceholder InlineRefCounts;
3535

3636
#include "llvm/Support/Compiler.h"
3737
#include "swift/Basic/type_traits.h"
38+
#include "swift/Runtime/Atomic.h"
3839
#include "swift/Runtime/Config.h"
3940
#include "swift/Runtime/Debug.h"
4041

41-
// FIXME: Workaround for rdar://problem/18889711. 'Consume' does not require
42-
// a barrier on ARM64, but LLVM doesn't know that. Although 'relaxed'
43-
// is formally UB by C++11 language rules, we should be OK because neither
44-
// the processor model nor the optimizer can realistically reorder our uses
45-
// of 'consume'.
46-
#if __arm64__ || __arm__
47-
# define SWIFT_MEMORY_ORDER_CONSUME (std::memory_order_relaxed)
48-
#else
49-
# define SWIFT_MEMORY_ORDER_CONSUME (std::memory_order_consume)
50-
#endif
5142

5243
/*
5344
An object conceptually has three refcounts. These refcounts

stdlib/public/runtime/ProtocolConformance.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ void ConformanceState::verify() const {
326326
// Iterate over all of the sections and verify all of the protocol
327327
// descriptors.
328328
auto &Self = const_cast<ConformanceState &>(*this);
329-
Self.SectionsToScan.read([](ConformanceSection *ptr, size_t count) -> char {
329+
Self.SectionsToScan.read([](const ConformanceSection *ptr, size_t count) -> char {
330330
for (size_t i = 0; i < count; i++) {
331331
for (const auto &Record : ptr[i]) {
332332
Record.get()->verify();
@@ -548,7 +548,7 @@ swift_conformsToProtocolImpl(const Metadata * const type,
548548
// Prepare to scan conformance records.
549549
size_t scannedCount;
550550
auto returnNull = C.SectionsToScan
551-
.read([&](ConformanceSection *ptr, size_t count) -> bool {
551+
.read([&](const ConformanceSection *ptr, size_t count) -> bool {
552552
scannedCount = count;
553553
// Scan only sections that were not scanned yet.
554554
// If we found an out-of-date negative cache entry,
@@ -658,7 +658,7 @@ swift::_searchConformancesByMangledTypeName(Demangle::NodePointer node) {
658658
auto &C = Conformances.get();
659659

660660
return C.SectionsToScan
661-
.read([&](ConformanceSection *ptr, size_t count) -> const TypeContextDescriptor * {
661+
.read([&](const ConformanceSection *ptr, size_t count) -> const TypeContextDescriptor * {
662662
for (size_t i = 0; i < count; i++) {
663663
auto &section = ptr[i];
664664
for (const auto &record : section) {

0 commit comments

Comments
 (0)