mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
When we miss the in-memory (libcache-based) code completion cache, we can now chain to an on-disk code completion cache. This drastically improves the time and peak memory usage it takes to do the first code completion (ie. before the in-memory cache is warm) if we've done the same lookup before. The on-disk cache, like the in-memory cache is tied to the specific compiled swift and clang module files (.swiftmodule and .pcm), and will consider itself out of date if they are modified. Responsibility for deleting completely dead/unreachable cache files falls to the client. Most of this commit is adding a simple serialization and deserialization for CodeCompletionResults and CodeCompletionStrings. The format is very simple, using an array of fixed size CodeCompletionResults, with offsets into two blobs: one for CodeCompletionString::Chunks, and one for strings. Currently that gives us about 5.8 MB for all the results in Cocoa, but it's very compressible if we decide we want to reduce it (gzip'd it is ~1.2 MB for the same data). Swift SVN r28369
126 lines
3.8 KiB
C++
126 lines
3.8 KiB
C++
//===- CodeCompletionCache.h - Routines for code completion caching -------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_IDE_CODE_COMPLETIONCACHE_H
|
|
#define SWIFT_IDE_CODE_COMPLETIONCACHE_H
|
|
|
|
#include "swift/IDE/CodeCompletion.h"
|
|
#include "swift/Basic/ThreadSafeRefCounted.h"
|
|
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
|
|
|
namespace swift {
|
|
namespace ide {
|
|
|
|
struct CodeCompletionCacheImpl;
|
|
class OnDiskCodeCompletionCache;
|
|
|
|
/// \brief In-memory per-module code completion result cache.
|
|
///
|
|
/// These results persist between multiple code completion requests and can be
|
|
/// used with different ASTContexts.
|
|
class CodeCompletionCache {
|
|
std::unique_ptr<CodeCompletionCacheImpl> Impl;
|
|
OnDiskCodeCompletionCache *nextCache;
|
|
|
|
public:
|
|
/// \brief Cache key.
|
|
struct Key {
|
|
std::string ModuleFilename;
|
|
std::string ModuleName;
|
|
std::vector<std::string> AccessPath;
|
|
bool ResultsHaveLeadingDot;
|
|
bool ForTestableLookup;
|
|
|
|
friend bool operator==(const Key &LHS, const Key &RHS) {
|
|
return LHS.ModuleFilename == RHS.ModuleFilename &&
|
|
LHS.ModuleName == RHS.ModuleName &&
|
|
LHS.AccessPath == RHS.AccessPath &&
|
|
LHS.ResultsHaveLeadingDot == RHS.ResultsHaveLeadingDot &&
|
|
LHS.ForTestableLookup == RHS.ForTestableLookup;
|
|
}
|
|
};
|
|
|
|
struct Value : public ThreadSafeRefCountedBase<Value> {
|
|
llvm::sys::TimeValue ModuleModificationTime;
|
|
CodeCompletionResultSink Sink;
|
|
};
|
|
using ValueRefCntPtr = llvm::IntrusiveRefCntPtr<Value>;
|
|
|
|
CodeCompletionCache(OnDiskCodeCompletionCache *nextCache = nullptr);
|
|
~CodeCompletionCache();
|
|
|
|
static ValueRefCntPtr createValue();
|
|
Optional<ValueRefCntPtr> get(const Key &K);
|
|
void set(const Key &K, ValueRefCntPtr V) { setImpl(K, V, /*setChain*/ true); }
|
|
|
|
private:
|
|
void setImpl(const Key &K, ValueRefCntPtr V, bool setChain);
|
|
};
|
|
|
|
/// \brief On-disk per-module code completion result cache.
|
|
///
|
|
/// These results persist between multiple code completion requests and can be
|
|
/// used with different ASTContexts.
|
|
class OnDiskCodeCompletionCache {
|
|
std::string cacheDirectory;
|
|
|
|
public:
|
|
using Key = CodeCompletionCache::Key;
|
|
using Value = CodeCompletionCache::Value;
|
|
using ValueRefCntPtr = CodeCompletionCache::ValueRefCntPtr;
|
|
|
|
OnDiskCodeCompletionCache(Twine cacheDirectory);
|
|
~OnDiskCodeCompletionCache();
|
|
|
|
Optional<ValueRefCntPtr> get(const Key &K);
|
|
std::error_code set(const Key &K, ValueRefCntPtr V);
|
|
|
|
static Optional<ValueRefCntPtr> getFromFile(StringRef filename);
|
|
};
|
|
|
|
struct RequestedCachedModule {
|
|
CodeCompletionCache::Key Key;
|
|
const ModuleDecl *TheModule;
|
|
bool OnlyTypes;
|
|
};
|
|
|
|
} // end namespace ide
|
|
} // end namespace swift
|
|
|
|
namespace llvm {
|
|
template<>
|
|
struct DenseMapInfo<swift::ide::CodeCompletionCache::Key> {
|
|
using KeyTy = swift::ide::CodeCompletionCache::Key;
|
|
static inline KeyTy getEmptyKey() {
|
|
return KeyTy{"", "", {}, false, false};
|
|
}
|
|
static inline KeyTy getTombstoneKey() {
|
|
return KeyTy{"", "", {}, true, false};
|
|
}
|
|
static unsigned getHashValue(const KeyTy &Val) {
|
|
size_t H = 0;
|
|
H ^= std::hash<std::string>()(Val.ModuleFilename);
|
|
H ^= std::hash<std::string>()(Val.ModuleName);
|
|
for (auto Piece : Val.AccessPath)
|
|
H ^= std::hash<std::string>()(Piece);
|
|
H ^= std::hash<bool>()(Val.ResultsHaveLeadingDot);
|
|
H ^= std::hash<bool>()(Val.ForTestableLookup);
|
|
return static_cast<unsigned>(H);
|
|
}
|
|
static bool isEqual(const KeyTy &LHS, const KeyTy &RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
};
|
|
} // end namespace llvm
|
|
|
|
#endif // SWIFT_IDE_CODE_COMPLETIONCACHE_H
|