Skip to content

Commit fea92a0

Browse files
committed
Runtime: Add support for resilient superclasses
If the nominal type descriptor's resilient superclass flag is set, the generic parameter offset, vtable start offset and field offset start offset are all relative to the start of the class's immedaite members, and not the start of the class metadata. Support this by loading the size of the superclass and adding it to these offsets if the flag is set.
1 parent 22f08f7 commit fea92a0

File tree

4 files changed

+139
-30
lines changed

4 files changed

+139
-30
lines changed

include/swift/Remote/MetadataReader.h

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,35 @@ class MetadataReader {
992992
swift_runtime_unreachable("Unhandled IsaEncodingKind in switch.");
993993
}
994994

995+
/// Read the offset of the generic parameters of a class from the nominal
996+
/// type descriptor. If the class has a resilient superclass, we also
997+
/// have to read the superclass size and add that to the offset.
998+
///
999+
/// The offset is in units of words, from the start of the class's
1000+
/// metadata.
1001+
std::pair<bool, uint32_t>
1002+
readGenericArgsOffset(MetadataRef metadata,
1003+
NominalTypeDescriptorRef descriptor) {
1004+
if (metadata->getKind() == MetadataKind::Class) {
1005+
auto *classMetadata = cast<TargetClassMetadata<Runtime>>(metadata);
1006+
if (classMetadata->SuperClass) {
1007+
auto superMetadata = readMetadata(classMetadata->SuperClass);
1008+
if (!superMetadata)
1009+
return std::make_pair(false, 0);
1010+
1011+
auto result =
1012+
descriptor->GenericParams.getOffset(
1013+
classMetadata,
1014+
cast<TargetClassMetadata<Runtime>>(superMetadata));
1015+
1016+
return std::make_pair(true, result);
1017+
}
1018+
}
1019+
1020+
auto result = descriptor->GenericParams.getOffset();
1021+
return std::make_pair(true, result);
1022+
}
1023+
9951024
/// Read a single generic type argument from a bound generic type
9961025
/// metadata.
9971026
std::pair<bool, StoredPointer>
@@ -1010,11 +1039,14 @@ class MetadataReader {
10101039
return std::make_pair(false, 0);
10111040

10121041
auto numGenericParams = descriptor->GenericParams.NumPrimaryParams;
1013-
auto offsetToGenericArgs =
1014-
sizeof(StoredPointer) * (descriptor->GenericParams.Offset);
1042+
auto offsetToGenericArgs = readGenericArgsOffset(Meta, descriptor);
1043+
if (!offsetToGenericArgs.first)
1044+
return std::make_pair(false, 0);
1045+
10151046
auto addressOfGenericArgAddress =
1016-
Meta.getAddress() + offsetToGenericArgs +
1017-
index * sizeof(StoredPointer);
1047+
(Meta.getAddress() +
1048+
offsetToGenericArgs.second * sizeof(StoredPointer) +
1049+
index * sizeof(StoredPointer));
10181050

10191051
if (index >= numGenericParams)
10201052
return std::make_pair(false, 0);
@@ -1357,10 +1389,13 @@ class MetadataReader {
13571389
std::vector<BuiltType> substitutions;
13581390

13591391
auto numGenericParams = descriptor->GenericParams.NumPrimaryParams;
1360-
auto offsetToGenericArgs =
1361-
sizeof(StoredPointer) * (descriptor->GenericParams.Offset);
1392+
auto offsetToGenericArgs = readGenericArgsOffset(metadata, descriptor);
1393+
if (!offsetToGenericArgs.first)
1394+
return {};
1395+
13621396
auto addressOfGenericArgAddress =
1363-
metadata.getAddress() + offsetToGenericArgs;
1397+
(metadata.getAddress() + sizeof(StoredPointer) *
1398+
offsetToGenericArgs.second);
13641399

13651400
using ArgIndex = decltype(descriptor->GenericParams.NumPrimaryParams);
13661401
for (ArgIndex i = 0; i < numGenericParams;

include/swift/Runtime/Metadata.h

Lines changed: 87 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#if SWIFT_OBJC_INTEROP
4040
#include <objc/runtime.h>
4141
#endif
42+
#include "llvm/Support/Casting.h"
4243

4344
namespace swift {
4445

@@ -1029,13 +1030,22 @@ struct GenericContextDescriptor {
10291030
};
10301031

10311032
/// Header for a generic parameter descriptor.
1032-
struct GenericParameterDescriptorHeader {
1033+
template<typename Runtime>
1034+
struct TargetGenericParameterDescriptorHeader {
1035+
using StoredPointer = typename Runtime::StoredPointer;
1036+
using ClassMetadata = TargetClassMetadata<Runtime>;
1037+
1038+
private:
10331039
/// The offset to the first generic argument from the start of
1034-
/// metadata record.
1040+
/// metadata record, in words.
10351041
///
10361042
/// This is meaningful if NumGenericRequirements is nonzero.
1043+
///
1044+
/// If this class has a resilient superclass, this offset is relative to the
1045+
/// size of the resilient superclass metadata. Otherwise, it is absolute.
10371046
uint32_t Offset;
10381047

1048+
public:
10391049
/// The amount of generic requirement data in the metadata record, in
10401050
/// words, excluding the lexical parent type. A value of zero means
10411051
/// there is no generic requirement data.
@@ -1056,6 +1066,30 @@ struct GenericParameterDescriptorHeader {
10561066
/// Flags for this generic parameter descriptor.
10571067
GenericParameterDescriptorFlags Flags;
10581068

1069+
/// This is factored in a silly way because remote mirrors cannot directly
1070+
/// dereference the SuperClass field of class metadata.
1071+
uint32_t getOffset(const ClassMetadata *classMetadata,
1072+
const ClassMetadata *superMetadata) const {
1073+
if (Flags.hasResilientSuperclass())
1074+
return superMetadata->getSizeInWords() + Offset;
1075+
1076+
return Offset;
1077+
}
1078+
1079+
uint32_t getOffset() const {
1080+
assert(!Flags.hasResilientSuperclass());
1081+
return Offset;
1082+
}
1083+
1084+
uint32_t getOffset(const TargetMetadata<Runtime> *metadata) const {
1085+
if (auto *classMetadata = llvm::dyn_cast<ClassMetadata>(metadata))
1086+
if (auto *superclass = classMetadata->SuperClass)
1087+
if (auto *superMetadata = llvm::dyn_cast<ClassMetadata>(superclass))
1088+
return getOffset(classMetadata, superMetadata);
1089+
1090+
return getOffset();
1091+
}
1092+
10591093
/// True if the nominal type has generic requirements other than its
10601094
/// parent metadata.
10611095
bool hasGenericRequirements() const { return NumGenericRequirements > 0; }
@@ -1080,14 +1114,31 @@ struct TargetMethodDescriptor {
10801114
/// Header for a class vtable descriptor. This is a variable-sized
10811115
/// structure that describes how to find and parse a vtable
10821116
/// within the type metadata for a class.
1083-
struct VTableDescriptorHeader {
1084-
/// The offset of the vtable for this class in its metadata, if any.
1117+
template <typename Runtime>
1118+
struct TargetVTableDescriptorHeader {
1119+
using StoredPointer = typename Runtime::StoredPointer;
1120+
1121+
private:
1122+
/// The offset of the vtable for this class in its metadata, if any,
1123+
/// in words.
1124+
///
1125+
/// If this class has a resilient superclass, this offset is relative to the
1126+
/// size of the resilient superclass metadata. Otherwise, it is absolute.
10851127
uint32_t VTableOffset;
1128+
1129+
public:
10861130
/// The number of vtable entries. This is the number of MethodDescriptor
10871131
/// records following the vtable header in the class's nominal type
10881132
/// descriptor, which is equal to the number of words this subclass's vtable
10891133
/// entries occupy in instantiated class metadata.
10901134
uint32_t VTableSize;
1135+
1136+
uint32_t getVTableOffset(const TargetClassMetadata<Runtime> *metadata) const {
1137+
const auto *description = metadata->getDescription();
1138+
if (description->GenericParams.Flags.hasResilientSuperclass())
1139+
return metadata->SuperClass->getSizeInWords() + VTableOffset;
1140+
return VTableOffset;
1141+
}
10911142
};
10921143

10931144
template<typename Runtime> struct TargetNominalTypeDescriptor;
@@ -1096,7 +1147,7 @@ template<typename Runtime>
10961147
using TargetNominalTypeDescriptorTrailingObjects
10971148
= swift::ABI::TrailingObjects<TargetNominalTypeDescriptor<Runtime>,
10981149
GenericContextDescriptor,
1099-
VTableDescriptorHeader,
1150+
TargetVTableDescriptorHeader<Runtime>,
11001151
TargetMethodDescriptor<Runtime>>;
11011152

11021153
/// Common information about all nominal types. For generic types, this
@@ -1116,6 +1167,9 @@ struct TargetNominalTypeDescriptor final
11161167
public:
11171168
using StoredPointer = typename Runtime::StoredPointer;
11181169
using MethodDescriptor = TargetMethodDescriptor<Runtime>;
1170+
using VTableDescriptorHeader = TargetVTableDescriptorHeader<Runtime>;
1171+
using GenericParameterDescriptorHeader = TargetGenericParameterDescriptorHeader<Runtime>;
1172+
using ClassMetadata = TargetClassMetadata<Runtime>;
11191173

11201174
/// The mangled name of the nominal type.
11211175
TargetRelativeDirectPointer<Runtime, const char> Name;
@@ -1127,19 +1181,22 @@ struct TargetNominalTypeDescriptor final
11271181
/// The number of stored properties in the class, not including its
11281182
/// superclasses. If there is a field offset vector, this is its length.
11291183
uint32_t NumFields;
1184+
1185+
private:
11301186
/// The offset of the field offset vector for this class's stored
1131-
/// properties in its metadata, if any. 0 means there is no field offset
1187+
/// properties in its metadata, in words. 0 means there is no field offset
11321188
/// vector.
11331189
///
1134-
/// To deal with resilient superclasses correctly, this will
1135-
/// eventually need to be relative to the start of this class's
1136-
/// metadata area.
1190+
/// If this class has a resilient superclass, this offset is relative to
1191+
/// the size of the resilient superclass metadata. Otherwise, it is
1192+
/// absolute.
11371193
uint32_t FieldOffsetVectorOffset;
1138-
1194+
1195+
public:
11391196
/// The field names. A doubly-null-terminated list of strings, whose
11401197
/// length and order is consistent with that of the field offset vector.
11411198
RelativeDirectPointer<const char, /*nullable*/ true> FieldNames;
1142-
1199+
11431200
/// The field type vector accessor. Returns a pointer to an array of
11441201
/// type metadata references whose order is consistent with that of the
11451202
/// field offset vector.
@@ -1148,7 +1205,16 @@ struct TargetNominalTypeDescriptor final
11481205

11491206
/// True if metadata records for this type have a field offset vector for
11501207
/// its stored properties.
1151-
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
1208+
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
1209+
1210+
unsigned getFieldOffsetVectorOffset(const ClassMetadata *metadata) const {
1211+
const auto *description = metadata->getDescription();
1212+
1213+
if (description->GenericParams.Flags.hasResilientSuperclass())
1214+
return metadata->SuperClass->getSizeInWords() + FieldOffsetVectorOffset;
1215+
1216+
return FieldOffsetVectorOffset;
1217+
}
11521218
} Class;
11531219

11541220
/// Information about struct types.
@@ -1503,7 +1569,7 @@ struct TargetClassMetadata : public TargetHeapMetadata<Runtime> {
15031569
/// Get a pointer to the field offset vector, if present, or null.
15041570
const StoredPointer *getFieldOffsets() const {
15051571
assert(isTypeMetadata());
1506-
auto offset = getDescription()->Class.FieldOffsetVectorOffset;
1572+
auto offset = getDescription()->Class.getFieldOffsetVectorOffset(this);
15071573
if (offset == 0)
15081574
return nullptr;
15091575
auto asWords = reinterpret_cast<const void * const*>(this);
@@ -1520,6 +1586,13 @@ struct TargetClassMetadata : public TargetHeapMetadata<Runtime> {
15201586
return getter(this);
15211587
}
15221588

1589+
uint32_t getSizeInWords() const {
1590+
assert(isTypeMetadata());
1591+
uint32_t size = getClassSize() - getClassAddressPoint();
1592+
assert(size % sizeof(StoredPointer) == 0);
1593+
return size / sizeof(StoredPointer);
1594+
}
1595+
15231596
static bool classof(const TargetMetadata<Runtime> *metadata) {
15241597
return metadata->getKind() == MetadataKind::Class;
15251598
}
@@ -1768,7 +1841,7 @@ struct TargetValueMetadata : public TargetMetadata<Runtime> {
17681841

17691842
auto asWords = reinterpret_cast<
17701843
ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *>(this);
1771-
return (asWords + Description->GenericParams.Offset);
1844+
return (asWords + Description->GenericParams.getOffset(this));
17721845
}
17731846

17741847
const TargetNominalTypeDescriptor<Runtime> *getDescription() const {

stdlib/public/runtime/Demangle.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ _buildDemanglingForNominalType(const Metadata *type, Demangle::Demangler &Dem) {
166166

167167
auto typeBytes = reinterpret_cast<const char *>(type);
168168
auto genericArgs = reinterpret_cast<const Metadata * const *>(
169-
typeBytes + sizeof(void*) * description->GenericParams.Offset);
169+
typeBytes + sizeof(void*) * description->GenericParams.getOffset(type));
170170

171171
return _applyGenericArguments(genericArgs, description, node,
172172
description->GenericParams.NestingDepth,

stdlib/public/runtime/Metadata.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,7 +1448,8 @@ static void _swift_initializeSuperclass(ClassMetadata *theClass) {
14481448
if (genericParams.Flags.hasVTable()) {
14491449
auto *vtable = description->getVTableDescriptor();
14501450
for (unsigned i = 0, e = vtable->VTableSize; i < e; ++i) {
1451-
classWords[vtable->VTableOffset + i] = description->getMethod(i);
1451+
classWords[vtable->getVTableOffset(theClass) + i]
1452+
= description->getMethod(i);
14521453
}
14531454
}
14541455
}
@@ -1470,23 +1471,23 @@ static void _swift_initializeSuperclass(ClassMetadata *theClass) {
14701471

14711472
// Copy the generic requirements.
14721473
if (genericParams.hasGenericRequirements()) {
1473-
unsigned numParamWords = genericParams.NumGenericRequirements;
1474-
memcpy(classWords + genericParams.Offset,
1475-
superWords + genericParams.Offset,
1476-
numParamWords * sizeof(uintptr_t));
1474+
memcpy(classWords + genericParams.getOffset(ancestor),
1475+
superWords + genericParams.getOffset(ancestor),
1476+
genericParams.NumGenericRequirements * sizeof(uintptr_t));
14771477
}
14781478

14791479
// Copy the vtable entries.
14801480
if (genericParams.Flags.hasVTable()) {
14811481
auto *vtable = description->getVTableDescriptor();
1482-
memcpy(classWords + vtable->VTableOffset,
1483-
superWords + vtable->VTableOffset,
1482+
memcpy(classWords + vtable->getVTableOffset(ancestor),
1483+
superWords + vtable->getVTableOffset(ancestor),
14841484
vtable->VTableSize * sizeof(uintptr_t));
14851485
}
14861486

14871487
// Copy the field offsets.
14881488
if (description->Class.hasFieldOffsetVector()) {
1489-
unsigned fieldOffsetVector = description->Class.FieldOffsetVectorOffset;
1489+
unsigned fieldOffsetVector =
1490+
description->Class.getFieldOffsetVectorOffset(ancestor);
14901491
memcpy(classWords + fieldOffsetVector,
14911492
superWords + fieldOffsetVector,
14921493
description->Class.NumFields * sizeof(uintptr_t));

0 commit comments

Comments
 (0)