Skip to content

Commit 497336c

Browse files
committed
IRGen: Use the right reference counting for subclass existentials
1 parent 19eb8d2 commit 497336c

11 files changed

+247
-110
lines changed

lib/AST/Type.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3977,7 +3977,6 @@ static bool doesOpaqueClassUseNativeReferenceCounting(const ASTContext &ctx) {
39773977

39783978
static bool usesNativeReferenceCounting(ClassDecl *theClass,
39793979
ResilienceExpansion resilience) {
3980-
// NOTE: if you change this, change irgen::getReferenceCountingForClass.
39813980
// TODO: Resilience? there might be some legal avenue of changing this.
39823981
while (Type supertype = theClass->getSuperclass()) {
39833982
theClass = supertype->getClassOrBoundGenericClass();
@@ -3987,8 +3986,6 @@ static bool usesNativeReferenceCounting(ClassDecl *theClass,
39873986
}
39883987

39893988
bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
3990-
assert(allowsOwnership());
3991-
39923989
CanType type = getCanonicalType();
39933990
switch (type->getKind()) {
39943991
#define SUGARED_TYPE(id, parent) case TypeKind::id:
@@ -4011,24 +4008,34 @@ bool TypeBase::usesNativeReferenceCounting(ResilienceExpansion resilience) {
40114008
return ::usesNativeReferenceCounting(
40124009
cast<BoundGenericClassType>(type)->getDecl(),
40134010
resilience);
4011+
case TypeKind::UnboundGeneric:
4012+
return ::usesNativeReferenceCounting(
4013+
cast<ClassDecl>(cast<UnboundGenericType>(type)->getDecl()),
4014+
resilience);
40144015

40154016
case TypeKind::DynamicSelf:
40164017
return cast<DynamicSelfType>(type).getSelfType()
40174018
->usesNativeReferenceCounting(resilience);
40184019

40194020
case TypeKind::Archetype: {
40204021
auto archetype = cast<ArchetypeType>(type);
4021-
assert(archetype->requiresClass());
4022+
auto layout = archetype->getLayoutConstraint();
4023+
assert(archetype->requiresClass() ||
4024+
(layout && layout->isRefCounted()));
40224025
if (auto supertype = archetype->getSuperclass())
40234026
return supertype->usesNativeReferenceCounting(resilience);
40244027
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
40254028
}
40264029

40274030
case TypeKind::Protocol:
4028-
case TypeKind::ProtocolComposition:
4031+
case TypeKind::ProtocolComposition: {
4032+
auto layout = getExistentialLayout();
4033+
assert(layout.requiresClass && "Opaque existentials don't use refcounting");
4034+
if (layout.superclass)
4035+
return layout.superclass->usesNativeReferenceCounting(resilience);
40294036
return ::doesOpaqueClassUseNativeReferenceCounting(type->getASTContext());
4037+
}
40304038

4031-
case TypeKind::UnboundGeneric:
40324039
case TypeKind::Function:
40334040
case TypeKind::GenericFunction:
40344041
case TypeKind::SILFunction:

lib/IRGen/GenArchetype.cpp

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -277,32 +277,28 @@ llvm::Value *irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
277277
const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
278278
assert(isExemplarArchetype(archetype) && "lowering non-exemplary archetype");
279279

280-
LayoutConstraint LayoutInfo = archetype->getLayoutConstraint();
280+
auto layout = archetype->getLayoutConstraint();
281281

282282
// If the archetype is class-constrained, use a class pointer
283283
// representation.
284284
if (archetype->requiresClass() ||
285-
(LayoutInfo && LayoutInfo->isRefCounted())) {
286-
ReferenceCounting refcount;
287-
llvm::PointerType *reprTy;
285+
(layout && layout->isRefCounted())) {
286+
auto refcount = getReferenceCountingForType(IGM, CanType(archetype));
288287

289-
if (!IGM.ObjCInterop) {
290-
refcount = ReferenceCounting::Native;
291-
reprTy = IGM.RefCountedPtrTy;
292-
} else {
293-
refcount = ReferenceCounting::Unknown;
294-
reprTy = IGM.UnknownRefCountedPtrTy;
295-
}
288+
llvm::PointerType *reprTy;
296289

297290
// If the archetype has a superclass constraint, it has at least the
298291
// retain semantics of its superclass, and it can be represented with
299292
// the supertype's pointer type.
300-
if (Type super = archetype->getSuperclass()) {
301-
ClassDecl *superClass = super->getClassOrBoundGenericClass();
302-
refcount = getReferenceCountingForClass(IGM, superClass);
303-
293+
if (auto super = archetype->getSuperclass()) {
304294
auto &superTI = IGM.getTypeInfoForUnlowered(super);
305295
reprTy = cast<llvm::PointerType>(superTI.StorageType);
296+
} else {
297+
if (refcount == ReferenceCounting::Native) {
298+
reprTy = IGM.RefCountedPtrTy;
299+
} else {
300+
reprTy = IGM.UnknownRefCountedPtrTy;
301+
}
306302
}
307303

308304
// As a hack, assume class archetypes never have spare bits. There's a
@@ -320,9 +316,9 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
320316

321317
// If the archetype is trivial fixed-size layout-constrained, use a fixed size
322318
// representation.
323-
if (LayoutInfo && LayoutInfo->isFixedSizeTrivial()) {
324-
Size size(LayoutInfo->getTrivialSizeInBytes());
325-
Alignment align(LayoutInfo->getTrivialSizeInBytes());
319+
if (layout && layout->isFixedSizeTrivial()) {
320+
Size size(layout->getTrivialSizeInBytes());
321+
Alignment align(layout->getTrivialSizeInBytes());
326322
auto spareBits =
327323
SpareBitVector::getConstant(size.getValueInBits(), false);
328324
// Get an integer type of the required size.
@@ -336,7 +332,7 @@ const TypeInfo *TypeConverter::convertArchetypeType(ArchetypeType *archetype) {
336332
// If the archetype is a trivial layout-constrained, use a POD
337333
// representation. This type is not loadable, but it is known
338334
// to be a POD.
339-
if (LayoutInfo && LayoutInfo->isAddressOnlyTrivial()) {
335+
if (layout && layout->isAddressOnlyTrivial()) {
340336
// TODO: Create NonFixedSizeArchetypeTypeInfo and return it.
341337
}
342338

lib/IRGen/GenClass.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,20 +63,25 @@ static ClassDecl *getRootClass(ClassDecl *theClass) {
6363
return theClass;
6464
}
6565

66-
/// What reference counting mechanism does a class have?
67-
ReferenceCounting irgen::getReferenceCountingForClass(IRGenModule &IGM,
68-
ClassDecl *theClass) {
66+
/// What reference counting mechanism does a class-like type have?
67+
ReferenceCounting irgen::getReferenceCountingForType(IRGenModule &IGM,
68+
CanType type) {
6969
// If ObjC interop is disabled, we have a Swift refcount.
7070
if (!IGM.ObjCInterop)
7171
return ReferenceCounting::Native;
7272

73-
// NOTE: if you change this, change Type::usesNativeReferenceCounting.
74-
// If the root class is implemented in swift, then we have a swift
75-
// refcount; otherwise, we have an ObjC refcount.
76-
if (getRootClass(theClass)->hasKnownSwiftImplementation())
73+
if (type->usesNativeReferenceCounting(ResilienceExpansion::Maximal))
7774
return ReferenceCounting::Native;
7875

79-
return ReferenceCounting::ObjC;
76+
// Class-constrained archetypes and existentials that don't use
77+
// native reference counting and yet have a superclass must be
78+
// using ObjC reference counting.
79+
auto superclass = type->getSuperclass(nullptr);
80+
if (superclass)
81+
return ReferenceCounting::ObjC;
82+
83+
// Otherwise, it could be either one.
84+
return ReferenceCounting::Unknown;
8085
}
8186

8287
/// What isa encoding mechanism does a type have?
@@ -2087,7 +2092,7 @@ const TypeInfo *
20872092
TypeConverter::convertClassType(CanType type, ClassDecl *D) {
20882093
llvm::StructType *ST = IGM.createNominalType(type);
20892094
llvm::PointerType *irType = ST->getPointerTo();
2090-
ReferenceCounting refcount = ::getReferenceCountingForClass(IGM, D);
2095+
ReferenceCounting refcount = ::getReferenceCountingForType(IGM, type);
20912096

20922097
SpareBitVector spareBits;
20932098

lib/IRGen/GenClass.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,11 @@ namespace irgen {
132132
/// correspond to the runtime alignment of instances of the class.
133133
llvm::Constant *tryEmitClassConstantFragileInstanceAlignMask(IRGenModule &IGM,
134134
ClassDecl *theClass);
135-
136-
/// What reference counting mechanism does a class use?
137-
ReferenceCounting getReferenceCountingForClass(IRGenModule &IGM,
138-
ClassDecl *theClass);
139-
135+
136+
/// What reference counting mechanism does a class-like type use?
137+
ReferenceCounting getReferenceCountingForType(IRGenModule &IGM,
138+
CanType type);
139+
140140
/// What isa-encoding mechanism does a type use?
141141
IsaEncoding getIsaEncodingForType(IRGenModule &IGM, CanType type);
142142

lib/IRGen/GenDecl.cpp

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -332,22 +332,22 @@ class ObjCProtocolInitializerVisitor
332332
NewProto = Builder.CreateCall(objc_allocateProtocol, protocolName);
333333

334334
// Add the parent protocols.
335-
//
336-
// FIXME: Look at the requirement signature instead.
337-
for (auto inherited : proto->getInherited()) {
338-
SmallVector<ProtocolDecl*, 4> protocols;
339-
inherited.getType()->getExistentialTypeProtocols(protocols);
340-
for (auto parentProto : protocols) {
341-
if (!parentProto->isObjC())
342-
continue;
343-
llvm::Value *parentRef
344-
= IGM.getAddrOfObjCProtocolRef(parentProto, NotForDefinition);
345-
parentRef = IGF.Builder.CreateBitCast(parentRef,
346-
IGM.ProtocolDescriptorPtrTy->getPointerTo());
347-
auto parent = Builder.CreateLoad(parentRef,
348-
IGM.getPointerAlignment());
349-
Builder.CreateCall(protocol_addProtocol, {NewProto, parent});
350-
}
335+
auto *requirementSig = proto->getRequirementSignature();
336+
auto conformsTo =
337+
requirementSig->getConformsTo(proto->getSelfInterfaceType(),
338+
*IGF.IGM.getSwiftModule());
339+
340+
for (auto parentProto : conformsTo) {
341+
if (!parentProto->isObjC())
342+
continue;
343+
llvm::Value *parentRef = IGM.getAddrOfObjCProtocolRef(parentProto,
344+
NotForDefinition);
345+
parentRef = IGF.Builder.CreateBitCast(parentRef,
346+
IGM.ProtocolDescriptorPtrTy
347+
->getPointerTo());
348+
auto parent = Builder.CreateLoad(parentRef,
349+
IGM.getPointerAlignment());
350+
Builder.CreateCall(protocol_addProtocol, {NewProto, parent});
351351
}
352352

353353
// Add the members.
@@ -616,16 +616,17 @@ void IRGenModule::emitRuntimeRegistration() {
616616

617617
llvm::SmallVector<ProtocolDecl*, 4> protoInitOrder;
618618

619-
// FIXME: Use the requirement signature instead.
620619
std::function<void(ProtocolDecl*)> orderProtocol
621620
= [&](ProtocolDecl *proto) {
621+
auto *requirementSig = proto->getRequirementSignature();
622+
auto conformsTo = requirementSig->getConformsTo(
623+
proto->getSelfInterfaceType(),
624+
*getSwiftModule());
625+
622626
// Recursively put parents first.
623-
for (auto &inherited : proto->getInherited()) {
624-
SmallVector<ProtocolDecl*, 4> parents;
625-
inherited.getType()->getExistentialTypeProtocols(parents);
626-
for (auto parent : parents)
627-
orderProtocol(parent);
628-
}
627+
for (auto parent : conformsTo)
628+
orderProtocol(parent);
629+
629630
// Skip if we don't need to reify this protocol.
630631
auto found = protos.find(proto);
631632
if (found == protos.end())

lib/IRGen/GenExistential.cpp

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,6 +1088,12 @@ class ClassExistentialTypeInfo final
10881088

10891089
public:
10901090

1091+
llvm::PointerType *getPayloadType() const {
1092+
auto *ty = getStorageType();
1093+
llvm::StructType *structTy = cast<llvm::StructType>(ty);
1094+
return cast<llvm::PointerType>(structTy->elements()[0]);
1095+
}
1096+
10911097
bool isSingleRetainablePointer(ResilienceExpansion expansion,
10921098
ReferenceCounting *refcounting) const override{
10931099
if (refcounting) *refcounting = Refcounting;
@@ -1388,7 +1394,6 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
13881394

13891395
// The existential container is class-constrained if any of its protocol
13901396
// constraints are.
1391-
bool requiresClass = layout.requiresClass;
13921397
bool allowsTaggedPointers = true;
13931398

13941399
for (auto protoTy : layout.getProtocols()) {
@@ -1412,21 +1417,23 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
14121417

14131418
// If the existential is class, lower it to a class
14141419
// existential representation.
1415-
if (requiresClass) {
1420+
if (layout.requiresClass) {
14161421
// If we're not using the Objective-C runtime, we can use the
14171422
// native reference counting entry points.
1418-
ReferenceCounting refcounting;
1419-
1420-
// FIXME: If there is a superclass constraint we might be able to
1421-
// use native refcounting.
1422-
if (!IGM.ObjCInterop) {
1423-
refcounting = ReferenceCounting::Native;
1424-
fields[1] = IGM.RefCountedPtrTy;
1423+
ReferenceCounting refcounting = getReferenceCountingForType(IGM, T);
1424+
1425+
llvm::PointerType *reprTy = nullptr;
1426+
if (layout.superclass) {
1427+
auto &superTI = IGM.getTypeInfoForUnlowered(layout.superclass);
1428+
reprTy = cast<llvm::PointerType>(superTI.getStorageType());
1429+
} else if (refcounting == ReferenceCounting::Native) {
1430+
reprTy = IGM.RefCountedPtrTy;
14251431
} else {
1426-
refcounting = ReferenceCounting::Unknown;
1427-
fields[1] = IGM.UnknownRefCountedPtrTy;
1432+
reprTy = IGM.UnknownRefCountedPtrTy;
14281433
}
14291434

1435+
fields[1] = reprTy;
1436+
14301437
// Replace the type metadata pointer with the class instance.
14311438
auto classFields = llvm::makeArrayRef(fields).slice(1);
14321439
type->setBody(classFields);
@@ -1438,7 +1445,9 @@ static const TypeInfo *createExistentialTypeInfo(IRGenModule &IGM, CanType T) {
14381445

14391446
// The class pointer is an unknown heap object, so it may be a tagged
14401447
// pointer, if the platform has those.
1441-
if (allowsTaggedPointers && IGM.TargetInfo.hasObjCTaggedPointers()) {
1448+
if (allowsTaggedPointers &&
1449+
refcounting != ReferenceCounting::Native &&
1450+
IGM.TargetInfo.hasObjCTaggedPointers()) {
14421451
spareBits.appendClearBits(IGM.getPointerSize().getValueInBits());
14431452
} else {
14441453
// If the platform doesn't use ObjC tagged pointers, we can go crazy.
@@ -1809,13 +1818,8 @@ void irgen::emitClassExistentialContainer(IRGenFunction &IGF,
18091818
auto &destTI = IGF.getTypeInfo(outType).as<ClassExistentialTypeInfo>();
18101819

18111820
// Cast the instance pointer to an opaque refcounted pointer.
1812-
llvm::Value *opaqueInstance;
1813-
if (!IGF.IGM.ObjCInterop)
1814-
opaqueInstance = IGF.Builder.CreateBitCast(instance,
1815-
IGF.IGM.RefCountedPtrTy);
1816-
else
1817-
opaqueInstance = IGF.Builder.CreateBitCast(instance,
1818-
IGF.IGM.UnknownRefCountedPtrTy);
1821+
auto opaqueInstance = IGF.Builder.CreateBitCast(instance,
1822+
destTI.getPayloadType());
18191823
out.add(opaqueInstance);
18201824

18211825
// Emit the witness table pointers.

lib/IRGen/GenMeta.cpp

Lines changed: 13 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,7 +1906,8 @@ namespace {
19061906

19071907
llvm::Value *visitAnyClassType(ClassDecl *classDecl) {
19081908
// All class types have the same layout.
1909-
switch (getReferenceCountingForClass(IGF.IGM, classDecl)) {
1909+
auto type = classDecl->getDeclaredType()->getCanonicalType();
1910+
switch (getReferenceCountingForType(IGF.IGM, type)) {
19101911
case ReferenceCounting::Native:
19111912
return emitFromValueWitnessTable(IGF.IGM.Context.TheNativeObjectType);
19121913

@@ -1953,39 +1954,26 @@ namespace {
19531954
// Reference storage types with witness tables need open-coded layouts.
19541955
// TODO: Maybe we could provide prefabs for 1 witness table.
19551956
if (referent.isExistentialType()) {
1956-
SmallVector<ProtocolDecl*, 2> protocols;
1957-
referent.getExistentialTypeProtocols(protocols);
1958-
for (auto *proto : protocols)
1959-
if (IGF.getSILTypes().protocolRequiresWitnessTable(proto))
1957+
auto layout = referent.getExistentialLayout();
1958+
for (auto *protoTy : layout.getProtocols()) {
1959+
auto *protoDecl = protoTy->getDecl();
1960+
if (IGF.getSILTypes().protocolRequiresWitnessTable(protoDecl))
19601961
return visitType(type);
1962+
}
19611963
}
19621964

19631965
// Unmanaged references are plain pointers with extra inhabitants,
19641966
// which look like thick metatypes.
1967+
//
1968+
// FIXME: This sounds wrong, an Objective-C tagged pointer could be
1969+
// stored in an unmanaged reference for instance.
19651970
if (type->getOwnership() == Ownership::Unmanaged) {
19661971
auto metatype = CanMetatypeType::get(C.TheNativeObjectType);
19671972
return emitFromValueWitnessTable(metatype);
19681973
}
19691974

1970-
auto getReferenceCountingForReferent
1971-
= [&](CanType referent) -> ReferenceCounting {
1972-
// If Objective-C interop is enabled, generic types might contain
1973-
// Objective-C references, so we have to use unknown reference
1974-
// counting.
1975-
if (isa<ArchetypeType>(referent) ||
1976-
referent->isExistentialType())
1977-
return (IGF.IGM.ObjCInterop ?
1978-
ReferenceCounting::Unknown :
1979-
ReferenceCounting::Native);
1980-
1981-
if (auto classDecl = referent->getClassOrBoundGenericClass())
1982-
return getReferenceCountingForClass(IGF.IGM, classDecl);
1983-
1984-
llvm_unreachable("unexpected referent for ref storage type");
1985-
};
1986-
19871975
CanType valueWitnessReferent;
1988-
switch (getReferenceCountingForReferent(referent)) {
1976+
switch (getReferenceCountingForType(IGF.IGM, referent)) {
19891977
case ReferenceCounting::Unknown:
19901978
case ReferenceCounting::Block:
19911979
case ReferenceCounting::ObjC:
@@ -3355,7 +3343,8 @@ namespace {
33553343
ClassFlags flags = ClassFlags::IsSwift1;
33563344

33573345
// Set a flag if the class uses Swift 1.0 refcounting.
3358-
if (getReferenceCountingForClass(IGM, Target)
3346+
auto type = Target->getDeclaredType()->getCanonicalType();
3347+
if (getReferenceCountingForType(IGM, type)
33593348
== ReferenceCounting::Native) {
33603349
flags |= ClassFlags::UsesSwift1Refcounting;
33613350
}

0 commit comments

Comments
 (0)