Skip to content

Commit efa619a

Browse files
authored
Merge pull request #15443 from slavapestov/protocol-resilience-preliminaries
Protocol resilience preliminaries
2 parents f8f9dca + 982a50a commit efa619a

22 files changed

+155
-125
lines changed

include/swift/ABI/MetadataValues.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,27 @@ static inline bool isValueWitnessTableMutable(StructLayoutFlags flags) {
980980
return uintptr_t(flags) & uintptr_t(StructLayoutFlags::IsVWTMutable);
981981
}
982982

983+
/// Flags for class layout.
984+
enum class ClassLayoutFlags : uintptr_t {
985+
/// Reserve space for 256 layout algorithms.
986+
AlgorithmMask = 0xff,
987+
988+
/// The ABI baseline algorithm, i.e. the algorithm implemented in Swift 5.
989+
Swift5Algorithm = 0x00,
990+
};
991+
static inline ClassLayoutFlags operator|(ClassLayoutFlags lhs,
992+
ClassLayoutFlags rhs) {
993+
return ClassLayoutFlags(uintptr_t(lhs) | uintptr_t(rhs));
994+
}
995+
static inline ClassLayoutFlags &operator|=(ClassLayoutFlags &lhs,
996+
ClassLayoutFlags rhs) {
997+
return (lhs = (lhs | rhs));
998+
}
999+
static inline ClassLayoutFlags getLayoutAlgorithm(ClassLayoutFlags flags) {
1000+
return ClassLayoutFlags(uintptr_t(flags)
1001+
& uintptr_t(ClassLayoutFlags::AlgorithmMask));
1002+
}
1003+
9831004
/// Flags for enum layout.
9841005
enum class EnumLayoutFlags : uintptr_t {
9851006
/// Reserve space for 256 layout algorithms.

include/swift/Runtime/Metadata.h

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1896,11 +1896,27 @@ struct TargetLiteralProtocolDescriptorList
18961896
};
18971897
using LiteralProtocolDescriptorList = TargetProtocolDescriptorList<InProcess>;
18981898

