Skip to content

Commit a947f34

Browse files
authored
Requestify needsNewVTableEntry (swiftlang#27541)
Requestify needsNewVTableEntry
2 parents 5b878ac + 91a792b commit a947f34

File tree

9 files changed

+136
-99
lines changed

9 files changed

+136
-99
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ class alignas(1 << DeclAlignInBits) Decl {
388388
SWIFT_INLINE_BITFIELD(SubscriptDecl, VarDecl, 2,
389389
StaticSpelling : 2
390390
);
391-
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1+1+1,
391+
SWIFT_INLINE_BITFIELD(AbstractFunctionDecl, ValueDecl, 3+8+1+1+1+1+1+1,
392392
/// \see AbstractFunctionDecl::BodyKind
393393
BodyKind : 3,
394394

@@ -404,12 +404,6 @@ class alignas(1 << DeclAlignInBits) Decl {
404404
/// Whether the function body throws.
405405
Throws : 1,
406406

407-
/// Whether this function requires a new vtable entry.
408-
NeedsNewVTableEntry : 1,
409-
410-
/// Whether NeedsNewVTableEntry is valid.
411-
HasComputedNeedsNewVTableEntry : 1,
412-
413407
/// Whether this member was synthesized as part of a derived
414408
/// protocol conformance.
415409
Synthesized : 1,
@@ -5553,6 +5547,8 @@ class ImportAsMemberStatus {
55535547

55545548
/// Base class for function-like declarations.
55555549
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
5550+
friend class NeedsNewVTableEntryRequest;
5551+
55565552
public:
55575553
enum class BodyKind {
55585554
/// The function did not have a body in the source code file.
@@ -5622,6 +5618,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
56225618
/// Location of the 'throws' token.
56235619
SourceLoc ThrowsLoc;
56245620

5621+
struct {
5622+
unsigned NeedsNewVTableEntryComputed : 1;
5623+
unsigned NeedsNewVTableEntry : 1;
5624+
} LazySemanticInfo = { };
5625+
56255626
AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
56265627
SourceLoc NameLoc, bool Throws, SourceLoc ThrowsLoc,
56275628
bool HasImplicitSelfDecl,
@@ -5633,8 +5634,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
56335634
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
56345635
Bits.AbstractFunctionDecl.Overridden = false;
56355636
Bits.AbstractFunctionDecl.Throws = Throws;
5636-
Bits.AbstractFunctionDecl.NeedsNewVTableEntry = false;
5637-
Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry = false;
56385637
Bits.AbstractFunctionDecl.Synthesized = false;
56395638
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
56405639
}
@@ -5804,16 +5803,9 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
58045803
return getBodyKind() == BodyKind::MemberwiseInitializer;
58055804
}
58065805

5807-
void setNeedsNewVTableEntry(bool value) {
5808-
Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry = true;
5809-
Bits.AbstractFunctionDecl.NeedsNewVTableEntry = value;
5810-
}
5811-
5812-
bool needsNewVTableEntry() const {
5813-
if (!Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry)
5814-
const_cast<AbstractFunctionDecl *>(this)->computeNeedsNewVTableEntry();
5815-
return Bits.AbstractFunctionDecl.NeedsNewVTableEntry;
5816-
}
5806+
/// For a method of a class, checks whether it will require a new entry in the
5807+
/// vtable.
5808+
bool needsNewVTableEntry() const;
58175809

58185810
bool isEffectiveLinkageMoreVisibleThan(ValueDecl *other) const {
58195811
return (std::min(getEffectiveAccess(), AccessLevel::Public) >

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,27 @@ class IsStaticRequest :
13141314
void cacheResult(bool value) const;
13151315
};
13161316

1317+
class NeedsNewVTableEntryRequest
1318+
: public SimpleRequest<NeedsNewVTableEntryRequest,
1319+
bool(AbstractFunctionDecl *),
1320+
CacheKind::SeparatelyCached> {
1321+
public:
1322+
using SimpleRequest::SimpleRequest;
1323+
1324+
private:
1325+
friend SimpleRequest;
1326+
1327+
// Evaluation.
1328+
llvm::Expected<bool> evaluate(Evaluator &evaluator,
1329+
AbstractFunctionDecl *decl) const;
1330+
1331+
public:
1332+
// Separate caching.
1333+
bool isCached() const { return true; }
1334+
Optional<bool> getCachedResult() const;
1335+
void cacheResult(bool value) const;
1336+
};
1337+
13171338
// Allow AnyValue to compare two Type values, even though Type doesn't
13181339
// support ==.
13191340
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,3 +149,5 @@ SWIFT_REQUEST(TypeChecker, IsABICompatibleOverrideRequest,
149149
bool(ValueDecl *), Cached, NoLocationInfo)
150150
SWIFT_REQUEST(TypeChecker, IsStaticRequest,
151151
bool(FuncDecl *), SeparatelyCached, NoLocationInfo)
152+
SWIFT_REQUEST(TypeChecker, NeedsNewVTableEntryRequest,
153+
bool(AbstractFunctionDecl *), SeparatelyCached, NoLocationInfo)

lib/AST/Decl.cpp

Lines changed: 4 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6539,81 +6539,12 @@ bool AbstractFunctionDecl::isObjCInstanceMethod() const {
65396539
return isInstanceMember() || isa<ConstructorDecl>(this);
65406540
}
65416541

6542-
static bool requiresNewVTableEntry(const AbstractFunctionDecl *decl) {
6543-
auto *dc = decl->getDeclContext();
6544-
6545-
if (!isa<ClassDecl>(dc))
6546-
return true;
6547-
6548-
assert(isa<FuncDecl>(decl) || isa<ConstructorDecl>(decl));
6549-
6550-
// Final members are always be called directly.
6551-
// Dynamic methods are always accessed by objc_msgSend().
6552-
if (decl->isFinal() || decl->isObjCDynamic() || decl->hasClangNode())
6553-
return false;
6554-
6555-
auto &ctx = dc->getASTContext();
6556-
6557-
// Initializers are not normally inherited, but required initializers can
6558-
// be overridden for invocation from dynamic types, and convenience initializers
6559-
// are conditionally inherited when all designated initializers are available,
6560-
// working by dynamically invoking the designated initializer implementation
6561-
// from the subclass. Convenience initializers can also override designated
6562-
// initializer implementations from their superclass.
6563-
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
6564-
if (!ctor->isRequired() && !ctor->isDesignatedInit()) {
6565-
return false;
6566-
}
6567-
}
6568-
6569-
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
6570-
// Check to see if it's one of the opaque accessors for the declaration.
6571-
auto storage = accessor->getStorage();
6572-
if (!storage->requiresOpaqueAccessor(accessor->getAccessorKind()))
6573-
return false;
6574-
}
6575-
6576-
auto base = decl->getOverriddenDecl();
6577-
6578-
if (!base || base->hasClangNode() || base->isObjCDynamic())
6579-
return true;
6580-
6581-
// As above, convenience initializers are not formally overridable in Swift
6582-
// vtables, although same-named initializers are modeled as overriding for
6583-
// various QoI and objc interop reasons. Even if we "override" a non-required
6584-
// convenience init, we still need a distinct vtable entry.
6585-
if (auto baseCtor = dyn_cast<ConstructorDecl>(base)) {
6586-
if (!baseCtor->isRequired() && !baseCtor->isDesignatedInit()) {
6587-
return true;
6588-
}
6589-
}
6590-
6591-
// If the base is less visible than the override, we might need a vtable
6592-
// entry since callers of the override might not be able to see the base
6593-
// at all.
6594-
if (decl->isEffectiveLinkageMoreVisibleThan(base))
6595-
return true;
6596-
6597-
using Direction = ASTContext::OverrideGenericSignatureReqCheck;
6598-
if (!ctx.overrideGenericSignatureReqsSatisfied(
6599-
base, decl, Direction::BaseReqSatisfiedByDerived)) {
6600-
return true;
6601-
}
6602-
6603-
// If this method is an ABI compatible override, then we don't need a new
6604-
// vtable entry. Otherwise, if it's not ABI compatible, for example if the
6605-
// base has a more general AST type, then we need a new entry. Note that an
6606-
// abstraction change is OK; we don't want to add a whole new vtable entry
6607-
// just because an @in parameter becomes @owned, or whatever.
6608-
auto isABICompatibleOverride = evaluateOrDefault(
6542+
bool AbstractFunctionDecl::needsNewVTableEntry() const {
6543+
auto &ctx = getASTContext();
6544+
return evaluateOrDefault(
66096545
ctx.evaluator,
6610-
IsABICompatibleOverrideRequest{const_cast<AbstractFunctionDecl *>(decl)},
6546+
NeedsNewVTableEntryRequest{const_cast<AbstractFunctionDecl *>(this)},
66116547
false);
6612-
return !isABICompatibleOverride;
6613-
}
6614-
6615-
void AbstractFunctionDecl::computeNeedsNewVTableEntry() {
6616-
setNeedsNewVTableEntry(requiresNewVTableEntry(this));
66176548
}
66186549

66196550
ParamDecl *AbstractFunctionDecl::getImplicitSelfDecl(bool createIfNeeded) {

lib/AST/TypeCheckRequests.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -908,4 +908,21 @@ Optional<bool> IsStaticRequest::getCachedResult() const {
908908
void IsStaticRequest::cacheResult(bool result) const {
909909
auto *FD = std::get<0>(getStorage());
910910
FD->setStatic(result);
911-
}
911+
}
912+
913+
//----------------------------------------------------------------------------//
914+
// NeedsNewVTableEntryRequest computation.
915+
//----------------------------------------------------------------------------//
916+
917+
Optional<bool> NeedsNewVTableEntryRequest::getCachedResult() const {
918+
auto *decl = std::get<0>(getStorage());
919+
if (decl->LazySemanticInfo.NeedsNewVTableEntryComputed)
920+
return decl->LazySemanticInfo.NeedsNewVTableEntry;
921+
return None;
922+
}
923+
924+
void NeedsNewVTableEntryRequest::cacheResult(bool value) const {
925+
auto *decl = std::get<0>(getStorage());
926+
decl->LazySemanticInfo.NeedsNewVTableEntryComputed = true;
927+
decl->LazySemanticInfo.NeedsNewVTableEntry = value;
928+
}

lib/ClangImporter/ImporterImpl.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,8 +1234,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
12341234
D->setAccess(access);
12351235
if (auto ASD = dyn_cast<AbstractStorageDecl>(D))
12361236
ASD->setSetterAccess(access);
1237-
if (auto AFD = dyn_cast<AbstractFunctionDecl>(static_cast<Decl *>(D)))
1238-
AFD->setNeedsNewVTableEntry(false);
12391237
return D;
12401238
}
12411239

lib/Sema/CodeSynthesis.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,8 +702,6 @@ createDesignatedInitOverride(ClassDecl *classDecl,
702702
// Note that this is a stub implementation.
703703
ctor->setStubImplementation(true);
704704

705-
// Stub constructors don't appear in the vtable.
706-
ctor->setNeedsNewVTableEntry(false);
707705
return ctor;
708706
}
709707

lib/Sema/TypeCheckDecl.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,82 @@ DefaultDefinitionTypeRequest::evaluate(Evaluator &evaluator,
13851385
return Type();
13861386
}
13871387

1388+
llvm::Expected<bool>
1389+
NeedsNewVTableEntryRequest::evaluate(Evaluator &evaluator,
1390+
AbstractFunctionDecl *decl) const {
1391+
auto *dc = decl->getDeclContext();
1392+
if (!isa<ClassDecl>(dc))
1393+
return true;
1394+
1395+
assert(isa<FuncDecl>(decl) || isa<ConstructorDecl>(decl));
1396+
1397+
// Final members are always be called directly.
1398+
// Dynamic methods are always accessed by objc_msgSend().
1399+
if (decl->isFinal() || decl->isObjCDynamic() || decl->hasClangNode())
1400+
return false;
1401+
1402+
auto &ctx = dc->getASTContext();
1403+
1404+
// Initializers are not normally inherited, but required initializers can
1405+
// be overridden for invocation from dynamic types, and convenience initializers
1406+
// are conditionally inherited when all designated initializers are available,
1407+
// working by dynamically invoking the designated initializer implementation
1408+
// from the subclass. Convenience initializers can also override designated
1409+
// initializer implementations from their superclass.
1410+
if (auto ctor = dyn_cast<ConstructorDecl>(decl)) {
1411+
if (!ctor->isRequired() && !ctor->isDesignatedInit()) {
1412+
return false;
1413+
}
1414+
1415+
// Stub constructors don't appear in the vtable.
1416+
if (ctor->hasStubImplementation())
1417+
return false;
1418+
}
1419+
1420+
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
1421+
// Check to see if it's one of the opaque accessors for the declaration.
1422+
auto storage = accessor->getStorage();
1423+
if (!storage->requiresOpaqueAccessor(accessor->getAccessorKind()))
1424+
return false;
1425+
}
1426+
1427+
auto base = decl->getOverriddenDecl();
1428+
1429+
if (!base || base->hasClangNode() || base->isObjCDynamic())
1430+
return true;
1431+
1432+
// As above, convenience initializers are not formally overridable in Swift
1433+
// vtables, although same-named initializers are modeled as overriding for
1434+
// various QoI and objc interop reasons. Even if we "override" a non-required
1435+
// convenience init, we still need a distinct vtable entry.
1436+
if (auto baseCtor = dyn_cast<ConstructorDecl>(base)) {
1437+
if (!baseCtor->isRequired() && !baseCtor->isDesignatedInit()) {
1438+
return true;
1439+
}
1440+
}
1441+
1442+
// If the base is less visible than the override, we might need a vtable
1443+
// entry since callers of the override might not be able to see the base
1444+
// at all.
1445+
if (decl->isEffectiveLinkageMoreVisibleThan(base))
1446+
return true;
1447+
1448+
using Direction = ASTContext::OverrideGenericSignatureReqCheck;
1449+
if (!ctx.overrideGenericSignatureReqsSatisfied(
1450+
base, decl, Direction::BaseReqSatisfiedByDerived)) {
1451+
return true;
1452+
}
1453+
1454+
// If this method is an ABI compatible override, then we don't need a new
1455+
// vtable entry. Otherwise, if it's not ABI compatible, for example if the
1456+
// base has a more general AST type, then we need a new entry. Note that an
1457+
// abstraction change is OK; we don't want to add a whole new vtable entry
1458+
// just because an @in parameter becomes @owned, or whatever.
1459+
auto isABICompatibleOverride =
1460+
evaluateOrDefault(evaluator, IsABICompatibleOverrideRequest{decl}, false);
1461+
return !isABICompatibleOverride;
1462+
}
1463+
13881464
namespace {
13891465
/// How to generate the raw value for each element of an enum that doesn't
13901466
/// have one explicitly specified.

lib/Serialization/Deserialization.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,7 +2552,8 @@ class swift::DeclDeserializer {
25522552
if (initKind.hasValue())
25532553
ctx.evaluator.cacheOutput(InitKindRequest{ctor},
25542554
std::move(initKind.getValue()));
2555-
ctor->setNeedsNewVTableEntry(needsNewVTableEntry);
2555+
ctx.evaluator.cacheOutput(NeedsNewVTableEntryRequest{ctor},
2556+
std::move(needsNewVTableEntry));
25562557

25572558
ctor->setOverriddenDecl(cast_or_null<ConstructorDecl>(overridden.get()));
25582559
if (auto *overridden = ctor->getOverriddenDecl()) {
@@ -3028,7 +3029,8 @@ class swift::DeclDeserializer {
30283029
fn->setImplicit();
30293030
fn->setIsObjC(isObjC);
30303031
fn->setForcedStaticDispatch(hasForcedStaticDispatch);
3031-
fn->setNeedsNewVTableEntry(needsNewVTableEntry);
3032+
ctx.evaluator.cacheOutput(NeedsNewVTableEntryRequest{fn},
3033+
std::move(needsNewVTableEntry));
30323034

30333035
if (opaqueReturnTypeID) {
30343036
ctx.evaluator.cacheOutput(

0 commit comments

Comments
 (0)