[Serialization] Add a "nested types" lookup table for partial modules.

There's a class of errors in Serialization called "circularity
issues", where declaration A in file A.swift depends on declaration B
in file B.swift, and B also depends on A. In some cases we can manage
to type-check each of these files individually due to the laziness of
'validateDecl', but then fail to merge the "partial modules" generated
from A.swift and B.swift to form a single swiftmodule for the library
(because deserialization is a little less lazy for some things). A
common case of this is when at least one of the declarations is
nested, in which case a lookup to find that declaration needs to load
all the members of the parent type. This gets even worse when the
nested type is defined in an extension.

This commit sidesteps that issue specifically for nested types by
creating a top-level, per-file table of nested types in the "partial
modules". When a type is in the same module, we can then look it up
/without/ importing all other members of the parent type.

The long-term solution is to allow accessing any members of a type
without having to load them all, something we should support not just
for module-merging while building a single target but when reading
from imported modules as well. This should improve both compile time
and memory usage, though I'm not sure to what extent. (Unfortunately,
too many things still depend on the whole members list being loaded.)

Because this is a new code path, I put in a switch to turn it off:
frontend flag -disable-serialization-nested-type-lookup-table

https://bugs.swift.org/browse/SR-3707 (and possibly others)
This commit is contained in:
Jordan Rose
2017-01-26 15:04:42 -08:00
parent 5d89d86a97
commit 8145cd0b22
17 changed files with 376 additions and 14 deletions

View File

@@ -377,6 +377,50 @@ public:
}
};
class ModuleFile::NestedTypeDeclsTableInfo {
public:
using internal_key_type = StringRef;
using external_key_type = Identifier;
using data_type = SmallVector<std::pair<DeclID, DeclID>, 4>;
using hash_value_type = uint32_t;
using offset_type = unsigned;
internal_key_type GetInternalKey(external_key_type ID) {
return ID.str();
}
hash_value_type ComputeHash(internal_key_type key) {
return llvm::HashString(key);
}
static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
return lhs == rhs;
}
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
return { keyLength, dataLength };
}
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
return StringRef(reinterpret_cast<const char *>(data), length);
}
static data_type ReadData(internal_key_type key, const uint8_t *data,
unsigned length) {
data_type result;
while (length > 0) {
DeclID parentID = endian::readNext<uint32_t, little, unaligned>(data);
DeclID childID = endian::readNext<uint32_t, little, unaligned>(data);
result.push_back({ parentID, childID });
length -= sizeof(uint32_t) * 2;
}
return result;
}
};
std::unique_ptr<ModuleFile::SerializedDeclTable>
ModuleFile::readDeclTable(ArrayRef<uint64_t> fields, StringRef blobData) {
uint32_t tableOffset;
@@ -399,6 +443,18 @@ ModuleFile::readLocalDeclTable(ArrayRef<uint64_t> fields, StringRef blobData) {
base + sizeof(uint32_t), base));
}
std::unique_ptr<ModuleFile::SerializedNestedTypeDeclsTable>
ModuleFile::readNestedTypeDeclsTable(ArrayRef<uint64_t> fields,
StringRef blobData) {
uint32_t tableOffset;
index_block::NestedTypeDeclsLayout::readRecord(fields, tableOffset);
auto base = reinterpret_cast<const uint8_t *>(blobData.data());
using OwnedTable = std::unique_ptr<SerializedNestedTypeDeclsTable>;
return OwnedTable(SerializedNestedTypeDeclsTable::Create(base + tableOffset,
base + sizeof(uint32_t), base));
}
/// Used to deserialize entries in the on-disk Objective-C method table.
class ModuleFile::ObjCMethodTableInfo {
public:
@@ -531,6 +587,9 @@ bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) {
case index_block::LOCAL_TYPE_DECLS:
LocalTypeDecls = readLocalDeclTable(scratch, blobData);
break;
case index_block::NESTED_TYPE_DECLS:
NestedTypeDecls = readNestedTypeDeclsTable(scratch, blobData);
break;
case index_block::LOCAL_DECL_CONTEXT_OFFSETS:
assert(blobData.empty());
LocalDeclContexts.assign(scratch.begin(), scratch.end());
@@ -1194,6 +1253,31 @@ TypeDecl *ModuleFile::lookupLocalType(StringRef MangledName) {
return cast<TypeDecl>(getDecl((*iter).first));
}
TypeDecl *ModuleFile::lookupNestedType(Identifier name,
const ValueDecl *parent) {
PrettyModuleFileDeserialization stackEntry(*this);
if (!NestedTypeDecls)
return nullptr;
auto iter = NestedTypeDecls->find(name);
if (iter == NestedTypeDecls->end())
return nullptr;
auto data = *iter;
for (std::pair<DeclID, DeclID> entry : data) {
assert(entry.first);
auto declOrOffset = Decls[entry.first - 1];
if (!declOrOffset.isComplete())
continue;
if (declOrOffset != parent)
continue;
return cast<TypeDecl>(getDecl(entry.second));
}
return nullptr;
}
OperatorDecl *ModuleFile::lookupOperator(Identifier name, DeclKind fixity) {
PrettyModuleFileDeserialization stackEntry(*this);