diff --git a/include/swift/Runtime/AtomicWaitQueue.h b/include/swift/Runtime/AtomicWaitQueue.h index cc0d99890d571..0985067828b25 100644 --- a/include/swift/Runtime/AtomicWaitQueue.h +++ b/include/swift/Runtime/AtomicWaitQueue.h @@ -20,6 +20,7 @@ #define SWIFT_RUNTIME_ATOMICWAITQUEUE_H #include "swift/Runtime/Heap.h" +#include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Mutex.h" #include @@ -84,7 +85,7 @@ class AtomicWaitQueue { /// global lock and while *not* holding the wait queue lock. void release_locked() { if (referenceCount == 1) { - delete &asImpl(); + swift_cxx_deleteObject(&asImpl()); } else { referenceCount--; } @@ -211,7 +212,7 @@ class AtomicWaitQueue { // If we created the queue but never published it, destroy it. if (CurrentQueue) { CurrentQueue->WaitQueueLock.unlock(); - delete CurrentQueue; + swift_cxx_deleteObject(CurrentQueue); } } @@ -425,12 +426,7 @@ class AtomicWaitQueue { private: template static Impl *createNewQueue(Args &&...args) { -#if !defined(__cpp_aligned_new) - static_assert(!swift::requires_aligned_alloc::value>::value || - is_aligned_alloc_aware::value, - "type is over-aligned for non-alignment aware operator new"); -#endif - auto queue = new Impl(std::forward(args)...); + auto queue = swift_cxx_newObject(std::forward(args)...); queue->WaitQueueLock.lock(); return queue; } diff --git a/include/swift/Runtime/HeapObject.h b/include/swift/Runtime/HeapObject.h index efb50b3f93c57..7825484670df1 100644 --- a/include/swift/Runtime/HeapObject.h +++ b/include/swift/Runtime/HeapObject.h @@ -19,6 +19,8 @@ #include #include +#include +#include #include "swift/Runtime/Config.h" #if SWIFT_OBJC_INTEROP @@ -131,6 +133,49 @@ void *swift_slowAlloc(size_t bytes, size_t alignMask); SWIFT_RUNTIME_EXPORT void swift_slowDealloc(void *ptr, size_t bytes, size_t alignMask); +/// Allocate and construct an instance of type \c T. +/// +/// \param args The arguments to pass to the constructor for \c T. +/// +/// \returns A pointer to a new, fully constructed instance of \c T. This +/// function never returns \c nullptr. The caller is responsible for +/// eventually destroying the resulting object by passing it to +/// \c swift_cxx_deleteObject(). +/// +/// This function avoids the use of the global \c operator \c new (which may be +/// overridden by other code in a process) in favor of calling +/// \c swift_slowAlloc() and constructing the new object with placement new. +/// +/// This function is capable of returning well-aligned memory even on platforms +/// that do not implement the C++17 "over-aligned new" feature. +template +static inline T *swift_cxx_newObject(Args &&... args) { + auto result = reinterpret_cast(swift_slowAlloc(sizeof(T), + alignof(T) - 1)); + ::new (result) T(std::forward(args)...); + return result; +} + +/// Destruct and deallocate an instance of type \c T. +/// +/// \param ptr A pointer to an instance of type \c T previously created with a +/// call to \c swift_cxx_newObject(). +/// +/// This function avoids the use of the global \c operator \c delete (which may +/// be overridden by other code in a process) in favor of directly calling the +/// destructor for \a *ptr and then freeing its memory by calling +/// \c swift_slowDealloc(). +/// +/// The effect of passing a pointer to this function that was \em not returned +/// from \c swift_cxx_newObject() is undefined. +template +static inline void swift_cxx_deleteObject(T *ptr) { + if (ptr) { + ptr->~T(); + swift_slowDealloc(ptr, sizeof(T), alignof(T) - 1); + } +} + /// Atomically increments the retain count of an object. /// /// \param object - may be null, in which case this is a no-op