Skip to content

Commit c23cc1e

Browse files
authored
Merge pull request #14016 from DougGregor/conformance-descriptor-in-witness-table
[ABI] Add the protocol conformance descriptor into a witness table.
2 parents e625488 + 39f8965 commit c23cc1e

36 files changed

+271
-168
lines changed

include/swift/ABI/MetadataValues.h

+3
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,9 @@ static inline bool isValueWitnessTableMutable(EnumLayoutFlags flags) {
916916
/// mutate the array to fill in the direct arguments.
917917
constexpr unsigned NumDirectGenericTypeMetadataAccessFunctionArgs = 3;
918918

919+
/// The offset (in pointers) to the first requirement in a witness table.
920+
constexpr unsigned WitnessTableFirstRequirementOffset = 1;
921+
919922
} // end namespace swift
920923

921924
#endif /* SWIFT_ABI_METADATAVALUES_H */

include/swift/Runtime/Metadata.h

+33-20
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ class WeakReference;
177177
template <typename Runtime> struct TargetMetadata;
178178
using Metadata = TargetMetadata<InProcess>;
179179

180+
template <typename Runtime> struct TargetProtocolConformanceDescriptor;
181+
180182
/// Storage for an arbitrary value. In C/C++ terms, this is an
181183
/// 'object', because it is rooted in memory.
182184
///
@@ -2204,10 +2206,19 @@ struct TargetProtocolDescriptor {
22042206
};
22052207
using ProtocolDescriptor = TargetProtocolDescriptor<InProcess>;
22062208

2207-
/// A witness table for a protocol. This type is intentionally opaque because
2209+
/// A witness table for a protocol.
2210+
///
2211+
/// With the exception of the initial protocol conformance descriptor,
22082212
/// the layout of a witness table is dependent on the protocol being
22092213
/// represented.
2210-
struct WitnessTable;
2214+
template <typename Runtime>
2215+
struct TargetWitnessTable {
2216+
/// The protocol conformance descriptor from which this witness table
2217+
/// was generated.
2218+
const TargetProtocolConformanceDescriptor<Runtime> *Description;
2219+
};
2220+
2221+
using WitnessTable = TargetWitnessTable<InProcess>;
22112222

