Skip to content

Commit 996a859

Browse files
committed
Reflection: Add basic type lowering for existentials
This approach doesn't work for imported Objective-C protocols yet.
1 parent c0c02a3 commit 996a859

File tree

7 files changed

+299
-53
lines changed

7 files changed

+299
-53
lines changed

include/swift/Reflection/TypeLowering.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,18 @@ class TypeRefBuilder;
3636
enum class RecordKind : unsigned {
3737
Tuple,
3838
Struct,
39+
40+
// A Swift-native function is always a function pointer followed by a
41+
// retainable, nullable context pointer.
3942
ThickFunction,
43+
44+
// An existential is a three-word buffer followed by value metadata and
45+
// witness tables.
46+
Existential,
47+
48+
// A class existential is a retainable pointer followed by witness
49+
// tables.
50+
ClassExistential,
4051
};
4152

4253
enum class ReferenceCounting : unsigned {

include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,23 @@ typedef struct swift_reflection_section_t {
3838
void *End;
3939
} swift_reflection_section_t;
4040

41-
/// The kind of a Swift type.
41+
/// The layout kind of a Swift type.
4242
typedef enum swift_layout_kind_t {
43+
// Nothing is known about the size or contents of this value.
4344
SWIFT_UNKNOWN,
4445

46+
// An opaque value with known size and alignment but no specific
47+
// interpretation.
4548
SWIFT_BUILTIN,
4649

50+
// Record types consisting of zero or more fields.
4751
SWIFT_TUPLE,
4852
SWIFT_STRUCT,
4953
SWIFT_THICK_FUNCTION,
54+
SWIFT_EXISTENTIAL,
55+
SWIFT_CLASS_EXISTENTIAL,
5056

57+
// References to other objects in the heap.
5158
SWIFT_STRONG_REFERENCE,
5259
SWIFT_UNOWNED_REFERENCE,
5360
SWIFT_WEAK_REFERENCE,
@@ -58,7 +65,7 @@ struct swift_childinfo;
5865

5966
/// A description of the memory layout of a type or field of a type.
6067
typedef struct swift_typeinfo {
61-
swift_layout_kind_t LayoutKind;
68+
swift_layout_kind_t Kind;
6269

6370
unsigned Size;
6471
unsigned Alignment;
@@ -71,6 +78,7 @@ typedef struct swift_childinfo {
7178
/// The memory for Name is owned by the reflection context.
7279
const char *Name;
7380
unsigned Offset;
81+
swift_layout_kind_t Kind;
7482
swift_typeref_t TR;
7583
} swift_childinfo_t;
7684

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 137 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,12 @@ class PrintTypeInfo {
107107
case RecordKind::ThickFunction:
108108
printHeader("thick_function");
109109
break;
110+
case RecordKind::Existential:
111+
printHeader("existential");
112+
break;
113+
case RecordKind::ClassExistential:
114+
printHeader("class_existential");
115+
break;
110116
}
111117
printBasic(TI);
112118
printFields(RecordTI);
@@ -224,6 +230,89 @@ class RecordTypeInfoBuilder {
224230
}
225231
};
226232

233+
class ExistentialTypeInfoBuilder {
234+
TypeConverter &TC;
235+
bool ObjC;
236+
bool Class;
237+
unsigned WitnessTableCount;
238+
bool Invalid;
239+
240+
public:
241+
ExistentialTypeInfoBuilder(TypeConverter &TC)
242+
: TC(TC), ObjC(false), Class(false), WitnessTableCount(0),
243+
Invalid(false) {}
244+
245+
void addProtocol(const TypeRef *TR) {
246+
auto *P = dyn_cast<ProtocolTypeRef>(TR);
247+
if (P == nullptr) {
248+
Invalid = true;
249+
return;
250+
}
251+
252+
// FIXME: AnyObject should go away
253+
if (P->getMangledName() == "Ps9AnyObject_") {
254+
Class = true;
255+
return;
256+
}
257+
258+
const FieldDescriptor *FD = TC.getBuilder().getFieldTypeInfo(TR);
259+
if (FD == nullptr) {
260+
Invalid = true;
261+
return;
262+
}
263+
264+
switch (FD->Kind) {
265+
case FieldDescriptorKind::ObjCProtocol:
266+
ObjC = true;
267+
break;
268+
case FieldDescriptorKind::ClassProtocol:
269+
Class = true;
270+
WitnessTableCount++;
271+
break;
272+
case FieldDescriptorKind::Protocol:
273+
WitnessTableCount++;
274+
break;
275+
case FieldDescriptorKind::Struct:
276+
case FieldDescriptorKind::Enum:
277+
case FieldDescriptorKind::Class:
278+
Invalid = true;
279+
break;
280+
}
281+
}
282+
283+
const TypeInfo *build() {
284+
if (Invalid)
285+
return nullptr;
286+
287+
if (ObjC) {
288+
if (WitnessTableCount > 0)
289+
return nullptr;
290+
291+
return TC.getReferenceTypeInfo(ReferenceKind::Strong,
292+
ReferenceCounting::Unknown);
293+
}
294+
295+
RecordTypeInfoBuilder builder(TC,
296+
Class
297+
? RecordKind::ClassExistential
298+
: RecordKind::Existential);
299+
300+
if (Class) {
301+
builder.addField("object", TC.getUnknownObjectTypeRef());
302+
} else {
303+
builder.addField("value", TC.getRawPointerTypeRef());
304+
builder.addField("value", TC.getRawPointerTypeRef());
305+
builder.addField("value", TC.getRawPointerTypeRef());
306+
builder.addField("metadata", TC.getRawPointerTypeRef());
307+
}
308+
309+
for (unsigned i = 0; i < WitnessTableCount; i++)
310+
builder.addField("wtable", TC.getRawPointerTypeRef());
311+
312+
return builder.build();
313+
}
314+
};
315+
227316
}
228317

229318
const ReferenceTypeInfo *
@@ -355,10 +444,16 @@ class LowerType
355444
//
356445
// Also this is wrong if we wrap a reference in multiple levels of
357446
// optionality
358-
if (NoPayloadCases == 1 &&
359-
PayloadCases == 1 &&
360-
isa<ReferenceTypeInfo>(PayloadTI))
361-
return PayloadTI;
447+
if (NoPayloadCases == 1 && PayloadCases == 1) {
448+
if (isa<ReferenceTypeInfo>(PayloadTI))
449+
return PayloadTI;
450+
451+
if (auto *RecordTI = dyn_cast<RecordTypeInfo>(PayloadTI)) {
452+
auto SubKind = RecordTI->getRecordKind();
453+
if (SubKind == RecordKind::ClassExistential)
454+
return PayloadTI;
455+
}
456+
}
362457

363458
return nullptr;
364459
}
@@ -399,14 +494,17 @@ class LowerType
399494
}
400495

