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