Skip to content

Commit 99d4761

Browse files
authored
Merge pull request #7067 from jrose-apple/nested-type-lookup-table
[Serialization] Add a "nested types" lookup table for partial modules
2 parents 52601c0 + 8145cd0 commit 99d4761

17 files changed

+384
-31
lines changed

include/swift/Frontend/FrontendOptions.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,11 @@ class FrontendOptions {
194194
/// until the end of all files.
195195
bool DelayedFunctionBodyParsing = false;
196196

197+
/// If true, serialization encodes an extra lookup table for use in module-
198+
/// merging when emitting partial modules (the per-file modules in a non-WMO
199+
/// build).
200+
bool EnableSerializationNestedTypeLookupTable = true;
201+
197202
/// Indicates whether or not an import statement can pick up a Swift source
198203
/// file (as opposed to a module file).
199204
bool EnableSourceImport = false;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ def autolink_library : Separate<["-"], "autolink-library">,
119119
def disable_typo_correction : Flag<["-"], "disable-typo-correction">,
120120
HelpText<"Disable typo correction">;
121121

122+
def disable_serialization_nested_type_lookup_table :
123+
Flag<["-"], "disable-serialization-nested-type-lookup-table">,
124+
HelpText<"Force module merging to use regular lookups to find nested types">;
125+
122126
} // end let Flags = [FrontendOption, NoDriverOption]
123127

124128
def debug_crash_Group : OptionGroup<"<automatic crashing options>">;

