Skip to content

Commit 13dd70a

Browse files
author
ematejska
authored
Merge pull request #7097 from jrose-apple/3.1-nested-type-lookup-table
[Serialization] Add a "nested types" lookup table for partial modules
2 parents e4a064f + adbfbe9 commit 13dd70a

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
@@ -320,13 +320,18 @@ class ModuleFile : public LazyMemberLoader {
320320
using SerializedLocalDeclTable =
321321
llvm::OnDiskIterableChainedHashTable<LocalDeclTableInfo>;
322322

323+
class NestedTypeDeclsTableInfo;
324+
using SerializedNestedTypeDeclsTable =
325+
llvm::OnDiskIterableChainedHashTable<NestedTypeDeclsTableInfo>;
326+
323327
std::unique_ptr<SerializedDeclTable> TopLevelDecls;
324328
std::unique_ptr<SerializedDeclTable> OperatorDecls;
325329
std::unique_ptr<SerializedDeclTable> PrecedenceGroupDecls;
326330
std::unique_ptr<SerializedDeclTable> ExtensionDecls;
327331
std::unique_ptr<SerializedDeclTable> ClassMembersByName;
328332
std::unique_ptr<SerializedDeclTable> OperatorMethodDecls;
329333
std::unique_ptr<SerializedLocalDeclTable> LocalTypeDecls;
334+
std::unique_ptr<SerializedNestedTypeDeclsTable> NestedTypeDecls;
330335

331336
class ObjCMethodTableInfo;
332337
using SerializedObjCMethodTable =
@@ -445,6 +450,11 @@ class ModuleFile : public LazyMemberLoader {
445450
std::unique_ptr<ModuleFile::SerializedObjCMethodTable>
446451
readObjCMethodTable(ArrayRef<uint64_t> fields, StringRef blobData);
447452

453+
/// Read an on-disk local decl hash table stored in
454+
/// index_block::NestedTypeDeclsLayout format.
455+
std::unique_ptr<SerializedNestedTypeDeclsTable>
456+
readNestedTypeDeclsTable(ArrayRef<uint64_t> fields, StringRef blobData);
457+
448458
/// Reads the index block, which contains global tables.
449459
///
450460
/// Returns false if there was an error.
@@ -584,6 +594,10 @@ class ModuleFile : public LazyMemberLoader {
584594
/// Searches the module's local type decls for the given mangled name.
585595
TypeDecl *lookupLocalType(StringRef MangledName);
586596

597+
/// Searches the module's nested type decls table for the given member of
598+
/// the given type.
599+
TypeDecl *lookupNestedType(Identifier name, const ValueDecl *parent);
600+
587601
/// Searches the module's operators for one with the given name and fixity.
588602
///
589603
/// 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>;
@@ -1442,7 +1442,8 @@ namespace index_block {
14421442
SIL_LAYOUT_OFFSETS,
14431443

14441444
PRECEDENCE_GROUPS,
1445-
1445+
NESTED_TYPE_DECLS,
1446+
14461447
LastRecordKind = PRECEDENCE_GROUPS,
14471448
};
14481449

@@ -1473,6 +1474,12 @@ namespace index_block {
14731474
BCBlob // map from Objective-C selectors to methods with that selector
14741475
>;
14751476

1477+
using NestedTypeDeclsLayout = BCRecordLayout<
1478+
NESTED_TYPE_DECLS, // record ID
1479+
BCVBR<16>, // table offset within the blob (see below)
1480+
BCBlob // map from identifier strings to decl kinds / decl IDs
1481+
>;
1482+
14761483
using EntryPointLayout = BCRecordLayout<
14771484
ENTRY_POINT,
14781485
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
@@ -22,8 +22,17 @@
2222
#include "swift/ClangImporter/ClangImporter.h"
2323
#include "swift/Parse/Parser.h"
2424
#include "swift/Serialization/BCReadingExtras.h"
25+
#include "swift/Serialization/SerializedModuleLoader.h"
26+
#include "llvm/ADT/Statistic.h"
2527
#include "llvm/Support/raw_ostream.h"
2628

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

@@ -225,6 +234,10 @@ namespace {
225234
path.push_back({ PathPiece::Kind::Unknown, kind });
226235
}
227236

237+
void removeLast() {
238+
path.pop_back();
239+
}
240+
228241
void print(raw_ostream &os) const override {
229242
os << "Cross-reference to module '" << baseM.getName() << "'\n";
230243
for (auto &piece : path) {
@@ -1408,7 +1421,61 @@ Decl *ModuleFile::resolveCrossReference(ModuleDecl *M, uint32_t pathLen) {
14081421
unsigned recordID = DeclTypeCursor.readRecord(entry.ID, scratch,
14091422
&blobData);
14101423
switch (recordID) {
1411-
case XREF_TYPE_PATH_PIECE:
1424+
case XREF_TYPE_PATH_PIECE: {
1425+
if (values.size() == 1) {
1426+
ModuleDecl *module = values.front()->getModuleContext();
1427+
if (module == this->getAssociatedModule()) {
1428+
// Fast path for nested types in the same module.
1429+
IdentifierID IID;
1430+
bool onlyInNominal = false;
1431+
XRefTypePathPieceLayout::readRecord(scratch, IID, onlyInNominal);
1432+
Identifier memberName = getIdentifier(IID);
1433+
pathTrace.addValue(memberName);
1434+
1435+
llvm::PrettyStackTraceString message{
1436+
"If you're seeing a crash here, try passing "
1437+
"-Xfrontend -disable-serialization-nested-type-lookup-table"};
1438+
1439+
TypeDecl *nestedType = nullptr;
1440+
if (onlyInNominal) {
1441+
// Only look in the file containing the type itself.
1442+
const DeclContext *dc = values.front()->getDeclContext();
1443+
auto *serializedFile =
1444+
dyn_cast<SerializedASTFile>(dc->getModuleScopeContext());
1445+
if (serializedFile) {
1446+
nestedType =
1447+
serializedFile->File.lookupNestedType(memberName,
1448+
values.front());
1449+
}
1450+
} else {
1451+
// Fault in extensions, then ask every serialized AST in the module.
1452+
(void)cast<NominalTypeDecl>(values.front())->getExtensions();
1453+
for (FileUnit *file : module->getFiles()) {
1454+
if (file == getFile())
1455+
continue;
1456+
auto *serializedFile = dyn_cast<SerializedASTFile>(file);
1457+
if (!serializedFile)
1458+
continue;
1459+
nestedType =
1460+
serializedFile->File.lookupNestedType(memberName,
1461+
values.front());
1462+
if (nestedType)
1463+
break;
1464+
}
1465+
}
1466+
1467+
if (nestedType) {
1468+
values.clear();
1469+
values.push_back(nestedType);
1470+
++NumNestedTypeShortcuts;
1471+
break;
1472+
}
1473+
1474+
pathTrace.removeLast();
1475+
}
1476+
}
1477+
SWIFT_FALLTHROUGH;
1478+
}
14121479
case XREF_VALUE_PATH_PIECE:
14131480
case XREF_INITIALIZER_PATH_PIECE: {
14141481
TypeID TID = 0;
@@ -4198,6 +4265,7 @@ Type ModuleFile::getType(TypeID TID) {
41984265

41994266
void ModuleFile::loadAllMembers(Decl *D, uint64_t contextData) {
42004267
PrettyStackTraceDecl trace("loading members for", D);
4268+
++NumMemberListsLoaded;
42014269

42024270
BCOffsetRAII restoreOffset(DeclTypeCursor);
42034271
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());
@@ -1206,6 +1265,31 @@ TypeDecl *ModuleFile::lookupLocalType(StringRef MangledName) {
12061265
return cast<TypeDecl>(getDecl((*iter).first));
12071266
}
12081267

1268+
TypeDecl *ModuleFile::lookupNestedType(Identifier name,
1269+
const ValueDecl *parent) {
1270+
PrettyModuleFileDeserialization stackEntry(*this);
1271+
1272+
if (!NestedTypeDecls)
1273+
return nullptr;
1274+
1275+
auto iter = NestedTypeDecls->find(name);
1276+
if (iter == NestedTypeDecls->end())
1277+
return nullptr;
1278+
1279+
auto data = *iter;
1280+
for (std::pair<DeclID, DeclID> entry : data) {
1281+
assert(entry.first);
1282+
auto declOrOffset = Decls[entry.first - 1];
1283+
if (!declOrOffset.isComplete())
1284+
continue;
1285+
if (declOrOffset != parent)
1286+
continue;
1287+
return cast<TypeDecl>(getDecl(entry.second));
1288+
}
1289+
1290+
return nullptr;
1291+
}
1292+
12091293
OperatorDecl *ModuleFile::lookupOperator(Identifier name, DeclKind fixity) {
12101294
PrettyModuleFileDeserialization stackEntry(*this);
12111295

0 commit comments

Comments
 (0)