Skip to content

Commit eaf14ab

Browse files
committed
[SourceKit] Store FileContents in ASTBuildOperation instead of snapshots
1 parent 757ee55 commit eaf14ab

File tree

1 file changed

+58
-79
lines changed

1 file changed

+58
-79
lines changed

tools/SourceKit/lib/SwiftLang/SwiftASTManager.cpp

Lines changed: 58 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ namespace {
230230

231231
typedef uint64_t BufferStamp;
232232

233-
struct FileContent {
233+
struct FileContent : llvm::RefCountedBase<FileContent> {
234234
ImmutableTextSnapshotRef Snapshot;
235235
std::string Filename;
236236
std::unique_ptr<llvm::MemoryBuffer> Buffer;
@@ -248,6 +248,8 @@ struct FileContent {
248248
}
249249
};
250250

251+
using FileContentRef = llvm::IntrusiveRefCntPtr<FileContent>;
252+
251253
/// An \c ASTBuildOperations builds an AST. Once the AST is built, it informs
252254
/// a list of \c SwiftASTConsumers about the built AST.
253255
/// It also supports cancellation with the following paradigm: If an \c
@@ -299,7 +301,9 @@ class ASTBuildOperation
299301
/// Parameters necessary to build the AST.
300302
const SwiftInvocationRef InvokRef;
301303
const IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem;
302-
const std::vector<ImmutableTextSnapshotRef> Snapshots;
304+
305+
/// The contents of all explicit input files of the compiler invoation.
306+
const std::vector<FileContentRef> FileContents;
303307

304308
/// Stamps of files used to build the AST. \c Stamps contains the stamps of
305309
/// all explicit input files, which can be determined at construction time of
@@ -357,38 +361,33 @@ class ASTBuildOperation
357361
/// depends on the severity of the error.
358362
ASTUnitRef buildASTUnit(std::string &Error);
359363

360-
/// Retrieve the contents of all files needed for the compiler invocation to
361-
/// build this AST. For files contained in \c Snapshots use the snapshot's
362-
/// content. For all other files, consult the file system.
363-
void findSnapshotAndOpenFiles(SmallVectorImpl<FileContent> &Contents,
364-
std::string &Error) const;
365-
366364
/// Transition the build operation to \p NewState, asserting that the current
367365
/// state is \p ExpectedOldState.
368366
void transitionToState(State NewState, State ExpectedOldState) {
369367
assert(OperationState == ExpectedOldState);
370368
OperationState = NewState;
371369
}
372370

373-
/// Create a vector of text snapshots containing all files explicitly
371+
/// Create a vector of \c FileContents containing all files explicitly
374372
/// referenced by the compiler invocation and a vector of buffer stamps of
375373
/// those files.
376-
std::pair<std::vector<ImmutableTextSnapshotRef>, std::vector<BufferStamp>>
377-
snapshotAndStampsForFilesInCompilerInvocation();
374+
std::pair<std::vector<FileContentRef>, std::vector<BufferStamp>>
375+
fileContentsAndStampsForFilesInCompilerInvocation();
378376

379377
public:
380378
ASTBuildOperation(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
381379
SwiftInvocationRef InvokRef, SwiftASTManagerRef ASTManager,
382380
std::function<void(void)> DidFinishCallback)
383381
: InvokRef(InvokRef), FileSystem(FileSystem), ASTManager(ASTManager),
384382
DidFinishCallback(DidFinishCallback) {
385-
auto SnapshotsAndStamps = snapshotAndStampsForFilesInCompilerInvocation();
383+
auto FileContentsAndStamps =
384+
fileContentsAndStampsForFilesInCompilerInvocation();
386385
// const_cast is fine here. We just want to guard against modifying these
387386
// fields later on. It's fine to set them in the constructor.
388-
const_cast<std::vector<ImmutableTextSnapshotRef> &>(this->Snapshots) =
389-
SnapshotsAndStamps.first;
387+
const_cast<std::vector<FileContentRef> &>(this->FileContents) =
388+
std::move(FileContentsAndStamps.first);
390389
const_cast<std::vector<BufferStamp> &>(this->Stamps) =
391-
SnapshotsAndStamps.second;
390+
FileContentsAndStamps.second;
392391
}
393392

394393
~ASTBuildOperation() {
@@ -398,7 +397,7 @@ class ASTBuildOperation
398397
"not receive their callback.");
399398
}
400399

401-
ArrayRef<ImmutableTextSnapshotRef> getSnapshots() const { return Snapshots; }
400+
ArrayRef<FileContentRef> getFileContents() const { return FileContents; }
402401

403402
/// Returns true if the build operation has finished.
404403
bool isFinished() {
@@ -413,7 +412,7 @@ class ASTBuildOperation
413412
}
414413

415414
size_t getMemoryCost() {
416-
return sizeof(*this) + getVectorMemoryCost(Snapshots) +
415+
return sizeof(*this) + getVectorMemoryCost(FileContents) +
417416
getVectorMemoryCost(Stamps) + Result.getMemoryCost();
418417
}
419418

@@ -609,7 +608,7 @@ struct SwiftASTManager::Implementation {
609608

610609
ASTProducerRef getASTProducer(SwiftInvocationRef InvokRef);
611610

612-
FileContent
611+
FileContentRef
613612
getFileContent(StringRef FilePath, bool IsPrimary,
614613
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
615614
std::string &Error) const;
@@ -644,10 +643,10 @@ SwiftASTManager::getMemoryBuffer(StringRef Filename, std::string &Error) {
644643
}
645644

646645
static FrontendInputsAndOutputs
647-
convertFileContentsToInputs(const SmallVectorImpl<FileContent> &contents) {
646+
convertFileContentsToInputs(ArrayRef<FileContentRef> contents) {
648647
FrontendInputsAndOutputs inputsAndOutputs;
649-
for (const FileContent &content : contents)
650-
inputsAndOutputs.addInput(InputFile(content));
648+
for (FileContentRef content : contents)
649+
inputsAndOutputs.addInput(InputFile(*content));
651650
return inputsAndOutputs;
652651
}
653652

@@ -790,15 +789,16 @@ SwiftASTManager::Implementation::getASTProducer(SwiftInvocationRef InvokRef) {
790789
return Producer;
791790
}
792791

793-
static FileContent getFileContentFromSnap(ImmutableTextSnapshotRef Snap,
794-
bool IsPrimary, StringRef FilePath) {
792+
static FileContentRef getFileContentFromSnap(ImmutableTextSnapshotRef Snap,
793+
bool IsPrimary,
794+
StringRef FilePath) {
795795
auto Buf = llvm::MemoryBuffer::getMemBufferCopy(
796796
Snap->getBuffer()->getText(), FilePath);
797-
return FileContent(Snap, FilePath.str(), std::move(Buf), IsPrimary,
798-
Snap->getStamp());
797+
return new FileContent(Snap, FilePath.str(), std::move(Buf), IsPrimary,
798+
Snap->getStamp());
799799
}
800800

801-
FileContent SwiftASTManager::Implementation::getFileContent(
801+
FileContentRef SwiftASTManager::Implementation::getFileContent(
802802
StringRef UnresolvedPath, bool IsPrimary,
803803
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
804804
std::string &Error) const {
@@ -810,8 +810,8 @@ FileContent SwiftASTManager::Implementation::getFileContent(
810810
// FIXME: Is there a way to get timestamp and buffer for a file atomically ?
811811
auto Stamp = getBufferStamp(FilePath, FileSystem);
812812
auto Buffer = getMemoryBuffer(FilePath, FileSystem, Error);
813-
return FileContent(nullptr, UnresolvedPath.str(), std::move(Buffer),
814-
IsPrimary, Stamp);
813+
return new FileContent(nullptr, UnresolvedPath.str(), std::move(Buffer),
814+
IsPrimary, Stamp);
815815
}
816816

817817
BufferStamp SwiftASTManager::Implementation::getBufferStamp(
@@ -849,13 +849,15 @@ SwiftASTManager::Implementation::getMemoryBuffer(
849849
return nullptr;
850850
}
851851

852-
std::pair<std::vector<ImmutableTextSnapshotRef>, std::vector<BufferStamp>>
853-
ASTBuildOperation::snapshotAndStampsForFilesInCompilerInvocation() {
852+
std::pair<std::vector<FileContentRef>, std::vector<BufferStamp>>
853+
ASTBuildOperation::fileContentsAndStampsForFilesInCompilerInvocation() {
854854
const InvocationOptions &Opts = InvokRef->Impl.Opts;
855855
std::string Error; // is ignored
856856

857-
std::vector<ImmutableTextSnapshotRef> Snapshots;
857+
std::vector<FileContentRef> FileContents;
858858
std::vector<BufferStamp> Stamps;
859+
FileContents.reserve(
860+
Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
859861
Stamps.reserve(Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
860862

861863
// IMPORTANT: The computation of stamps must match the one in
@@ -866,33 +868,40 @@ ASTBuildOperation::snapshotAndStampsForFilesInCompilerInvocation() {
866868
bool IsPrimary = input.isPrimary();
867869
auto Content =
868870
ASTManager->Impl.getFileContent(Filename, IsPrimary, FileSystem, Error);
869-
Stamps.push_back(Content.Stamp);
870-
if (Content.Snapshot) {
871-
Snapshots.push_back(Content.Snapshot);
871+
if (!Content->Buffer) {
872+
LOG_WARN_FUNC("failed getting file contents for " << Filename << ": "
873+
<< Error);
874+
// File may not exist, continue and recover as if it was empty.
875+
Content->Buffer =
876+
llvm::WritableMemoryBuffer::getNewMemBuffer(0, Filename);
872877
}
878+
Stamps.push_back(Content->Stamp);
879+
FileContents.push_back(Content);
873880
}
874881
assert(Stamps.size() ==
875882
Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
876-
return std::make_pair(Snapshots, Stamps);
883+
assert(FileContents.size() ==
884+
Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
885+
return std::make_pair(FileContents, Stamps);
877886
}
878887

879888
bool ASTBuildOperation::matchesSourceState(
880889
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> OtherFileSystem) {
881-
const SwiftInvocation::Implementation &Invok = InvokRef->Impl;
890+
const InvocationOptions &Opts = InvokRef->Impl.Opts;
882891

883892
// Check if the inputs changed.
884893
std::vector<BufferStamp> InputStamps;
885894
InputStamps.reserve(
886-
Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
895+
Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
887896
// IMPORTANT: The computation of stamps must match the one in
888897
// snapshotAndStampsForFilesInCompilerInvocation.
889898
for (const auto &input :
890-
Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
899+
Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
891900
InputStamps.push_back(
892901
ASTManager->Impl.getBufferStamp(input.getFileName(), OtherFileSystem));
893902
}
894903
assert(InputStamps.size() ==
895-
Invok.Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
904+
Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
896905
if (Stamps != InputStamps)
897906
return false;
898907

@@ -1016,13 +1025,10 @@ ASTUnitRef ASTBuildOperation::buildASTUnit(std::string &Error) {
10161025
Log->getOS() << Opts.Invok.getModuleName() << '/' << Opts.PrimaryFile;
10171026
}
10181027

1019-
SmallVector<FileContent, 8> Contents;
1020-
findSnapshotAndOpenFiles(Contents, Error);
1021-
10221028
ASTUnitRef ASTRef = new ASTUnit(++ASTUnitGeneration, ASTManager->Impl.Stats);
1023-
for (auto &Content : Contents) {
1024-
if (Content.Snapshot)
1025-
ASTRef->Impl.Snapshots.push_back(Content.Snapshot);
1029+
for (auto &Content : getFileContents()) {
1030+
if (Content->Snapshot)
1031+
ASTRef->Impl.Snapshots.push_back(Content->Snapshot);
10261032
}
10271033
auto &CompIns = ASTRef->Impl.CompInst;
10281034
auto &Consumer = ASTRef->Impl.CollectDiagConsumer;
@@ -1041,7 +1047,7 @@ ASTUnitRef ASTBuildOperation::buildASTUnit(std::string &Error) {
10411047

10421048
CompilerInvocation Invocation;
10431049
InvokRef->Impl.Opts.applyToSubstitutingInputs(
1044-
Invocation, convertFileContentsToInputs(Contents));
1050+
Invocation, convertFileContentsToInputs(getFileContents()));
10451051

10461052
Invocation.getLangOptions().CollectParsedToken = true;
10471053

@@ -1111,38 +1117,6 @@ ASTUnitRef ASTBuildOperation::buildASTUnit(std::string &Error) {
11111117
return ASTRef;
11121118
}
11131119

1114-
void ASTBuildOperation::findSnapshotAndOpenFiles(
1115-
SmallVectorImpl<FileContent> &Contents, std::string &Error) const {
1116-
const InvocationOptions &Opts = InvokRef->Impl.Opts;
1117-
for (const auto &input :
1118-
Opts.Invok.getFrontendOptions().InputsAndOutputs.getAllInputs()) {
1119-
const std::string &File = input.getFileName();
1120-
bool IsPrimary = input.isPrimary();
1121-
bool FoundSnapshot = false;
1122-
for (auto &Snap : Snapshots) {
1123-
if (Snap->getFilename() == File) {
1124-
FoundSnapshot = true;
1125-
Contents.push_back(getFileContentFromSnap(Snap, IsPrimary, File));
1126-
break;
1127-
}
1128-
}
1129-
if (FoundSnapshot)
1130-
continue;
1131-
1132-
auto Content =
1133-
ASTManager->Impl.getFileContent(File, IsPrimary, FileSystem, Error);
1134-
if (!Content.Buffer) {
1135-
LOG_WARN_FUNC("failed getting file contents for " << File << ": "
1136-
<< Error);
1137-
// File may not exist, continue and recover as if it was empty.
1138-
Content.Buffer = llvm::WritableMemoryBuffer::getNewMemBuffer(0, File);
1139-
}
1140-
Contents.push_back(std::move(Content));
1141-
}
1142-
assert(Contents.size() ==
1143-
Opts.Invok.getFrontendOptions().InputsAndOutputs.inputCount());
1144-
}
1145-
11461120
void ASTBuildOperation::schedule(WorkQueue Queue) {
11471121
transitionToState(State::Queued, /*ExpectedOldState=*/State::Created);
11481122
auto SharedThis = shared_from_this();
@@ -1219,10 +1193,15 @@ ASTBuildOperationRef ASTProducer::getBuildOperationForConsumer(
12191193
if (BuildOp->isCancelled()) {
12201194
continue;
12211195
}
1196+
std::vector<ImmutableTextSnapshotRef> Snapshots;
1197+
Snapshots.reserve(BuildOp->getFileContents().size());
1198+
for (auto &FileContent : BuildOp->getFileContents()) {
1199+
Snapshots.push_back(FileContent->Snapshot);
1200+
}
12221201
if (BuildOp->matchesSourceState(FileSystem)) {
12231202
++Mgr->Impl.Stats->numASTCacheHits;
12241203
return BuildOp;
1225-
} else if (Consumer->canUseASTWithSnapshots(BuildOp->getSnapshots())) {
1204+
} else if (Consumer->canUseASTWithSnapshots(Snapshots)) {
12261205
++Mgr->Impl.Stats->numASTsUsedWithSnaphots;
12271206
return BuildOp;
12281207
}

0 commit comments

Comments
 (0)