OLD | NEW |
| (Empty) |
1 // Copyright 2013 the V8 project authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #ifndef V8_UNIQUE_H_ | |
6 #define V8_UNIQUE_H_ | |
7 | |
8 #include <ostream> // NOLINT(readability/streams) | |
9 | |
10 #include "src/base/functional.h" | |
11 #include "src/handles.h" | |
12 #include "src/utils.h" | |
13 #include "src/zone.h" | |
14 | |
15 namespace v8 { | |
16 namespace internal { | |
17 | |
18 | |
19 template <typename T> | |
20 class UniqueSet; | |
21 | |
22 | |
23 // Represents a handle to an object on the heap, but with the additional | |
24 // ability of checking for equality and hashing without accessing the heap. | |
25 // | |
26 // Creating a Unique<T> requires first dereferencing the handle to obtain | |
27 // the address of the object, which is used as the hashcode and the basis for | |
28 // comparison. The object can be moved later by the GC, but comparison | |
29 // and hashing use the old address of the object, without dereferencing it. | |
30 // | |
31 // Careful! Comparison of two Uniques is only correct if both were created | |
32 // in the same "era" of GC or if at least one is a non-movable object. | |
33 template <typename T> | |
34 class Unique final { | |
35 public: | |
36 Unique<T>() : raw_address_(NULL) {} | |
37 | |
38 // TODO(titzer): make private and introduce a uniqueness scope. | |
39 explicit Unique(Handle<T> handle) { | |
40 if (handle.is_null()) { | |
41 raw_address_ = NULL; | |
42 } else { | |
43 // This is a best-effort check to prevent comparing Unique<T>'s created | |
44 // in different GC eras; we require heap allocation to be disallowed at | |
45 // creation time. | |
46 // NOTE: we currently consider maps to be non-movable, so no special | |
47 // assurance is required for creating a Unique<Map>. | |
48 // TODO(titzer): other immortable immovable objects are also fine. | |
49 DCHECK(!AllowHeapAllocation::IsAllowed() || handle->IsMap()); | |
50 raw_address_ = reinterpret_cast<Address>(*handle); | |
51 DCHECK_NOT_NULL(raw_address_); // Non-null should imply non-zero address. | |
52 } | |
53 handle_ = handle; | |
54 } | |
55 | |
56 // Constructor for handling automatic up casting. | |
57 // Eg. Unique<JSFunction> can be passed when Unique<Object> is expected. | |
58 template <class S> Unique(Unique<S> uniq) { | |
59 #ifdef DEBUG | |
60 T* a = NULL; | |
61 S* b = NULL; | |
62 a = b; // Fake assignment to enforce type checks. | |
63 USE(a); | |
64 #endif | |
65 raw_address_ = uniq.raw_address_; | |
66 handle_ = uniq.handle_; | |
67 } | |
68 | |
69 template <typename U> | |
70 inline bool operator==(const Unique<U>& other) const { | |
71 DCHECK(IsInitialized() && other.IsInitialized()); | |
72 return raw_address_ == other.raw_address_; | |
73 } | |
74 | |
75 template <typename U> | |
76 inline bool operator!=(const Unique<U>& other) const { | |
77 DCHECK(IsInitialized() && other.IsInitialized()); | |
78 return raw_address_ != other.raw_address_; | |
79 } | |
80 | |
81 friend inline size_t hash_value(Unique<T> const& unique) { | |
82 DCHECK(unique.IsInitialized()); | |
83 return base::hash<void*>()(unique.raw_address_); | |
84 } | |
85 | |
86 inline intptr_t Hashcode() const { | |
87 DCHECK(IsInitialized()); | |
88 return reinterpret_cast<intptr_t>(raw_address_); | |
89 } | |
90 | |
91 inline bool IsNull() const { | |
92 DCHECK(IsInitialized()); | |
93 return raw_address_ == NULL; | |
94 } | |
95 | |
96 inline bool IsKnownGlobal(void* global) const { | |
97 DCHECK(IsInitialized()); | |
98 return raw_address_ == reinterpret_cast<Address>(global); | |
99 } | |
100 | |
101 inline Handle<T> handle() const { | |
102 return handle_; | |
103 } | |
104 | |
105 template <class S> static Unique<T> cast(Unique<S> that) { | |
106 // Allow fetching location() to unsafe-cast the handle. This is necessary | |
107 // since we can't concurrently safe-cast. Safe-casting requires looking at | |
108 // the heap which may be moving concurrently to the compiler thread. | |
109 AllowHandleDereference allow_deref; | |
110 return Unique<T>(that.raw_address_, | |
111 Handle<T>(reinterpret_cast<T**>(that.handle_.location()))); | |
112 } | |
113 | |
114 inline bool IsInitialized() const { | |
115 return raw_address_ != NULL || handle_.is_null(); | |
116 } | |
117 | |
118 // TODO(titzer): this is a hack to migrate to Unique<T> incrementally. | |
119 static Unique<T> CreateUninitialized(Handle<T> handle) { | |
120 return Unique<T>(NULL, handle); | |
121 } | |
122 | |
123 static Unique<T> CreateImmovable(Handle<T> handle) { | |
124 return Unique<T>(reinterpret_cast<Address>(*handle), handle); | |
125 } | |
126 | |
127 private: | |
128 Unique(Address raw_address, Handle<T> handle) | |
129 : raw_address_(raw_address), handle_(handle) {} | |
130 | |
131 Address raw_address_; | |
132 Handle<T> handle_; | |
133 | |
134 friend class UniqueSet<T>; // Uses internal details for speed. | |
135 template <class U> | |
136 friend class Unique; // For comparing raw_address values. | |
137 }; | |
138 | |
139 template <typename T> | |
140 inline std::ostream& operator<<(std::ostream& os, Unique<T> uniq) { | |
141 return os << Brief(*uniq.handle()); | |
142 } | |
143 | |
144 | |
145 template <typename T> | |
146 class UniqueSet final : public ZoneObject { | |
147 public: | |
148 // Constructor. A new set will be empty. | |
149 UniqueSet() : size_(0), capacity_(0), array_(NULL) { } | |
150 | |
151 // Capacity constructor. A new set will be empty. | |
152 UniqueSet(int capacity, Zone* zone) | |
153 : size_(0), capacity_(capacity), | |
154 array_(zone->NewArray<Unique<T> >(capacity)) { | |
155 DCHECK(capacity <= kMaxCapacity); | |
156 } | |
157 | |
158 // Singleton constructor. | |
159 UniqueSet(Unique<T> uniq, Zone* zone) | |
160 : size_(1), capacity_(1), array_(zone->NewArray<Unique<T> >(1)) { | |
161 array_[0] = uniq; | |
162 } | |
163 | |
164 // Add a new element to this unique set. Mutates this set. O(|this|). | |
165 void Add(Unique<T> uniq, Zone* zone) { | |
166 DCHECK(uniq.IsInitialized()); | |
167 // Keep the set sorted by the {raw_address} of the unique elements. | |
168 for (int i = 0; i < size_; i++) { | |
169 if (array_[i] == uniq) return; | |
170 if (array_[i].raw_address_ > uniq.raw_address_) { | |
171 // Insert in the middle. | |
172 Grow(size_ + 1, zone); | |
173 for (int j = size_ - 1; j >= i; j--) array_[j + 1] = array_[j]; | |
174 array_[i] = uniq; | |
175 size_++; | |
176 return; | |
177 } | |
178 } | |
179 // Append the element to the the end. | |
180 Grow(size_ + 1, zone); | |
181 array_[size_++] = uniq; | |
182 } | |
183 | |
184 // Remove an element from this set. Mutates this set. O(|this|) | |
185 void Remove(Unique<T> uniq) { | |
186 for (int i = 0; i < size_; i++) { | |
187 if (array_[i] == uniq) { | |
188 while (++i < size_) array_[i - 1] = array_[i]; | |
189 size_--; | |
190 return; | |
191 } | |
192 } | |
193 } | |
194 | |
195 // Compare this set against another set. O(|this|). | |
196 bool Equals(const UniqueSet<T>* that) const { | |
197 if (that->size_ != this->size_) return false; | |
198 for (int i = 0; i < this->size_; i++) { | |
199 if (this->array_[i] != that->array_[i]) return false; | |
200 } | |
201 return true; | |
202 } | |
203 | |
204 // Check whether this set contains the given element. O(|this|) | |
205 // TODO(titzer): use binary search for large sets to make this O(log|this|) | |
206 template <typename U> | |
207 bool Contains(const Unique<U> elem) const { | |
208 for (int i = 0; i < this->size_; ++i) { | |
209 Unique<T> cand = this->array_[i]; | |
210 if (cand.raw_address_ >= elem.raw_address_) { | |
211 return cand.raw_address_ == elem.raw_address_; | |
212 } | |
213 } | |
214 return false; | |
215 } | |
216 | |
217 // Check if this set is a subset of the given set. O(|this| + |that|). | |
218 bool IsSubset(const UniqueSet<T>* that) const { | |
219 if (that->size_ < this->size_) return false; | |
220 int j = 0; | |
221 for (int i = 0; i < this->size_; i++) { | |
222 Unique<T> sought = this->array_[i]; | |
223 while (true) { | |
224 if (sought == that->array_[j++]) break; | |
225 // Fail whenever there are more elements in {this} than {that}. | |
226 if ((this->size_ - i) > (that->size_ - j)) return false; | |
227 } | |
228 } | |
229 return true; | |
230 } | |
231 | |
232 // Returns a new set representing the intersection of this set and the other. | |
233 // O(|this| + |that|). | |
234 UniqueSet<T>* Intersect(const UniqueSet<T>* that, Zone* zone) const { | |
235 if (that->size_ == 0 || this->size_ == 0) return new(zone) UniqueSet<T>(); | |
236 | |
237 UniqueSet<T>* out = new(zone) UniqueSet<T>( | |
238 Min(this->size_, that->size_), zone); | |
239 | |
240 int i = 0, j = 0, k = 0; | |
241 while (i < this->size_ && j < that->size_) { | |
242 Unique<T> a = this->array_[i]; | |
243 Unique<T> b = that->array_[j]; | |
244 if (a == b) { | |
245 out->array_[k++] = a; | |
246 i++; | |
247 j++; | |
248 } else if (a.raw_address_ < b.raw_address_) { | |
249 i++; | |
250 } else { | |
251 j++; | |
252 } | |
253 } | |
254 | |
255 out->size_ = k; | |
256 return out; | |
257 } | |
258 | |
259 // Returns a new set representing the union of this set and the other. | |
260 // O(|this| + |that|). | |
261 UniqueSet<T>* Union(const UniqueSet<T>* that, Zone* zone) const { | |
262 if (that->size_ == 0) return this->Copy(zone); | |
263 if (this->size_ == 0) return that->Copy(zone); | |
264 | |
265 UniqueSet<T>* out = new(zone) UniqueSet<T>( | |
266 this->size_ + that->size_, zone); | |
267 | |
268 int i = 0, j = 0, k = 0; | |
269 while (i < this->size_ && j < that->size_) { | |
270 Unique<T> a = this->array_[i]; | |
271 Unique<T> b = that->array_[j]; | |
272 if (a == b) { | |
273 out->array_[k++] = a; | |
274 i++; | |
275 j++; | |
276 } else if (a.raw_address_ < b.raw_address_) { | |
277 out->array_[k++] = a; | |
278 i++; | |
279 } else { | |
280 out->array_[k++] = b; | |
281 j++; | |
282 } | |
283 } | |
284 | |
285 while (i < this->size_) out->array_[k++] = this->array_[i++]; | |
286 while (j < that->size_) out->array_[k++] = that->array_[j++]; | |
287 | |
288 out->size_ = k; | |
289 return out; | |
290 } | |
291 | |
292 // Returns a new set representing all elements from this set which are not in | |
293 // that set. O(|this| * |that|). | |
294 UniqueSet<T>* Subtract(const UniqueSet<T>* that, Zone* zone) const { | |
295 if (that->size_ == 0) return this->Copy(zone); | |
296 | |
297 UniqueSet<T>* out = new(zone) UniqueSet<T>(this->size_, zone); | |
298 | |
299 int i = 0, j = 0; | |
300 while (i < this->size_) { | |
301 Unique<T> cand = this->array_[i]; | |
302 if (!that->Contains(cand)) { | |
303 out->array_[j++] = cand; | |
304 } | |
305 i++; | |
306 } | |
307 | |
308 out->size_ = j; | |
309 return out; | |
310 } | |
311 | |
312 // Makes an exact copy of this set. O(|this|). | |
313 UniqueSet<T>* Copy(Zone* zone) const { | |
314 UniqueSet<T>* copy = new(zone) UniqueSet<T>(this->size_, zone); | |
315 copy->size_ = this->size_; | |
316 memcpy(copy->array_, this->array_, this->size_ * sizeof(Unique<T>)); | |
317 return copy; | |
318 } | |
319 | |
320 void Clear() { | |
321 size_ = 0; | |
322 } | |
323 | |
324 inline int size() const { | |
325 return size_; | |
326 } | |
327 | |
328 inline Unique<T> at(int index) const { | |
329 DCHECK(index >= 0 && index < size_); | |
330 return array_[index]; | |
331 } | |
332 | |
333 private: | |
334 // These sets should be small, since operations are implemented with simple | |
335 // linear algorithms. Enforce a maximum size. | |
336 static const int kMaxCapacity = 65535; | |
337 | |
338 uint16_t size_; | |
339 uint16_t capacity_; | |
340 Unique<T>* array_; | |
341 | |
342 // Grow the size of internal storage to be at least {size} elements. | |
343 void Grow(int size, Zone* zone) { | |
344 CHECK(size < kMaxCapacity); // Enforce maximum size. | |
345 if (capacity_ < size) { | |
346 int new_capacity = 2 * capacity_ + size; | |
347 if (new_capacity > kMaxCapacity) new_capacity = kMaxCapacity; | |
348 Unique<T>* new_array = zone->NewArray<Unique<T> >(new_capacity); | |
349 if (size_ > 0) { | |
350 memcpy(new_array, array_, size_ * sizeof(Unique<T>)); | |
351 } | |
352 capacity_ = new_capacity; | |
353 array_ = new_array; | |
354 } | |
355 } | |
356 }; | |
357 | |
358 } // namespace internal | |
359 } // namespace v8 | |
360 | |
361 #endif // V8_UNIQUE_H_ | |
OLD | NEW |