Skip to content

Commit 982a50a

Browse files
committed
Runtime: Add protocol dispatch thunk to requirement descriptor
These will be used as lookup keys for order-independent witness table instantiation. In the future, a reflective call mechanism could make use of this metadata as well.
1 parent b7ff05d commit 982a50a

File tree

5 files changed

+82
-30
lines changed

5 files changed

+82
-30
lines changed

include/swift/Runtime/Metadata.h

Lines changed: 16 additions & 0 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
};

lib/IRGen/GenMeta.cpp

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3557,6 +3557,9 @@ namespace {
35573557
// Flags.
35583558
reqt.addInt32(info.Flags.getIntValue());
35593559

3560+
// Dispatch thunk.
3561+
reqt.addRelativeAddressOrNull(info.Thunk);
3562+
35603563
// Default implementation.
35613564
reqt.addRelativeAddressOrNull(info.DefaultImpl);
35623565
#ifndef NDEBUG
@@ -3594,6 +3597,7 @@ namespace {
35943597

35953598
struct RequirementInfo {
35963599
ProtocolRequirementFlags Flags;
3600+
llvm::Constant *Thunk;
35973601
llvm::Constant *DefaultImpl;
35983602
};
35993603

@@ -3603,36 +3607,41 @@ namespace {
36033607
if (entry.isBase()) {
36043608
assert(entry.isOutOfLineBase());
36053609
auto flags = Flags(Flags::Kind::BaseProtocol);
3606-
return { flags, nullptr };
3610+
return { flags, nullptr, nullptr };
36073611
}
36083612

36093613
if (entry.isAssociatedType()) {
36103614
auto flags = Flags(Flags::Kind::AssociatedTypeAccessFunction);
3611-
return { flags, nullptr };
3615+
return { flags, nullptr, nullptr };
36123616
}
36133617

36143618
if (entry.isAssociatedConformance()) {
36153619
auto flags = Flags(Flags::Kind::AssociatedConformanceAccessFunction);
3616-
return { flags, nullptr };
3620+
return { flags, nullptr, nullptr };
36173621
}
36183622

36193623
assert(entry.isFunction());
3620-
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);
36213630

36223631
// Classify the function.
3623-
auto flags = getMethodDescriptorFlags<Flags>(func);
3632+
auto flags = getMethodDescriptorFlags<Flags>(func.getDecl());
36243633

36253634
// Look for a default witness.
36263635
llvm::Constant *defaultImpl = findDefaultWitness(func);
36273636

3628-
return { flags, defaultImpl };
3637+
return { flags, thunk, defaultImpl };
36293638
}
36303639

3631-
llvm::Constant *findDefaultWitness(AbstractFunctionDecl *func) {
3640+
llvm::Constant *findDefaultWitness(SILDeclRef func) {
36323641
if (!DefaultWitnesses) return nullptr;
36333642

36343643
for (auto &entry : DefaultWitnesses->getResilientDefaultEntries()) {
3635-
if (entry.getRequirement().getDecl() != func)
3644+
if (entry.getRequirement() != func)
36363645
continue;
36373646
return IGM.getAddrOfSILFunction(entry.getWitness(), NotForDefinition);
36383647
}

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

test/IRGen/protocol_metadata.swift

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,9 @@ protocol ABO : A, B, O { func abo() }
4747
// CHECK-SAME: @_PROTOCOL_METHOD_TYPES__TtP17protocol_metadata1O_
4848
// CHECK-SAME: }
4949

50-
// CHECK: [[A_REQTS]] = internal unnamed_addr constant [1 x %swift.protocol_requirement] [%swift.protocol_requirement { i32 17, i32 0 }]
51-
// CHECK: [[B_REQTS]] = internal unnamed_addr constant [1 x %swift.protocol_requirement] [%swift.protocol_requirement { i32 17, i32 0 }]
52-
// CHECK: [[C_REQTS]] = internal unnamed_addr constant [1 x %swift.protocol_requirement] [%swift.protocol_requirement { i32 17, i32 0 }]
50+
// CHECK: [[A_REQTS]] = internal unnamed_addr constant [1 x %swift.protocol_requirement] [%swift.protocol_requirement { i32 17, i32 0, i32 0 }]
51+
// CHECK: [[B_REQTS]] = internal unnamed_addr constant [1 x %swift.protocol_requirement] [%swift.protocol_requirement { i32 17, i32 0, i32 0 }]
52+
// CHECK: [[C_REQTS]] = internal unnamed_addr constant [1 x %swift.protocol_requirement] [%swift.protocol_requirement { i32 17, i32 0, i32 0 }]
5353

5454
// -- @objc protocol OPT uses ObjC symbol mangling and layout
5555
// CHECK: @_PROTOCOL__TtP17protocol_metadata3OPT_ = private constant { {{.*}} i32, [4 x i8*]*, i8*, i8* } {
@@ -67,7 +67,7 @@ protocol ABO : A, B, O { func abo() }
6767
// CHECK: %swift.protocol* @"$S17protocol_metadata1AMp",
6868
// CHECK: %swift.protocol* @"$S17protocol_metadata1BMp"
6969
// CHECK: }
70-
// CHECK: [[AB_REQTS:@.*]] = internal unnamed_addr constant [3 x %swift.protocol_requirement] [%swift.protocol_requirement zeroinitializer, %swift.protocol_requirement zeroinitializer, %swift.protocol_requirement { i32 17, i32 0 }]
70+
// CHECK: [[AB_REQTS:@.*]] = internal unnamed_addr constant [3 x %swift.protocol_requirement] [%swift.protocol_requirement zeroinitializer, %swift.protocol_requirement zeroinitializer, %swift.protocol_requirement { i32 17, i32 0, i32 0 }]
7171
// CHECK: @"$S17protocol_metadata2ABMp" = hidden constant %swift.protocol {
7272
// CHECK-SAME: [[AB_INHERITED]]
7373
// CHECK-SAME: i32 72, i32 7,
@@ -92,17 +92,17 @@ protocol Comprehensive {
9292
}
9393

9494
// CHECK: [[COMPREHENSIVE_REQTS:@.*]] = internal unnamed_addr constant [11 x %swift.protocol_requirement]
95-
// CHECK-SAME: [%swift.protocol_requirement { i32 6, i32 0 },
96-
// CHECK-SAME: %swift.protocol_requirement { i32 7, i32 0 },
97-
// CHECK-SAME: %swift.protocol_requirement { i32 2, i32 0 },
98-
// CHECK-SAME: %swift.protocol_requirement { i32 17, i32 0 },
99-
// CHECK-SAME: %swift.protocol_requirement { i32 1, i32 0 },
100-
// CHECK-SAME: %swift.protocol_requirement { i32 19, i32 0 },
101-
// CHECK-SAME: %swift.protocol_requirement { i32 20, i32 0 },
102-
// CHECK-SAME: %swift.protocol_requirement { i32 21, i32 0 },
103-
// CHECK-SAME: %swift.protocol_requirement { i32 3, i32 0 },
104-
// CHECK-SAME: %swift.protocol_requirement { i32 4, i32 0 },
105-
// CHECK-SAME: %swift.protocol_requirement { i32 5, i32 0 }]
95+
// CHECK-SAME: [%swift.protocol_requirement { i32 6, i32 0, i32 0 },
96+
// CHECK-SAME: %swift.protocol_requirement { i32 7, i32 0, i32 0 },
97+
// CHECK-SAME: %swift.protocol_requirement { i32 2, i32 0, i32 0 },
98+
// CHECK-SAME: %swift.protocol_requirement { i32 17, i32 0, i32 0 },
99+
// CHECK-SAME: %swift.protocol_requirement { i32 1, i32 0, i32 0 },
100+
// CHECK-SAME: %swift.protocol_requirement { i32 19, i32 0, i32 0 },
101+
// CHECK-SAME: %swift.protocol_requirement { i32 20, i32 0, i32 0 },
102+
// CHECK-SAME: %swift.protocol_requirement { i32 21, i32 0, i32 0 },
103+
// CHECK-SAME: %swift.protocol_requirement { i32 3, i32 0, i32 0 },
104+
// CHECK-SAME: %swift.protocol_requirement { i32 4, i32 0, i32 0 },
105+
// CHECK-SAME: %swift.protocol_requirement { i32 5, i32 0, i32 0 }]
106106

107107
// CHECK: [[COMPREHENSIVE_ASSOC_NAME:@.*]] = private constant [6 x i8] c"Assoc\00"
108108

test/IRGen/protocol_resilience.sil

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,39 @@ import resilient_protocol
1515
// Protocol is public -- needs resilient witness table
1616

1717
// CHECK: [[RP_REQTS:@.*]] = internal unnamed_addr constant [8 x %swift.protocol_requirement]
18-
// CHECK-SAME: [%swift.protocol_requirement { i32 6, i32 0 },
19-
// CHECK-SAME: %swift.protocol_requirement { i32 7, i32 0 },
20-
// CHECK-SAME: %swift.protocol_requirement { i32 17, i32 0 },
21-
// CHECK-SAME: %swift.protocol_requirement { i32 17, i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @defaultC to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 4, i32 1) to [[INT]])){{ | to i32\) }}},
22-
// CHECK-SAME: %swift.protocol_requirement { i32 17, i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @defaultD to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 5, i32 1) to [[INT]])){{ | to i32\) }}},
23-
// CHECK-SAME: %swift.protocol_requirement { i32 1, i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @defaultE to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 6, i32 1) to [[INT]])){{ | to i32\) }}},
24-
// CHECK-SAME: %swift.protocol_requirement { i32 1, i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @defaultF to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 7, i32 1) to [[INT]])){{ | to i32\) }}}]
18+
// CHECK-SAME: [%swift.protocol_requirement { i32 6, i32 0, i32 0 },
19+
// CHECK-SAME: %swift.protocol_requirement { i32 7, i32 0, i32 0 },
20+
21+
// CHECK-SAME: %swift.protocol_requirement { i32 17,
22+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @"$S19protocol_resilience17ResilientProtocolP10noDefaultAyyFTj" to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 2, i32 1) to [[INT]])){{ | to i32\) }}
23+
// CHECK-SAME: i32 0
24+
// CHECK-SAME: },
25+
26+
// CHECK-SAME: %swift.protocol_requirement { i32 17,
27+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @"$S19protocol_resilience17ResilientProtocolP10noDefaultByyFTj" to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 3, i32 1) to [[INT]])){{ | to i32\) }}
28+
// CHECK-SAME: i32 0
29+
// CHECK-SAME: },
30+
31+
// CHECK-SAME: %swift.protocol_requirement { i32 17,
32+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @"$S19protocol_resilience17ResilientProtocolP8defaultCyyFTj" to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 4, i32 1) to [[INT]])){{ | to i32\) }}
33+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @defaultC to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 4, i32 2) to [[INT]])){{ | to i32\) }}
34+
// CHECK-SAME: },
35+
36+
// CHECK-SAME: %swift.protocol_requirement { i32 17,
37+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @"$S19protocol_resilience17ResilientProtocolP8defaultDyyFTj" to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 5, i32 1) to [[INT]])){{ | to i32\) }}
38+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.opaque*, %swift.type*, i8**)* @defaultD to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 5, i32 2) to [[INT]])){{ | to i32\) }}
39+
// CHECK-SAME: },
40+
41+
// CHECK-SAME: %swift.protocol_requirement { i32 1,
42+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @"$S19protocol_resilience17ResilientProtocolP8defaultEyyFZTj" to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 6, i32 1) to [[INT]])){{ | to i32\) }}
43+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @defaultE to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 6, i32 2) to [[INT]])){{ | to i32\) }}
44+
// CHECK-SAME: },
45+
46+
// CHECK-SAME: %swift.protocol_requirement { i32 1,
47+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @"$S19protocol_resilience17ResilientProtocolP8defaultFyyFZTj" to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 7, i32 1) to [[INT]])){{ | to i32\) }}
48+
// CHECK-SAME: i32{{ | trunc \(i64 }}sub ([[INT]] ptrtoint (void (%swift.type*, %swift.type*, i8**)* @defaultF to [[INT]]), [[INT]] ptrtoint (i32* getelementptr inbounds ([8 x %swift.protocol_requirement], [8 x %swift.protocol_requirement]* [[RP_REQTS]], i32 0, i32 7, i32 2) to [[INT]])){{ | to i32\) }}
49+
// CHECK-SAME: }
50+
// CHECK-SAME: ]
2551

2652
// CHECK: @"$S19protocol_resilience17ResilientProtocolMp" = {{(protected )?}}constant %swift.protocol {
2753
// CHECK-SAME: i32 1031,

0 commit comments

Comments
 (0)