Skip to content

Commit 1057985

Browse files
authored
Merge pull request #19105 from slavapestov/resilient-method-overrides
Resilient method overrides
2 parents ab04797 + 870c58e commit 1057985

22 files changed

+1006
-632
lines changed

include/swift/ABI/Metadata.h

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -770,14 +770,20 @@ struct TargetHeapMetadata : TargetMetadata<Runtime> {
770770
};
771771
using HeapMetadata = TargetHeapMetadata<InProcess>;
772772

773+
/// An opaque descriptor describing a class or protocol method. References to
774+
/// these descriptors appear in the method override table of a class context
775+
/// descriptor, or a resilient witness table pattern, respectively.
776+
///
777+
/// Clients should not assume anything about the contents of this descriptor
778+
/// other than it having 4 byte alignment.
773779
template <typename Runtime>
774780
struct TargetMethodDescriptor {
775-
/// The method implementation.
776-
TargetRelativeDirectPointer<Runtime, void> Impl;
777-
778781
/// Flags describing the method.
779782
MethodDescriptorFlags Flags;
780783

784+
/// The method implementation.
785+
TargetRelativeDirectPointer<Runtime, void> Impl;
786+
781787
// TODO: add method types or anything else needed for reflection.
782788
};
783789

@@ -804,14 +810,41 @@ struct TargetVTableDescriptorHeader {
804810
/// entries occupy in instantiated class metadata.
805811
uint32_t VTableSize;
806812

807-
uint32_t getVTableOffset(const TargetClassMetadata<Runtime> *metadata) const {
808-
const auto *description = metadata->getDescription();
809-
if (description->hasResilientSuperclass())
810-
return metadata->Superclass->getSizeInWords() + VTableOffset;
813+
uint32_t getVTableOffset(const TargetClassDescriptor<Runtime> *description) const {
814+
if (description->hasResilientSuperclass()) {
815+
auto bounds = description->getMetadataBounds();
816+
return (bounds.ImmediateMembersOffset / sizeof(StoredPointer)
817+
+ VTableOffset);
818+
}
819+
811820
return VTableOffset;
812821
}
813822
};
814823

824+
/// An entry in the method override table, referencing a method from one of our
825+
/// ancestor classes, together with an implementation.
826+
template <typename Runtime>
827+
struct TargetMethodOverrideDescriptor {
828+
/// The class containing the base method.
829+
TargetRelativeIndirectablePointer<Runtime, TargetClassDescriptor<Runtime>> Class;
830+
831+
/// The base method.
832+
TargetRelativeIndirectablePointer<Runtime, TargetMethodDescriptor<Runtime>> Method;
833+
834+
/// The implementation of the override.
835+
TargetRelativeDirectPointer<Runtime, void, /*Nullable=*/true> Impl;
836+
};
837+
838+
/// Header for a class vtable override descriptor. This is a variable-sized
839+
/// structure that provides implementations for overrides of methods defined
840+
/// in superclasses.
841+
template <typename Runtime>
842+
struct TargetOverrideTableHeader {
843+
/// The number of MethodOverrideDescriptor records following the vtable
844+
/// override header in the class's nominal type descriptor.
845+
uint32_t NumEntries;
846+
};
847+
815848
/// The bounds of a class metadata object.
816849
///
817850
/// This type is a currency type and is not part of the ABI.
@@ -1107,7 +1140,7 @@ struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
11071140
/// Get a pointer to the field offset vector, if present, or null.
11081141
const StoredPointer *getFieldOffsets() const {
11091142
assert(isTypeMetadata());
1110-
auto offset = getDescription()->getFieldOffsetVectorOffset(this);
1143+
auto offset = getDescription()->getFieldOffsetVectorOffset();
11111144
if (offset == 0)
11121145
return nullptr;
11131146
auto asWords = reinterpret_cast<const void * const*>(this);
@@ -3580,15 +3613,19 @@ class TargetClassDescriptor final
35803613
TargetForeignMetadataInitialization<Runtime>,
35813614
TargetSingletonMetadataInitialization<Runtime>,
35823615
TargetVTableDescriptorHeader<Runtime>,
3583-
TargetMethodDescriptor<Runtime>> {
3616+
TargetMethodDescriptor<Runtime>,
3617+
TargetOverrideTableHeader<Runtime>,
3618+
TargetMethodOverrideDescriptor<Runtime>> {
35843619
private:
35853620
using TrailingGenericContextObjects =
35863621
TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
35873622
TargetTypeGenericContextDescriptorHeader,
35883623
TargetForeignMetadataInitialization<Runtime>,
35893624
TargetSingletonMetadataInitialization<Runtime>,
35903625
TargetVTableDescriptorHeader<Runtime>,
3591-
TargetMethodDescriptor<Runtime>>;
3626+
TargetMethodDescriptor<Runtime>,
3627+
TargetOverrideTableHeader<Runtime>,
3628+
TargetMethodOverrideDescriptor<Runtime>>;
35923629

35933630
using TrailingObjects =
35943631
typename TrailingGenericContextObjects::TrailingObjects;
@@ -3597,6 +3634,8 @@ class TargetClassDescriptor final
35973634
public:
35983635
using MethodDescriptor = TargetMethodDescriptor<Runtime>;
35993636
using VTableDescriptorHeader = TargetVTableDescriptorHeader<Runtime>;
3637+
using OverrideTableHeader = TargetOverrideTableHeader<Runtime>;
3638+
using MethodOverrideDescriptor = TargetMethodOverrideDescriptor<Runtime>;
36003639
using ForeignMetadataInitialization =
36013640
TargetForeignMetadataInitialization<Runtime>;
36023641
using SingletonMetadataInitialization =
@@ -3707,6 +3746,17 @@ class TargetClassDescriptor final
37073746
return getVTableDescriptor()->VTableSize;
37083747
}
37093748

3749+
size_t numTrailingObjects(OverloadToken<OverrideTableHeader>) const {
3750+
return hasOverrideTable() ? 1 : 0;
3751+
}
3752+
3753+
size_t numTrailingObjects(OverloadToken<MethodOverrideDescriptor>) const {
3754+
if (!hasOverrideTable())
3755+
return 0;
3756+
3757+
return getOverrideTable()->NumEntries;
3758+
}
3759+
37103760
public:
37113761
const ForeignMetadataInitialization &getForeignMetadataInitialization() const{
37123762
assert(this->hasForeignMetadataInitialization());
@@ -3722,11 +3772,12 @@ class TargetClassDescriptor final
37223772
/// its stored properties.
37233773
bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }
37243774

3725-
unsigned getFieldOffsetVectorOffset(const ClassMetadata *metadata) const {
3726-
const auto *description = metadata->getDescription();
3727-
3728-
if (description->hasResilientSuperclass())
3729-
return metadata->Superclass->getSizeInWords() + FieldOffsetVectorOffset;
3775+
unsigned getFieldOffsetVectorOffset() const {
3776+
if (hasResilientSuperclass()) {
3777+
auto bounds = getMetadataBounds();
3778+
return (bounds.ImmediateMembersOffset / sizeof(StoredPointer)
3779+
+ FieldOffsetVectorOffset);
3780+
}
37303781

37313782
return FieldOffsetVectorOffset;
37323783
}
@@ -3735,6 +3786,10 @@ class TargetClassDescriptor final
37353786
return this->getTypeContextDescriptorFlags().class_hasVTable();
37363787
}
37373788

3789+
bool hasOverrideTable() const {
3790+
return this->getTypeContextDescriptorFlags().class_hasOverrideTable();
3791+
}
3792+
37383793
bool hasResilientSuperclass() const {
37393794
return this->getTypeContextDescriptorFlags().class_hasResilientSuperclass();
37403795
}
@@ -3744,14 +3799,27 @@ class TargetClassDescriptor final
37443799
return nullptr;
37453800
return this->template getTrailingObjects<VTableDescriptorHeader>();
37463801
}
3747-
3802+
37483803
llvm::ArrayRef<MethodDescriptor> getMethodDescriptors() const {
37493804
if (!hasVTable())
37503805
return {};
37513806
return {this->template getTrailingObjects<MethodDescriptor>(),
37523807
numTrailingObjects(OverloadToken<MethodDescriptor>{})};
37533808
}
37543809

3810+
const OverrideTableHeader *getOverrideTable() const {
3811+
if (!hasOverrideTable())
3812+
return nullptr;
3813+
return this->template getTrailingObjects<OverrideTableHeader>();
3814+
}
3815+
3816+
llvm::ArrayRef<MethodOverrideDescriptor> getMethodOverrideDescriptors() const {
3817+
if (!hasOverrideTable())
3818+
return {};
3819+
return {this->template getTrailingObjects<MethodOverrideDescriptor>(),
3820+
numTrailingObjects(OverloadToken<MethodOverrideDescriptor>{})};
3821+
}
3822+
37553823
/// Return the bounds of this class's metadata.
37563824
TargetClassMetadataBounds<Runtime> getMetadataBounds() const {
37573825
if (!hasResilientSuperclass())

include/swift/ABI/MetadataValues.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,19 +1245,23 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
12451245
/// descriptor. A TypeReferenceKind.
12461246
///
12471247
/// Only meaningful for class descriptors.
1248-
Class_SuperclassReferenceKind = 10,
1248+
Class_SuperclassReferenceKind = 9,
12491249
Class_SuperclassReferenceKind_width = 3,
12501250

12511251
/// Whether the immediate class members in this metadata are allocated
12521252
/// at negative offsets. For now, we don't use this.
1253-
Class_AreImmediateMembersNegative = 13,
1253+
Class_AreImmediateMembersNegative = 12,
12541254

12551255
/// Set if the context descriptor is for a class with resilient ancestry.
12561256
///
12571257
/// Only meaningful for class descriptors.
1258-
Class_HasResilientSuperclass = 14,
1258+
Class_HasResilientSuperclass = 13,
12591259

1260-
/// Set if the context descriptor is includes metadata for dynamically
1260+
/// Set if the context descriptor includes metadata for dynamically
1261+
/// installing method overrides at metadata instantiation time.
1262+
Class_HasOverrideTable = 14,
1263+
1264+
/// Set if the context descriptor includes metadata for dynamically
12611265
/// constructing a class's vtables at metadata instantiation time.
12621266
///
12631267
/// Only meaningful for class descriptors.
@@ -1305,6 +1309,9 @@ class TypeContextDescriptorFlags : public FlagSet<uint16_t> {
13051309
FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasVTable,
13061310
class_hasVTable,
13071311
class_setHasVTable)
1312+
FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasOverrideTable,
1313+
class_hasOverrideTable,
1314+
class_setHasOverrideTable)
13081315
FLAGSET_DEFINE_FLAG_ACCESSORS(Class_HasResilientSuperclass,
13091316
class_hasResilientSuperclass,
13101317
class_setHasResilientSuperclass)

0 commit comments

Comments
 (0)