Skip to content

Commit a1cb063

Browse files
committed
Rebase InMemoryOutputFileSystem change on top of the monorepo.
1 parent ee5311c commit a1cb063

File tree

5 files changed

+237
-0
lines changed

5 files changed

+237
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
//===-- InMemoryOutputFileSystem.h - Collects outputs in memory -*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_BASIC_INMEMORYOUTPUTFILESYSTEM_H_
11+
#define LLVM_CLANG_BASIC_INMEMORYOUTPUTFILESYSTEM_H_
12+
13+
#include <memory>
14+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
15+
#include "llvm/ADT/SmallVector.h"
16+
#include "llvm/ADT/StringMap.h"
17+
#include "llvm/ADT/StringRef.h"
18+
#include "llvm/Support/Mutex.h"
19+
#include "llvm/Support/MutexGuard.h"
20+
#include "llvm/Support/raw_ostream.h"
21+
#include "llvm/Support/MemoryBuffer.h"
22+
#include "llvm/Support/VirtualFileSystem.h"
23+
24+
namespace clang {
25+
26+
/// Collects output files in memory, and provides a `llvm::vfs::FileSystem`
27+
/// interface for accessing those files.
28+
///
29+
/// This class is threadsafe. Unsynchronized calls from multiple threads will
30+
/// not corrupt the internal state, and operations occur atomically and
31+
/// sequentially consistently from the point of view of all threads.
32+
class InMemoryOutputFileSystem : public llvm::vfs::FileSystem {
33+
public:
34+
InMemoryOutputFileSystem() : OutputFiles(new llvm::vfs::InMemoryFileSystem())
35+
{}
36+
37+
/// Creates a temporary buffer that collects data for a file that may
38+
/// eventually appear on the `llvm::vfs::FileSystem` interface.
39+
/// `InMemoryOutputFileSystem` owns the buffer, which will not be released
40+
/// until `DeleteTemporaryFile` or `FinalizeTemporaryFile` is called.
41+
/// \param OutputPath the path of the file that may eventually be created.
42+
/// \param TemporaryPath must be non-null. Pointee will be set to a unique
43+
// string identifying this particular temporary buffer.
44+
// \returns A stream that can be used to write to the buffer.
45+
std::unique_ptr<llvm::raw_pwrite_stream> CreateTemporaryBuffer(
46+
llvm::StringRef OutputPath,
47+
std::string *TemporaryPath);
48+
49+
/// Releases the buffer underlying the temporary file.
50+
/// \param TemporaryPath the unique string from `CreateTemporaryFile`.
51+
void DeleteTemporaryBuffer(llvm::StringRef TemporaryPath);
52+
53+
/// Makes the contents of the specified temporary buffer visible on the
54+
/// `llvm::vfs::FileSystem` interface, and releases the temporary buffer. If
55+
/// the file already exists on the `llvm::vfs::FileSystem` interface, then
56+
/// the new contents is silently ignored.
57+
/// \param OutputPath the path of the file to create.
58+
/// \param TemporaryPath the unique string from `CreateTemporaryFile`.
59+
void FinalizeTemporaryBuffer(llvm::StringRef OutputPath,
60+
llvm::StringRef TemporaryPath);
61+
62+
// MARK: - `llvm::vfs::FileSystem` overrides
63+
64+
llvm::ErrorOr<llvm::vfs::Status> status(const llvm::Twine& relpath) override {
65+
llvm::MutexGuard locked(Mu);
66+
return OutputFiles->status(relpath);
67+
}
68+
69+
llvm::ErrorOr<std::unique_ptr<llvm::vfs::File>> openFileForRead(
70+
const llvm::Twine& relpath) override {
71+
llvm::MutexGuard locked(Mu);
72+
return OutputFiles->openFileForRead(relpath);
73+
}
74+
75+
llvm::vfs::directory_iterator dir_begin(const llvm::Twine& reldir,
76+
std::error_code& err) override {
77+
llvm::MutexGuard locked(Mu);
78+
return OutputFiles->dir_begin(reldir, err);
79+
}
80+
81+
std::error_code setCurrentWorkingDirectory(const llvm::Twine& path) override {
82+
llvm::MutexGuard locked(Mu);
83+
return OutputFiles->setCurrentWorkingDirectory(path);
84+
}
85+
86+
llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
87+
llvm::MutexGuard locked(Mu);
88+
return OutputFiles->getCurrentWorkingDirectory();
89+
}
90+
91+
std::error_code getRealPath(
92+
const llvm::Twine& path,
93+
llvm::SmallVectorImpl<char>& output) const override {
94+
llvm::MutexGuard locked(Mu);
95+
return OutputFiles->getRealPath(path, output);
96+
}
97+
98+
private:
99+
mutable llvm::sys::Mutex Mu;
100+
llvm::StringMap<llvm::SmallVector<char, 0>> TemporaryBuffers;
101+
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> OutputFiles;
102+
};
103+
104+
} // namespace clang
105+
106+
#endif // LLVM_CLANG_BASIC_INMEMORYOUTPUTFILESYSTEM_H_

