Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions include/swift/Runtime/Heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define SWIFT_RUNTIME_HEAP_H

#include <cstddef>
#include <limits>
#include <new>
#include <utility>

Expand Down Expand Up @@ -88,6 +89,94 @@ static inline void swift_cxx_deleteObject(T *ptr) {
swift_slowDealloc(ptr, sizeof(T), alignof(T) - 1);
}
}

/// Define a custom operator delete; this is useful when a class has a
/// virtual destructor, as in that case the compiler will emit a deleting
/// version of the destructor, which will call ::operator delete unless the
/// class (or its superclasses) define one of their own.
#define SWIFT_CXX_DELETE_OPERATOR(T) \
void operator delete(void *ptr) { \
swift_slowDealloc(ptr, sizeof(T), alignof(T) - 1); \
}

/// A C++ Allocator that uses the above functions instead of operator new
/// and operator delete. This lets us use STL containers without pulling
/// in global operator new and global operator delete.
template <typename T>
struct cxx_allocator {
// Member types
typedef T value_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef std::true_type propagate_on_container_move_assignment;
typedef std::true_type is_always_equal;

template <typename U>
struct rebind {
typedef cxx_allocator<U> other;
};

cxx_allocator() noexcept {}
cxx_allocator(const cxx_allocator &other) noexcept { (void)other; }

template <class U>
cxx_allocator(const cxx_allocator<U> &other) noexcept { (void)other; }

~cxx_allocator() {}

pointer address(reference x) const noexcept {
return reinterpret_cast<pointer>(&reinterpret_cast<volatile char &>(x));
}

const_pointer address(const_reference x) const noexcept {
return reinterpret_cast<const_pointer>(&
reinterpret_cast<const volatile char &>(x));
}

T *allocate(std::size_t n) {
return reinterpret_cast<T *>(swift_slowAlloc(sizeof(T) * n,
alignof(T) - 1));
}
T *allocate(std::size_t n, const void *hint) {
(void)hint;
return allocate(n);
}

void deallocate(T *p, std::size_t n) {
swift_slowDealloc(p, sizeof(T) * n, alignof(T) - 1);
}

size_type max_size() const noexcept {
return std::numeric_limits<size_type>::max() / sizeof(T);
}

template <class U, class... Args>
void construct(U *p, Args&&... args) {
::new((void *)p) U(std::forward<Args>(args)...);
}

template <class U>
void destroy(U *p) {
p->~U();
}
};

template <typename T, typename U>
bool operator==(const cxx_allocator<T> &lhs,
const cxx_allocator<U> &rhs) noexcept {
return true;
}

template <typename T, typename U>
bool operator!=(const cxx_allocator<T> &lha,
const cxx_allocator<U> &rhs) noexcept {
return false;
}

}

