mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[Runtime] Add ObjC support to isKnownUniquelyReferenced.
Add code to support detecting uniquely referenced Objective-C and Core Foundation objects. rdar://47902425 rdar://66805490
This commit is contained in:
@@ -748,6 +748,10 @@ public:
|
||||
/// tag single payloads.
|
||||
AvailabilityContext getMultiPayloadEnumTagSinglePayload();
|
||||
|
||||
/// Get the runtime availability of the Objective-C enabled
|
||||
/// swift_isUniquelyReferenced functions.
|
||||
AvailabilityContext getObjCIsUniquelyReferencedAvailability();
|
||||
|
||||
/// Get the runtime availability of features introduced in the Swift 5.2
|
||||
/// compiler for the target platform.
|
||||
AvailabilityContext getSwift52Availability();
|
||||
|
||||
@@ -211,6 +211,18 @@ size_t swift_unownedRetainCount(HeapObject *object);
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
size_t swift_weakRetainCount(HeapObject *object);
|
||||
|
||||
/// Is this pointer a non-null unique reference to an object?
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
bool swift_isUniquelyReferenced(const void *);
|
||||
|
||||
/// Is this non-null pointer a unique reference to an object?
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
bool swift_isUniquelyReferenced_nonNull(const void *);
|
||||
|
||||
/// Is this non-null BridgeObject a unique reference to an object?
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
bool swift_isUniquelyReferenced_nonNull_bridgeObject(uintptr_t bits);
|
||||
|
||||
/// Is this pointer a non-null unique reference to an object
|
||||
/// that uses Swift reference counting?
|
||||
SWIFT_RUNTIME_EXPORT
|
||||
|
||||
@@ -473,6 +473,30 @@ FUNCTION(IsUniquelyReferencedNonObjC_nonNull_bridgeObject,
|
||||
ARGS(BridgeObjectPtrTy),
|
||||
ATTRS(NoUnwind, ZExt))
|
||||
|
||||
// bool swift_isUniquelyReferenced(const void *);
|
||||
FUNCTION(IsUniquelyReferenced, swift_isUniquelyReferenced,
|
||||
C_CC, ObjCIsUniquelyReferencedAvailability,
|
||||
RETURNS(Int1Ty),
|
||||
ARGS(UnknownRefCountedPtrTy),
|
||||
ATTRS(NoUnwind, ZExt))
|
||||
|
||||
// bool swift_isUniquelyReferenced_nonNull(const void *);
|
||||
FUNCTION(IsUniquelyReferenced_nonNull,
|
||||
swift_isUniquelyReferenced_nonNull,
|
||||
C_CC, ObjCIsUniquelyReferencedAvailability,
|
||||
RETURNS(Int1Ty),
|
||||
ARGS(UnknownRefCountedPtrTy),
|
||||
ATTRS(NoUnwind, ZExt))
|
||||
|
||||
// bool swift_isUniquelyReferenced_nonNull_bridgeObject(
|
||||
// uintptr_t bits);
|
||||
FUNCTION(IsUniquelyReferenced_nonNull_bridgeObject,
|
||||
swift_isUniquelyReferenced_nonNull_bridgeObject,
|
||||
C_CC, ObjCIsUniquelyReferencedAvailability,
|
||||
RETURNS(Int1Ty),
|
||||
ARGS(BridgeObjectPtrTy),
|
||||
ATTRS(NoUnwind, ZExt))
|
||||
|
||||
// bool swift_isUniquelyReferenced_native(const struct HeapObject *);
|
||||
FUNCTION(IsUniquelyReferenced_native, swift_isUniquelyReferenced_native,
|
||||
C_CC, AlwaysAvailable,
|
||||
|
||||
@@ -338,6 +338,10 @@ AvailabilityContext ASTContext::getMultiPayloadEnumTagSinglePayload() {
|
||||
return getSwift56Availability();
|
||||
}
|
||||
|
||||
AvailabilityContext ASTContext::getObjCIsUniquelyReferencedAvailability() {
|
||||
return getSwift56Availability();
|
||||
}
|
||||
|
||||
AvailabilityContext ASTContext::getSwift52Availability() {
|
||||
auto target = LangOpts.Target;
|
||||
|
||||
|
||||
@@ -1343,21 +1343,34 @@ llvm::Value *IRGenFunction::emitLoadRefcountedPtr(Address addr,
|
||||
llvm::Value *IRGenFunction::
|
||||
emitIsUniqueCall(llvm::Value *value, SourceLoc loc, bool isNonNull) {
|
||||
llvm::Constant *fn;
|
||||
bool nonObjC = !IGM.getAvailabilityContext().isContainedIn(
|
||||
IGM.Context.getObjCIsUniquelyReferencedAvailability());
|
||||
|
||||
if (value->getType() == IGM.RefCountedPtrTy) {
|
||||
if (isNonNull)
|
||||
fn = IGM.getIsUniquelyReferenced_nonNull_nativeFn();
|
||||
else
|
||||
fn = IGM.getIsUniquelyReferenced_nativeFn();
|
||||
} else if (value->getType() == IGM.UnknownRefCountedPtrTy) {
|
||||
if (isNonNull)
|
||||
fn = IGM.getIsUniquelyReferencedNonObjC_nonNullFn();
|
||||
else
|
||||
fn = IGM.getIsUniquelyReferencedNonObjCFn();
|
||||
if (nonObjC) {
|
||||
if (isNonNull)
|
||||
fn = IGM.getIsUniquelyReferencedNonObjC_nonNullFn();
|
||||
else
|
||||
fn = IGM.getIsUniquelyReferencedNonObjCFn();
|
||||
} else {
|
||||
if (isNonNull)
|
||||
fn = IGM.getIsUniquelyReferenced_nonNullFn();
|
||||
else
|
||||
fn = IGM.getIsUniquelyReferencedFn();
|
||||
}
|
||||
} else if (value->getType() == IGM.BridgeObjectPtrTy) {
|
||||
if (!isNonNull)
|
||||
unimplemented(loc, "optional bridge ref");
|
||||
|
||||
fn = IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFn();
|
||||
if (nonObjC)
|
||||
fn = IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFn();
|
||||
else
|
||||
fn = IGM.getIsUniquelyReferenced_nonNull_bridgeObjectFn();
|
||||
} else {
|
||||
llvm_unreachable("Unexpected LLVM type for a refcounted pointer.");
|
||||
}
|
||||
|
||||
@@ -802,6 +802,17 @@ namespace RuntimeConstants {
|
||||
}
|
||||
return RuntimeAvailability::AlwaysAvailable;
|
||||
}
|
||||
|
||||
RuntimeAvailability
|
||||
ObjCIsUniquelyReferencedAvailability(ASTContext &context) {
|
||||
auto featureAvailability =
|
||||
context.getObjCIsUniquelyReferencedAvailability();
|
||||
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
|
||||
return RuntimeAvailability::ConditionallyAvailable;
|
||||
}
|
||||
return RuntimeAvailability::AlwaysAvailable;
|
||||
}
|
||||
|
||||
} // namespace RuntimeConstants
|
||||
|
||||
// We don't use enough attributes to justify generalizing the
|
||||
|
||||
@@ -108,7 +108,7 @@ extension _ArrayBuffer {
|
||||
if !_isClassOrObjCExistential(Element.self) {
|
||||
return _storage.isUniquelyReferencedUnflaggedNative()
|
||||
}
|
||||
return _storage.isUniquelyReferencedNative() && _isNative
|
||||
return _storage.isUniquelyReferencedNative()
|
||||
}
|
||||
|
||||
/// Returns `true` and puts the buffer in a mutable state iff the buffer's
|
||||
|
||||
@@ -72,7 +72,7 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
|
||||
@inlinable
|
||||
@inline(__always)
|
||||
internal mutating func isUniquelyReferencedNative() -> Bool {
|
||||
return _isUnique(&rawValue)
|
||||
return isNative && _isUnique(&rawValue)
|
||||
}
|
||||
|
||||
@_alwaysEmitIntoClient
|
||||
|
||||
@@ -76,7 +76,6 @@ const ClassMetadata *swift::_swift_getClass(const void *object) {
|
||||
}
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
|
||||
/// Replacement for ObjC object_isClass(), which is unavailable on
|
||||
/// deployment targets macOS 10.9 and iOS 7.
|
||||
static bool objcObjectIsClass(id object) {
|
||||
@@ -1352,6 +1351,36 @@ bool swift::swift_isUniquelyReferencedNonObjC_nonNull(const void* object) {
|
||||
swift_isUniquelyReferenced_nonNull_native((const HeapObject*)object);
|
||||
}
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
// It would be nice to weak link instead of doing this, but we can't do that
|
||||
// until the new API is in the versions of libobjc that we're linking against.
|
||||
static bool isUniquelyReferenced(id object) {
|
||||
#if OBJC_ISUNIQUELYREFERENCED_DEFINED
|
||||
return objc_isUniquelyReferenced(object);
|
||||
#else
|
||||
auto objcIsUniquelyRefd = SWIFT_LAZY_CONSTANT(reinterpret_cast<bool (*)(id)>(
|
||||
dlsym(RTLD_NEXT, "objc_isUniquelyReferenced")));
|
||||
|
||||
return objcIsUniquelyRefd && objcIsUniquelyRefd(object);
|
||||
#endif /* OBJC_ISUNIQUELYREFERENCED_DEFINED */
|
||||
}
|
||||
#endif
|
||||
|
||||
bool swift::swift_isUniquelyReferenced_nonNull(const void *object) {
|
||||
assert(object != nullptr);
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
if (isObjCTaggedPointer(object))
|
||||
return false;
|
||||
|
||||
if (!usesNativeSwiftReferenceCounting_nonNull(object)) {
|
||||
return isUniquelyReferenced(id_const_cast(object));
|
||||
}
|
||||
#endif
|
||||
return swift_isUniquelyReferenced_nonNull_native(
|
||||
static_cast<const HeapObject *>(object));
|
||||
}
|
||||
|
||||
// Given an object reference, return true iff it is non-nil and refers
|
||||
// to a native swift object with strong reference count of 1.
|
||||
bool swift::swift_isUniquelyReferencedNonObjC(
|
||||
@@ -1361,6 +1390,12 @@ bool swift::swift_isUniquelyReferencedNonObjC(
|
||||
&& swift_isUniquelyReferencedNonObjC_nonNull(object);
|
||||
}
|
||||
|
||||
// Given an object reference, return true if it is non-nil and refers
|
||||
// to an ObjC or native swift object with a strong reference count of 1.
|
||||
bool swift::swift_isUniquelyReferenced(const void *object) {
|
||||
return object != nullptr && swift_isUniquelyReferenced_nonNull(object);
|
||||
}
|
||||
|
||||
/// Return true if the given bits of a Builtin.BridgeObject refer to a
|
||||
/// native swift object whose strong reference count is 1.
|
||||
bool swift::swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(
|
||||
@@ -1386,6 +1421,26 @@ bool swift::swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Return true if the given bits of a Builtin.BridgeObject refer to
|
||||
/// an object whose strong reference count is 1.
|
||||
bool swift::swift_isUniquelyReferenced_nonNull_bridgeObject(uintptr_t bits) {
|
||||
auto bridgeObject = reinterpret_cast<void *>(bits);
|
||||
|
||||
if (isObjCTaggedPointer(bridgeObject))
|
||||
return false;
|
||||
|
||||
const auto object = toPlainObject_unTagged_bridgeObject(bridgeObject);
|
||||
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
return !isNonNative_unTagged_bridgeObject(bridgeObject)
|
||||
? swift_isUniquelyReferenced_nonNull_native(
|
||||
(const HeapObject *)object)
|
||||
: swift_isUniquelyReferenced_nonNull(object);
|
||||
#else
|
||||
return swift_isUniquelyReferenced_nonNull_native((const HeapObject *)object);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Given a non-@objc object reference, return true iff the
|
||||
// object is non-nil and has a strong reference count greather than 1
|
||||
bool swift::swift_isEscapingClosureAtFileLocation(const HeapObject *object,
|
||||
|
||||
@@ -662,7 +662,7 @@ func acceptsAnyObject(_ ref: inout Builtin.AnyObject?) {}
|
||||
// CHECK-NEXT: [[ADDR:%.+]] = getelementptr inbounds [[OPTIONAL_ANYOBJECT_TY]], [[OPTIONAL_ANYOBJECT_TY]]* %0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[CASTED:%.+]] = bitcast {{.+}}* [[ADDR]] to [[UNKNOWN_OBJECT:%objc_object|%swift\.refcounted]]**
|
||||
// CHECK-NEXT: [[REF:%.+]] = load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** [[CASTED]]
|
||||
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferencedNonObjC([[UNKNOWN_OBJECT]]* [[REF]])
|
||||
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced{{(NonObjC)?}}([[UNKNOWN_OBJECT]]* [[REF]])
|
||||
// CHECK-native-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced_native([[UNKNOWN_OBJECT]]* [[REF]])
|
||||
// CHECK-NEXT: ret i1 [[RESULT]]
|
||||
func isUnique(_ ref: inout Builtin.AnyObject?) -> Bool {
|
||||
@@ -675,7 +675,7 @@ func isUnique(_ ref: inout Builtin.AnyObject?) -> Bool {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: [[ADDR:%.+]] = getelementptr inbounds %AnyObject, %AnyObject* %0, i32 0, i32 0
|
||||
// CHECK-NEXT: [[REF:%.+]] = load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** [[ADDR]]
|
||||
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferencedNonObjC_nonNull([[UNKNOWN_OBJECT]]* [[REF]])
|
||||
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced{{(NonObjC)?}}_nonNull([[UNKNOWN_OBJECT]]* [[REF]])
|
||||
// CHECK-native-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced_nonNull_native([[UNKNOWN_OBJECT]]* [[REF]])
|
||||
// CHECK-NEXT: ret i1 [[RESULT]]
|
||||
func isUnique(_ ref: inout Builtin.AnyObject) -> Bool {
|
||||
@@ -686,7 +686,7 @@ func isUnique(_ ref: inout Builtin.AnyObject) -> Bool {
|
||||
// CHECK-LABEL: define hidden {{.*}}i1 @"$s8builtins8isUniqueyBi1_BbzF"(%swift.bridge** nocapture dereferenceable({{.*}}) %0) {{.*}} {
|
||||
// CHECK-NEXT: entry:
|
||||
// CHECK-NEXT: load %swift.bridge*, %swift.bridge** %0
|
||||
// CHECK-NEXT: call i1 @swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(%swift.bridge* %1)
|
||||
// CHECK-NEXT: call i1 @swift_isUniquelyReferenced{{(NonObjC)?}}_nonNull_bridgeObject(%swift.bridge* %1)
|
||||
// CHECK-NEXT: ret i1 %2
|
||||
func isUnique(_ ref: inout Builtin.BridgeObject) -> Bool {
|
||||
return Builtin.isUnique(&ref)
|
||||
|
||||
Reference in New Issue
Block a user