1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
//===--- 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.inc"
#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);
}
};
} // 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<DefaultCache*>(Impl);
llvm::sys::ScopedLock L(DCache.Mux);
DefaultCacheKey CKey(Key, &DCache.CBs);
auto Entry = DCache.Entries.find(CKey);
// If there is no existing entry, retain the value and insert the entry.
if (Entry == DCache.Entries.end()) {
DCache.CBs.valueRetainCB(Value, nullptr);
DCache.Entries[CKey] = Value;
return;
}
// If there is an existing entry, the original key and the new key are ==.
// Swap the new key into the map and destroy the original key.
std::swap(Entry->first.Key, Key);
DCache.CBs.keyDestroyCB(Key, nullptr);
// Replace the value, if necessary.
if (Entry->second != Value) {
DCache.CBs.valueRetainCB(Value, nullptr);
std::swap(Entry->second, Value);
DCache.CBs.valueReleaseCB(Value, nullptr);
}
// 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.valueReleaseCB(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.valueReleaseCB(Entry.second, nullptr);
}
DCache.Entries.clear();
}
void CacheImpl::destroy() {
removeAll();
delete static_cast<DefaultCache*>(Impl);
}
#endif // finish default implementation
|