[AST] Use cached deserialized decl in getOpaqueResultTypeDecl

Mangling and looking up the opaque result type decl
for serialized decls is a fairly expensive
operation. Instead, fallthrough to the request
which will have a cached value set by deserialization.
This shaves ~30ms off the cached completion for:

```swift
import SwiftUI

struct V: View {
  var body: some View {
    Table(#^CC^#
  }
}
```
This commit is contained in:
Hamish Knight
2024-11-04 11:29:55 +00:00
parent 43839ac5fd
commit 152812cc86
7 changed files with 69 additions and 46 deletions

View File

@@ -2758,6 +2758,10 @@ private:
/// output a null pointer. /// output a null pointer.
unsigned noDynamicallyReplacedDecl : 1; unsigned noDynamicallyReplacedDecl : 1;
/// Whether the OpaqueResultTypeRequest request was evaluated and produced
/// a null pointer.
unsigned noOpaqueResultType : 1;
/// Whether the "isFinal" bit has been computed yet. /// Whether the "isFinal" bit has been computed yet.
unsigned isFinalComputed : 1; unsigned isFinalComputed : 1;
@@ -2785,7 +2789,7 @@ private:
friend class InterfaceTypeRequest; friend class InterfaceTypeRequest;
friend class CheckRedeclarationRequest; friend class CheckRedeclarationRequest;
friend class ActorIsolationRequest; friend class ActorIsolationRequest;
friend class DynamicallyReplacedDeclRequest; friend class OpaqueResultTypeRequest;
friend class ApplyAccessNoteRequest; friend class ApplyAccessNoteRequest;
friend class Decl; friend class Decl;

View File

@@ -2295,21 +2295,22 @@ public:
/// Builds an opaque result type for a declaration. /// Builds an opaque result type for a declaration.
class OpaqueResultTypeRequest class OpaqueResultTypeRequest
: public SimpleRequest<OpaqueResultTypeRequest, : public SimpleRequest<
OpaqueTypeDecl *(ValueDecl *), OpaqueResultTypeRequest, OpaqueTypeDecl *(ValueDecl *),
RequestFlags::Cached> { RequestFlags::SeparatelyCached | RequestFlags::SplitCached> {
public: public:
using SimpleRequest::SimpleRequest; using SimpleRequest::SimpleRequest;
private: private:
friend SimpleRequest; friend SimpleRequest;
OpaqueTypeDecl * OpaqueTypeDecl *evaluate(Evaluator &evaluator, ValueDecl *VD) const;
evaluate(Evaluator &evaluator, ValueDecl *VD) const;
public: public:
// Caching. // Split caching.
bool isCached() const { return true; } bool isCached() const { return true; }
std::optional<OpaqueTypeDecl *> getCachedResult() const;
void cacheResult(OpaqueTypeDecl *result) const;
}; };
/// Determines if a function declaration is 'static'. /// Determines if a function declaration is 'static'.

View File

@@ -262,7 +262,7 @@ SWIFT_REQUEST(TypeChecker, OpaqueReadOwnershipRequest,
NoLocationInfo) NoLocationInfo)
SWIFT_REQUEST(TypeChecker, OpaqueResultTypeRequest, SWIFT_REQUEST(TypeChecker, OpaqueResultTypeRequest,
OpaqueTypeDecl *(ValueDecl *), OpaqueTypeDecl *(ValueDecl *),
Cached, NoLocationInfo) SeparatelyCached | SplitCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, OperatorPrecedenceGroupRequest, SWIFT_REQUEST(TypeChecker, OperatorPrecedenceGroupRequest,
PrecedenceGroupDecl *(PrecedenceGroupDecl *), PrecedenceGroupDecl *(PrecedenceGroupDecl *),
Cached, NoLocationInfo) Cached, NoLocationInfo)

View File

