blob: 2f6008c5a2b007a3f763c8849be06223ea988c81 [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:
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +0000145 Unique<T>() : raw_address_(NULL) { }
146
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000147 Address raw_address_;
148 Handle<T> handle_;
machenbach@chromium.orgca2f2042014-03-10 10:03:12 +0000149
150 friend class SideEffectsTracker;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000151};
152
153
154template <typename T>
155class UniqueSet V8_FINAL : public ZoneObject {
156 public:
157 // Constructor. A new set will be empty.
158 UniqueSet() : size_(0), capacity_(0), array_(NULL) { }
159
160 // Add a new element to this unique set. Mutates this set. O(|this|).
161 void Add(Unique<T> uniq, Zone* zone) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000162 ASSERT(uniq.IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000163 // Keep the set sorted by the {raw_address} of the unique elements.
164 for (int i = 0; i < size_; i++) {
165 if (array_[i] == uniq) return;
166 if (array_[i].raw_address_ > uniq.raw_address_) {
167 // Insert in the middle.
168 Grow(size_ + 1, zone);
169 for (int j = size_ - 1; j >= i; j--) array_[j + 1] = array_[j];
170 array_[i] = uniq;
171 size_++;
172 return;
173 }
174 }
175 // Append the element to the the end.
176 Grow(size_ + 1, zone);
177 array_[size_++] = uniq;
178 }
179
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000180 // Remove an element from this set. Mutates this set. O(|this|)
181 void Remove(Unique<T> uniq) {
182 for (int i = 0; i < size_; i++) {
183 if (array_[i] == uniq) {
184 while (++i < size_) array_[i - 1] = array_[i];
185 size_--;
186 return;
187 }
188 }
189 }
190
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000191 // Compare this set against another set. O(|this|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000192 bool Equals(UniqueSet<T>* that) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000193 if (that->size_ != this->size_) return false;
194 for (int i = 0; i < this->size_; i++) {
195 if (this->array_[i] != that->array_[i]) return false;
196 }
197 return true;
198 }
199
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +0000200 // Check whether this set contains the given element. O(|this|)
201 // TODO(titzer): use binary search for large sets to make this O(log|this|)
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000202 template <typename U>
203 bool Contains(Unique<U> elem) const {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000204 for (int i = 0; i < size_; i++) {
205 if (this->array_[i] == elem) return true;
206 }
207 return false;
208 }
209
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000210 // Check if this set is a subset of the given set. O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000211 bool IsSubset(UniqueSet<T>* that) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000212 if (that->size_ < this->size_) return false;
213 int j = 0;
214 for (int i = 0; i < this->size_; i++) {
215 Unique<T> sought = this->array_[i];
216 while (true) {
217 if (sought == that->array_[j++]) break;
218 // Fail whenever there are more elements in {this} than {that}.
219 if ((this->size_ - i) > (that->size_ - j)) return false;
220 }
221 }
222 return true;
223 }
224
225 // Returns a new set representing the intersection of this set and the other.
226 // O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000227 UniqueSet<T>* Intersect(UniqueSet<T>* that, Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000228 if (that->size_ == 0 || this->size_ == 0) return new(zone) UniqueSet<T>();
229
230 UniqueSet<T>* out = new(zone) UniqueSet<T>();
231 out->Grow(Min(this->size_, that->size_), zone);
232
233 int i = 0, j = 0, k = 0;
234 while (i < this->size_ && j < that->size_) {
235 Unique<T> a = this->array_[i];
236 Unique<T> b = that->array_[j];
237 if (a == b) {
238 out->array_[k++] = a;
239 i++;
240 j++;
241 } else if (a.raw_address_ < b.raw_address_) {
242 i++;
243 } else {
244 j++;
245 }
246 }
247
248 out->size_ = k;
249 return out;
250 }
251
252 // Returns a new set representing the union of this set and the other.
253 // O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000254 UniqueSet<T>* Union(UniqueSet<T>* that, Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000255 if (that->size_ == 0) return this->Copy(zone);
256 if (this->size_ == 0) return that->Copy(zone);
257
258 UniqueSet<T>* out = new(zone) UniqueSet<T>();
259 out->Grow(this->size_ + that->size_, zone);
260
261 int i = 0, j = 0, k = 0;
262 while (i < this->size_ && j < that->size_) {
263 Unique<T> a = this->array_[i];
264 Unique<T> b = that->array_[j];
265 if (a == b) {
266 out->array_[k++] = a;
267 i++;
268 j++;
269 } else if (a.raw_address_ < b.raw_address_) {
270 out->array_[k++] = a;
271 i++;
272 } else {
273 out->array_[k++] = b;
274 j++;
275 }
276 }
277
278 while (i < this->size_) out->array_[k++] = this->array_[i++];
279 while (j < that->size_) out->array_[k++] = that->array_[j++];
280
281 out->size_ = k;
282 return out;
283 }
284
hpayer@chromium.orgea9b8ba2013-12-20 19:22:39 +0000285 // Makes an exact copy of this set. O(|this|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000286 UniqueSet<T>* Copy(Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000287 UniqueSet<T>* copy = new(zone) UniqueSet<T>();
288 copy->size_ = this->size_;
289 copy->capacity_ = this->size_;
290 copy->array_ = zone->NewArray<Unique<T> >(this->size_);
291 memcpy(copy->array_, this->array_, this->size_ * sizeof(Unique<T>));
292 return copy;
293 }
294
machenbach@chromium.orgcfdf67d2013-09-27 07:27:26 +0000295 void Clear() {
296 size_ = 0;
297 }
298
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000299 inline int size() const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000300 return size_;
301 }
302
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000303 inline Unique<T> at(int index) const {
304 ASSERT(index >= 0 && index < size_);
305 return array_[index];
306 }
307
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000308 private:
309 // These sets should be small, since operations are implemented with simple
310 // linear algorithms. Enforce a maximum size.
311 static const int kMaxCapacity = 65535;
312
313 uint16_t size_;
314 uint16_t capacity_;
315 Unique<T>* array_;
316
317 // Grow the size of internal storage to be at least {size} elements.
318 void Grow(int size, Zone* zone) {
319 CHECK(size < kMaxCapacity); // Enforce maximum size.
320 if (capacity_ < size) {
321 int new_capacity = 2 * capacity_ + size;
322 if (new_capacity > kMaxCapacity) new_capacity = kMaxCapacity;
323 Unique<T>* new_array = zone->NewArray<Unique<T> >(new_capacity);
324 if (size_ > 0) {
325 memcpy(new_array, array_, size_ * sizeof(Unique<T>));
326 }
327 capacity_ = new_capacity;
328 array_ = new_array;
329 }
330 }
331};
332
333
334} } // namespace v8::internal
335
336#endif // V8_HYDROGEN_UNIQUE_H_