Skip to content
This repository has been archived by the owner on Mar 28, 2020. It is now read-only.

[4.1] Don't bother caching compiled API notes at all #121

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 0 additions & 3 deletions include/clang/APINotes/APINotesManager.h
Expand Up @@ -65,9 +65,6 @@ class APINotesManager {
/// for private headers.
APINotesReader *CurrentModuleReaders[2] = { nullptr, nullptr };

/// Whether we have already pruned the API notes cache.
bool PrunedCache;

/// A mapping from header file directories to the API notes reader for
/// that directory, or a redirection to another directory entry that may
/// have more information, or NULL to indicate that there is no API notes
Expand Down
4 changes: 0 additions & 4 deletions include/clang/Basic/DiagnosticFrontendKinds.td
Expand Up @@ -229,10 +229,6 @@ def err_missing_vfs_overlay_file : Error<
def err_invalid_vfs_overlay : Error<
"invalid virtual filesystem overlay file '%0'">, DefaultFatal;

def err_no_apinotes_cache_path : Error<
"-fapinotes was provided without -fapinotes-cache-path=<directory>">,
DefaultFatal;

def warn_option_invalid_ocl_version : Warning<
"OpenCL version %0 does not support the option '%1'">, InGroup<Deprecated>;
}
3 changes: 0 additions & 3 deletions include/clang/Basic/FileSystemOptions.h
Expand Up @@ -25,9 +25,6 @@ class FileSystemOptions {
/// \brief If set, paths are resolved as if the working directory was
/// set to the value of WorkingDir.
std::string WorkingDir;

/// The path to the API notes cache.
std::string APINotesCachePath;
};

} // end namespace clang
Expand Down
4 changes: 2 additions & 2 deletions include/clang/Driver/Options.td
Expand Up @@ -701,8 +701,8 @@ def fno_apinotes : Flag<["-"], "fno-apinotes">, Group<f_clang_Group>,
def fno_apinotes_modules : Flag<["-"], "fno-apinotes-modules">, Group<f_clang_Group>,
Flags<[CC1Option]>, HelpText<"Disable module-based external API notes support">;
def fapinotes_cache_path : Joined<["-"], "fapinotes-cache-path=">,
Group<i_Group>, Flags<[DriverOption, CC1Option]>, MetaVarName<"<directory>">,
HelpText<"Specify the API notes cache path">;
Group<i_Group>, Flags<[DriverOption]>, MetaVarName<"<directory>">,
HelpText<"Does nothing; API notes are no longer cached separately from modules">;
def fapinotes_swift_version : Joined<["-"], "fapinotes-swift-version=">,
Group<f_clang_Group>, Flags<[CC1Option]>, MetaVarName<"<version>">,
HelpText<"Specify the Swift version to use when filtering API notes">;
Expand Down
167 changes: 3 additions & 164 deletions lib/APINotes/APINotesManager.cpp
Expand Up @@ -46,12 +46,6 @@ STATISTIC(NumDirectoriesSearched,
"header directories searched");
STATISTIC(NumDirectoryCacheHits,
"directory cache hits");
STATISTIC(NumBinaryCacheHits,
"binary form cache hits");
STATISTIC(NumBinaryCacheMisses,
"binary form cache misses");
STATISTIC(NumBinaryCacheRebuilds,
"binary form cache rebuilds");