1899+
/// A protocol requirement descriptor. This describes a single protocol
1900+
/// requirement in a protocol descriptor. The index of the requirement in
1901+
/// the descriptor determines the offset of the witness in a witness table
1902+
/// for this protocol.
18991903
template <typename Runtime>
19001904
struct TargetProtocolRequirement {
19011905
ProtocolRequirementFlags Flags;
19021906
// TODO: name, type
19031907

1908+
/// A function pointer to a global symbol which is used by client code
1909+
/// to invoke the protocol requirement from a witness table. This pointer
1910+
/// is also to uniquely identify the requirement in resilient witness
1911+
/// tables, which is why it appears here.
1912+
///
1913+
/// This forms the basis of our mechanism to hide witness table offsets
1914+
/// from clients, both when calling protocol requirements and when
1915+
/// defining witness tables.
1916+
///
1917+
/// Will be null if the protocol is not resilient.
1918+
RelativeDirectPointer<void, /*nullable*/ true> Function;
1919+
19041920
/// The optional default implementation of the protocol.
19051921
RelativeDirectPointer<void, /*nullable*/ true> DefaultImplementation;
19061922
};
@@ -4075,10 +4091,11 @@ swift_relocateClassMetadata(ClassMetadata *self,
40754091
/// Initialize the field offset vector for a dependent-layout class, using the
40764092
/// "Universal" layout strategy.
40774093
SWIFT_RUNTIME_EXPORT
4078-
void swift_initClassMetadata_UniversalStrategy(ClassMetadata *self,
4079-
size_t numFields,
4080-
const TypeLayout * const *fieldTypes,
4081-
size_t *fieldOffsets);
4094+
void swift_initClassMetadata(ClassMetadata *self,
4095+
ClassLayoutFlags flags,
4096+
size_t numFields,
4097+
const TypeLayout * const *fieldTypes,
4098+
size_t *fieldOffsets);
40824099

40834100
/// \brief Fetch a uniqued metadata for a metatype type.
40844101
SWIFT_RUNTIME_EXPORT

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -914,14 +914,15 @@ FUNCTION(RelocateClassMetadata,
914914
ATTRS(NoUnwind))
915915

916916
// struct FieldInfo { size_t Size; size_t AlignMask; };
917-
// void swift_initClassMetadata_UniversalStrategy(Metadata *self,
918-
// size_t numFields,
919-
// TypeLayout * const *fieldTypes,
920-
// size_t *fieldOffsets);
921-
FUNCTION(InitClassMetadataUniversal,
922-
swift_initClassMetadata_UniversalStrategy, C_CC,
923-
RETURNS(VoidTy),
924-
ARGS(TypeMetadataPtrTy, SizeTy,
917+
// void swift_initClassMetadata(Metadata *self,
918+
// ClassLayoutFlags flags,
919+
// size_t numFields,
920+
// TypeLayout * const *fieldTypes,
921+
// size_t *fieldOffsets);
922+
FUNCTION(InitClassMetadata,
923+
swift_initClassMetadata, C_CC,
924+
RETURNS(VoidTy),
925+
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy,
925926
Int8PtrPtrTy->getPointerTo(),
926927
SizeTy->getPointerTo()),
927928
ATTRS(NoUnwind))
@@ -934,7 +935,8 @@ FUNCTION(InitClassMetadataUniversal,
934935
FUNCTION(InitStructMetadata,
935936
swift_initStructMetadata, C_CC,
936937
RETURNS(VoidTy),
937-
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy, Int8PtrPtrTy->getPointerTo(0),
938+
ARGS(TypeMetadataPtrTy, SizeTy, SizeTy,
939+
Int8PtrPtrTy->getPointerTo(0),
938940
SizeTy->getPointerTo()),
939941
ATTRS(NoUnwind))
940942

include/swift/SIL/SILWitnessTable.h

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,20 +84,13 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
8484
ProtocolConformance *Witness;
8585
};
8686

87-
/// A witness table entry for an optional requirement that is not present.
88-
struct MissingOptionalWitness {
89-
/// The witness for the optional requirement that wasn't present.
90-
ValueDecl *Witness;
91-
};
92-
9387
/// A witness table entry kind.
9488
enum WitnessKind {
9589
Invalid,
9690
Method,
9791
AssociatedType,
9892
AssociatedTypeProtocol,
99-
BaseProtocol,
100-
MissingOptional
93+
BaseProtocol
10194
};
10295

10396
/// A witness table entry.
@@ -108,7 +101,6 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
108101
AssociatedTypeWitness AssociatedType;
109102
AssociatedTypeProtocolWitness AssociatedTypeProtocol;
110103
BaseProtocolWitness BaseProtocol;
111-
MissingOptionalWitness MissingOptional;
112104
};
113105

114106
public:
@@ -132,10 +124,6 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
132124
BaseProtocol(BaseProtocol)
133125
{}
134126

135-
Entry(const MissingOptionalWitness &MissingOptional)
136-
: Kind(WitnessKind::MissingOptional), MissingOptional(MissingOptional) {
137-
}
138-
139127
WitnessKind getKind() const { return Kind; }
140128

141129
const MethodWitness &getMethodWitness() const {
@@ -156,11 +144,6 @@ class SILWitnessTable : public llvm::ilist_node<SILWitnessTable>,
156144
return BaseProtocol;
157145
}
158146

159-
const MissingOptionalWitness &getMissingOptionalWitness() const {
160-
assert(Kind == WitnessKind::MissingOptional);
161-
return MissingOptional;
162-
}
163-
164147
void removeWitnessMethod() {
165148
assert(Kind == WitnessKind::Method);
166149
if (Method.Witness) {

lib/IRGen/GenClass.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,9 +1810,8 @@ namespace {
18101810
break;
18111811
}
18121812
case FieldAccess::ConstantIndirect:
1813-
// Otherwise, swift_initClassMetadata_UniversalStrategy() will point
1814-
// the Objective-C runtime into the field offset vector of the
1815-
// instantiated metadata.
1813+
// Otherwise, swift_initClassMetadata() will point the Objective-C
1814+
// runtime into the field offset vector of the instantiated metadata.
18161815
offsetPtr
18171816
= llvm::ConstantPointerNull::get(IGM.IntPtrTy->getPointerTo());
18181817
break;

lib/IRGen/GenDecl.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1633,8 +1633,15 @@ bool LinkEntity::isAvailableExternally(IRGenModule &IGM) const {
16331633
switch (getKind()) {
16341634
case Kind::DispatchThunk:
16351635
case Kind::DispatchThunkInitializer:
1636-
case Kind::DispatchThunkAllocator:
1636+
case Kind::DispatchThunkAllocator: {
1637+
auto *decl = getDecl();
1638+
1639+
// Protocol requirements don't have their own access control
1640+
if (auto *proto = dyn_cast<ProtocolDecl>(decl->getDeclContext()))
1641+
decl = proto;
1642+
16371643
return ::isAvailableExternally(IGM, getDecl());
1644+
}
16381645

16391646
case Kind::ValueWitnessTable:
16401647
case Kind::TypeMetadata:

lib/IRGen/GenMeta.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,9 +1405,11 @@ void irgen::emitInitializeFieldOffsetVector(IRGenFunction &IGF,
14051405
auto numFields = IGF.IGM.getSize(Size(storedProperties.size()));
14061406

14071407
if (isa<ClassDecl>(target)) {
1408-
IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
1409-
{metadata, numFields,
1410-
fields.getAddress(), fieldVector});
1408+
ClassLayoutFlags flags = ClassLayoutFlags::Swift5Algorithm;
1409+
1410+
IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataFn(),
1411+
{metadata, IGF.IGM.getSize(Size(uintptr_t(flags))),
1412+
numFields, fields.getAddress(), fieldVector});
14111413
} else {
14121414
assert(isa<StructDecl>(target));
14131415
StructLayoutFlags flags = StructLayoutFlags::Swift5Algorithm;
@@ -3555,6 +3557,9 @@ namespace {
35553557
// Flags.
35563558
reqt.addInt32(info.Flags.getIntValue());
35573559

3560+
// Dispatch thunk.
3561+
reqt.addRelativeAddressOrNull(info.Thunk);
3562+
35583563
// Default implementation.
35593564
reqt.addRelativeAddressOrNull(info.DefaultImpl);
35603565
#ifndef NDEBUG
@@ -3592,6 +3597,7 @@ namespace {
35923597

35933598
struct RequirementInfo {
35943599
ProtocolRequirementFlags Flags;
3600+
llvm::Constant *Thunk;
35953601
llvm::Constant *DefaultImpl;
35963602
};
35973603

@@ -3601,36 +3607,41 @@ namespace {
36013607
if (entry.isBase()) {
36023608
assert(entry.isOutOfLineBase());
36033609
auto flags = Flags(Flags::Kind::BaseProtocol);
3604-
return { flags, nullptr };
3610+
return { flags, nullptr, nullptr };
36053611
}
36063612

36073613
if (entry.isAssociatedType()) {
36083614
auto flags = Flags(Flags::Kind::AssociatedTypeAccessFunction);
3609-
return { flags, nullptr };
3615+
return { flags, nullptr, nullptr };
36103616
}
36113617

36123618
if (entry.isAssociatedConformance()) {
36133619
auto flags = Flags(Flags::Kind::AssociatedConformanceAccessFunction);
3614-
return { flags, nullptr };
3620+
return { flags, nullptr, nullptr };
36153621
}
36163622

36173623
assert(entry.isFunction());
3618-
auto func = entry.getFunction();
3624+
SILDeclRef func(entry.getFunction());
3625+
3626+
// Look up the dispatch thunk if the protocol is resilient.
3627+
llvm::Constant *thunk = nullptr;
3628+
if (Protocol->isResilient())
3629+
thunk = IGM.getAddrOfDispatchThunk(func, NotForDefinition);
36193630

36203631
// Classify the function.
3621-
auto flags = getMethodDescriptorFlags<Flags>(func);
3632+
auto flags = getMethodDescriptorFlags<Flags>(func.getDecl());
36223633

36233634
// Look for a default witness.
36243635
llvm::Constant *defaultImpl = findDefaultWitness(func);
36253636

3626-
return { flags, defaultImpl };
3637+
return { flags, thunk, defaultImpl };
36273638
}
36283639

3629-
llvm::Constant *findDefaultWitness(AbstractFunctionDecl *func) {
3640+
llvm::Constant *findDefaultWitness(SILDeclRef func) {
36303641
if (!DefaultWitnesses) return nullptr;
36313642

36323643
for (auto &entry : DefaultWitnesses->getResilientDefaultEntries()) {
3633-
if (entry.getRequirement().getDecl() != func)
3644+
if (entry.getRequirement() != func)
36343645
continue;
36353646
return IGM.getAddrOfSILFunction(entry.getWitness(), NotForDefinition);
36363647
}

lib/IRGen/GenProto.cpp

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -730,18 +730,6 @@ void irgen::setProtocolWitnessTableName(IRGenModule &IGM, llvm::Value *wtable,
730730
}
731731

732732
namespace {
733-
/// A concrete witness table, together with its known layout.
734-
class WitnessTable {
735-
llvm::Value *Table;
736-
const ProtocolInfo &Info;
737-
public:
738-
WitnessTable(llvm::Value *wtable, const ProtocolInfo &info)
739-
: Table(wtable), Info(info) {}
740-
741-
llvm::Value *getTable() const { return Table; }
742-
const ProtocolInfo &getInfo() const { return Info; }
743-
};
744-
745733
/// A class which lays out a witness table in the abstract.
746734
class WitnessTableLayout : public SILWitnessVisitor<WitnessTableLayout> {
747735
SmallVector<WitnessTableEntry, 16> Entries;
@@ -1194,8 +1182,7 @@ class AccessorConformanceInfo : public ConformanceInfo {
11941182
: IGM(IGM), Table(table),
11951183
ConcreteType(SILWT->getConformance()->getDeclContext()
11961184
->mapTypeIntoContext(
1197-
SILWT->getConformance()->getType()
1198-
->getCanonicalType())
1185+
SILWT->getConformance()->getType())
11991186
->getCanonicalType()),
12001187
Conformance(*SILWT->getConformance()),
12011188
ConformanceInContext(mapConformanceIntoContext(IGM,
@@ -1271,12 +1258,6 @@ class AccessorConformanceInfo : public ConformanceInfo {
12711258
auto &entry = SILEntries.front();
12721259
SILEntries = SILEntries.slice(1);
12731260

1274-
// Handle missing optional requirements.
1275-
if (entry.getKind() == SILWitnessTable::MissingOptional) {
1276-
Table.addNullPointer(IGM.Int8PtrTy);
1277-
return;
1278-
}
1279-
12801261
#ifndef NDEBUG
12811262
assert(entry.getKind() == SILWitnessTable::Method
12821263
&& "sil witness table does not match protocol");

lib/IRGen/GenThunk.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ IRGenModule::getAddrOfDispatchThunk(SILDeclRef declRef,
5050
Signature signature = getSignature(fnType);
5151
LinkInfo link = LinkInfo::get(*this, entity, forDefinition);
5252

53-
return createFunction(*this, link, signature);
53+
entry = createFunction(*this, link, signature);
54+
return entry;
5455
}
5556

5657
static FunctionPointer lookupMethod(IRGenFunction &IGF,

lib/IRGen/IRGenModule.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ IRGenModule::IRGenModule(IRGenerator &irgen,
217217
ProtocolRequirementStructTy =
218218
createStructType(*this, "swift.protocol_requirement", {
219219
Int32Ty, // flags
220+
Int32Ty, // thunk
220221
Int32Ty // default implementation
221222
});
222223

lib/SIL/SILPrinter.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,13 +2856,6 @@ void SILWitnessTable::print(llvm::raw_ostream &OS, bool Verbose) const {
28562856
baseProtoWitness.Witness->printName(OS, Options);
28572857
break;
28582858
}
2859-
case MissingOptional: {
2860-
// optional requirement 'declref': <<not present>>
2861-
OS << "optional requirement '"
2862-
<< witness.getMissingOptionalWitness().Witness->getBaseName()
2863-
<< "': <<not present>>";
2864-
break;
2865-
}
28662859
}
28672860
OS << '\n';
28682861
}

lib/SIL/SILWitnessTable.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ SILWitnessTable::~SILWitnessTable() {
116116
case AssociatedType:
117117
case AssociatedTypeProtocol:
118118
case BaseProtocol:
119-
case MissingOptional:
120119
case Invalid:
121120
break;
122121
}
@@ -146,7 +145,6 @@ void SILWitnessTable::convertToDefinition(
146145
case AssociatedType:
147146
case AssociatedTypeProtocol:
148147
case BaseProtocol:
149-
case MissingOptional:
150148
case Invalid:
151149
break;
152150
}

lib/SILGen/SILGenType.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -478,16 +478,6 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
478478
IsFreeFunctionWitness_t isFree,
479479
Witness witness) {
480480
// Emit the witness thunk and add it to the table.
481-
482-
// If this is a non-present optional requirement, emit a MissingOptional.
483-
if (!witnessRef) {
484-
auto *fd = requirementRef.getDecl();
485-
assert(fd->getAttrs().hasAttribute<OptionalAttr>() &&
486-
"Non-optional protocol requirement lacks a witness?");
487-
Entries.push_back(SILWitnessTable::MissingOptionalWitness{ fd });
488-
return;
489-
}
490-
491481
auto witnessLinkage = witnessRef.getLinkage(ForDefinition);
492482
auto witnessSerialized = Serialized;
493483
if (witnessSerialized &&

lib/SILOptimizer/IPO/DeadFunctionElimination.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ class FunctionLivenessComputation {
177177
break;
178178

179179
case SILWitnessTable::Invalid:
180-
case SILWitnessTable::MissingOptional:
181180
case SILWitnessTable::AssociatedType:
182181
break;
183182
}

0 commit comments

Comments
 (0)