Skip to content

Commit f8e5ebe

Browse files
authored
Merge pull request #18299 from jckarter/enable-key-path-resilience
Enable key path resilience.
2 parents 2d88bb6 + aaf1caf commit f8e5ebe

22 files changed

+615
-243
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ namespace swift {
226226
bool EnableSILOpaqueValues = false;
227227

228228
/// Enables key path resilience.
229-
bool EnableKeyPathResilience = false;
229+
bool EnableKeyPathResilience = true;
230230

231231
/// If set to true, the diagnosis engine can assume the emitted diagnostics
232232
/// will be used in editor. This usually leads to more aggressive fixit.

lib/IRGen/GenDecl.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1582,11 +1582,18 @@ SILLinkage LinkEntity::getLinkage(ForDefinition_t forDefinition) const {
15821582
return getSILLinkage(linkage, forDefinition);
15831583
}
15841584

1585+
case Kind::PropertyDescriptor: {
1586+
// Return the linkage of the getter, which may be more permissive than the
1587+
// property itself (for instance, with a private/internal property whose
1588+
// accessor is @inlinable or @usableFromInline)
1589+
auto getterDecl = cast<AbstractStorageDecl>(getDecl())->getGetter();
1590+
return getSILLinkage(getDeclLinkage(getterDecl), forDefinition);
1591+
}
1592+
15851593
case Kind::ObjCClass:
15861594
case Kind::ObjCMetaclass:
15871595
case Kind::SwiftMetaclassStub:
15881596
case Kind::NominalTypeDescriptor:
1589-
case Kind::PropertyDescriptor:
15901597
case Kind::ClassMetadataBaseOffset:
15911598
case Kind::ProtocolDescriptor:
15921599
return getSILLinkage(getDeclLinkage(getDecl()), forDefinition);

lib/IRGen/GenKeyPath.cpp

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,16 @@
4646
#include "swift/AST/GenericEnvironment.h"
4747
#include "swift/AST/ParameterList.h"
4848
#include "swift/AST/Types.h"
49+
#include "swift/Basic/Statistic.h"
4950
#include "swift/IRGen/Linking.h"
5051

5152
using namespace swift;
5253
using namespace irgen;
5354

55+
#define DEBUG_TYPE "IRGen key paths"
56+
STATISTIC(NumTrivialPropertyDescriptors, "# of trivial property descriptors");
57+
STATISTIC(NumNonTrivialPropertyDescriptors, "# of nontrivial property descriptors");
58+
5459
enum KeyPathAccessor {
5560
Getter,
5661
Setter,
@@ -910,23 +915,43 @@ emitKeyPathComponent(IRGenModule &IGM,
910915
idValue = IGM.getAddrOfObjCSelectorRef(declRef);
911916
idResolved = false;
912917
} else {
913-
idKind = KeyPathComponentHeader::VTableOffset;
918+
if (auto overridden = declRef.getOverriddenVTableEntry())
919+
declRef = overridden;
920+
914921
auto dc = declRef.getDecl()->getDeclContext();
922+
923+
// If the method context is resilient, use the dispatch thunk as a
924+
// stable identifier for the storage.
925+
if (IGM.isResilient(cast<NominalTypeDecl>(dc),
926+
ResilienceExpansion::Minimal)) {
927+
idKind = KeyPathComponentHeader::Pointer;
928+
idValue = IGM.getAddrOfDispatchThunk(declRef, NotForDefinition);
929+
idResolved = true;
930+
break;
931+
}
932+
933+
idKind = KeyPathComponentHeader::VTableOffset;
915934
if (isa<ClassDecl>(dc) && !cast<ClassDecl>(dc)->isForeign()) {
916-
auto overridden = declRef.getOverriddenVTableEntry();
917935
auto declaringClass =
918-
cast<ClassDecl>(overridden.getDecl()->getDeclContext());
936+
cast<ClassDecl>(declRef.getDecl()->getDeclContext());
919937
auto &metadataLayout = IGM.getClassMetadataLayout(declaringClass);
920-
// FIXME: Resilience. We don't want vtable layout to be ABI, so this
921-
// should be encoded as a reference to the method dispatch thunk
922-
// instead.
923-
auto offset = metadataLayout.getStaticMethodOffset(overridden);
938+
939+
// For a class method, we don't necessarily need the absolute offset,
940+
// only an offset that's unique to this method. For a class with
941+
// resilient ancestry, all of the superclass methods will be
942+
// identified by their dispatch thunk (see above), so we can use
943+
// relative offsets from the dynamic base offset to identify the local
944+
// class's own methods.
945+
auto methodInfo = metadataLayout.getMethodOffsetInfo(declRef);
946+
Size offset;
947+
if (methodInfo.isStatic())
948+
offset = methodInfo.getStaticOffset();
949+
else
950+
offset = methodInfo.getRelativeOffset();
951+
924952
idValue = llvm::ConstantInt::get(IGM.SizeTy, offset.getValue());
925953
idResolved = true;
926954
} else if (auto methodProto = dyn_cast<ProtocolDecl>(dc)) {
927-
// FIXME: Resilience. We don't want witness table layout to be ABI,
928-
// so this should be encoded as a reference to the method dispatch
929-
// thunk instead.
930955
auto &protoInfo = IGM.getProtocolInfo(methodProto);
931956
auto index = protoInfo.getFunctionIndex(
932957
cast<AbstractFunctionDecl>(declRef.getDecl()));
@@ -1187,6 +1212,7 @@ IRGenModule::getAddrOfKeyPathPattern(KeyPathPattern *pattern,
11871212

11881213
void IRGenModule::emitSILProperty(SILProperty *prop) {
11891214
if (prop->isTrivial()) {
1215+
++NumTrivialPropertyDescriptors;
11901216
// All trivial property descriptors can share a single definition in the
11911217
// translation unit.
11921218
if (!TheTrivialPropertyDescriptor) {
@@ -1213,6 +1239,8 @@ void IRGenModule::emitSILProperty(SILProperty *prop) {
12131239
return;
12141240
}
12151241

1242+
++NumNonTrivialPropertyDescriptors;
1243+
12161244
ConstantInitBuilder builder(*this);
12171245
ConstantStructBuilder fields = builder.beginStruct();
12181246
fields.setPacked(true);

lib/IRGen/MetadataLayout.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -400,12 +400,9 @@ ClassMetadataLayout::getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const{
400400
return MethodInfo(offset);
401401
}
402402

403-
Size ClassMetadataLayout::getStaticMethodOffset(SILDeclRef method) const{
404-
auto &stored = getStoredMethodInfo(method);
405-
406-
assert(stored.TheOffset.isStatic() &&
407-
"resilient class metadata layout unsupported!");
408-
return stored.TheOffset.getStaticOffset();
403+
MetadataLayout::StoredOffset
404+
ClassMetadataLayout::getMethodOffsetInfo(SILDeclRef method) const {
405+
return getStoredMethodInfo(method).TheOffset;
409406
}
410407

411408
Offset

lib/IRGen/MetadataLayout.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -249,12 +249,9 @@ class ClassMetadataLayout : public NominalMetadataLayout {
249249

250250
MethodInfo getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const;
251251

252-
/// Assuming that the given method is at a static offset in the metadata,
253-
/// return that static offset.
254-
///
255-
/// DEPRECATED: callers should be updated to handle this in a
256-
/// more arbitrary fashion.
257-
Size getStaticMethodOffset(SILDeclRef method) const;
252+
/// Return the information necessary to compute the offset of a method's
253+
/// vtable entry in the class object.
254+
StoredOffset getMethodOffsetInfo(SILDeclRef method) const;
258255

259256
Offset getFieldOffset(IRGenFunction &IGF, VarDecl *field) const;
260257

lib/SIL/SIL.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
#include "swift/AST/ASTContext.h"
2020
#include "swift/AST/AnyFunctionRef.h"
2121
#include "swift/AST/Decl.h"
22+
#include "swift/AST/GenericEnvironment.h"
2223
#include "swift/AST/Pattern.h"
24+
#include "swift/AST/ParameterList.h"
2325
#include "swift/AST/ProtocolConformance.h"
2426
#include "swift/ClangImporter/ClangModule.h"
2527
#include "clang/AST/Attr.h"
@@ -218,6 +220,10 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const {
218220
if (!getDeclContext()->isTypeContext() || isStatic())
219221
return false;
220222

223+
// Protocol requirements do not need property descriptors.
224+
if (isa<ProtocolDecl>(getDeclContext()))
225+
return false;
226+
221227
// Any property that's potentially resilient should have accessors
222228
// synthesized.
223229
if (!getGetter())
@@ -230,6 +236,7 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const {
230236
// TODO: If previous versions of an ABI-stable binary needed the descriptor,
231237
// then we still do.
232238

239+
// Check the linkage of the declaration.
233240
auto getter = SILDeclRef(getGetter());
234241
auto getterLinkage = getter.getLinkage(ForDefinition);
235242

@@ -252,5 +259,33 @@ bool AbstractStorageDecl::exportsPropertyDescriptor() const {
252259
llvm_unreachable("should be definition linkage?");
253260
}
254261

262+
// Subscripts with inout arguments (FIXME)and reabstracted arguments(/FIXME)
263+
// don't have descriptors either.
264+
if (auto sub = dyn_cast<SubscriptDecl>(this)) {
265+
for (auto *index : *sub->getIndices()) {
266+
// Keypaths can't capture inout indices.
267+
if (index->isInOut())
268+
return false;
269+
270+
auto indexTy = index->getInterfaceType()
271+
->getCanonicalType(sub->getGenericSignatureOfContext());
272+
273+
// TODO: Handle reabstraction and tuple explosion in thunk generation.
274+
// This wasn't previously a concern because anything that was Hashable
275+
// had only one abstraction level and no explosion.
276+
277+
if (isa<TupleType>(indexTy))
278+
return false;
279+
280+
auto indexObjTy = indexTy;
281+
if (auto objTy = indexObjTy.getOptionalObjectType())
282+
indexObjTy = objTy;
283+
284+
if (isa<AnyFunctionType>(indexObjTy)
285+
|| isa<AnyMetatypeType>(indexObjTy))
286+
return false;
287+
}
288+
}
289+
255290
return true;
256291
}

lib/SILGen/SILGen.cpp

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,20 +1286,17 @@ void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) {
12861286

12871287
Type baseTy;
12881288
if (decl->getDeclContext()->isTypeContext()) {
1289+
// TODO: Static properties should eventually be referenceable as
1290+
// keypaths from T.Type -> Element, viz `baseTy = MetatypeType::get(baseTy)`
1291+
assert(!decl->isStatic());
1292+
12891293
baseTy = decl->getDeclContext()->getSelfInterfaceType()
12901294
->getCanonicalType(decl->getInnermostDeclContext()
12911295
->getGenericSignatureOfContext());
1292-
if (decl->isStatic()) {
1293-
// TODO: Static properties should eventually be referenceable as
1294-
// keypaths from T.Type -> Element
1295-
//baseTy = MetatypeType::get(baseTy);
1296-
return;
1297-
}
12981296
} else {
12991297
// TODO: Global variables should eventually be referenceable as
1300-
// key paths from ()
1301-
//baseTy = TupleType::getEmpty(getASTContext());
1302-
return;
1298+
// key paths from (), viz. baseTy = TupleType::getEmpty(getASTContext());
1299+
llvm_unreachable("should not export a property descriptor yet");
13031300
}
13041301

13051302
auto genericEnv = decl->getInnermostDeclContext()
@@ -1316,33 +1313,6 @@ void SILGenModule::tryEmitPropertyDescriptor(AbstractStorageDecl *decl) {
13161313
if (genericEnv)
13171314
subs = genericEnv->getForwardingSubstitutionMap();
13181315

1319-
if (auto sub = dyn_cast<SubscriptDecl>(decl)) {
1320-
for (auto *index : *sub->getIndices()) {
1321-
// Keypaths can't capture inout indices.
1322-
if (index->isInOut())
1323-
return;
1324-
1325-
// TODO: Handle reabstraction and tuple explosion in thunk generation.
1326-
// This wasn't previously a concern because anything that was Hashable
1327-
// had only one abstraction level and no explosion.
1328-
auto indexTy = index->getInterfaceType();
1329-
1330-
if (isa<TupleType>(indexTy->getCanonicalType(sub->getGenericSignature())))
1331-
return;
1332-
1333-
if (genericEnv)
1334-
indexTy = genericEnv->mapTypeIntoContext(indexTy);
1335-
1336-
auto indexLoweredTy = Types.getLoweredType(indexTy);
1337-
auto indexOpaqueLoweredTy =
1338-
Types.getLoweredType(AbstractionPattern::getOpaque(), indexTy);
1339-
1340-
if (indexOpaqueLoweredTy.getAddressType()
1341-
!= indexLoweredTy.getAddressType())
1342-
return;
1343-
}
1344-
}
1345-
13461316
auto component = emitKeyPathComponentForDecl(SILLocation(decl),
13471317
genericEnv,
13481318
baseOperand, needsGenericContext,

lib/SILGen/SILGenExpr.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3635,7 +3635,13 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
36353635
[&]() -> bool {
36363636
return getASTContext().LangOpts.EnableKeyPathResilience
36373637
&& !forPropertyDescriptor
3638-
&& storage->getModuleContext() != SwiftModule;
3638+
&& storage->getModuleContext() != SwiftModule
3639+
// Protocol requirements don't have nor need property descriptors.
3640+
&& !isa<ProtocolDecl>(storage->getDeclContext())
3641+
// Properties that only dispatch via ObjC lookup do not have nor need
3642+
// property descriptors, since the selector identifies the storage.
3643+
&& (!storage->hasAnyAccessors()
3644+
|| !getGetterDeclRef(storage).isForeign);
36393645
};
36403646

36413647
auto strategy = storage->getAccessStrategy(AccessSemantics::Ordinary,

0 commit comments

Comments
 (0)