401496
const TypeInfo *visitProtocolTypeRef(const ProtocolTypeRef *P) {
402-
// FIXME
403-
return nullptr;
497+
ExistentialTypeInfoBuilder builder(TC);
498+
builder.addProtocol(P);
499+
return builder.build();
404500
}
405501

406502
const TypeInfo *
407503
visitProtocolCompositionTypeRef(const ProtocolCompositionTypeRef *PC) {
408-
// FIXME
409-
return nullptr;
504+
ExistentialTypeInfoBuilder builder(TC);
505+
for (auto *P : PC->getProtocols())
506+
builder.addProtocol(P);
507+
return builder.build();
410508
}
411509

412510
const TypeInfo *visitMetatypeTypeRef(const MetatypeTypeRef *M) {
@@ -442,16 +540,44 @@ class LowerType
442540
ReferenceCounting::Unknown);
443541
}
444542

543+
const TypeInfo *
544+
rebuildStorageTypeInfo(const TypeInfo *TI, ReferenceKind Kind) {
545+
if (auto *ReferenceTI = dyn_cast<ReferenceTypeInfo>(TI))
546+
return TC.getReferenceTypeInfo(Kind, ReferenceTI->getReferenceCounting());
547+
548+
if (auto *RecordTI = dyn_cast<RecordTypeInfo>(TI)) {
549+
auto SubKind = RecordTI->getRecordKind();
550+
if (SubKind == RecordKind::ClassExistential) {
551+
std::vector<FieldInfo> Fields;
552+
for (auto &Field : RecordTI->getFields()) {
553+
if (Field.Name == "object") {
554+
auto *FieldTI = rebuildStorageTypeInfo(&Field.TI, Kind);
555+
Fields.push_back({Field.Name, Field.Offset, Field.TR, *FieldTI});
556+
continue;
557+
}
558+
Fields.push_back(Field);
559+
}
560+
561+
return TC.makeTypeInfo<RecordTypeInfo>(
562+
RecordTI->getSize(),
563+
RecordTI->getAlignment(),
564+
RecordTI->getStride(),
565+
RecordTI->getNumExtraInhabitants(),
566+
SubKind, Fields);
567+
}
568+
}
569+
570+
return nullptr;
571+
}
572+
445573
template<typename StorageTypeRef>
446574
const TypeInfo *
447575
visitAnyStorageTypeRef(const StorageTypeRef *S, ReferenceKind Kind) {
448576
auto *TI = TC.getTypeInfo(S->getType());
449577
if (TI == nullptr)
450578
return nullptr;
451579

452-
// FIXME: This might also be a class existential
453-
return TC.getReferenceTypeInfo(Kind,
454-
cast<ReferenceTypeInfo>(TI)->getReferenceCounting());
580+
return rebuildStorageTypeInfo(TI, Kind);
455581
}
456582

