Skip to content

Commit c1a1ddd

Browse files
committed
Requestify needsNewVTableEntry
This commit introduces `NeedsNewVTableEntryRequest`, which checks whether a class method needs a new vtable entry.
1 parent 013c4f1 commit c1a1ddd

File tree

8 files changed

+135
-93
lines changed

8 files changed

+135
-93
lines changed

include/swift/AST/Decl.h

Lines changed: 13 additions & 16 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,
@@ -5574,6 +5568,8 @@ class ImportAsMemberStatus {
55745568

55755569
/// Base class for function-like declarations.
55765570
class AbstractFunctionDecl : public GenericContext, public ValueDecl {
5571+
friend class NeedsNewVTableEntryRequest;
5572+
55775573
public:
55785574
enum class BodyKind {
55795575
/// The function did not have a body in the source code file.
@@ -5643,6 +5639,11 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
56435639
/// Location of the 'throws' token.
56445640
SourceLoc ThrowsLoc;
56455641

5642+
struct {
5643+
unsigned NeedsNewVTableEntryComputed : 1;
5644+
unsigned NeedsNewVTableEntry : 1;
5645+
} LazySemanticInfo = { };
5646+
56465647
AbstractFunctionDecl(DeclKind Kind, DeclContext *Parent, DeclName Name,
56475648
SourceLoc NameLoc, bool Throws, SourceLoc ThrowsLoc,
56485649
bool HasImplicitSelfDecl,
@@ -5654,8 +5655,6 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
56545655
Bits.AbstractFunctionDecl.HasImplicitSelfDecl = HasImplicitSelfDecl;
56555656
Bits.AbstractFunctionDecl.Overridden = false;
56565657
Bits.AbstractFunctionDecl.Throws = Throws;
5657-
Bits.AbstractFunctionDecl.NeedsNewVTableEntry = false;
5658-
Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry = false;
56595658
Bits.AbstractFunctionDecl.Synthesized = false;
56605659
Bits.AbstractFunctionDecl.HasSingleExpressionBody = false;
56615660
}
@@ -5826,15 +5825,13 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
58265825
}
58275826

58285827
void setNeedsNewVTableEntry(bool value) {
5829-
Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry = true;
5830-
Bits.AbstractFunctionDecl.NeedsNewVTableEntry = value;
5828+
LazySemanticInfo.NeedsNewVTableEntryComputed = true;
5829+
LazySemanticInfo.NeedsNewVTableEntry = value;
58315830
}
58325831

5833-
bool needsNewVTableEntry() const {
5834-
if (!Bits.AbstractFunctionDecl.HasComputedNeedsNewVTableEntry)
5835-
const_cast<AbstractFunctionDecl *>(this)->computeNeedsNewVTableEntry();
5836-
return Bits.AbstractFunctionDecl.NeedsNewVTableEntry;
5837-
}
5832+
/// For a method of a class, checks whether it will require a new entry in the
5833+
/// vtable.
5834+
bool needsNewVTableEntry() const;
58385835

58395836
bool isEffectiveLinkageMoreVisibleThan(ValueDecl *other) const {
58405837
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
@@ -1273,6 +1273,27 @@ class IsABICompatibleOverrideRequest
12731273
bool isCached() const { return true; }
12741274
};
12751275

1276+
class NeedsNewVTableEntryRequest
1277+
: public SimpleRequest<NeedsNewVTableEntryRequest,
1278+
bool(AbstractFunctionDecl *),
1279+
CacheKind::SeparatelyCached> {
1280+
public:
1281+
using SimpleRequest::SimpleRequest;
1282+
1283+
private:
1284+
friend SimpleRequest;
1285+
1286+
// Evaluation.
1287+
llvm::Expected<bool> evaluate(Evaluator &evaluator,
1288+
AbstractFunctionDecl *decl) const;
1289+
1290+
public:
1291+
// Separate caching.
1292+
bool isCached() const { return true; }
1293+
Optional<bool> getCachedResult() const;
1294+
void cacheResult(bool value) const;
1295+
};
1296+
12761297
// Allow AnyValue to compare two Type values, even though Type doesn't
12771298
// support ==.
12781299
template<>

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,5 @@ SWIFT_REQUEST(TypeChecker, USRGenerationRequest, std::string(const ValueDecl *),
144144
Cached, NoLocationInfo)
145145
SWIFT_REQUEST(TypeChecker, IsABICompatibleOverrideRequest,
146146
bool(ValueDecl *), Cached, NoLocationInfo)
147+
SWIFT_REQUEST(TypeChecker, NeedsNewVTableEntryRequest,
148+
bool(AbstractFunctionDecl *), SeparatelyCached, NoLocationInfo)

lib/AST/Decl.cpp

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

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

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

lib/AST/TypeCheckRequests.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,3 +895,20 @@ void EnumRawValuesRequest::diagnoseCycle(DiagnosticEngine &diags) const {
895895
void EnumRawValuesRequest::noteCycleStep(DiagnosticEngine &diags) const {
896896

897897
}
898+
899+
//----------------------------------------------------------------------------//
900+
// NeedsNewVTableEntryRequest computation.
901+
//----------------------------------------------------------------------------//
902+
903+
Optional<bool> NeedsNewVTableEntryRequest::getCachedResult() const {
904+
auto *decl = std::get<0>(getStorage());
905+
if (decl->LazySemanticInfo.NeedsNewVTableEntryComputed)
906+
return decl->LazySemanticInfo.NeedsNewVTableEntry;
907+
return None;
908+
}
909+
910+
void NeedsNewVTableEntryRequest::cacheResult(bool value) const {
911+
auto *decl = std::get<0>(getStorage());
912+
decl->LazySemanticInfo.NeedsNewVTableEntryComputed = true;
913+
decl->LazySemanticInfo.NeedsNewVTableEntry = value;
914+
}

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/TypeCheckDecl.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,80 @@ DefaultDefinitionTypeRequest::evaluate(Evaluator &evaluator,
13661366
return Type();
13671367
}
13681368

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

lib/Serialization/Deserialization.cpp

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

25582559
ctor->setOverriddenDecl(cast_or_null<ConstructorDecl>(overridden.get()));
25592560
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 (opaqueResultTypeDeclID)
30343036
fn->setOpaqueResultTypeDecl(

0 commit comments

Comments
 (0)