From 24367fa5d91ab90641adaef48759c9fd8e4059bb Mon Sep 17 00:00:00 2001 From: Joe Groff Date: Thu, 23 Feb 2017 17:32:53 -0800 Subject: [PATCH] Runtime: Have native refcounting entry points ignore negative pointer values on x86-64 and arm64. The high half of the address space is used by the kernel in these architectures, and it would be useful for us to be able to pack small values into places the ABI otherwise requires a refcountable pointer, such as closures and maybe refcounted existentials. --- lib/IRGen/SwiftTargetInfo.cpp | 8 +++++ lib/IRGen/SwiftTargetInfo.h | 4 +++ stdlib/public/runtime/HeapObject.cpp | 54 +++++++++++++++++----------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/lib/IRGen/SwiftTargetInfo.cpp b/lib/IRGen/SwiftTargetInfo.cpp index 47ecc2288cd21..ea5464ecf4e9c 100644 --- a/lib/IRGen/SwiftTargetInfo.cpp +++ b/lib/IRGen/SwiftTargetInfo.cpp @@ -54,6 +54,10 @@ static void configureARM64(IRGenModule &IGM, const llvm::Triple &triple, // arm64 requires ISA-masking. target.ObjCUseISAMask = true; + + // arm64 tops out at 56 effective bits of address space and reserves the high + // half for the kernel. + target.SwiftRetainIgnoresNegativeValues = true; } /// Configures target-specific information for x86-64 platforms. @@ -75,6 +79,10 @@ static void configureX86_64(IRGenModule &IGM, const llvm::Triple &triple, // x86-64 requires ISA-masking. target.ObjCUseISAMask = true; + + // x86-64 only has 48 effective bits of address space and reserves the high + // half for the kernel. + target.SwiftRetainIgnoresNegativeValues = true; } /// Configures target-specific information for 32-bit x86 platforms. diff --git a/lib/IRGen/SwiftTargetInfo.h b/lib/IRGen/SwiftTargetInfo.h index 755047371822a..f9de7ef4c904c 100644 --- a/lib/IRGen/SwiftTargetInfo.h +++ b/lib/IRGen/SwiftTargetInfo.h @@ -95,6 +95,10 @@ class SwiftTargetInfo { /// The value stored in a Builtin.once predicate to indicate that an /// initialization has already happened, if known. Optional OnceDonePredicateValue = None; + + /// True if `swift_retain` and `swift_release` are no-ops when passed + /// "negative" pointer values. + bool SwiftRetainIgnoresNegativeValues = false; }; } diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 402c9d4a1f6c9..3797b6c74c3b4 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -43,6 +43,18 @@ using namespace swift; +/// Returns true if the pointer passed to a native retain or release is valid. +/// If false, the operation should immediately return. +static inline bool isValidPointerForNativeRetain(const void *p) { +#if defined(__x86_64__) || defined(__arm64__) + // On these platforms, the upper half of address space is reserved for the + // kernel, so we can assume that pointer values in this range are invalid. + return (intptr_t)p > 0; +#else + return p != nullptr; +#endif +} + HeapObject *swift::swift_allocObject(HeapMetadata const *metadata, size_t requiredSize, size_t requiredAlignmentMask) @@ -185,7 +197,7 @@ OpaqueValue *swift::swift_projectBox(HeapObject *o) { // for boxes of empty type. The address of an empty value is always undefined, // so we can just return nil back in this case. if (!o) - return reinterpret_cast(o); + return nullptr; auto metadata = static_cast(o->metadata); return metadata->project(o); } @@ -206,7 +218,7 @@ void swift::swift_nonatomic_retain(HeapObject *object) { SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_retain)(HeapObject *object) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.incrementNonAtomic(1); } @@ -217,7 +229,7 @@ void swift::swift_nonatomic_release(HeapObject *object) { SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_release)(HeapObject *object) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.decrementAndMaybeDeinitNonAtomic(1); } @@ -225,7 +237,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_retain)(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.increment(1); } @@ -238,7 +250,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_retain_n)(HeapObject *object, uint32_t n) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.increment(n); } @@ -251,7 +263,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_retain_n)(HeapObject *object, uint32_t n) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.incrementNonAtomic(n); } @@ -264,7 +276,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_release)(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.decrementAndMaybeDeinit(1); } @@ -277,7 +289,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_release_n)(HeapObject *object, uint32_t n) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.decrementAndMaybeDeinit(n); } @@ -294,7 +306,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" void SWIFT_RT_ENTRY_IMPL(swift_nonatomic_release_n)(HeapObject *object, uint32_t n) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.decrementAndMaybeDeinitNonAtomic(n); } @@ -308,7 +320,7 @@ size_t swift::swift_unownedRetainCount(HeapObject *object) { void swift::swift_unownedRetain(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return; object->refCounts.incrementUnowned(1); @@ -316,7 +328,7 @@ void swift::swift_unownedRetain(HeapObject *object) void swift::swift_unownedRelease(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return; // Only class objects can be unowned-retained and unowned-released. @@ -334,7 +346,7 @@ void swift::swift_unownedRelease(HeapObject *object) void swift::swift_unownedRetain_n(HeapObject *object, int n) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return; object->refCounts.incrementUnowned(n); @@ -342,7 +354,7 @@ void swift::swift_unownedRetain_n(HeapObject *object, int n) void swift::swift_unownedRelease_n(HeapObject *object, int n) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return; // Only class objects can be unowned-retained and unowned-released. @@ -359,7 +371,7 @@ void swift::swift_unownedRelease_n(HeapObject *object, int n) HeapObject *swift::swift_tryPin(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - assert(object); + assert(isValidPointerForNativeRetain(object)); // Try to set the flag. If this succeeds, the caller will be // responsible for clearing it. @@ -373,7 +385,7 @@ HeapObject *swift::swift_tryPin(HeapObject *object) void swift::swift_unpin(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.decrementAndUnpinAndMaybeDeinit(); } @@ -398,7 +410,7 @@ HeapObject *swift::swift_nonatomic_tryPin(HeapObject *object) void swift::swift_nonatomic_unpin(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (object) + if (isValidPointerForNativeRetain(object)) object->refCounts.decrementAndUnpinAndMaybeDeinitNonAtomic(); } @@ -406,7 +418,7 @@ SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" HeapObject *SWIFT_RT_ENTRY_IMPL(swift_tryRetain)(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return nullptr; if (object->refCounts.tryIncrement()) return object; @@ -421,14 +433,14 @@ bool swift_isDeallocating(HeapObject *object) { SWIFT_RT_ENTRY_IMPL_VISIBILITY extern "C" bool SWIFT_RT_ENTRY_IMPL(swift_isDeallocating)(HeapObject *object) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return false; return object->refCounts.isDeiniting(); } void swift::swift_unownedRetainStrong(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return; assert(object->refCounts.getUnownedCount() && "object is not currently unowned-retained"); @@ -439,7 +451,7 @@ void swift::swift_unownedRetainStrong(HeapObject *object) void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) SWIFT_CC(RegisterPreservingCC_IMPL) { - if (!object) + if (!isValidPointerForNativeRetain(object)) return; assert(object->refCounts.getUnownedCount() && "object is not currently unowned-retained"); @@ -454,7 +466,7 @@ void swift::swift_unownedRetainStrongAndRelease(HeapObject *object) } void swift::swift_unownedCheck(HeapObject *object) { - if (!object) return; + if (!isValidPointerForNativeRetain(object)) return; assert(object->refCounts.getUnownedCount() && "object is not currently unowned-retained");