Skip to content

Commit 5534eb4

Browse files
committed
[DefaultOverides] Install in vtables at runtime.
1 parent ddb89af commit 5534eb4

File tree

3 files changed

+388
-7
lines changed

3 files changed

+388
-7
lines changed

include/swift/ABI/Metadata.h

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,54 @@ using TargetRelativeProtocolRequirementPointer =
654654
using RelativeProtocolRequirementPointer =
655655
TargetRelativeProtocolRequirementPointer<InProcess>;
656656

657+
/// An entry in the default override table, consisting of one of our methods
658+
/// `replacement` together with (1) another of our methods `original` which
659+
/// might have been overridden by a subclass and (2) an implementation of
660+
/// `replacement` to be used by such a subclass if it does not provide its own
661+
/// implementation.
662+
template <typename Runtime>
663+
struct TargetMethodDefaultOverrideDescriptor {
664+
/// The method which replaced the original at call-sites.
665+
TargetRelativeMethodDescriptorPointer<Runtime> Replacement;
666+
667+
/// The method originally called at such call sites.
668+
TargetRelativeMethodDescriptorPointer<Runtime> Original;
669+
670+
union {
671+
TargetCompactFunctionPointer<Runtime, void, /*nullable*/ true> Impl;
672+
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> AsyncImpl;
673+
TargetRelativeDirectPointer<Runtime, void, /*nullable*/ true> CoroImpl;
674+
};
675+
676+
bool isData() const {
677+
auto *replacement = Replacement.get();
678+
assert(replacement && "no replacement");
679+
return replacement->Flags.isData();
680+
}
681+
682+
void *getImpl() const {
683+
auto *replacement = Replacement.get();
684+
assert(replacement && "no replacement");
685+
if (replacement->Flags.isAsync()) {
686+
return AsyncImpl.get();
687+
} else if (replacement->Flags.isCalleeAllocatedCoroutine()) {
688+
return CoroImpl.get();
689+
} else {
690+
return Impl.get();
691+
}
692+
}
693+
};
694+
695+
/// Header for a table of default override descriptors. Such a table is a
696+
/// variable-sized structure whose length is stored in this header which is
697+
/// followed by that many TargetMethodDefaultOverrideDescriptors.
698+
template <typename Runtime>
699+
struct TargetMethodDefaultOverrideTableHeader {
700+
/// The number of TargetMethodDefaultOverrideDescriptor records following this
701+
/// header in the class's nominal type descriptor.
702+
uint32_t NumEntries;
703+
};
704+
657705
/// An entry in the method override table, referencing a method from one of our
658706
/// ancestor classes, together with an implementation.
659707
template <typename Runtime>
@@ -4205,9 +4253,11 @@ class swift_ptrauth_struct_context_descriptor(ClassDescriptor)
42054253
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
42064254
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>,
42074255
InvertibleProtocolSet,
4208-
TargetSingletonMetadataPointer<Runtime>> {
4256+
TargetSingletonMetadataPointer<Runtime>,
4257+
TargetMethodDefaultOverrideTableHeader<Runtime>,
4258+
TargetMethodDefaultOverrideDescriptor<Runtime>> {
42094259
private:
4210-
using TrailingGenericContextObjects =
4260+
using TrailingGenericContextObjects =
42114261
swift::TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
42124262
TargetTypeGenericContextDescriptorHeader,
42134263
TargetResilientSuperclass<Runtime>,
@@ -4223,7 +4273,9 @@ class swift_ptrauth_struct_context_descriptor(ClassDescriptor)
42234273
TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
42244274
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>,
42254275
InvertibleProtocolSet,
4226-
TargetSingletonMetadataPointer<Runtime>>;
4276+
TargetSingletonMetadataPointer<Runtime>,
4277+
TargetMethodDefaultOverrideTableHeader<Runtime>,
4278+
TargetMethodDefaultOverrideDescriptor<Runtime>>;
42274279

42284280
using TrailingObjects =
42294281
typename TrailingGenericContextObjects::TrailingObjects;
@@ -4254,6 +4306,10 @@ class swift_ptrauth_struct_context_descriptor(ClassDescriptor)
42544306
using MetadataCachingOnceToken =
42554307
TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>;
42564308
using SingletonMetadataPointer = TargetSingletonMetadataPointer<Runtime>;
4309+
using DefaultOverrideTableHeader =
4310+
TargetMethodDefaultOverrideTableHeader<Runtime>;
4311+
using DefaultOverrideDescriptor =
4312+
TargetMethodDefaultOverrideDescriptor<Runtime>;
42574313

42584314
using StoredPointer = typename Runtime::StoredPointer;
42594315
using StoredPointerDifference = typename Runtime::StoredPointerDifference;
@@ -4399,6 +4455,16 @@ class swift_ptrauth_struct_context_descriptor(ClassDescriptor)
43994455
return this->hasSingletonMetadataPointer() ? 1 : 0;
44004456
}
44014457

4458+
size_t numTrailingObjects(OverloadToken<DefaultOverrideTableHeader>) const {
4459+
return hasDefaultOverrideTable() ? 1 : 0;
4460+
}
4461+
4462+
size_t numTrailingObjects(OverloadToken<DefaultOverrideDescriptor>) const {
4463+
if (!hasDefaultOverrideTable())
4464+
return 0;
4465+
return getDefaultOverrideTable()->NumEntries;
4466+
}
4467+
44024468
public:
44034469
const TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> &
44044470
getResilientSuperclass() const {
@@ -4430,6 +4496,10 @@ class swift_ptrauth_struct_context_descriptor(ClassDescriptor)
44304496
return FieldOffsetVectorOffset;
44314497
}
44324498

4499+
bool hasDefaultOverrideTable() const {
4500+
return getTypeContextDescriptorFlags().class_hasDefaultOverrideTable();
4501+
}
4502+
44334503
bool isActor() const {
44344504
return this->getTypeContextDescriptorFlags().class_isActor();
44354505
}
@@ -4476,6 +4546,20 @@ class swift_ptrauth_struct_context_descriptor(ClassDescriptor)
44764546
numTrailingObjects(OverloadToken<MethodOverrideDescriptor>{})};
44774547
}
44784548