22122223
/// The basic layout of an opaque (non-class-bounded) existential type.
22132224
template <typename Runtime>
@@ -2216,12 +2227,13 @@ struct TargetOpaqueExistentialContainer {
22162227
const TargetMetadata<Runtime> *Type;
22172228
// const void *WitnessTables[];
22182229

2219-
const WitnessTable **getWitnessTables() {
2220-
return reinterpret_cast<const WitnessTable **>(this + 1);
2230+
const TargetWitnessTable<Runtime> **getWitnessTables() {
2231+
return reinterpret_cast<const TargetWitnessTable<Runtime> **>(this + 1);
22212232
}
22222233

2223-
const WitnessTable * const *getWitnessTables() const {
2224-
return reinterpret_cast<const WitnessTable * const *>(this + 1);
2234+
const TargetWitnessTable<Runtime> * const *getWitnessTables() const {
2235+
return reinterpret_cast<const TargetWitnessTable<Runtime> * const *>(
2236+
this + 1);
22252237
}
22262238

22272239
void copyTypeInto(swift::TargetOpaqueExistentialContainer<Runtime> *dest,
@@ -2305,8 +2317,9 @@ struct TargetExistentialTypeMetadata : public TargetMetadata<Runtime> {
23052317

23062318
/// Get a witness table from an existential container of the type described
23072319
/// by this metadata.
2308-
const WitnessTable * getWitnessTable(const OpaqueValue *container,
2309-
unsigned i) const;
2320+
const TargetWitnessTable<Runtime> * getWitnessTable(
2321+
const OpaqueValue *container,
2322+
unsigned i) const;
23102323

23112324
/// Return true iff all the protocol constraints are @objc.
23122325
bool isObjC() const {
@@ -2345,11 +2358,11 @@ template <typename Runtime>
23452358
struct TargetExistentialMetatypeContainer {
23462359
const TargetMetadata<Runtime> *Value;
23472360

2348-
const WitnessTable **getWitnessTables() {
2349-
return reinterpret_cast<const WitnessTable**>(this + 1);
2361+
const TargetWitnessTable<Runtime> **getWitnessTables() {
2362+
return reinterpret_cast<const TargetWitnessTable<Runtime>**>(this + 1);
23502363
}
2351-
const WitnessTable * const *getWitnessTables() const {
2352-
return reinterpret_cast<const WitnessTable* const *>(this + 1);
2364+
const TargetWitnessTable<Runtime> * const *getWitnessTables() const {
2365+
return reinterpret_cast<const TargetWitnessTable<Runtime>* const *>(this + 1);
23532366
}
23542367

23552368
void copyTypeInto(TargetExistentialMetatypeContainer *dest,
@@ -2532,10 +2545,10 @@ struct TargetGenericWitnessTable {
25322545
/*nullable*/ true> Protocol;
25332546

25342547
/// The pattern.
2535-
RelativeDirectPointer<const WitnessTable> Pattern;
2548+
RelativeDirectPointer<const TargetWitnessTable<Runtime>> Pattern;
25362549

25372550
/// The instantiation function, which is called after the template is copied.
2538-
RelativeDirectPointer<void(WitnessTable *instantiatedTable,
2551+
RelativeDirectPointer<void(TargetWitnessTable<Runtime> *instantiatedTable,
25392552
const TargetMetadata<Runtime> *type,
25402553
void * const *instantiationArgs),
25412554
/*nullable*/ true> Instantiator;
@@ -2609,9 +2622,9 @@ template <typename Runtime>
26092622
struct TargetProtocolConformanceDescriptor {
26102623
public:
26112624
using WitnessTableAccessorFn
2612-
= const WitnessTable *(const TargetMetadata<Runtime>*,
2613-
const WitnessTable **,
2614-
size_t);
2625+
= const TargetWitnessTable<Runtime> *(const TargetMetadata<Runtime>*,
2626+
const TargetWitnessTable<Runtime> **,
2627+
size_t);
26152628

26162629
private:
26172630
/// The protocol being conformed to.
@@ -2637,7 +2650,7 @@ struct TargetProtocolConformanceDescriptor {
26372650
// The conformance, or a generator function for the conformance.
26382651
union {
26392652
/// A direct reference to the witness table for the conformance.
2640-
RelativeDirectPointer<const WitnessTable> WitnessTable;
2653+
RelativeDirectPointer<const TargetWitnessTable<Runtime>> WitnessTable;
26412654

26422655
/// A function that produces the witness table given an instance of the
26432656
/// type.
@@ -2696,7 +2709,7 @@ struct TargetProtocolConformanceDescriptor {
26962709
}
26972710

26982711
/// Get the directly-referenced static witness table.
2699-
const swift::WitnessTable *getStaticWitnessTable() const {
2712+
const swift::TargetWitnessTable<Runtime> *getStaticWitnessTable() const {
27002713
switch (getConformanceKind()) {
27012714
case ConformanceFlags::ConformanceKind::WitnessTable:
27022715
break;
@@ -2727,7 +2740,7 @@ struct TargetProtocolConformanceDescriptor {
27272740
/// Get the witness table for the specified type, realizing it if
27282741
/// necessary, or return null if the conformance does not apply to the
27292742
/// type.
2730-
const swift::WitnessTable *
2743+
const swift::TargetWitnessTable<Runtime> *
27312744
getWitnessTable(const TargetMetadata<Runtime> *type) const;
27322745

27332746
#if !defined(NDEBUG) && SWIFT_OBJC_INTEROP

include/swift/SIL/SILWitnessVisitor.h

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ template <class T> class SILWitnessVisitor : public ASTVisitor<T> {
4848

4949
public:
5050
void visitProtocolDecl(ProtocolDecl *protocol) {
51+
// The protocol conformance descriptor gets added first.
52+
asDerived().addProtocolConformanceDescriptor();
53+
5154
// Associated types get added after the inherited conformances, but
5255
// before all the function requirements.
5356
bool haveAddedAssociatedTypes = false;

lib/IRGen/GenProto.cpp

+37-14
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,8 @@ namespace {
746746
SmallVector<WitnessTableEntry, 16> Entries;
747747

748748
public:
749+
void addProtocolConformanceDescriptor() { }
750+
749751
/// The next witness is an out-of-line base protocol.
750752
void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) {
751753
Entries.push_back(WitnessTableEntry::forOutOfLineBase(baseProto));
@@ -822,7 +824,7 @@ namespace {
822824
llvm::Value *apply(IRGenFunction &IGF, llvm::Value *wtable) const {
823825
for (unsigned i = ReversePath.size(); i != 0; --i) {
824826
wtable = emitInvariantLoadOfOpaqueWitness(IGF, wtable,
825-
ReversePath[i-1]);
827+
ReversePath[i-1].forProtocolWitnessTable());
826828
wtable = IGF.Builder.CreateBitCast(wtable, IGF.IGM.WitnessTablePtrTy);
827829
}
828830
return wtable;
@@ -1224,6 +1226,18 @@ class AccessorConformanceInfo : public ConformanceInfo {
12241226
/// Create the access function.
12251227
void buildAccessFunction(llvm::Constant *wtable);
12261228

1229+
/// Add reference to the protocol conformance descriptor that generated
1230+
/// this table.
1231+
void addProtocolConformanceDescriptor() {
1232+
if (Conformance.isBehaviorConformance()) {
1233+
Table.addNullPointer(IGM.Int8PtrTy);
1234+
} else {
1235+
auto descriptor =
1236+
IGM.getAddrOfProtocolConformanceDescriptor(&Conformance);
1237+
Table.addBitCast(descriptor, IGM.Int8PtrTy);
1238+
}
1239+
}
1240+
12271241
/// A base protocol is witnessed by a pointer to the conformance
12281242
/// of this type to that protocol.
12291243
void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) {
@@ -1234,7 +1248,8 @@ class AccessorConformanceInfo : public ConformanceInfo {
12341248
assert(entry.getBaseProtocolWitness().Requirement == baseProto
12351249
&& "sil witness table does not match protocol");
12361250
auto piIndex = PI.getBaseIndex(baseProto);
1237-
assert((size_t)piIndex.getValue() == Table.size() &&
1251+
assert((size_t)piIndex.getValue() ==
1252+
Table.size() - WitnessTableFirstRequirementOffset &&
12381253
"offset doesn't match ProtocolInfo layout");
12391254
#endif
12401255

@@ -1279,7 +1294,8 @@ class AccessorConformanceInfo : public ConformanceInfo {
12791294
&& "sil witness table does not match protocol");
12801295
auto piIndex =
12811296
PI.getFunctionIndex(cast<AbstractFunctionDecl>(requirement.getDecl()));
1282-
assert((size_t)piIndex.getValue() == Table.size() &&
1297+
assert((size_t)piIndex.getValue() ==
1298+
Table.size() - WitnessTableFirstRequirementOffset &&
12831299
"offset doesn't match ProtocolInfo layout");
12841300
#endif
12851301

@@ -1310,7 +1326,8 @@ class AccessorConformanceInfo : public ConformanceInfo {
13101326
== requirement.getAssociation()
13111327
&& "sil witness table does not match protocol");
13121328
auto piIndex = PI.getAssociatedTypeIndex(requirement);
1313-
assert((size_t)piIndex.getValue() == Table.size() &&
1329+
assert((size_t)piIndex.getValue() ==
1330+
Table.size() - WitnessTableFirstRequirementOffset &&
13141331
"offset doesn't match ProtocolInfo layout");
13151332
#endif
13161333

@@ -1358,7 +1375,8 @@ class AccessorConformanceInfo : public ConformanceInfo {
13581375
requirement.getAssociatedRequirement()
13591376
&& "sil witness table does not match protocol");
13601377
auto piIndex = PI.getAssociatedConformanceIndex(requirement);
1361-
assert((size_t)piIndex.getValue() == Table.size() &&
1378+
assert((size_t)piIndex.getValue() ==
1379+
Table.size() - WitnessTableFirstRequirementOffset &&
13621380
"offset doesn't match ProtocolInfo layout");
13631381
#endif
13641382

@@ -2057,16 +2075,17 @@ void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) {
20572075

20582076
// Build the witnesses.
20592077
ConstantInitBuilder builder(*this);
2060-
auto witnesses = builder.beginArray(Int8PtrTy);
2061-
WitnessTableBuilder wtableBuilder(*this, witnesses, wt);
2078+
auto wtableContents = builder.beginArray(Int8PtrTy);
2079+
WitnessTableBuilder wtableBuilder(*this, wtableContents, wt);
20622080
wtableBuilder.build();
20632081

2064-
assert(getProtocolInfo(wt->getConformance()->getProtocol())
2065-
.getNumWitnesses() == witnesses.size()
2082+
assert((getProtocolInfo(wt->getConformance()->getProtocol())
2083+
.getNumWitnesses() + WitnessTableFirstRequirementOffset)
2084+
== wtableContents.size()
20662085
&& "witness table size doesn't match ProtocolInfo");
20672086

20682087
// Produce the initializer value.
2069-
auto initializer = witnesses.finishAndCreateFuture();
2088+
auto initializer = wtableContents.finishAndCreateFuture();
20702089

20712090
auto global = cast<llvm::GlobalVariable>(
20722091
getAddrOfWitnessTable(wt->getConformance(), initializer));
@@ -2264,7 +2283,8 @@ emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF,
22642283
llvm::Value *wtable,
22652284
WitnessIndex index,
22662285
llvm::Value *associatedTypeMetadata) {
2267-
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
2286+
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable,
2287+
index.forProtocolWitnessTable());
22682288

22692289
// Cast the witness to the appropriate function type.
22702290
auto sig = IGF.IGM.getAssociatedTypeWitnessTableAccessFunctionSignature();
@@ -2360,7 +2380,8 @@ llvm::Value *MetadataPath::followComponent(IRGenFunction &IGF,
23602380

23612381
if (source) {
23622382
WitnessIndex index(component.getPrimaryIndex(), /*prefix*/ false);
2363-
source = emitInvariantLoadOfOpaqueWitness(IGF, source, index);
2383+
source = emitInvariantLoadOfOpaqueWitness(IGF, source,
2384+
index.forProtocolWitnessTable());
23642385
source = IGF.Builder.CreateBitCast(source, IGF.IGM.WitnessTablePtrTy);
23652386
setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type,
23662387
inheritedProtocol);
@@ -3090,7 +3111,8 @@ irgen::emitWitnessMethodValue(IRGenFunction &IGF,
30903111
auto &fnProtoInfo = IGF.IGM.getProtocolInfo(proto);
30913112
auto index = fnProtoInfo.getFunctionIndex(fn);
30923113
llvm::Value *witnessFnPtr =
3093-
emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
3114+
emitInvariantLoadOfOpaqueWitness(IGF, wtable,
3115+
index.forProtocolWitnessTable());
30943116

30953117
auto fnType = IGF.IGM.getSILTypes().getConstantFunctionType(member);
30963118
Signature signature = IGF.IGM.getSignature(fnType);
@@ -3134,7 +3156,8 @@ llvm::Value *irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF,
31343156
AssociatedType associatedType) {
31353157
auto &pi = IGF.IGM.getProtocolInfo(associatedType.getSourceProtocol());
31363158
auto index = pi.getAssociatedTypeIndex(associatedType);
3137-
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index);
3159+
llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable,
3160+
index.forProtocolWitnessTable());
31383161

31393162
// Cast the witness to the appropriate function type.
31403163
auto sig = IGF.IGM.getAssociatedTypeMetadataAccessFunctionSignature();

lib/IRGen/LocalTypeData.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,8 @@ void IRGenFunction::bindLocalTypeDataFromSelfWitnessTable(
264264
/*prefix*/ false);
265265

266266
auto table =
267-
emitInvariantLoadOfOpaqueWitness(*this, selfTable, wIndex);
267+
emitInvariantLoadOfOpaqueWitness(*this, selfTable,
268+
wIndex.forProtocolWitnessTable());
268269
table = Builder.CreateBitCast(table, IGM.WitnessTablePtrTy);
269270
setProtocolWitnessTableName(IGM, table, archetype, proto);
270271

lib/IRGen/WitnessIndex.h

+10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef SWIFT_IRGEN_WITNESSINDEX_H
1919
#define SWIFT_IRGEN_WITNESSINDEX_H
2020

21+
#include "swift/ABI/MetadataValues.h"
2122
#include "swift/IRGen/ValueWitness.h"
2223

2324
namespace swift {
@@ -38,6 +39,15 @@ class WitnessIndex {
3839
int getValue() const { return Value; }
3940

4041
bool isPrefix() const { return IsPrefix; }
42+
43+
/// Adjust the index to refer into a protocol witness table (rather than
44+
/// a value witness table).
45+
WitnessIndex forProtocolWitnessTable() const {
46+
int NewValue = Value < 0
47+
? Value
48+
: Value + WitnessTableFirstRequirementOffset;
49+
return WitnessIndex(NewValue, IsPrefix);
50+
}
4151
};
4252

4353
} // end namespace irgen

lib/SILGen/SILGenType.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,10 @@ class SILGenConformance : public SILGenWitnessTable<SILGenConformance> {
439439
Entries, ConditionalConformances);
440440
}
441441

442+
void addProtocolConformanceDescriptor() {
443+
}
444+
445+
442446
void addOutOfLineBaseProtocol(ProtocolDecl *baseProtocol) {
443447
assert(Lowering::TypeConverter::protocolRequiresWitnessTable(baseProtocol));
444448

@@ -725,6 +729,8 @@ class SILGenDefaultWitnessTable
725729
DefaultWitnesses.push_back(SILDefaultWitnessTable::Entry());
726730
}
727731

732+
void addProtocolConformanceDescriptor() { }
733+
728734
void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) {
729735
addMissingDefault();
730736
}

stdlib/public/runtime/Casting.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -2682,6 +2682,12 @@ namespace {
26822682

26832683
// protocol _ObjectiveCBridgeable {
26842684
struct _ObjectiveCBridgeableWitnessTable {
2685+
/// The protocol conformance descriptor.
2686+
const void *protocolConformanceDescriptor;
2687+
2688+
static_assert(WitnessTableFirstRequirementOffset == 1,
2689+
"Witness table layout changed");
2690+
26852691
// associatedtype _ObjectiveCType : class
26862692
const Metadata * (*ObjectiveCType)(
26872693
const Metadata *parentMetadata,

stdlib/public/runtime/Metadata.cpp

+9-4
Original file line numberDiff line numberDiff line change
@@ -2749,7 +2749,8 @@ static bool doesNotRequireInstantiation(GenericWitnessTable *genericTable) {
27492749
if (genericTable->Instantiator.isNull() &&
27502750
genericTable->WitnessTablePrivateSizeInWords == 0 &&
27512751
genericTable->WitnessTableSizeInWords ==
2752-
genericTable->Protocol->NumRequirements) {
2752+
(genericTable->Protocol->NumRequirements +
2753+
WitnessTableFirstRequirementOffset)) {
27532754
return true;
27542755
}
27552756

@@ -2770,11 +2771,13 @@ allocateWitnessTable(GenericWitnessTable *genericTable,
27702771

27712772
// The number of mandatory requirements, i.e. requirements lacking
27722773
// default implementations.
2773-
size_t numMandatoryRequirements = protocol->NumMandatoryRequirements;
2774+
size_t numMandatoryRequirements =
2775+
protocol->NumMandatoryRequirements + WitnessTableFirstRequirementOffset;
27742776
assert(numPatternWitnesses >= numMandatoryRequirements);
27752777

27762778
// The total number of requirements.
2777-
size_t numRequirements = protocol->NumRequirements;
2779+
size_t numRequirements =
2780+
protocol->NumRequirements + WitnessTableFirstRequirementOffset;
27782781
assert(numPatternWitnesses <= numRequirements);
27792782

27802783
// Number of bytes for any private storage used by the conformance itself.
@@ -2807,7 +2810,9 @@ allocateWitnessTable(GenericWitnessTable *genericTable,
28072810

28082811
// Fill in any default requirements.
28092812
for (size_t i = numPatternWitnesses, e = numRequirements; i < e; ++i) {
2810-
void *defaultImpl = requirements[i].DefaultImplementation.get();
2813+
size_t requirementIndex = i - WitnessTableFirstRequirementOffset;
2814+
void *defaultImpl =
2815+
requirements[requirementIndex].DefaultImplementation.get();
28112816
assert(defaultImpl &&
28122817
"no default implementation for missing requirement");
28132818
table[i] = defaultImpl;

0 commit comments

Comments
 (0)