[Serialization] Store offset of decls in .swiftsourceinfo

The locations stored in .swiftsourceinfo included the presumed file,
line, and column. When a location is requested it would read these, open
the external file, create a line map, and find the offset corresponding
to that line/column.

The offset is known during serialization though, so output it as well to
avoid having to read the file and generate the line map.

Since the serialized location is returned from `Decl::getLoc()`, it
should not be the presumed location. Instead, also output the line
directives so that the presumed location can be built as per normal
locations.

Finally, move the cache out of `Decl` and into `ASTContext`, since very
few declarations will actually have their locations deserialized. Make
sure to actually write to that cache so it's used - the old cache was
never written to.
This commit is contained in:
Ben Barham
2021-04-23 11:36:18 +10:00
parent 02b5be7047
commit c763ab5d1e
18 changed files with 309 additions and 225 deletions

View File

@@ -1020,16 +1020,36 @@ void ModuleFile::collectBasicSourceFileInfo(
}
}
Optional<BasicDeclLocs>
ModuleFile::getBasicDeclLocsForDecl(const Decl *D) const {
assert(D);
static StringRef readLocString(const char *&Data, StringRef StringData) {
auto Str =
StringData.substr(endian::readNext<uint32_t, little, unaligned>(Data));
size_t TerminatorOffset = Str.find('\0');
assert(TerminatorOffset != StringRef::npos && "unterminated string data");
return Str.slice(0, TerminatorOffset);
}
static void readRawLoc(ExternalSourceLocs::RawLoc &Loc, const char *&Data,
StringRef StringData) {
Loc.Offset = endian::readNext<uint32_t, little, unaligned>(Data);
Loc.Line = endian::readNext<uint32_t, little, unaligned>(Data);
Loc.Column = endian::readNext<uint32_t, little, unaligned>(Data);
Loc.Directive.Offset = endian::readNext<uint32_t, little, unaligned>(Data);
Loc.Directive.LineOffset = endian::readNext<int32_t, little, unaligned>(Data);
Loc.Directive.Length = endian::readNext<uint32_t, little, unaligned>(Data);
Loc.Directive.Name = readLocString(Data, StringData);
}
Optional<ExternalSourceLocs::RawLocs>
ModuleFile::getExternalRawLocsForDecl(const Decl *D) const {
assert(D);
// Keep these as assertions instead of early exits to ensure that we are not
// doing extra work. These cases should be handled by clients of this API.
assert(!D->hasClangNode() &&
"cannot find comments for Clang decls in Swift modules");
assert(D->getDeclContext()->getModuleScopeContext() == FileContext &&
"Decl is from a different serialized file");
if (!Core->DeclUSRsTable)
return None;
// Future compilers may not provide BasicDeclLocsData anymore.
@@ -1037,6 +1057,7 @@ ModuleFile::getBasicDeclLocsForDecl(const Decl *D) const {
return None;
if (D->isImplicit())
return None;
// Compute the USR.
llvm::SmallString<128> USRBuffer;
llvm::raw_svector_ostream OS(USRBuffer);
@@ -1046,52 +1067,39 @@ ModuleFile::getBasicDeclLocsForDecl(const Decl *D) const {
auto It = Core->DeclUSRsTable->find(OS.str());
if (It == Core->DeclUSRsTable->end())
return None;
auto UsrId = *It;
uint32_t NumSize = 4;
// Size of BasicDeclLocs in the buffer.
// FilePathOffset + LocNum * LineColumn
uint32_t LineColumnCount = 3;
uint32_t RecordSize =
NumSize + // Offset into source filename blob
NumSize + // Offset into doc ranges blob
NumSize * 2 * LineColumnCount; // Line/column of: Loc, StartLoc, EndLoc
4 + // Source filename offset
4 + // Doc ranges offset
4 * 3 * 7; // Loc/StartLoc/EndLoc each have 7 4-byte fields
uint32_t RecordOffset = RecordSize * UsrId;
assert(RecordOffset < Core->BasicDeclLocsData.size());
assert(Core->BasicDeclLocsData.size() % RecordSize == 0);
BasicDeclLocs Result;
auto *Record = Core->BasicDeclLocsData.data() + RecordOffset;
auto ReadNext = [&Record]() {
return endian::readNext<uint32_t, little, unaligned>(Record);
};
auto FilePath = Core->SourceLocsTextData.substr(ReadNext());
size_t TerminatorOffset = FilePath.find('\0');
assert(TerminatorOffset != StringRef::npos && "unterminated string data");
Result.SourceFilePath = FilePath.slice(0, TerminatorOffset);
ExternalSourceLocs::RawLocs Result;
Result.SourceFilePath = readLocString(Record, Core->SourceLocsTextData);
const auto DocRangesOffset = ReadNext();
const auto DocRangesOffset =
endian::readNext<uint32_t, little, unaligned>(Record);
if (DocRangesOffset) {
assert(!Core->DocRangesData.empty());
const auto *Data = Core->DocRangesData.data() + DocRangesOffset;
const auto NumLocs = endian::readNext<uint32_t, little, unaligned>(Data);
assert(NumLocs);
for (uint32_t i = 0; i < NumLocs; ++i) {
SourcePosition LC;
LC.Line = endian::readNext<uint32_t, little, unaligned>(Data);
LC.Column = endian::readNext<uint32_t, little, unaligned>(Data);
auto Length = endian::readNext<uint32_t, little, unaligned>(Data);
Result.DocRanges.push_back(std::make_pair(LC, Length));
for (uint32_t I = 0; I < NumLocs; ++I) {
auto &Range =
Result.DocRanges.emplace_back(ExternalSourceLocs::RawLoc(), 0);
readRawLoc(Range.first, Data, Core->SourceLocsTextData);
Range.second = endian::readNext<uint32_t, little, unaligned>(Data);
}
}
#define READ_FIELD(X) \
Result.X.Line = ReadNext(); \
Result.X.Column = ReadNext();
READ_FIELD(Loc)
READ_FIELD(StartLoc)
READ_FIELD(EndLoc)
#undef READ_FIELD
readRawLoc(Result.Loc, Record, Core->SourceLocsTextData);
readRawLoc(Result.StartLoc, Record, Core->SourceLocsTextData);
readRawLoc(Result.EndLoc, Record, Core->SourceLocsTextData);
return Result;
}