Make deserialization of known protocol adopters lazy.

...by adding a new callback to ModuleLoader: loadDeclsConformingTo.
This is used only when the type checker doesn't have enough contextual
information to resolve an expression involving a literal, so it's
possible many *LiteralConvertible types will never be loaded.

Deserialization of types with conversion methods is still eager, since
there's no easy hook to tell when they're needed, but the list has been
renamed to refer to any decls that need to be eagerly deserialized, in
case we need it for other purposes in the future.

This probably won't help much in a real program, but it cuts the test
run time by about 5-10% in my build.

Swift SVN r7268
This commit is contained in:
Jordan Rose
2013-08-15 18:43:40 +00:00
parent 4c74b6ced7
commit 95ff29b6e2
8 changed files with 87 additions and 42 deletions

View File

@@ -2004,8 +2004,8 @@ static Optional<KnownProtocolKind> getActualKnownProtocol(unsigned rawKind) {
#define PROTOCOL(Id) \
case index_block::Id: return KnownProtocolKind::Id;
#include "swift/AST/KnownProtocols.def"
case index_block::CONVERSION:
llvm_unreachable("must handle CONVERSION explicitly");
case index_block::FORCE_DESERIALIZATION:
llvm_unreachable("must handle FORCE_DESERIALIZATION explicitly");
}
// If there's a new case value in the module file, ignore it.
@@ -2032,17 +2032,19 @@ bool ModuleFile::readKnownProtocolsBlock(llvm::BitstreamCursor &cursor) {
case llvm::BitstreamEntry::Record: {
scratch.clear();
unsigned rawKind = cursor.readRecord(next.ID, scratch);
unsigned index;
if (rawKind == index_block::CONVERSION)
index = NumKnownProtocols;
else if (auto actualKind = getActualKnownProtocol(rawKind))
index = static_cast<unsigned>(actualKind.getValue());
else
break; // ignore this record
DeclIDVector *list;
if (rawKind == index_block::FORCE_DESERIALIZATION) {
list = &EagerDeserializationDecls;
} else if (auto actualKind = getActualKnownProtocol(rawKind)) {
auto index = static_cast<unsigned>(actualKind.getValue());
list = &KnownProtocolAdopters[index];
} else {
// Ignore this record.
break;
}
auto &adopterList = KnownProtocolAdopters[index];
adopterList.append(scratch.begin(), scratch.end());
list->append(scratch.begin(), scratch.end());
break;
}
}
@@ -2265,6 +2267,12 @@ ModuleFile::ModuleFile(llvm::OwningPtr<llvm::MemoryBuffer> &&input)
return error();
}
static NominalTypeDecl *getAnyNominal(Decl *D) {
if (auto extension = dyn_cast<ExtensionDecl>(D))
D = extension->getExtendedType()->getAnyNominal();
return dyn_cast_or_null<NominalTypeDecl>(D);
}
bool ModuleFile::associateWithModule(Module *module) {
assert(Status == ModuleStatus::Valid && "invalid module file");
assert(!ModuleContext && "already associated with an AST module");
@@ -2303,21 +2311,11 @@ bool ModuleFile::associateWithModule(Module *module) {
return false;
}
// Eagerly deserialize decls conforming to special protocols.
for (unsigned i = 0; i < NumKnownProtocols+1; ++i) {
for (DeclID DID : KnownProtocolAdopters[i]) {
Decl *decl = getDecl(DID);
// Don't record any conformance for the plain "force deserialization"
// decls.
if (i < NumKnownProtocols)
ctx.recordConformance(static_cast<KnownProtocolKind>(i), decl);
if (auto extension = dyn_cast<ExtensionDecl>(decl))
decl = extension->getExtendedType()->getAnyNominal();
if (auto nominal = dyn_cast_or_null<NominalTypeDecl>(decl))
loadExtensions(nominal);
}
// Process decls we know we want to eagerly deserialize.
for (DeclID DID : EagerDeserializationDecls) {
Decl *decl = getDecl(DID);
if (auto nominal = getAnyNominal(decl))
loadExtensions(nominal);
}
return Status == ModuleStatus::Valid;
@@ -2408,3 +2406,13 @@ void ModuleFile::loadExtensions(NominalTypeDecl *nominal) {
}
}
void ModuleFile::loadDeclsConformingTo(KnownProtocolKind kind) {
auto index = static_cast<unsigned>(kind);
for (DeclID DID : KnownProtocolAdopters[index]) {
Decl *D = getDecl(DID);
ModuleContext->Ctx.recordConformance(kind, D);
if (auto nominal = getAnyNominal(D))
loadExtensions(nominal);
}
}