Optimize Condition Resolution (#6279)

* Pack the bits for IfConfigDecls into Decl

* Don't open symbols into a module when evaluating canImport statements

The module loaders now have API to check whether a given module can be
imported without importing the referenced module.  This provides a
significant speed boost to condition resolution and no longer
introduces symbols from the referenced module into the current context
without the user explicitly requesting it.

The definition of ‘canImport’ does not necessarily mean that a full
import without error is possible, merely that the path to the import is
visible to the compiler and the module is loadable in some form or
another.

Note that this means this check is insufficient to guarantee that you
are on one platform or another.  For those kinds of checks, use
‘os(OSNAME)’.
This commit is contained in:
Robert Widmann
2017-01-05 12:08:54 -07:00
committed by GitHub
parent d5a55c4b90
commit dfa41d625b
16 changed files with 211 additions and 24 deletions

View File

@@ -19,6 +19,7 @@
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Version.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Debug.h"
@@ -39,15 +40,25 @@ SerializedModuleLoader::~SerializedModuleLoader() = default;
static std::error_code
openModuleFiles(StringRef DirName, StringRef ModuleFilename,
StringRef ModuleDocFilename,
std::unique_ptr<llvm::MemoryBuffer> &ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> &ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
llvm::SmallVectorImpl<char> &Scratch) {
assert(((ModuleBuffer && ModuleDocBuffer)
|| (!ModuleBuffer && !ModuleDocBuffer))
&& "Module and Module Doc buffer must both be initialized or NULL");
// Try to open the module file first. If we fail, don't even look for the
// module documentation file.
Scratch.clear();
llvm::sys::path::append(Scratch, DirName, ModuleFilename);
// If there are no buffers to load into, simply check for the existence of
// the module file.
if (!(ModuleBuffer || ModuleDocBuffer)) {
return llvm::sys::fs::access(StringRef(Scratch.data(), Scratch.size()),
llvm::sys::fs::AccessMode::Exist);
}
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ModuleOrErr =
llvm::MemoryBuffer::getFile(StringRef(Scratch.data(), Scratch.size()));
llvm::MemoryBuffer::getFile(StringRef(Scratch.data(), Scratch.size()));
if (!ModuleOrErr)
return ModuleOrErr.getError();
@@ -56,21 +67,23 @@ openModuleFiles(StringRef DirName, StringRef ModuleFilename,
Scratch.clear();
llvm::sys::path::append(Scratch, DirName, ModuleDocFilename);
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ModuleDocOrErr =
llvm::MemoryBuffer::getFile(StringRef(Scratch.data(), Scratch.size()));
llvm::MemoryBuffer::getFile(StringRef(Scratch.data(), Scratch.size()));
if (!ModuleDocOrErr &&
ModuleDocOrErr.getError() != std::errc::no_such_file_or_directory) {
return ModuleDocOrErr.getError();
}
ModuleBuffer = std::move(ModuleOrErr.get());
*ModuleBuffer = std::move(ModuleOrErr.get());
if (ModuleDocOrErr)
ModuleDocBuffer = std::move(ModuleDocOrErr.get());
*ModuleDocBuffer = std::move(ModuleDocOrErr.get());
return std::error_code();
}
static bool
findModule(ASTContext &ctx, AccessPathElem moduleID,
std::unique_ptr<llvm::MemoryBuffer> &moduleBuffer,
std::unique_ptr<llvm::MemoryBuffer> &moduleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
bool &isFramework) {
llvm::SmallString<64> moduleFilename(moduleID.first.str());
moduleFilename += '.';
@@ -95,7 +108,6 @@ findModule(ASTContext &ctx, AccessPathElem moduleID,
llvm::SmallString<128> scratch;
llvm::SmallString<128> currPath;
isFramework = false;
for (auto path : ctx.SearchPathOpts.ImportSearchPaths) {
auto err = openModuleFiles(path,
@@ -353,6 +365,21 @@ FileUnit *SerializedModuleLoader::loadAST(
return nullptr;
}
bool
SerializedModuleLoader::canImportModule(std::pair<Identifier, SourceLoc> mID) {
// First see if we find it in the registered memory buffers.
if (!MemoryBuffers.empty()) {
auto bufIter = MemoryBuffers.find(mID.first.str());
if (bufIter != MemoryBuffers.end()) {
return true;
}
}
// Otherwise look on disk.
bool isFramework = false;
return findModule(Ctx, mID, nullptr, nullptr, isFramework);
}
Module *SerializedModuleLoader::loadModule(SourceLoc importLoc,
Module::AccessPathTy path) {
// FIXME: Swift submodules?
@@ -378,7 +405,7 @@ Module *SerializedModuleLoader::loadModule(SourceLoc importLoc,
// Otherwise look on disk.
if (!moduleInputBuffer) {
if (!findModule(Ctx, moduleID, moduleInputBuffer, moduleDocInputBuffer,
if (!findModule(Ctx, moduleID, &moduleInputBuffer, &moduleDocInputBuffer,
isFramework)) {
return nullptr;
}