@@ -26,27 +26,31 @@ namespace dependencies {
2626// / the dependency scanning filesystem.
2727// /
2828// / It represents one of the following:
29- // / - an opened source file with minimized contents and a stat value.
30- // / - an opened source file with original contents and a stat value.
31- // / - a directory entry with its stat value.
32- // / - an error value to represent a file system error.
29+ // / - opened file with original contents and a stat value,
30+ // / - opened file with original contents, minimized contents and a stat value,
31+ // / - directory entry with its stat value,
32+ // / - filesystem error,
3333// / - uninitialized entry with unknown status.
3434class CachedFileSystemEntry {
3535public:
3636 // / Creates an uninitialized entry.
37- CachedFileSystemEntry () : MaybeStat(llvm::vfs::Status()) {}
37+ CachedFileSystemEntry ()
38+ : MaybeStat(llvm::vfs::Status()), MinimizedContentsAccess(nullptr ) {}
3839
3940 // / Initialize the cached file system entry.
4041 void init (llvm::ErrorOr<llvm::vfs::Status> &&MaybeStatus, StringRef Filename,
41- llvm::vfs::FileSystem &FS, bool ShouldMinimize = true );
42+ llvm::vfs::FileSystem &FS);
4243
4344 // / Initialize the entry as file with minimized or original contents.
4445 // /
4546 // / The filesystem opens the file even for `stat` calls open to avoid the
4647 // / issues with stat + open of minimized files that might lead to a
4748 // / mismatching size of the file.
48- llvm::ErrorOr<llvm::vfs::Status>
49- initFile (StringRef Filename, llvm::vfs::FileSystem &FS, bool Minimize = true );
49+ llvm::ErrorOr<llvm::vfs::Status> initFile (StringRef Filename,
50+ llvm::vfs::FileSystem &FS);
51+
52+ // / Minimize contents of the file.
53+ void minimizeFile ();
5054
5155 // / \returns True if the entry is initialized.
5256 bool isInitialized () const {
@@ -56,13 +60,38 @@ class CachedFileSystemEntry {
5660 // / \returns True if the current entry points to a directory.
5761 bool isDirectory () const { return MaybeStat && MaybeStat->isDirectory (); }
5862
59- // / \returns The error or the file's contents.
60- llvm::ErrorOr<StringRef> getContents () const {
63+ // / \returns The error or the file's original contents.
64+ llvm::ErrorOr<StringRef> getOriginalContents () const {
65+ if (!MaybeStat)
66+ return MaybeStat.getError ();
67+ assert (!MaybeStat->isDirectory () && " not a file" );
68+ assert (isInitialized () && " not initialized" );
69+ assert (OriginalContents && " not read" );
70+ return OriginalContents->getBuffer ();
71+ }
72+
73+ // / \returns The error or the file's minimized contents.
74+ llvm::ErrorOr<StringRef> getMinimizedContents () const {
6175 if (!MaybeStat)
6276 return MaybeStat.getError ();
6377 assert (!MaybeStat->isDirectory () && " not a file" );
6478 assert (isInitialized () && " not initialized" );
65- return Contents->getBuffer ();
79+ llvm::MemoryBuffer *Buffer = MinimizedContentsAccess.load ();
80+ assert (Buffer && " not minimized" );
81+ return Buffer->getBuffer ();
82+ }
83+
84+ // / \returns True if this entry represents a file that can be read.
85+ bool isReadable () const { return MaybeStat && !MaybeStat->isDirectory (); }
86+
87+ // / \returns True if this cached entry needs to be updated.
88+ bool needsUpdate (bool ShouldBeMinimized) const {
89+ return isReadable () && needsMinimization (ShouldBeMinimized);
90+ }
91+
92+ // / \returns True if the contents of this entry need to be minimized.
93+ bool needsMinimization (bool ShouldBeMinimized) const {
94+ return ShouldBeMinimized && !MinimizedContentsAccess.load ();
6695 }
6796
6897 // / \returns The error or the status of the entry.
@@ -83,15 +112,16 @@ class CachedFileSystemEntry {
83112 return PPSkippedRangeMapping;
84113 }
85114
86- CachedFileSystemEntry (CachedFileSystemEntry &&) = default ;
87- CachedFileSystemEntry &operator =(CachedFileSystemEntry &&) = default ;
88-
89- CachedFileSystemEntry (const CachedFileSystemEntry &) = delete ;
90- CachedFileSystemEntry &operator =(const CachedFileSystemEntry &) = delete ;
91-
92115private:
93116 llvm::ErrorOr<llvm::vfs::Status> MaybeStat;
94- std::unique_ptr<llvm::MemoryBuffer> Contents;
117+ std::unique_ptr<llvm::MemoryBuffer> OriginalContents;
118+
119+ // / Owning storage for the minimized file contents.
120+ std::unique_ptr<llvm::MemoryBuffer> MinimizedContentsStorage;
121+ // / Atomic view of the minimized file contents.
122+ // / This prevents data races when multiple threads call `needsMinimization`.
123+ std::atomic<llvm::MemoryBuffer *> MinimizedContentsAccess;
124+
95125 PreprocessorSkippedRangeMapping PPSkippedRangeMapping;
96126};
97127
@@ -108,61 +138,70 @@ class DependencyScanningFilesystemSharedCache {
108138 CachedFileSystemEntry Value;
109139 };
110140
141+ DependencyScanningFilesystemSharedCache ();
142+
111143 // / Returns a cache entry for the corresponding key.
112144 // /
113145 // / A new cache entry is created if the key is not in the cache. This is a
114146 // / thread safe call.
115- SharedFileSystemEntry &get (StringRef Key, bool Minimized );
147+ SharedFileSystemEntry &get (StringRef Key);
116148
117149private:
118- class SingleCache {
119- public:
120- SingleCache ();
121-
122- SharedFileSystemEntry &get (StringRef Key);
123-
124- private:
125- struct CacheShard {
126- std::mutex CacheLock;
127- llvm::StringMap<SharedFileSystemEntry, llvm::BumpPtrAllocator> Cache;
128- };
129- std::unique_ptr<CacheShard[]> CacheShards;
130- unsigned NumShards;
150+ struct CacheShard {
151+ std::mutex CacheLock;
152+ llvm::StringMap<SharedFileSystemEntry, llvm::BumpPtrAllocator> Cache;
131153 };
132-
133- SingleCache CacheMinimized;
134- SingleCache CacheOriginal;
154+ std::unique_ptr<CacheShard[]> CacheShards;
155+ unsigned NumShards;
135156};
136157
137158// / This class is a local cache, that caches the 'stat' and 'open' calls to the
138159// / underlying real file system. It distinguishes between minimized and original
139160// / files.
140161class DependencyScanningFilesystemLocalCache {
141- private:
142- using SingleCache =
143- llvm::StringMap<const CachedFileSystemEntry *, llvm::BumpPtrAllocator>;
162+ llvm::StringMap<const CachedFileSystemEntry *, llvm::BumpPtrAllocator> Cache;
144163
145- SingleCache CacheMinimized;
146- SingleCache CacheOriginal;
147-
148- SingleCache &selectCache (bool Minimized) {
149- return Minimized ? CacheMinimized : CacheOriginal;
164+ public:
165+ const CachedFileSystemEntry *getCachedEntry (StringRef Filename) {
166+ return Cache[Filename];
150167 }
168+ };
169+
170+ // / Reference to a CachedFileSystemEntry.
171+ // / If the underlying entry is an opened file, this wrapper returns the correct
172+ // / contents (original or minimized) and ensures consistency with file size
173+ // / reported by status.
174+ class EntryRef {
175+ // / For entry that is an opened file, this bit signifies whether its contents
176+ // / are minimized.
177+ bool Minimized;
178+
179+ // / The underlying cached entry.
180+ const CachedFileSystemEntry *Entry;
151181
152182public:
153- void setCachedEntry (StringRef Filename, bool Minimized,
154- const CachedFileSystemEntry *Entry) {
155- SingleCache &Cache = selectCache (Minimized);
156- bool IsInserted = Cache.try_emplace (Filename, Entry).second ;
157- (void )IsInserted;
158- assert (IsInserted && " local cache is updated more than once" );
183+ EntryRef (bool Minimized, const CachedFileSystemEntry *Entry)
184+ : Minimized(Minimized), Entry(Entry) {}
185+
186+ llvm::ErrorOr<llvm::vfs::Status> getStatus () const {
187+ auto MaybeStat = Entry->getStatus ();
188+ if (!MaybeStat || MaybeStat->isDirectory ())
189+ return MaybeStat;
190+ return llvm::vfs::Status::copyWithNewSize (*MaybeStat,
191+ getContents ()->size ());
192+ }
193+
194+ bool isDirectory () const { return Entry->isDirectory (); }
195+
196+ StringRef getName () const { return Entry->getName (); }
197+
198+ llvm::ErrorOr<StringRef> getContents () const {
199+ return Minimized ? Entry->getMinimizedContents ()
200+ : Entry->getOriginalContents ();
159201 }
160202
161- const CachedFileSystemEntry *getCachedEntry (StringRef Filename,
162- bool Minimized) {
163- SingleCache &Cache = selectCache (Minimized);
164- auto It = Cache.find (Filename);
165- return It == Cache.end () ? nullptr : It->getValue ();
203+ const PreprocessorSkippedRangeMapping *getPPSkippedRangeMapping () const {
204+ return Minimized ? &Entry->getPPSkippedRangeMapping () : nullptr ;
166205 }
167206};
168207
@@ -197,8 +236,7 @@ class DependencyScanningWorkerFilesystem : public llvm::vfs::ProxyFileSystem {
197236 // / Check whether the file should be minimized.
198237 bool shouldMinimize (StringRef Filename);
199238
200- llvm::ErrorOr<const CachedFileSystemEntry *>
201- getOrCreateFileSystemEntry (const StringRef Filename);
239+ llvm::ErrorOr<EntryRef> getOrCreateFileSystemEntry (StringRef Filename);
202240
203241 // / The global cache shared between worker threads.
204242 DependencyScanningFilesystemSharedCache &SharedCache;
0 commit comments