Skip to content

Commit e81fca9

Browse files
committed
Reflection: Use correct starting offset and alignment in class instance layout
Also, add caching for class instance layout.
1 parent ce1c30b commit e81fca9

File tree

5 files changed

+78
-42
lines changed

5 files changed

+78
-42
lines changed

include/swift/Reflection/ReflectionContext.h

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ class ReflectionContext
4040
: public remote::MetadataReader<Runtime, TypeRefBuilder> {
4141
using super = remote::MetadataReader<Runtime, TypeRefBuilder>;
4242

43+
std::unordered_map<typename super::StoredPointer, const TypeInfo *> Cache;
44+
4345
public:
4446
using super::getBuilder;
4547
using super::readTypeFromMetadata;
4648
using typename super::StoredPointer;
4749

48-
public:
49-
5050
explicit ReflectionContext(std::shared_ptr<MemoryReader> reader)
5151
: super(std::move(reader)) {}
5252

@@ -72,28 +72,44 @@ class ReflectionContext
7272
/// Return a description of the layout of a heap object having the given
7373
/// metadata as its isa pointer.
7474
const TypeInfo *getInstanceTypeInfo(StoredPointer MetadataAddress) {
75-
// FIXME: Add caching
75+
// See if we cached the layout already
76+
auto found = Cache.find(MetadataAddress);
77+
if (found != Cache.end())
78+
return found->second;
79+
7680
auto &TC = getBuilder().getTypeConverter();
7781

78-
auto TR = readTypeFromMetadata(MetadataAddress);
79-
if (TR == nullptr)
80-
return nullptr;
82+
const TypeInfo *TI = nullptr;
8183

84+
auto TR = readTypeFromMetadata(MetadataAddress);
8285
auto kind = this->readKindFromMetadata(MetadataAddress);
83-
if (!kind.first)
84-
return nullptr;
85-
86-
switch (kind.second) {
87-
case MetadataKind::Class: {
88-
auto start = this->readInstanceStartFromClassMetadata(MetadataAddress);
89-
if (!start.first)
90-
return nullptr;
91-
auto *TI = TC.getInstanceTypeInfo(TR, start.second);
92-
return TI;
93-
}
94-
default:
95-
return nullptr;
86+
if (TR != nullptr && kind.first) {
87+
switch (kind.second) {
88+
case MetadataKind::Class: {
89+
// Figure out where the stored properties of this class begin
90+
// by looking at the size of the superclass
91+
bool valid;
92+
unsigned size, align;
93+
auto super =
94+
this->readSuperClassFromClassMetadata(MetadataAddress);
95+
if (super) {
96+
std::tie(valid, size, align) =
97+
this->readInstanceSizeAndAlignmentFromClassMetadata(super);
98+
99+
// Perform layout
100+
if (valid)
101+
TI = TC.getInstanceTypeInfo(TR, size, align);
102+
}
103+
break;
104+
}
105+
default:
106+
break;
107+
}
96108
}
109+
110+
// Cache the result for future lookups
111+
Cache[MetadataAddress] = TI;
112+
return TI;
97113
}
98114

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

include/swift/Reflection/TypeLowering.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ class TypeConverter {
180180
///
181181
/// Not cached.
182182
const TypeInfo *getInstanceTypeInfo(const TypeRef *TR,
183-
unsigned InstanceStart);
183+
unsigned start,
184+
unsigned align);
184185

185186
/* Not really public */
186187
const ReferenceTypeInfo *

include/swift/Remote/MetadataReader.h

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -482,27 +482,48 @@ class MetadataReader {
482482
return {true, meta->getKind()};
483483
}
484484

485-
/// Given a remote pointer to class metadata, attempt to discover its class
486-
/// instance start offset.
487-
std::pair<bool, unsigned>
488-
readInstanceStartFromClassMetadata(StoredPointer MetadataAddress) {
485+
/// Given a remote pointer to class metadata, attempt to read its superclass.
486+
StoredPointer
487+
readSuperClassFromClassMetadata(StoredPointer MetadataAddress) {
489488
auto meta = readMetadata(MetadataAddress);
490-
if (!meta)
491-
return {false, 0};
489+
if (!meta || meta->getKind() != MetadataKind::Class)
490+
return StoredPointer();
492491

493-
auto address = readAddressOfNominalTypeDescriptor(meta);
494-
if (!address)
495-
return {false, 0};
492+
auto classMeta = cast<TargetClassMetadata<Runtime>>(meta);
493+
return classMeta->SuperClass;
494+
}
496495

497-
auto descriptor = readNominalTypeDescriptor(address);
498-
if (!descriptor)
499-
return {false, 0};
496+
/// Given a remote pointer to class metadata, attempt to discover its class
497+
/// instance size and alignment.
498+
std::tuple<bool, unsigned, unsigned>
499+
readInstanceSizeAndAlignmentFromClassMetadata(StoredPointer MetadataAddress) {
500+
auto superMeta = readMetadata(MetadataAddress);
501+
if (!superMeta || superMeta->getKind() != MetadataKind::Class)
502+
return {false, 0, 0};
503+
auto super = cast<TargetClassMetadata<Runtime>>(superMeta);
504+
505+
// See swift_initClassMetadata_UniversalStrategy()
506+
uint32_t size, align;
507+
if (super->isTypeMetadata()) {
508+
size = super->getInstanceSize();
509+
align = super->getInstanceAlignMask() + 1;
510+
} else {
511+
// The following algorithm only works on the non-fragile Apple runtime.
512+
513+
// Grab the RO-data pointer. This part is not ABI.
514+
StoredPointer roDataPtr = readObjCRODataPtr(MetadataAddress);
515+
if (!roDataPtr)
516+
return false;
500517

501-
if (descriptor->Class.NumFields == 0)
502-
return {true, sizeof(StoredPointer)};
518+
auto address = roDataPtr + sizeof(uint32_t) * 2;
519+
520+
align = 16; // malloc alignment guarantee
521+
522+
if (!Reader->readInteger(RemoteAddress(address), &size))
523+
return {false, 0, 0};
524+
}
503525

504-
// return {true, meta->getFieldOffsets()[0]};
505-
return {true, sizeof(StoredPointer)};
526+
return {true, size, align};
506527
}
507528

508529
/// Given a remote pointer to metadata, attempt to turn it into a type.

include/swift/Runtime/Metadata.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1659,7 +1659,7 @@ struct TargetClassMetadata : public TargetHeapMetadata<Runtime> {
16591659
Flags = flags;
16601660
}
16611661

1662-
StoredPointer getInstanceSize() const {
1662+
StoredSize getInstanceSize() const {
16631663
assert(isTypeMetadata());
16641664
return InstanceSize;
16651665
}

stdlib/public/Reflection/TypeLowering.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -871,7 +871,8 @@ const TypeInfo *TypeConverter::getTypeInfo(const TypeRef *TR) {
871871
}
872872

873873
const TypeInfo *TypeConverter::getInstanceTypeInfo(const TypeRef *TR,
874-
unsigned InstanceStart) {
874+
unsigned start,
875+
unsigned align) {
875876
const FieldDescriptor *FD = getBuilder().getFieldTypeInfo(TR);
876877
if (FD == nullptr)
877878
return nullptr;
@@ -881,12 +882,9 @@ const TypeInfo *TypeConverter::getInstanceTypeInfo(const TypeRef *TR,
881882
// Lower the class's fields using substitutions from the
882883
// TypeRef to make field types concrete.
883884
RecordTypeInfoBuilder builder(*this, RecordKind::ClassInstance);
884-
auto *ReferenceTI = getTypeInfo(getNativeObjectTypeRef());
885-
if (ReferenceTI == nullptr)
886-
return nullptr;
887885

888886
// Start layout from the given instance start offset.
889-
builder.addField(InstanceStart, ReferenceTI->getAlignment());
887+
builder.addField(start, align);
890888

891889
for (auto Field : getBuilder().getFieldTypeRefs(TR, FD))
892890
builder.addField(Field.first, Field.second);

0 commit comments

Comments
 (0)