Skip to content

Commit ad14730

Browse files
authored
Merge pull request swiftlang#38309 from al45tair/problem/47902425
[Runtime] Add ObjC support to isKnownUniquelyReferenced.
2 parents a8bb9ff + abec55f commit ad14730

File tree

10 files changed

+134
-11
lines changed

10 files changed

+134
-11
lines changed

include/swift/AST/ASTContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,10 @@ class ASTContext final {
759759
/// tag single payloads.
760760
AvailabilityContext getMultiPayloadEnumTagSinglePayload();
761761

762+
/// Get the runtime availability of the Objective-C enabled
763+
/// swift_isUniquelyReferenced functions.
764+
AvailabilityContext getObjCIsUniquelyReferencedAvailability();
765+
762766
/// Get the runtime availability of features introduced in the Swift 5.2
763767
/// compiler for the target platform.
764768
AvailabilityContext getSwift52Availability();

include/swift/Runtime/HeapObject.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ size_t swift_unownedRetainCount(HeapObject *object);
211211
SWIFT_RUNTIME_EXPORT
212212
size_t swift_weakRetainCount(HeapObject *object);
213213

214+
/// Is this pointer a non-null unique reference to an object?
215+
SWIFT_RUNTIME_EXPORT
216+
bool swift_isUniquelyReferenced(const void *);
217+
218+
/// Is this non-null pointer a unique reference to an object?
219+
SWIFT_RUNTIME_EXPORT
220+
bool swift_isUniquelyReferenced_nonNull(const void *);
221+
222+
/// Is this non-null BridgeObject a unique reference to an object?
223+
SWIFT_RUNTIME_EXPORT
224+
bool swift_isUniquelyReferenced_nonNull_bridgeObject(uintptr_t bits);
225+
214226
/// Is this pointer a non-null unique reference to an object
215227
/// that uses Swift reference counting?
216228
SWIFT_RUNTIME_EXPORT

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,30 @@ FUNCTION(IsUniquelyReferencedNonObjC_nonNull_bridgeObject,
473473
ARGS(BridgeObjectPtrTy),
474474
ATTRS(NoUnwind, ZExt))
475475

476+
// bool swift_isUniquelyReferenced(const void *);
477+
FUNCTION(IsUniquelyReferenced, swift_isUniquelyReferenced,
478+
C_CC, ObjCIsUniquelyReferencedAvailability,
479+
RETURNS(Int1Ty),
480+
ARGS(UnknownRefCountedPtrTy),
481+
ATTRS(NoUnwind, ZExt))
482+
483+
// bool swift_isUniquelyReferenced_nonNull(const void *);
484+
FUNCTION(IsUniquelyReferenced_nonNull,
485+
swift_isUniquelyReferenced_nonNull,
486+
C_CC, ObjCIsUniquelyReferencedAvailability,
487+
RETURNS(Int1Ty),
488+
ARGS(UnknownRefCountedPtrTy),
489+
ATTRS(NoUnwind, ZExt))
490+
491+
// bool swift_isUniquelyReferenced_nonNull_bridgeObject(
492+
// uintptr_t bits);
493+
FUNCTION(IsUniquelyReferenced_nonNull_bridgeObject,
494+
swift_isUniquelyReferenced_nonNull_bridgeObject,
495+
C_CC, ObjCIsUniquelyReferencedAvailability,
496+
RETURNS(Int1Ty),
497+
ARGS(BridgeObjectPtrTy),
498+
ATTRS(NoUnwind, ZExt))
499+
476500
// bool swift_isUniquelyReferenced_native(const struct HeapObject *);
477501
FUNCTION(IsUniquelyReferenced_native, swift_isUniquelyReferenced_native,
478502
C_CC, AlwaysAvailable,

lib/AST/Availability.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,10 @@ AvailabilityContext ASTContext::getMultiPayloadEnumTagSinglePayload() {
338338
return getSwift56Availability();
339339
}
340340

341+
AvailabilityContext ASTContext::getObjCIsUniquelyReferencedAvailability() {
342+
return getSwift56Availability();
343+
}
344+
341345
AvailabilityContext ASTContext::getSwift52Availability() {
342346
auto target = LangOpts.Target;
343347

lib/IRGen/GenHeap.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,21 +1343,34 @@ llvm::Value *IRGenFunction::emitLoadRefcountedPtr(Address addr,
13431343
llvm::Value *IRGenFunction::
13441344
emitIsUniqueCall(llvm::Value *value, SourceLoc loc, bool isNonNull) {
13451345
llvm::Constant *fn;
1346+
bool nonObjC = !IGM.getAvailabilityContext().isContainedIn(
1347+
IGM.Context.getObjCIsUniquelyReferencedAvailability());
1348+
13461349
if (value->getType() == IGM.RefCountedPtrTy) {
13471350
if (isNonNull)
13481351
fn = IGM.getIsUniquelyReferenced_nonNull_nativeFn();
13491352
else
13501353
fn = IGM.getIsUniquelyReferenced_nativeFn();
13511354
} else if (value->getType() == IGM.UnknownRefCountedPtrTy) {
1352-
if (isNonNull)
1353-
fn = IGM.getIsUniquelyReferencedNonObjC_nonNullFn();
1354-
else
1355-
fn = IGM.getIsUniquelyReferencedNonObjCFn();
1355+
if (nonObjC) {
1356+
if (isNonNull)
1357+
fn = IGM.getIsUniquelyReferencedNonObjC_nonNullFn();
1358+
else
1359+
fn = IGM.getIsUniquelyReferencedNonObjCFn();
1360+
} else {
1361+
if (isNonNull)
1362+
fn = IGM.getIsUniquelyReferenced_nonNullFn();
1363+
else
1364+
fn = IGM.getIsUniquelyReferencedFn();
1365+
}
13561366
} else if (value->getType() == IGM.BridgeObjectPtrTy) {
13571367
if (!isNonNull)
13581368
unimplemented(loc, "optional bridge ref");
13591369

1360-
fn = IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFn();
1370+
if (nonObjC)
1371+
fn = IGM.getIsUniquelyReferencedNonObjC_nonNull_bridgeObjectFn();
1372+
else
1373+
fn = IGM.getIsUniquelyReferenced_nonNull_bridgeObjectFn();
13611374
} else {
13621375
llvm_unreachable("Unexpected LLVM type for a refcounted pointer.");
13631376
}

lib/IRGen/IRGenModule.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,17 @@ namespace RuntimeConstants {
802802
}
803803
return RuntimeAvailability::AlwaysAvailable;
804804
}
805+
806+
RuntimeAvailability
807+
ObjCIsUniquelyReferencedAvailability(ASTContext &context) {
808+
auto featureAvailability =
809+
context.getObjCIsUniquelyReferencedAvailability();
810+
if (!isDeploymentAvailabilityContainedIn(context, featureAvailability)) {
811+
return RuntimeAvailability::ConditionallyAvailable;
812+
}
813+
return RuntimeAvailability::AlwaysAvailable;
814+
}
815+
805816
} // namespace RuntimeConstants
806817

807818
// We don't use enough attributes to justify generalizing the

stdlib/public/core/ArrayBuffer.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ extension _ArrayBuffer {
108108
if !_isClassOrObjCExistential(Element.self) {
109109
return _storage.isUniquelyReferencedUnflaggedNative()
110110
}
111-
return _storage.isUniquelyReferencedNative() && _isNative
111+
return _storage.isUniquelyReferencedNative()
112112
}
113113

114114
/// Returns `true` and puts the buffer in a mutable state iff the buffer's

stdlib/public/core/BridgeStorage.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ internal struct _BridgeStorage<NativeClass: AnyObject> {
7272
@inlinable
7373
@inline(__always)
7474
internal mutating func isUniquelyReferencedNative() -> Bool {
75-
return _isUnique(&rawValue)
75+
return isNative && _isUnique(&rawValue)
7676
}
7777

7878
@_alwaysEmitIntoClient

stdlib/public/runtime/SwiftObject.mm

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ OBJC_EXPORT __attribute__((__weak_import__))
7676
}
7777

7878
#if SWIFT_OBJC_INTEROP
79-
8079
/// Replacement for ObjC object_isClass(), which is unavailable on
8180
/// deployment targets macOS 10.9 and iOS 7.
8281
static bool objcObjectIsClass(id object) {
@@ -1352,6 +1351,36 @@ static bool usesNativeSwiftReferenceCounting_nonNull(
13521351
swift_isUniquelyReferenced_nonNull_native((const HeapObject*)object);
13531352
}
13541353

1354+
#if SWIFT_OBJC_INTEROP
1355+
// It would be nice to weak link instead of doing this, but we can't do that
1356+
// until the new API is in the versions of libobjc that we're linking against.
1357+
static bool isUniquelyReferenced(id object) {
1358+
#if OBJC_ISUNIQUELYREFERENCED_DEFINED
1359+
return objc_isUniquelyReferenced(object);
1360+
#else
1361+
auto objcIsUniquelyRefd = SWIFT_LAZY_CONSTANT(reinterpret_cast<bool (*)(id)>(
1362+
dlsym(RTLD_NEXT, "objc_isUniquelyReferenced")));
1363+
1364+
return objcIsUniquelyRefd && objcIsUniquelyRefd(object);
1365+
#endif /* OBJC_ISUNIQUELYREFERENCED_DEFINED */
1366+
}
1367+
#endif
1368+
1369+
bool swift::swift_isUniquelyReferenced_nonNull(const void *object) {
1370+
assert(object != nullptr);
1371+
1372+
#if SWIFT_OBJC_INTEROP
1373+
if (isObjCTaggedPointer(object))
1374+
return false;
1375+
1376+
if (!usesNativeSwiftReferenceCounting_nonNull(object)) {
1377+
return isUniquelyReferenced(id_const_cast(object));
1378+
}
1379+
#endif
1380+
return swift_isUniquelyReferenced_nonNull_native(
1381+
static_cast<const HeapObject *>(object));
1382+
}
1383+
13551384
// Given an object reference, return true iff it is non-nil and refers
13561385
// to a native swift object with strong reference count of 1.
13571386
bool swift::swift_isUniquelyReferencedNonObjC(
@@ -1361,6 +1390,12 @@ static bool usesNativeSwiftReferenceCounting_nonNull(
13611390
&& swift_isUniquelyReferencedNonObjC_nonNull(object);
13621391
}
13631392

1393+
// Given an object reference, return true if it is non-nil and refers
1394+
// to an ObjC or native swift object with a strong reference count of 1.
1395+
bool swift::swift_isUniquelyReferenced(const void *object) {
1396+
return object != nullptr && swift_isUniquelyReferenced_nonNull(object);
1397+
}
1398+
13641399
/// Return true if the given bits of a Builtin.BridgeObject refer to a
13651400
/// native swift object whose strong reference count is 1.
13661401
bool swift::swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(
@@ -1386,6 +1421,26 @@ static bool usesNativeSwiftReferenceCounting_nonNull(
13861421
#endif
13871422
}
13881423

1424+
/// Return true if the given bits of a Builtin.BridgeObject refer to
1425+
/// an object whose strong reference count is 1.
1426+
bool swift::swift_isUniquelyReferenced_nonNull_bridgeObject(uintptr_t bits) {
1427+
auto bridgeObject = reinterpret_cast<void *>(bits);
1428+
1429+
if (isObjCTaggedPointer(bridgeObject))
1430+
return false;
1431+
1432+
const auto object = toPlainObject_unTagged_bridgeObject(bridgeObject);
1433+
1434+
#if SWIFT_OBJC_INTEROP
1435+
return !isNonNative_unTagged_bridgeObject(bridgeObject)
1436+
? swift_isUniquelyReferenced_nonNull_native(
1437+
(const HeapObject *)object)
1438+
: swift_isUniquelyReferenced_nonNull(object);
1439+
#else
1440+
return swift_isUniquelyReferenced_nonNull_native((const HeapObject *)object);
1441+
#endif
1442+
}
1443+
13891444
// Given a non-@objc object reference, return true iff the
13901445
// object is non-nil and has a strong reference count greather than 1
13911446
bool swift::swift_isEscapingClosureAtFileLocation(const HeapObject *object,

test/IRGen/builtins.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -662,7 +662,7 @@ func acceptsAnyObject(_ ref: inout Builtin.AnyObject?) {}
662662
// CHECK-NEXT: [[ADDR:%.+]] = getelementptr inbounds [[OPTIONAL_ANYOBJECT_TY]], [[OPTIONAL_ANYOBJECT_TY]]* %0, i32 0, i32 0
663663
// CHECK-NEXT: [[CASTED:%.+]] = bitcast {{.+}}* [[ADDR]] to [[UNKNOWN_OBJECT:%objc_object|%swift\.refcounted]]**
664664
// CHECK-NEXT: [[REF:%.+]] = load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** [[CASTED]]
665-
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferencedNonObjC([[UNKNOWN_OBJECT]]* [[REF]])
665+
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced{{(NonObjC)?}}([[UNKNOWN_OBJECT]]* [[REF]])
666666
// CHECK-native-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced_native([[UNKNOWN_OBJECT]]* [[REF]])
667667
// CHECK-NEXT: ret i1 [[RESULT]]
668668
func isUnique(_ ref: inout Builtin.AnyObject?) -> Bool {
@@ -675,7 +675,7 @@ func isUnique(_ ref: inout Builtin.AnyObject?) -> Bool {
675675
// CHECK-NEXT: entry:
676676
// CHECK-NEXT: [[ADDR:%.+]] = getelementptr inbounds %AnyObject, %AnyObject* %0, i32 0, i32 0
677677
// CHECK-NEXT: [[REF:%.+]] = load [[UNKNOWN_OBJECT]]*, [[UNKNOWN_OBJECT]]** [[ADDR]]
678-
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferencedNonObjC_nonNull([[UNKNOWN_OBJECT]]* [[REF]])
678+
// CHECK-objc-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced{{(NonObjC)?}}_nonNull([[UNKNOWN_OBJECT]]* [[REF]])
679679
// CHECK-native-NEXT: [[RESULT:%.+]] = call i1 @swift_isUniquelyReferenced_nonNull_native([[UNKNOWN_OBJECT]]* [[REF]])
680680
// CHECK-NEXT: ret i1 [[RESULT]]
681681
func isUnique(_ ref: inout Builtin.AnyObject) -> Bool {
@@ -686,7 +686,7 @@ func isUnique(_ ref: inout Builtin.AnyObject) -> Bool {
686686
// CHECK-LABEL: define hidden {{.*}}i1 @"$s8builtins8isUniqueyBi1_BbzF"(%swift.bridge** nocapture dereferenceable({{.*}}) %0) {{.*}} {
687687
// CHECK-NEXT: entry:
688688
// CHECK-NEXT: load %swift.bridge*, %swift.bridge** %0
689-
// CHECK-NEXT: call i1 @swift_isUniquelyReferencedNonObjC_nonNull_bridgeObject(%swift.bridge* %1)
689+
// CHECK-NEXT: call i1 @swift_isUniquelyReferenced{{(NonObjC)?}}_nonNull_bridgeObject(%swift.bridge* %1)
690690
// CHECK-NEXT: ret i1 %2
691691
func isUnique(_ ref: inout Builtin.BridgeObject) -> Bool {
692692
return Builtin.isUnique(&ref)

0 commit comments

Comments
 (0)