Skip to content

Commit 079efad

Browse files
authored
Merge pull request #13687 from slavapestov/class-resilience-part-10
Class resilience part 10
2 parents 1c42337 + 6af8d18 commit 079efad

File tree

14 files changed

+252
-102
lines changed

14 files changed

+252
-102
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,6 @@ namespace swift {
199199
/// accesses.
200200
bool DisableTsanInoutInstrumentation = false;
201201

202-
/// \brief Staging flag for class resilience, which we do not want to enable
203-
/// fully until more code is in place, to allow the standard library to be
204-
/// tested with value type resilience only.
205-
bool EnableClassResilience = false;
206-
207202
/// Should we check the target OSs of serialized modules to see that they're
208203
/// new enough?
209204
bool EnableTargetOSChecking = true;

include/swift/Option/FrontendOptions.td

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -442,10 +442,6 @@ def enable_resilience : Flag<["-"], "enable-resilience">,
442442
HelpText<"Compile the module to export resilient interfaces for all "
443443
"public declarations by default">;
444444

445-
def enable_class_resilience : Flag<["-"], "enable-class-resilience">,
446-
HelpText<"Compile the module to export resilient interfaces for all "
447-
"public classes by default (doesn't work yet)">;
448-
449445
def group_info_path : Separate<["-"], "group-info-path">,
450446
HelpText<"The path to collect the group information of the compiled module">;
451447

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 {

lib/Frontend/CompilerInvocation.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,9 +1011,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
10111011
Opts.EnableExperimentalPropertyBehaviors |=
10121012
Args.hasArg(OPT_enable_experimental_property_behaviors);
10131013

1014-
Opts.EnableClassResilience |=
1015-
Args.hasArg(OPT_enable_class_resilience);
1016-
10171014
if (auto A = Args.getLastArg(OPT_enable_deserialization_recovery,
10181015
OPT_disable_deserialization_recovery)) {
10191016
Opts.EnableDeserializationRecovery

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ template <class Impl> class ClassMetadataVisitor
9393
// Visit the superclass first.
9494
if (Type superclass = type->getSuperclass()) {
9595
auto *superclassDecl = superclass->getClassOrBoundGenericClass();
96-
if (IGM.Context.LangOpts.EnableClassResilience &&
97-
IGM.isResilient(superclassDecl, ResilienceExpansion::Maximal)) {
96+
if (IGM.isResilient(superclassDecl, ResilienceExpansion::Maximal)) {
9897
// Just note that we have a resilient superclass and move on.
9998
//
10099
// Runtime metadata instantiation needs to slide our entries down

lib/IRGen/GenClass.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,14 +295,6 @@ namespace {
295295

296296
// If the superclass is resilient to us, we cannot statically
297297
// know the layout of either its instances or its class objects.
298-
//
299-
// FIXME: We need to implement indirect field/vtable entry access
300-
// before we can enable this
301-
if (!IGM.Context.LangOpts.EnableClassResilience) {
302-
addFieldsForClass(superclass, superclassType);
303-
NumInherited = Elements.size();
304-
}
305-
306298
ClassHasFixedSize = false;
307299

308300
// Furthermore, if the superclass is a generic context, we have to

lib/IRGen/GenMeta.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3529,11 +3529,20 @@ namespace {
35293529
IGF.Builder.CreateBitCast(superMetadata, IGF.IGM.Int8PtrTy),
35303530
IGM.getPointerAlignment());
35313531

3532-
Address slot = IGF.Builder.CreateConstByteArrayGEP(
3532+
Address sizeSlot = IGF.Builder.CreateConstByteArrayGEP(
35333533
metadataAsBytes,
35343534
layout.getMetadataSizeOffset());
3535-
slot = IGF.Builder.CreateBitCast(slot, IGM.Int32Ty->getPointerTo());
3536-
llvm::Value *size = IGF.Builder.CreateLoad(slot);
3535+
sizeSlot = IGF.Builder.CreateBitCast(sizeSlot, IGM.Int32Ty->getPointerTo());
3536+
llvm::Value *size = IGF.Builder.CreateLoad(sizeSlot);
3537+
3538+
Address addressPointSlot = IGF.Builder.CreateConstByteArrayGEP(
3539+
metadataAsBytes,
3540+
layout.getMetadataAddressPointOffset());
3541+
addressPointSlot = IGF.Builder.CreateBitCast(addressPointSlot, IGM.Int32Ty->getPointerTo());
3542+
llvm::Value *addressPoint = IGF.Builder.CreateLoad(addressPointSlot);
3543+
3544+
size = IGF.Builder.CreateSub(size, addressPoint);
3545+
35373546
if (IGM.SizeTy != IGM.Int32Ty)
35383547
size = IGF.Builder.CreateZExt(size, IGM.SizeTy);
35393548

lib/IRGen/MetadataLayout.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,7 @@ ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
251251
// to us, we will access metadata members relative to a base offset.
252252
if (forClass == Target) {
253253
if (Layout.HasResilientSuperclass ||
254-
(IGM.Context.LangOpts.EnableClassResilience &&
255-
IGM.isResilient(forClass, ResilienceExpansion::Maximal))) {
254+
IGM.isResilient(forClass, ResilienceExpansion::Maximal)) {
256255
assert(!DynamicOffsetBase);
257256
DynamicOffsetBase = NextOffset;
258257
}
@@ -264,6 +263,11 @@ ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl)
264263
super::addClassSize();
265264
}
266265

266+
void addClassAddressPoint() {
267+
Layout.MetadataAddressPoint = getNextOffset();
268+
super::addClassAddressPoint();
269+
}
270+
267271
void addInstanceSize() {
268272
Layout.InstanceSize = getNextOffset();
269273
super::addInstanceSize();
@@ -345,6 +349,11 @@ Size ClassMetadataLayout::getMetadataSizeOffset() const {
345349
return MetadataSize.getStaticOffset();
346350
}
347351

352+
Size ClassMetadataLayout::getMetadataAddressPointOffset() const {
353+
assert(MetadataAddressPoint.isStatic());
354+
return MetadataAddressPoint.getStaticOffset();
355+
}
356+
348357
Size ClassMetadataLayout::getInstanceSizeOffset() const {
349358
assert(InstanceSize.isStatic());
350359
return InstanceSize.getStaticOffset();

0 commit comments

Comments
 (0)