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.
|
/// tag single payloads.
|
||||||
AvailabilityContext getMultiPayloadEnumTagSinglePayload();
|
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
|
/// Get the runtime availability of features introduced in the Swift 5.2
|
||||||
/// compiler for the target platform.
|
/// compiler for the target platform.
|
||||||
AvailabilityContext getSwift52Availability();
|
AvailabilityContext getSwift52Availability();
|
||||||
|
|||||||
@@ -211,6 +211,18 @@ size_t swift_unownedRetainCount(HeapObject *object);
|
|||||||
SWIFT_RUNTIME_EXPORT
|
SWIFT_RUNTIME_EXPORT
|
||||||
size_t swift_weakRetainCount(HeapObject *object);
|
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
|
/// Is this pointer a non-null unique reference to an object
|
||||||
/// that uses Swift reference counting?
|
/// that uses Swift reference counting?
|
||||||
SWIFT_RUNTIME_EXPORT
|
SWIFT_RUNTIME_EXPORT
|
||||||
|
|||||||
@@ -473,6 +473,30 @@ FUNCTION(IsUniquelyReferencedNonObjC_nonNull_bridgeObject,
|
|||||||
ARGS(BridgeObjectPtrTy),
|
ARGS(BridgeObjectPtrTy),
|
||||||
ATTRS(NoUnwind, ZExt))
|
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 *);
|
// bool swift_isUniquelyReferenced_native(const struct HeapObject *);
|
||||||
FUNCTION(IsUniquelyReferenced_native, swift_isUniquelyReferenced_native,
|
FUNCTION(IsUniquelyReferenced_native, swift_isUniquelyReferenced_native,
|
||||||
C_CC, AlwaysAvailable,
|
C_CC, AlwaysAvailable,
|
||||||
|
|||||||
@@ -338,6 +338,10 @@ AvailabilityContext ASTContext::getMultiPayloadEnumTagSinglePayload() {
|
|||||||
return getSwift56Availability();
|
return getSwift56Availability();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AvailabilityContext ASTContext::getObjCIsUniquelyReferencedAvailability() {
|
||||||
|
return getSwift56Availability();
|
||||||
|
}
|
||||||
|
|
||||||
AvailabilityContext ASTContext::getSwift52Availability() {
|
AvailabilityContext ASTContext::getSwift52Availability() {
|
||||||
auto target = LangOpts.Target;
|
auto target = LangOpts.Target;
|
||||||
|
|
||||||
|
|||||||
@@ -1343,21 +1343,34 @@ llvm::Value *IRGenFunction::emitLoadRefcountedPtr(Address addr,
|
|||||||
llvm::Value *IRGenFunction::
|
llvm::Value *IRGenFunction::
|
||||||
emitIsUniqueCall(llvm::Value *value, SourceLoc loc, bool isNonNull) {
|
emitIsUniqueCall(llvm::Value *value, SourceLoc loc, bool isNonNull) {
|
||||||
llvm::Constant *fn;
|
llvm::Constant *fn;
|
||||||
|
bool nonObjC = !IGM.getAvailabilityContext().isContainedIn(
|
||||||
|
IGM.Context.getObjCIsUniquelyReferencedAvailability());
|
||||||
|
|
||||||
if (value->getType() == IGM.RefCountedPtrTy) {
|
if (value->getType() == IGM.RefCountedPtrTy) {
|
||||||
if (isNonNull)
|
if (isNonNull)
|
||||||
fn = IGM.getIsUniquelyReferenced_nonNull_nativeFn();
|
fn = IGM.getIsUniquelyReferenced_nonNull_nativeFn();
|
||||||
else
|
else
|
||||||
fn = IGM.getIsUniquelyReferenced_nativeFn();
|
fn = IGM.getIsUniquelyReferenced_nativeFn();
|
||||||
} else if (value->getType() == IGM.UnknownRefCountedPtrTy) {
|
} else if (value->getType() == IGM.UnknownRefCountedPtrTy) {
|
||||||
if (isNonNull)
|
if (nonObjC) {
|
||||||
fn = IGM.getIsUniquelyReferencedNonObjC_nonNullFn();
|
if (isNonNull)
|
||||||
else
|
fn = IGM.getIsUniquelyReferencedNonObjC_nonNullFn();
|
||||||
fn = IGM.getIsUniquelyReferencedNonObjCFn();
|
else
|
||||||
|
fn = IGM.getIsUniquelyReferencedNonObjCFn();
|
||||||
|
} else {
|
||||||
|
if (isNonNull)
|
||||||
|
fn = IGM.getIsUniquelyReferenced_nonNullFn();
|
||||||
|
else
|
||||||
|
fn = IGM.getIsUniquelyReferencedFn();
|
||||||
|
}
|
||||||
} else if (value->getType() == IGM.BridgeObjectPtrTy) {
|
} else if (value->getType() == IGM.BridgeObjectPtrTy) {
|
||||||
if (!isNonNull)
|
if (!isNonNull)
|
||||||
unimplemented(loc, "optional bridge ref");
|
unimplemented(loc, "optional bridge ref");
|
||||||
|
|
||||||
fn = IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFn();
|
if (nonObjC)
|
||||||
|
fn = IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFn();
|
||||||
|
else
|
||||||
|
fn = IGM.getIsUniquelyReferenced_nonNull_bridgeObjectFn();
|
||||||
} else {
|
} else {
|
||||||
llvm_unreachable("Unexpected LLVM type for a refcounted pointer.");
|
llvm_unreachable("Unexpected LLVM type for a refcounted pointer.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -802,6 +802,17 @@ namespace RuntimeConstants {
|
|||||||
}
|
}
|
||||||
return RuntimeAvailability::AlwaysAvailable;
|
return RuntimeAvailability::AlwaysAvailable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RuntimeAvailability
|
||||||
|
ObjCIsUniquelyReferencedAvailability(ASTContext &context) {
|
||||||
|
auto featureAvailability =
|
||||||
|
context.getObjCIsUniquelyReferencedAvailability();
|
||||||
|
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
|
||||||
|
return RuntimeAvailability::ConditionallyAvailable;
|
||||||
|
}
|
||||||
|
return RuntimeAvailability::AlwaysAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace RuntimeConstants
|
} // namespace RuntimeConstants
|
||||||
|
|
||||||
// We don't use enough attributes to justify generalizing the
|
// We don't use enough attributes to justify generalizing the
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ extension _ArrayBuffer {
|
|||||||
if !_isClassOrObjCExistential(Element.self) {
|
if !_isClassOrObjCExistential(Element.self) {
|
||||||
return _storage.isUniquelyReferencedUnflaggedNative()
|
return _storage.isUniquelyReferencedUnflaggedNative()
|
||||||
}
|
}
|
||||||
return _storage.isUniquelyReferencedNative() && _isNative
|
return _storage.isUniquelyReferencedNative()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` and puts the buffer in a mutable state iff the buffer's
|
/// Returns `true` and puts the buffer in a mutable state iff the buffer's
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
|
|||||||
@inlinable
|
@inlinable
|
||||||
@inline(__always)
|
@inline(__always)
|
||||||
internal mutating func isUniquelyReferencedNative() -> Bool {
|
internal mutating func isUniquelyReferencedNative() -> Bool {
|
||||||
return _isUnique(&rawValue)
|
return isNative && _isUnique(&rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@_alwaysEmitIntoClient
|
@_alwaysEmitIntoClient
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ const ClassMetadata *swift::_swift_getClass(const void *object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if SWIFT_OBJC_INTEROP
|
#if SWIFT_OBJC_INTEROP
|
||||||
|
|
||||||
/// Replacement for ObjC object_isClass(), which is unavailable on
|
/// Replacement for ObjC object_isClass(), which is unavailable on
|
||||||
/// deployment targets macOS 10.9 and iOS 7.
|
/// deployment targets macOS 10.9 and iOS 7.
|
||||||
static bool objcObjectIsClass(id object) {
|
static bool objcObjectIsClass(id object) {
|
||||||
@@ -1352,6 +1351,36 @@ bool swift::swift_isUniquelyReferencedNonObjC_nonNull(const void* object) {
|
|||||||
swift_isUniquelyReferenced_nonNull_native((const HeapObject*)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
|
// Given an object reference, return true iff it is non-nil and refers
|
||||||
// to a native swift object with strong reference count of 1.
|
// to a native swift object with strong reference count of 1.
|
||||||
bool swift::swift_isUniquelyReferencedNonObjC(
|
bool swift::swift_isUniquelyReferencedNonObjC(
|
||||||
@@ -1361,6 +1390,12 @@ bool swift::swift_isUniquelyReferencedNonObjC(
|
|||||||
&& swift_isUniquelyReferencedNonObjC_nonNull(object);
|
&& 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
|
/// Return true if the given bits of a Builtin.BridgeObject refer to a
|
||||||
/// native swift object whose strong reference count is 1.
|
/// native swift object whose strong reference count is 1.
|
||||||
bool swift::swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(
|
bool swift::swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(
|
||||||
@@ -1386,6 +1421,26 @@ bool swift::swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(
|
|||||||
#endif
|
#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
|
// Given a non-@objc object reference, return true iff the
|
||||||
// object is non-nil and has a strong reference count greather than 1
|
// object is non-nil and has a strong reference count greather than 1
|
||||||
bool swift::swift_isEscapingClosureAtFileLocation(const HeapObject *object,
|
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: [[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: [[CASTED:%.+]] = bitcast {{.+}}* [[ADDR]] to [[UNKNOWN_OBJECT:%objc_object|%swift\.refcounted]]**
|
||||||
// CHECK-NEXT: [[REF:%.+]] = load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** [[CASTED]]
|
// 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-native-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced_native([[UNKNOWN_OBJECT]]* [[REF]])
|
||||||
// CHECK-NEXT: ret i1 [[RESULT]]
|
// CHECK-NEXT: ret i1 [[RESULT]]
|
||||||
func isUnique(_ ref: inout Builtin.AnyObject?) -> Bool {
|
func isUnique(_ ref: inout Builtin.AnyObject?) -> Bool {
|
||||||
@@ -675,7 +675,7 @@ func isUnique(_ ref: inout Builtin.AnyObject?) -> Bool {
|
|||||||
// CHECK-NEXT: entry:
|
// CHECK-NEXT: entry:
|
||||||
// CHECK-NEXT: [[ADDR:%.+]] = getelementptr inbounds %AnyObject, %AnyObject* %0, i32 0, i32 0
|
// CHECK-NEXT: [[ADDR:%.+]] = getelementptr inbounds %AnyObject, %AnyObject* %0, i32 0, i32 0
|
||||||
// CHECK-NEXT: [[REF:%.+]] = load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** [[ADDR]]
|
// 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-native-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced_nonNull_native([[UNKNOWN_OBJECT]]* [[REF]])
|
||||||
// CHECK-NEXT: ret i1 [[RESULT]]
|
// CHECK-NEXT: ret i1 [[RESULT]]
|
||||||
func isUnique(_ ref: inout Builtin.AnyObject) -> Bool {
|
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-LABEL: define hidden {{.*}}i1 @"$s8builtins8isUniqueyBi1_BbzF"(%swift.bridge** nocapture dereferenceable({{.*}}) %0) {{.*}} {
|
||||||
// CHECK-NEXT: entry:
|
// CHECK-NEXT: entry:
|
||||||
// CHECK-NEXT: load %swift.bridge*, %swift.bridge** %0
|
// 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
|
// CHECK-NEXT: ret i1 %2
|
||||||
func isUnique(_ ref: inout Builtin.BridgeObject) -> Bool {
|
func isUnique(_ ref: inout Builtin.BridgeObject) -> Bool {
|
||||||
return Builtin.isUnique(&ref)
|
return Builtin.isUnique(&ref)
|
||||||
|
|||||||
Reference in New Issue
Block a user