Skip to content

Commit 8048a13

Browse files
authored
Merge pull request #3285 from slavapestov/multi-payload-enum-reflection
2 parents 1ef1d1f + 12d9cc2 commit 8048a13

38 files changed

+676
-548
lines changed

include/swift/Reflection/Records.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ enum class FieldDescriptorKind : uint16_t {
111111
Class,
112112
Enum,
113113

114+
// Fixed-size multi-payload enums have a special descriptor format that
115+
// encodes spare bits.
116+
//
117+
// FIXME: Actually implement this. For now, a descriptor with this kind
118+
// just means we also have a builtin descriptor from which we get the
119+
// size and alignment.
120+
MultiPayloadEnum,
121+
114122
// A Swift opaque protocol. There are no fields, just a record for the
115123
// type itself.
116124
Protocol,
@@ -145,6 +153,22 @@ class FieldDescriptor {
145153

146154
using const_iterator = FieldRecordIterator;
147155

156+
bool isEnum() const {
157+
return (Kind == FieldDescriptorKind::Enum ||
158+
Kind == FieldDescriptorKind::MultiPayloadEnum);
159+
}
160+
161+
bool isClass() const {
162+
return (Kind == FieldDescriptorKind::Class ||
163+
Kind == FieldDescriptorKind::ObjCClass);
164+
}
165+
166+
bool isProtocol() const {
167+
return (Kind == FieldDescriptorKind::Protocol ||
168+
Kind == FieldDescriptorKind::ClassProtocol ||
169+
Kind == FieldDescriptorKind::ObjCProtocol);
170+
}
171+
148172
const_iterator begin() const {
149173
auto Begin = getFieldRecordBuffer();
150174
auto End = Begin + NumFields;

include/swift/Reflection/TypeLowering.h

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,17 @@ class BuiltinTypeDescriptor;
3636

3737
// Defined in TypeLowering.cpp, not public -- they're friends below
3838
class LowerType;
39+
class EnumTypeInfoBuilder;
3940
class RecordTypeInfoBuilder;
4041
class ExistentialTypeInfoBuilder;
4142

4243
enum class RecordKind : unsigned {
44+
Invalid,
45+
46+
// A Swift tuple type.
4347
Tuple,
48+
49+
// A Swift struct type.
4450
Struct,
4551

4652
// An enum with no payload cases. The record will have no fields, but
@@ -51,6 +57,10 @@ enum class RecordKind : unsigned {
5157
// field, being the enum payload.
5258
SinglePayloadEnum,
5359

60+
// An enum with multiple payload cases. The record consists of a multiple
61+
// fields, one for each enum payload.
62+
MultiPayloadEnum,
63+
5464
// A Swift-native function is always a function pointer followed by a
5565
// retainable, nullable context pointer.
5666
ThickFunction,
@@ -237,6 +247,7 @@ class TypeConverter {
237247

238248
private:
239249
friend class swift::reflection::LowerType;
250+
friend class swift::reflection::EnumTypeInfoBuilder;
240251
friend class swift::reflection::RecordTypeInfoBuilder;
241252
friend class swift::reflection::ExistentialTypeInfoBuilder;
242253

@@ -272,15 +283,15 @@ class TypeConverter {
272283
/// tuples, structs, thick functions, etc.
273284
class RecordTypeInfoBuilder {
274285
TypeConverter &TC;
275-
unsigned Size, Alignment, Stride, NumExtraInhabitants;
286+
unsigned Size, Alignment, NumExtraInhabitants;
276287
RecordKind Kind;
277288
std::vector<FieldInfo> Fields;
278289
bool Empty;
279290
bool Invalid;
280291

281292
public:
282293
RecordTypeInfoBuilder(TypeConverter &TC, RecordKind Kind)
283-
: TC(TC), Size(0), Alignment(1), Stride(0), NumExtraInhabitants(0),
294+
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
284295
Kind(Kind), Empty(true), Invalid(false) {}
285296

286297
bool isInvalid() const {
@@ -289,7 +300,10 @@ class RecordTypeInfoBuilder {
289300

290301
unsigned addField(unsigned fieldSize, unsigned fieldAlignment,
291302
unsigned numExtraInhabitants);
303+
304+
// Add a field of a record type, such as a struct.
292305
void addField(const std::string &Name, const TypeRef *TR);
306+
293307
const RecordTypeInfo *build();
294308

295309
unsigned getNumFields() const {
@@ -299,13 +313,6 @@ class RecordTypeInfoBuilder {
299313
unsigned getFieldOffset(unsigned Index) const {
300314
return Fields[Index].Offset;
301315
}
302-
303-
void setNumExtraInhabitants(unsigned numExtraInhabitants) {
304-
// We can only take away extra inhabitants while performing
305-
// record layout, never add new ones.
306-
assert(numExtraInhabitants <= NumExtraInhabitants);
307-
NumExtraInhabitants = numExtraInhabitants;
308-
}
309316
};
310317

311318
}

include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ typedef enum swift_layout_kind {
7272
// field, being the enum payload.
7373
SWIFT_SINGLE_PAYLOAD_ENUM,
7474

75+
// An enum with multiple payload cases. The record consists of a multiple
76+
// fields, one for each enum payload.
77+
SWIFT_MULTI_PAYLOAD_ENUM,
78+
7579
SWIFT_THICK_FUNCTION,
7680

7781
SWIFT_OPAQUE_EXISTENTIAL,

lib/IRGen/GenEnum.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ class EnumImplStrategy {
173173
/// storage type, calculates its size and alignment, and produces the
174174
/// TypeInfo for the enum.
175175
virtual TypeInfo *completeEnumTypeLayout(TypeConverter &TC,
176-
SILType Type,
177-
EnumDecl *theEnum,
178-
llvm::StructType *enumTy) = 0;
179-
176+
SILType Type,
177+
EnumDecl *theEnum,
178+
llvm::StructType *enumTy) = 0;
179+
180180
const TypeInfo &getTypeInfo() const {
181181
assert(TI);
182182
return *TI;

lib/IRGen/GenMeta.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5677,6 +5677,9 @@ namespace {
56775677
/// the protocol descriptor, and for ObjC interop, references to the descriptor
56785678
/// that the ObjC runtime uses for uniquing.
56795679
void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
5680+
// Emit remote reflection metadata for the protocol.
5681+
emitFieldMetadataRecord(protocol);
5682+
56805683
// If the protocol is Objective-C-compatible, go through the path that
56815684
// produces an ObjC-compatible protocol_t.
56825685
if (protocol->isObjC()) {
@@ -5706,8 +5709,6 @@ void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
57065709
init->getType()));
57075710
var->setConstant(true);
57085711
var->setInitializer(init);
5709-
5710-
emitFieldMetadataRecord(protocol);
57115712
}
57125713

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

lib/IRGen/GenReflection.cpp

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ class ReflectionMetadataBuilder : public ConstantBuilder<> {
197197
else if (auto PD = dyn_cast<ProtocolDecl>(Nominal))
198198
IGM.ImportedProtocols.insert(PD);
199199
else
200-
IGM.BuiltinTypes.insert(CanType(t));
200+
IGM.OpaqueTypes.insert(Nominal);
201201
}
202202
});
203203
}
@@ -352,7 +352,18 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
352352
IGM, enumDecl->getDeclaredTypeInContext()
353353
->getCanonicalType());
354354

355-
addConstantInt16(uint16_t(FieldDescriptorKind::Enum));
355+
auto kind = FieldDescriptorKind::Enum;
356+
357+
// If this is a fixed-size multi-payload enum, we have to emit a descriptor
358+
// with the size and alignment of the type, because the reflection library
359+
// cannot derive this information at runtime.
360+
if (strategy.getElementsWithPayload().size() > 1 &&
361+
!strategy.needsPayloadSizeInMetadata()) {
362+
kind = FieldDescriptorKind::MultiPayloadEnum;
363+
IGM.OpaqueTypes.insert(enumDecl);
364+
}
365+
366+
addConstantInt16(uint16_t(kind));
356367
addConstantInt16(fieldRecordSize);
357368
addConstantInt32(strategy.getElementsWithPayload().size() +
358369
strategy.getElementsWithNoPayload().size());
@@ -448,25 +459,40 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder {
448459
}
449460
};
450461

451-
class BuiltinTypeMetadataBuilder : public ReflectionMetadataBuilder {
452-
void addBuiltinType(CanType builtinType) {
453-
addTypeRef(builtinType->getASTContext().TheBuiltinModule, builtinType);
462+
class FixedTypeMetadataBuilder : public ReflectionMetadataBuilder {
463+
void addFixedType(Module *module, CanType type,
464+
const FixedTypeInfo &ti) {
465+
addTypeRef(module, type);
454466

455-
auto &ti = cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(builtinType));
456467
addConstantInt32(ti.getFixedSize().getValue());
457468
addConstantInt32(ti.getFixedAlignment().getValue());
458469
addConstantInt32(ti.getFixedStride().getValue());
459470
addConstantInt32(ti.getFixedExtraInhabitantCount(IGM));
460471
}
461472

473+
void addBuiltinType(CanType builtinType) {
474+
auto &ti = cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(builtinType));
475+
addFixedType(builtinType->getASTContext().TheBuiltinModule, builtinType, ti);
476+
}
477+
478+
void addOpaqueType(const NominalTypeDecl *nominalDecl) {
479+
auto &ti = cast<FixedTypeInfo>(IGM.getTypeInfoForUnlowered(
480+
nominalDecl->getDeclaredTypeInContext()->getCanonicalType()));
481+
482+
addFixedType(nominalDecl->getParentModule(),
483+
nominalDecl->getDeclaredType()->getCanonicalType(), ti);
484+
}
485+
462486
void layout() {
463-
for (auto builtinType : IGM.BuiltinTypes) {
487+
for (auto builtinType : IGM.BuiltinTypes)
464488
addBuiltinType(builtinType);
465-
}
489+
490+
for (auto nominalDecl : IGM.OpaqueTypes)
491+
addOpaqueType(nominalDecl);
466492
}
467493

468494
public:
469-
BuiltinTypeMetadataBuilder(IRGenModule &IGM)
495+
FixedTypeMetadataBuilder(IRGenModule &IGM)
470496
: ReflectionMetadataBuilder(IGM) {}
471497

472498
llvm::GlobalVariable *emit() {
@@ -889,7 +915,7 @@ void IRGenModule::emitBuiltinReflectionMetadata() {
889915
for (auto PD : ImportedProtocols)
890916
emitFieldMetadataRecord(PD);
891917

892-
BuiltinTypeMetadataBuilder builder(*this);
918+
FixedTypeMetadataBuilder builder(*this);
893919
auto var = builder.emit();
894920
if (var)
895921
addUsedGlobal(var);

lib/IRGen/IRGenModule.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -719,12 +719,17 @@ class IRGenModule {
719719
/// Builtin types referenced by types in this module when emitting
720720
/// reflection metadata.
721721
llvm::SetVector<CanType> BuiltinTypes;
722+
/// Opaque but fixed-size types for which we also emit builtin type
723+
/// descriptors, allowing the reflection library to layout these types
724+
/// without knowledge of their contents. This includes imported structs
725+
/// and fixed-size multi-payload enums.
726+
llvm::SetVector<const NominalTypeDecl *> OpaqueTypes;
722727
/// Imported classes referenced by types in this module when emitting
723728
/// reflection metadata.
724-
llvm::SetVector<ClassDecl *> ImportedClasses;
729+
llvm::SetVector<const ClassDecl *> ImportedClasses;
725730
/// Imported protocols referenced by types in this module when emitting
726731
/// reflection metadata.
727-
llvm::SetVector<ProtocolDecl *> ImportedProtocols;
732+
llvm::SetVector<const ProtocolDecl *> ImportedProtocols;
728733

729734
llvm::Constant *getAddrOfStringForTypeRef(StringRef Str);
730735
llvm::Constant *getAddrOfFieldName(StringRef Name);

0 commit comments

Comments
 (0)