Skip to content

Commit 8946fa3

Browse files
slavapestovtkremenek
authored andcommitted
Reflection fixes for closures and imported types (3.0) (#2736)
* Reflection: Emit metadata for fixed-layout SIL boxes We were recovering metadata from generic boxes by reading the instantiated payload metadata from the box's metadata, but this approach doesn't work for fixed-size boxes, whose metadata does not store the payload metadata at all. Instead, emit a capture descriptor with no metadata sources and a single capture, using the lowered AST type appearing in the alloc_box instruction that emitted the box. Since box metadata is shared by all POD types of the same size, and all single-retainable pointer payloads, the AST type might not accurately reflect what is actually in the box. However, this type is *layout compatible* with the box payload, at least enough to know where the retainable pointers are, because after all IRGen uses this type to synthesize the destructor. Fixes <rdar://problem/26314060>. * Reflection: Don't emit associated type records for conformances without associated types This saves a bit of space. We don't care about conformances per se in remote reflection, only what the associated types are. * Reflection: Record builtin and imported types referenced from captures * Reflection: Don't emit builtin descriptors for imported classes Previously we would emit both a builtin descriptor and field descriptor for imported classes, but we only need the latter. Untangle some code and fix a crash with imported Objective-C generics in the process. Fixes <rdar://problem/26498484>. * Reflection: Emit field metadata for @objc classes While we can skip emitting metadata for imported classes (clients should ask the Objective-C runtime instead) it was not correct to do so for Swift-defined classes that used Objective-C reference counting. * Reflection: Emit descriptors for referenced imported protocols When we encounter a protocol typeref, we have to know if its @objc, class-bound, or opaque, so make sure we provide the necessary information when imported protocols are referenced. * Reflection: Simplify associated type metadata emission Instead of hooking into nominal type and extension emission and walking all conformances of those declarations, let's just directly hook into the logic for emitting conformances. This fixes an issue where we would apparently emit duplicate conformances, as well as unnecessary conformances that are defined elsewhere. * Reflection: Fix tests for iPhoneOS * Reflection: More robust typeref_decoding_objc test Go through some pains to ensure that we emit an override for the default initializer, since otherwise we emit a fatalError() call which ends up creating some closures. The exact order of the closures changed between master and swift-3.0-preview-1-branch. It is better not to test this part at all.
1 parent 67d3b2b commit 8946fa3

20 files changed

+452
-425
lines changed

include/swift/Reflection/Records.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,14 +104,25 @@ struct FieldRecordIterator {
104104
};
105105

106106
enum class FieldDescriptorKind : uint16_t {
107+
// Swift nominal types.
107108
Struct,
108109
Class,
109110
Enum,
111+
112+
// A Swift opaque protocol. There are no fields, just a record for the
113+
// type itself.
110114
Protocol,
115+
116+
// A Swift class-bound protocol.
111117
ClassProtocol,
118+
119+
// An Objective-C protocol, which may be imported or defined in Swift.
112120
ObjCProtocol,
113-
ObjCClass,
114-
Imported
121+
122+
// An Objective-C class, which may be imported or defined in Swift.
123+
// In the former case, field type metadata is not emitted, and
124+
// must be obtained from the Objective-C runtime.
125+
ObjCClass
115126
};
116127

117128
// Field descriptors contain a collection of field records for a single

lib/IRGen/GenClass.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,7 +773,7 @@ void IRGenModule::emitClassDecl(ClassDecl *D) {
773773
classTI.getLayout(*this, selfType),
774774
classTI.getClassLayout(*this, selfType));
775775
emitNestedTypeDecls(D->getMembers());
776-
emitReflectionMetadata(D);
776+
emitFieldMetadataRecord(D);
777777
}
778778