@@ -3887,21 +3887,6 @@ TypeRepr *ValueDecl::getOpaqueResultTypeRepr() const {
} }
OpaqueTypeDecl *ValueDecl::getOpaqueResultTypeDecl() const { OpaqueTypeDecl *ValueDecl::getOpaqueResultTypeDecl() const {
if (getOpaqueResultTypeRepr() == nullptr) {
if (!isa<VarDecl>(this) &&
!isa<FuncDecl>(this) &&
!isa<SubscriptDecl>(this))
return nullptr;
auto file = cast<FileUnit>(getDeclContext()->getModuleScopeContext());
// Don't look up when the decl is from source, otherwise a cycle will happen.
if (file->getKind() == FileUnitKind::SerializedAST) {
Mangle::ASTMangler mangler;
auto name = mangler.mangleOpaqueTypeDecl(this);
return file->lookupOpaqueResultType(name);
}
return nullptr;
}
return evaluateOrDefault(getASTContext().evaluator, return evaluateOrDefault(getASTContext().evaluator,
OpaqueResultTypeRequest{const_cast<ValueDecl *>(this)}, OpaqueResultTypeRequest{const_cast<ValueDecl *>(this)},
nullptr); nullptr);

View File

@@ -385,6 +385,28 @@ void DynamicallyReplacedDeclRequest::cacheResult(ValueDecl *result) const {
decl->getASTContext().evaluator.cacheNonEmptyOutput(*this, std::move(result)); decl->getASTContext().evaluator.cacheNonEmptyOutput(*this, std::move(result));
} }
//----------------------------------------------------------------------------//
// OpaqueResultTypeRequest caching.
//----------------------------------------------------------------------------//
std::optional<OpaqueTypeDecl *>
OpaqueResultTypeRequest::getCachedResult() const {
auto *decl = std::get<0>(getStorage());
if (decl->LazySemanticInfo.noOpaqueResultType)
return std::optional(nullptr);
return decl->getASTContext().evaluator.getCachedNonEmptyOutput(*this);
}
void OpaqueResultTypeRequest::cacheResult(OpaqueTypeDecl *result) const {
auto *decl = std::get<0>(getStorage());
if (!result) {
decl->LazySemanticInfo.noOpaqueResultType = 1;
return;
}
decl->getASTContext().evaluator.cacheNonEmptyOutput(*this, std::move(result));
}
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//
// ApplyAccessNoteRequest computation. // ApplyAccessNoteRequest computation.
//----------------------------------------------------------------------------// //----------------------------------------------------------------------------//

View File

@@ -42,7 +42,9 @@ OpaqueTypeDecl *
OpaqueResultTypeRequest::evaluate(Evaluator &evaluator, OpaqueResultTypeRequest::evaluate(Evaluator &evaluator,
ValueDecl *originatingDecl) const { ValueDecl *originatingDecl) const {
auto *repr = originatingDecl->getOpaqueResultTypeRepr(); auto *repr = originatingDecl->getOpaqueResultTypeRepr();
assert(repr && "Declaration does not have an opaque result type"); if (!repr)
return nullptr;
auto *dc = originatingDecl->getInnermostDeclContext(); auto *dc = originatingDecl->getInnermostDeclContext();
auto &ctx = dc->getASTContext(); auto &ctx = dc->getASTContext();

View File

@@ -3936,14 +3936,17 @@ public:
if (var->hasStorage()) if (var->hasStorage())
AddAttribute(new (ctx) HasStorageAttr(/*isImplicit:*/true)); AddAttribute(new (ctx) HasStorageAttr(/*isImplicit:*/true));
if (opaqueReturnTypeID) { {
auto opaqueReturnType = MF.getDeclChecked(opaqueReturnTypeID); OpaqueTypeDecl *opaqueDecl = nullptr;
if (!opaqueReturnType) if (opaqueReturnTypeID) {
return opaqueReturnType.takeError(); auto opaqueReturnType = MF.getDeclChecked(opaqueReturnTypeID);
if (!opaqueReturnType)
return opaqueReturnType.takeError();
ctx.evaluator.cacheOutput( opaqueDecl = cast<OpaqueTypeDecl>(opaqueReturnType.get());
OpaqueResultTypeRequest{var}, }
cast<OpaqueTypeDecl>(opaqueReturnType.get())); ctx.evaluator.cacheOutput(OpaqueResultTypeRequest{var},
std::move(opaqueDecl));
} }
// If this is a lazy property, record its backing storage. // If this is a lazy property, record its backing storage.
@@ -4357,14 +4360,17 @@ public:
fn->setIsObjC(isObjC); fn->setIsObjC(isObjC);
fn->setForcedStaticDispatch(hasForcedStaticDispatch); fn->setForcedStaticDispatch(hasForcedStaticDispatch);
if (opaqueReturnTypeID) { {
auto declOrError = MF.getDeclChecked(opaqueReturnTypeID); OpaqueTypeDecl *opaqueDecl = nullptr;
if (!declOrError) if (opaqueReturnTypeID) {
return declOrError.takeError(); auto declOrError = MF.getDeclChecked(opaqueReturnTypeID);
if (!declOrError)
return declOrError.takeError();
ctx.evaluator.cacheOutput( opaqueDecl = cast<OpaqueTypeDecl>(declOrError.get());
OpaqueResultTypeRequest{fn}, }
cast<OpaqueTypeDecl>(declOrError.get())); ctx.evaluator.cacheOutput(OpaqueResultTypeRequest{fn},
std::move(opaqueDecl));
} }
if (!isAccessor) if (!isAccessor)
@@ -5204,16 +5210,19 @@ public:
subscript->setOverriddenDecl(cast_or_null<SubscriptDecl>(overridden.get())); subscript->setOverriddenDecl(cast_or_null<SubscriptDecl>(overridden.get()));
if (subscript->getOverriddenDecl()) if (subscript->getOverriddenDecl())
AddAttribute(new (ctx) OverrideAttr(SourceLoc())); AddAttribute(new (ctx) OverrideAttr(SourceLoc()));
if (opaqueReturnTypeID) {
Decl *opaqueReturnType;
UNWRAP(MF.getDeclChecked(opaqueReturnTypeID), opaqueReturnType);
ctx.evaluator.cacheOutput( {
OpaqueResultTypeRequest{subscript}, OpaqueTypeDecl *opaqueDecl = nullptr;
cast<OpaqueTypeDecl>(opaqueReturnType)); if (opaqueReturnTypeID) {
Decl *opaqueReturnType;
UNWRAP(MF.getDeclChecked(opaqueReturnTypeID), opaqueReturnType);
opaqueDecl = cast<OpaqueTypeDecl>(opaqueReturnType);
}
ctx.evaluator.cacheOutput(OpaqueResultTypeRequest{subscript},
std::move(opaqueDecl));
} }
return subscript; return subscript;
} }