namespace {
/// Prints two successive strings, which much be kept alive as long as the
Expand All @@ -69,8 +63,7 @@ namespace {

APINotesManager::APINotesManager(SourceManager &sourceMgr,
const LangOptions &langOpts)
: SourceMgr(sourceMgr), ImplicitAPINotes(langOpts.APINotes),
PrunedCache(false) { }
: SourceMgr(sourceMgr), ImplicitAPINotes(langOpts.APINotes) { }

APINotesManager::~APINotesManager() {
// Free the API notes readers.
Expand All @@ -84,78 +77,8 @@ APINotesManager::~APINotesManager() {
delete CurrentModuleReaders[1];
}

/// \brief Write a new timestamp file with the given path.
static void writeTimestampFile(StringRef TimestampFile) {
std::error_code EC;
llvm::raw_fd_ostream Out(TimestampFile.str(), EC, llvm::sys::fs::F_None);
}

/// \brief Prune the API notes cache of API notes that haven't been accessed in
/// a long time.
static void pruneAPINotesCache(StringRef APINotesCachePath) {
struct stat StatBuf;
llvm::SmallString<128> TimestampFile;
TimestampFile = APINotesCachePath;
llvm::sys::path::append(TimestampFile, "APINotes.timestamp");

// Try to stat() the timestamp file.
if (::stat(TimestampFile.c_str(), &StatBuf)) {
// If the timestamp file wasn't there, create one now.
if (errno == ENOENT) {
llvm::sys::fs::create_directories(APINotesCachePath);
writeTimestampFile(TimestampFile);
}
return;
}

const unsigned APINotesCachePruneInterval = 7 * 24 * 60 * 60;
const unsigned APINotesCachePruneAfter = 31 * 24 * 60 * 60;

// Check whether the time stamp is older than our pruning interval.
// If not, do nothing.
time_t TimeStampModTime = StatBuf.st_mtime;
time_t CurrentTime = time(nullptr);
if (CurrentTime - TimeStampModTime <= time_t(APINotesCachePruneInterval))
return;

// Write a new timestamp file so that nobody else attempts to prune.
// There is a benign race condition here, if two Clang instances happen to
// notice at the same time that the timestamp is out-of-date.
writeTimestampFile(TimestampFile);

// Walk the entire API notes cache, looking for unused compiled API notes.
std::error_code EC;
SmallString<128> APINotesCachePathNative;
llvm::sys::path::native(APINotesCachePath, APINotesCachePathNative);
for (llvm::sys::fs::directory_iterator
File(APINotesCachePathNative.str(), EC), DirEnd;
File != DirEnd && !EC; File.increment(EC)) {
StringRef Extension = llvm::sys::path::extension(File->path());
if (Extension.empty())
continue;

if (Extension.substr(1) != BINARY_APINOTES_EXTENSION)
continue;

// Look at this file. If we can't stat it, there's nothing interesting
// there.
if (::stat(File->path().c_str(), &StatBuf))
continue;

// If the file has been used recently enough, leave it there.
time_t FileAccessTime = StatBuf.st_atime;
if (CurrentTime - FileAccessTime <= time_t(APINotesCachePruneAfter)) {
continue;
}

// Remove the file.
llvm::sys::fs::remove(File->path());
}
}

std::unique_ptr<APINotesReader>
APINotesManager::loadAPINotes(const FileEntry *apiNotesFile) {
FileManager &fileMgr = SourceMgr.getFileManager();
PrettyStackTraceDoubleString trace("Loading API notes from ",
apiNotesFile->getName());

Expand All @@ -174,59 +97,6 @@ APINotesManager::loadAPINotes(const FileEntry *apiNotesFile) {
return APINotesReader::getUnmanaged(buffer, SwiftVersion);
}

// If we haven't pruned the API notes cache yet during this execution, do
// so now.
if (!PrunedCache) {
pruneAPINotesCache(fileMgr.getFileSystemOpts().APINotesCachePath);
PrunedCache = true;
}

// Compute a hash of the API notes file's directory and the Clang version,
// to be used as part of the filename for the cached binary copy.
auto code = llvm::hash_value(StringRef(apiNotesFile->getDir()->getName()));
code = hash_combine(code, getClangFullRepositoryVersion());

// Determine the file name for the cached binary form.
SmallString<128> compiledFileName;
compiledFileName += fileMgr.getFileSystemOpts().APINotesCachePath;
assert(!compiledFileName.empty() && "No API notes cache path provided?");
llvm::sys::path::append(compiledFileName,
(llvm::Twine(llvm::sys::path::stem(apiNotesFileName)) + "-"
+ llvm::APInt(64, code).toString(36, /*Signed=*/false) + "."
+ BINARY_APINOTES_EXTENSION));

// Try to open the cached binary form.
if (const FileEntry *compiledFile = fileMgr.getFile(compiledFileName,
/*openFile=*/true,
/*cacheFailure=*/false)) {
// Load the file contents.
if (auto buffer = fileMgr.getBufferForFile(compiledFile)) {
// Load the file.
if (auto reader = APINotesReader::get(std::move(buffer.get()),
SwiftVersion)) {
bool outOfDate = false;
if (auto sizeAndModTime = reader->getSourceFileSizeAndModTime()) {
if (sizeAndModTime->first != apiNotesFile->getSize() ||
sizeAndModTime->second != apiNotesFile->getModificationTime())
outOfDate = true;
}

if (!outOfDate) {
// Success.
++NumBinaryCacheHits;
return reader;
}
}
}

// The cache entry was somehow broken; delete this one so we can build a
// new one below.
llvm::sys::fs::remove(compiledFileName.str());
++NumBinaryCacheRebuilds;
} else {
++NumBinaryCacheMisses;
}

// Open the source file.
auto sourceFileID = SourceMgr.createFileID(apiNotesFile, SourceLocation(), SrcMgr::C_User);
auto sourceBuffer = SourceMgr.getBuffer(sourceFileID, SourceLocation());
Expand All @@ -235,6 +105,8 @@ APINotesManager::loadAPINotes(const FileEntry *apiNotesFile) {
// Compile the API notes source into a buffer.
// FIXME: Either propagate OSType through or, better yet, improve the binary
// APINotes format to maintain complete availability information.
// FIXME: We don't even really need to go through the binary format at all;
// we're just going to immediately deserialize it again.
llvm::SmallVector<char, 1024> apiNotesBuffer;
std::unique_ptr<llvm::MemoryBuffer> compiledBuffer;
{
Expand All @@ -257,39 +129,6 @@ APINotesManager::loadAPINotes(const FileEntry *apiNotesFile) {
StringRef(apiNotesBuffer.data(), apiNotesBuffer.size()));
}

// Save the binary form into the cache. Perform this operation
// atomically.
SmallString<64> temporaryBinaryFileName = compiledFileName.str();
temporaryBinaryFileName.erase(
temporaryBinaryFileName.end()
- llvm::sys::path::extension(temporaryBinaryFileName).size(),
temporaryBinaryFileName.end());
temporaryBinaryFileName += "-%%%%%%.";
temporaryBinaryFileName += BINARY_APINOTES_EXTENSION;

int temporaryFD;
llvm::sys::fs::create_directories(
fileMgr.getFileSystemOpts().APINotesCachePath);
if (!llvm::sys::fs::createUniqueFile(temporaryBinaryFileName.str(),
temporaryFD, temporaryBinaryFileName)) {
// Write the contents of the buffer.
bool hadError;
{
llvm::raw_fd_ostream out(temporaryFD, /*shouldClose=*/true);
out.write(compiledBuffer.get()->getBufferStart(),
compiledBuffer.get()->getBufferSize());
out.flush();

hadError = out.has_error();
}

if (!hadError) {
// Rename the temporary file to the actual compiled file.
llvm::sys::fs::rename(temporaryBinaryFileName.str(),
compiledFileName.str());
}
}

// Load the binary form we just compiled.
auto reader = APINotesReader::get(std::move(compiledBuffer), SwiftVersion);
assert(reader && "Could not load the API notes we just generated?");
Expand Down
22 changes: 0 additions & 22 deletions lib/Driver/ToolChains/Clang.cpp
Expand Up @@ -3507,28 +3507,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_apinotes_modules, false))
CmdArgs.push_back("-fapinotes-modules");

SmallString<128> APINotesCachePath;
if (Arg *A = Args.getLastArg(options::OPT_fapinotes_cache_path)) {
APINotesCachePath = A->getValue();
}

if (C.isForDiagnostics()) {
// When generating crash reports, we want to emit the API notes along with
// the reproduction sources, so we ignore any provided API notes path.
APINotesCachePath = Output.getFilename();
llvm::sys::path::replace_extension(APINotesCachePath, ".cache");
llvm::sys::path::append(APINotesCachePath, "apinotes");
} else if (APINotesCachePath.empty()) {
// No API notes path was provided: use the default.
llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false,
APINotesCachePath);
llvm::sys::path::append(APINotesCachePath, "org.llvm.clang");
llvm::sys::path::append(APINotesCachePath, "APINotesCache");
}
const char Arg[] = "-fapinotes-cache-path=";
APINotesCachePath.insert(APINotesCachePath.begin(), Arg, Arg + strlen(Arg));
CmdArgs.push_back(Args.MakeArgString(APINotesCachePath));

Args.AddLastArg(CmdArgs, options::OPT_fapinotes_swift_version);
}

Expand Down
8 changes: 0 additions & 8 deletions lib/Frontend/CompilerInvocation.cpp
Expand Up @@ -1171,7 +1171,6 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args,

static void ParseFileSystemArgs(FileSystemOptions &Opts, ArgList &Args) {
Opts.WorkingDir = Args.getLastArgValue(OPT_working_directory);
Opts.APINotesCachePath = Args.getLastArgValue(OPT_fapinotes_cache_path);
}

/// Parse the argument to the -ftest-module-file-extension
Expand Down Expand Up @@ -2696,13 +2695,6 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res,
Res.getPreprocessorOpts(), Diags);
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
LangOpts.ObjCExceptions = 1;

// -fapinotes and -fapinotes-modules requires -fapinotes-cache-path=<directory>.
if ((LangOpts.APINotes || LangOpts.APINotesModules) &&
Res.getFileSystemOpts().APINotesCachePath.empty()) {
Diags.Report(diag::err_no_apinotes_cache_path);
Success = false;
}
}

if (LangOpts.CUDA) {
Expand Down
2 changes: 1 addition & 1 deletion test/APINotes/availability.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s -verify

#include "HeaderLib.h"
#import <SomeKit/SomeKit.h>
Expand Down
2 changes: 1 addition & 1 deletion test/APINotes/broken_types.m
@@ -1,5 +1,5 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fapinotes-cache-path=%t/APINotesCache -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s 2> %t.err
// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -F %S/Inputs/Frameworks %s 2> %t.err
// RUN: FileCheck %s < %t.err

#include "BrokenTypes.h"
Expand Down
32 changes: 0 additions & 32 deletions test/APINotes/cache.m

This file was deleted.