//===--- Cache.cpp - Caching mechanism implementation ---------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://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 Entries; explicit DefaultCache(CacheImpl::CallBacks CBs) : CBs(std::move(CBs)) { } }; } // end anonymous namespace namespace llvm { template<> struct DenseMapInfo { static inline DefaultCacheKey getEmptyKey() { return { DenseMapInfo::getEmptyKey(), nullptr }; } static inline DefaultCacheKey getTombstoneKey() { return { DenseMapInfo::getTombstoneKey(), nullptr }; } static unsigned getHashValue(const DefaultCacheKey &Val) { uintptr_t Hash = Val.CBs->keyHashCB(Val.Key, nullptr); return DenseMapInfo::getHashValue(Hash); } static bool isEqual(const DefaultCacheKey &LHS, const DefaultCacheKey &RHS) { if (LHS.Key == RHS.Key) return true; if (LHS.Key == DenseMapInfo::getEmptyKey() || LHS.Key == DenseMapInfo::getTombstoneKey() || RHS.Key == DenseMapInfo::getEmptyKey() || RHS.Key == DenseMapInfo::getTombstoneKey()) return false; return LHS.CBs->keyIsEqualCB(LHS.Key, RHS.Key, nullptr); } }; } // namespace llvm 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(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(Impl); llvm::sys::ScopedLock L(DCache.Mux); DefaultCacheKey CKey(const_cast(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(Impl); llvm::sys::ScopedLock L(DCache.Mux); DefaultCacheKey CKey(const_cast(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(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(Impl); } #endif // finish default implementation