diff --git a/Package.swift b/Package.swift index 46b98c67a..e4e59f75d 100644 --- a/Package.swift +++ b/Package.swift @@ -196,12 +196,19 @@ let cfCGTypes = envBoolValue("CF_CGTYPES", default: buildForDarwinPlatform) var sharedCSettings: [CSetting] = [ .define("NDEBUG", .when(configuration: .release)), + // Rewrite malloc() to malloc_type_malloc() for type-isolated allocation buckets (xzone malloc). + .unsafeFlags(["-ftyped-memory-operations"], .when(platforms: .darwinPlatforms)), .unsafeFlags(["-fmodules"]), .define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])), .unsafeFlags(["-isystem", swiftCorelibsPath], .when(platforms: .nonDarwinPlatforms)), ] var sharedCxxSettings: [CXXSetting] = [ + .define("NDEBUG", .when(configuration: .release)), + // Rewrite malloc() to malloc_type_malloc() for type-isolated allocation buckets (xzone malloc). + .unsafeFlags(["-ftyped-memory-operations"], .when(platforms: .darwinPlatforms)), + // Rewrite operator new/delete to typed variants (operator new(size_t, std::__type_descriptor_t)). + .unsafeFlags(["-ftyped-cxx-new-delete"], .when(platforms: .darwinPlatforms)), .unsafeFlags(["-fcxx-modules"]), .define("_WASI_EMULATED_SIGNAL", .when(platforms: [.wasi])), .unsafeFlags(["-isystem", swiftCorelibsPath], .when(platforms: .nonDarwinPlatforms)), diff --git a/Sources/OpenSwiftUICore/Data/Update.swift b/Sources/OpenSwiftUICore/Data/Update.swift index af73d7fdf..7ef3db858 100644 --- a/Sources/OpenSwiftUICore/Data/Update.swift +++ b/Sources/OpenSwiftUICore/Data/Update.swift @@ -17,7 +17,7 @@ package enum Update { private static var depth = 0 private static var dispatchDepth = 0 - private static let _lock = MovableLock.create() + private static let _lock = MovableLock() private static var actions: [() -> Void] = [] private static let lockAssertionsAreEnabled = EnvironmentHelper.bool(for: "OPENSWIFTUI_ASSERT_LOCKS") diff --git a/Sources/OpenSwiftUI_SPI/Util/MovableLock.c b/Sources/OpenSwiftUI_SPI/Util/MovableLock.c index ca4b33314..833b085d6 100644 --- a/Sources/OpenSwiftUI_SPI/Util/MovableLock.c +++ b/Sources/OpenSwiftUI_SPI/Util/MovableLock.c @@ -2,7 +2,7 @@ // MovableLock.c // OpenSwiftUI // -// Audited for 3.5.2 +// Audited for 6.5.4 // Status: Complete #include "MovableLock.h" @@ -17,8 +17,8 @@ extern pthread_t pthread_main_thread_np(void); #endif -void wait_for_lock(MovableLock lock, pthread_t thread); -void sync_main_callback(MovableLock lock); +static void wait_for_lock(MovableLock lock, pthread_t thread); +static void sync_main_callback(MovableLock lock); MovableLock _MovableLockCreate() { #if OPENSWIFTUI_TARGET_OS_DARWIN @@ -29,79 +29,82 @@ MovableLock _MovableLockCreate() { abort(); } pthread_mutex_init(&lock->mutex, NULL); - pthread_cond_init(&lock->cond1, NULL); - pthread_cond_init(&lock->cond2, NULL); - pthread_cond_init(&lock->cond3, NULL); + pthread_cond_init(&lock->lock_condition, NULL); + pthread_cond_init(&lock->main_callback_condition, NULL); + pthread_cond_init(&lock->broadcast_condition, NULL); #if OPENSWIFTUI_TARGET_OS_DARWIN - lock->main = pthread_main_thread_np(); + lock->main_thread = pthread_main_thread_np(); #endif return lock; } void _MovableLockDestroy(MovableLock lock) { - pthread_cond_destroy(&lock->cond1); - pthread_cond_destroy(&lock->cond2); - pthread_cond_destroy(&lock->cond3); + pthread_cond_destroy(&lock->lock_condition); + pthread_cond_destroy(&lock->main_callback_condition); + pthread_cond_destroy(&lock->broadcast_condition); pthread_mutex_destroy(&lock->mutex); free(lock); } bool _MovableLockIsOwner(MovableLock lock) { - return pthread_self() == lock->owner; + pthread_t owner = lock->owner_thread; + return pthread_self() == owner; } -bool _MovableLockIsOuterMostOwner(MovableLock lock) { - return pthread_self() == lock->owner && lock->level == 1; +bool _MovableLockIsOutermostOwner(MovableLock lock) { + pthread_t owner = lock->owner_thread; + return pthread_self() == owner && lock->lock_level == 1; } void _MovableLockLock(MovableLock lock) { #if OPENSWIFTUI_TARGET_OS_DARWIN pthread_t owner = pthread_self(); - if (owner == lock->owner) { - lock->level += 1; + if (owner == lock->owner_thread) { + lock->lock_level += 1; return; } pthread_mutex_lock(&lock->mutex); - while (lock->owner) { + while (lock->owner_thread) { + [[clang::noinline]] wait_for_lock(lock, owner); } - lock->owner = owner; - lock->level = 1; + lock->owner_thread = owner; + lock->lock_level = 1; #endif } void _MovableLockUnlock(MovableLock lock) { #if OPENSWIFTUI_TARGET_OS_DARWIN - lock->level -= 1; - if (lock->level != 0) { + lock->lock_level -= 1; + if (lock->lock_level != 0) { return; } - if (lock->unknown != 0) { - pthread_cond_signal(&lock->cond1); + if (lock->waiter_count != 0) { + pthread_cond_signal(&lock->lock_condition); } - lock->owner = NULL; + lock->owner_thread = NULL; pthread_mutex_unlock(&lock->mutex); #endif } -void _MovableLockSyncMain(MovableLock lock, const void *context, void (*function)(const void *context)) { +void _MovableLockSyncMain(MovableLock lock, const void *main_callback_context, void (*main_callback)(const void *main_callback_context)) { #if OPENSWIFTUI_TARGET_OS_DARWIN - if (pthread_self() == lock->main) { - function(context); + if (pthread_self() == lock->main_thread) { + main_callback(main_callback_context); } else { - lock->function = function; - lock->context = context; - if (lock->unknown5) { - pthread_cond_signal_thread_np(&lock->cond1, lock->main); - } else if (!lock->unknown4) { - lock->unknown4 = true; + lock->main_callback = main_callback; + lock->main_callback_context = main_callback_context; + if (lock->main_thread_waiting) { + pthread_cond_signal_thread_np(&lock->lock_condition, lock->main_thread); + } else if (!lock->main_callback_pending) { + lock->main_callback_pending = true; dispatch_async_f(dispatch_get_main_queue(), lock, (dispatch_function_t)&sync_main_callback); - if (lock->unknown5) { - pthread_cond_signal_thread_np(&lock->cond1, lock->main); + if (lock->main_thread_waiting) { + pthread_cond_signal_thread_np(&lock->lock_condition, lock->main_thread); } } - while (lock->function) { - pthread_cond_wait(&lock->cond2, &lock->mutex); + while (lock->main_callback) { + pthread_cond_wait(&lock->main_callback_condition, &lock->mutex); } } #endif @@ -110,57 +113,63 @@ void _MovableLockSyncMain(MovableLock lock, const void *context, void (*function void _MovableLockWait(MovableLock lock) { #if OPENSWIFTUI_TARGET_OS_DARWIN pthread_t owner = pthread_self(); - uint32_t level = lock->level; - lock->level = 0; - lock->owner = NULL; - if (lock->unknown != 0) { - pthread_cond_broadcast(&lock->cond1); + uint32_t level = lock->lock_level; + lock->lock_level = 0; + lock->owner_thread = NULL; + if (lock->waiter_count != 0) { + pthread_cond_broadcast(&lock->lock_condition); } - pthread_cond_wait(&lock->cond3, &lock->mutex); - while (lock->owner) { + pthread_cond_wait(&lock->broadcast_condition, &lock->mutex); + while (lock->owner_thread) { + [[clang::noinline]] wait_for_lock(lock, owner); } - lock->owner = owner; - lock->level = level; + lock->owner_thread = owner; + lock->lock_level = level; #endif } void _MovableLockBroadcast(MovableLock lock) { #if OPENSWIFTUI_TARGET_OS_DARWIN - pthread_cond_broadcast(&lock->cond3); + pthread_cond_broadcast(&lock->broadcast_condition); #endif } -void wait_for_lock(MovableLock lock, pthread_t owner) { +static void wait_for_lock(MovableLock lock, pthread_t owner) { #if OPENSWIFTUI_TARGET_OS_DARWIN - lock->unknown += 1; - if (lock->main == owner) { - lock->unknown5 = 1; - if (lock->function) { - uint32_t original_level = lock->level; - pthread_t original_owner = lock->owner; - lock->owner = lock->main; - lock->level = original_level + 1; - lock->function(lock->context); - lock->level = original_level; - lock->owner = original_owner; - lock->function = NULL; - lock->context = NULL; - pthread_cond_signal(&lock->cond2); + lock->waiter_count += 1; + if (lock->main_thread == owner) { + lock->main_thread_waiting = true; + if (lock->main_callback) { + pthread_t original_owner = __atomic_load_n(&lock->owner_thread, __ATOMIC_SEQ_CST); + uint32_t original_level = lock->lock_level; + pthread_t main_thread = lock->main_thread; + lock->owner_thread = main_thread; + lock->lock_level = original_level + 1; + void (*main_callback)(const void *) = lock->main_callback; + const void *main_callback_context = lock->main_callback_context; + main_callback(main_callback_context); + lock->lock_level = original_level; + lock->owner_thread = original_owner; + lock->main_callback = NULL; + lock->main_callback_context = NULL; + pthread_cond_signal(&lock->main_callback_condition); } } - pthread_cond_wait(&lock->cond1, &lock->mutex); - if (lock->main == owner) { - lock->unknown5 = 0; + pthread_cond_wait(&lock->lock_condition, &lock->mutex); + if (lock->main_thread == owner) { + lock->main_thread_waiting = false; } - lock->unknown -= 1; + lock->waiter_count -= 1; #endif } -void sync_main_callback(MovableLock lock) { +static void sync_main_callback(MovableLock lock) { #if OPENSWIFTUI_TARGET_OS_DARWIN + [[clang::noinline]] _MovableLockLock(lock); - lock->unknown4 = 0; + lock->main_callback_pending = false; + [[clang::noinline]] _MovableLockUnlock(lock); #endif } diff --git a/Sources/OpenSwiftUI_SPI/Util/MovableLock.h b/Sources/OpenSwiftUI_SPI/Util/MovableLock.h index 08f95df20..22059b316 100644 --- a/Sources/OpenSwiftUI_SPI/Util/MovableLock.h +++ b/Sources/OpenSwiftUI_SPI/Util/MovableLock.h @@ -2,7 +2,7 @@ // MovableLock.h // OpenSwiftUI // -// Audited for 3.5.2 +// Audited for 6.5.4 // Status: Complete #ifndef MovableLock_h @@ -15,34 +15,37 @@ OPENSWIFTUI_ASSUME_NONNULL_BEGIN typedef struct MovableLock_s { pthread_mutex_t mutex; - pthread_cond_t cond1; - pthread_cond_t cond2; - pthread_cond_t cond3; - pthread_t main; - pthread_t owner; - uint32_t level; - uint32_t unknown; - void (* _Nullable function)(const void *context); - const void * _Nullable context; - bool unknown4; - bool unknown5; + pthread_cond_t lock_condition; + pthread_cond_t main_callback_condition; + pthread_cond_t broadcast_condition; + pthread_t main_thread; + pthread_t owner_thread; + uint32_t lock_level; + uint32_t waiter_count; + void (* _Nullable main_callback)(const void *main_callback_context); + const void * _Nullable main_callback_context; + bool main_callback_pending; + bool main_thread_waiting; } MovableLock_t; typedef MovableLock_t *MovableLock __attribute((swift_newtype(struct))); -OPENSWIFTUI_EXPORT -OPENSWIFTUI_REFINED_FOR_SWIFT -MovableLock _MovableLockCreate(void) OPENSWIFTUI_SWIFT_NAME(MovableLock.create()); +MovableLock _MovableLockCreate(void) OPENSWIFTUI_SWIFT_NAME(MovableLock.init()); -OPENSWIFTUI_EXPORT -OPENSWIFTUI_REFINED_FOR_SWIFT void _MovableLockDestroy(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.destroy(self:)); + bool _MovableLockIsOwner(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(getter:MovableLock.isOwner(self:)); -bool _MovableLockIsOuterMostOwner(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(getter:MovableLock.isOuterMostOwner(self:)); + +bool _MovableLockIsOutermostOwner(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(getter:MovableLock.isOutermostOwner(self:)); + void _MovableLockLock(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.lock(self:)); + void _MovableLockUnlock(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.unlock(self:)); -void _MovableLockSyncMain(MovableLock lock, const void *context, void (*function)(const void *context)) OPENSWIFTUI_SWIFT_NAME(MovableLock.syncMain(self:_:function:)); + +void _MovableLockSyncMain(MovableLock lock, const void *main_callback_context, void (*main_callback)(const void *main_callback_context)) OPENSWIFTUI_SWIFT_NAME(MovableLock.syncMain(self:_:function:)); + void _MovableLockWait(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.wait(self:)); + void _MovableLockBroadcast(MovableLock lock) OPENSWIFTUI_SWIFT_NAME(MovableLock.broadcast(self:)); OPENSWIFTUI_ASSUME_NONNULL_END diff --git a/Tests/OpenSwiftUI_SPITests/Util/MovableLockTests.swift b/Tests/OpenSwiftUI_SPITests/Util/MovableLockTests.swift index eb392e0dc..31154b336 100644 --- a/Tests/OpenSwiftUI_SPITests/Util/MovableLockTests.swift +++ b/Tests/OpenSwiftUI_SPITests/Util/MovableLockTests.swift @@ -10,7 +10,7 @@ final class MovableLockTests { let lock: MovableLock init() { - lock = MovableLock.create() + lock = MovableLock() } deinit { @@ -20,13 +20,13 @@ final class MovableLockTests { @Test func owner() { #expect(lock.isOwner == false) - #expect(lock.isOuterMostOwner == false) + #expect(lock.isOutermostOwner == false) lock.lock() #expect(lock.isOwner == true) - #expect(lock.isOuterMostOwner == true) + #expect(lock.isOutermostOwner == true) lock.unlock() #expect(lock.isOwner == false) - #expect(lock.isOuterMostOwner == false) + #expect(lock.isOutermostOwner == false) } } #endif