Skip to content

Commit a0a77fa

Browse files
authored
Merge pull request #76870 from al45tair/eng/PR-137286187
[Concurrency] Remove C++ runtime references from embedded Concurrency.
2 parents f65d41e + 793d87e commit a0a77fa

File tree

7 files changed

+131
-22
lines changed

7 files changed

+131
-22
lines changed

include/swift/Runtime/Heap.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_RUNTIME_HEAP_H
1919

2020
#include <cstddef>
21+
#include <limits>
2122
#include <new>
2223
#include <utility>
2324

@@ -88,6 +89,94 @@ static inline void swift_cxx_deleteObject(T *ptr) {
8889
swift_slowDealloc(ptr, sizeof(T), alignof(T) - 1);
8990
}
9091
}
92+
93+
/// Define a custom operator delete; this is useful when a class has a
94+
/// virtual destructor, as in that case the compiler will emit a deleting
95+
/// version of the destructor, which will call ::operator delete unless the
96+
/// class (or its superclasses) define one of their own.
97+
#define SWIFT_CXX_DELETE_OPERATOR(T) \
98+
void operator delete(void *ptr) { \
99+
swift_slowDealloc(ptr, sizeof(T), alignof(T) - 1); \
100+
}
101+
102+
/// A C++ Allocator that uses the above functions instead of operator new
103+
/// and operator delete. This lets us use STL containers without pulling
104+
/// in global operator new and global operator delete.
105+
template <typename T>
106+
struct cxx_allocator {
107+
// Member types
108+
typedef T value_type;
109+
typedef T *pointer;
110+
typedef const T *const_pointer;
111+
typedef T &reference;
112+
typedef const T &const_reference;
113+
typedef std::size_t size_type;
114+
typedef std::ptrdiff_t difference_type;
115+
typedef std::true_type propagate_on_container_move_assignment;
116+
typedef std::true_type is_always_equal;
117+
118+
template <typename U>
119+
struct rebind {
120+
typedef cxx_allocator<U> other;
121+
};
122+
123+
cxx_allocator() noexcept {}
124+
cxx_allocator(const cxx_allocator &other) noexcept { (void)other; }
125+
126+
template <class U>
127+
cxx_allocator(const cxx_allocator<U> &other) noexcept { (void)other; }
128+
129+
~cxx_allocator() {}
130+
131+
pointer address(reference x) const noexcept {
132+
return reinterpret_cast<pointer>(&reinterpret_cast<volatile char &>(x));
133+
}
134+
135+
const_pointer address(const_reference x) const noexcept {
136+
return reinterpret_cast<const_pointer>(&
137+
reinterpret_cast<const volatile char &>(x));
138+
}
139+
140+
T *allocate(std::size_t n) {
141+
return reinterpret_cast<T *>(swift_slowAlloc(sizeof(T) * n,
142+
alignof(T) - 1));
143+
}
144+
T *allocate(std::size_t n, const void *hint) {
145+
(void)hint;
146+
return allocate(n);
147+
}
148+
149+
void deallocate(T *p, std::size_t n) {
150+
swift_slowDealloc(p, sizeof(T) * n, alignof(T) - 1);
151+
}
152+
153+
size_type max_size() const noexcept {
154+
return std::numeric_limits<size_type>::max() / sizeof(T);
155+
}
156+
157+
template <class U, class... Args>
158+
void construct(U *p, Args&&... args) {
159+
::new((void *)p) U(std::forward<Args>(args)...);
160+
}
161+
162+
template <class U>
163+
void destroy(U *p) {
164+
p->~U();
165+
}
166+
};
167+
168+
template <typename T, typename U>
169+
bool operator==(const cxx_allocator<T> &lhs,
170+
const cxx_allocator<U> &rhs) noexcept {
171+
return true;
172+
}
173+
174+
template <typename T, typename U>
175+
bool operator!=(const cxx_allocator<T> &lha,
176+
const cxx_allocator<U> &rhs) noexcept {
177+
return false;
178+
}
179+
91180
}
92181

93182
#endif // SWIFT_RUNTIME_HEAP_H