779779
namespace {

lib/IRGen/GenDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2053,6 +2053,8 @@ llvm::Constant *IRGenModule::emitProtocolConformances() {
20532053

20542054
SmallVector<llvm::Constant*, 8> elts;
20552055
for (auto *conformance : ProtocolConformances) {
2056+
emitAssociatedTypeMetadataRecord(conformance);
2057+
20562058
auto descriptorRef = getAddrOfLLVMVariableOrGOTEquivalent(
20572059
LinkEntity::forProtocolDescriptor(conformance->getProtocol()),
20582060
getPointerAlignment(), ProtocolDescriptorStructTy);
@@ -2755,7 +2757,6 @@ static bool shouldEmitCategory(IRGenModule &IGM, ExtensionDecl *ext) {
27552757
}
27562758

27572759
void IRGenModule::emitExtension(ExtensionDecl *ext) {
2758-
emitAssociatedTypeMetadataRecord(ext);
27592760
emitNestedTypeDecls(ext->getMembers());
27602761

27612762
// Generate a category if the extension either introduces a

lib/IRGen/GenEnum.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5562,7 +5562,7 @@ const TypeInfo *TypeConverter::convertEnumType(TypeBase *key, CanType type,
55625562
void IRGenModule::emitEnumDecl(EnumDecl *theEnum) {
55635563
emitEnumMetadata(*this, theEnum);
55645564
emitNestedTypeDecls(theEnum->getMembers());
5565-
emitReflectionMetadata(theEnum);
5565+
emitFieldMetadataRecord(theEnum);
55665566
}
55675567

55685568
void irgen::emitSwitchAddressOnlyEnumDispatch(IRGenFunction &IGF,

lib/IRGen/GenHeap.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,7 +1386,7 @@ class BoxTypeInfo : public HeapTypeInfo<BoxTypeInfo> {
13861386

13871387
/// Allocate a box of the given type.
13881388
virtual OwnedAddress
1389-
allocate(IRGenFunction &IGF, SILType boxedType,
1389+
allocate(IRGenFunction &IGF, SILType boxedType, SILType boxedInterfaceType,
13901390
const llvm::Twine &name) const = 0;
13911391

13921392
/// Deallocate an uninitialized box.
@@ -1404,7 +1404,7 @@ class EmptyBoxTypeInfo final : public BoxTypeInfo {
14041404
EmptyBoxTypeInfo(IRGenModule &IGM) : BoxTypeInfo(IGM) {}
14051405

14061406
OwnedAddress
1407-
allocate(IRGenFunction &IGF, SILType boxedType,
1407+
allocate(IRGenFunction &IGF, SILType boxedType, SILType boxedInterfaceType,
14081408
const llvm::Twine &name) const override {
14091409
return OwnedAddress(IGF.getTypeInfo(boxedType).getUndefAddress(),
14101410
IGF.IGM.RefCountedNull);
@@ -1429,7 +1429,7 @@ class NonFixedBoxTypeInfo final : public BoxTypeInfo {
14291429
NonFixedBoxTypeInfo(IRGenModule &IGM) : BoxTypeInfo(IGM) {}
14301430

14311431
OwnedAddress
1432-
allocate(IRGenFunction &IGF, SILType boxedType,
1432+
allocate(IRGenFunction &IGF, SILType boxedType, SILType boxedInterfaceType,
14331433
const llvm::Twine &name) const override {
14341434
auto &ti = IGF.getTypeInfo(boxedType);
14351435
// Use the runtime to allocate a box of the appropriate size.
@@ -1470,14 +1470,15 @@ class FixedBoxTypeInfoBase : public BoxTypeInfo {
14701470
{}
14711471

14721472
OwnedAddress
1473-
allocate(IRGenFunction &IGF, SILType boxedType, const llvm::Twine &name)
1473+
allocate(IRGenFunction &IGF, SILType boxedType, SILType boxedInterfaceType,
1474+
const llvm::Twine &name)
14741475
const override {
14751476
// Allocate a new object using the layout.
14761477

1477-
auto nullCaptureDescriptor
1478-
= llvm::ConstantPointerNull::get(IGF.IGM.CaptureDescriptorPtrTy);
1478+
auto boxDescriptor = IGF.IGM.getAddrOfBoxDescriptor(
1479+
boxedInterfaceType.getSwiftRValueType());
14791480
llvm::Value *allocation = IGF.emitUnmanagedAlloc(layout, name,
1480-
nullCaptureDescriptor);
1481+
boxDescriptor);
14811482
Address rawAddr = project(IGF, allocation, boxedType);
14821483
return {rawAddr, allocation};
14831484
}
@@ -1586,9 +1587,13 @@ const TypeInfo *TypeConverter::convertBoxType(SILBoxType *T) {
15861587

15871588
OwnedAddress
15881589
irgen::emitAllocateBox(IRGenFunction &IGF, CanSILBoxType boxType,
1590+
CanSILBoxType boxInterfaceType,
15891591
const llvm::Twine &name) {
15901592
auto &boxTI = IGF.getTypeInfoForLowered(boxType).as<BoxTypeInfo>();
1591-
return boxTI.allocate(IGF, boxType->getBoxedAddressType(), name);
1593+
return boxTI.allocate(IGF,
1594+
boxType->getBoxedAddressType(),
1595+
boxInterfaceType->getBoxedAddressType(),
1596+
name);
15921597
}
15931598

15941599
void irgen::emitDeallocateBox(IRGenFunction &IGF,

lib/IRGen/GenHeap.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,12 @@ void emitDeallocatePartialClassInstance(IRGenFunction &IGF,
116116
llvm::Value *alignMask);
117117

118118
/// Allocate a boxed value.
119+
///
120+
/// The interface type is required for emitting reflection metadata.
119121
OwnedAddress
120-
emitAllocateBox(IRGenFunction &IGF, CanSILBoxType boxType,
122+
emitAllocateBox(IRGenFunction &IGF,
123+
CanSILBoxType boxType,
124+
CanSILBoxType boxInterfaceType,
121125
const llvm::Twine &name);
122126

123127
/// Deallocate a box whose value is uninitialized.

lib/IRGen/GenMeta.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5690,7 +5690,7 @@ void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
56905690
var->setConstant(true);
56915691
var->setInitializer(init);
56925692

5693-
emitReflectionMetadata(protocol);
5693+
emitFieldMetadataRecord(protocol);
56945694
}
56955695

56965696
/// \brief Load a reference to the protocol descriptor for the given protocol.

0 commit comments

Comments
 (0)