[PATCH] D78058: option to write files to memory instead of disk

2020-04-13 Thread Marc Rasi via Phabricator via cfe-commits
marcrasi created this revision.
Herald added subscribers: cfe-commits, jfb, mgorny.
Herald added a project: clang.
marcrasi edited the summary of this revision.

This allows clients to invoke clang without writing anything to disk.

I'm not sure if this is the right design, so I'm sending this patch to
start a discussion about the right way to do this. I'll be happy to make
changes and add tests after talking about the right way to do this!

Motivation:

At Google, we run some Swift source tooling on diskless servers. The
Swift source tooling calls Clang through the ClangImporter
(https://github.com/apple/swift/blob/master/lib/ClangImporter/ClangImporter.cpp).
Clang compiles module to an on-disk module cache, which does not work on
the diskless servers. This patch lets clients ask Clang to write the
module cache to memory.

Current design:

- Adds `class InMemoryOutputFileSystem : public llvm::vfs::FileSystem` that 
supports write operations backed by memory. After a file is written, its 
contents are accessible through the `llvm::vfs::FileSystem` interface.
- Adds an `InMemoryOutputFileSystem` field to `CompilerInstance`. When this 
field is set, the `CompilerInstance` writes to the `InMemoryOutputFileSystem` 
instead of the real file system.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78058

Files:
  clang/include/clang/Basic/InMemoryOutputFileSystem.h
  clang/include/clang/Frontend/CompilerInstance.h
  clang/lib/Basic/CMakeLists.txt
  clang/lib/Basic/InMemoryOutputFileSystem.cpp
  clang/lib/Frontend/CompilerInstance.cpp

Index: clang/lib/Frontend/CompilerInstance.cpp
===
--- clang/lib/Frontend/CompilerInstance.cpp
+++ clang/lib/Frontend/CompilerInstance.cpp
@@ -642,6 +642,18 @@
 
 void CompilerInstance::clearOutputFiles(bool EraseFiles) {
   for (OutputFile &OF : OutputFiles) {
+if (InMemoryOutputFileSystem) {
+  assert(!OF.TempFilename.empty() &&
+ "InMemoryOutputFileSystem requires using temporary files");
+  if (EraseFiles) {
+InMemoryOutputFileSystem->DeleteTemporaryBuffer(OF.TempFilename);
+  } else {
+InMemoryOutputFileSystem->FinalizeTemporaryBuffer(OF.Filename,
+  OF.TempFilename);
+  }
+  continue;
+}
+
 if (!OF.TempFilename.empty()) {
   if (EraseFiles) {
 llvm::sys::fs::remove(OF.TempFilename);
@@ -728,6 +740,18 @@
 OutFile = "-";
   }
 
+  if (InMemoryOutputFileSystem) {
+assert(UseTemporary &&
+   "InMemoryOutputFileSystem requires using temporary files");
+auto stream =
+InMemoryOutputFileSystem->CreateTemporaryBuffer(OutFile, &TempFile);
+if (ResultPathName)
+  *ResultPathName = OutFile;
+if (TempPathName)
+  *TempPathName = TempFile;
+return stream;
+  }
+
   std::unique_ptr OS;
   std::string OSFile;
 
@@ -1126,6 +1150,9 @@
ImportingInstance.getDiagnosticClient()),
  /*ShouldOwnClient=*/true);
 
+  Instance.setInMemoryOutputFileSystem(
+  ImportingInstance.getInMemoryOutputFileSystem());
+
   // Note that this module is part of the module build stack, so that we
   // can detect cycles in the module graph.
   Instance.setFileManager(&ImportingInstance.getFileManager());
@@ -1271,6 +1298,32 @@
 << Module->Name << SourceRange(ImportLoc, ModuleNameLoc);
   };
 
+  // If we're writing to an InMemoryOutputFileSystem, then immediately compile
+  // and read the module, rather than doing all the lockfile based locking logic
+  // below, because the InMemoryOutputFileSystem doesn't support lockfiles. This
+  // is okay because the locks are only necessary for performance, not
+  // correctness.
+  if (ImportingInstance.getInMemoryOutputFileSystem()) {
+if (!compileModule(ImportingInstance, ModuleNameLoc, Module,
+   ModuleFileName)) {
+  diagnoseBuildFailure();
+  return false;
+}
+
+// Try to read the module file, now that we've compiled it.
+ASTReader::ASTReadResult ReadResult =
+ImportingInstance.getASTReader()->ReadAST(
+ModuleFileName, serialization::MK_ImplicitModule, ImportLoc,
+ASTReader::ARR_None);
+
+if (ReadResult != ASTReader::Success) {
+  diagnoseBuildFailure();
+  return false;
+}
+
+return true;
+  }
+
   // FIXME: have LockFileManager return an error_code so that we can
   // avoid the mkdir when the directory already exists.
   StringRef Dir = llvm::sys::path::parent_path(ModuleFileName);
Index: clang/lib/Basic/InMemoryOutputFileSystem.cpp
===
--- /dev/null
+++ clang/lib/Basic/InMemoryOutputFileSystem.cpp
@@ -0,0 +1,56 @@
+//=== InMemoryOutputFileSystem.cpp - Collects outputs in memory -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dist

[PATCH] D78058: option to write files to memory instead of disk

2020-12-02 Thread Marc Rasi via Phabricator via cfe-commits
marcrasi added a comment.

Ping on this. Could anyone take a look?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D78058/new/

https://reviews.llvm.org/D78058

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits