Skip to content

Commit c763ab5

Browse files
committed
[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.
1 parent 02b5be7 commit c763ab5

18 files changed

+308
-224
lines changed

Diff for: include/swift/AST/ASTContext.h

+5
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ namespace swift {
7373
class DerivativeAttr;
7474
class DifferentiableAttr;
7575
class ExtensionDecl;
76+
struct ExternalSourceLocs;
7677
class ForeignRepresentationInfo;
7778
class FuncDecl;
7879
class GenericContext;
@@ -1184,6 +1185,10 @@ class ASTContext final {
11841185

11851186
private:
11861187
friend Decl;
1188+
1189+
Optional<ExternalSourceLocs *> getExternalSourceLocs(const Decl *D);
1190+
void setExternalSourceLocs(const Decl *D, ExternalSourceLocs *Locs);
1191+
11871192
Optional<std::pair<RawComment, bool>> getRawComment(const Decl *D);
11881193
void setRawComment(const Decl *D, RawComment RC, bool FromSerialized);
11891194

Diff for: include/swift/AST/Decl.h

+7-8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ namespace swift {
6262
class DynamicSelfType;
6363
class Type;
6464
class Expr;
65+
struct ExternalSourceLocs;
6566
class CaptureListExpr;
6667
class DeclRefExpr;
6768
class ForeignAsyncConvention;
@@ -688,14 +689,12 @@ class alignas(1 << DeclAlignInBits) Decl {
688689
void operator=(const Decl&) = delete;
689690
SourceLoc getLocFromSource() const;
690691

691-
struct CachedExternalSourceLocs {
692-
SourceLoc Loc;
693-
SourceLoc StartLoc;
694-
SourceLoc EndLoc;
695-
SmallVector<CharSourceRange, 4> DocRanges;
696-
};
697-
mutable CachedExternalSourceLocs const *CachedSerializedLocs = nullptr;
698-
const CachedExternalSourceLocs *getSerializedLocs() const;
692+
/// Returns the serialized locations of this declaration from the
693+
/// corresponding .swiftsourceinfo file. "Empty" (ie. \c BufferID of 0, an
694+
/// invalid \c Loc, and empty \c DocRanges) if either there is no
695+
/// .swiftsourceinfo or the buffer could not be created, eg. if the file
696+
/// no longer exists.
697+
const ExternalSourceLocs *getSerializedLocs() const;
699698

700699
/// Directly set the invalid bit
701700
void setInvalidBit();

Diff for: include/swift/AST/FileUnit.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ class FileUnit : public DeclContext {
164164
return None;
165165
}
166166

167-
virtual Optional<BasicDeclLocs> getBasicLocsForDecl(const Decl *D) const {
167+
virtual Optional<ExternalSourceLocs::RawLocs>
168+
getExternalRawLocsForDecl(const Decl *D) const {
168169
return None;
169170
}
170171

Diff for: include/swift/AST/SourceFile.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ class SourceFile final : public FileUnit {
399399

400400
Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override;
401401
Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; }
402-
Optional<BasicDeclLocs> getBasicLocsForDecl(const Decl *D) const override;
402+
Optional<ExternalSourceLocs::RawLocs>
403+
getExternalRawLocsForDecl(const Decl *D) const override;
403404

404405
/// Returns the synthesized file for this source file, if it exists.
405406
SynthesizedFileUnit *getSynthesizedFile() const { return SynthesizedFile; };

Diff for: include/swift/Basic/BasicSourceInfo.h

+29-12
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,42 @@
1515

1616
#include "swift/Basic/Fingerprint.h"
1717
#include "swift/Basic/LLVM.h"
18+
#include "swift/Basic/SourceLoc.h"
1819
#include "llvm/ADT/PointerIntPair.h"
1920
#include "llvm/Support/Chrono.h"
2021

2122
namespace swift {
2223

2324
class SourceFile;
2425

25-
struct SourcePosition {
26-
uint32_t Line = 0;
27-
uint32_t Column = 0;
28-
bool isValid() const { return Line && Column; }
29-
};
30-
31-
struct BasicDeclLocs {
32-
StringRef SourceFilePath;
33-
SmallVector<std::pair<SourcePosition, uint32_t>, 4> DocRanges;
34-
SourcePosition Loc;
35-
SourcePosition StartLoc;
36-
SourcePosition EndLoc;
26+
struct ExternalSourceLocs {
27+
struct LocationDirective {
28+
uint32_t Offset = 0;
29+
int32_t LineOffset = 0;
30+
uint32_t Length = 0;
31+
StringRef Name;
32+
33+
bool isValid() const { return Length > 0; }
34+
};
35+
36+
struct RawLoc {
37+
uint32_t Offset = 0;
38+
uint32_t Line = 0;
39+
uint32_t Column = 0;
40+
LocationDirective Directive;
41+
};
42+
43+
struct RawLocs {
44+
StringRef SourceFilePath;
45+
SmallVector<std::pair<RawLoc, uint32_t>, 4> DocRanges;
46+
RawLoc Loc;
47+
RawLoc StartLoc;
48+
RawLoc EndLoc;
49+
};
50+
51+
unsigned BufferID = 0;
52+
SourceLoc Loc;
53+
SmallVector<CharSourceRange, 4> DocRanges;
3754
};
3855

3956
class BasicSourceFileInfo {

Diff for: include/swift/Basic/SourceManager.h

+32-15
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ namespace swift {
2424

2525
/// This class manages and owns source buffers.
2626
class SourceManager {
27+
public:
28+
/// A \c #sourceLocation-defined virtual file region, representing the source
29+
/// source after a \c #sourceLocation (or between two). It provides a
30+
/// filename and line offset to be applied to \c SourceLoc's within its
31+
/// \c Range.
32+
struct VirtualFile {
33+
CharSourceRange Range;
34+
std::string Name;
35+
int LineOffset;
36+
};
37+
38+
private:
2739
llvm::SourceMgr LLVMSourceMgr;
2840
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem;
2941
unsigned CodeCompletionBufferID = 0U;
@@ -52,12 +64,6 @@ class SourceManager {
5264
};
5365
ReplacedRangeType ReplacedRange;
5466

55-
// \c #sourceLocation directive handling.
56-
struct VirtualFile {
57-
CharSourceRange Range;
58-
std::string Name;
59-
int LineOffset;
60-
};
6167
std::map<const char *, VirtualFile> VirtualFiles;
6268
mutable std::pair<const char *, const VirtualFile*> CachedVFile = {nullptr, nullptr};
6369

@@ -143,6 +149,10 @@ class SourceManager {
143149
/// Adds a memory buffer to the SourceManager, taking ownership of it.
144150
unsigned addNewSourceBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer);
145151

152+
/// Add a \c #sourceLocation-defined virtual file region of \p Length.
153+
void createVirtualFile(SourceLoc Loc, StringRef Name, int LineOffset,
154+
unsigned Length);
155+
146156
/// Add a \c #sourceLocation-defined virtual file region.
147157
///
148158
/// By default, this region continues to the end of the buffer.
@@ -275,18 +285,17 @@ class SourceManager {
275285

276286
std::string getLineString(unsigned BufferID, unsigned LineNumber);
277287

288+
/// Retrieve the buffer ID for \p Path, loading if necessary.
289+
unsigned getExternalSourceBufferID(StringRef Path);
290+
278291
SourceLoc getLocFromExternalSource(StringRef Path, unsigned Line, unsigned Col);
279-
private:
292+
293+
/// Retrieve the virtual file for the given \p Loc, or nullptr if none exists.
280294
const VirtualFile *getVirtualFile(SourceLoc Loc) const;
281-
unsigned getExternalSourceBufferId(StringRef Path);
282-
int getLineOffset(SourceLoc Loc) const {
283-
if (auto VFile = getVirtualFile(Loc))
284-
return VFile->LineOffset;
285-
else
286-
return 0;
287-
}
288295

289-
public:
296+
/// Whether or not \p Loc is after a \c #sourceLocation directive, ie. its
297+
/// file, line, and column should be reported using the information in the
298+
/// directive.
290299
bool isLocInVirtualFile(SourceLoc Loc) const {
291300
return getVirtualFile(Loc) != nullptr;
292301
}
@@ -295,6 +304,14 @@ class SourceManager {
295304
/// owned by \p otherManager. Returns an invalid SourceLoc if it cannot be
296305
/// translated.
297306
SourceLoc getLocForForeignLoc(SourceLoc otherLoc, SourceManager &otherMgr);
307+
308+
private:
309+
int getLineOffset(SourceLoc Loc) const {
310+
if (auto VFile = getVirtualFile(Loc))
311+
return VFile->LineOffset;
312+
else
313+
return 0;
314+
}
298315
};
299316

300317
} // end namespace swift

Diff for: include/swift/Serialization/SerializedModuleLoader.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ class SerializedASTFile final : public LoadedFile {
392392

393393
Optional<StringRef> getGroupNameByUSR(StringRef USR) const override;
394394

395-
Optional<BasicDeclLocs> getBasicLocsForDecl(const Decl *D) const override;
395+
Optional<ExternalSourceLocs::RawLocs>
396+
getExternalRawLocsForDecl(const Decl *D) const override;
396397

397398
void collectAllGroups(SmallVectorImpl<StringRef> &Names) const override;
398399

Diff for: lib/AST/ASTContext.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ struct ASTContext::Implementation {
287287
/// The module loader used to load Clang modules from DWARF.
288288
ClangModuleLoader *TheDWARFModuleLoader = nullptr;
289289

290+
/// Map from Swift declarations to deserialized resolved locations, ie.
291+
/// actual \c SourceLocs that require opening their external buffer.
292+
llvm::DenseMap<const Decl *, ExternalSourceLocs *> ExternalSourceLocs;
293+
290294
/// Map from Swift declarations to raw comments.
291295
llvm::DenseMap<const Decl *, std::pair<RawComment, bool>> RawComments;
292296

@@ -2048,6 +2052,20 @@ ModuleDecl *ASTContext::getStdlibModule(bool loadIfAbsent) {
20482052
return TheStdlibModule;
20492053
}
20502054

2055+
Optional<ExternalSourceLocs *>
2056+
ASTContext::getExternalSourceLocs(const Decl *D) {
2057+
auto Known = getImpl().ExternalSourceLocs.find(D);
2058+
if (Known == getImpl().ExternalSourceLocs.end())
2059+
return None;
2060+
2061+
return Known->second;
2062+
}
2063+
2064+
void ASTContext::setExternalSourceLocs(const Decl *D,
2065+
ExternalSourceLocs *Locs) {
2066+
getImpl().ExternalSourceLocs[D] = Locs;
2067+
}
2068+
20512069
Optional<std::pair<RawComment, bool>> ASTContext::getRawComment(const Decl *D) {
20522070
auto Known = getImpl().RawComments.find(D);
20532071
if (Known == getImpl().RawComments.end())

Diff for: lib/AST/Decl.cpp

+38-24
Original file line numberDiff line numberDiff line change
@@ -610,36 +610,50 @@ case DeclKind::ID: return cast<ID##Decl>(this)->getLocFromSource();
610610
llvm_unreachable("Unknown decl kind");
611611
}
612612

613-
const Decl::CachedExternalSourceLocs *Decl::getSerializedLocs() const {
614-
if (CachedSerializedLocs) {
615-
return CachedSerializedLocs;
616-
}
613+
const ExternalSourceLocs *Decl::getSerializedLocs() const {
614+
auto &Context = getASTContext();
615+
if (auto EL = Context.getExternalSourceLocs(this).getValueOr(nullptr))
616+
return EL;
617+
618+
static ExternalSourceLocs NullLocs{};
619+
617620
auto *File = cast<FileUnit>(getDeclContext()->getModuleScopeContext());
618-
assert(File->getKind() == FileUnitKind::SerializedAST &&
619-
"getSerializedLocs() should only be called on decls in "
620-
"a 'SerializedASTFile'");
621-
auto Locs = File->getBasicLocsForDecl(this);
622-
if (!Locs.hasValue()) {
623-
static const Decl::CachedExternalSourceLocs NullLocs{};
621+
if (File->getKind() != FileUnitKind::SerializedAST)
622+
return &NullLocs;
623+
624+
auto RawLocs = File->getExternalRawLocsForDecl(this);
625+
if (!RawLocs.hasValue()) {
626+
// Don't read .swiftsourceinfo again on failure
627+
Context.setExternalSourceLocs(this, &NullLocs);
624628
return &NullLocs;
625629
}
626-
auto *Result = getASTContext().Allocate<Decl::CachedExternalSourceLocs>();
627-
auto &SM = getASTContext().SourceMgr;
628-
#define CASE(X) \
629-
Result->X = SM.getLocFromExternalSource(Locs->SourceFilePath, Locs->X.Line, \
630-
Locs->X.Column);
631-
CASE(Loc)
632-
CASE(StartLoc)
633-
CASE(EndLoc)
634-
#undef CASE
635630

636-
for (const auto &LineColumnAndLength : Locs->DocRanges) {
637-
auto Start = SM.getLocFromExternalSource(Locs->SourceFilePath,
638-
LineColumnAndLength.first.Line,
639-
LineColumnAndLength.first.Column);
640-
Result->DocRanges.push_back({ Start, LineColumnAndLength.second });
631+
auto &SM = getASTContext().SourceMgr;
632+
unsigned BufferID = SM.getExternalSourceBufferID(RawLocs->SourceFilePath);
633+
if (!BufferID) {
634+
// Don't try open the file again on failure
635+
Context.setExternalSourceLocs(this, &NullLocs);
636+
return &NullLocs;
641637
}
642638

639+
auto ResolveLoc = [&](const ExternalSourceLocs::RawLoc &Raw) -> SourceLoc {
640+
// If the decl had a presumed loc, create its virtual file so that
641+
// getPresumedLineAndColForLoc works from serialized locations as well.
642+
if (Raw.Directive.isValid()) {
643+
auto &LD = Raw.Directive;
644+
SourceLoc Loc = SM.getLocForOffset(BufferID, LD.Offset);
645+
SM.createVirtualFile(Loc, LD.Name, LD.LineOffset, LD.Length);
646+
}
647+
return SM.getLocForOffset(BufferID, Raw.Offset);
648+
};
649+
650+
auto *Result = getASTContext().Allocate<ExternalSourceLocs>();
651+
Result->BufferID = BufferID;
652+
Result->Loc = ResolveLoc(RawLocs->Loc);
653+
for (auto &Range : RawLocs->DocRanges) {
654+
Result->DocRanges.emplace_back(ResolveLoc(Range.first), Range.second);
655+
}
656+
Context.setExternalSourceLocs(this, Result);
643657
return Result;
644658
}
645659

Diff for: lib/AST/Module.cpp

+33-20
Original file line numberDiff line numberDiff line change
@@ -864,37 +864,50 @@ TypeDecl *SourceFile::lookupLocalType(llvm::StringRef mangledName) const {
864864
return nullptr;
865865
}
866866

867-
Optional<BasicDeclLocs>
868-
SourceFile::getBasicLocsForDecl(const Decl *D) const {
867+
Optional<ExternalSourceLocs::RawLocs>
868+
SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
869869
auto *FileCtx = D->getDeclContext()->getModuleScopeContext();
870870
assert(FileCtx == this && "D doesn't belong to this source file");
871871
if (FileCtx != this) {
872872
// D doesn't belong to this file. This shouldn't happen in practice.
873873
return None;
874874
}
875-
if (D->getLoc().isInvalid())
875+
876+
SourceLoc Loc = D->getLoc(/*SerializedOK=*/false);
877+
if (Loc.isInvalid())
876878
return None;
879+
877880
SourceManager &SM = getASTContext().SourceMgr;
878-
BasicDeclLocs Result;
879-
Result.SourceFilePath = SM.getDisplayNameForLoc(D->getLoc());
881+
auto BufferID = SM.findBufferContainingLoc(Loc);
880882

881-
for (const auto &SRC : D->getRawComment(/*SerializedOK*/false).Comments) {
882-
auto LineAndCol = SM.getLineAndColumnInBuffer(SRC.Range.getStart());
883-
Result.DocRanges.push_back(
884-
std::make_pair(SourcePosition{LineAndCol.first, LineAndCol.second},
885-
SRC.Range.getByteLength()));
886-
}
883+
ExternalSourceLocs::RawLocs Result;
884+
auto setLoc = [&](ExternalSourceLocs::RawLoc &RawLoc, SourceLoc Loc) {
885+
if (!Loc.isValid())
886+
return;
887887

888-
auto setLineColumn = [&SM](SourcePosition &Home, SourceLoc Loc) {
889-
if (Loc.isValid()) {
890-
std::tie(Home.Line, Home.Column) = SM.getPresumedLineAndColumnForLoc(Loc);
891-
}
888+
RawLoc.Offset = SM.getLocOffsetInBuffer(Loc, BufferID);
889+
std::tie(RawLoc.Line, RawLoc.Column) = SM.getLineAndColumnInBuffer(Loc);
890+
891+
auto *VF = SM.getVirtualFile(Loc);
892+
if (!VF)
893+
return;
894+
895+
RawLoc.Directive.Offset =
896+
SM.getLocOffsetInBuffer(VF->Range.getStart(), BufferID);
897+
RawLoc.Directive.LineOffset = VF->LineOffset;
898+
RawLoc.Directive.Length = VF->Range.getByteLength();
899+
RawLoc.Directive.Name = StringRef(VF->Name);
892900
};
893-
#define SET(X) setLineColumn(Result.X, D->get##X());
894-
SET(Loc)
895-
SET(StartLoc)
896-
SET(EndLoc)
897-
#undef SET
901+
902+
Result.SourceFilePath = SM.getIdentifierForBuffer(BufferID);
903+
for (const auto &SRC : D->getRawComment(/*SerializedOK=*/false).Comments) {
904+
Result.DocRanges.emplace_back(ExternalSourceLocs::RawLoc(),
905+
SRC.Range.getByteLength());
906+
setLoc(Result.DocRanges.back().first, SRC.Range.getStart());
907+
}
908+
setLoc(Result.Loc, D->getLoc(/*SerializedOK=*/false));
909+
setLoc(Result.StartLoc, D->getStartLoc());
910+
setLoc(Result.EndLoc, D->getEndLoc());
898911
return Result;
899912
}
900913

0 commit comments

Comments
 (0)