Skip to content

Commit 49df44f

Browse files
committed
[cxx-interop][Runtime] Initialize metadata of a Swift array of C++ references correctly
This fixes a crash at runtime when destroying a Swift array of values of a C++ foreign reference type. Swift optimizes the amount of metadata emitted for `_ContiguousArrayStorage<Element>` by reusing `_ContiguousArrayStorage<AnyObject>` whenever possible (see `getContiguousArrayStorageType`). However, C++ foreign reference types are not `AnyObject`s, since they have custom retain/release operations. This change disables the `_ContiguousArrayStorage` metadata optimization for C++ reference types, which makes sure that `swift_arrayDestroy` will call the correct release operation for elements of `[MyCxxRefType]`. rdar://127154770 (cherry picked from commit fd04cc3)
1 parent 19da726 commit 49df44f

File tree

6 files changed

+40
-4
lines changed

6 files changed

+40
-4
lines changed

include/swift/ABI/Metadata.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,6 @@ struct TargetMetadata {
297297
case MetadataKind::Class:
298298
case MetadataKind::ObjCClassWrapper:
299299
case MetadataKind::ForeignClass:
300-
case MetadataKind::ForeignReferenceType:
301300
return true;
302301

303302
default:

lib/SILOptimizer/SILCombiner/SILCombinerApplyVisitors.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,7 +1430,8 @@ SILCombiner::propagateConcreteTypeOfInitExistential(FullApplySite Apply) {
14301430
/// getContiguousArrayStorageType<Int>(for:)
14311431
/// => metatype @thick ContiguousArrayStorage<Int>.Type
14321432
/// We know that `getContiguousArrayStorageType` will not return the AnyObject
1433-
/// type optimization for any non class or objc existential type instantiation.
1433+
/// type optimization for any non class or objc existential type instantiation
1434+
/// or a C++ foreign reference type.
14341435
static bool shouldReplaceCallByMetadataConstructor(CanType storageMetaTy) {
14351436
auto metaTy = dyn_cast<MetatypeType>(storageMetaTy);
14361437
if (!metaTy || metaTy->getRepresentation() != MetatypeRepresentation::Thick)
@@ -1451,7 +1452,7 @@ static bool shouldReplaceCallByMetadataConstructor(CanType storageMetaTy) {
14511452
if (ty->getStructOrBoundGenericStruct() || ty->getEnumOrBoundGenericEnum() ||
14521453
isa<BuiltinVectorType>(ty) || isa<BuiltinIntegerType>(ty) ||
14531454
isa<BuiltinFloatType>(ty) || isa<TupleType>(ty) ||
1454-
isa<AnyFunctionType>(ty) ||
1455+
isa<AnyFunctionType>(ty) || ty->isForeignReferenceType() ||
14551456
(ty->isAnyExistentialType() && !ty->isObjCExistentialType()))
14561457
return true;
14571458

lib/SILOptimizer/SILCombiner/SILCombinerMiscVisitors.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,10 @@ shouldReplaceCallByContiguousArrayStorageAnyObject(SILFunction &F,
17461746
auto ty = genericArgs[0]->getCanonicalType();
17471747
if (!ty->getClassOrBoundGenericClass() && !ty->isObjCExistentialType())
17481748
return std::nullopt;
1749+
// C++ foreign reference types have custom release/retain operations and are
1750+
// not AnyObjects.
1751+
if (ty->isForeignReferenceType())
1752+
return std::nullopt;
17491753

17501754
auto anyObjectTy = ctxt.getAnyObjectType();
17511755
auto arrayStorageTy =

test/Interop/Cxx/foreign-reference/not-any-object.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ module Test {
1515

1616
inline void* operator new(unsigned long, void* p) { return p; }
1717

18-
struct __attribute__((swift_attr("import_reference"))) Empty {
18+
struct __attribute__((swift_attr("import_reference")))
19+
__attribute__((swift_attr("retain:immortal")))
20+
__attribute__((swift_attr("release:immortal"))) Empty {
1921
static Empty *create() { return new (malloc(sizeof(Empty))) Empty(); }
2022
};
2123

@@ -27,3 +29,4 @@ public func test(_ _: AnyObject) {}
2729

2830
// TODO: make this a better error.
2931
test(Empty.create()) // expected-error {{type of expression is ambiguous without a type annotation}}
32+
test([Empty.create()][0]) // expected-error {{argument type 'Any' expected to be an instance of a class or class-constrained type}}

test/Interop/Cxx/foreign-reference/reference-counted-irgen.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %target-swift-emit-irgen %s -I %S/Inputs -cxx-interoperability-mode=default -Xcc -fignore-exceptions -disable-availability-checking | %FileCheck %s
22
// XFAIL: OS=linux-android, OS=linux-androideabi
3+
// XFAIL: OS=windows-msvc
34

45
import ReferenceCounted
56

@@ -51,3 +52,17 @@ public func getNullable(wantNullptr: Bool) -> GlobalCountNullableInit? {
5152
// CHECK: lifetime.cont:
5253
// CHECK: ret i64 %2
5354
// CHECK-NEXT: }
55+
56+
57+
public func getArrayOfLocalCount() -> [NS.LocalCount] {
58+
return [NS.LocalCount.create()]
59+
}
60+
61+
// CHECK: define {{.*}}swiftcc ptr @"$s4main20getArrayOfLocalCountSaySo2NSO0eF0VGyF"()
62+
// CHECK-NEXT: entry:
63+
// CHECK-NEXT: %0 = call swiftcc %swift.metadata_response @"$sSo2NSO10LocalCountVMa"(i64 0)
64+
// CHECK-NEXT: %1 = extractvalue %swift.metadata_response %0, 0
65+
// CHECK-NEXT: %2 = call swiftcc { ptr, ptr } @"$ss27_allocateUninitializedArrayySayxG_BptBwlF"(i64 1, ptr %1)
66+
// CHECK: %5 = call ptr @{{_ZN2NS10LocalCount6createEv|"\?create\@LocalCount\@NS\@\@SAPEAU12\@XZ"}}()
67+
// CHECK-NEXT: call void @{{_Z8LCRetainPN2NS10LocalCountE|"\?LCRetain\@\@YAXPEAULocalCount\@NS\@\@\@Z"}}(ptr %5)
68+
// CHECK: }

test/Interop/Cxx/foreign-reference/reference-counted.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,18 @@ ReferenceCountedTestSuite.test("Global") {
6767
expectEqual(globalCount, 0)
6868
}
6969

70+
var globalArray: [GlobalCount] = []
71+
72+
ReferenceCountedTestSuite.test("Global array") {
73+
expectEqual(globalCount, 0)
74+
75+
globalArray = [GlobalCount.create()]
76+
#if NO_OPTIMIZATIONS
77+
expectEqual(globalCount, 1)
78+
#endif
79+
80+
globalArray = []
81+
expectEqual(globalCount, 0)
82+
}
83+
7084
runAllTests()

0 commit comments

Comments
 (0)