457583
const TypeInfo *

stdlib/public/Reflection/TypeRefBuilder.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ TypeRefBuilder::getFieldTypeInfo(const TypeRef *TR) {
7777
MangledName = N->getMangledName();
7878
else if (auto BG = dyn_cast<BoundGenericTypeRef>(TR))
7979
MangledName = BG->getMangledName();
80+
else if (auto P = dyn_cast<ProtocolTypeRef>(TR))
81+
MangledName = P->getMangledName();
8082
else
8183
return {};
8284

stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,41 @@ swift_reflection_genericArgumentCountOfTypeRef(swift_typeref_t OpaqueTypeRef) {
101101
return 0;
102102
}
103103

104+
swift_layout_kind_t getTypeInfoKind(const TypeInfo &TI) {
105+
switch (TI.getKind()) {
106+
case TypeInfoKind::Builtin:
107+
return SWIFT_BUILTIN;
108+
case TypeInfoKind::Record: {
109+
auto &RecordTI = cast<RecordTypeInfo>(TI);
110+
switch (RecordTI.getRecordKind()) {
111+
case RecordKind::Tuple:
112+
return SWIFT_TUPLE;
113+
case RecordKind::Struct:
114+
return SWIFT_STRUCT;
115+
case RecordKind::ThickFunction:
116+
return SWIFT_THICK_FUNCTION;
117+
case RecordKind::Existential:
118+
return SWIFT_EXISTENTIAL;
119+
case RecordKind::ClassExistential:
120+
return SWIFT_CLASS_EXISTENTIAL;
121+
}
122+
}
123+
case TypeInfoKind::Reference: {
124+
auto &ReferenceTI = cast<ReferenceTypeInfo>(TI);
125+
switch (ReferenceTI.getReferenceKind()) {
126+
case ReferenceKind::Strong:
127+
return SWIFT_STRONG_REFERENCE;
128+
case ReferenceKind::Unowned:
129+
return SWIFT_UNOWNED_REFERENCE;
130+
case ReferenceKind::Weak:
131+
return SWIFT_WEAK_REFERENCE;
132+
case ReferenceKind::Unmanaged:
133+
return SWIFT_UNMANAGED_REFERENCE;
134+
}
135+
}
136+
}
137+
}
138+
104139
swift_typeinfo_t
105140
swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
106141
swift_typeref_t OpaqueTypeRef) {
@@ -118,50 +153,12 @@ swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
118153
};
119154
}
120155

