mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user