4549+
const DefaultOverrideTableHeader *getDefaultOverrideTable() const {
4550+
if (!hasDefaultOverrideTable())
4551+
return nullptr;
4552+
return this->template getTrailingObjects<DefaultOverrideTableHeader>();
4553+
}
4554+
4555+
llvm::ArrayRef<DefaultOverrideDescriptor> getDefaultOverrideDescriptors()
4556+
const {
4557+
if (!hasDefaultOverrideTable())
4558+
return {};
4559+
return {this->template getTrailingObjects<DefaultOverrideDescriptor>(),
4560+
numTrailingObjects(OverloadToken<DefaultOverrideDescriptor>{})};
4561+
}
4562+
44794563
/// Return the bounds of this class's metadata.
44804564
TargetClassMetadataBounds<Runtime> getMetadataBounds() const {
44814565
if (!hasResilientSuperclass())

stdlib/public/runtime/Metadata.cpp

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3682,9 +3682,11 @@ static void installOverrideInVTable(ContextDescriptor const *baseContext,
36823682
}
36833683

36843684
/// Using the information in the class context descriptor, fill in in the
3685-
/// immediate vtable entries for the class and install overrides of any
3686-
/// superclass vtable entries.
3687-
static void initClassVTable(ClassMetadata *self) {
3685+
/// immediate vtable entries for the class install overrides of any
3686+
/// superclass vtable entries, and install any default overrides if appropriate.
3687+
static void initClassVTable(ClassMetadata *self,
3688+
llvm::SmallVectorImpl<const ClassDescriptor *>
3689+
&superclassesWithDefaultOverrides) {
36883690
const auto *description = self->getDescription();
36893691
auto *classWords = reinterpret_cast<void **>(self);
36903692

@@ -3706,14 +3708,46 @@ static void initClassVTable(ClassMetadata *self) {
37063708
return;
37073709
}
37083710

3711+
auto hasSuperclassWithDefaultOverride =
3712+
superclassesWithDefaultOverrides.size() > 0;
3713+
std::unordered_set<const MethodDescriptor *> seenDescriptors;
3714+
3715+
// Install our overrides.
37093716
auto *overrideTable = description->getOverrideTable();
37103717
auto overrideDescriptors = description->getMethodOverrideDescriptors();
37113718
for (auto &descriptor : overrideDescriptors) {
3719+
if (hasSuperclassWithDefaultOverride)
3720+
seenDescriptors.insert(descriptor.Method);
3721+
37123722
installOverrideInVTable(
37133723
descriptor.Class.get(), descriptor.Method.get(),
37143724
[&descriptor]() { return descriptor.getImpl(); }, overrideTable,
37153725
classWords);
37163726
}
3727+
3728+
if (!hasSuperclassWithDefaultOverride) {
3729+
// No ancestor had default overrides to consider, so we're done.
3730+
return;
3731+
}
3732+
3733+
// Install any necessary default overrides.
3734+
for (auto *description : superclassesWithDefaultOverrides) {
3735+
assert(description->hasDefaultOverrideTable());
3736+
auto *header = description->getDefaultOverrideTable();
3737+
assert(header->NumEntries > 0 && "default override table with 0 entries");
3738+
auto entries = description->getDefaultOverrideDescriptors();
3739+
for (auto &entry : entries) {
3740+
auto *original = entry.Original.get();
3741+
if (!seenDescriptors.count(original))
3742+
continue;
3743+
auto *replacement = entry.Replacement.get();
3744+
if (seenDescriptors.count(replacement))
3745+
continue;
3746+
installOverrideInVTable(
3747+
description, replacement, [&entry]() { return entry.getImpl(); },
3748+
header, classWords);
3749+
}
3750+
}
37173751
}
37183752

37193753
static void initClassFieldOffsetVector(ClassMetadata *self,
@@ -4059,6 +4093,7 @@ _swift_initClassMetadataImpl(ClassMetadata *self,
40594093
auto superDependencyAndSuper = getSuperclassMetadata(self, allowDependency);
40604094
if (superDependencyAndSuper.first)
40614095
return superDependencyAndSuper.first;
4096+
40624097
auto super = superDependencyAndSuper.second;
40634098

40644099
self->Superclass = super;
@@ -4079,14 +4114,36 @@ _swift_initClassMetadataImpl(ClassMetadata *self,
40794114
nullptr);
40804115
#endif
40814116

4117+
// To populate the vtable, we must check our ancestors for default overloads.
4118+
// We may obstructed by dependencies, however, so do it now before doing any
4119+
// setup.
4120+
llvm::SmallVector<const ClassDescriptor *, 16>
4121+
superclassesWithDefaultOverrides;
4122+
if (self->getDescription()->hasOverrideTable()) {
4123+
const ClassMetadata *super = superDependencyAndSuper.second;
4124+
while (super && !super->isPureObjC()) {
4125+
const auto *description = super->getDescription();
4126+
if (description->hasDefaultOverrideTable()) {
4127+
// This superclass has default overrides. Record it for later
4128+
// traversal.
4129+
superclassesWithDefaultOverrides.push_back(description);
4130+
}
4131+
auto superDependencyAndSuper =
4132+
getSuperclassMetadata(super, allowDependency);
4133+
if (superDependencyAndSuper.first)
4134+
return superDependencyAndSuper.first;
4135+
super = superDependencyAndSuper.second;
4136+
}
4137+
}
4138+
40824139
// Copy field offsets, generic arguments and (if necessary) vtable entries
40834140
// from our superclass.
40844141
copySuperclassMetadataToSubclass(self, layoutFlags);
40854142

40864143
// Copy the class's immediate methods from the nominal type descriptor
40874144
// to the class metadata.
40884145
if (!hasStaticVTable(layoutFlags))
4089-
initClassVTable(self);
4146+
initClassVTable(self, superclassesWithDefaultOverrides);
40904147

40914148
initClassFieldOffsetVector(self, numFields, fieldTypes, fieldOffsets);
40924149

0 commit comments

Comments
 (0)