include/swift/Serialization/ModuleFile.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,18 @@ class ModuleFile : public LazyMemberLoader {
316316
using SerializedLocalDeclTable =
317317
llvm::OnDiskIterableChainedHashTable<LocalDeclTableInfo>;
318318

319+
class NestedTypeDeclsTableInfo;
320+
using SerializedNestedTypeDeclsTable =
321+
llvm::OnDiskIterableChainedHashTable<NestedTypeDeclsTableInfo>;
322+
319323
std::unique_ptr<SerializedDeclTable> TopLevelDecls;
320324
std::unique_ptr<SerializedDeclTable> OperatorDecls;
321325
std::unique_ptr<SerializedDeclTable> PrecedenceGroupDecls;
322326
std::unique_ptr<SerializedDeclTable> ExtensionDecls;
323327
std::unique_ptr<SerializedDeclTable> ClassMembersByName;
324328
std::unique_ptr<SerializedDeclTable> OperatorMethodDecls;
325329
std::unique_ptr<SerializedLocalDeclTable> LocalTypeDecls;
330+
std::unique_ptr<SerializedNestedTypeDeclsTable> NestedTypeDecls;
326331

327332
class ObjCMethodTableInfo;
328333
using SerializedObjCMethodTable =
@@ -441,6 +446,11 @@ class ModuleFile : public LazyMemberLoader {
441446
std::unique_ptr<ModuleFile::SerializedObjCMethodTable>
442447
readObjCMethodTable(ArrayRef<uint64_t> fields, StringRef blobData);
443448

449+
/// Read an on-disk local decl hash table stored in
450+
/// index_block::NestedTypeDeclsLayout format.
451+
std::unique_ptr<SerializedNestedTypeDeclsTable>
452+
readNestedTypeDeclsTable(ArrayRef<uint64_t> fields, StringRef blobData);
453+
444454
/// Reads the index block, which contains global tables.
445455
///
446456
/// Returns false if there was an error.
@@ -580,6 +590,10 @@ class ModuleFile : public LazyMemberLoader {
580590
/// Searches the module's local type decls for the given mangled name.
581591
TypeDecl *lookupLocalType(StringRef MangledName);
582592

593+
/// Searches the module's nested type decls table for the given member of
594+
/// the given type.
595+
TypeDecl *lookupNestedType(Identifier name, const ValueDecl *parent);
596+
583597
/// Searches the module's operators for one with the given name and fixity.
584598
///
585599
/// If none is found, returns null.

include/swift/Serialization/ModuleFormat.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const uint16_t VERSION_MAJOR = 0;
5454
/// in source control, you should also update the comment to briefly
5555
/// describe what change you made. The content of this comment isn't important;
5656
/// it just ensures a conflict if two people change the module format.
57-
const uint16_t VERSION_MINOR = 307; // Last change: layout requirements
57+
const uint16_t VERSION_MINOR = 308; // Last change: nested type table
5858

5959
using DeclID = PointerEmbeddedInt<unsigned, 31>;
6060
using DeclIDField = BCFixed<31>;
@@ -1463,7 +1463,8 @@ namespace index_block {
14631463
SIL_LAYOUT_OFFSETS,
14641464

14651465
PRECEDENCE_GROUPS,
1466-
1466+
NESTED_TYPE_DECLS,
1467+
14671468
LastRecordKind = PRECEDENCE_GROUPS,
14681469
};
14691470

@@ -1494,6 +1495,12 @@ namespace index_block {
14941495
BCBlob // map from Objective-C selectors to methods with that selector
14951496
>;
14961497

1498+
using NestedTypeDeclsLayout = BCRecordLayout<
1499+
NESTED_TYPE_DECLS, // record ID
1500+
BCVBR<16>, // table offset within the blob (see below)
1501+
BCBlob // map from identifier strings to decl kinds / decl IDs
1502+
>;
1503+
14971504
using EntryPointLayout = BCRecordLayout<
14981505
ENTRY_POINT,
14991506
DeclIDField // the ID of the main class; 0 if there was a main source file

include/swift/Serialization/SerializationOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ namespace swift {
3636
ArrayRef<std::string> ExtraClangOptions;
3737

3838
bool AutolinkForceLoad = false;
39+
bool EnableNestedTypeLookupTable = false;
3940
bool SerializeAllSIL = false;
4041
bool SerializeOptionsForDebugging = false;
4142
bool IsSIB = false;

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class SerializedModuleLoader : public ModuleLoader {
104104
class SerializedASTFile final : public LoadedFile {
105105
friend class SerializedModuleLoader;
106106
friend class SerializedSILLoader;
107+
friend class ModuleFile;
107108

108109
ModuleFile &File;
109110
bool IsSIB;

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,8 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args,
767767
Opts.EnableSourceImport |= Args.hasArg(OPT_enable_source_import);
768768
Opts.ImportUnderlyingModule |= Args.hasArg(OPT_import_underlying_module);
769769
Opts.SILSerializeAll |= Args.hasArg(OPT_sil_serialize_all);
770+
Opts.EnableSerializationNestedTypeLookupTable &=
771+
!Args.hasArg(OPT_disable_serialization_nested_type_lookup_table);
770772

771773
if (const Arg *A = Args.getLastArgNoClaim(OPT_import_objc_header)) {
772774
Opts.ImplicitObjCHeaderPath = A->getValue();

lib/FrontendTool/FrontendTool.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,8 @@ static bool performCompile(std::unique_ptr<CompilerInstance> &Instance,
666666
serializationOpts.ModuleLinkName = opts.ModuleLinkName;
667667
serializationOpts.ExtraClangOptions =
668668
Invocation.getClangImporterOptions().ExtraArgs;
669+
serializationOpts.EnableNestedTypeLookupTable =
670+
opts.EnableSerializationNestedTypeLookupTable;
669671
if (!IRGenOpts.ForceLoadSymbolName.empty())
670672
serializationOpts.AutolinkForceLoad = true;
671673

lib/Serialization/Deserialization.cpp

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,17 @@
2323
#include "swift/ClangImporter/ClangImporter.h"
2424
#include "swift/Parse/Parser.h"
2525
#include "swift/Serialization/BCReadingExtras.h"
26+
#include "swift/Serialization/SerializedModuleLoader.h"
27+
#include "llvm/ADT/Statistic.h"
2628
#include "llvm/Support/raw_ostream.h"
2729

30+
#define DEBUG_TYPE "Serialization"
31+
32+
STATISTIC(NumMemberListsLoaded,
33+
"# of nominals/extensions whose members were loaded");
34+
STATISTIC(NumNestedTypeShortcuts,
35+
"# of same-module nested types resolved without lookup");
36+
2837
using namespace swift;
2938
using namespace swift::serialization;
3039

@@ -226,6 +235,10 @@ namespace {
226235
path.push_back({ PathPiece::Kind::Unknown, kind });
227236
}
228237

238+
void removeLast() {
239+
path.pop_back();
240+
}
241+
229242
void print(raw_ostream &os) const override {
230243
os << "Cross-reference to module '" << baseM.getName() << "'\n";
231244
for (auto &piece : path) {
@@ -1455,7 +1468,61 @@ Decl *ModuleFile::resolveCrossReference(ModuleDecl *M, uint32_t pathLen) {
14551468
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch,
14561469
&blobData);
14571470
switch (recordID) {
1458-
case XREF_TYPE_PATH_PIECE:
1471+
case XREF_TYPE_PATH_PIECE: {
1472+
if (values.size() == 1) {
1473+
ModuleDecl *module = values.front()->getModuleContext();
1474+
if (module == this->getAssociatedModule()) {
1475+
// Fast path for nested types in the same module.
1476+
IdentifierID IID;
1477+
bool onlyInNominal = false;
1478+
XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
1479+
Identifier memberName = getIdentifier(IID);
1480+
pathTrace.addValue(memberName);
1481+
1482+
llvm::PrettyStackTraceString message{
1483+
"If you're seeing a crash here, try passing "
1484+
"-Xfrontend -disable-serialization-nested-type-lookup-table"};
1485+
1486+
TypeDecl *nestedType = nullptr;
1487+
if (onlyInNominal) {
1488+
// Only look in the file containing the type itself.
1489+
const DeclContext *dc = values.front()->getDeclContext();
1490+
auto *serializedFile =
1491+
dyn_cast<SerializedASTFile>(dc->getModuleScopeContext());
1492+
if (serializedFile) {
1493+
nestedType =
1494+
serializedFile->File.lookupNestedType(memberName,
1495+
values.front());
1496+
}
1497+
} else {
1498+
// Fault in extensions, then ask every serialized AST in the module.
1499+
(void)cast<NominalTypeDecl>(values.front())->getExtensions();
1500+
for (FileUnit *file : module->getFiles()) {
1501+
if (file == getFile())
1502+
continue;
1503+
auto *serializedFile = dyn_cast<SerializedASTFile>(file);
1504+
if (!serializedFile)
1505+
continue;
1506+
nestedType =
1507+
serializedFile->File.lookupNestedType(memberName,
1508+
values.front());
1509+
if (nestedType)
1510+
break;
1511+
}
1512+
}
1513+
1514+
if (nestedType) {
1515+
values.clear();
1516+
values.push_back(nestedType);
1517+
++NumNestedTypeShortcuts;
1518+
break;
1519+
}
1520+
1521+
pathTrace.removeLast();
1522+
}
1523+
}
1524+
SWIFT_FALLTHROUGH;
1525+
}
14591526
case XREF_VALUE_PATH_PIECE:
14601527
case XREF_INITIALIZER_PATH_PIECE: {
14611528
TypeID TID = 0;
@@ -4254,6 +4321,7 @@ Type ModuleFile::getType(TypeID TID) {
42544321

42554322
void ModuleFile::loadAllMembers(Decl *D, uint64_t contextData) {
42564323
PrettyStackTraceDecl trace("loading members for", D);
4324+
++NumMemberListsLoaded;
42574325

42584326
BCOffsetRAII restoreOffset(DeclTypeCursor);
42594327
DeclTypeCursor.JumpToBit(contextData);

lib/Serialization/ModuleFile.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,50 @@ class ModuleFile::LocalDeclTableInfo {
377377
}
378378
};
379379

380+
class ModuleFile::NestedTypeDeclsTableInfo {
381+
public:
382+
using internal_key_type = StringRef;
383+
using external_key_type = Identifier;
384+
using data_type = SmallVector<std::pair<DeclID, DeclID>, 4>;
385+
using hash_value_type = uint32_t;
386+
using offset_type = unsigned;
387+
388+
internal_key_type GetInternalKey(external_key_type ID) {
389+
return ID.str();
390+
}
391+
392+
hash_value_type ComputeHash(internal_key_type key) {
393+
return llvm::HashString(key);
394+
}
395+
396+
static bool EqualKey(internal_key_type lhs, internal_key_type rhs) {
397+
return lhs == rhs;
398+
}
399+
400+
static std::pair<unsigned, unsigned> ReadKeyDataLength(const uint8_t *&data) {
401+
unsigned keyLength = endian::readNext<uint16_t, little, unaligned>(data);
402+
unsigned dataLength = endian::readNext<uint16_t, little, unaligned>(data);
403+
return { keyLength, dataLength };
404+
}
405+
406+
static internal_key_type ReadKey(const uint8_t *data, unsigned length) {
407+
return StringRef(reinterpret_cast<const char *>(data), length);
408+
}
409+
410+
static data_type ReadData(internal_key_type key, const uint8_t *data,
411+
unsigned length) {
412+
data_type result;
413+
while (length > 0) {
414+
DeclID parentID = endian::readNext<uint32_t, little, unaligned>(data);
415+
DeclID childID = endian::readNext<uint32_t, little, unaligned>(data);
416+
result.push_back({ parentID, childID });
417+
length -= sizeof(uint32_t) * 2;
418+
}
419+
420+
return result;
421+
}
422+
};
423+
380424
std::unique_ptr<ModuleFile::SerializedDeclTable>
381425
ModuleFile::readDeclTable(ArrayRef<uint64_t> fields, StringRef blobData) {
382426
uint32_t tableOffset;
@@ -399,6 +443,18 @@ ModuleFile::readLocalDeclTable(ArrayRef<uint64_t> fields, StringRef blobData) {
399443
base + sizeof(uint32_t), base));
400444
}
401445

446+
std::unique_ptr<ModuleFile::SerializedNestedTypeDeclsTable>
447+
ModuleFile::readNestedTypeDeclsTable(ArrayRef<uint64_t> fields,
448+
StringRef blobData) {
449+
uint32_t tableOffset;
450+
index_block::NestedTypeDeclsLayout::readRecord(fields, tableOffset);
451+
auto base = reinterpret_cast<const uint8_t *>(blobData.data());
452+
453+
using OwnedTable = std::unique_ptr<SerializedNestedTypeDeclsTable>;
454+
return OwnedTable(SerializedNestedTypeDeclsTable::Create(base + tableOffset,
455+
base + sizeof(uint32_t), base));
456+
}
457+
402458
/// Used to deserialize entries in the on-disk Objective-C method table.
403459
class ModuleFile::ObjCMethodTableInfo {
404460
public:
@@ -531,6 +587,9 @@ bool ModuleFile::readIndexBlock(llvm::BitstreamCursor &cursor) {
531587
case index_block::LOCAL_TYPE_DECLS:
532588
LocalTypeDecls = readLocalDeclTable(scratch, blobData);
533589
break;
590+
case index_block::NESTED_TYPE_DECLS:
591+
NestedTypeDecls = readNestedTypeDeclsTable(scratch, blobData);
592+
break;
534593
case index_block::LOCAL_DECL_CONTEXT_OFFSETS:
535594
assert(blobData.empty());
536595
LocalDeclContexts.assign(scratch.begin(), scratch.end());
@@ -1198,6 +1257,31 @@ TypeDecl *ModuleFile::lookupLocalType(StringRef MangledName) {
11981257
return cast<TypeDecl>(getDecl((*iter).first));
11991258
}
12001259

1260+
TypeDecl *ModuleFile::lookupNestedType(Identifier name,
1261+
const ValueDecl *parent) {
1262+
PrettyModuleFileDeserialization stackEntry(*this);
1263+
1264+
if (!NestedTypeDecls)
1265+
return nullptr;
1266+
1267+
auto iter = NestedTypeDecls->find(name);
1268+
if (iter == NestedTypeDecls->end())
1269+
return nullptr;
1270+
1271+
auto data = *iter;
1272+
for (std::pair<DeclID, DeclID> entry : data) {
1273+
assert(entry.first);
1274+
auto declOrOffset = Decls[entry.first - 1];
1275+
if (!declOrOffset.isComplete())
1276+
continue;
1277+
if (declOrOffset != parent)
1278+
continue;
1279+
return cast<TypeDecl>(getDecl(entry.second));
1280+
}
1281+
1282+
return nullptr;
1283+
}
1284+
12011285
OperatorDecl *ModuleFile::lookupOperator(Identifier name, DeclKind fixity) {
12021286
PrettyModuleFileDeserialization stackEntry(*this);
12031287

0 commit comments

Comments
 (0)