121-
swift_layout_kind_t Kind;
122156
unsigned NumFields = 0;
123-
124-
switch (TI->getKind()) {
125-
case TypeInfoKind::Builtin:
126-
Kind = SWIFT_BUILTIN;
127-
break;
128-
case TypeInfoKind::Record: {
129-
auto *RecordTI = cast<RecordTypeInfo>(TI);
130-
switch (RecordTI->getRecordKind()) {
131-
case RecordKind::Tuple:
132-
Kind = SWIFT_TUPLE;
133-
break;
134-
case RecordKind::Struct:
135-
Kind = SWIFT_STRUCT;
136-
break;
137-
case RecordKind::ThickFunction:
138-
Kind = SWIFT_THICK_FUNCTION;
139-
break;
140-
}
157+
if (auto *RecordTI = dyn_cast<RecordTypeInfo>(TI))
141158
NumFields = RecordTI->getNumFields();
142-
break;
143-
}
144-
case TypeInfoKind::Reference: {
145-
auto *ReferenceTI = cast<ReferenceTypeInfo>(TI);
146-
switch (ReferenceTI->getReferenceKind()) {
147-
case ReferenceKind::Strong:
148-
Kind = SWIFT_STRONG_REFERENCE;
149-
break;
150-
case ReferenceKind::Unowned:
151-
Kind = SWIFT_UNOWNED_REFERENCE;
152-
break;
153-
case ReferenceKind::Weak:
154-
Kind = SWIFT_WEAK_REFERENCE;
155-
break;
156-
case ReferenceKind::Unmanaged:
157-
Kind = SWIFT_UNMANAGED_REFERENCE;
158-
break;
159-
}
160-
}
161-
}
162159

163160
return {
164-
Kind,
161+
getTypeInfoKind(*TI),
165162
TI->getSize(),
166163
TI->getAlignment(),
167164
TI->getStride(),
@@ -182,6 +179,7 @@ swift_reflection_infoForChild(SwiftReflectionContextRef ContextRef,
182179
return {
183180
FieldInfo.Name.c_str(),
184181
FieldInfo.Offset,
182+
getTypeInfoKind(FieldInfo.TI),
185183
reinterpret_cast<swift_typeref_t>(FieldInfo.TR),
186184
};
187185
}

test/Reflection/Inputs/TypeLowering.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,24 @@ public struct FunctionStruct {
4747
public let thinFunction: @convention(thin) () -> ()
4848
public let cFunction: @convention(c) () -> ()
4949
}
50+
51+
public protocol P1 {}
52+
public protocol P2 : P1 {}
53+
public protocol P3 {}
54+
55+
public protocol CP1 : class {}
56+
public protocol CP2 : CP1 {}
57+
58+
public struct ExistentialStruct {
59+
public let any: Any
60+
public let anyObject: AnyObject
61+
public let anyProto: P1
62+
public let anyProtoComposition: protocol<P1, P2, P3>
63+
public let anyClassBoundProto1: CP1
64+
public let anyClassBoundProto2: CP2
65+
public let anyClassBoundProtoComposition1: protocol<CP1, CP2>
66+
public let anyClassBoundProtoComposition2: protocol<P1, CP2>
67+
68+
public weak var weakAnyObject: AnyObject?
69+
public weak var weakAnyClassBoundProto: CP1?
70+
}

0 commit comments

Comments
 (0)