Skip to content

Runtime: Have native refcounting entry points ignore negative pointer values on x86-64 and arm64. #7732

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 25, 2017
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
8 changes: 8 additions & 0 deletions lib/IRGen/SwiftTargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
4 changes: 4 additions & 0 deletions lib/IRGen/SwiftTargetInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<int64_t> OnceDonePredicateValue = None;

/// True if `swift_retain` and `swift_release` are no-ops when passed
/// "negative" pointer values.
bool SwiftRetainIgnoresNegativeValues = false;
};

}
Expand Down
54 changes: 33 additions & 21 deletions stdlib/public/runtime/HeapObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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<OpaqueValue*>(o);
return nullptr;
auto metadata = static_cast<const GenericBoxHeapMetadata *>(o->metadata);
return metadata->project(o);
}
Expand All @@ -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);
}

Expand All @@ -217,15 +229,15 @@ 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);
}

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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -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);
}

Expand All @@ -308,15 +320,15 @@ 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);
}

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.
Expand All @@ -334,15 +346,15 @@ 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);
}

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.
Expand All @@ -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.
Expand All @@ -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();
}

Expand All @@ -398,15 +410,15 @@ 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();
}

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;
Expand All @@ -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");
Expand All @@ -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");
Expand All @@ -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");

Expand Down