#endif // SWIFT_RUNTIME_HEAP_H
9 changes: 5 additions & 4 deletions stdlib/public/Concurrency/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/DispatchShims.h"
#include "swift/Runtime/EnvironmentVariables.h"
#include "swift/Runtime/Heap.h"
#include "swift/Threading/Mutex.h"
#include "swift/Threading/Once.h"
#include "swift/Threading/Thread.h"
Expand Down Expand Up @@ -1325,7 +1326,7 @@ dispatch_lock_t *DefaultActorImpl::drainLockAddr() {

void DefaultActorImpl::scheduleActorProcessJob(
JobPriority priority, TaskExecutorRef taskExecutor) {
Job *job = new ProcessOutOfLineJob(this, priority);
Job *job = swift_cxx_newObject<ProcessOutOfLineJob>(this, priority);
SWIFT_TASK_DEBUG_LOG(
"Scheduling processing job %p for actor %p at priority %#zx, with taskExecutor %p", job, this,
priority, taskExecutor.getIdentity());
Expand Down Expand Up @@ -1677,7 +1678,7 @@ void ProcessOutOfLineJob::process(Job *job) {
auto self = cast<ProcessOutOfLineJob>(job);
DefaultActorImpl *actor = self->Actor;

delete self;
swift_cxx_deleteObject(self);
return defaultActorDrain(actor); // 'return' forces tail call
}

Expand Down Expand Up @@ -2293,7 +2294,7 @@ class IsolatedDeinitJob : public Job {
auto *job = cast<IsolatedDeinitJob>(_job);
void *object = job->Object;
DeinitWorkFunction *work = job->Work;
delete job;
swift_cxx_deleteObject(job);
return work(object);
}

Expand Down Expand Up @@ -2379,7 +2380,7 @@ static void swift_task_deinitOnExecutorImpl(void *object,
auto priority = currentTask ? swift_task_currentPriority(currentTask)
: swift_task_getCurrentThreadPriority();

auto job = new IsolatedDeinitJob(priority, object, work);
auto job = swift_cxx_newObject<IsolatedDeinitJob>(priority, object, work);
swift_task_enqueue(job, newExecutor);
#endif
}
Expand Down
5 changes: 3 additions & 2 deletions stdlib/public/Concurrency/CooperativeGlobalExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

#include <errno.h>
#include "swift/Basic/PriorityQueue.h"
#include "swift/Runtime/Heap.h"

#if __has_include(<time.h>)
# include <time.h>
Expand Down Expand Up @@ -103,10 +104,10 @@ struct JobDeadlineStorage<false> {
return *storage(job);
}
static void set(SwiftJob *job, JobDeadline deadline) {
storage(job) = new JobDeadline(deadline);
storage(job) = swift_cxx_newObject<JobDeadline>(deadline);
}
static void destroy(SwiftJob *job) {
delete storage(job);
swift_cxx_deleteObject(storage(job));
}
};

Expand Down
5 changes: 3 additions & 2 deletions stdlib/public/Concurrency/Task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/EnvironmentVariables.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Heap.h"
#include "swift/Threading/Mutex.h"
#include <atomic>
#include <new>
Expand Down Expand Up @@ -220,7 +221,7 @@ void NullaryContinuationJob::process(Job *_job) {

auto *continuation = job->Continuation;

delete job;
swift_cxx_deleteObject(job);

auto *context =
static_cast<ContinuationAsyncContext*>(continuation->ResumeContext);
Expand Down Expand Up @@ -1718,7 +1719,7 @@ static NullaryContinuationJob*
swift_task_createNullaryContinuationJobImpl(
size_t priority,
AsyncTask *continuation) {
auto *job = new NullaryContinuationJob(swift_task_getCurrent(),
auto *job = swift_cxx_newObject<NullaryContinuationJob>(swift_task_getCurrent(),
static_cast<JobPriority>(priority), continuation);

return job;
Expand Down
30 changes: 26 additions & 4 deletions stdlib/public/Concurrency/TaskGroup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
#include "swift/Basic/STLExtras.h"
#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/Config.h"
#include "swift/Runtime/Heap.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Threading/Mutex.h"
#include <atomic>
#include <deque>
#include <new>

#if SWIFT_STDLIB_HAS_ASL
Expand Down Expand Up @@ -114,7 +116,7 @@ class DiscardingTaskGroup;

template<typename T>
class NaiveTaskGroupQueue {
std::queue <T> queue;
std::queue<T, std::deque<T, swift::cxx_allocator<T>>> queue;

public:
NaiveTaskGroupQueue() = default;
Expand Down Expand Up @@ -346,6 +348,11 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
public:
virtual ~TaskGroupBase() {}

/// Because we have a virtual destructor, we need to declare a delete operator
/// here, otherwise the compiler will generate a deleting destructor that
/// calls ::operator delete.
SWIFT_CXX_DELETE_OPERATOR(TaskGroupBase)

TaskStatusRecordKind getKind() const {
return Flags.getKind();
}
Expand Down Expand Up @@ -419,7 +426,9 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {
TaskGroupStatus statusLoadRelaxed() const;
TaskGroupStatus statusLoadAcquire() const;

#if !SWIFT_CONCURRENCY_EMBEDDED
std::string statusString() const;
#endif

bool isEmpty() const;

Expand Down Expand Up @@ -469,6 +478,7 @@ class TaskGroupBase : public TaskGroupTaskStatusRecord {

};

#if !SWIFT_CONCURRENCY_EMBEDDED
[[maybe_unused]]
static std::string to_string(TaskGroupBase::PollStatus status) {
switch (status) {
Expand All @@ -478,6 +488,7 @@ static std::string to_string(TaskGroupBase::PollStatus status) {
case TaskGroupBase::PollStatus::Error: return "Error";
}
}
#endif

/// The status of a task group.
///
Expand Down Expand Up @@ -579,7 +590,13 @@ struct TaskGroupStatus {
swift_asprintf(
&message,
"error: %sTaskGroup: detected pending task count overflow, in task group %p! Status: %s",
group->isDiscardingResults() ? "Discarding" : "", group, status.to_string(group).c_str());
group->isDiscardingResults() ? "Discarding" : "", group,
#if !SWIFT_CONCURRENCY_EMBEDDED
status.to_string(group).c_str()
#else
"<status unavailable in embedded>"
#endif
);

#if !SWIFT_CONCURRENCY_EMBEDDED
if (_swift_shouldReportFatalErrorsToDebugger()) {
Expand Down Expand Up @@ -612,6 +629,7 @@ struct TaskGroupStatus {
abort();
}

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

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

#if !SWIFT_CONCURRENCY_EMBEDDED
std::string TaskGroupBase::statusString() const {
return statusLoadRelaxed().to_string(this);
}
#endif

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

SWIFT_TASK_GROUP_DEBUG_LOG(this, "addPending, after: %s", s.to_string(this).c_str());

return s;
}

Expand Down Expand Up @@ -967,13 +989,13 @@ static void swift_taskGroup_initializeImpl(TaskGroup *group, const Metadata *T)
SWIFT_CC(swift)
static void swift_taskGroup_initializeWithFlagsImpl(size_t rawGroupFlags,
TaskGroup *group, const Metadata *T) {
ResultTypeInfo resultType;
#if !SWIFT_CONCURRENCY_EMBEDDED
ResultTypeInfo resultType;
resultType.metadata = T;
_swift_taskGroup_initialize(resultType, rawGroupFlags, group);
#else
swift_unreachable("swift_taskGroup_initializeWithFlags in embedded");
#endif
_swift_taskGroup_initialize(resultType, rawGroupFlags, group);
}

// Initializes into the preallocated _group an actual instance.
Expand Down
9 changes: 7 additions & 2 deletions stdlib/public/Concurrency/TaskLocal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "swift/Runtime/Atomic.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Concurrency.h"
#include "swift/Runtime/Heap.h"
#include "swift/Threading/ThreadLocalStorage.h"
#include "llvm/ADT/PointerIntPair.h"
#include <new>
Expand Down Expand Up @@ -473,7 +474,9 @@ void TaskLocal::Storage::copyTo(AsyncTask *target) {
// because it is the most "specific"/"recent" binding and any other binding
// of a key does not matter for the target task as it will never be able to
// observe it.
std::set<const HeapObject*> copied = {};
std::set<const HeapObject *,
std::less<const HeapObject *>,
swift::cxx_allocator<const HeapObject *>> copied = {};

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

auto item = head;
TaskLocal::Item *copiedHead = nullptr;
Expand Down
10 changes: 0 additions & 10 deletions test/embedded/dependencies-concurrency-custom-executor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,6 @@
// Fail if there is any entry in actual-dependencies.txt that's not in allowed-dependencies.txt
// RUN: test -z "`comm -13 %t/allowed-dependencies.txt %t/actual-dependencies.txt`"

// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKc
// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6appendEPKcm
// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEE6insertEmPKc
// DEP: __ZNSt3__112basic_stringIcNS_11char_traitsIcEENS_9allocatorIcEEED1Ev
// DEP: __ZNSt3__16chrono12steady_clock3nowEv
// DEP: __ZNSt3__19to_stringEj
// DEP: __ZNSt3__19to_stringEy
// DEP: __ZdlPv
// DEP: __ZdlPvm
// DEP: __Znwm
// DEP: ___assert_rtn
// DEP: ___error
// DEP: ___stack_chk_fail
Expand Down