stdlib/public/Concurrency/Actor.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "swift/Runtime/Casting.h"
3333
#include "swift/Runtime/DispatchShims.h"
3434
#include "swift/Runtime/EnvironmentVariables.h"
35+
#include "swift/Runtime/Heap.h"
3536
#include "swift/Threading/Mutex.h"
3637
#include "swift/Threading/Once.h"
3738
#include "swift/Threading/Thread.h"
@@ -1325,7 +1326,7 @@ dispatch_lock_t *DefaultActorImpl::drainLockAddr() {
13251326

13261327
void DefaultActorImpl::scheduleActorProcessJob(
13271328
JobPriority priority, TaskExecutorRef taskExecutor) {
1328-
Job *job = new ProcessOutOfLineJob(this, priority);
1329+
Job *job = swift_cxx_newObject<ProcessOutOfLineJob>(this, priority);
13291330
SWIFT_TASK_DEBUG_LOG(
13301331
"Scheduling processing job %p for actor %p at priority %#zx, with taskExecutor %p", job, this,
13311332
priority, taskExecutor.getIdentity());
@@ -1677,7 +1678,7 @@ void ProcessOutOfLineJob::process(Job *job) {
16771678
auto self = cast<ProcessOutOfLineJob>(job);
16781679
DefaultActorImpl *actor = self->Actor;
16791680

1680-
delete self;
1681+
swift_cxx_deleteObject(self);
16811682
return defaultActorDrain(actor); // 'return' forces tail call
16821683
}
16831684

@@ -2293,7 +2294,7 @@ class IsolatedDeinitJob : public Job {
22932294
auto *job = cast<IsolatedDeinitJob>(_job);
22942295
void *object = job->Object;
22952296
DeinitWorkFunction *work = job->Work;
2296-
delete job;
2297+
swift_cxx_deleteObject(job);
22972298
return work(object);
22982299
}
22992300

@@ -2379,7 +2380,7 @@ static void swift_task_deinitOnExecutorImpl(void *object,
23792380
auto priority = currentTask ? swift_task_currentPriority(currentTask)
23802381
: swift_task_getCurrentThreadPriority();
23812382

2382-
auto job = new IsolatedDeinitJob(priority, object, work);
2383+
auto job = swift_cxx_newObject<IsolatedDeinitJob>(priority, object, work);
23832384
swift_task_enqueue(job, newExecutor);
23842385
#endif
23852386
}

stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include <errno.h>
4040
#include "swift/Basic/PriorityQueue.h"
41+
#include "swift/Runtime/Heap.h"
4142

4243
#if __has_include(<time.h>)
4344
# include <time.h>
@@ -103,10 +104,10 @@ struct JobDeadlineStorage<false> {
103104
return *storage(job);
104105
}
105106
static void set(SwiftJob *job, JobDeadline deadline) {
106-
storage(job) = new JobDeadline(deadline);
107+
storage(job) = swift_cxx_newObject<JobDeadline>(deadline);
107108
}
108109
static void destroy(SwiftJob *job) {
109-
delete storage(job);
110+
swift_cxx_deleteObject(storage(job));
110111
}
111112
};
112113

stdlib/public/Concurrency/Task.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "swift/Runtime/Concurrency.h"
3535
#include "swift/Runtime/EnvironmentVariables.h"
3636
#include "swift/Runtime/HeapObject.h"
37+
#include "swift/Runtime/Heap.h"
3738
#include "swift/Threading/Mutex.h"
3839
#include <atomic>
3940
#include <new>
@@ -220,7 +221,7 @@ void NullaryContinuationJob::process(Job *_job) {
220221

221222
auto *continuation = job->Continuation;
222223

223-
delete job;
224+
swift_cxx_deleteObject(job);
224225

225226
auto *context =
226227
static_cast<ContinuationAsyncContext*>(continuation->ResumeContext);
@@ -1720,7 +1721,7 @@ static NullaryContinuationJob*
17201721
swift_task_createNullaryContinuationJobImpl(
17211722
size_t priority,
17221723
AsyncTask *continuation) {
1723-
auto *job = new NullaryContinuationJob(swift_task_getCurrent(),
1724+
auto *job = swift_cxx_newObject<NullaryContinuationJob>(swift_task_getCurrent(),
17241725
static_cast<JobPriority>(priority), continuation);
17251726

17261727
return job;

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
#include "swift/Basic/STLExtras.h"
3232
#include "swift/Runtime/Concurrency.h"
3333
#include "swift/Runtime/Config.h"
34+
#include "swift/Runtime/Heap.h"
3435
#include "swift/Runtime/HeapObject.h"
3536
#include "swift/Threading/Mutex.h"
3637
#include <atomic>
38+
#include <deque>
3739
#include <new>
3840

3941
#if SWIFT_STDLIB_HAS_ASL
@@ -114,7 +116,7 @@ class DiscardingTaskGroup;
114116

115117
template<typename T>
116118
class NaiveTaskGroupQueue {
117-
std::queue <T> queue;
119+
std::queue<T, std::deque<T, swift::cxx_allocator<T>>> queue;
118120

119121
public:
120122
NaiveTaskGroupQueue() = default;
@@ -346,6 +348,11 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
346348
public:
347349
virtual ~TaskGroupBase() {}
348350

351+
/// Because we have a virtual destructor, we need to declare a delete operator
352+
/// here, otherwise the compiler will generate a deleting destructor that
353+
/// calls ::operator delete.
354+
SWIFT_CXX_DELETE_OPERATOR(TaskGroupBase)
355+
349356
TaskStatusRecordKind getKind() const {
350357
return Flags.getKind();
351358
}
@@ -419,7 +426,9 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
419426
TaskGroupStatus statusLoadRelaxed() const;
420427
TaskGroupStatus statusLoadAcquire() const;
421428

429+
#if !SWIFT_CONCURRENCY_EMBEDDED
422430
std::string statusString() const;
431+
#endif
423432

424433
bool isEmpty() const;
425434

@@ -469,6 +478,7 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
469478

470479
};
471480

481+
#if !SWIFT_CONCURRENCY_EMBEDDED
472482
[[maybe_unused]]
473483
static std::string to_string(TaskGroupBase::PollStatus status) {
474484
switch (status) {
@@ -478,6 +488,7 @@ static std::string to_string(TaskGroupBase::PollStatus status) {
478488
case TaskGroupBase::PollStatus::Error: return "Error";
479489
}
480490
}
491+
#endif
481492

482493
/// The status of a task group.
483494
///
@@ -579,7 +590,13 @@ struct TaskGroupStatus {
579590
swift_asprintf(
580591
&message,
581592
"error: %sTaskGroup: detected pending task count overflow, in task group %p! Status: %s",
582-
group->isDiscardingResults() ? "Discarding" : "", group, status.to_string(group).c_str());
593+
group->isDiscardingResults() ? "Discarding" : "", group,
594+
#if !SWIFT_CONCURRENCY_EMBEDDED
595+
status.to_string(group).c_str()
596+
#else
597+
"<status unavailable in embedded>"
598+
#endif
599+
);
583600

584601
#if !SWIFT_CONCURRENCY_EMBEDDED
585602
if (_swift_shouldReportFatalErrorsToDebugger()) {
@@ -612,6 +629,7 @@ struct TaskGroupStatus {
612629
abort();
613630
}
614631

632+
#if !SWIFT_CONCURRENCY_EMBEDDED
615633
/// Pretty prints the status, as follows:
616634
/// If accumulating results:
617635
/// TaskGroupStatus{ C:{cancelled} W:{waiting task} R:{ready tasks} P:{pending tasks} {binary repr} }
@@ -634,6 +652,7 @@ struct TaskGroupStatus {
634652
str.append(" }");
635653
return str;
636654
}
655+
#endif // !SWIFT_CONCURRENCY_EMBEDDED
637656

638657
/// Initially there are no waiting and no pending tasks.
639658
static const TaskGroupStatus initial() {
@@ -691,9 +710,11 @@ TaskGroupStatus TaskGroupBase::statusLoadAcquire() const {
691710
return TaskGroupStatus{status.load(std::memory_order_acquire)};
692711
}
693712

713+
#if !SWIFT_CONCURRENCY_EMBEDDED
694714
std::string TaskGroupBase::statusString() const {
695715
return statusLoadRelaxed().to_string(this);
696716
}
717+
#endif
697718

698719
bool TaskGroupBase::isEmpty() const {
699720
auto oldStatus = TaskGroupStatus{status.load(std::memory_order_relaxed)};
@@ -749,6 +770,7 @@ TaskGroupStatus TaskGroupBase::statusAddPendingTaskAssumeRelaxed(bool unconditio
749770
}
750771

751772
SWIFT_TASK_GROUP_DEBUG_LOG(this, "addPending, after: %s", s.to_string(this).c_str());
773+
752774
return s;
753775
}
754776

stdlib/public/Concurrency/TaskLocal.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/Runtime/Atomic.h"
2020
#include "swift/Runtime/Casting.h"
2121
#include "swift/Runtime/Concurrency.h"
22+
#include "swift/Runtime/Heap.h"
2223
#include "swift/Threading/ThreadLocalStorage.h"
2324
#include "llvm/ADT/PointerIntPair.h"
2425
#include <new>
@@ -473,7 +474,9 @@ void TaskLocal::Storage::copyTo(AsyncTask *target) {
473474
// because it is the most "specific"/"recent" binding and any other binding
474475
// of a key does not matter for the target task as it will never be able to
475476
// observe it.
476-
std::set<const HeapObject*> copied = {};
477+
std::set<const HeapObject *,
478+
std::less<const HeapObject *>,
479+
swift::cxx_allocator<const HeapObject *>> copied = {};
477480

478481
auto item = head;
479482
while (item) {
@@ -499,7 +502,9 @@ void TaskLocal::Storage::copyToOnlyOnlyFromCurrentGroup(AsyncTask *target) {
499502
// because it is the most "specific"/"recent" binding and any other binding
500503
// of a key does not matter for the target task as it will never be able to
501504
// observe it.
502-
std::set<const HeapObject*> copied = {};
505+
std::set<const HeapObject *,
506+
std::less<const HeapObject *>,
507+
swift::cxx_allocator<const HeapObject *>> copied = {};
503508

504509
auto item = head;
505510
TaskLocal::Item *copiedHead = nullptr;

test/embedded/dependencies-concurrency-custom-executor.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,6 @@
1010
// Fail if there is any entry in actual-dependencies.txt that's not in allowed-dependencies.txt
1111
// RUN: test -z "`comm -13 %t/allowed-dependencies.txt %t/actual-dependencies.txt`"
1212

13-
// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc
14-
// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKcm
15-
// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6insertEmPKc
16-
// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev
17-
// DEP: __ZNSt3__16chrono12steady_clock3nowEv
18-
// DEP: __ZNSt3__19to_stringEj
19-
// DEP: __ZNSt3__19to_stringEy
20-
// DEP: __ZdlPv
21-
// DEP: __ZdlPvm
22-
// DEP: __Znwm
2313
// DEP: ___assert_rtn
2414
// DEP: ___error
2515
// DEP: ___stack_chk_fail

0 commit comments

Comments
 (0)