From a22419f1d023384fe0ff877f7124fe91e38766f8 Mon Sep 17 00:00:00 2001 From: Jeremy Day Date: Mon, 22 Jul 2024 14:46:01 -0700 Subject: [PATCH 1/2] Fix sourcekitd persistent file-locks on Windows --- include/swift/Basic/SourceManager.h | 5 +++++ lib/Basic/SourceLoc.cpp | 6 +++++- lib/Frontend/Frontend.cpp | 6 ++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index 350ea0744d948..d7343e00c9f75 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -94,6 +94,7 @@ class SourceManager { private: llvm::SourceMgr LLVMSourceMgr; llvm::IntrusiveRefCntPtr FileSystem; + bool EditorMode = false; unsigned IDEInspectionTargetBufferID = 0U; unsigned IDEInspectionTargetOffset; @@ -166,6 +167,10 @@ class SourceManager { return FileSystem; } + void setEditorMode() { + EditorMode = true; + } + void setIDEInspectionTarget(unsigned BufferID, unsigned Offset) { assert(BufferID != 0U && "Buffer should be valid"); diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 07e2b5bc743cb..6696dd97f5456 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -695,7 +695,11 @@ unsigned SourceManager::getExternalSourceBufferID(StringRef Path) { return It->getSecond(); } unsigned Id = 0u; - auto InputFileOrErr = swift::vfs::getFileOrSTDIN(*getFileSystem(), Path); + auto InputFileOrErr = + swift::vfs::getFileOrSTDIN(*getFileSystem(), Path, + /* FileSize */ -1, + /* RequiresNullTerminator */ true, + /* isVolatile */ this->EditorMode); if (InputFileOrErr) { // This assertion ensures we can look up from the map in the future when // using the same Path. diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index 19fef52dca664..ab52d93fc5c67 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -552,6 +552,12 @@ bool CompilerInstance::setup(const CompilerInvocation &Invoke, if (LangOpts.EnableModuleLoadingRemarks) { Invocation.getSearchPathOptions().dump(LangOpts.Target.isOSDarwin()); } + + // If the compiler instance is managed by an IDE, inform the source manager to avoid + // memory-mapping source files that are likely to be mutated in an editor. + if (LangOpts.DiagnosticsEditorMode) { + this->getSourceMgr().setEditorMode(); + } // If we expect an implicit stdlib import, load in the standard library. If we // either fail to find it or encounter an error while loading it, bail early. Continuing will at best From 221c7039bd2da16ed8ea6259bfa5af88a3838c8d Mon Sep 17 00:00:00 2001 From: Jeremy Day Date: Fri, 26 Jul 2024 16:57:39 -0700 Subject: [PATCH 2/2] Add explicit OpenSourcesAsVolatile option --- include/swift/Basic/LangOptions.h | 6 ++++++ include/swift/Basic/SourceManager.h | 8 +++++--- lib/Basic/SourceLoc.cpp | 2 +- lib/Frontend/Frontend.cpp | 8 +++----- lib/IDETool/CompilerInvocation.cpp | 5 +++++ 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 1401f7324fd0f..13cc2bd42b0a4 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -496,6 +496,12 @@ namespace swift { /// Enable verification when every SubstitutionMap is constructed. bool VerifyAllSubstitutionMaps = false; + /// If set to true, the source manager will avoid memory mapping source files + /// with the expectation they may change on disk. This is most useful when + /// opening files under sourcekitd on Windows, as memory mapping on Windows + /// prevents files from being written. + bool OpenSourcesAsVolatile = false; + /// Load swiftmodule files in memory as volatile and avoid mmap. bool EnableVolatileModules = false; diff --git a/include/swift/Basic/SourceManager.h b/include/swift/Basic/SourceManager.h index d7343e00c9f75..ced1aa5b88f7c 100644 --- a/include/swift/Basic/SourceManager.h +++ b/include/swift/Basic/SourceManager.h @@ -94,7 +94,7 @@ class SourceManager { private: llvm::SourceMgr LLVMSourceMgr; llvm::IntrusiveRefCntPtr FileSystem; - bool EditorMode = false; + bool OpenSourcesAsVolatile = false; unsigned IDEInspectionTargetBufferID = 0U; unsigned IDEInspectionTargetOffset; @@ -167,8 +167,10 @@ class SourceManager { return FileSystem; } - void setEditorMode() { - EditorMode = true; + // Setting this prevents SourceManager from memory mapping sources (via opening files + // with isVolatile=true); + void setOpenSourcesAsVolatile() { + OpenSourcesAsVolatile = true; } void setIDEInspectionTarget(unsigned BufferID, unsigned Offset) { diff --git a/lib/Basic/SourceLoc.cpp b/lib/Basic/SourceLoc.cpp index 6696dd97f5456..fc201c1f8eeac 100644 --- a/lib/Basic/SourceLoc.cpp +++ b/lib/Basic/SourceLoc.cpp @@ -699,7 +699,7 @@ unsigned SourceManager::getExternalSourceBufferID(StringRef Path) { swift::vfs::getFileOrSTDIN(*getFileSystem(), Path, /* FileSize */ -1, /* RequiresNullTerminator */ true, - /* isVolatile */ this->EditorMode); + /* isVolatile */ this->OpenSourcesAsVolatile); if (InputFileOrErr) { // This assertion ensures we can look up from the map in the future when // using the same Path. diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index ab52d93fc5c67..2cd914838e57d 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -552,11 +552,9 @@ bool CompilerInstance::setup(const CompilerInvocation &Invoke, if (LangOpts.EnableModuleLoadingRemarks) { Invocation.getSearchPathOptions().dump(LangOpts.Target.isOSDarwin()); } - - // If the compiler instance is managed by an IDE, inform the source manager to avoid - // memory-mapping source files that are likely to be mutated in an editor. - if (LangOpts.DiagnosticsEditorMode) { - this->getSourceMgr().setEditorMode(); + + if (LangOpts.OpenSourcesAsVolatile) { + this->getSourceMgr().setOpenSourcesAsVolatile(); } // If we expect an implicit stdlib import, load in the standard library. If we diff --git a/lib/IDETool/CompilerInvocation.cpp b/lib/IDETool/CompilerInvocation.cpp index 47556d28f91a2..a3a7a5cd0e89d 100644 --- a/lib/IDETool/CompilerInvocation.cpp +++ b/lib/IDETool/CompilerInvocation.cpp @@ -225,6 +225,11 @@ bool ide::initCompilerInvocation( LangOpts.AttachCommentsToDecls = true; LangOpts.DiagnosticsEditorMode = true; LangOpts.CollectParsedToken = true; + #if defined(_WIN32) + // Source files that might be open in an editor should not be memory mapped on Windows, + // as they will become read-only. + LangOpts.OpenSourcesAsVolatile = true; + #endif if (LangOpts.PlaygroundTransform) { // The playground instrumenter changes the AST in ways that disrupt the // SourceKit functionality. Since we don't need the instrumenter, and all we