Skip to content

Commit 7a9a4dc

Browse files
committed
Reflection: Preliminary C API entry points for class instance layout
Tested by manually running swift-reflection-test, no automated tests yet, but coming soon.
1 parent 46dd5cd commit 7a9a4dc

File tree

8 files changed

+181
-39
lines changed

8 files changed

+181
-39
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,29 @@ class ReflectionContext
6767

6868
/// Return a description of the layout of a heap object having the given
6969
/// metadata as its isa pointer.
70-
const TypeInfo *getTypeInfo(StoredPointer MetadataAddress) {
71-
// This is wrong...
70+
const TypeInfo *getInstanceTypeInfo(StoredPointer MetadataAddress) {
71+
// FIXME: Add caching
72+
auto &TC = getBuilder().getTypeConverter();
73+
7274
auto TR = readTypeFromMetadata(MetadataAddress);
73-
return getTypeInfo(TR);
75+
if (TR == nullptr)
76+
return nullptr;
77+
78+
auto kind = this->readKindFromMetadata(MetadataAddress);
79+
if (!kind.first)
80+
return nullptr;
81+
82+
switch (kind.second) {
83+
case MetadataKind::Class: {
84+
auto start = this->readInstanceStartFromClassMetadata(MetadataAddress);
85+
if (!start.first)
86+
return nullptr;
87+
auto *TI = TC.getInstanceTypeInfo(TR, start.second);
88+
return TI;
89+
}
90+
default:
91+
return nullptr;
92+
}
7493
}
7594

7695
/// Return a description of the layout of a value with the given type.

include/swift/Reflection/TypeLowering.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ enum class RecordKind : unsigned {
5151

5252
// An existential metatype.
5353
ExistentialMetatype,
54+
55+
// A class instance layout, consisting of the stored properties of
56+
// one class, excluding superclasses.
57+
ClassInstance,
5458
};
5559

5660
enum class ReferenceCounting : unsigned {
@@ -167,8 +171,17 @@ class TypeConverter {
167171

168172
TypeRefBuilder &getBuilder() { return Builder; }
169173

174+
/// Returns layout information for a value of the given type.
175+
/// For a class, this returns the lowering of the reference value.
170176
const TypeInfo *getTypeInfo(const TypeRef *TR);
171177

178+
/// Returns layout information for an instance of the given
179+
/// class.
180+
///
181+
/// Not cached.
182+
const TypeInfo *getInstanceTypeInfo(const TypeRef *TR,
183+
unsigned InstanceStart);
184+
172185
/* Not really public */
173186
const ReferenceTypeInfo *
174187
getReferenceTypeInfo(ReferenceKind Kind,

include/swift/Remote/MetadataReader.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,29 @@ class MetadataReader {
465465
return {true, meta->getKind()};
466466
}
467467

468+
/// Given a remote pointer to class metadata, attempt to discover its class
469+
/// instance start offset.
470+
std::pair<bool, unsigned>
471+
readInstanceStartFromClassMetadata(StoredPointer MetadataAddress) {
472+
auto meta = readMetadata(MetadataAddress);
473+
if (!meta)
474+
return {false, 0};
475+
476+
auto address = readAddressOfNominalTypeDescriptor(meta);
477+
if (!address)
478+
return {false, 0};
479+
480+
auto descriptor = readNominalTypeDescriptor(address);
481+
if (!descriptor)
482+
return {false, 0};
483+
484+
if (descriptor->Class.NumFields == 0)
485+
return {true, sizeof(StoredPointer)};
486+
487+
// return {true, meta->getFieldOffsets()[0]};
488+
return {true, sizeof(StoredPointer)};
489+
}
490+
468491
/// Given a remote pointer to metadata, attempt to turn it into a type.
469492
BuiltType readTypeFromMetadata(StoredPointer MetadataAddress) {
470493
auto Cached = TypeCache.find(MetadataAddress);

include/swift/SwiftRemoteMirror/SwiftRemoteMirror.h

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,32 @@ swift_reflection_addReflectionInfo(SwiftReflectionContextRef ContextRef,
6262
/// NULL if one can't be constructed.
6363
swift_typeref_t
6464
swift_reflection_typeRefForMetadata(SwiftReflectionContextRef ContextRef,
65-
uintptr_t metadata);
65+
uintptr_t Metadata);
6666

67-
/// Returns a structure describing the overall layout of a typeref.
67+
/// Returns a structure describing the layout of a value of a typeref.
68+
/// For classes, this returns the reference value itself.
6869
swift_typeinfo_t
6970
swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
7071
swift_typeref_t OpaqueTypeRef);
7172

72-
/// Returns the information about a child by index.
73+
/// Returns the information about a child field of a value by index.
7374
swift_childinfo_t
74-
swift_reflection_infoForField(SwiftReflectionContextRef ContextRef,
75-
swift_typeref_t OpaqueTypeRef,
76-
unsigned Index);
75+
swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef,
76+
swift_typeref_t OpaqueTypeRef,
77+
unsigned Index);
78+
79+
/// Returns a structure describing the layout of a class instance
80+
/// from the isa pointer of a class.
81+
swift_typeinfo_t
82+
swift_reflection_infoForMetadata(SwiftReflectionContextRef ContextRef,
83+
uintptr_t Metadata);
84+
85+
/// Returns the information about a child field of a class instance
86+
/// by index.
87+
swift_childinfo_t
88+
swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef,
89+
uintptr_t Metadata,
90+
unsigned Index);
7791

7892
/// Returns a fully instantiated typeref for a generic argument by index.
7993
unsigned
@@ -83,6 +97,7 @@ swift_reflection_genericArgumentCountOfTypeRef(swift_typeref_t OpaqueTypeRef);
8397
swift_typeref_t
8498
swift_reflection_genericArgumentOfTypeRef(swift_typeref_t OpaqueTypeRef,
8599
unsigned Index);
100+
86101
#ifdef __cplusplus
87102
} // extern "C"
88103
#endif

include/swift/SwiftRemoteMirror/SwiftRemoteMirrorTypes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ typedef enum swift_layout_kind_t {
5454
SWIFT_EXISTENTIAL,
5555
SWIFT_CLASS_EXISTENTIAL,
5656
SWIFT_EXISTENTIAL_METATYPE,
57+
SWIFT_CLASS_INSTANCE,
5758

5859
// References to other objects in the heap.
5960
SWIFT_STRONG_REFERENCE,

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ class PrintTypeInfo {
119119
case RecordKind::ExistentialMetatype:
120120
printHeader("existential_metatype");
121121
break;
122+
case RecordKind::ClassInstance:
123+
printHeader("class_instance");
124+
break;
122125
}
123126
printBasic(TI);
124127
printFields(RecordTI);
@@ -197,6 +200,25 @@ class RecordTypeInfoBuilder {
197200
: TC(TC), Size(0), Alignment(1), Stride(0), NumExtraInhabitants(0),
198201
Kind(Kind), Invalid(false) {}
199202

203+
unsigned addField(unsigned fieldSize, unsigned fieldAlignment) {
204+
// Align the current size appropriately
205+
Size = ((Size + fieldAlignment - 1) & ~(fieldAlignment - 1));
206+
207+
// Record the offset
208+
unsigned offset = Size;
209+
210+
// Update the aggregate size
211+
Size += fieldSize;
212+
213+
// Update the aggregate alignment
214+
Alignment = std::max(Alignment, fieldAlignment);
215+
216+
// Re-calculate the stride
217+
Stride = ((Size + Alignment - 1) & ~(Alignment - 1));
218+
219+
return offset;
220+
}
221+
200222
void addField(const std::string &Name, const TypeRef *TR) {
201223
const TypeInfo *TI = TC.getTypeInfo(TR);
202224
if (TI == nullptr) {
@@ -213,20 +235,8 @@ class RecordTypeInfoBuilder {
213235
unsigned fieldSize = TI->getSize();
214236
unsigned fieldAlignment = TI->getAlignment();
215237

216-
// Align the current size appropriately
217-
Size = ((Size + fieldAlignment - 1) & ~(fieldAlignment - 1));
218-
219-
// Add the field at the aligned offset
220-
Fields.push_back({Name, Size, TR, *TI});
221-
222-
// Update the aggregate size
223-
Size += fieldSize;
224-
225-
// Update the aggregate alignment
226-
Alignment = std::max(Alignment, fieldAlignment);
227-
228-
// Re-calculate the stride
229-
Stride = ((Size + Alignment - 1) & ~(Alignment - 1));
238+
unsigned fieldOffset = addField(fieldSize, fieldAlignment);
239+
Fields.push_back({Name, fieldOffset, TR, *TI});
230240
}
231241

232242
const RecordTypeInfo *build() {
@@ -859,3 +869,35 @@ const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) {
859869

860870
return TI;
861871
}
872+
873+
const TypeInfo *TypeConverter::getInstanceTypeInfo(const TypeRef *TR,
874+
unsigned InstanceStart) {
875+
const FieldDescriptor *FD = getBuilder().getFieldTypeInfo(TR);
876+
if (FD == nullptr)
877+
return nullptr;
878+
879+
switch (FD->Kind) {
880+
case FieldDescriptorKind::Class: {
881+
// Lower the class's fields using substitutions from the
882+
// TypeRef to make field types concrete.
883+
RecordTypeInfoBuilder builder(*this, RecordKind::ClassInstance);
884+
auto *ReferenceTI = getTypeInfo(getNativeObjectTypeRef());
885+
if (ReferenceTI == nullptr)
886+
return nullptr;
887+
888+
// Start layout from the given instance start offset.
889+
builder.addField(InstanceStart, ReferenceTI->getAlignment());
890+
891+
for (auto Field : getBuilder().getFieldTypeRefs(TR, FD))
892+
builder.addField(Field.first, Field.second);
893+
return builder.build();
894+
}
895+
case FieldDescriptorKind::Struct:
896+
case FieldDescriptorKind::Enum:
897+
case FieldDescriptorKind::ObjCProtocol:
898+
case FieldDescriptorKind::ClassProtocol:
899+
case FieldDescriptorKind::Protocol:
900+
// Invalid field descriptor.
901+
return nullptr;
902+
}
903+
}

stdlib/public/SwiftRemoteMirror/SwiftRemoteMirror.cpp

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ swift_layout_kind_t getTypeInfoKind(const TypeInfo &TI) {
120120
return SWIFT_CLASS_EXISTENTIAL;
121121
case RecordKind::ExistentialMetatype:
122122
return SWIFT_EXISTENTIAL_METATYPE;
123+
case RecordKind::ClassInstance:
124+
return SWIFT_CLASS_INSTANCE;
123125
}
124126
}
125127
case TypeInfoKind::Reference: {
@@ -138,13 +140,7 @@ swift_layout_kind_t getTypeInfoKind(const TypeInfo &TI) {
138140
}
139141
}
140142

141-
swift_typeinfo_t
142-
swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
143-
swift_typeref_t OpaqueTypeRef) {
144-
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
145-
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
146-
auto TI = Context->getTypeInfo(TR);
147-
143+
static swift_typeinfo_t convertTypeInfo(const TypeInfo *TI) {
148144
if (TI == nullptr) {
149145
return {
150146
SWIFT_UNKNOWN,
@@ -168,14 +164,8 @@ swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
168164
};
169165
}
170166

171-
swift_childinfo_t
172-
swift_reflection_infoForChild(SwiftReflectionContextRef ContextRef,
173-
swift_typeref_t OpaqueTypeRef,
174-
unsigned Index) {
175-
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
176-
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
177-
178-
auto *RecordTI = cast<RecordTypeInfo>(Context->getTypeInfo(TR));
167+
static swift_childinfo_t convertChild(const TypeInfo *TI, unsigned Index) {
168+
auto *RecordTI = cast<RecordTypeInfo>(TI);
179169
auto FieldInfo = RecordTI->getFields()[Index];
180170

181171
return {
@@ -185,3 +175,39 @@ swift_reflection_infoForChild(SwiftReflectionContextRef ContextRef,
185175
reinterpret_cast<swift_typeref_t>(FieldInfo.TR),
186176
};
187177
}
178+
179+
swift_typeinfo_t
180+
swift_reflection_infoForTypeRef(SwiftReflectionContextRef ContextRef,
181+
swift_typeref_t OpaqueTypeRef) {
182+
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
183+
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
184+
auto TI = Context->getTypeInfo(TR);
185+
return convertTypeInfo(TI);
186+
}
187+
188+
swift_childinfo_t
189+
swift_reflection_childOfTypeRef(SwiftReflectionContextRef ContextRef,
190+
swift_typeref_t OpaqueTypeRef,
191+
unsigned Index) {
192+
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
193+
auto TR = reinterpret_cast<const TypeRef *>(OpaqueTypeRef);
194+
auto *TI = Context->getTypeInfo(TR);
195+
return convertChild(TI, Index);
196+
}
197+
198+
swift_typeinfo_t
199+
swift_reflection_infoForMetadata(SwiftReflectionContextRef ContextRef,
200+
uintptr_t Metadata) {
201+
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
202+
auto *TI = Context->getInstanceTypeInfo(Metadata);
203+
return convertTypeInfo(TI);
204+
}
205+
206+
swift_childinfo_t
207+
swift_reflection_childOfMetadata(SwiftReflectionContextRef ContextRef,
208+
uintptr_t Metadata,
209+
unsigned Index) {
210+
auto Context = reinterpret_cast<NativeReflectionContext *>(ContextRef);
211+
auto *TI = Context->getInstanceTypeInfo(Metadata);
212+
return convertChild(TI, Index);
213+
}

tools/swift-reflection-test/swift-reflection-test.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ struct RemoteReflectionInfo {
5656
const StoredPointer StartAddress;
5757
const StoredSize TotalSize;
5858

59+
/// Return the lowest start address, excluding sections with a zero start
60+
/// address, which denotes the section is missing.
5961
static StoredPointer getStartAddress(std::vector<Section<Runtime>> &&elts) {
6062
StoredPointer Start = 0;
6163
for (auto elt : elts) {
@@ -69,6 +71,7 @@ struct RemoteReflectionInfo {
6971
return Start;
7072
}
7173

74+
/// Return the largest end address.
7275
static StoredPointer getEndAddress(std::vector<Section<Runtime>> &&elts) {
7376
StoredPointer End = 0;
7477
for (auto elt : elts) {
@@ -367,7 +370,7 @@ static int doDumpHeapInstance(std::string BinaryFilename) {
367370
auto TR = RC.readTypeFromMetadata(isa);
368371
TR->dump(std::cout, 0);
369372

370-
auto TI = RC.getTypeInfo(isa);
373+
auto TI = RC.getInstanceTypeInfo(isa);
371374
if (TI != nullptr)
372375
TI->dump();
373376
}

0 commit comments

Comments
 (0)