mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[libBasic] Introduce a caching mechanism, that evicts its entries when there is memory pressure.
The underlying mechanism uses darwin's libcache library (if not building on darwin there is a default implementation). This was originally introduced in SourceKit, but we are moving it to libswiftBasic so it can be utilized by libswiftIDE for caching code-completion results. Swift SVN r9610
This commit is contained in:
142
lib/Basic/Cache.cpp
Normal file
142
lib/Basic/Cache.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
//===--- Cache.h - Caching mechanism implementation -----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===---------------------------------------------------------------------===//
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include "Darwin/Cache-Mac.cpp"
|
||||
#else
|
||||
|
||||
// This file implements a default caching implementation that never evicts
|
||||
// its entries.
|
||||
|
||||
#include "swift/Basic/Cache.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
|
||||
using namespace swift::sys;
|
||||
using llvm::StringRef;
|
||||
|
||||
namespace {
|
||||
struct DefaultCacheKey {
|
||||
void *Key = nullptr;
|
||||
CacheImpl::CallBacks *CBs = nullptr;
|
||||
|
||||
//DefaultCacheKey() = default;
|
||||
DefaultCacheKey(void *Key, CacheImpl::CallBacks *CBs) : Key(Key), CBs(CBs) {}
|
||||
};
|
||||
|
||||
struct DefaultCache {
|
||||
llvm::sys::Mutex Mux;
|
||||
CacheImpl::CallBacks CBs;
|
||||
llvm::DenseMap<DefaultCacheKey, void *> Entries;
|
||||
|
||||
explicit DefaultCache(CacheImpl::CallBacks CBs) : CBs(std::move(CBs)) { }
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
namespace llvm {
|
||||
template<> struct DenseMapInfo<DefaultCacheKey> {
|
||||
static inline DefaultCacheKey getEmptyKey() {
|
||||
return { DenseMapInfo<void*>::getEmptyKey(), nullptr };
|
||||
}
|
||||
static inline DefaultCacheKey getTombstoneKey() {
|
||||
return { DenseMapInfo<void*>::getTombstoneKey(), nullptr };
|
||||
}
|
||||
static unsigned getHashValue(const DefaultCacheKey &Val) {
|
||||
uintptr_t Hash = Val.CBs->keyHashCB(Val.Key, nullptr);
|
||||
return DenseMapInfo<uintptr_t>::getHashValue(Hash);
|
||||
}
|
||||
static bool isEqual(const DefaultCacheKey &LHS, const DefaultCacheKey &RHS) {
|
||||
if (LHS.Key == RHS.Key)
|
||||
return true;
|
||||
if (LHS.Key == DenseMapInfo<void*>::getEmptyKey() ||
|
||||
LHS.Key == DenseMapInfo<void*>::getTombstoneKey() ||
|
||||
RHS.Key == DenseMapInfo<void*>::getEmptyKey() ||
|
||||
RHS.Key == DenseMapInfo<void*>::getTombstoneKey())
|
||||
return false;
|
||||
return LHS.CBs->keyIsEqualCB(LHS.Key, RHS.Key, nullptr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CacheImpl::ImplTy CacheImpl::create(StringRef Name, const CallBacks &CBs) {
|
||||
return new DefaultCache(CBs);
|
||||
}
|
||||
|
||||
void CacheImpl::setAndRetain(void *Key, void *Value, size_t Cost) {
|
||||
DefaultCache &DCache = *static_cast<DefaultCache*>(Impl);
|
||||
llvm::sys::ScopedLock L(DCache.Mux);
|
||||
|
||||
DefaultCacheKey CKey(Key, &DCache.CBs);
|
||||
auto Entry = DCache.Entries.find(CKey);
|
||||
if (Entry != DCache.Entries.end()) {
|
||||
DCache.CBs.keyDestroyCB(Entry->first.Key, nullptr);
|
||||
DCache.CBs.valueDestroyCB(Entry->second, nullptr);
|
||||
DCache.Entries.erase(Entry);
|
||||
}
|
||||
|
||||
DCache.Entries[CKey] = Value;
|
||||
|
||||
// FIXME: Not thread-safe! It should avoid deleting the value until
|
||||
// 'releaseValue is called on it.
|
||||
}
|
||||
|
||||
bool CacheImpl::getAndRetain(const void *Key, void **Value_out) {
|
||||
DefaultCache &DCache = *static_cast<DefaultCache*>(Impl);
|
||||
llvm::sys::ScopedLock L(DCache.Mux);
|
||||
|
||||
DefaultCacheKey CKey(const_cast<void*>(Key), &DCache.CBs);
|
||||
auto Entry = DCache.Entries.find(CKey);
|
||||
if (Entry != DCache.Entries.end()) {
|
||||
// FIXME: Not thread-safe! It should avoid deleting the value until
|
||||
// 'releaseValue is called on it.
|
||||
*Value_out = Entry->second;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CacheImpl::releaseValue(void *Value) {
|
||||
// FIXME: Implementation.
|
||||
}
|
||||
|
||||
bool CacheImpl::remove(const void *Key) {
|
||||
DefaultCache &DCache = *static_cast<DefaultCache*>(Impl);
|
||||
llvm::sys::ScopedLock L(DCache.Mux);
|
||||
|
||||
DefaultCacheKey CKey(const_cast<void*>(Key), &DCache.CBs);
|
||||
auto Entry = DCache.Entries.find(CKey);
|
||||
if (Entry != DCache.Entries.end()) {
|
||||
DCache.CBs.keyDestroyCB(Entry->first.Key, nullptr);
|
||||
DCache.CBs.valueDestroyCB(Entry->second, nullptr);
|
||||
DCache.Entries.erase(Entry);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CacheImpl::removeAll() {
|
||||
DefaultCache &DCache = *static_cast<DefaultCache*>(Impl);
|
||||
llvm::sys::ScopedLock L(DCache.Mux);
|
||||
|
||||
for (auto Entry : DCache.Entries) {
|
||||
DCache.CBs.keyDestroyCB(Entry.first.Key, nullptr);
|
||||
DCache.CBs.valueDestroyCB(Entry.second, nullptr);
|
||||
}
|
||||
DCache.Entries.clear();
|
||||
}
|
||||
|
||||
void CacheImpl::destroy() {
|
||||
removeAll();
|
||||
delete static_cast<DefaultCache*>(Impl);
|
||||
}
|
||||
|
||||
#endif // finish default implementation
|
||||
Reference in New Issue
Block a user