clang/include/clang/Frontend/CompilerInstance.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include "clang/AST/ASTConsumer.h"
1313
#include "clang/Basic/Diagnostic.h"
14+
// SWIFT_ENABLE_TENSORFLOW
15+
#include "clang/Basic/InMemoryOutputFileSystem.h"
1416
#include "clang/Basic/SourceManager.h"
1517
#include "clang/Frontend/CompilerInvocation.h"
1618
#include "clang/Frontend/PCHContainerOperations.h"
@@ -186,6 +188,11 @@ class CompilerInstance : public ModuleLoader {
186188
/// Force an output buffer.
187189
std::unique_ptr<llvm::raw_pwrite_stream> OutputStream;
188190

191+
// SWIFT_ENABLE_TENSORFLOW
192+
/// If defined, outputs will be written here instead of to the real
193+
/// filesystem.
194+
IntrusiveRefCntPtr<InMemoryOutputFileSystem> InMemoryOutputFileSystem;
195+
189196
CompilerInstance(const CompilerInstance &) = delete;
190197
void operator=(const CompilerInstance &) = delete;
191198
public:
@@ -393,6 +400,19 @@ class CompilerInstance : public ModuleLoader {
393400
return getFileManager().getVirtualFileSystem();
394401
}
395402

403+
// SWIFT_ENABLE_TENSORFLOW
404+
/// }
405+
/// @name In-Memory Output File System
406+
/// {
407+
408+
IntrusiveRefCntPtr<clang::InMemoryOutputFileSystem> getInMemoryOutputFileSystem() const {
409+
return InMemoryOutputFileSystem;
410+
}
411+
412+
void setInMemoryOutputFileSystem(IntrusiveRefCntPtr<clang::InMemoryOutputFileSystem> FS) {
413+
InMemoryOutputFileSystem = std::move(FS);
414+
}
415+
396416
/// }
397417
/// @name File Manager
398418
/// {

clang/lib/Basic/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ add_clang_library(clangBasic
4949
FileSystemStatCache.cpp
5050
FixedPoint.cpp
5151
IdentifierTable.cpp
52+
InMemoryOutputFileSystem.cpp
5253
LangOptions.cpp
5354
LangStandards.cpp
5455
Module.cpp
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//=== InMemoryOutputFileSystem.cpp - Collects outputs in memory -*- C++ -*-===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "clang/Basic/InMemoryOutputFileSystem.h"
11+
12+
namespace clang {
13+
14+
std::unique_ptr<llvm::raw_pwrite_stream>
15+
InMemoryOutputFileSystem::CreateTemporaryBuffer(llvm::StringRef OutputPath,
16+
std::string *TemporaryPath) {
17+
assert(TemporaryPath);
18+
llvm::MutexGuard locked(Mu);
19+
llvm::StringMap<llvm::SmallVector<char, 0>>::iterator it;
20+
bool inserted = false;
21+
unsigned suffix = 0;
22+
while (!inserted) {
23+
*TemporaryPath = "";
24+
llvm::raw_string_ostream TemporaryPathOS(*TemporaryPath);
25+
TemporaryPathOS << OutputPath << "-" << suffix;
26+
TemporaryPathOS.flush();
27+
auto result = TemporaryBuffers.try_emplace(*TemporaryPath);
28+
it = result.first;
29+
inserted = result.second;
30+
suffix += 1;
31+
}
32+
return llvm::make_unique<llvm::raw_svector_ostream>(it->getValue());
33+
}
34+
35+
void InMemoryOutputFileSystem::DeleteTemporaryBuffer(llvm::StringRef TemporaryPath) {
36+
llvm::MutexGuard locked(Mu);
37+
auto it = TemporaryBuffers.find(TemporaryPath);
38+
assert(it != TemporaryBuffers.end());
39+
TemporaryBuffers.erase(it);
40+
}
41+
42+
void InMemoryOutputFileSystem::FinalizeTemporaryBuffer(llvm::StringRef OutputPath,
43+
llvm::StringRef TemporaryPath) {
44+
llvm::MutexGuard locked(Mu);
45+
auto it = TemporaryBuffers.find(TemporaryPath);
46+
assert(it != TemporaryBuffers.end());
47+
auto memoryBuffer = llvm::MemoryBuffer::getMemBufferCopy(
48+
llvm::StringRef{it->getValue().data(), it->getValue().size()},
49+
OutputPath);
50+
OutputFiles->addFile(OutputPath, /*ModificationTime=*/0,
51+
std::move(memoryBuffer));
52+
TemporaryBuffers.erase(it);
53+
}
54+
55+
} // namespace clang

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,19 @@ void CompilerInstance::addOutputFile(OutputFile &&OutFile) {
652652

653653
void CompilerInstance::clearOutputFiles(bool EraseFiles) {
654654
for (OutputFile &OF : OutputFiles) {
655+
// SWIFT_ENABLE_TENSORFLOW
656+
if (InMemoryOutputFileSystem) {
657+
assert(!OF.TempFilename.empty() &&
658+
"InMemoryOutputFileSystem requires using temporary files");
659+
if (EraseFiles) {
660+
InMemoryOutputFileSystem->DeleteTemporaryBuffer(OF.TempFilename);
661+
} else {
662+
InMemoryOutputFileSystem->FinalizeTemporaryBuffer(OF.Filename,
663+
OF.TempFilename);
664+
}
665+
continue;
666+
}
667+
655668
if (!OF.TempFilename.empty()) {
656669
if (EraseFiles) {
657670
llvm::sys::fs::remove(OF.TempFilename);
@@ -738,6 +751,18 @@ std::unique_ptr<llvm::raw_pwrite_stream> CompilerInstance::createOutputFile(
738751
OutFile = "-";
739752
}
740753

754+
// SWIFT_ENABLE_TENSORFLOW
755+
if (InMemoryOutputFileSystem) {
756+
assert(UseTemporary && "InMemoryOutputFileSystem requires using temporary files");
757+
auto stream = InMemoryOutputFileSystem->CreateTemporaryBuffer(OutFile,
758+
&TempFile);
759+
if (ResultPathName)
760+
*ResultPathName = OutFile;
761+
if (TempPathName)
762+
*TempPathName = TempFile;
763+
return stream;
764+
}
765+
741766
std::unique_ptr<llvm::raw_fd_ostream> OS;
742767
std::string OSFile;
743768

@@ -1128,6 +1153,9 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
11281153
ImportingInstance.getDiagnosticClient()),
11291154
/*ShouldOwnClient=*/true);
11301155

1156+
// SWIFT_ENABLE_TENSORFLOW
1157+
Instance.setInMemoryOutputFileSystem(ImportingInstance.getInMemoryOutputFileSystem());
1158+
11311159
// Note that this module is part of the module build stack, so that we
11321160
// can detect cycles in the module graph.
11331161
Instance.setFileManager(&ImportingInstance.getFileManager());
@@ -1277,6 +1305,33 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance,
12771305
<< Module->Name << SourceRange(ImportLoc, ModuleNameLoc);
12781306
};
12791307

1308+
// SWIFT_ENABLE_TENSORFLOW
1309+
// If we're writing to an InMemoryOutputFileSystem, then immediately compile
1310+
// and read the module, rather than doing all the lockfile based locking logic
1311+
// below, because the InMemoryOutputFileSystem doesn't support lockfiles. This
1312+
// is okay because the locks are only necessary for performance, not
1313+
// correctness.
1314+
if (ImportingInstance.getInMemoryOutputFileSystem()) {
1315+
if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module,
1316+
ModuleFileName)) {
1317+
diagnoseBuildFailure();
1318+
return false;
1319+
}
1320+
1321+
// Try to read the module file, now that we've compiled it.
1322+
ASTReader::ASTReadResult ReadResult =
1323+
ImportingInstance.getModuleManager()->ReadAST(
1324+
ModuleFileName, serialization::MK_ImplicitModule, ImportLoc,
1325+
ASTReader::ARR_None);
1326+
1327+
if (ReadResult != ASTReader::Success) {
1328+
diagnoseBuildFailure();
1329+
return false;
1330+
}
1331+
1332+
return true;
1333+
}
1334+
12801335
// FIXME: have LockFileManager return an error_code so that we can
12811336
// avoid the mkdir when the directory already exists.
12821337
StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);

0 commit comments

Comments
 (0)