1+ // ===--- RequestCache.h - Per-request caching ----------------- -*- C++ -*-===//
2+ //
3+ // This source file is part of the Swift.org open source project
4+ //
5+ // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+ // Licensed under Apache License v2.0 with Runtime Library Exception
7+ //
8+ // See https://swift.org/LICENSE.txt for license information
9+ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+ //
11+ // ===----------------------------------------------------------------------===//
12+ //
13+ // This file defines data structures to efficiently support the request
14+ // evaluator's request caching.
15+ //
16+ // ===----------------------------------------------------------------------===//
17+
18+ #include " llvm/ADT/DenseMap.h"
19+ #include " llvm/ADT/StringRef.h"
20+
21+ #ifndef SWIFT_AST_REQUEST_CACHE_H
22+ #define SWIFT_AST_REQUEST_CACHE_H
23+
24+ namespace swift {
25+
26+ namespace evaluator {
27+
28+ namespace detail {
29+
30+ // Remove this when the compiler bumps to C++17.
31+ template <typename ...> using void_t = void ;
32+ template <typename T, typename = void_t <>>
33+
34+ struct TupleHasDenseMapInfo {};
35+
36+ template <typename ... Ts>
37+ struct TupleHasDenseMapInfo <
38+ std::tuple<Ts...>,
39+ void_t <decltype (llvm::DenseMapInfo<Ts>::getEmptyKey)...>> {
40+ using type = void_t <>;
41+ };
42+
43+ } // end namespace detail
44+
45+ namespace {
46+
47+ // / Wrapper for a request with additional empty and tombstone states.
48+ template <typename Request, typename = detail::void_t <>>
49+ class RequestKey {
50+ friend struct llvm ::DenseMapInfo<RequestKey>;
51+ union {
52+ char Empty;
53+ Request Req;
54+ };
55+
56+ enum class StorageKind : uint8_t {
57+ Normal, Empty, Tombstone
58+ };
59+ StorageKind Kind;
60+
61+ static RequestKey getEmpty () {
62+ return RequestKey (StorageKind::Empty);
63+ }
64+ static RequestKey getTombstone () {
65+ return RequestKey (StorageKind::Tombstone);
66+ }
67+
68+ RequestKey (StorageKind kind) : Empty(), Kind(kind) {
69+ assert (kind != StorageKind::Normal);
70+ }
71+
72+ public:
73+ explicit RequestKey (Request req)
74+ : Req(std::move(req)), Kind(StorageKind::Normal) {}
75+
76+ RequestKey (const RequestKey &other) : Empty(), Kind(other.Kind) {
77+ if (Kind == StorageKind::Normal)
78+ new (&Req) Request (other.Req );
79+ }
80+ RequestKey (RequestKey &&other) : Empty(), Kind(other.Kind) {
81+ if (Kind == StorageKind::Normal)
82+ new (&Req) Request (std::move (other.Req ));
83+ }
84+ RequestKey &operator =(const RequestKey &other) {
85+ if (&other != this ) {
86+ this ->~RequestKey ();
87+ new (this ) RequestKey (other);
88+ }
89+ return *this ;
90+ }
91+ RequestKey &operator =(RequestKey &&other) {
92+ if (&other != this ) {
93+ this ->~RequestKey ();
94+ new (this ) RequestKey (std::move (other));
95+ }
96+ return *this ;
97+ }
98+
99+ ~RequestKey () {
100+ if (Kind == StorageKind::Normal)
101+ Req.~Request ();
102+ }
103+
104+ bool isStorageEqual (const Request &req) const {
105+ if (Kind != StorageKind::Normal)
106+ return false ;
107+ return Req == req;
108+ }
109+ friend bool operator ==(const RequestKey &lhs, const RequestKey &rhs) {
110+ if (lhs.Kind == StorageKind::Normal && rhs.Kind == StorageKind::Normal) {
111+ return lhs.Req == rhs.Req ;
112+ } else {
113+ return lhs.Kind == rhs.Kind ;
114+ }
115+ }
116+ friend bool operator !=(const RequestKey &lhs, const RequestKey &rhs) {
117+ return !(lhs == rhs);
118+ }
119+ friend llvm::hash_code hash_value (const RequestKey &key) {
120+ if (key.Kind != StorageKind::Normal)
121+ return 1 ;
122+ return hash_value (key.Req );
123+ }
124+ };
125+
126+ template <typename Request>
127+ class RequestKey <Request, typename detail::TupleHasDenseMapInfo<
128+ typename Request::Storage>::type> {
129+ friend struct llvm ::DenseMapInfo<RequestKey>;
130+ using Info = llvm::DenseMapInfo<typename Request::Storage>;
131+
132+ Request Req;
133+
134+ static RequestKey getEmpty () {
135+ return RequestKey (Request (Info::getEmptyKey ()));
136+ }
137+ static RequestKey getTombstone () {
138+ return RequestKey (Request (Info::getTombstoneKey ()));
139+ }
140+
141+ public:
142+ explicit RequestKey (Request req) : Req(std::move(req)) {}
143+
144+ bool isStorageEqual (const Request &req) const {
145+ return Req == req;
146+ }
147+ friend bool operator ==(const RequestKey &lhs, const RequestKey &rhs) {
148+ return lhs.Req == rhs.Req ;
149+ }
150+ friend bool operator !=(const RequestKey &lhs, const RequestKey &rhs) {
151+ return !(lhs == rhs);
152+ }
153+ friend llvm::hash_code hash_value (const RequestKey &key) {
154+ return hash_value (key.Req );
155+ }
156+ };
157+
158+ } // end namespace
159+
160+ // / Type-erased wrapper for caching results of a single type of request.
161+ class PerRequestCache {
162+ void *Storage;
163+ std::function<void (void *)> Deleter;
164+
165+ PerRequestCache (void *storage, std::function<void (void *)> deleter)
166+ : Storage(storage), Deleter(deleter) {}
167+
168+ public:
169+ PerRequestCache () : Storage(nullptr ), Deleter([](void *) {}) {}
170+ PerRequestCache (PerRequestCache &&other)
171+ : Storage(other.Storage), Deleter(std::move(other.Deleter)) {
172+ other.Storage = nullptr ;
173+ }
174+
175+ PerRequestCache &operator =(PerRequestCache &&other) {
176+ if (&other != this ) {
177+ this ->~PerRequestCache ();
178+ new (this ) PerRequestCache (std::move (other));
179+ }
180+ return *this ;
181+ }
182+
183+ PerRequestCache (const PerRequestCache &) = delete ;
184+ PerRequestCache &operator =(const PerRequestCache &) = delete ;
185+
186+ template <typename Request>
187+ static PerRequestCache makeEmpty () {
188+ using Map =
189+ llvm::DenseMap<RequestKey<Request>,
190+ typename Request::OutputType>;
191+ return PerRequestCache (new Map (),
192+ [](void *ptr) { delete static_cast <Map *>(ptr); });
193+ }
194+
195+ template <typename Request>
196+ llvm::DenseMap<RequestKey<Request>,
197+ typename Request::OutputType> *
198+ get () const {
199+ using Map =
200+ llvm::DenseMap<RequestKey<Request>,
201+ typename Request::OutputType>;
202+ assert (Storage);
203+ return static_cast <Map *>(Storage);
204+ }
205+
206+ bool isNull () const { return !Storage; }
207+ ~PerRequestCache () {
208+ if (Storage)
209+ Deleter (Storage);
210+ }
211+ };
212+
213+ // / Data structure for caching results of requests. Sharded by the type ID
214+ // / zone and request kind, with a PerRequestCache for each request kind.
215+ // /
216+ // / Conceptually equivalent to DenseMap<AnyRequest, AnyValue>, but without
217+ // / type erasure overhead for keys and values.
218+ class RequestCache {
219+
220+ #define SWIFT_TYPEID_ZONE (Name, Id ) \
221+ std::vector<PerRequestCache> Name##ZoneCache; \
222+ \
223+ template < \
224+ typename Request, typename ZoneTypes = TypeIDZoneTypes<Zone::Name>, \
225+ typename std::enable_if<TypeID<Request>::zone == Zone::Name>::type * = \
226+ nullptr > \
227+ llvm::DenseMap<RequestKey<Request>, \
228+ typename Request::OutputType> * \
229+ getCache () { \
230+ auto &caches = Name##ZoneCache; \
231+ if (caches.empty ()) { \
232+ caches.resize (ZoneTypes::Count); \
233+ } \
234+ auto idx = TypeID<Request>::localID; \
235+ if (caches[idx].isNull ()) { \
236+ caches[idx] = PerRequestCache::makeEmpty<Request>(); \
237+ } \
238+ return caches[idx].template get <Request>(); \
239+ }
240+ #include " swift/Basic/TypeIDZones.def"
241+ #undef SWIFT_TYPEID_ZONE
242+
243+ public:
244+ template <typename Request>
245+ typename llvm::DenseMap<RequestKey<Request>,
246+ typename Request::OutputType>::const_iterator
247+ find_as (const Request &req) {
248+ auto *cache = getCache<Request>();
249+ return cache->find_as (req);
250+ }
251+
252+ template <typename Request>
253+ typename llvm::DenseMap<RequestKey<Request>,
254+ typename Request::OutputType>::const_iterator
255+ end () {
256+ auto *cache = getCache<Request>();
257+ return cache->end ();
258+ }
259+
260+ template <typename Request>
261+ void insert (Request req, typename Request::OutputType val) {
262+ auto *cache = getCache<Request>();
263+ auto result = cache->insert ({RequestKey<Request>(std::move (req)),
264+ std::move (val)});
265+ assert (result.second && " Request result was already cached" );
266+ (void ) result;
267+ }
268+
269+ template <typename Request>
270+ void erase (Request req) {
271+ auto *cache = getCache<Request>();
272+ cache->erase (RequestKey<Request>(std::move (req)));
273+ }
274+
275+ void clear () {
276+ #define SWIFT_TYPEID_ZONE (Name, Id ) Name##ZoneCache.clear();
277+ #include " swift/Basic/TypeIDZones.def"
278+ #undef SWIFT_TYPEID_ZONE
279+ }
280+ };
281+
282+ } // end namespace evaluator
283+
284+ } // end namespace swift
285+
286+ namespace llvm {
287+
288+ template <typename Request, typename Info>
289+ struct DenseMapInfo <swift::evaluator::RequestKey<Request, Info>> {
290+ using RequestKey = swift::evaluator::RequestKey<Request, Info>;
291+ static inline RequestKey getEmptyKey () {
292+ return RequestKey::getEmpty ();
293+ }
294+ static inline RequestKey getTombstoneKey () {
295+ return RequestKey::getTombstone ();
296+ }
297+ static unsigned getHashValue (const RequestKey &key) {
298+ return hash_value (key);
299+ }
300+ static unsigned getHashValue (const Request &request) {
301+ return hash_value (request);
302+ }
303+ static bool isEqual (const RequestKey &lhs, const RequestKey &rhs) {
304+ return lhs == rhs;
305+ }
306+ static bool isEqual (const Request &lhs, const RequestKey &rhs) {
307+ return rhs.isStorageEqual (lhs);
308+ }
309+ };
310+
311+ } // end namespace llvm
312+
313+ #endif // SWIFT_AST_REQUEST_CACHE_H
0 commit comments