blob: a2f29e433535f33bbb9db08dec02de672f783941 [file] [log] [blame]
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_HYDROGEN_UNIQUE_H_
29#define V8_HYDROGEN_UNIQUE_H_
30
31#include "handles.h"
machenbach@chromium.org528ce022013-09-23 14:09:36 +000032#include "objects.h"
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000033#include "utils.h"
34#include "zone.h"
35
36namespace v8 {
37namespace internal {
38
39
40template <typename T>
41class UniqueSet;
42
43
44// Represents a handle to an object on the heap, but with the additional
45// ability of checking for equality and hashing without accessing the heap.
46//
47// Creating a Unique<T> requires first dereferencing the handle to obtain
48// the address of the object, which is used as the hashcode and the basis for
49// comparison. The object can be moved later by the GC, but comparison
50// and hashing use the old address of the object, without dereferencing it.
51//
52// Careful! Comparison of two Uniques is only correct if both were created
53// in the same "era" of GC or if at least one is a non-movable object.
54template <typename T>
55class Unique V8_FINAL {
56 public:
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +000057 // TODO(titzer): make private and introduce a uniqueness scope.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000058 explicit Unique(Handle<T> handle) {
59 if (handle.is_null()) {
60 raw_address_ = NULL;
61 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000062 // This is a best-effort check to prevent comparing Unique<T>'s created
63 // in different GC eras; we require heap allocation to be disallowed at
64 // creation time.
65 // NOTE: we currently consider maps to be non-movable, so no special
66 // assurance is required for creating a Unique<Map>.
67 // TODO(titzer): other immortable immovable objects are also fine.
68 ASSERT(!AllowHeapAllocation::IsAllowed() || handle->IsMap());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000069 raw_address_ = reinterpret_cast<Address>(*handle);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000070 ASSERT_NE(raw_address_, NULL); // Non-null should imply non-zero address.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000071 }
72 handle_ = handle;
73 }
74
machenbach@chromium.org528ce022013-09-23 14:09:36 +000075 // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
76 Unique(Address raw_address, Handle<T> handle)
77 : raw_address_(raw_address), handle_(handle) { }
78
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000079 // Constructor for handling automatic up casting.
machenbach@chromium.org528ce022013-09-23 14:09:36 +000080 // Eg. Unique<JSFunction> can be passed when Unique<Object> is expected.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000081 template <class S> Unique(Unique<S> uniq) {
82#ifdef DEBUG
83 T* a = NULL;
84 S* b = NULL;
85 a = b; // Fake assignment to enforce type checks.
86 USE(a);
87#endif
88 raw_address_ = uniq.raw_address_;
machenbach@chromium.org528ce022013-09-23 14:09:36 +000089 handle_ = uniq.handle_;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000090 }
91
92 template <typename U>
machenbach@chromium.org528ce022013-09-23 14:09:36 +000093 inline bool operator==(const Unique<U>& other) const {
94 ASSERT(IsInitialized() && other.IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000095 return raw_address_ == other.raw_address_;
96 }
97
98 template <typename U>
machenbach@chromium.org528ce022013-09-23 14:09:36 +000099 inline bool operator!=(const Unique<U>& other) const {
100 ASSERT(IsInitialized() && other.IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000101 return raw_address_ != other.raw_address_;
102 }
103
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000104 inline intptr_t Hashcode() const {
105 ASSERT(IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000106 return reinterpret_cast<intptr_t>(raw_address_);
107 }
108
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000109 inline bool IsNull() const {
110 ASSERT(IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000111 return raw_address_ == NULL;
112 }
113
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000114 inline bool IsKnownGlobal(void* global) const {
115 ASSERT(IsInitialized());
116 return raw_address_ == reinterpret_cast<Address>(global);
117 }
118
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000119 inline Handle<T> handle() const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000120 return handle_;
121 }
122
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000123 template <class S> static Unique<T> cast(Unique<S> that) {
124 return Unique<T>(that.raw_address_, Handle<T>::cast(that.handle_));
125 }
126
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000127 inline bool IsInitialized() const {
128 return raw_address_ != NULL || handle_.is_null();
129 }
130
131 // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
132 static Unique<T> CreateUninitialized(Handle<T> handle) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000133 return Unique<T>(reinterpret_cast<Address>(NULL), handle);
134 }
135
136 static Unique<T> CreateImmovable(Handle<T> handle) {
137 return Unique<T>(reinterpret_cast<Address>(*handle), handle);
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000138 }
139
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000140 friend class UniqueSet<T>; // Uses internal details for speed.
141 template <class U>
142 friend class Unique; // For comparing raw_address values.
143
144 private:
145 Address raw_address_;
146 Handle<T> handle_;
147};
148
149
150template <typename T>
151class UniqueSet V8_FINAL : public ZoneObject {
152 public:
153 // Constructor. A new set will be empty.
154 UniqueSet() : size_(0), capacity_(0), array_(NULL) { }
155
156 // Add a new element to this unique set. Mutates this set. O(|this|).
157 void Add(Unique<T> uniq, Zone* zone) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000158 ASSERT(uniq.IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000159 // Keep the set sorted by the {raw_address} of the unique elements.
160 for (int i = 0; i < size_; i++) {
161 if (array_[i] == uniq) return;
162 if (array_[i].raw_address_ > uniq.raw_address_) {
163 // Insert in the middle.
164 Grow(size_ + 1, zone);
165 for (int j = size_ - 1; j >= i; j--) array_[j + 1] = array_[j];
166 array_[i] = uniq;
167 size_++;
168 return;
169 }
170 }
171 // Append the element to the the end.
172 Grow(size_ + 1, zone);
173 array_[size_++] = uniq;
174 }
175
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000176 // Remove an element from this set. Mutates this set. O(|this|)
177 void Remove(Unique<T> uniq) {
178 for (int i = 0; i < size_; i++) {
179 if (array_[i] == uniq) {
180 while (++i < size_) array_[i - 1] = array_[i];
181 size_--;
182 return;
183 }
184 }
185 }
186
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000187 // Compare this set against another set. O(|this|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000188 bool Equals(UniqueSet<T>* that) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000189 if (that->size_ != this->size_) return false;
190 for (int i = 0; i < this->size_; i++) {
191 if (this->array_[i] != that->array_[i]) return false;
192 }
193 return true;
194 }
195
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000196 // Check whether this set contains the given element. O(|this|)
197 // TODO(titzer): use binary search for large sets to make this O(log|this|)
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000198 template <typename U>
199 bool Contains(Unique<U> elem) const {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000200 for (int i = 0; i < size_; i++) {
201 if (this->array_[i] == elem) return true;
202 }
203 return false;
204 }
205
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000206 // Check if this set is a subset of the given set. O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000207 bool IsSubset(UniqueSet<T>* that) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000208 if (that->size_ < this->size_) return false;
209 int j = 0;
210 for (int i = 0; i < this->size_; i++) {
211 Unique<T> sought = this->array_[i];
212 while (true) {
213 if (sought == that->array_[j++]) break;
214 // Fail whenever there are more elements in {this} than {that}.
215 if ((this->size_ - i) > (that->size_ - j)) return false;
216 }
217 }
218 return true;
219 }
220
221 // Returns a new set representing the intersection of this set and the other.
222 // O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000223 UniqueSet<T>* Intersect(UniqueSet<T>* that, Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000224 if (that->size_ == 0 || this->size_ == 0) return new(zone) UniqueSet<T>();
225
226 UniqueSet<T>* out = new(zone) UniqueSet<T>();
227 out->Grow(Min(this->size_, that->size_), zone);
228
229 int i = 0, j = 0, k = 0;
230 while (i < this->size_ && j < that->size_) {
231 Unique<T> a = this->array_[i];
232 Unique<T> b = that->array_[j];
233 if (a == b) {
234 out->array_[k++] = a;
235 i++;
236 j++;
237 } else if (a.raw_address_ < b.raw_address_) {
238 i++;
239 } else {
240 j++;
241 }
242 }
243
244 out->size_ = k;
245 return out;
246 }
247
248 // Returns a new set representing the union of this set and the other.
249 // O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000250 UniqueSet<T>* Union(UniqueSet<T>* that, Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000251 if (that->size_ == 0) return this->Copy(zone);
252 if (this->size_ == 0) return that->Copy(zone);
253
254 UniqueSet<T>* out = new(zone) UniqueSet<T>();
255 out->Grow(this->size_ + that->size_, zone);
256
257 int i = 0, j = 0, k = 0;
258 while (i < this->size_ && j < that->size_) {
259 Unique<T> a = this->array_[i];
260 Unique<T> b = that->array_[j];
261 if (a == b) {
262 out->array_[k++] = a;
263 i++;
264 j++;
265 } else if (a.raw_address_ < b.raw_address_) {
266 out->array_[k++] = a;
267 i++;
268 } else {
269 out->array_[k++] = b;
270 j++;
271 }
272 }
273
274 while (i < this->size_) out->array_[k++] = this->array_[i++];
275 while (j < that->size_) out->array_[k++] = that->array_[j++];
276
277 out->size_ = k;
278 return out;
279 }
280
hpayer@chromium.orgea9b8ba2013-12-20 19:22:39 +0000281 // Makes an exact copy of this set. O(|this|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000282 UniqueSet<T>* Copy(Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000283 UniqueSet<T>* copy = new(zone) UniqueSet<T>();
284 copy->size_ = this->size_;
285 copy->capacity_ = this->size_;
286 copy->array_ = zone->NewArray<Unique<T> >(this->size_);
287 memcpy(copy->array_, this->array_, this->size_ * sizeof(Unique<T>));
288 return copy;
289 }
290
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000291 void Clear() {
292 size_ = 0;
293 }
294
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000295 inline int size() const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000296 return size_;
297 }
298
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000299 inline Unique<T> at(int index) const {
300 ASSERT(index >= 0 && index < size_);
301 return array_[index];
302 }
303
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000304 private:
305 // These sets should be small, since operations are implemented with simple
306 // linear algorithms. Enforce a maximum size.
307 static const int kMaxCapacity = 65535;
308
309 uint16_t size_;
310 uint16_t capacity_;
311 Unique<T>* array_;
312
313 // Grow the size of internal storage to be at least {size} elements.
314 void Grow(int size, Zone* zone) {
315 CHECK(size < kMaxCapacity); // Enforce maximum size.
316 if (capacity_ < size) {
317 int new_capacity = 2 * capacity_ + size;
318 if (new_capacity > kMaxCapacity) new_capacity = kMaxCapacity;
319 Unique<T>* new_array = zone->NewArray<Unique<T> >(new_capacity);
320 if (size_ > 0) {
321 memcpy(new_array, array_, size_ * sizeof(Unique<T>));
322 }
323 capacity_ = new_capacity;
324 array_ = new_array;
325 }
326 }
327};
328
329
330} } // namespace v8::internal
331
332#endif // V8_HYDROGEN_UNIQUE_H_